http HEAD request returns blank without a response

My HTTP GET request works perfectly, returning body data and response headers. The exact same request with the extra paramter , { method: "HEAD" } as per the docs returns empty. Server side I can see there was a sucessful HEAD request that was returned with a status 200.

        async function getHead() {
            const url = document.getElementById('url').value;
            if(url.slice(0, 4) != 'http') {
                alert("URL must start with http or https!")
                document.getElementById("responseCode").innerHTML = "ERROR"
                document.getElementById("responseBody").innerHTML = ""
            };
            try {
                const response = await fetch(url, { method: "HEAD" });
                if (!response.ok) {
                throw new Error(`Response status: ${response.status}`);
            }

            const json = await response.json();
            console.log(json);
            console.log(response);
            document.getElementById("responseCode").innerHTML = response.status;
            document.getElementById("responseBody").innerHTML = JSON.stringify(json);
            } catch (error) {
                console.error(error.message);
                document.getElementById("responseBody").innerHTML = error.message;
            }
        }

I’m expecting a response exactly the same as the GET fetch but without the body, but I’m just getting ‘Unexpected end of JSON input’ (empty)?

Full HTML & JS here

If the user clicks on the page while some JS code is running, what exactly does the browser do?

Suppose you have a button with an event listener that has a very long execution time. For the sake of simplicity, let’s just take this code as an example.

HTML

<div>
  <button>Click this</button>
</div>

JS

function sleep(millis) {
    var date = new Date();
    var curDate = null;
    do { curDate = new Date(); }
    while(curDate-date < millis);
}

addEventListener("DOMContentLoaded", (event) => {
    document.getElementsByTagName("button")[0].addEventListener("click", (e) => {
    sleep(2000);
    e.target.parentElement.innerHTML = "Clicked";
  });
});

I have noticed that in this example if you make a double click in the middle of the button, you end up with the “Clicked” text selected.

So if I understand correctly, if the user makes a double click, the browser does not queue another click event for the button. Instead, it only records the coordinates of the click, and processes it later, after the JavaScript code that is currently being ran finishes. So, for example, if at that time there is another button, then the click event of that button is going to fire.

Is this correct?

Is this behaviour consistent among all major browsers?

Are there any sources where this is documented in detail?

VSCode color problem when use single quote with object value

After the recent VS Code updates, I noticed that the colors of my code have changed.

When I use the following code, everything works fine:

:class="{
  focused: isAddingStatus,
}"

However, when I add conditions with single quote like this:

:class="{
  'no-result': !dataList?.length,
  focused: isAddingStatus,
}"

code colors are corrupted.

How can I fix this issue?

How to resolve “The default Firebase app does not exist” error when calling Cloud Functions v2 from a client app?

I’m encountering an issue when calling Firebase Cloud Functions v2 from my client app. Specifically, I’m getting the following error:

The default Firebase app does not exist. Make sure you call initializeApp() before using any of the Firebase services.

I have already initialized Firebase in my client app, and I’m able to use other Firebase services (e.g., Firestore, Authentication) without any issues. Here’s the code I’m using to initialize Firebase and call a Cloud Function:

import { initializeApp } from 'firebase/app';
import { getFunctions, httpsCallable } from 'firebase/functions';

const firebaseApp = initializeApp(firebaseConfig);

const functions = getFunctions(firebaseApp, 'europe-west3');

const myFunction = httpsCallable(functions, 'myFunction');
try {
  const result = await myFunction({ someData: 'example' });
  console.log(result.data);
} catch (error) {
  console.error("Error calling function:", error);
}

Installed package:
firebase": "^10.13.2"

