Blog

  • Handle AJAX Multiple File Upload Using PHP And MariaDB

    Handle AJAX Multiple File Upload Using PHP And MariaDB


    Beginner’s Guide: Secure File Uploads with PHP, AJAX, and MariaDB

    In our previous tutorial, we focused on the frontend, using HTML5 and the Fetch API to create a sleek, drag-and-drop user interface for file uploads. That was all about making the user experience seamless.

    Now, we shift our focus to the engine room: the backend. This is where the real work happens- where we secure the data, process the files, and permanently store information in our database. This guide will walk you through setting up a robust PHP script to handle the Fetch API requests and interact with a MariaDB database.

    1. Understanding the Backend’s Role

    The backend’s primary job is to process the data sent from the frontend securely and efficiently. For file uploads, this means:

    1. Validation: Checking file size, type, and quantity.
    2. Processing: Saving the file to a secure location on the server.
    3. Database Interaction: Recording the file’s information (like its name, path, and user ID) into the database.
    4. Action Handling: Managing operations like deletion and replacement.

    2. Setting up the PHP Handler for Fetch

    The frontend sends the files and other data to your PHP script via the Fetch API. On the backend, PHP reads this data from the global $_FILES superglobal array.

    Your PHP handler needs to listen for a specific action passed in the request. For example, the request might include an action flag like ‘upload’, ‘delete’, or ‘replace’.

    
    
    
    <?php
    // PHP Script to handle AJAX/Fetch requests (e.g., upload_handler.php)
    
    // 1. Database Connection Setup (Replace with your credentials)
    $conn = new mysqli("localhost", "user", "password", "database");
    
    if ($conn->connect_error) {
        die("Connection failed: " . $conn->connect_error);
    }
    
    // 2. Security and Setup
    $upload_dir = 'uploads/'; // Ensure this directory exists and is writable!
    // ... (Your security checks for user authentication would go here)
    
    if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['file_data'])) {
        $action = $_POST['action'] ?? 'upload'; // Get the intended action
    
        foreach ($_FILES['file_data']['name'] as $key => $name) {
            // Basic security and sanitization before proceeding
            $safe_name = preg_replace("/[^A-Za-z0-9.]/", '_', $name);
            $temp_path = $_FILES['file_data']['tmp_name'][$key];
            $target_file = $upload_dir . basename($safe_name);
    
            if ($action === 'upload' && move_uploaded_file($temp_path, $target_file)) {
                // Success: Save details to MariaDB
                $stmt = $conn->prepare("INSERT INTO files (file_name, file_path) VALUES (?, ?)");
                $stmt->bind_param("ss", $safe_name, $target_file);
                $stmt->execute();
                // ... Respond to frontend
            } else {
                // Handle error or other actions
            }
        }
    }
    ?>
    
    

    3. Handling Replacement and Deletion Actions

    This is where the power of a database comes in. To handle file replacement or deletion, you primarily interact with MariaDB.

    File Deletion

    When the frontend sends a ‘delete’ action along with a unique file ID:

    1. Delete from Server: Use PHP’s unlink() function to remove the physical file from the uploads/ directory.
    2. Delete from Database: Run a SQL DELETE command on your MariaDB table using the file ID.
    DELETE FROM files WHERE id = [file_id];

    File Replacement

    When the frontend sends a ‘replace’ action:

    1. Get Old Data: Retrieve the existing file path from MariaDB using the old file’s ID.
    2. Upload New File: Save the new file to the server (as shown in Step 2).
    3. Remove Old File: Use unlink() to delete the original file.
    4. Update Database: Run a SQL UPDATE command to point the existing file ID to the new file name and path.
    UPDATE files SET file_name = 'new_name.jpg', file_path = 'uploads/new_name.jpg' WHERE id = [file_id];

    Screenshots and Screencast

    Multiple File Upload Code
    Gnome Text Editor Displaying Fetch URL For File Upload HTML Code

    Multiple File Upload Handler
    Gnome Text Editor Displaying PHP File Upload Code

    Multiple File Upload Form
    Web Browser Displaying A Drag And Drop Multiple File Upload Form

    Multiple File Upload Failure
    Web Browser Displaying A Failed Multiple File Upload

    Uploaded Files In Database
    Web Browser RUnning PHPMyAdmin Displaying A List Of Uploaded Files

    PHP Multiple File Upload AJAX Video

    Ready to Master PHP?

    This backend process is a core skill for any serious web developer. If you’re a beginner ready to dive deep into PHP, I highly recommend checking out my resources:

    Need hands-on help with your projects? I’m available for one-on-one programming tutorials and services like framework updates or migration.

    Contact me for direct consultation:

    https://ojambo.com/contact

  • HTML5 Multiple File Upload AJAX Using Fetch API

    HTML5 Multiple File Upload AJAX Using Fetch API

    Frontend File Uploads: Mastering HTML5 Multiple Upload AJAX with Fetch API

    Welcome to the start of an exciting, beginner-friendly series! Dealing with **file uploads** is a fundamental task in web development, and modern techniques make it far more powerful and user-friendly than the old-school methods.

    In this tutorial, we’re going to dive deep into the **frontend** mechanics of creating a **multiple file upload** system using **HTML5**, the **Fetch API** for **AJAX**, and a touch of **Drag and Drop** functionality. This will lay the groundwork for a robust system, with the backend processing to follow in our next post!

    Let’s get started on building a sleek and functional file upload interface.

    The HTML5 Foundation

    Every modern web application starts with solid **HTML**. For file uploads, the core is a simple <input type="file"> element with two crucial attributes:

    1. multiple: This tells the browser to allow the user to select more than one file.
    2. accept: This helps restrict the types of files the user can select (e.g., image/* for all image types).

    Here’s the basic HTML structure we’ll use:

    
    
    
    &lt;div id=&quot;drop-area&quot;&gt;
        &lt;p&gt;Drag and Drop files here, or click to select files&lt;/p&gt;
        &lt;input type=&quot;file&quot; id=&quot;fileElem&quot; multiple accept=&quot;image/*&quot; style=&quot;display: none;&quot;&gt;
        &lt;label for=&quot;fileElem&quot; class=&quot;button&quot;&gt;Select Files&lt;/label&gt;
        &lt;progress id=&quot;progressBar&quot; value=&quot;0&quot; max=&quot;100&quot; style=&quot;display:none;&quot;&gt;&lt;/progress&gt;
    &lt;/div&gt;
    &lt;div id=&quot;status&quot;&gt;&lt;/div&gt;
    
    

    We’ve added a few extras:

    • #drop-area: This is the main container that will receive the dropped files.
    • The <input> is hidden (style="display: none;") and triggered by a user-friendly <label> acting as a button.
    • #progressBar: A simple HTML5 element to show upload progress.
    • #status: A space for messages (like “Upload Complete!”).

    Adding Drag and Drop Functionality

    To make this user-friendly, we’ll implement **Drag and Drop**. This requires listening for a few specific **JavaScript** events on our #drop-area:

    • dragenter and dragleave: To change the area’s visual style when a user drags a file over it.
    • dragover: To prevent the browser’s default behavior (which is to open the file).
    • drop: The key event where we actually access the files.

    The core code for handling the drop event looks like this:

    
    
    
    const dropArea = document.getElementById(&#039;drop-area&#039;);
    const fileInput = document.getElementById(&#039;fileElem&#039;);
    
    // Prevent default drag behaviors
    [&#039;dragenter&#039;, &#039;dragover&#039;, &#039;dragleave&#039;, &#039;drop&#039;].forEach(eventName =&gt; {
      dropArea.addEventListener(eventName, preventDefaults, false);
    });
    
    function preventDefaults(e) {
      e.preventDefault();
      e.stopPropagation();
    }
    
    // Handle dropped files
    dropArea.addEventListener(&#039;drop&#039;, handleDrop, false);
    
    function handleDrop(e) {
      const dt = e.dataTransfer;
      const files = dt.files;
    
      // Pass the files to the upload function
      uploadFiles(files);
    }
    
    // Also trigger upload when the hidden input changes
    fileInput.addEventListener(&#039;change&#039;, (e) =&gt; {
        uploadFiles(e.target.files);
    });
    
    

    When a file is dropped or selected, we pass the collection of files to our main uploadFiles function.

    AJAX Upload using the Fetch API

    The **Fetch API** is the modern, promise-based standard for making network requests, replacing older XMLHttpRequest techniques for most tasks. To send files, we must use the **FormData** object. This object easily constructs a set of key/value pairs representing form fields and their values, including the file data.

    Here is the uploadFiles function, focusing purely on the frontend preparation and sending:

    
    
    
    function uploadFiles(files) {
        const formData = new FormData();
        const statusDiv = document.getElementById(&#039;status&#039;);
        const progressBar = document.getElementById(&#039;progressBar&#039;);
    
        // 1. Append all selected files to the FormData object
        // Note: The key name &#039;uploaded_files&#039; must match what the backend expects.
        for (let i = 0; i &lt; files.length; i++) {
            formData.append(&#039;uploaded_files[]&#039;, files[i]);
        }
    
        // 2. Configure the Fetch request
        // IMPORTANT: Replace &#039;/upload-endpoint&#039; with your actual backend URL.
        fetch(&#039;/upload-endpoint&#039;, {
            method: &#039;POST&#039;,
            // Fetch automatically sets the &#039;Content-Type&#039; header correctly 
            // for FormData, so we don&#039;t need to manually set it!
            body: formData 
        })
        .then(response =&gt; {
            // 3. Handle the response (This is where the next tutorial will focus!)
            if (response.ok) {
                statusDiv.innerHTML = &#039;Upload successful!&#039;;
                progressBar.style.display = &#039;none&#039;;
            } else {
                statusDiv.innerHTML = &#039;Upload failed!&#039;;
                progressBar.style.display = &#039;none&#039;;
            }
            return response.json(); // Assuming the backend returns JSON
        })
        .catch(error =&gt; {
            // 4. Handle network errors
            statusDiv.innerHTML = `Error: ${error.message}`;
            progressBar.style.display = &#039;none&#039;;
            console.error(&#039;Upload Error:&#039;, error);
        });
    
        // Display a loading message and the progress bar (though progress tracking 
        // is more complex and often handled by the XHR object, 
        // for this simple fetch, we just show the bar).
        statusDiv.innerHTML = &#039;Uploading...&#039;;
        progressBar.style.display = &#039;block&#039;;
        progressBar.value = 50; // Simple placeholder progress
    }
    
    

    Next Steps: The Backend!

    And that’s it for the frontend! You now have a working **HTML5 Drag and Drop interface** that collects multiple files and sends them to a backend endpoint using the modern **Fetch API**.

    In the **next tutorial**, we will focus on the **backend**, showing you how to correctly receive the FormData object and process (save, validate, resize, etc.) the uploaded_files on the server using a language like PHP, Node.js, or Python.

    Screenshots and Screencast

    A hover over drag and drop interface
    Web Browser Displaying A Hover Over Drag And Drop Interface

    A drag and drop multiple file animation
    Web Browser Displaying A Drag And Drop Multiple File Animation

    A drag and drop file failed upload
    Web Browser Displaying A Drag And Drop File Failed Upload Message

    HTML Drag And Drop Multiple Upload Animation Video

    Keep Learning JavaScript!

    If you’re eager to deepen your understanding of the language that powers the frontend-**JavaScript**-I have resources designed just for you:

    • **Book:** Check out my book, **”Learning JavaScript: A Programming Beginner’s Guide,”** available now! Grab your copy on Amazon today.
    • **Course:** Prefer a guided course format? The comprehensive **”Learning JavaScript”** course covers everything from basics to advanced topics. Enroll in the course here.
    • **One-on-One Help:** Need personalized attention? I’m available for **one-on-one programming tutorials**, including in-depth **JavaScript** sessions to help you master challenging concepts. Contact me to schedule a session!
  • Generate Tensegrity Tables With Blender Python API For Website

    Generate Tensegrity Tables With Blender Python API For Website


    Tensegrity Tables from Code to Web: Your Blender Python & Model-Viewer Project

    Ever wanted to create cool 3D models with code and show them on your website? This beginner-friendly blog post will guide you through generating a fascinating Tensegrity Table (a structure held together by continuous tension and discontinuous compression) using a Python script inside Blender, and then displaying that 3D model right in your web browser using Google’s awesome <model-viewer> element! Get ready to combine the power of Python, 3D design, and web development.

    Step 1: Generating the Low-Poly Tensegrity Table in Blender with Python

    Blender, the free and open-source 3D suite, has a powerful Python API (Application Programming Interface). To keep things simple and easy to understand for beginners, we will use a **low-poly** approach, building the struts from simple **cubes** and the cables from **edges**.

    Here is the Python script you need. Save it as low_poly_tensegrity_table.py:

    
    
    
    import bpy
    import math
    from mathutils import Vector
    
    # --- Configuration ---
    FILE_NAME = &quot;square_floating_table.glb&quot;
    TABLE_HEIGHT = 1.0          # Vertical distance between the plates
    SIDE_LENGTH = 1.5           # Side length of the square tabletop and base
    TOP_THICKNESS = 0.05        # Thickness of the tabletop
    BASE_THICKNESS = 0.05       # Thickness of the base
    STRUT_HEIGHT = 0.2          # Height of the floating central strut
    STRUT_THICKNESS = 0.05      # Thickness of the floating central strut
    CABLE_THICKNESS = 0.008
    LOW_POLY_VERTICES = 8       # Vertex count for low-poly appearance
    JOINT_SIZE = 0.04
    
    # --- Constants for Z-Positioning ---
    TABLE_TOP_Z = TABLE_HEIGHT + TOP_THICKNESS / 2 
    BASE_BOTTOM_Z = -BASE_THICKNESS / 2 
    STRUT_TOP_Z = TABLE_HEIGHT / 2 + STRUT_HEIGHT / 2
    STRUT_BOTTOM_Z = TABLE_HEIGHT / 2 - STRUT_HEIGHT / 2
    STRUT_CENTER_Z = TABLE_HEIGHT / 2
    
    # --- Utility Functions ---
    
    def clear_scene():
        &quot;&quot;&quot;Removes all objects from the current scene.&quot;&quot;&quot;
        bpy.ops.object.select_all(action=&#039;DESELECT&#039;)
        bpy.ops.object.select_all(action=&#039;SELECT&#039;)
        bpy.ops.object.delete(use_global=False)
    
    def create_material(name, color, metallic=0.0, roughness=0.5):
        &quot;&quot;&quot;Creates a simple PBR material.&quot;&quot;&quot;
        if name in bpy.data.materials: return bpy.data.materials[name]
        mat = bpy.data.materials.new(name=name); mat.use_nodes = True
        bsdf = mat.node_tree.nodes[&quot;Principled BSDF&quot;]
        bsdf.inputs[&#039;Base Color&#039;].default_value = color
        bsdf.inputs[&#039;Metallic&#039;].default_value = metallic
        bsdf.inputs[&#039;Roughness&#039;].default_value = roughness
        return mat
    
    def apply_material(obj, mat):
        &quot;&quot;&quot;Applies a material to a given object.&quot;&quot;&quot;
        if obj.data.materials: obj.data.materials[0] = mat
        else: obj.data.materials.append(mat)
    
    def create_cylinder_between_points(start_loc, end_loc, radius, name, material, vertices=LOW_POLY_VERTICES):
        &quot;&quot;&quot;Creates a cylinder and aligns it between two vector locations.&quot;&quot;&quot;
        center = (start_loc + end_loc) / 2; direction = end_loc - start_loc
        length = direction.length
        bpy.ops.mesh.primitive_cylinder_add(vertices=vertices, radius=radius, depth=length, location=center)
        obj = bpy.context.object; obj.name = name; apply_material(obj, material)
        if length &gt; 0.0001:
            rotation_quat = direction.normalized().to_track_quat(&#039;Z&#039;, &#039;Y&#039;)
            obj.rotation_euler = rotation_quat.to_euler()
        return obj
    
    def create_joint(location, size, name, material):
        &quot;&quot;&quot;Creates a low-poly sphere at a connection point.&quot;&quot;&quot;
        bpy.ops.mesh.primitive_uv_sphere_add(
            segments=LOW_POLY_VERTICES, ring_count=LOW_POLY_VERTICES // 2,
            radius=size / 2, location=location
        )
        obj = bpy.context.object; obj.name = name; apply_material(obj, material)
        return obj
    
    # --- Main Generation Logic ---
    
    def generate_square_floating_table():
        clear_scene()
        
        # Define Materials
        WOOD_MATERIAL = create_material(&quot;Wood_Material&quot;, (0.5, 0.25, 0.0, 1.0), roughness=0.8)
        CABLE_MATERIAL = create_material(&quot;Cable_Material&quot;, (0.1, 0.1, 0.1, 1.0), metallic=0.0, roughness=0.9)
        JOINT_MATERIAL = create_material(&quot;Joint_Material&quot;, (0.1, 0.3, 0.5, 1.0), metallic=0.2, roughness=0.4) 
        
        # --- 1. Define Points ---
        
        half_side = SIDE_LENGTH / 2
        
        # Base Corners (Z-level of base surface)
        base_surface_z = BASE_BOTTOM_Z + BASE_THICKNESS/2
        base_pts = [
            Vector(( half_side,  half_side, base_surface_z)),
            Vector((-half_side,  half_side, base_surface_z)),
            Vector((-half_side, -half_side, base_surface_z)),
            Vector(( half_side, -half_side, base_surface_z))
        ]
        # Tabletop Corners (Z-level of top surface)
        top_surface_z = TABLE_TOP_Z - TOP_THICKNESS/2
        top_pts = [p + Vector((0, 0, TABLE_HEIGHT)) for p in base_pts]
        
        # Cable Anchor Points (Midpoints of table/base edges)
        # These points are closer to the center to suspend the central strut
        anchor_radius = SIDE_LENGTH * 0.25 
        
        base_anchor_pts = [
            Vector(( anchor_radius,  0, base_surface_z)),
            Vector((0, anchor_radius, base_surface_z)),
            Vector((-anchor_radius, 0, base_surface_z)),
            Vector((0, -anchor_radius, base_surface_z))
        ]
        top_anchor_pts = [p + Vector((0, 0, TABLE_HEIGHT)) for p in base_anchor_pts]
        
        # All points for joint creation
        all_points = base_pts + top_pts + base_anchor_pts + top_anchor_pts + [Vector((0,0,STRUT_TOP_Z)), Vector((0,0,STRUT_BOTTOM_Z))]
    
        # --- 2. Create Tabletop and Base (Compression Plates) ---
        
        # Table Top (Square Cube)
        bpy.ops.mesh.primitive_cube_add(
            size=SIDE_LENGTH,
            location=(0, 0, TABLE_TOP_Z),
            scale=(1, 1, TOP_THICKNESS / SIDE_LENGTH)
        )
        obj = bpy.context.object; obj.name = &quot;Table_Top&quot;; apply_material(obj, WOOD_MATERIAL)
        
        # Base (Square Cube)
        bpy.ops.mesh.primitive_cube_add(
            size=SIDE_LENGTH,
            location=(0, 0, BASE_BOTTOM_Z),
            scale=(1, 1, BASE_THICKNESS / SIDE_LENGTH)
        )
        obj = bpy.context.object; obj.name = &quot;Base_Bottom&quot;; apply_material(obj, WOOD_MATERIAL)
    
        # --- 3. Create Central Strut (Compression) ---
        bpy.ops.mesh.primitive_cube_add(
            size=STRUT_THICKNESS,
            location=(0, 0, STRUT_CENTER_Z),
            scale=(1, 1, STRUT_HEIGHT / STRUT_THICKNESS)
        )
        obj = bpy.context.object; obj.name = &quot;Central_Strut&quot;; apply_material(obj, WOOD_MATERIAL)
    
        # --- 4. Create Cables and Joints (Tension) ---
        
        # a) Main Tensegrity Cables (4 diagonal, providing overall stability)
        # These run from the base corners to the OPPOSITE side tabletop corners (i+2 is more stable than i+1)
        for i in range(4):
            create_cylinder_between_points(
                base_pts[i], top_pts[(i + 2) % 4], CABLE_THICKNESS / 2, f&quot;Cable_Main_{i+1}&quot;, CABLE_MATERIAL
            )
            
        # b) Central Strut Suspension Cables (8 total, connecting strut to plates)
        strut_top = Vector((0, 0, STRUT_TOP_Z))
        strut_bottom = Vector((0, 0, STRUT_BOTTOM_Z))
        
        for i in range(4):
            # Top Strut to Tabletop Anchors
            create_cylinder_between_points(
                strut_top, top_anchor_pts[i], CABLE_THICKNESS / 2, f&quot;Cable_Strut_Top_{i+1}&quot;, CABLE_MATERIAL
            )
            # Bottom Strut to Base Anchors
            create_cylinder_between_points(
                strut_bottom, base_anchor_pts[i], CABLE_THICKNESS / 2, f&quot;Cable_Strut_Bottom_{i+1}&quot;, CABLE_MATERIAL
            )
    
        # c) Place Spheres (Joints) at all cable attachment points
        for i, loc in enumerate(all_points):
            create_joint(loc, JOINT_SIZE, f&quot;Joint_{i}&quot;, JOINT_MATERIAL)
    
    
    # --- Execution ---
    
    if __name__ == &quot;__main__&quot;:
        generate_square_floating_table()
        print(f&quot;\n--- Square Tensegrity Table (Floating Strut Design) generation complete! ---&quot;)
    
    

    This script clears the scene, uses simple math to calculate the positions of the three struts, creates those struts as **low-poly cubes**, connects the top and bottom points with **simple edges** (our cables), and then exports the final model as a **GLB file**.

    How to Run the Python Script from the Command Line

    To run your low_poly_tensegrity_table.py script using the Blender Python interpreter, open your Terminal (macOS/Linux) or Command Prompt/PowerShell (Windows) and use the following format:

    /path/to/blender -b -P low_poly_tensegrity_table.py
    • Replace /path/to/blender with the actual path to your Blender executable (e.g., on Windows: "C:\Program Files\Blender Foundation\Blender\blender.exe").
    • The -b flag tells Blender to run in background mode (headless), meaning the graphical user interface won’t load-it’s faster!
    • The -P flag specifies the Python script Blender should execute.

    This command will run your script, which should be set up to export the generated Tensegrity Table as a 3D file format suitable for the web, like GLB or GLTF.

    Step 2: Displaying the Model on the Web with <model-viewer>

    Once you have your low_poly_tensegrity.glb file exported from Blender, it’s time to put it on a webpage! The <model-viewer> custom web element makes embedding interactive 3D models incredibly easy, often without needing complex frameworks.

    1. Include the Library: In the <head> of your HTML file, include the <model-viewer> script:
      &lt;script type="module" src="https://ajax.googleapis.com/ajax/libs/model-viewer/3.4.0/model-viewer.min.js"&gt;&lt;/script&gt;
    2. Add the Element: Place the <model-viewer> tag in the <body> of your HTML, pointing to your exported model file:
      &lt;model-viewer
      src="low_poly_tensegrity.glb"
      alt="A Low-Poly Tensegrity Table generated with Blender Python"
      shadow-intensity="1"
      camera-controls
      touch-action="pan"
      auto-rotate&gt;
      &lt;/model-viewer&gt;

    The attributes like camera-controls and auto-rotate allow users to interact with your 3D model (rotate, zoom, pan) right in their browser!

    📸 Screenshots & Screencast

    Low poly tensegrity table Python code
    Blender Scripting Workspace Displaying Low Poly Tensegrity Table Python Code

    Low poly tensegrity table in Blender
    Blender Layout Workspace Displaying Low Poly Tensegrity Table

    Low poly tensegrity table in Web browser
    Web Browser Displaying Rendered Low Poly Tensegrity Table

    Screencast For Blender Python API Low Poly Tensegrity Table

    Resources to Keep Learning

    Ready to dive deeper into Python and Blender scripting? Check out these resources!

    My Books:

    My Course:

    One-on-One Tutoring:

    • Need personalized help with Python, including the Blender Python API? I’m available for one-on-one online Python tutorials.

      Contact me for availability: https://ojambo.com/contact

    Happy coding and happy modeling!

  • Getting Started with Gitblit: A Guide to Installation and Setup

    Getting Started with Gitblit: A Guide to Installation and Setup


    Gitblit: Your Easy Open Source Git Server for Beginners

    Are you new to programming and looking for a simple, self-hosted way to manage your Git repositories? Look no further than Gitblit!

    What is Gitblit?

    In simple terms, Gitblit is a pure Java stack for managing, viewing, and accessing Git repositories. Think of it as your own personal, lightweight GitHub that you can run on your own server or even your laptop. It’s incredibly easy to set up and is an excellent choice for individuals, small teams, or anyone who needs a private Git solution without the complexity of larger enterprise tools.

    One of the best things about Gitblit is that it is open source. This means it’s code is freely available, constantly being reviewed and improved by a community of developers, and you don’t have to pay a licensing fee to use it!

    Why Choose Gitblit?

    1. Ease of Use: Gitblit is famous for its simple, user-friendly interface. Getting a repository set up and browsing the code is a breeze.
    2. Lightweight: It doesn’t require a large amount of resources, making it perfect for smaller servers or running locally for testing.
    3. Cross-Platform: Since it’s built with Java, it runs effortlessly on Windows, macOS, and Linux.
    4. No Databases Required: Gitblit can use files for user authentication and repository storage, simplifying the initial setup immensely.

    Installation Example: Running Gitblit with Podman

    For modern deployments, using a containerization tool like Podman (or Docker) is the easiest and most reliable way to get Gitblit running. We’ll use a podman-compose setup, which is similar to Docker Compose, to define and run the service.

    First, you’ll need Podman and Podman-Compose installed on your system.

    1. Create a podman-compose.yaml file:

    This file tells Podman exactly how to build and run your Gitblit container.

    version: '3.8'
    services:
      gitblit:
        image: gitblit/gitblit:latest
        container_name: gitblit_server
        # Map a directory on your computer to where Gitblit stores its data and repositories
        volumes:
          - ./data:/opt/gitblit/data
        # Map the container's port 8080 (HTTP) and 29418 (Git Protocol) 
        # to accessible ports on your machine.
        ports:
          - "8080:8080"
          - "29418:29418"
        restart: always

    2. Run the Service:

    Navigate to the directory where you saved the podman-compose.yaml file and run:

    podman-compose up -d

    The -d flag runs the container in “detached” mode, meaning it will run in the background.

    3. Access Gitblit:

    After a few moments, your Gitblit server will be running! You can access the web interface by opening your browser and navigating to:

    http://localhost:8080

    The default administrator username is admin and the password is admin. Make sure to change this immediately after your first login!

    Screenshots and Screencast Tutorial

    SSH Key
    Command Line Podman Generating SSH Key pair

    Compose YAML
    Gnome Text Editor Displaying Podman Compose YAML File

    Gitblit Container
    Command Line Podman Compose Building Gitblit Container

    Gitblit Dashboard
    Web Browser Displaying Gitblit Dashboard

    Gitblit New Repo
    Web Browser Displaying Gitblit Repository Creation

    Gitblit Repo Summary
    Web Browser Displaying Gitblit Repository Summary

    Gitblit SSH Keys
    Web Browser Displaying Gitblit SSH Keys

    Gitblit Clone Repo
    Command Line Pushing To Cloning Gitblit Repository

    Gitblit Repo Push
    Command Line Pushing To Gitblit Repository

    Gitblit Updated Repo Summary
    Web Browser Displaying Gitblit Updated Repo Summary

    Gitblit Repo Tree
    Web Browser Displaying Gitblit Repo Tree

    Screencast Of Gitblit Setup

    Ready to Learn More?

    If you’re interested in diving deeper into programming, version control, and setting up tools like Gitblit, I can help!

    Happy coding, and enjoy your new open-source Git server!

  • Zed 0.208.4 Advanced Editor Review

    Zed 0.208.4 Advanced Editor Review

    Zed: Your Next Code Editor? A Beginner’s Guide to the Open Source Speed Demon

    If you’ve been looking for a code editor that feels truly **fast**, responsive, and built for modern development, you need to meet **Zed**. Unlike many of today’s popular editors that are built on web technologies, Zed is engineered from the ground up in the Rust programming language to leverage your computer’s hardware, including the GPU, to deliver an experience with virtually zero lag.

    It’s been described as “remarkably responsive,” and for good reason-it’s designed to be the next-generation tool for developers.

    Lightning-Fast and Built for Collaboration

    Zed isn’t just fast; it’s packed with modern features:

    • **Blazing Speed:** The core experience is all about speed. From startup time to keystroke response, Zed is built for minimal latency, making your coding flow feel seamless.
    • **Real-Time Collaboration:** One of its standout features is built-in, real-time “multiplayer” collaboration. You can invite a teammate into your project to co-edit code, share terminals, and even chat-all from within the editor.
    • **AI Integration:** Zed smoothly integrates with Large Language Models (LLMs), allowing you to use AI to explain code, generate snippets, and assist with complex refactoring right within your workflow.

    Open Source and Licensing

    In a major move for the community, Zed is **open source**! This means its source code is publicly available, allowing anyone to inspect it, suggest improvements, and build upon it.

    The Zed code editor is primarily licensed under the **GNU General Public License (GPL) version 3**, which is a popular and robust license for open source software. This commitment to being open source makes Zed a transparent and community-driven project.

    How to Install Zed on Different Platforms (Focus on Fedora Linux)

    Zed supports the major operating systems, but as a Linux enthusiast, I want to focus on getting you set up on **Fedora**.

    Installation for Fedora Linux

    While you can often find third-party packages in Fedora’s COPR repositories, the most straightforward and officially recommended way to install Zed on Linux distributions like Fedora is by using the official installation script.

    1. **Open your Terminal** (Ctrl + Alt + T).
    2. **Run the official install script:** This script downloads the stable binary and places it in your local application directory (~/.local).
      curl -f https://zed.dev/install.sh | sh
    3. **Start Coding:** Once the script finishes, you should be able to launch the editor by typing zed in your terminal or by finding it in your application launcher!

    Note: Zed requires a Vulkan-compatible GPU for optimal performance, as it uses your graphics card for rendering a smoother UI.

    Installation for Other Platforms

    • **macOS:** You can download the native installer from the official Zed website or install it using **Homebrew**:
      brew install --cask zed
    • **Windows:** Zed is also available on Windows. You can download the stable release directly from the official Zed website. It also features integration with the Windows Subsystem for Linux (WSL).

    Screenshots and Screencast

    Zed Installation
    Command Line Displaying Displaying Zed Install

    Zed Intial Settings
    Zed Displaying Initial Settings Dialog

    Zed Extensions View
    Zed Displaying Extensions

    Zed Settings View
    Zed Displaying Settings

    Zed PHP Syntax Highlighting
    Zed Displaying PHP Syntax Highlighting

    Zed Folder View
    Zed Displaying Folder In Workspace

    Zed Terminal View
    Zed Displaying Terminal In Workspace

    👉 Screencast showing a beginner session in Zed—editing, saving files, and navigating buffers.

    Zed Review And Feature Test

    Requirements For Programming Text Editor

    Glossary:

    Code Editor

    Designed for writing and editing source code.

    IDE

    Integrated Development Environment combines various tools need for software development.

    Plugin

    Software component that adds specific functionality.

    Theme

    Preset package containing graphical appearance to customize look and feel.

    Open source

    Freely available for possible modification and redistribution.

    SCM

    Source code management use to manage and track modifications to a source code repository.

    LMB

    Left Mouse Button (LMB) or left click

    MMB

    Middle Mouse Button (MMB) or scroll wheel

    Test Tools

    Test System
    Name Description
    CPU Ryzen 5 5600GT @ 3.60GHz.
    Memory 32GB DDR4.
    Operating System Fedora Linux Workstation 42.
    Desktop Environment Gnome 48.
    Name Description

    Test Suite
    Name Description
    Large File 1GB human-readable text.
    Regex File Text with word “Zed” repeated.
    Syntax File PHP file containing HTML, CSS & JavaScript.
    Media File Smiley face or Tux Linux JPEG file.
    Java Version OpenJDK 21.0.8.
    PHP Version PHP 8.4.13.
    Python Version Python 3.13.7.
    Zed Version 0.208.4.
    Name Description

    Test Scoring

    1. Each feature has two parts.
    2. Score of zero indicates a missing feature.
    3. A part of a feature is work a score of 0.5.

    Three bias elimination steps were utilized. The editor was used for at least three years on different platforms. Attempts were made to get stable plug-ins for missing features. The same editor was compared between the one in the repository, the developers website, and the compiled version if applicable.

    Selecting Editor Version

    For this review, Zed was installed using the instructions from the developers website and it did not require additional plugins.

    Features

    1. The theme can be native for the editor in terms of the background. Zed dark and light themes can be created or downloaded and changed. The score for the theme was a perfect 1.0.
    2. Dragging and dropping a text file into the editor opens a new tab or buffer. It is not possible to specify the tab location during the drag and drop operation. The score for drag and drop into editor was 0.5.
    3. Opening a very large text file did not crash Zed. Zed was able to open or to edit the large file. The score for opening a large file was 1.0.
    4. Multiple documents can opened in multiple tabs or buffers. Tear-off tabs do not work and Zed does not have a feature to open in new window as a new instance which is handy for multiple monitors. The score for multiple documents was 0.5.
    5. Multiple editors can be opened as new tabs with drag options. Each tab window view can be split either vertically or horizontally as a multiple editor view in Wayland display server protocol. The score for multiple editor view was 1.0.
    6. Creating non-project files is possible. Non-project files can be opened on the command line. The score for creating non-project files was a perfect 1.0.
    7. Soft word wrap can be enabled on all documents as wrapping. Automatic soft wrap for documents is available from the Zed View menu. The score for word wrap was a perfect 1.0.
    8. Spell check does work as words are typed by enabling the extension Codebook Spell Checker. Spelling errors are shown in opened documents. The score for spell check was 1.0.
    9. Word count is not available. Word count for the current buffer or file is not enabled. Selection word count is not available as part of word count. The score for word count was 0.0.
    10. Go to line can jump to a specified line using CTRL-G and entering the line number. It is possible to jump to either the first or last line. The score for go to line is a perfect 1.0.
    11. Indentation can default to user-defined tab stops. Children are automatically indented. The score for indentation was a perfect 1.0.
    12. Fonts can be dynamically scaled with custom keyboard shortcuts CTRL-+/-. The system font can be bypassed and a new editor font and size can be set. The score for fonts was a perfect 1.0.
    13. Find and replace using regular expressions can be utilized for all open documents in the current session. Find and replace will work for the current document or a selection in the current document. The score for find and replacing using regular expressions was a perfect 1.0.
    14. Multiple language syntax highlighting in one file is enabled. Each language has code-sensitive syntax colours. The score for multiple language syntax highlighting was a perfect 1.0.
    15. Code folding does work for markup languages such as HTML. Code folding also works for programming languages such as Java. The score for code folding was 1.0.
    16. Selecting rectangular block per column works using CTRL-SHIFT. Rectangular block selection works with word wrap enabled. The score for selecting rectangular block was a perfect 1.0.
    17. Multiple selection is available using ALT. Search multiple selection does not work. The score for multiple selection was 0.5.
    18. Distraction-free mode to hide panes works. Line numbers can not be toggled to improve distraction-free mode. The score for distraction-free was a perfect 1.0.
    19. The file manager can be enabled by default. Media files can be dragged and dropped into the file manager pane. The score for file manager was 1.0.
    20. Terminal is be enabled. The terminal does follow folder. Terminal can execute system commands. The score for terminal was 1.0.

    Results

    Zed is a lightweight IDE. By default, the Zed editor is missing required features that can be enabled or implemented by plugins. For my required features, the Zed editor scored 87.5% or 8.75 out of 10.

    Next Steps in Your Programming Journey

    Whether you’re just starting out or looking to sharpen your skills, using a fast and reliable editor like Zed is only the beginning.

    I have a collection of **programming books** available on my Amazon Author Page that cover a range of topics to help you master your craft:

    ➡ **Explore my Programming Books:**
    https://www.amazon.com/stores/Edward-Ojambo/author/B0D94QM76N

    If you prefer structured learning, my **programming courses** offer in-depth lessons and practical projects:

    ➡ **View Programming Courses:**
    https://ojamboshop.com/product-category/course

    Need Personalized Help?

    If you’re finding a particular topic challenging or want to rapidly accelerate your learning, I’m available for **one-on-one online programming tutorials**. We can work through specific problems, review code, and set a learning path tailored just for you.

    ➡ **Book a Tutorial Session:**
    https://ojambo.com/contact

    Do you love the look of Zed but need help getting it set up on your specific system, or are you looking to migrate from an older editor? I offer specialized technical services to ensure your development environment is running perfectly:

    ➡ **Get Help Installing Zed or Migrating Your Setup:**
    https://ojamboservices.com/contact

    Happy Coding!

  • How to Install LibreOffice Online Office Suite

    How to Install LibreOffice Online Office Suite

    How to Use LibreOffice Online: Open Source Office Suite in Your Browser

    If you have ever wanted a private, open-source alternative to Google Docs or Microsoft Office Online, LibreOffice Online is a great choice. It is the web-based version of the popular LibreOffice suite, allowing you to edit documents, spreadsheets, and presentations right from your browser.

    In this post, we will go over what LibreOffice Online is, how to install it using Podman or Podman Compose, and where you can get additional help and programming resources.

    What is LibreOffice Online?

    LibreOffice Online is the cloud version of the LibreOffice suite. It allows users to:

    • Create and edit documents, spreadsheets, and presentations directly in the browser
    • Collaborate in real-time with multiple users
    • Maintain full control over their data (since you can host it yourself)

    It is completely open-source, which means anyone can use, modify, and distribute it freely.

    Installing LibreOffice Online Using Podman

    You can run LibreOffice Online in containers using Podman, a daemonless alternative to Docker.

    Here is a basic example setup using Podman Compose. This example uses Collabora CODE, a popular implementation of LibreOffice Online.

    Prerequisites: Podman, podman-compose, and a domain name with SSL (optional but recommended for production)

    1. Create a Project Folder

    mkdir libreoffice-online &amp;&amp; cd libreoffice-online

    2. Create a podman-compose.yml File

    version: "3"
    
    services:
      collabora:
        image: collabora/code
        container_name: libreoffice-online
        restart: always
        ports:
          - "9980:9980"
        environment:
          - domain=your\\.domain\\.com
          - username=admin
          - password=securepassword
          - extra_params=--o:ssl.enable=false

    Replace your\\.domain\\.com with the domain you will use.

    For testing purposes, --o:ssl.enable=false disables SSL. In production, you should reverse proxy with NGINX and Let’s Encrypt.

    3. Start the Service

    podman-compose up -d

    LibreOffice Online should now be running at:
    http://localhost:9980

    📷 Screenshots & 📽️ Screencast

    Collabora Online Frontend Containerfile
    Gnome Text Editor Displaying Collabora Online Frontend Container Containerfile

    Collabora Online Backend Containerfile
    Gnome Text Editor Displaying Collabora Online Backend Container Containerfile

    Collabora Online Nginx Configuration
    Gnome Text Editor Displaying Collabora Online Nginx Virtual Host Configuration

    Collabora Online Backend Python
    Gnome Text Editor Displaying Collabora Online Backend Handling Python Script

    Collabora Online Iframe
    Gnome Text Editor Displaying Collabora Online Iframe HTML

    Collabora Online YAML Compose
    Gnome Text Editor Displaying Collabora Online Podman Compose YAML

    Collabora Online Podman Container
    Command Line Displaying Collabora Online Podman Compose Container

    Collabora Online Hosting Discovery
    Web Browser Displaying Collabora Online Hosting Discovery XML

    Collabora Online Admin URL OK
    Web Browser Displaying Collabora Online Admin URL OK

    Collabora Online Admin Login Prompt
    Web Browser Displaying Collabora Online Admin Authentication Prompt

    Collabora Online Admin Console
    Web Browser Displaying Collabora Online Admin Console Dashboard

    Collabora Online Loaded Document
    Web Browser Displaying Collabora Online Loaded Document For Editing

    Collabora Online Installation And Setup Screencast

    More Resources from Edward Ojambo

    I have written and recorded several programming tutorials and courses that can help you learn and grow as a developer:

    Final Thoughts

    LibreOffice Online is a powerful tool for anyone who wants control over their online document editing. Using Podman, you can set it up in minutes and begin editing documents securely in your own environment.

    Whether you are learning to code, managing your own server, or just curious about self-hosting, LibreOffice Online is a great addition to your toolkit.

  • Review Generative AI Wan 2.2 TI2V 5B Model

    Review Generative AI Wan 2.2 TI2V 5B Model

    Getting Started with Wan 2.2 TI2V 5B Running in ComfyUI: An Open-Source Powerhouse for AI Projects

    Wan 2.2 TI2V 5B is an exciting, cutting-edge AI model that can supercharge your projects in fields like natural language processing, image generation, and more. Running it within ComfyUI, an easy-to-use graphical user interface, allows you to harness the model’s power without worrying about coding complexities. Plus, Wan 2.2 TI2V 5B is open-source and licensed under the Apache 2.0 License, making it accessible for both personal and commercial use.

    In this post, I’ll walk you through the installation process, explain the features of this model, and clarify how its open-source license impacts your usage.

    What is Wan 2.2 TI2V 5B?

    Wan 2.2 TI2V 5B is a powerful AI model designed for advanced machine learning tasks. It has been trained to generate high-quality outputs based on large datasets, making it an excellent choice for those working with text, images, or other types of data.

    Running Wan 2.2 TI2V 5B in ComfyUI makes it much easier to interact with the model. ComfyUI provides a user-friendly graphical interface that abstracts away the need for complex command-line operations or programming, making it ideal for both beginners and advanced users alike.

    The Apache 2.0 License: What Does It Mean?

    One of the best parts of using Wan 2.2 TI2V 5B and ComfyUI is that they are open-source and distributed under the Apache 2.0 License. Here’s what this means:

    • Free to Use: You can use the model for personal and commercial purposes without needing permission.
    • Modify and Distribute: You are allowed to modify the model and share your modified versions. If you do redistribute, you must provide a copy of the license and credit the original authors.
    • Patent Grant: The Apache 2.0 License includes a patent grant, meaning contributors cannot sue you for using patented technology that’s part of the model.
    • No Warranty: The model comes without any warranty. You’re using it at your own risk, but the flexibility and power it provides are worth it for many developers.

    By being released under the Apache 2.0 License, Wan 2.2 TI2V 5B encourages collaboration and innovation within the open-source community, which leads to faster improvements and wider accessibility.

    Installation Guide for Wan 2.2 TI2V 5B in ComfyUI

    Here’s a beginner-friendly step-by-step guide to get Wan 2.2 TI2V 5B running in ComfyUI.

    Step 1: Install Python and Dependencies

    First, ensure that you have Python 3.8+ installed on your system. You will also need a few key dependencies.

    1. Install Python: Download and install Python from python.org.
    2. Set Up a Virtual Environment (optional but recommended):
      python -m venv comfyenv
      source comfyenv/bin/activate  # On Windows use comfyenv\Scripts\activate
    3. Install Dependencies: Use pip to install the required libraries.
      pip install -r requirements.txt

    Step 2: Clone the Wan 2.2 TI2V 5B Repository

    Now, you’ll need to clone the Wan 2.2 TI2V 5B repository.

    1. Clone the GitHub Repository:
      git clone https://github.com/Wan-Video/Wan2.2.git
      cd Wan2.2

    Step 3: Clone the ComfyUI Repository

    Next, clone ComfyUI from its official GitHub repository:

    git clone https://github.com/comfyanonymous/ComfyUI.git
    cd ComfyUI

    At this point, you should have both ComfyUI and Wan 2.2 TI2V 5B cloned onto your machine.

    Step 4: Place the Model Files in the Correct Folder

    Now, let’s get the model files into the correct location.

    1. Download the Wan 2.2 TI2V 5B Model: Go to the Hugging Face page for Wan 2.2 TI2V 5B and download the model file (it will likely be a .pth or .bin file).
    2. Find the “Models” Folder in ComfyUI: Inside the ComfyUI folder, you will see a folder called models. This is where you need to place the Wan 2.2 TI2V 5B model file.
    3. Place the Model File in the “Models” Folder: Move or copy the Wan 2.2 TI2V 5B model file into the models folder inside ComfyUI.

    Step 5: Configure ComfyUI to Use the Model (if needed)

    In most cases, ComfyUI will automatically detect the model. However, if needed, you may have to configure ComfyUI to recognize the model:

    1. Open the ComfyUI settings file (usually named config.json or similar).
    2. If you need to manually configure the model path, make sure it points to the correct file in the models folder:
      {
        "model_path": "models/Wan2.2_TI2V_5B.pth"
      }

    Step 6: Launch ComfyUI

    Once the model file is in place, you’re ready to start ComfyUI.

    1. Open a terminal (or command prompt) in the ComfyUI folder and run:
      python app.py
    2. Visit http://localhost:5000 in your web browser to start interacting with Wan 2.2 TI2V 5B through the ComfyUI interface.

    📷 Screenshots

    ComfyUI With Wan 2.2 TI2V 5B Setup
    ComfyUI With Wan 2.2 TI2V 5B Default Nodes.

    CoolerControl Showing AMD GPU Idle Temperature
    CoolerControl Showing Idle AMD CPU AND GPUs Temperatures.

    CoolerControl Showing AMD GPU Computation Temperature
    CoolerControl Showing Computation AMD CPU AND GPUs Temperatures.

    File manager Showing Generated Videos
    Gnome Files Displaying Generated Video Files.

    ComfyUI Generated Video Status
    Command Line Displaying Status Of Video Generation.

    ▶️ Screencast

    Watch my real-time demo of Wan 2.2 TI2V 5B on Linux:

    Video Displaying ComfyUI With Wan 2.2 TI2V 5B Setup

    Results:

    0 second 512×512 24FPS Video

    Produced vertical pixelated video in Quicktime container.

    1 second 512×512 24FPS Video

    Produced vertical low resolution video in Quicktime container.

    1 second 512×512 24FPS Video

    Produced vertical low resolution subway platform video in Quicktime container.

    1 second 896×512 24FPS Video

    Produced wide angle low resolution subway platform video in Quicktime container.

    1 second 1280×704 24FPS Video

    Took a very long time and seems to be stuck after loading WanVAE.

    Learn Python with My Resources

    If you’re new to Python or want to deepen your understanding, I have resources that can help you:

    • Book: Check out my book, Learning Python, which is designed for beginners and will guide you step-by-step through the basics of Python programming.
    • Online Course: My course, Learning Python, offers a comprehensive curriculum that covers essential Python concepts and practical applications.
    • One-on-One Python Tutorials: If you need personalized guidance, I offer one-on-one online Python tutorials. Learn at your own pace—contact me here to schedule a session.

    Need Help with Wan 2.2 TI2V 5B Installation?

    If you want to install or migrate Wan 2.2 TI2V 5B, I’m available to assist you with that. I can walk you through the process or set it up for you. Get in touch with me via this contact form.

    Conclusion

    Wan 2.2 TI2V 5B running in ComfyUI is a powerful, flexible, and open-source solution for AI projects. With the Apache 2.0 License, you have the freedom to use, modify, and distribute the model, enabling innovation and collaboration. I hope this guide helps you get up and running quickly with Wan 2.2 TI2V 5B.