The regex does not identify all matching strings. It feels like a JS bug [closed]

const text = ":apple: fsd<@viktor>fsd text :apple :apple: banana 2332 <@maria> :apple: nice <@maria> :apple:"
console.log("ALL APPLES")
console.log(text.match(/:apple:/g))
console.log("-------------")

/**
 * 
 * @param {string} text 
 */
function countApples(text) {
    const matches = text.matchAll(/(?<name>(?<=<@)w+)>(?<text>[a-z0-9s:]+(?=<@|$))/g);
    for (const match of matches) {
        console.log(`Text group: ${match.groups.text}`)
        console.log(match.groups.text.match(/:apple:/g))
        console.log("-------------")
    }
}

countApples(text)

This is the output

ALL APPLES
[ ':apple:', ':apple:', ':apple:', ':apple:' ]
-------------
Text group: fsd text :apple :apple: banana 2332 
[ ':apple:' ]
-------------
Text group:  :apple: nice 
[ ':apple:' ]
-------------
Text group:  :apple:
[ ':apple:' ]
-------------

Does anyone have any idea why the output from the first text group is a single :apple: and not :apple: :apple:?

Drag event between browser tabs using fullcalendar

I want to use Fullcalendars External-DragNDrop-Functionality, but I can’t manage to drag the event from a seperate Browser-Tab.

Is there any possibilty to achieve this?