I tried following the documentation (https://firebase.google.com/docs/functions/callable?gen=2nd#web_7) but I still get the error. Any advice is welcome.

How to render the js content written in a cshtml in a script tag in ASP.Net Core MVC

I have a cshtml file where i declare all my route data.

FileName: _Routes.cshtml

@{ Layout = ""; Context.Response.ContentType = "text/javascript"; }
var commonRoutes = {
  userList: '@Url.RouteUrl("Default", new { Controller = "User", Action = "GetUserList" })',
  location: '@Url.RouteUrl("Default", new { Controller = "User", Action = "GetUserLocations" })',
}

I also have a Action method in my HomeController

public IActionResult GetRoutes()
{
    Response.ContentType = "text/javascript";
    return this.View("_Routes");
}

In _Layout.cshtml and _LayoutNone.cshtml, I have to get this commonRoutes as js content since im using this routes in the ajax calls in some of the pages

my current implementation is like:

<script type="text/javascript" src='@Url.RouteUrl("Default", new { Controller = "Home", Action = "GetRoutes"})'></script>

Since I’m migrating my code from MVC to ASP.Net Core (.net8). I’m getting 400 Bad Request error in my network tab.

Need help to fix and understand this issue.

Performant and correct way of finding signed distance of vertex

I want to find vertex distance to another mesh, how close is or even penetrates it other mesh, which if I am correct trying to find signed distance and give color representing -1 to 1 from red to blue color which gives heatmap coloring like look.

I have achieved some result using three-mesh-bvh:

Vertex coloring 1Vertex coloring 2Vertex coloring 3

But this solution is not giving any negative value which represents penetrated vertexes. But it also not performance either.

One-Way Audio on 1:1 call .NET MAUI , Azure Communication Services using Javascript

I’m working on a 1:1 video call using Azure Communication Services (ACS) with a .NET MAUI app. I’ve managed to get video working both ways, but the audio only works one way. The callee can hear the caller, but the caller can’t hear the callee. I’ve tried using RemoteAudioStream but still no luck. I have done the permissions part correctly, at least from the .NET MAUI side. I have checked multiple times on the app permissions from the manifest but also from the app details/permissions.

Basically from the output log I don’t see any errors:

CallAgent initialized.
main.js:61 Device permissions granted.
main.js:65 Available microphones: Array(3)
main.js:71 Selected microphone: Headset earpiece
main.js:80 Incoming call received.
main.js:85 Notifying user of incoming call.
main.js:127 Call accepted.
main.js:273 Local participant is muted: false
main.js:312 Remote participant added: 8:acs:7fd9cad8-493b-4fd3-9e67-48bd84547a61_00000022-e7e6-7d84-8ed3-....
main.js:315 Remote participant is muted: false
main.js:276 Call state changed to: EarlyMedia
main.js:276 Call state changed to: Connected
main.js:280 Connected label shown.
main.js:336 Remote participant state changed to: Connected
main.js:330 Remote video stream removed

This worked and works fine when I use regular chrome browser or through the desktop, it even worked fine when I was calling from desktop to android, just not mobile to mobile.

I am providing the javascript I am using below

// Import necessary ACS modules
const { CallClient, VideoStreamRenderer, LocalVideoStream } = require('@azure/communication-calling');
const { AzureCommunicationTokenCredential } = require('@azure/communication-common');
const { AzureLogger, setLogLevel } = require("@azure/logger");

// Set the log level and output for debugging purposes
setLogLevel('error'); // Change to 'info' or 'verbose' for more detailed logs during development
AzureLogger.log = (...args) => {
    console.error(...args);
};

// Variables to store ACS objects and call state
let callAgent;
let deviceManager;
let call;
let currentCall;
let localVideoStream;
let localVideoRenderer;
let remoteVideoRenderer;
let isVideoStarted = false; // Track video state

// UI elements
let remoteVideosGallery = document.getElementById('remoteVideosGallery');
let localVideoContainer = document.getElementById('localVideoContainer');
let connectedLabel = document.getElementById('connectedLabel'); // Ensure this element exists in HTML
let localAudioIndicator = document.getElementById('localAudioIndicator'); // Optional: Add this in your HTML

// Extract query parameters
const urlParams = new URLSearchParams(window.location.search);
const token = urlParams.get('token');
const userId = urlParams.get('userId');
const targetId = urlParams.get('targetId');
const role = urlParams.get('role'); 

// Function to select the best microphone
function selectBestMicrophone(mics) {
    // Prefer 'Headset earpiece' if available
    const headset = mics.find(m => m.name.toLowerCase().includes('headset'));
    if (headset) return headset;
    
    // Fallback to 'microphone:default' if available
    const defaultMic = mics.find(m => m.id === 'microphone:default');
    if (defaultMic) return defaultMic;
    
    // Otherwise, return the first available microphone with a valid name
    return mics.find(m => m.name && m.name.trim() !== '') || mics[0];
}

// Function to initialize the Call Agent
async function initializeCallAgent(token, userId, targetId, role) {
    try {
        const credential = new AzureCommunicationTokenCredential(token);
        const callClient = new CallClient();

        callAgent = await callClient.createCallAgent(credential);
        console.log('CallAgent initialized.');

        // Initialize the device manager to access camera and microphone
        deviceManager = await callClient.getDeviceManager();
        await deviceManager.askDevicePermission({ video: true, audio: true });
        console.log('Device permissions granted.');

        // Select the best microphone
        const microphones = await deviceManager.getMicrophones();
        console.log('Available microphones:', microphones);

        let selectedMicrophone = selectBestMicrophone(microphones);

        if (selectedMicrophone) {
            await deviceManager.selectMicrophone(selectedMicrophone);
            console.log(`Selected microphone: ${selectedMicrophone.name || 'Default Microphone'}`);
        } else {
            console.error('No suitable microphone device found.');
            alert('No suitable microphone detected. Please connect a microphone and refresh the page.');
            return;
        }

        // Handle incoming calls
        callAgent.on('incomingCall', async (args) => {
            console.log('Incoming call received.');
            currentCall = args.incomingCall;

            // Notify the user of the incoming call
            setTimeout(async () => {
                console.log('Notifying user of incoming call.');
                alert('Incoming call received. Press OK to accept.');
                await acceptCall(); // Automatically accept the call for testing
            }, 1000);
        });
    } catch (error) {
        console.error('Error initializing CallAgent:', error);
        alert(`Failed to initialize call. Error: ${error.message}`);
    }
}

async function startCall() {
    if (!callAgent) {
        console.error('CallAgent is not initialized.');
        alert('CallAgent is not initialized.');
        return;
    }

    try {
        const targetUser = { communicationUserId: targetId };
        const callOptions = {
            audioOptions: { muted: false },  // Start with audio, no video
            // videoOptions: { localVideoStreams: [] } // Uncomment if starting without video
        };

        call = callAgent.startCall([targetUser], callOptions);
        console.log('Call initiated.');
        setupCall(call);
    } catch (error) {
        console.error('Error starting call:', error);
        alert('Failed to start call. Please check the console for more details.');
    }
}

async function acceptCall() {
    if (currentCall) {
        try {
            const callOptions = {
                audioOptions: { muted: false },  // Start with audio
                // videoOptions: { localVideoStreams: [] } // Uncomment if accepting without video
            };
            call = await currentCall.accept(callOptions);
            console.log('Call accepted.');
            setupCall(call);
        } catch (error) {
            console.error('Error accepting call:', error);
            alert('Failed to accept the call.');
        }
    } else {
        console.error('No incoming call to accept.');
    }
}

async function declineCall() {
    if (currentCall) {
        try {
            await currentCall.reject();
            console.log('Call declined.');
            currentCall = null;
        } catch (error) {
            console.error('Error declining call:', error);
            alert('Failed to decline the call.');
        }
    }
}

async function hangUpCall() {
    if (call) {
        try {
            await call.hangUp();
            console.log('Call hung up.');
            call = null;
            currentCall = null;
            isVideoStarted = false;  // Reset video state after hang up

            // Clear video containers when the call ends
            clearVideoContainers();
        } catch (error) {
            console.error('Error hanging up call:', error);
            alert('Failed to hang up the call.');
        }
    }
}

// Clear video elements (both local and remote)
function clearVideoContainers() {
    if (localVideoRenderer) {
        localVideoRenderer.dispose();  // Dispose the local video renderer
        localVideoRenderer = null;
        localVideoContainer.hidden = true;
    }

    if (remoteVideoRenderer) {
        remoteVideoRenderer.dispose();  // Dispose the remote video renderer
        remoteVideoRenderer = null;
    }
    
    remoteVideosGallery.innerHTML = ''; // Clear all remote video elements
}

// Start video
async function startVideo() {
    if (!call) {
        console.error('No active call to start video.');
        alert('No active call to start video.');
        return;
    }

    try {
        if (!localVideoStream) {
            localVideoStream = await createLocalVideoStream();
        }

        await call.startVideo(localVideoStream);
        console.log('Video started.');
        await displayLocalVideoStream();
        isVideoStarted = true;
    } catch (error) {
        console.error('Error starting video:', error);
        alert('Failed to start video.');
    }
}

// Stop video
async function stopVideo() {
    if (!call || !isVideoStarted) {
        console.error('No active video to stop.');
        alert('No active video to stop.');
        return;
    }

    try {
        await call.stopVideo(localVideoStream);
        console.log('Video stopped.');
        isVideoStarted = false;

        // Remove local video stream and replace it with a black screen
        if (localVideoRenderer) {
            localVideoRenderer.dispose();
            localVideoRenderer = null;
            localVideoContainer.style.backgroundColor = 'black'; // Black background
        }
    } catch (error) {
        console.error('Error stopping video:', error);
        alert('Failed to stop video.');
    }
}

// Create local video stream
async function createLocalVideoStream() {
    const cameras = await deviceManager.getCameras();
    if (cameras.length > 0) {
        const camera = cameras[0];
        console.log(`Using camera: ${camera.name || 'Default Camera'}`);
        localVideoStream = new LocalVideoStream(camera);
        return localVideoStream;
    } else {
        console.error('No camera device found.');
        alert('No camera device detected. Please connect a camera and refresh the page.');
        return null;
    }
}

// Display local video stream
async function displayLocalVideoStream() {
    try {
        if (localVideoRenderer) {
            localVideoRenderer.dispose();  // Dispose of existing renderer to prevent duplicates
        }

        if (localVideoStream) {
            localVideoRenderer = new VideoStreamRenderer(localVideoStream);
            const view = await localVideoRenderer.createView();
            localVideoContainer.innerHTML = '';  // Clear any existing video element
            localVideoContainer.appendChild(view.target);
            localVideoContainer.hidden = false;
            console.log('Local video stream rendered.');
        }
    } catch (error) {
        console.error('Error displaying local video stream:', error);
        alert('Failed to display local video stream.');
    }
}

// Setup call event listeners
function setupCall(call) {
    currentCall = call;

    console.log(`Local participant is muted: ${call.isMuted}`);

    call.on('stateChanged', () => {
        console.log(`Call state changed to: ${call.state}`);
        if (call.state === 'Connected') {
            if (connectedLabel) {
                connectedLabel.hidden = false;
                console.log('Connected label shown.');
            }
        } else if (call.state === 'Disconnected') {
            if (connectedLabel) {
                connectedLabel.hidden = true;
                console.log('Connected label hidden.');
            }
            call = null;
            clearVideoContainers(); // Ensure media is cleared on disconnect
        }
    });

    call.on('isMutedChanged', () => {
        console.log(`Local participant mute state changed: ${call.isMuted}`);
        if (localAudioIndicator) {
            localAudioIndicator.textContent = call.isMuted ? 'Local Audio: Muted' : 'Local Audio: Unmuted';
        }
    });

    call.remoteParticipants.forEach(remoteParticipant => {
        subscribeToRemoteParticipant(remoteParticipant);
    });

    call.on('remoteParticipantsUpdated', e => {
        e.added.forEach(remoteParticipant => subscribeToRemoteParticipant(remoteParticipant));
        e.removed.forEach(() => console.log('Remote participant removed'));
    });
}

// Subscribe to remote participants and handle video streams
function subscribeToRemoteParticipant(remoteParticipant) {
    const remoteId = remoteParticipant.identifier.communicationUserId || remoteParticipant.identifier.id;
    console.log(`Remote participant added: ${remoteId}`);

    // Log if remote participant is muted
    console.log(`Remote participant is muted: ${remoteParticipant.isMuted}`);

    remoteParticipant.on('isMutedChanged', () => {
        console.log(`Remote participant mute state changed: ${remoteParticipant.isMuted}`);
    });

    remoteParticipant.videoStreams.forEach(remoteVideoStream => {
        subscribeToRemoteVideoStream(remoteVideoStream);
    });

    remoteParticipant.on('videoStreamsUpdated', e => {
        e.added.forEach(remoteVideoStream => {
            subscribeToRemoteVideoStream(remoteVideoStream);
        });
        e.removed.forEach(() => {
            console.log('Remote video stream removed');
        });
    });

    // Handle remote participant state changes
    remoteParticipant.on('stateChanged', () => {
        console.log(`Remote participant state changed to: ${remoteParticipant.state}`);
    });
}

// Subscribe to remote video streams
async function subscribeToRemoteVideoStream(remoteVideoStream) {
    if (remoteVideoStream.isAvailable) {
        await displayRemoteVideoStream(remoteVideoStream);
    }

    remoteVideoStream.on('isAvailableChanged', async () => {
        if (remoteVideoStream.isAvailable) {
            await displayRemoteVideoStream(remoteVideoStream);
        } else {
            console.log('Remote video stream is no longer available.');
        }
    });
}

// Display remote video stream
async function displayRemoteVideoStream(remoteVideoStream) {
    try {
        // Dispose of the previous renderer to prevent duplication
        if (remoteVideoRenderer) {
            remoteVideoRenderer.dispose();
            remoteVideoRenderer = null;
        }

        remoteVideoRenderer = new VideoStreamRenderer(remoteVideoStream);
        const view = await remoteVideoRenderer.createView();
        remoteVideosGallery.innerHTML = '';  // Clear existing video elements
        remoteVideosGallery.appendChild(view.target);
        console.log('Remote video stream rendered.');
    } catch (error) {
        console.error('Error rendering remote video stream:', error);
        alert('Failed to render remote video stream.');
    }
}

// Initialize Call Agent with extracted parameters
initializeCallAgent(token, userId, targetId, role);

// Expose functions to be callable from MAUI WebView
window.startCall = startCall;
window.hangUpCall = hangUpCall;
window.startVideo = startVideo;
window.stopVideo = stopVideo;
window.acceptCall = acceptCall;
window.declineCall = declineCall;
window.toggleMute = toggleMute;

window.isReady = true;  // Flag to notify MAUI WebView that the script is ready

// For testing in a browser environment
console.log('Script is ready.');

// Toggle Mute Function
let isMuted = false;

// Toggle mute state
async function toggleMute() {
    if (!call) {
        console.error('No active call to toggle mute.');
        alert('No active call to toggle mute.');
        return;
    }

    try {
        if (isMuted) {
            await call.unmute();
            console.log('Unmuted.');
        } else {
            await call.mute();
            console.log('Muted.');
        }
        isMuted = !isMuted;

        // Optionally, update local audio indicator
        if (localAudioIndicator) {
            localAudioIndicator.textContent = isMuted ? 'Local Audio: Muted' : 'Local Audio: Unmuted';
        }
    } catch (error) {
        console.error('Error toggling mute:', error);
        alert('Failed to toggle mute.');
    }
}

Also once it did work amphidromously and the call was perfect, but without changing anything just by re-running it, it started being one-way call again!

I appreciate any heads-up, help or critique, I am new on this .NET MAUI and I like it so far!
Thank you for your time.

I attempted a 1:1 video call using Azure Communication Services. I implemented remoteAudioStream.getMediaStream() for audio and subscribed to remote participants, but audio is one-way; callee hears the caller, but the caller cannot hear the callee. Tried selecting microphones and speakers with deviceManager, checked mute states, and handled audio streams with audioStreamsUpdated events. Expected two-way audio.

Also troubleshooted:

  1. Microphone Selection: The application might not be using the correct microphone.
  2. Participant Subscription: There could be issues with subscribing to remote participants correctly.
  3. Mute States: One of the participants might be muted unintentionally.
  4. Device Permissions: Permissions for microphone access might not be properly granted.
  5. Audio Device Management: The application might not be selecting or managing audio devices correctly.

I am also running it on HTTPS using legitimate SSL

How to Get Text Value from PlateJS

I found PlateJS has API to desrialize string html into editor values:

editor.api.html.deserialize({element:"<p>Hi!</P>"})

I need a method in reverse, so it takes the value after change and convert it to plain string html like:

"<p><strong>Hi!</strong> It's me.</p>"

How can I achieve this or convert children to string?

onValueChange pass a value with this type {value: ValueOf<E>} where value has children property.

Mediasource sourcebuffer error when loading older blobs

Mediasource sourcebuffer error when loading older blobs

The problem: I am not able to go back in a video recording by loading old blobs in a sourceBuffer

I am creating a js video player that records live the video from the webcam and allows to go back. The video could be very long (more than one hour). The idea is making a Camera Assisted Video application (like the soccer/judo one, to replay older actions).

Since the MediaSource sourceBuffer has a limited duration, I am using IndexDb to store and retrieve the various Blobs, which are pieces of video recorded.

Currently this is what I am doing to show the live video:

  • start the recording with a MediaRecorder. When a new Blob is available, store it in the IndexDB

  • I create from Javascript the video tag (more on why later), create a MediaSource, attach it on the video element and create a source buffer, then start retrieving blobs

  • I have a global variable i that tells me the id of the next blob to retrieve. Every time a blob is attached to the sourceBuffer, I fetch the next one and append it to the same sourceBuffer.

This works nicely, as I am able to see the livestream of the recording and retrieve all the blobs to save the total video (while using just the sourceBuffer, I cannot have a video longer than 150MB before it gets cut).

I have various methods to let the user decide to go back at what timestamp (keyboard shortcuts, custom timeline) and a function that, given a timestamp, returns me the index of the nearest previous blob.

My problem is, once I know what old blob to load next, I am not able to show it, since the stream just freezes and/or returns error.

Here is what I have tried so far, and none of them works:

  • Simpy setting the global variable i to the old blob id, so that the next loaded blob in the source buffer is an old one
  • create a new sourcebuffer, and start appending old blobs to it
  • create a new mediasource, linking it to the video tag, and using it
  • create a new video html tag, and start again by loading old blobs

Every time, when the first blob is added the sourceBuffer gets an error (which is not printed anywhere, since it returns an event) and the video freezes. How can I do what I want to do?

Here are the relevant pieces of code, you can find the full code here if it is helpful. Thank you very much

/** The blob lenght from a MediaRecorder in milliseconds. It decides also when a new blob is stored / retrieved */
const REFRESHRATE = 1 * 1000;
/** how much to wait from recording to showing the first blob of the live. Total delay to the live is this times REFRESHRATE */
const DELAY_MULTIPLIER = 2;
const mimeType = 'video/webm; codecs="vp8, opus"';
const videoContainer = document.querySelector(".video-container");

getWebcamStream();

/** get the webcam stream, save it to the mediaStream and start the mediaRecorder */
function getWebcamStream() {
  navigator.mediaDevices
    .getUserMedia({
      audio: useAudio,
      video: { width: 1920, height: 1080 },
      facingMode: { exact: "enviroment" },
    })
    .then((stream) => {
      // todo we can add multiple videotracks in the future
      const videoTrack = stream.getVideoTracks()[0];
      /** holder of the webcam audio and video stream */
      const mediaStream = new MediaStream();
      mediaStream.addTrack(videoTrack);
      if (useAudio) {
        const audioTrack = stream.getAudioTracks()[0];
        mediaStream.addTrack(audioTrack);
      }

      /** saves the webcam stream to various Blobs */
      const mediaRecorder = new MediaRecorder(
        mediaStream,
        useAudio
          ? {
              audioBitsPerSecond: 128000,
              videoBitsPerSecond: videoBitsPerSecond,
            }
          : { videoBitsPerSecond: videoBitsPerSecond }
      );

      mediaRecorder.start(REFRESHRATE);

      // * when data is aviable to the recorder, add it to the arrayOfBlob and then call appendToSourceBuffer to process it
      mediaRecorder.addEventListener("dataavailable", (e) => {
        const blob = e.data;
        storeBlob(blob);
      });

      setTimeout(appendToSourceBuffer, REFRESHRATE * DELAY_MULTIPLIER);
    })
    .catch((err) => {
      console.log(err);
      alert(
        "Assicurati che la webcam non sia usata da qualche altro programma, poi ricarica il CARE system"
      );
    });
}

/** source for the video tag @type {MediaSource} */
let mediaSource;
/** buffer to hold various Blobs @type {SourceBuffer} */
let sourceBuffer;
/** index of the last blob added in the db. Autoindexing starts at 1 */
let i = 1;
/** @type {HTMLVideoElement} */
let video;

createVideoElement();

function createVideoElement() {
  if (video) {
    try {
      console.log("Removing previous video element");
      mediaSource.removeSourceBuffer(sourceBuffer);
      sourceBuffer = null;
      mediaSource.endOfStream();
      mediaSource = null;
      videoContainer.removeChild(video);
    } catch (e) {
      console.error("Error removing previous video element:", e);
    }
  }
  console.log("Creating video element");
  video = videoContainer.appendChild(document.createElement("video"));
  addVideoEvents();
  createMediaSource();
  setTimeout(() => video.play().catch(console.error), REFRESHRATE);
}

function createMediaSource() {
  console.log("Creating mediaSource");
  mediaSource = new MediaSource();

  const url = URL.createObjectURL(mediaSource);
  video.src = url;

  // * when mediaSource is ready, create the sourceBuffer
  mediaSource.addEventListener("sourceopen", createSourceBuffer);
}

function createSourceBuffer() {
  console.log("Creating sourceBuffer with mimeType:", mimeType);
  sourceBuffer = mediaSource.addSourceBuffer(mimeType);
  sourceBuffer.mode = "segments";
  // * when the previous blob has been appended, append a new one
  sourceBuffer.addEventListener("updateend", () =>
    setTimeout(appendToSourceBuffer, REFRESHRATE)
  );
  sourceBuffer.addEventListener("error", (e) => {
    console.error("Error with sourceBuffer:", e);
  });
}

/** add to the sourceBuffer the new segment */
function appendToSourceBuffer() {
  if (!mediaSource) return;
  if (mediaSource.readyState !== "open") return;
  if (!sourceBuffer) return;
  if (sourceBuffer.updating) return;

  getBlobById(
    i,
    (blob, timestamp) => {
      i++;
      blob
        .arrayBuffer()
        .then((arrayBuffer) => {
          sourceBuffer.appendBuffer(arrayBuffer);
          currentTimestamp = timestamp;
          updateTotalTime();
        })
        .catch((e) =>
          console.error("Error appending blob to sourceBuffer:", e)
        );
    },
    () => setTimeout(appendToSourceBuffer, REFRESHRATE)
  );
}

function moveToTimestamp(timestamp) {
  if (timestamp > lastTimestamp) return returnLive();
  if (timestamp < startTimestamp) timestamp = startTimestamp;

  getNearestBlobByTimestamp(timestamp, (blob, timestamp, id) => {
    i = id;
    createVideoElement();
    setTimeout(appendToSourceBuffer, REFRESHRATE * DELAY_MULTIPLIER);
  });
}

function returnLive() {
  moveToTimestamp(lastTimestamp - REFRESHRATE * DELAY_MULTIPLIER);
}

Variable declared in global scope is only defined within the function it was assigned to(using destructuring assignment) [duplicate]

let wallet, rpcUrl, connection;

async function envload() {
    const envFilePath = ".env";
    const defaultEnvContent = `# Please fill in the following environment variablesnRPC_URL=nPRIVATE_KEY=`;
    try {
        if (!fs.existsSync(envFilePath)) {
            fs.writeFileSync(envFilePath, defaultEnvContent, "utf8");
            console.log(chalk.green
                ("Everything is set!")
            );
            process.exit(0);
        }
    } catch (error) {
        console.error(chalk.red
            ("Cannot create ENV file due to an error:",
            error,
            "Please try again.")
        );
        process.exit(1);
    }

    dotenv.config();
    if (!process.env.PRIVATE_KEY || !process.env.RPC_URL) {
        console.error(chalk.red
            ("Cannot find PRIVATE_KEY and RPC_URL variables. Are you sure you set them right?")
        );
        process.exit(1);
    }

    return [
        new Wallet(
            solanaWeb3.Keypair.fromSecretKey(
                bs58.default.decode(process.env.PRIVATE_KEY)
            )
        ),
        process.env.RPC_URL,
    ];
}

async function initialize() { // rename func
    await greeting();
    [wallet, rpcUrl] = await envload();
    connection = new Connection(rpcUrl, "confirmed", { // This can be used to interact to rpc
        commitment: "confirmed",
        confirmTransactionInitialTimeout: 30000,
    });
    console.log(wallet); // defined
}
console.log(wallet); // undefined

async function introduction() { 
    await initialize();
    const envFilePath = ".env";
    //
}

For some reason wallet outside the function is undefined even though it was declared in global scope and after assignment in function must be defined in the code like any other variable. Is the destucturing assignment making it impossible to do so?

It was impossible for me to use destructuring assignment without a function so everything I did was making it work inside a function and declaring all variables needed in a global scope(which gave me this error)

How to extract the body as a JSON from a server response in Javascript

I want to insert header response into my HTML, I need to insert response code, headers and body.

I can get the response code and header without issue. However, the body just returns object promise?

This is the JS:

        function GETcall () {
            const url = document.getElementById('url').value;
            fetch(url, {
            method: 'GET', 
            headers: {
            'Content-Type': 'application/json; charset=UTF-8',
        }
        })
        .then((response) => {
            document.getElementById("responseCode").innerHTML = response.status
            console.log("HEADERS =", response)
            document.getElementById("responseBody").innerHTML = response.json()
        })
        .catch((error) => { console.error('Error:', error); });
        }

This is the console and the body is a correctly constructed JSON
enter image description here

I want the JSON that is in the body which I know looks like: {“id”: 1, “name”: “Frozen”, “studio”: “Disney”}

Woocommerce filters not showing

I have an issue with my woocommerce filters.

The price one shows an error “There was an error loading the content. Error: Cannot read properties of undefined (reading ‘Label’)”, and the two other filters simply doens’t show up at all.

Here is the page in question : https://staging2.ateliermauny.fr/shop/
(or any product listing pages anyway)

I isolated the issue coming from Siteground plugin Speed Optimizer.

I tried to exclude following scripts related to woocommerce on the plugin (in Frontend > Javascript > Exclude from Deferral & Exclude from Minification :

  • /plugins/woocommerce/assets/js/jquery-blockui/jquery.blockUI.min.js
  • /plugins/woocommerce/assets/js/frontend/woocommerce.min.js

I also found out an error on the console, as you can see on following photo :

Is there a way to keep numbers as numbers in Express?

I am posting an Express route which seems to handle all params and data as strings. I am currently having to individually convert them to Number values and was wondering if there was a way to take care of all of them in one pass?

This is how the route looks:

Router.post('/user/:UserID',
    async function (req, res, next) {
    
    const UserID = Number(req.params.UserID);
    const StatusID = Number(req.body.StatusID);
    const DepartmentID = Number(req.body.DepartmentID);
    ...
    
     try {
         await API.getUserDetails({
                DepartmentID: DepartmentID,
                UserID: UserID,
                StatusID: StatusID
               ...
            });
    } catch (e) { 
    console.error(e) 
    }

}

Rather than individually converting the params and data to Numbers I would like to do something like this:

Router.post('/user/:UserID',
    async function (req, res, next) {

   // If a value can be converted to a Number, then convert it

       req = JSON.stringify(req, function (key, value) {
            return Number(value) || value
        });

        req = JSON.parse(req, function (key, value) {
            return Number(value) || value
        });
            
     try {
         await API.getUserDetails({
                DepartmentID: req.body.DepartmentID,
                UserID: req.params.UserID,
                StatusID: req.body.StatusID
               ...
            });
    } catch (e) { 
    console.error(e) 
    }

}

Obviously the above attempt does not work and I get errors like: TypeError: Cannot convert object to primitive value.

Is this even achieveable?

How to implement Pagination using JavaScript/jQuery in a list of data which is called using AJAX method in simple HTML, CSS, Bootstrap Project

Here is my HTML Code for it

<body>
    <div class="container-fluid">
        <!-- Alphabet Filter -->
        <div id="letter-container" class="d-flex flex-wrap justify-content-center"></div>
        <!-- Search Bar and Filters  -->
        <form class="d-flex flex-wrap justify-content-center align-items-center">
            <div class="input-group me-3 mx-5" style="flex: 1 1 400px">
                <span class="input-group-text"><i class="fa fa-search"></i></span>
                <input class="form-control" type="text" id="globalSearchInput" placeholder="Search"
                    style="width: 150px" />
                <button class="btn btn-primary" id="searchButton" type="button">
                    <i class="fa fa-arrow-right"></i>
                </button>
            </div>

            <div class="me-3 d-flex align-items-center" style="flex: 1">
                <label class="me-2" for="sortSelect">Sort:</label>
                <select class="form-select" id="sortSelect">
                    <option class="DropdownData" value="firstName" selected>
                        First Name
                    </option>
                    <option class="DropdownData" value="lastName">Last Name</option>
                    <option class="DropdownData" value="department">Department</option>
                </select>
            </div>

            <div class="d-flex align-items-center flex-wrap" style="flex: 1">
                <label class="me-2" title="Filter By Department">Filter By Department:</label>
                <div class="dropdown">
                    <button class="btn btn-link dropdown-toggle" type="button" id="departmentFilterDropdown"
                        data-bs-toggle="dropdown" aria-expanded="false">
                        <i class="fa fa-filter"></i>
                    </button>
                    <ul class="dropdown-menu" aria-labelledby="departmentFilterDropdown" id="filterOptions">
                        <li><a class="dropdown-item" href="#" data-department="All">All Departments</a></li>
                        <li><a class="dropdown-item" href="#" data-department="IT">IT</a></li>
                        <li><a class="dropdown-item" href="#" data-department="HR">HR</a></li>
                        <li><a class="dropdown-item" href="#" data-department="Business Development">Business
                                Development</a></li>
                        <li><a class="dropdown-item" href="#" data-department="QA">QA</a></li>
                        <li><a class="dropdown-item" href="#" data-department="Knacktek">Knacktek</a></li>
                    </ul>
                </div>
            </div>

        </form>
    </div>
    <!-- Profile card -->
    <div class="container mt-3">
        <div class="row" id="profileContainer">
            <div class="card text-center mx-auto" style="width: 100%; border: 1px solid black" id="profileCard1">
                <div class="card-body p-0">
                    <h5 class="card-title text-white py-2"
                        style="background-color: rgb(52, 179, 221); margin-bottom: 0">
                        <span id="name1">Demo Data</span>
                    </h5>
                    <p class="card-subtitle mb-2" id="designation1">Demo Data</p>
                    <img src="./assets/avatar.png" class="rounded-circle mb-2 img-fluid" id="profilePhoto1"
                        alt="Profile Photo" style="width: 100px; height: 100px" />
                    <p class="card-text mb-2"><strong>Company:</strong> <span id="company1">Binary
                            Republik</span>
                    </p>
                    <p class="card-text mb-2"><strong>Department:</strong> <span id="department1">Demo Data</span>
                    </p>
                    <p class="card-text mb-2"><strong>Email:</strong> <span id="email1">Demo Data</span></p>
                    <p class="card-text mb-4"><strong>Manager/Reports To:</strong> <span id="reporter1">Demo
                            Data</span></p>
                    <div class="d-flex justify-content-between">
                        <p class="card-text"><strong>Extension:</strong> <span id="extension1">Demo Data</span></p>
                        <p class="card-text"><strong>Location:</strong> <span id="location1">Demo Data</span></p>
                    </div>
                </div>
            </div>
        </div>
    </div>
    <!-- Paginations  -->
    <div id="pagination-container" class="container mt-2">
        <div class="d-flex justify-content-between align-items-center mb-2">
            <div class="d-flex align-items-center">
                <label for="itemsPerPage" class="me-2">Items per page:</label>
                <select id="itemsPerPage" class="form-select d-inline-block w-auto">
                    <option value="8">8</option>
                    <option value="16">16</option>
                    <option value="20">20</option>
                    <option value="24">24</option>
                    <option value="all">All</option>
                </select>
            </div>
            <ul class="pagination mb-0" id="pagination"></ul>
        </div>
    </div>

</body>

Here is my JS Code for it

$(document).ready(function () {
    const letters = "All,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z".split(",");
    letters.forEach((letter) => {
        $("#letter-container").append(`<div class="letters">${letter}</div>`);
    });
    var jsonData = [];
    let filteredEmployees = [];
    let sortedEmployees = [];
    // var currentPage = 1;
    // var itemsPerPage = $("#itemsPerPage").val() || 8;
    // var pageCount = Math.ceil(filteredEmployees.length / itemsPerPage);


    $.ajax({
        url: "./assets/employeeDirectory.json",
        method: "GET",
        dataType: "json",
        success: function (data) {
            jsonData = data;
            displayEmployeeCards(data);
        },
        error: function () {
            alert("Failed to fetch data.");
        },
    });

    // Filter By Alphabets
    filterByAlphabet();

    // Sort By Dropdown
    sortByDropdown();

    //Filter By departments
    filterByDepartment();

    //Global Search
    applyGlobalSearch();

    function displayEmployeeCards(jsonData) {
        const container = $("#profileContainer");
        container.empty();
        jsonData.forEach((employee) => {
            const businessPhones = employee.businessPhones.join(", ") || "NA";
            var cardHtml = `
                <div class="col-12 col-sm-6 col-md-4 col-lg-3 mb-3">
        <div class="card text-center mx-auto" style="border: 1px solid black; height: 440px">
            <div class="card-body p-0">
                <h5 class="card-title text-white py-2" style="background-color: rgb(52, 179, 221); margin-bottom: 0">
                    <span>${employee.displayName || "NA"}</span>
                </h5>
                <div style="padding: 5px">
                    <p class="card-subtitle mb-2">${employee.jobTitle || "NA"}</p>
                    <img src="./assets/avatar.png" class="rounded-circle mb-3 img-fluid" alt="Profile Photo"
                        style="width: 100px; height: 100px" />
                    <p class="card-text mb-2">Binary Republik</p>
                    <p class="card-text mb-2">${employee.department || "NA"}</p>
                    <p class="card-text mb-2">
                        <strong>Email:</strong> <span>${employee.mail}</span>
                    </p>
                    <p class="card-text mb-4">
                        <strong>Manager/Reports To:</strong>
                        <span>NA</span>
                    </p>
                    <div class="d-flex justify-content-between">
                        <p class="card-text mb-0">
                            <strong>Extension:</strong> <span>${businessPhones}</span>
                        </p>
                        <p class="card-text mb-0">
                            <strong>Location:</strong>
                            <span>${employee.officeLocation || "NA"}</span>
                        </p>
                    </div>
                </div>
            </div>
        </div>
    </div>`;
            container.append(cardHtml);
        });
    }


    function filterByDepartment() {
        $("#filterOptions .dropdown-item").on("click", function () {
            const selectedDepartment = $(this).data("department");
            if (selectedDepartment === "All") {
                departmentFilteredEmployees = sortedEmployees;
            }
            else {
                departmentFilteredEmployees = sortedEmployees.filter(function (employee) {
                    return employee.department === selectedDepartment;
                });
            }
            if (departmentFilteredEmployees.length == 0) {
                $("#profileContainer").html(`<div class="col-12 text-center"> <p class="mt-4">No Data Found</p> </div>`);
            }
            else {
                displayEmployeeCards(departmentFilteredEmployees);
            }
        });
    }

    function sortByDropdown() {
        $("#sortSelect").on("change", function () {
            const selectedFilterDropdown = $(this).val();
            sortedEmployees = filteredEmployees.slice();;

            if (selectedFilterDropdown === "firstName") {
                sortedEmployees.sort();
            }
            else if (selectedFilterDropdown === "lastName") {
                sortedEmployees.sort(function (a, b) {
                    const surnameA = a.surname || "";
                    const surnameB = b.surname || "";
                    return surnameA.localeCompare(surnameB);
                });
            } else if (selectedFilterDropdown === "department") {
                sortedEmployees.sort(function (a, b) {
                    const departmentA = a.department || "";
                    const departmentB = b.department || "";
                    return departmentA.localeCompare(departmentB);
                });
            }
            if (sortedEmployees.length == 0) {
                $("#profileContainer").html(`<div class="col-12 text-center"> <p class="mt-4">No Data Found</p> </div>`);
            }
            else {
                displayEmployeeCards(sortedEmployees);
            }
        });
    }

    function filterByAlphabet() {
        $(".letters").on("click", function () {

            const selectedLetter = this.innerText;
            if (selectedLetter === "All") {
                filteredEmployees = jsonData;
            }
            else {
                filteredEmployees = jsonData.filter(function (employee) {
                    return employee.displayName.startsWith(selectedLetter);
                });
            }
            if (filteredEmployees.length == 0) {
                $("#profileContainer").html(`<div class="col-12 text-center"> <p class="mt-4">No Data Found</p> </div>`);
            }
            else {
                displayEmployeeCards(filteredEmployees);
            }
        });
    }
    function applyGlobalSearch() {
        $("#searchButton").on("click", function () {
            const searchTerm = $("#globalSearchInput").val().toLowerCase();

            const filteredEmployees = jsonData.filter(function (employee) {
                return (
                    (employee.givenName && employee.givenName.toLowerCase().includes(searchTerm)) ||
                    (employee.surname && employee.surname.toLowerCase().includes(searchTerm)) ||
                    (employee.displayName && employee.displayName.toLowerCase().includes(searchTerm)) ||
                    (employee.department && employee.department.toLowerCase().includes(searchTerm)) ||
                    (employee.jobTitle && employee.jobTitle.toLowerCase().includes(searchTerm)) ||
                    (employee.mail && employee.mail.toLowerCase().includes(searchTerm)) ||
                    (employee.businessPhones && employee.businessPhones.filter(phone => phone.toLowerCase().includes(searchTerm)).length > 0) ||
                    (employee.officeLocation && employee.officeLocation.toLowerCase().includes(searchTerm))
                );
            });
            if (filteredEmployees.length === 0) {
                $("#profileContainer").html(`<div class="col-12 text-center"><p class="mt-4">No Data Found</p></div>`);
            } else {
                displayEmployeeCards(filteredEmployees);
            }
        });
    }


});

I tried to implement using the twbsPagination method, which was shown in javatpoint website, but it doesn’t work on my code, maybe some error from my side. also i tried the ChatGPT method but it filters and sorts the entire data other than the already sorted data (if any)