From 39476324938b37c90a63c6f5bbe999c10623376f Mon Sep 17 00:00:00 2001
From: John Doe <johndoe@example.com>
Date: Fri, 27 Sep 2024 16:34:50 +0500
Subject: [PATCH] AsyncPHP added

---
 Async-PHP/Backend/db_connect.php              |  26 ++++
 .../Backend/multiple_async_get_outputs.php    |  58 ++++++++
 Async-PHP/Backend/template.php                |   8 ++
 Async-PHP/Backend/template_async.php          |  18 +++
 Async-PHP/app/.htaccess                       |  25 ++++
 Async-PHP/app/reuseable_views/footer.php      |  23 ++++
 .../app/reuseable_views/footer_async.php      |  31 +++++
 Async-PHP/app/reuseable_views/footer_form.php |  38 ++++++
 .../app/reuseable_views/footer_form.php.bak   |  30 +++++
 Async-PHP/app/reuseable_views/footer_json.php |  31 +++++
 Async-PHP/app/reuseable_views/header.php      |  11 ++
 Async-PHP/app/template.php                    |  17 +++
 Async-PHP/async_scripts/db_connect.php        |  19 +++
 Async-PHP/css/style.php                       |  80 +++++++++++
 Async-PHP/index.php                           |  36 +++++
 Async-PHP/index1.php                          |  57 ++++++++
 Async-PHP/js/router_js.php                    | 126 ++++++++++++++++++
 Async-PHP/lib/AsyncRunner.php                 |  38 ++++++
 Async-PHP/router_links/links.php              |  11 ++
 19 files changed, 683 insertions(+)
 create mode 100644 Async-PHP/Backend/db_connect.php
 create mode 100644 Async-PHP/Backend/multiple_async_get_outputs.php
 create mode 100644 Async-PHP/Backend/template.php
 create mode 100644 Async-PHP/Backend/template_async.php
 create mode 100644 Async-PHP/app/.htaccess
 create mode 100644 Async-PHP/app/reuseable_views/footer.php
 create mode 100644 Async-PHP/app/reuseable_views/footer_async.php
 create mode 100644 Async-PHP/app/reuseable_views/footer_form.php
 create mode 100644 Async-PHP/app/reuseable_views/footer_form.php.bak
 create mode 100644 Async-PHP/app/reuseable_views/footer_json.php
 create mode 100644 Async-PHP/app/reuseable_views/header.php
 create mode 100644 Async-PHP/app/template.php
 create mode 100644 Async-PHP/async_scripts/db_connect.php
 create mode 100644 Async-PHP/css/style.php
 create mode 100644 Async-PHP/index.php
 create mode 100644 Async-PHP/index1.php
 create mode 100644 Async-PHP/js/router_js.php
 create mode 100644 Async-PHP/lib/AsyncRunner.php
 create mode 100644 Async-PHP/router_links/links.php