What I tried is to test with the Demo-Sites of FullCalendar(Duplicate the Tab and try to drag one of the events to the other Browser-Tab. I tested with my implementations before and this might sound stupid, but if it doesn’t work in their own demo, where else?
The demo can be found here.

Where are resolved values of promises stored?

I’ve been following a tutorial on full-stack development. On the client side, there is an api.js file, which contains the following code snippet:

var API = {

   api: axios.create({ baseURL: "http://localhost:5000/api" }),

   // a bunch of functions

   getAllAuthors: function() {
      return this.api.get(`/author`)
      .then(response => response.data)
   },

   // a bunch of functions
}

And there is also an actions.js file, which contains the following:

var actions = {

   // a bunch of functions
   
   refreshMessage: function(author) {
      if (!author) {
         API.getAllAuthors().then(response => {
         
            // some code
         
         })
      }
   }

   // a bunch of functions
}

I was initially confused about that second then() because I thought that a resolved promise (API.getAllAuthors() in this case) returns the resolved value (response.data in this case). It seemed like the second then() was called on what would be a string or a JavaScript object. But now I know (or think I know) that thens don’t just register a callback for the previous promise, they also create a new one which is going to be resolved with the value that the callback is going to spit out when it’s run.

I quickly created
a diagram to visualize my current understanding of this whole thing

Essentially, every then() creates a new promise and registers a callback that uses the resolved value associated with the previous promise, which is stored somewhere, hidden from the user (by that I mean that it’s not a property of the promise, though I’m not entirely sure where the resolved value “lives”). When the previous promise is fulfilled, its value gets passed on to the registered callback. And whatever THAT callback spits out is going to be stored somewhere and “associated” with the new promise. Is my current understanding correct? And where is this somewhere?

How to allow iframes or raw HTML inside Trix Editor in Rails (ActionText)?

I’m using Trix Editor via ActionText in a Ruby on Rails 7 application.

When I paste raw HTML like a YouTube or Vimeo into the Trix editor, it automatically escapes the tags. For example:

<iframe src="https://player.vimeo.com/video/123"></iframe>

Becomes:

&lt;iframe src="https://player.vimeo.com/video/123"&gt;&lt;/iframe&gt;

This ends up in the params[:text_page][:text_es] as escaped text, and renders as plain text in the view — not as an actual iframe.

Context:
Only trusted admins use this form, so XSS isn’t a concern in this case.

I just want to allow some safe tags (like iframes from Vimeo/YouTube) and render them correctly.

Question:
Is there a clean and safe way to allow specific raw HTML tags like in Trix (ActionText) in Rails?

Or is switching to another WYSIWYG like TinyMCE/CKEditor the only reliable path?

CS50W Project network, can’t figure how to implement the Paginator

I’ve been trying to implement the paginator function for about two months now. I’ve tried many different approaches, but they always lead to new bugs.

In views.py, I load the posts and send them to JavaScript. In loadPosts and loadProfile, I pass the fetch function as a parameter to the buttons. Everything else works fine. The buttons call the fetch function, and the posts are displayed.

The issue is: once I load the second page of profile posts, then switch to loadPosts and click “next” again, it loads the profile posts instead. I’ve already tried using removeEventListener and flags, but I couldn’t figure out how to properly reset the event listener when switching between the functions.

[06/Jun/2025 09:01:10] “GET /post?start=0&end=9 HTTP/1.1” 200 825
[06/Jun/2025 09:01:10] “GET /post/new?start=0&end=9 HTTP/1.1” 200 810


// Switch between the pages: 

document.querySelector("#profile-link").addEventListener('click', function(event) {
        // Top left username, to load the profile
        loadProfile(loggedInUsername)
    });

document.querySelector("#index").addEventListener('click', function(event) {
        event.preventDefault();
        loadPosts()
    });



@csrf_exempt
def post_view(request, username = None):
    if request.method == "GET":
        # Loading all posts
        if username == None:
            posts = Post.objects.all().order_by('-date')
            start = int(request.GET.get("start") or 0 )
            end = int(request.GET.get("end") or (start + 9))
            posts_in_range = posts[start:end+1].values("text","date","user__username")
            return JsonResponse({"posts": list(posts_in_range)})
        else:
            # Loading a profile
            user = User.objects.get(username=username)
            user_id = user.id
            posts = Post.objects.filter(user_id=user_id).order_by('-date')
            start = int(request.GET.get("start") or 0 )
            end = int(request.GET.get("end") or (start + 9))
            posts_in_range = posts[start:end+1].values("text","date","user__username")
            return JsonResponse({"posts": list(posts_in_range)})



// Loads all the posts on the All Posts page
    function loadPosts() {
        let counter = 1;
        let start = (page - 1) * 10;
        let end = start + 9;
        if (page < 1) {
            page = 1
        }
        // Fetch all posts
        fetch(`/post?start=${start}&end=${end}`,null)
            .then(response => response.json())
            .then(data => {
                buttons(counter, `/post?start=${start}&end=${end}`)
                // Hidding buttons and content
                document.getElementById("slider").style.display = "none";
                document.querySelector("#following").innerHTML = "";
                document.querySelector("#posts").innerHTML = "";
                document.getElementById("new-post-form").style.display = "block";
                // buttons next and previous
                data.posts.forEach(add_Post);
            })
    }

    // Loading a profile page
    function loadProfile(username, loggedInUsername) {
        let counter = 1;
        let start = (page - 1) * 10;
        let end = start + 9;
        if (page < 1) {
            page = 1
        }
        // Fetch profile 
        fetch(`/post/${username}?start=${start}&end=${end}`)
            .then(response => response.json())
            .then(data => {
                console.log(username)
                buttons(counter, `/post/${username}?start=${start}&end=${end}`, username)
                document.getElementById("slider").style.display = "none";
                document.querySelector("#following").innerHTML = "";
                document.getElementById("new-post-form").style.display = "none";
                document.querySelector("#posts").innerHTML = "";
                // Checks if a username is already followed
                checkFollow(username)
                // Check if the logged in user wants to see his own profile
                if (username === loggedInUsername) {
                    // Hide the follow function so user cannot follow himself
                    document.getElementById("slider").style.display = "none";
                    // Loads posts
                    if (data.posts.length > 0) {
                        data.posts.forEach(add_Post);
                    }
                } else {
                    // Load profile content
                    document.getElementById("slider").style.display = "block";
                    const checkbox = document.querySelector('.switch input[type="checkbox"]');
                    checkbox.addEventListener('change', function(event) {
                        handleCheckboxChange(username);
                    });
                    if (data.posts.length > 0) {
                        data.posts.forEach(add_Post);
                    }
                }
            })
    }



    function buttons(counter, url, username) {
        const previous = document.getElementById("previous");
        const next = document.getElementById("next");
        console.log(username)

        // If no username fetch all posts
    if (!username) {
            function handleNextClick() {
            counter++;
            start = (counter - 1) * 10;
            end = start + 9;
            const newUrl = `/post?start=${start}&end=${end}`
            load(counter, newUrl, start, end);
        }

    function handlePreviousClick() {
            counter--;
            start = (counter - 1) * 10;
            end = start + 9;
            const newUrl = `/post?start=${start}&end=${end}`
            load(counter, newUrl, start, end);
        }


        }

        // load profile
        else {
        function handleNextClick() {
            counter++;
            start = (counter - 1) * 10;
            end = start + 9;
            const newUrl = `/post/${username}?start=${start}&end=${end}`
            load(counter, newUrl, start, end);
        }

        function handlePreviousClick() {
            counter--;
            start = (counter - 1) * 10;
            end = start + 9;
            const newUrl = `/post/${username}?start=${start}&end=${end}`
            load(counter, newUrl, start, end);
        }
    }

         function handleClick(event) {
                    if (event.target.id === "next") {
                        handleNextClick();
                    }
                    else if (event.target.id === "previous") {
                        handlePreviousClick();
                    }
                }
        fetch(url)
            .then(response => response.json())
            .then(data => {
                pageContainer.removeEventListener("click", handleClick);
                pageContainer.addEventListener("click", handleClick);
            });
        }

   // Loads the post after being called by buttons
    function load(page, newUrl, start, end) {
        console.log(load)
        fetch(newUrl)
            .then(response => response.json())
            .then(data => {
                // Clear previous posts
                document.querySelector("#posts").innerHTML = "";
                if (data.posts.length > 0) {
                    data.posts.forEach(add_Post);
                }
            });
    }

Is there any way to have a loading memory cache in PHP?

I want to avoid to use database connection to retrieve very repetitive content of my web app.

I would like to know if exists any way to use a memory cache (memcache?) with time expiration and loading feature.
Just to be clear whan I mean for time expiration and loading feature it is something like Java Guava LoadingCache library. A memory storage that expires after a defined time span and then provide a method to retrieve that content externally.

My goal is to use this cache for x seconds after that the content is refreshed from database.
I know the database has its own cache but for sure it makes more overhead than a memory storage.

What is the difference between PHP’s mb_strolower() and IntlChar::tolower()?

I have been testing PHP’s mb_strtolower() and IntlChar::tolower() functions. By and large they give the same results, but I notice that they give different results for the Turkish dotted I ‘İ’: mb_strtolower() gives ‘i̇’ whereas IntlChar::tolower() gives ‘i’.

Would you expect them to give the same results? Or is there another method that would give the same result as mb_strtolower()? I’m looking for an alternative to mb_strtolower() when the mbstring extension isn’t available.

repeat select users when login [closed]

I’m use default login program in laravel 12.

It’s work very well before few day ago.

When I try to login my web, it will select user again and again event I delete my update in that day.

I’m listen my query, and log is like this.

[2025-06-06 04:19:23] local.INFO: SQL Query {"sql":"select * from `users` where `id` = ? limit 1","bindings":[1],"time":0.14} 
[2025-06-06 04:19:23] local.INFO: SQL Query {"sql":"select * from `users` where `id` = ? limit 1","bindings":[1],"time":0.15} 
[2025-06-06 04:19:23] local.INFO: SQL Query {"sql":"select * from `users` where `id` = ? limit 1","bindings":[1],"time":0.16} 
[2025-06-06 04:19:23] local.INFO: SQL Query {"sql":"select * from `users` where `id` = ? limit 1","bindings":[1],"time":0.16} 
[2025-06-06 04:19:23] local.INFO: SQL Query {"sql":"select * from `users` where `id` = ? limit 1","bindings":[1],"time":0.16} 
[2025-06-06 04:19:23] local.INFO: SQL Query {"sql":"select * from `users` where `id` = ? limit 1","bindings":[1],"time":0.15} 
[2025-06-06 04:19:23] local.INFO: SQL Query {"sql":"select * from `users` where `id` = ? limit 1","bindings":[1],"time":0.15} 
[2025-06-06 04:19:23] local.INFO: SQL Query {"sql":"select * from `users` where `id` = ? limit 1","bindings":[1],"time":0.14} 
[2025-06-06 04:19:23] local.INFO: SQL Query {"sql":"select * from `users` where `id` = ? limit 1","bindings":[1],"time":0.15} 

The most weird thing is this program is work at another computer.

I found that delete this line in SessionGuard.php will fix the problem, but $request->user() will be null.

protected function updateSession($id)
{
    $this->session->put($this->getName(), $id);  // delete this line

    $this->session->migrate(true);
}

my login function in AuthenticatedSessionController

public function store(Request $request): RedirectResponse
{
    $request->validate([
       'email' => 'required|email',
       'password' => 'required',
    ]);
    $request->authenticateAccount(); // crash function

    $request->user()->createToken('api');
    return redirect('/homeManage');
}

crash function

public function authenticate(): bool
{
    $result = $this->ensureIsNotRateLimited();

    if (! Auth::attempt($this->only('email', 'password'), $this->boolean('remember'))) { // crash in this condition process
        RateLimiter::hit($this->throttleKey());

        throw ValidationException::withMessages([
            'email' => __('auth.failed'),
        ]);
    }

    RateLimiter::clear($this->throttleKey());
    return $result;
}

Can someone tell me how to fix it?

One property missing when sending FormData object

I’m submitting data to the backend. The data includes patient_name, age, date, and medication_files, which are from the active record.

The problem is that I use formData in collecting the data and sending it to the API, however, all the other data is being sent except the medication_files from the active record. I shall share some code and a screenshot to help the more experienced guys help me.

enter image description here

As you can see from the screenshot, the formData object is empty hence can not process it for the API

import { Formik, Field, Form, FieldArray, ErrorMessage } from 'formik';
import './PrescriptionForm.scss';
import { prescriptionSchema } from '../../utils/schema';
import axios from 'axios';
import { getCookie } from '../../utils/helper/tokenHandler';


const PrescriptionForm = () => {
  console.log("Debugging!!!");
  const handleSubmit = async (
    values: {
      patientName: string;
      age: number;
      gender: string;
      date: string;
      medicationFiles: File[];
    },
    { setSubmitting, resetForm }: { setSubmitting: (isSubmitting: boolean) => void; resetForm: () => void }
  ) => {
    
    const token = getCookie();

    const formData = new FormData();

    formData.append('prescription[patient_name]', values.patientName);
    formData.append('prescription[age]', values.age.toString());
    formData.append('prescription[gender]', values.gender);
    formData.append('prescription[date]', values.date);

    console.log('Type:', typeof values.medicationFiles);

    if (values.medicationFiles && values.medicationFiles.length > 0) {
      values.medicationFiles.forEach((file) => {
        formData.append('prescription[medication_files][]', file);
      });
    }

    console.log('Files appended to FormData:');
    Array.from(formData.entries()).forEach(([key, value]) => {
      console.log(`${key}:`, value);
    });

    console.log('medicationFiles:', values.medicationFiles);

    try {
      console.log("Submitting prescription with values:", values);
      console.log("Form data:", formData);
      const res = await axios.post(
        'http://localhost:3000/api/v1/prescriptions',
        formData,
        {
          headers: {
            Authorization: `Bearer ${token}`,
          },
        }
      );
      console.log(res);
      alert('Prescription submitted successfully!');
      resetForm();
    } catch (error) {
      console.error('Submit error:', error);
      if (
        typeof error === 'object' &&
        error !== null &&
        'response' in error &&
        (error as any).response?.data?.errors
      ) {
        alert('Submission failed: ' + (error as any).response.data.errors.join(', '));
      } else {
        alert('An unexpected error occurred. Please try again.');
      }
    } finally {
      setSubmitting(false);
    }
  };

  return (
    <Formik
      initialValues={{
        patientName: '',
        age: 0,
        gender: '',
        date: '',
        medicationFiles: [],
      }}
      validationSchema={prescriptionSchema}
      onSubmit={handleSubmit}
    >
      {({ values, isSubmitting, setFieldValue }) => (
        <Form className="prescription-form">
          <h2>Prescription Form</h2>

          <label>Patient Name</label>
          <Field name="patientName" />
          <ErrorMessage name="patientName" component="div" />

          <label>Age</label>
          <Field
            name="age"
            type="number"
            parse={(value: string) => (value === '' ? 0 : Number(value))}
          />
          <ErrorMessage name="age" component="div" />

          <label>Gender</label>
          <Field name="gender" as="select">
            <option value="">Select</option>
            <option value="male">Male</option>
            <option value="female">Female</option>
            <option value="other">Other</option>
          </Field>
          <ErrorMessage name="gender" component="div" />

          <label>Date</label>
          <Field name="date" type="date" />
          <ErrorMessage name="date" component="div" />

          <label>Medication File</label>
          <input
            name="medicationFiles"
            type="file"
            accept=".pdf,.doc,.docx"
            multiple
            onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
              const files = Array.from(e.currentTarget.files || []);
              setFieldValue("medicationFiles", files);
            }}
          />
          <ErrorMessage name="medicationFiles" component="div" />


          <button type="submit" disabled={isSubmitting}>Submit</button>
        </Form>
      )}
    </Formik>
  );
};

export default PrescriptionForm;

Pixi js – repeating texture for stroke

Hi I am having a hard time finding out how to set a texture of to repeat it self dynamically. Is there even a way to do that?

My use case is that I need to be able to create a 2d structure (top view), that has straight and curved walls around and inside it.

From what I was able to find using path for the walls (I want to be able to set different textures to different parts of the walls) is the best way.

const g = new PIXI.Graphics();
const path = new PIXI.GraphicsPath();

path.moveTo(100, 100);
path.lineTo(200, 100);
path.arcTo(250, 100, 250, 150, 30); // Rounded corner
path.lineTo(250, 200);

// Load texture
const baseTexture = await PIXI.Assets.load('https://pixijs.io/examples/examples/assets/bunny.png');

// ✅ Set wrap mode to REPEAT on baseTexture
baseTexture.wrapMode = PIXI.WRAP_MODES.REPEAT;
baseTexture.update(); // apply changes to GPU

// Create Texture from baseTexture (you can also reuse baseTexture directly)
const texture = new PIXI.Texture(baseTexture);

// Use the path and stroke with the texture
g.path(path);
g.stroke({ width: 12, texture: texture }); // adjust width for visibility

app.stage.addChild(g); 

Have someone encountered and handle how to this?

Set individual sound for each aframe entity