diff --git a/Async-PHP/Backend/db_connect.php b/Async-PHP/Backend/db_connect.php
new file mode 100644
index 0000000..acdee90
--- /dev/null
+++ b/Async-PHP/Backend/db_connect.php
@@ -0,0 +1,26 @@
+<?php
+$servername = "";
+$username = "";
+$password = "";
+$dbname = "";
+$port = "";
+
+// Create connection
+$conn = new mysqli($servername, $username, $password, $dbname, $port);
+
+// Check connection
+if ($conn->connect_error) {
+    die("Connection failed: " . $conn->connect_error);
+    }
+
+
+
+
+//else{
+//    echo "Connected successfully";
+//}
+// Make sure to stop connection in files where you will use this
+
+
+?>
+
diff --git a/Async-PHP/Backend/multiple_async_get_outputs.php b/Async-PHP/Backend/multiple_async_get_outputs.php
new file mode 100644
index 0000000..26c4399
--- /dev/null
+++ b/Async-PHP/Backend/multiple_async_get_outputs.php
@@ -0,0 +1,58 @@
+<?php
+
+
+require_once '../lib/AsyncRunner.php';
+
+if ($_SERVER['REQUEST_METHOD'] === 'POST') {
+    echo "Received POST request.<br>"; // Debug statement
+    $path = '../async_scripts';
+    $scripts = ["$path/script1.php", "$path/script2.php", "$path/script3.php"];
+
+    // Run the scripts asynchronously
+    $outputs = runScriptsAsync($scripts); // Call the function directly
+    echo "Scripts executed. Outputs:<br>"; // Debug statement
+
+    // Initialize variables for individual outputs
+    $output1 = '';
+    $output2 = '';
+    $output3 = '';
+
+    // Assign outputs to individual variables
+    if (isset($outputs[0])) {
+        $output1 = trim($outputs[0]); // Script 1 output
+    }
+    if (isset($outputs[1])) {
+        $output2 = trim($outputs[1]); // Script 2 output
+    }
+    if (isset($outputs[2])) {
+        $output3 = trim($outputs[2]); // Script 3 output
+    }
+
+    // Output the individual outputs
+    echo "Output 1: " . $output1 . "<br>";
+    echo "Output 2: " . $output2 . "<br>";
+    echo "Output 3: " . $output3 . "<br>";
+
+    // Initialize the sum
+    $sum = 0;
+
+    // Calculate the sum only for non-empty outputs
+    if ($output1 !== '') {
+        $sum += floatval($output1);
+    }
+    if ($output2 !== '') {
+        $sum += floatval($output2);
+    }
+    if ($output3 !== '') {
+        $sum += floatval($output3);
+    }
+
+    // Output the total sum
+    echo "<strong>Total Sum: " . $sum . "</strong>";
+echo "ok";
+}
+
+
+
+
+?>
diff --git a/Async-PHP/Backend/template.php b/Async-PHP/Backend/template.php
new file mode 100644
index 0000000..e3cb372
--- /dev/null
+++ b/Async-PHP/Backend/template.php
@@ -0,0 +1,8 @@
+<?php
+
+
+echo "hellow from AsyncPHP";
+
+
+
+?>
diff --git a/Async-PHP/Backend/template_async.php b/Async-PHP/Backend/template_async.php
new file mode 100644
index 0000000..6e9f491
--- /dev/null
+++ b/Async-PHP/Backend/template_async.php
@@ -0,0 +1,18 @@
+<?php
+
+require_once '../lib/AsyncRunner.php';
+
+if ($_SERVER['REQUEST_METHOD'] === 'POST') {
+    $path = '../async_scripts';
+    $scripts = ["$path/db_script1.php", "$path/db_script2.php", "$path/db_script3.php"];
+
+    $outputs = runScriptsAsync($scripts); // Call the function directly
+
+    foreach ($outputs as $output) {
+        echo "<pre>$output</pre>";
+    }
+}
+
+echo "Script executed successfully.";
+
+?>
diff --git a/Async-PHP/app/.htaccess b/Async-PHP/app/.htaccess
new file mode 100644
index 0000000..82cbaaf
--- /dev/null
+++ b/Async-PHP/app/.htaccess
@@ -0,0 +1,25 @@
+<IfModule mod_rewrite.c>
+    RewriteEngine On
+
+    # Redirect any requests with .php extension to the URL without the extension
+    RewriteCond %{THE_REQUEST} \s/([^.]+)\.php[\s?] [NC]
+    RewriteRule ^ /%1 [R=301,L]
+
+    # Internally rewrite requests without .php to the actual .php file
+    RewriteCond %{REQUEST_FILENAME} !-d
+    RewriteCond %{REQUEST_FILENAME} !-f
+    RewriteCond %{REQUEST_FILENAME}\.php -f
+    RewriteRule ^(.*)$ $1.php [L]
+
+
+# Route /app to app/index.php
+RewriteRule ^app/?$ /app/index.php [L]
+
+# If you want to handle all requests under /app (e.g., /app/something)
+RewriteRule ^app/(.*)$ /app/index.php [L,QSA]
+
+</IfModule>
+
+# Enable the rewrite engine
+Options +FollowSymLinks
+
diff --git a/Async-PHP/app/reuseable_views/footer.php b/Async-PHP/app/reuseable_views/footer.php
new file mode 100644
index 0000000..4d764d7
--- /dev/null
+++ b/Async-PHP/app/reuseable_views/footer.php
@@ -0,0 +1,23 @@
+<script>
+    $(document).ready(function() {
+        // Use event delegation to handle click events for elements with class 'runScripts'
+        $(document).on('click', '.runScripts', function(e) {
+            e.preventDefault();
+            var url = $(this).data('url'); // Get the URL from the data attribute
+
+            $.ajax({
+                url: url,
+                method: 'POST',
+                success: function(data) {
+                    $('#output').html(data);
+                },
+                error: function(jqXHR, textStatus, errorThrown) {
+                    $('#output').html("Error: " + textStatus + " " + errorThrown);
+                }
+            });
+        });
+    });
+</script>
+</body>
+</html>
+
diff --git a/Async-PHP/app/reuseable_views/footer_async.php b/Async-PHP/app/reuseable_views/footer_async.php
new file mode 100644
index 0000000..5b90903
--- /dev/null
+++ b/Async-PHP/app/reuseable_views/footer_async.php
@@ -0,0 +1,31 @@
+<script>
+    document.addEventListener('DOMContentLoaded', () => {
+        const button = document.querySelector('.runScripts');
+        button.addEventListener('click', (e) => {
+            e.preventDefault();
+            const url = button.getAttribute('data-url'); // Get the URL from the data attribute
+            
+            fetch(url, {
+                method: 'POST',  // Change to POST
+                headers: {
+                    'Content-Type': 'application/x-www-form-urlencoded'  // Set content type
+                }
+            })
+            .then(response => {
+                if (!response.ok) {
+                    throw new Error('Network response was not ok ' + response.statusText);
+                }
+                return response.text();
+            })
+            .then(data => {
+                document.getElementById('output').innerHTML = data;
+            })
+            .catch(err => {
+                console.error('Error fetching output:', err);
+                document.getElementById('output').innerHTML = 'Error fetching output: ' + err.message;
+            });
+        });
+    });
+</script>
+</body>
+</html>
diff --git a/Async-PHP/app/reuseable_views/footer_form.php b/Async-PHP/app/reuseable_views/footer_form.php
new file mode 100644
index 0000000..7c213eb
--- /dev/null
+++ b/Async-PHP/app/reuseable_views/footer_form.php
@@ -0,0 +1,38 @@
+<script>
+    $(document).ready(function() {
+        // Use event delegation to handle click events for elements with class 'runScripts'
+        $(document).on('click', '.runScripts', function(e) {
+            e.preventDefault();
+
+            // Get the URL from the data-url attribute of the button
+            var url = $(this).data('url');
+
+            // Get the form associated with the button that was clicked
+            var form = $(this).closest('form');
+
+            // Check if a form was found
+            if (form.length) {
+                // Gather form data using FormData object
+                var formData = new FormData(form[0]);
+
+                $.ajax({
+                    url: url,
+                    type: 'POST',
+                    data: formData,
+                    processData: false,  // Do not process the data into a query string
+                    contentType: false,  // Do not set content type
+                    success: function(data) {
+                        $('#output').html(data);  // Show response in the output div
+                    },
+                    error: function(jqXHR, textStatus, errorThrown) {
+                        $('#output').html("Error: " + textStatus + " " + errorThrown);
+                    }
+                });
+            } else {
+                $('#output').html("Error: No form associated with this button.");
+            }
+        });
+    });
+</script>
+</body>
+</html>
diff --git a/Async-PHP/app/reuseable_views/footer_form.php.bak b/Async-PHP/app/reuseable_views/footer_form.php.bak
new file mode 100644
index 0000000..82cb418
--- /dev/null
+++ b/Async-PHP/app/reuseable_views/footer_form.php.bak
@@ -0,0 +1,30 @@
+<script>
+    $(document).ready(function() {
+        // Use event delegation to handle click events for elements with class 'runScripts'
+        $(document).on('click', '.runScripts', function(e) {
+            e.preventDefault();
+
+            // Get the URL from the data-url attribute of the button
+            var url = $(this).data('url');
+
+            // Gather form data using FormData object
+            var formData = new FormData($('#userForm')[0]);
+
+            $.ajax({
+                url: url,
+                type: 'POST',
+                data: formData,
+                processData: false,  // Do not process the data into a query string
+                contentType: false,  // Do not set content type
+                success: function(data) {
+                    $('#output').html(data);  // Show response in the output div
+                },
+                error: function(jqXHR, textStatus, errorThrown) {
+                    $('#output').html("Error: " + textStatus + " " + errorThrown);
+                }
+            });
+        });
+    });
+</script>
+</body>
+</html>
diff --git a/Async-PHP/app/reuseable_views/footer_json.php b/Async-PHP/app/reuseable_views/footer_json.php
new file mode 100644
index 0000000..c5727d8
--- /dev/null
+++ b/Async-PHP/app/reuseable_views/footer_json.php
@@ -0,0 +1,31 @@
+<script>
+
+$(document).ready(function() {
+    $(document).on('click', '.runScripts', function(e) {
+        e.preventDefault();
+        var url = $(this).data('url'); // Get the URL from the data attribute
+        console.log("AJAX URL:", url); // Log the URL to console
+
+        $.ajax({
+            url: url,
+            method: 'POST',
+            success: function(data) {
+                console.log("AJAX Success:", data); // Log the response
+                $('#output').html(data); // Directly output the raw response data
+            },
+            error: function(jqXHR, textStatus, errorThrown) {
+                console.error("AJAX Error:", textStatus, errorThrown); // Log error details
+                $('#output').html("Error: " + textStatus + " " + errorThrown);
+            }
+        });
+    });
+});
+
+
+
+</script>
+
+
+</body>
+</html>
+
diff --git a/Async-PHP/app/reuseable_views/header.php b/Async-PHP/app/reuseable_views/header.php
new file mode 100644
index 0000000..e05e381
--- /dev/null
+++ b/Async-PHP/app/reuseable_views/header.php
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title><?php echo isset($pageTitle) ? $pageTitle : 'Default Title'; ?></title>
+    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
+    <script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
+</head>
+<body class="container">
+
diff --git a/Async-PHP/app/template.php b/Async-PHP/app/template.php
new file mode 100644
index 0000000..72236e5
--- /dev/null
+++ b/Async-PHP/app/template.php
@@ -0,0 +1,17 @@
+<?php
+$pageTitle = 'Index'; // Set the page title
+include 'reuseable_views/header.php'; ?>
+
+
+<h1 class="mt-5">Logs</h1>
+<button class="runScripts" class="btn btn-primary mb-3" data-url="../Backend/template.php">Run Scripts</button>
+<h2>Script Outputs:</h2>
+<div id="output" class="bg-light p-3"></div>
+
+
+
+<?php include 'reuseable_views/footer.php'; ?>
+
+
+
+
diff --git a/Async-PHP/async_scripts/db_connect.php b/Async-PHP/async_scripts/db_connect.php
new file mode 100644
index 0000000..a38108f
--- /dev/null
+++ b/Async-PHP/async_scripts/db_connect.php
@@ -0,0 +1,19 @@
+<?php
+$servername = "";
+$username = "";
+$password = "";
+$dbname = "";
+$port = ;
+
+// Create connection
+$conn = new mysqli($servername, $username, $password, $dbname, $port);
+
+// Check connection
+if ($conn->connect_error) {
+    die("Connection failed: " . $conn->connect_error);
+    }
+
+
+
+?>
+
diff --git a/Async-PHP/css/style.php b/Async-PHP/css/style.php
new file mode 100644
index 0000000..c5d2482
--- /dev/null
+++ b/Async-PHP/css/style.php
@@ -0,0 +1,80 @@
+<style>
+/* styles.css */
+body {
+    display: flex;
+    transition: margin-left 0.3s; /* Smooth transition */
+}
+
+.sidebar {
+    width: 250px; /* Adjust the width of the sidebar */
+    background-color: #f8f9fa;
+    padding: 15px;
+    box-shadow: 2px 0 5px rgba(0,0,0,0.1);
+    position: fixed; /* Fix sidebar position */
+    height: 100vh; /* Full height */
+    overflow-y: auto; /* Enable scrolling if needed */
+    transition: transform 0.3s; /* Smooth transition for hiding */
+}
+
+.sidebar.hidden {
+    transform: translateX(-100%); /* Move sidebar out of view */
+}
+
+.main-content {
+    flex-grow: 1;
+    padding: 20px;
+    transition: margin-left 0.3s; /* Smooth transition for margin */
+    margin-left: 250px; /* Default margin for sidebar */
+}
+
+.main-content.shifted {
+    margin-left: 0; /* Shift content when sidebar is hidden */
+}
+
+/* Responsive Design */
+@media (max-width: 768px) {
+    .sidebar {
+        width: 200px; /* Adjust sidebar width on mobile */
+    }
+    .main-content {
+        margin-left: 0; /* No margin when sidebar is hidden on mobile */
+    }
+}
+
+.dropbtn {
+  background-color: #04AA6D;
+  color: white;
+  padding: 16px;
+  font-size: 16px;
+  border: none;
+}
+
+.dropdown {
+  position: relative;
+  display: inline-block;
+}
+
+.dropdown-content {
+  display: none;
+  position: absolute;
+  background-color: #f1f1f1;
+  min-width: 160px;
+  box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
+  z-index: 1;
+}
+
+.dropdown-content a {
+  color: black;
+  padding: 12px 16px;
+  text-decoration: none;
+  display: block;
+}
+
+.dropdown-content a:hover {background-color: #ddd;}
+
+.dropdown:hover .dropdown-content {display: block;}
+
+.dropdown:hover .dropbtn {background-color: #3e8e41;}
+
+</style>
+
diff --git a/Async-PHP/index.php b/Async-PHP/index.php
new file mode 100644
index 0000000..2890a0a
--- /dev/null
+++ b/Async-PHP/index.php
@@ -0,0 +1,36 @@
+<?php include "router_links/links.php"; ?>
+
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>Router Example</title>
+    <link href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet">
+    <?php include "css/style.php"; ?>
+</head>
+<body>
+    <!-- Sidebar Navigation -->
+    <div class="sidebar" id="sidebar">
+        <h4>Navigation</h4>
+
+        <button id="toggleSidebar" class="btn btn-primary">Toggle Sidebar</button>
+        <ul class="nav flex-column">
+            <?php foreach ($pageNames as $key => $name): ?>
+                <li class="nav-item">
+                    <a class="nav-link" href="#/<?php echo $key; ?>"><?php echo $name; ?></a>
+                </li>
+            <?php endforeach; ?>
+        </ul>
+    </div>
+
+    <!-- Main Content Area -->
+    <div id="app" class="main-content">
+        <button id="showSidebar" class="btn btn-secondary" style="display: none;">Show Sidebar</button>
+        <router-view></router-view>
+    </div>
+
+    <?php include "js/router_js.php"; ?>
+</body>
+</html>
+
diff --git a/Async-PHP/index1.php b/Async-PHP/index1.php
new file mode 100644
index 0000000..651f330
--- /dev/null
+++ b/Async-PHP/index1.php
@@ -0,0 +1,57 @@
+<?php include "router_links/links.php"; ?>
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title>Router Example</title>
+    <link href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet">
+    <?php include "css/style.php"; ?>
+</head>
+<body>
+
+
+    <!-- Sidebar Navigation -->
+    <div class="sidebar" id="sidebar">
+        <h4>Navigation</h4>
+
+        <button id="toggleSidebar" class="btn btn-primary">Toggle Sidebar</button>
+        <ul class="nav flex-column">
+            <!-- Manual Links -->
+            <li class="nav-item">
+                <a class="nav-link" href="#/app/index">Index</a>
+            </li>
+            <li class="nav-item">
+                <a class="nav-link" href="#/app/async_calculation.php">Async Calculation</a>
+            </li>
+            <li class="nav-item">
+                <a class="nav-link" href="#/app/100_async_time.php">Insert 100 timestamps</a>
+            </li>
+            <li class="nav-item">
+                <a class="nav-link" href="#/app/run_without_reload.php">Run Without Reload</a>
+            </li>
+            <li class="nav-item">
+                       <div class="dropdown">
+                       <button class="dropbtn">Dropdown</button>
+                       <div class="dropdown-content">
+
+                    <a class="dropdown-item" href="#/app/insert_user_form_template.php">Insert User</a>
+                    <a class="dropdown-item" href="#/app/insert_product_form_template.php">Insert Product</a>
+                </div>
+                </div>
+            </li>
+        </ul>
+    </div>
+
+    <!-- Main Content Area -->
+    <div id="app" class="main-content">
+        <button id="showSidebar" class="btn btn-secondary" style="display: none;">Show Sidebar</button>
+        <router-view></router-view>
+    </div>
+
+
+
+<?php include "js/router_js.php"; ?>
+</body>
+</html>
+
diff --git a/Async-PHP/js/router_js.php b/Async-PHP/js/router_js.php
new file mode 100644
index 0000000..8468da9
--- /dev/null
+++ b/Async-PHP/js/router_js.php
@@ -0,0 +1,126 @@
+    <script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
+    <script src="https://cdn.jsdelivr.net/npm/vue-router@3"></script>
+    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script> 
+    <script>
+        function createComponent(path) {
+            return {
+                template: `<div id="${path}-content"></div>`,
+                mounted() {
+                    this.loadContent();
+                },
+                methods: {
+                    loadContent() {
+                        const paths = <?php echo json_encode($pagePaths); ?>;
+                        const currentPath = paths[this.$route.path.substring(1)] || paths['index'];
+
+                        fetch(currentPath)
+                            .then(response => {
+                                if (!response.ok) {
+                                    throw new Error('Network response was not ok ' + response.statusText);
+                                }
+                                return response.text();
+                            })
+                            .then(data => {
+                                document.getElementById(`${path}-content`).innerHTML = data;
+                            })
+                            .catch(err => {
+                                console.error(`Error fetching ${path}:`, err);
+                                document.getElementById(`${path}-content`).innerHTML = 'Error fetching content.';
+                            });
+                    }
+                }
+            };
+        }
+        const routes = Object.keys(<?php echo json_encode($pagePaths); ?>).map(key => ({
+            path: `/${key}`,
+            component: createComponent(key)
+        }));
+        const router = new VueRouter({
+            mode: 'hash',
+            routes
+        });
+        const app = new Vue({
+            el: '#app',
+            router,
+            mounted() {
+                this.initGlobalEvents();
+            },
+            methods: {
+                initGlobalEvents() {
+                    // Global event delegation for form submissions and button clicks
+                    document.addEventListener('click', (e) => {
+                        if (e.target.matches('.runScripts')) {
+                            e.preventDefault();
+                            const url = e.target.getAttribute('data-url');
+
+                            if (e.target.closest('form')) {
+                                const form = e.target.closest('form');
+                                const formData = new FormData(form);
+
+                                axios.post(url, formData)
+                                    .then(response => {
+                                        document.getElementById('output').innerHTML = response.data;
+                                    })
+                                    .catch(err => {
+                                        document.getElementById('output').innerHTML = 'Error: ' + err.message;
+                                    });
+                            } else {
+                                axios.post(url)
+                                    .then(response => {
+                                        document.getElementById('output').innerHTML = response.data;
+                                    })
+                                    .catch(err => {
+                                        document.getElementById('output').innerHTML = 'Error: ' + err.message;
+                                    });
+                            }
+                        }
+                    });
+
+                    // Global event for form submissions
+                    document.addEventListener('submit', (e) => {
+                        if (e.target.matches('form')) {
+                            e.preventDefault();
+                            const url = e.target.querySelector('.runScripts').getAttribute('data-url');
+                            const formData = new FormData(e.target);
+
+                            axios.post(url, formData)
+                                .then(response => {
+                                    document.getElementById('output').innerHTML = response.data;
+                                })
+                                .catch(err => {
+                                    document.getElementById('output').innerHTML = 'Error: ' + err.message;
+                                });
+                        }
+                    });
+                }
+            }
+        });
+ </script>
+
+<script>
+        // JavaScript for sidebar toggle
+        const toggleButton = document.getElementById('toggleSidebar');
+        const sidebar = document.getElementById('sidebar');
+        const mainContent = document.getElementById('app');
+        const showSidebarButton = document.getElementById('showSidebar');
+
+        toggleButton.addEventListener('click', function() {
+            sidebar.classList.toggle('hidden'); // Hide/Show sidebar
+            mainContent.classList.toggle('shifted'); // Shift main content
+
+            // Show or hide the "Show Sidebar" button
+            if (sidebar.classList.contains('hidden')) {
+                showSidebarButton.style.display = 'block'; // Show button to bring back sidebar
+            } else {
+                showSidebarButton.style.display = 'none'; // Hide the button if sidebar is visible
+            }
+        });
+
+        showSidebarButton.addEventListener('click', function() {
+            sidebar.classList.remove('hidden'); // Show sidebar
+            mainContent.classList.remove('shifted'); // Reset main content position
+            showSidebarButton.style.display = 'none'; // Hide the button
+        });
+    </script>
+
+
diff --git a/Async-PHP/lib/AsyncRunner.php b/Async-PHP/lib/AsyncRunner.php
new file mode 100644
index 0000000..6d29aac
--- /dev/null
+++ b/Async-PHP/lib/AsyncRunner.php
@@ -0,0 +1,38 @@
+<?php
+function runScriptsAsync(array $scripts) {
+    $descriptorspec = [
+        0 => ["pipe", "r"],  // stdin
+        1 => ["pipe", "w"],  // stdout
+        2 => ["pipe", "w"],  // stderr
+    ];
+
+    $processes = [];
+    $pipes = [];
+    $outputs = [];
+
+    // Start processes for each script
+    foreach ($scripts as $index => $script) {
+        $process = proc_open("php $script", $descriptorspec, $pipes[$index]);
+        if (is_resource($process)) {
+            $processes[$index] = $process;
+        } else {
+            echo "Failed to start $script\n";
+        }
+    }
+
+    // Optionally, you can read output
+    foreach ($pipes as $index => $pipe) {
+        $outputs[$index] = stream_get_contents($pipe[1]);
+        fclose($pipe[1]); // Close stdout
+    }
+
+    // Close the processes when done
+    foreach ($processes as $index => $process) {
+        proc_close($process);
+    }
+
+    // Return the outputs if needed
+    return $outputs;
+}
+?>
+
diff --git a/Async-PHP/router_links/links.php b/Async-PHP/router_links/links.php
new file mode 100644
index 0000000..61ff142
--- /dev/null
+++ b/Async-PHP/router_links/links.php
@@ -0,0 +1,11 @@
+<?php
+$pagePaths = [
+    'app/template' => 'app/template.php',
+
+];
+
+$pageNames = [
+    'app/template' => 'Index',
+
+];
+?>