I wanna realize next functionality: user are scanning one image (it is a target, all ones are 5 item), and after than as the picture will be scan – will start playing sound (related to this image).I am using Arame library (creating scene and sound objects) and mindAR (detect of scaned photos); All are based on React function components. For test I`ve created mock:

<a-scene ref={sceneRef} mindar-image={`imageTargetSrc: http://localhost:5000/wild%20nature/wild_nature.mind; autoStart: false; uiLoading: true; uiError: true; uiScanning: true; maxTrack: 3`} color-space="sRGB" embedded renderer="colorManagement: true, physicallyCorrectLights" vr-mode-ui="enabled: false" device-orientation-permission-ui="enabled: false">
              <a-assets>
  
                   <audio id="lion" src="http://localhost:5000/wild%20nature/lion/lion.mp3" preload='auto'></audio>
                   <audio id="owl" src="http://localhost:5000/wild%20nature/owl/owl.mp3" preload='auto'></audio>


              </a-assets>
              

              <a-camera position="0 0 0" look-controls="enabled: true"></a-camera>

             
                <a-entity 
                  mindar-image-target="targetIndex: 4"
                  geometry="primitive: plane" 
                  position=" 0 0 0" 
                  sound="src:#lion;" 
                />
                <a-entity 
                  mindar-image-target="targetIndex: 3"
                  geometry="primitive: plane" 
                  position=" 0 0 0" 
                  sound="src:#owl;" 
                />
            </a-scene>

At this moment:
When I scan a lion photo – all works correctly, but when I change scaned photo to owl – sound doesn`t play.

import React, { useCallback, useEffect, useRef, useState } from 'react';
import 'aframe';
import 'mind-ar/dist/mindar-image-aframe.prod.js';
import { getChildrenByGroup } from './../utils/helpers'; 

const MindARViewer = ({children_AR_list}) => {
  
  const sceneRef = useRef(null);
  const sceneRefering= useRef([]);
  const [targetFound, setTargetFound] = useState("");

  let [targetFoundCounter,setTargetFoundCounter] = useState(0);
  const [groupedChildren, setGroupedChildren] = useState([]);

  useEffect(() => {
    setGroupedChildren(getChildrenByGroup(children_AR_list))
    
  }, []);

  useEffect(() => {
    const sceneEl = sceneRef.current;
    const arSystem = sceneEl.systems?.["mindar-image-system"];
    
    const entity = document.querySelector('a-entity[sound]');

    // Start AR system when scene starts rendering
    sceneEl.addEventListener('loaded', () => {
      arSystem.start();
    });

    // Handle target detection events
    
    sceneEl.addEventListener('targetFound', () => {
      setTargetFound(entity?.components.sound.parsingAttrValue)
      console.log(`Target found:`, entity?.components.sound.parsingAttrValue);
      
      // setTargetFoundCounter(targetFoundCounter++)

      entity?.components.sound?.playSound();
    });



    sceneEl.addEventListener('targetLost', () => {
      entity?.components.sound?.pause();
    });

    return () => {
      arSystem.stop();
      entity?.components.sound.pause();
    }
  }, []);

   



  return (
    <>
    
    {
      
      
          <>
           <a-scene ref={sceneRef} mindar-image={`imageTargetSrc: http://localhost:5000/wild%20nature/wild_nature.mind; autoStart: false; uiLoading: true; uiError: true; uiScanning: true; maxTrack: 3`} color-space="sRGB" embedded renderer="colorManagement: true, physicallyCorrectLights" vr-mode-ui="enabled: false" device-orientation-permission-ui="enabled: false">
              <a-assets>
  
                   <audio id="lion" src="http://localhost:5000/wild%20nature/lion/lion.mp3" preload='auto'></audio>
                   <audio id="owl" src="http://localhost:5000/wild%20nature/owl/owl.mp3" preload='auto'></audio>


              </a-assets>
              

              <a-camera position="0 0 0" look-controls="enabled: true"></a-camera>

             
                <a-entity 
                  mindar-image-target="targetIndex: 4"
                  geometry="primitive: plane" 
                  position=" 0 0 0" 
                  sound="src:#lion;" 
                />
                <a-entity 
                  mindar-image-target="targetIndex: 3"
                  geometry="primitive: plane" 
                  position=" 0 0 0" 
                  sound="src:#owl;" 
                />
            </a-scene>
          </>
     
    }
   
    
    </>
  )
}

export default MindARViewer;

Audio is not working in when remove from recent

our team built a React Native calling app using sip.js and WebRTC. Everything works fine when the app is active.

However, when a call is ongoing and the user swipes the app from recents (kill), the audio stops immediately.

We’ve already implemented a foreground service on Android to keep the app alive, but the JavaScript engine is stopped, which seems to break WebRTC audio.

❓ How can we keep the audio stream (or SIP call) active after the app is removed from recents — like WhatsApp or Microsoft Teams do?

Are we expected to move SIP and audio handling fully to native Android? Or is there a reliable pattern to keep sip.js/WebRTC alive in React Native apps?

Would appreciate insights from anyone who has solved this in VoIP apps.

i want when i kill app my audio is not disconnect

Video Form Upload With Preview & Submit html

I am facing issues in Coding. I have Creating a Video upload Form and trying to submit in localhost server. but i am getting error messages Continuously. I am facing problems in Javascript code. Please help me resolve this. I also want to know how to change the existing video title

const input = document.getElementById('file-input');
const video = document.getElementById('video');
const videoSource = document.createElement('source');

input.addEventListener('change', function () {
  const files = this.files || [];

  if (!files.length) return;

  const reader = new FileReader();

  reader.onload = function (e) {
    videoSource.setAttribute('src', e.target.result);
    video.appendChild(videoSource);
    video.load();
    video.play();
  };

  reader.onprogress = function (e) {
    console.log('progress: ', Math.round((e.loaded * 100) / e.total));
  };

  reader.readAsDataURL(files[0]);
});

function updateFileName(input) {
  let file = input.files[0];

  let newName = 'new_filename'; // Set your desired new filename

  document.getElementById('fileNameDisplay').textContent = newName;
}

JavaScript – The JSON object is not printing

I want to display the JSON object to the JSP page via JavaScript function. The function is invoked when search button is clicked. I want to search the patient details and display it on the same webpage. Please check the code below and let me know if any correction can be done.

function searchPatient() {
const query = document.getElementById("searchInput").value.trim();
const resultsContainer = document.getElementById("searchResults");

if (!query) {
    alert("Please enter ID or contact number.");
    return;
}

resultsContainer.innerHTML = "<p>Searching...</p>";
const url = "searchPatient.jsp?q=" + encodeURIComponent(query);
fetch(url)
    .then(response => {
        if (!response.ok) {
            throw new Error("Network response was not ok");
        }
        return response.json();
    })
   
    .then(data => {
        resultsContainer.innerHTML = ""; // Clear previous or loading message
        
        if (!data || data.length === 0) {
            resultsContainer.innerHTML = "<p>No patient found.</p>";
            return;
        }
        resultsContainer.innerHTML = "<p>Found " + data.length + " patient(s).</p>";

        data.forEach(patient => {
            const patientDiv = document.createElement("div");
            patientDiv.className = "patient-card";
            patientDiv.innerHTML = `
                <p><strong>ID:</strong> ${patient.id}</p>
                <p><strong>Name:</strong> ${patient.full_name}</p>
                <p><strong>Contact:</strong> ${patient.contact_number}</p>
                <p><strong>Concern:</strong> ${patient.concern}</p>
            `;
            resultsContainer.appendChild(patientDiv);
        });
    })
    .catch(error => {
        console.error("Search error:", error);
        resultsContainer.innerHTML = "<p>Error fetching patient data.</p>";
    });
 }

This is my jsp code to search patients from the MySQL database:

<%@page import="action.Database"%>
<%@ page import="java.sql.*, org.json.*, java.io.*" %>
<%@ page contentType="application/json" pageEncoding="UTF-8" %>

<%
response.setCharacterEncoding("UTF-8");

String query = request.getParameter("q");
JSONArray patients = new JSONArray();

if (query != null && !query.trim().isEmpty()) {
    Connection conn = null;
    PreparedStatement stmt = null;
    ResultSet rs = null;

    try {
        conn = Database.getConnection();
        String sql = "SELECT * FROM patients WHERE id = ? OR contact_number = ?";
        stmt = conn.prepareStatement(sql);
        stmt.setString(1, query);
        stmt.setString(2, query);
        rs = stmt.executeQuery();

        while (rs.next()) {
            JSONObject patient = new JSONObject();
            patient.put("id", rs.getInt("id"));
            patient.put("full_name", rs.getString("full_name"));
            patient.put("contact_number", rs.getString("contact_number"));
            patient.put("concern", rs.getString("chief_complaint"));
            patients.put(patient);
        }
    } catch (Exception e) {
        e.printStackTrace();  // Logs to server console
    } finally {
        try { if (rs != null) rs.close(); } catch (Exception e) {}
        try { if (stmt != null) stmt.close(); } catch (Exception e) {}
        try { if (conn != null) conn.close(); } catch (Exception e) {}
    }
}
out.print(patients.toString());
%>

There is no error, but the output is not printed in the searchResults div.