PWA not obtainable without internet connection

I have made a PWA by following the tutorial at https://learn.microsoft.com/en-us/microsoft-edge/progressive-web-apps-chromium/how-to/

I put the PWA on a server and when I navigate to it using Chrome on my Linux desktop I am able to download it to my desktop and then open it and use it. In Firefox I can still use the PWA after selecting “offline” from development tools. So it seems to be working to some extent.

When I navigate to the PWA from my Android phone using Firefox I can install the PWA to my home screen but if I turn off WiFi and mobile data it will not open the PWA. It warns that I am offline. Chrome does the same except instead of (when online) opening the site at example.com/pwa it opens the root ie. example.com which I do not want.

All i want to do is run some simple JavaScript code in a web browser when I am offline but it seems to be extremely difficult. I have tried to do this on several occasions over the last few years and can never get it to work.

I would very much appreciate seeing some minimal code to be able to deploy a PWA which I can put on a server, navigate to from my android phone, install on my android phone and then use offline in Chrome and Firefox. The example I quoted at the beginning of this question does not seem to do that.

Uncaught TypeError: butterchurn.createRenderer is not a function (using Electron)

I am trying to use the npm package butterchurn in an Electron environment, but whatever I try, I get the error that butterchurn.createRenderer is not a function.

index.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Butterchurn Example</title>
</head>
<body>
    <canvas id="visualizer" width="800" height="600"></canvas>
    <script src="renderer.js"></script>
</body>
</html>

renderer.js:

const butterchurn = require('butterchurn');
const presets = require('butterchurn-presets'); 
const { createAudioContext } = butterchurn; 

const audioContext = new (window.AudioContext|| window.webkitAudioContext)();

const visualizer = butterchurn.createRenderer();
const canvas = document.getElementById('visualizer');
visualizer.setSize(canvas.width, canvas.height);
const gl = canvas.getContext('webgl');
visualizer.setGL(gl);

const audioElement = new Audio('/home/Music/HaveACigar.mp3');
const source = audioContext.createMediaElementSource(audioElement);
source.connect(audioContext.destination);
visualizer.setAudioSource(source);

const preset = presets['Default']; 
visualizer.loadPreset(preset);

audioElement.play();
visualizer.start();

JavaScript’s fetch API triggers Cloudflare challenge while cURL does not

The following request in cURL does not trigger the Cloudflare challenge:

curl -A "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36" "https://www.jeuxvideo.com/"

In cURL I can see using -v option that headers are sent in this order:

> Host: www.jeuxvideo.com
> User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36
> Accept: */*

However, when using the fetch API (or axios module) the Cloudflare challenge is triggered:

async function main() {
    const response = await fetch("https://www.jeuxvideo.com", { headers: { "Host": "www.jeuxvideo.com", "User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36", "Accept": "*/*" }});
    console.log(await response.text())
}

await main();

My question is similar to this one, except that I’d like to find a way to make the request work in JavaScript. In fact, I haven’t been able to get the requests library to work either: while the accepted answer says it’s a question of headers ordering (Host should come before User-Agent), the request still fails when this is corrected. Nevertheless, I do not encounter any issue using urllib as the OP explained.

How to upload Tensorflow JSON and weights.bin files into javascript for live use

Code that created my files:

model.save('downloads://my_model');

The following created a JSON and weights.bin file that I tried to upload.

I have two different html file inputs to distinguish between the file types. My goal is to upload and convert the files into a model and weights but there has been difficulties.

This is a purely front end project.

ChatGPT has not been useful.

I used the code below to load the files but there is no longer any class classification

const uploadJSONInput = document.getElementById('upload-json');
const uploadWeightsInput = document.getElementById('upload-weights');
const model = await tf.loadLayersModel(tf.io.browserFiles(
     [uploadJSONInput.files[0], uploadWeightsInput.files[0]]));

How do I get memory extensive JavaScript to work on HTML canvas via Android Studio Webview?

I am trying to make an Android App, I’m a baby developer I won’t lie, but it’s based on astrology calculations. However my canvas will load when I comment out astrology.js but breaks because of this following error. I even tried adding a time out and loading bar to hopefully slow the code down and also tried to override the memory in my MainActivity.java which in return makes my app run slower. So Idk what to do guys cause I see people making all kinds of cool apps and I finally have an idea and it can’t perform a simple calculation and draw it to a canvas. Also the code works outside of AndroidStudio. Any help would be awesome.

ERROR: 2025-02-02 14:33:58.130 25503-25555 chromium com.google.android.webview E [ERROR:tile_manager.cc(937)] WARNING: tile memory limits exceeded, some content may not draw

/**
 * Calculates planetary positions based on the date and time of birth using Keplerian mechanics.
 * @param {string} dateOfBirth - The date of birth in "YYYY-MM-DD" format.
 * @param {string} timeOfBirth - The time of birth in "HH:MM" format.
 * @returns {Array<Object>} - An array of planetary positions with names and degrees.
 */
function calculatePlanetaryPositions(dateOfBirth, timeOfBirth, callback) {
  setTimeout(() => { // Increase timeout duration for better performance
    const birthDate = new Date(`${dateOfBirth}T${timeOfBirth}`);
    const JD = (birthDate.getTime() / 86400000.0) + 2440587.5;

    const planets = {
      '☉': { a: 1.0000, e: 0.0167, i: 0.000, L: 100.464, w: 102.937, N: 0.0 },
      '☽': { a: 0.00257, e: 0.0549, i: 5.145, L: 218.32, w: 318.15, N: 125.08 },
      '♀': { a: 0.7233, e: 0.0068, i: 3.395, L: 181.98, w: 131.532, N: 76.68 },
      '♂': { a: 1.5237, e: 0.0934, i: 1.850, L: -4.568, w: -23.943, N: 49.58 },
      '♃': { a: 5.2026, e: 0.0489, i: 1.303, L: 34.404, w: 14.753, N: 100.47 },
      '♄': { a: 9.5549, e: 0.0565, i: 2.485, L: 49.944, w: 92.598, N: 113.67 },
      '♅': { a: 19.2184, e: 0.0463, i: 0.773, L: 313.232, w: 170.964, N: 74.02 },
      '♆': { a: 30.1104, e: 0.0086, i: 1.770, L: -55.126, w: 44.971, N: 131.78 }
    };

    const positions = Object.entries(planets).map(([name, p]) => {
      let M = (p.L - p.w + (JD - 2451545.0) * (360 / (365.25 * Math.sqrt(p.a**3)))) % 360;
      if (M < 0) M += 360;
      let M_rad = M * (Math.PI / 180);
      let E = M_rad;
      for (let i = 0; i < 5; i++) {
        E = M_rad + p.e * Math.sin(E);
      }
      let ν = 2 * Math.atan2(
        Math.sqrt(1 + p.e) * Math.sin(E / 2),
        Math.sqrt(1 - p.e) * Math.cos(E / 2)
      );
      let ν_deg = (ν * 180 / Math.PI + 360) % 360;
      return { name, degree: ν_deg };
    });

    callback(positions); // Return data after timeout
  }, 2500); // Increased delay to 1.5 seconds for better UI response
}

// Add a loading bar to the bottom of the page
const loadingBar = document.createElement('div');
loadingBar.style.position = 'fixed';
loadingBar.style.bottom = '0';
loadingBar.style.left = '0';
loadingBar.style.width = '0%';
loadingBar.style.height = '5px';
loadingBar.style.backgroundColor = 'green';
document.body.appendChild(loadingBar);

function updateLoadingBar(progress) {
  loadingBar.style.width = `${progress}%`;
}

/**
 * Draws an astrological chart with 6 intersecting lines and zodiac symbols.
 * @param {CanvasRenderingContext2D} ctx - The 2D context of the canvas.
 * @param {HTMLCanvasElement} canvas - The canvas element.
 * @param {Array<Object>} positions - The planetary positions.
 */
function drawAstrologicalChart(ctx, canvas, positions) {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  updateLoadingBar(50); // Update loading bar midway

  const centerX = canvas.width / 2;
  const centerY = canvas.height / 2;
  const radius = Math.min(canvas.width, canvas.height) / 2 - 10;

  // Zodiac signs in order
  const zodiacSigns = ['♈', '♉', '♊', '♋', '♌', '♍', '♎', '♏', '♐', '♑', '♒', '♓'];

  // Draw outer circle
  ctx.beginPath();
  ctx.arc(centerX, centerY, radius, 0, Math.PI * 2);
  ctx.strokeStyle = '#fff';
  ctx.lineWidth = 2;
  ctx.stroke();
  updateLoadingBar(75); // Update loading bar further

  // Draw zodiac signs and planetary positions
  positions.forEach((planet, i) => {
    const angle = (i * Math.PI) / 6;
    const x = centerX + radius * Math.cos(angle);
    const y = centerY + radius * Math.sin(angle);
    ctx.fillStyle = '#f4d03f';
    ctx.font = '20px Arial';
    ctx.fillText(zodiacSigns[i], x, y);
  });

  updateLoadingBar(100); // Finish loading
  setTimeout(() => loadingBar.style.width = '0%', 1000); // Hide bar after completion
}

// Export the functions
export { calculatePlanetaryPositions, drawAstrologicalChart };

I tried overriding the memory, I’ve tried modifying manifests.xml, and all of these overrides and exceptions in my mainactivity

package com.example.astrodate;

import android.content.pm.ActivityInfo;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.webkit.ConsoleMessage;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {
    private WebView webView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); //  Lock in portrait mode

        webView = new WebView(this);
        setContentView(webView);

        WebSettings webSettings = webView.getSettings();
        webSettings.setJavaScriptEnabled(true);  //  Enable JavaScript for all files
        webSettings.setDomStorageEnabled(true);  //  Enable local storage
        webSettings.setAllowFileAccess(true);  //  Allow access to local files
        webSettings.setAllowContentAccess(true);

        //  Allow mixed content (fix CORS issues if loading external resources)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            webSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
        }

        //  Force software rendering for WebView (fixes canvas issues)
        webView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);

        webView.setWebViewClient(new WebViewClient() {
            @Override
            public void onPageFinished(WebView view, String url) {
                Log.d("WebView", " Page loaded successfully: " + url);
                webView.loadUrl("javascript:console.log(' JavaScript is running inside WebView!')");
            }
        });

        //  Capture JavaScript console logs for debugging
        webView.setWebChromeClient(new WebChromeClient() {
            @Override
            public boolean onConsoleMessage(ConsoleMessage consoleMessage) {
                Log.d("WebView", "JS Log: " + consoleMessage.message());
                return true;
            }
        });

        if (savedInstanceState != null) {
            webView.restoreState(savedInstanceState); //  Restore WebView state on rotate
        } else {
            Log.d("WebView", " Loading index.html...");
            webView.loadUrl("file:///android_asset/index.html"); //  Load index.html from assets
        }
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        webView.saveState(outState); //  Save WebView state before rotation
    }

    @Override
    public void onBackPressed() {
        if (webView.canGoBack()) {
            webView.goBack(); //  Navigate back instead of exiting the app
        } else {
            super.onBackPressed(); // Exit the app if there's no history
        }
    }
}

How to use Socket.io Server in Oracle APEX

I am trying to learn how to use socket.io in Oracle APEX and have developed a small real-time chat with HTML, JS and node.js. In VS-Code everything works fine.

But now I want to integrate this chat into Oracle Apex. First I created a region, inserted my HTML and JS code and then started my node.js server (localhost:3000).

I always get the error message from Oracle:

“Mixed Content: The page at ‘’ was loaded via HTTPS, but
requested an insecure XMLHttpRequest endpoint ‘’. This request
has been blocked; the content must be served over HTTPS.”

I would like to use HTTP, as I am just learning the http and do not yet know how to create a node.JS server with https and certificates.

Does anyone have an idea how I can access my Node.JS server from Oracle APEX? Is it even possible to connect to my socket.io server with oracle apex, has anyone already tried it?

Workspace: ILYAS_TEST
User: demo1234
Password: demo1234
Application: 62505 (Chat)
Page: 1 (Home)
Oracle APEX 24.2.1

King Regards

Jegor

//Socket.io JS
$(function () {
    // Hilfsvariablen für HTML-Elemente werden mit Hilfe von JQuery gesetzt.
    var $window = $(window);
    var $usernameInput = $('.usernameInput'); // Eingabefeld für Benutzername
    var $messages = $('.messages');           // Liste mit Chat-Nachrichten
    var $inputMessage = $('.inputMessage');   // Eingabefeld für Chat-Nachricht
    var $loginPage = $('.login.page');        // Login-Seite
    var $chatPage = $('.chat.page');          // Chat-Seite
  
    var username;                             // Aktueller Benutzername
    var connected = false;                    // Kennzeichen ob angemeldet
    
    // Eingabefeld für Benutzername erhält den Fokus
    var $currentInput = $usernameInput.focus();
    
    // Socket.io Objekt anlegen
    var socket = io.connect('http://192.168.2.198:3000');
    console.log(socket)
  
    // ==== Code für Benutzerschnittstelle
  
    // Tastendruck behandeln
    $window.keydown(function (event) {
      // Die Return-Taste (Ascii 13) behandeln wir speziell
      if (event.which === 13) {
        if (username) {
          // Wenn der Benutzername schon gesetzt ist, handelt es sich
          // um eine Chat-Nachricht.
          sendMessage();
        } else {
          // Wenn der Benutzername noch nicht gesetzt ist, hat sich
          // der Benutzer gerade angemeldet.
          setUsername();
        }
      }
    });
  
    // Benutzername wird gesetzt
    function setUsername() {
      // Benutzername aus Eingabefeld holen (ohne Leerzeichen am Anfang oder Ende).
      username = $usernameInput.val().trim();
  
      // Prüfen, ob der Benutzername nicht leer ist
      if (username) {
        // Loginmaske ausblenden und Chat-Seite einblenden
        $loginPage.fadeOut();
        $chatPage.show();
  
        // Chat-Nachricht wird neues, aktuelles Eingabefeld
        $currentInput = $inputMessage.focus();
  
        // Server mit Socket.io über den neuen Benutzer informieren. Wenn die
        // Anmeldung klappt wird der Server die "login"-Nachricht zurückschicken.
        socket.emit('add user', username);
      }
    }
  
    // Chat-Nachricht versenden
    function sendMessage() {
      // Nachricht aus Eingabefeld holen (ohne Leerzeichen am Anfang oder Ende).
      var message = $inputMessage.val().trim();
        console.log(message)
        console.log(connected)
      // Prüfen, ob die Nachricht nicht leer ist und wir verbunden sind.
      if (message && connected) {
        // Eingabefeld auf leer setzen
        $inputMessage.val('');
  
        // Chat-Nachricht zum Chatprotokoll hinzufügen
        addChatMessage({ username: username, message: message });
        
        // Server über neue Nachricht informieren. Der Server wird die Nachricht
        // an alle anderen Clients verteilen.
        socket.emit('new message', message);
      }
    }
  
    // Protokollnachricht zum Chat-Protokoll anfügen
    function log(message) {
      var $el = $('<li>').addClass('log').text(message);
      $messages.append($el);
    }
  
    // Chat-Nachricht zum Chat-Protokoll anfügen
    function addChatMessage(data) {
      var $usernameDiv = $('<span class="username"/>').text(data.username);
      var $messageBodyDiv = $('<span class="messageBody">').text(data.message);
      var $messageDiv = $('<li class="message"/>').append($usernameDiv, $messageBodyDiv);
      $messages.append($messageDiv);
    }
  
    // ==== Code für Socket.io Events
  
    // Server schickt "login": Anmeldung war erfolgreich
    socket.on('login', function (data) {
        console.log("hi2")
      connected = true;
      log("Willkommen beim Chat!");
    });
  
    // Server schickt "new message": Neue Nachricht zum Chat-Protokoll hinzufügen
    socket.on('new message', function (data) {
      addChatMessage(data);
    });
  
    // Server schickt "user joined": Neuen Benutzer im Chat-Protokoll anzeigen
    socket.on('user joined', function (data) {
      log(data + ' joined');
    });
  
    // Server schickt "user left": Benutzer, der gegangen ist, im Chat-Protokoll anzeigen
    socket.on('user left', function (data) {
      log(data + ' left');
    });
  });
<html lang="de">
<head>
  <meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests" />
  <!-- <meta charset="UTF-8"> -->
  <title>CoderDojo Linz | Chat Beispiel</title>
  <style>
    /* Globale Schriftart setzen (weniger "schnörkelig") */
    body {
      font-family: sans-serif;
    }
    
    /* Chat-Seite initial ausblenden */
    .chat.page {
      display: none;
    }
    
    /* Format für Benutzernamen bei der Ausgabe einer Chat-Nachricht */
    .username {
      font-weight: bold;
      margin-right: 5px;
    }
  </style>
</head>
<body>
  <!-- Login-Seite -->
  <div class="login page">
    <h3 class="title">Wie ist dein Name?</h3>
    <input class="usernameInput" type="text" maxlength="14" />
  </div>

  <!-- Chat-Seite (initial ausgeblendet) -->
  <div class="chat page">
    <h3 class="title">Was möchtest du allen anderen mitteilen?</h3>
    <input class="inputMessage" placeholder="Type here..."/>
    <ul class="messages"></ul>
  </div>

  <!-- Programmcode auf der Client-Seite -->
  <script src="https://code.jquery.com/jquery-1.10.2.min.js"></script>
  <!-- <script src="http://192.168.2.198:3000/socket.io/socket.io.js"></script> -->
  <script src="https://cdn.socket.io/4.8.1/socket.io.min.js" integrity="sha384-mkQ3/7FUtcGyoppY6bz/PORYoGqOl7/aSUMn2ymDOJcapfS6PHqxhRTMh1RR0Q6+" crossorigin="anonymous"></script>
  <!-- <script src="main.js"></script> -->
</body>
</html>
// express und http Module importieren. Sie sind dazu da, die HTML-Dateien
// aus dem Ordner "public" zu veröffentlichen.
//
var express = require('express');
var app = require("express")();
var server = require('http').createServer(app);
// Mit dieser zusätzlichen Zeile bringen wir Socket.io in unseren Server.
var io = require('socket.io')(server);

// Mit diesem Kommando starten wir den Webserver.
var port = process.env.PORT || 3000;
server.listen(port, '192.168.2.198', function () {
  // Wir geben einen Hinweis aus, dass der Webserer läuft.
  console.log('Webserver läuft und hört auf Port %d', port);
});

// Hier teilen wir express mit, dass die öffentlichen HTML-Dateien
// im Ordner "public" zu finden sind.
app.use(express.static(__dirname));

// === Ab hier folgt der Code für den Chat-Server

// Hier sagen wir Socket.io, dass wir informiert werden wollen,
// wenn sich etwas bei den Verbindungen ("connections") zu 
// den Browsern tut. 
io.on('connection', function (socket) {
  // Die variable "socket" repräsentiert die aktuelle Web Sockets
  // Verbindung zu jeweiligen Browser client.
  
  // Kennzeichen, ob der Benutzer sich angemeldet hat 
  var addedUser = false;

  // Funktion, die darauf reagiert, wenn sich der Benutzer anmeldet
  socket.on('add user', function (username) {
    // Benutzername wird in der aktuellen Socket-Verbindung gespeichert
    socket.username = username;
    addedUser = true;
    
    // Dem Client wird die "login"-Nachricht geschickt, damit er weiß,
    // dass er erfolgreich angemeldet wurde.
    socket.emit('login');
    
    // Alle Clients informieren, dass ein neuer Benutzer da ist.
    socket.broadcast.emit('user joined', socket.username);
  });

  // Funktion, die darauf reagiert, wenn ein Benutzer eine Nachricht schickt
  socket.on('new message', function (data) {
    // Sende die Nachricht an alle Clients
    socket.broadcast.emit('new message', {
      username: socket.username,
      message: data
    });
    console.log(data)
  });

  // Funktion, die darauf reagiert, wenn sich ein Benutzer abmeldet.
  // Benutzer müssen sich nicht explizit abmelden. "disconnect"
  // tritt auch auf wenn der Benutzer den Client einfach schließt.
  socket.on('disconnect', function () {
    if (addedUser) {
      // Alle über den Abgang des Benutzers informieren
      socket.broadcast.emit('user left', socket.username);
    }
  });
});

ionic vue, bottom nav not rendering display in mobile

I have this layout in my ionic vue codebase,

<template>
    <ion-app :class="[className, 'overflow-y-scroll home__bg']">
        <ion-split-pane content-id="main-content">
            <!-- Side Menu -->
            <ion-menu content-id="main-content" type="overlay">
                <ion-header>
                    <ion-toolbar>
                        <ion-title>Menu</ion-title>
                    </ion-toolbar>
                </ion-header>
                <ion-content>
                    <ion-list>
                        <ion-menu-toggle auto-hide="false" v-for="item in navItems" :key="item.title">
                            <ion-item :router-link="item.to" router-direction="root" lines="none">
                                <ion-icon :icon="item.icon" slot="start" />
                                <ion-label>{{ item.title }}</ion-label>
                            </ion-item>
                        </ion-menu-toggle>
                    </ion-list>
                </ion-content>
            </ion-menu>

            <!-- Main Content -->
            <div class="ion-page" id="main-content">
                <ion-header>
                    <ion-toolbar>
                        <ion-buttons slot="start">
                            <ion-menu-button></ion-menu-button>
                        </ion-buttons>
                        <ion-title>{{ pageTitle }}</ion-title>
                        <ion-buttons slot="end">
                            <ion-button router-link="/notifications">
                                <ion-icon :icon="notificationsOutline" slot="icon-only" />
                            </ion-button>
                        </ion-buttons>
                    </ion-toolbar>
                </ion-header>

                <ion-content :class="['bg-background-primary']">
                    <div class="w-full">
                        <main class="py-5 px-10">
                            <ion-router-outlet />
                        </main>
                    </div>
                </ion-content>

                <!-- Bottom Navigation (visible only on mobile) -->
                <nav class="md:hidden fixed bottom-0 left-0 right-0 bg-white border-t border-gray-200 rounded-tr-3xl rounded-tl-2xl shadow-xl">
                    <div class="flex justify-around">
                        <router-link
                            v-for="item in bottomNavItems"
                            :key="item.to"
                            :to="item.to"
                            class="flex flex-col items-center py-2 px-3 text-gray-600 hover:text-primary"
                            active-class="text-primary"
                        >
                            <ion-icon :icon="item.icon" class="w-6 h-6" />
                            <span class="text-xs mt-1">{{ item.title }}</span>
                        </router-link>
                    </div>
                </nav>
            </div>
        </ion-split-pane>
    </ion-app>
</template>


<script setup lang="ts">
import { ISiteHeader, ISiteNavigation } from 'asc-lib'
import { ref, computed } from 'vue'
import { RouterLink, useRouter, useRoute } from "vue-router";
import { storeToRefs } from "pinia";
import { useAuthenticationStore } from "@/stores/authentication";
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
import { IonContent, IonApp, IonRouterOutlet, IonIcon, IonTabButton, IonTabs, IonLabel, IonTabBar  } from "@ionic/vue";
import { usePatientFaqService } from '@/composables/patients/usePatientFaqService';
import { usePatientKnowledgeDeskService } from '@/composables/patients/usePatientKnowledgeDeskService';
import {usePageTitle} from "@/composables/usePageTitle";
import { homeOutline, searchOutline, personOutline } from 'ionicons/icons';

const router = useRouter();
const route = useRoute();
const authenticationStore = useAuthenticationStore();
const isSiteNavigationOpen = ref<boolean>(false)
const { userType, user, lastLoginDate } = storeToRefs(authenticationStore);
const { pageTitle } = usePageTitle();
const { getAllCached: getAllFaqCached, faqs } = usePatientFaqService();
const { getAllCached: getAllKdCached, knowledgeDesks } = usePatientKnowledgeDeskService();

function toggleMenu() {
    isMenuOpen.value = !isMenuOpen.value
    isSiteNavigationOpen.value = !isSiteNavigationOpen.value
}

const className = route.meta.wrapperClass;

const navItems = ref([
    {
        title: 'Home',
        icon: 'house',
        to: { name: 'dashboard' }
    },
    {
        title: 'My Health',
        icon: 'heart',
        to: { name: 'dashboard' }
    },
    {
        title: 'Test Results',
        icon: 'clipboard',
        to: { name: 'dashboard' }
    },
    {
        title: 'Health Surveys',
        icon: 'clipboard-question',
        to: { name: 'surveys' }
    },
    {
        title: 'My Clinical Team',
        icon: 'people-group',
        to: { name: 'dashboard' }
    },
    {
        title: 'Information',
        icon: 'circle-info',
        to: { name: 'dashboard' }
    },
    {
        title: 'My Appointments',
        icon: 'calendar-days',
        to: { name: 'dashboard' }
    },
    {
        title: 'Notifications',
        icon: 'bell',
        to: { name: 'dashboard' }
    },
    {
        title: 'Logout',
        icon: 'right-from-bracket',
        to: { name: 'auth.logout' }
    }
]);

const bottomNavItems = ref([
    { title: 'Home', to: '/home', icon: homeOutline },
    { title: 'Health', to: '/search', icon: searchOutline },
    { title: 'Clinical Health', to: '/profile', icon: personOutline },
    { title: 'Test Results', to: '/profile', icon: personOutline },
    { title: 'Appts', to: '/profile', icon: personOutline },
]);

const isMenuOpen = ref<boolean>(false);

getAllFaqCached().then(function () {
    if (faqs.value && faqs.value.length) {
        faqs.value.forEach(function (faq) {
            navItems.value.splice(navItems.value.length - 1, 0, {
                component: RouterLink,
                title: faq.name,
                icon: 'circle-question',
                to: { name: 'faqs', params: { id: faq.id } }
            });
        })
    }
});

getAllKdCached().then(function () {
    if (knowledgeDesks.value && knowledgeDesks.value.length) {
        knowledgeDesks.value.forEach(function (knowledgeDesk) {
            navItems.value.splice(navItems.value.length - 1, 0, {
                component: RouterLink,
                title: knowledgeDesk.name,
                icon: 'circle-info',
                to: { name: 'knowledgeDesk', params: { id: knowledgeDesk.id } }
            });
        })
    }
});

const siteLink = computed(() => {
    if (userType.value == "practitioner") {
        return "/admin/dashboard"
    }

    return "/"
})

const handleProfileClick = () => {
    router.push({name: 'user.profile'})
}

</script>

<style lang="postcss" scoped>

.page__title {
    @apply text-title;
}

.home {
    .page__title {
        @apply text-white
    }

    .home__bg {
        background-image:url(/images/hero_section.png);
        background-position:top left;
        background-repeat: no-repeat;
        background-size:100%;
    }
}

</style>

The bottom nav displays at the bottom of the viewport in my browser, but when viewing on a mobile device, there is no bottom nav, and I cannot figure out why, not sure if it’s a CSS, vue, ionic or platform problem?

Next.js FormData Not Sending Nested Object Array Correctly in API Request

I’m working on a Next.js project where I need to send form data, including images and a nested object array (itineraries), to my API.

I have the following useState object:

 const [formData, setFormData] = useState({
  images: [],
  title: "",
  locationName: "",
  location: { lat: "", lon: "" },
  description: "",
  price: "",
  offerPrice: "",
  maxCapacity: "",
  duration: "",
  groupSize: "",
  language: ["English"],
  popularFeatures: [],
  included: [],
  excluded: [],
  highlights: "",
  itineraries: [
    { title: "Test", time: "10:00", image: null, description: "Sample", duration: 20 },
  ],
  peopleTypes: ["adult"],
  prices: { adult: "", child: "", infant: "" },
});

im submitting the form using FormData like this

    export const formatFormData = (formData) => {

    const data = new FormData();
  
  data.append("title", formData.title);
  data.append("locationName", formData.locationName);
  data.append("location", JSON.stringify(formData.location));
  data.append("description", formData.description);
  data.append("price", formData.price);
  data.append("offerPrice", formData.offerPrice);
  data.append("maxCapacity", formData.maxCapacity);
  data.append("duration", formData.duration);
  data.append("groupSize", formData.groupSize);
  data.append("language", JSON.stringify(formData.language));
  data.append("popularFeatures", JSON.stringify(formData.popularFeatures));
  data.append("included", JSON.stringify(formData.included));
  data.append("excluded", JSON.stringify(formData.excluded));
  data.append("highlights", formData.highlights);
  data.append("peopleTypes", JSON.stringify(formData.peopleTypes));
  data.append("prices", JSON.stringify(formData.prices));

  data.append("itineraries", JSON.stringify(formData.itineraries));

  // Append main images
  formData.images.forEach((image) => {
    data.append(`images`, image); // Append images (they will be stored as an array)
  });

  // Append images for itineraries
  formData.itineraries.forEach((itinerary, index) => {
    if (itinerary.image) {
      data.append(`itineraries[${index}][image]`, itinerary.image);
    }
  });
      
    return data;
};

and this is the data i get from client to server

title: 'Ab itaque sapiente m',
  description: '<p>Quis excepturi offic.</p>',
  location: '{"lat":34.0522,"lon":-118.2437}',
  locationName: 'Los Angeles',
  price: '688',
  prices: '{"adult":"","child":"","infant":"54"}',
  offerPrice: '309',
  peopleTypes: [ '["infant"]' ],
  duration: '5',
  groupSize: '10-15',
  language: [ '["Italian","English","Albanian","Spanish"]' ],
  maxCapacity: '10',
  popularFeatures: [ '["Relaxing","Swimming"]' ],
  highlight: '<p>Culpa ipsum, veniam.</p>',
  included: [ '["Neque nostrum ipsum"]' ],
  excluded: [ '["Porro in accusamus e"]' ],
  itineraries: [
    '[{"title":"Est ex eum natus vol","time":"17:38","image":{},"description":"Culpa mollitia volup","duration":"30"},{"title":"Quo aliqua Beatae a","image":{},"description":"Quia saepe animi re","duration":"26","time":"07:58"}]'  
  ]
}

but i cant not get the image as object is there any way to pass it as file object or should i sperate it in other field

Next.js – window is not defined error even when using useEffect and typeof window !== ‘undefined’ check

I am working on a Next.js project where I am encountering the error:
Error occurred prerendering page "/dashboard". Read more: https://nextjs.org/docs/messages/prerender-error ReferenceError: window is not defined at new u (D:ProjectsFREELANCEROAD RUNNER RSAFrontend.nextserverchunks500.js:13:9122)

  1. What I Have Tried
    Ensured the code runs only in the browser by wrapping window inside useEffect:
useEffect(() => {
  if (typeof window !== "undefined") {
    const scrollbarWidth =
      window.innerWidth - document.documentElement.clientWidth;
    setScrollbarWidth(scrollbarWidth);
  }
}, []);
  1. Checked that the component is a client component by adding “use client” at the top of the file:
"use client";
import { useEffect, useState } from "react";

3.Checked third-party libraries (lucide-react, framer-motion, next/navigation, and @radix-ui/react-visually-hidden) to ensure none of them are accessing window on the server.

Cannot read properties of undefined (reading ‘_id’) and Cast to ObjectId failed for value for express router

So I am having this two error in my terminal(postman):

This one for my authUser function in authController.js:

{
    "message": "Cast to ObjectId failed for value "{ email: '[email protected]' }" (type Object) at path "_id" for model "User"",
    "stack": "CastError: Cast to ObjectId failed for value "{ email: '[email protected]' }" (type Object) at path "_id" for model "User"n    at SchemaObjectId.cast (D:\PRATHAMESH\My_React\inotebook\backend\node_modules\mongoose\lib\schema\objectId.js:250:11)n    at SchemaType.applySetters (D:\PRATHAMESH\My_React\inotebook\backend\node_modules\mongoose\lib\schemaType.js:1255:12)n    at SchemaType.castForQuery (D:\PRATHAMESH\My_React\inotebook\backend\node_modules\mongoose\lib\schemaType.js:1673:17)n    at cast (D:\PRATHAMESH\My_React\inotebook\backend\node_modules\mongoose\lib\cast.js:319:34)n    at Query.cast (D:\PRATHAMESH\My_React\inotebook\backend\node_modules\mongoose\lib\query.js:4889:12)n    at Query._castConditions (D:\PRATHAMESH\My_React\inotebook\backend\node_modules\mongoose\lib\query.js:2306:10)n    at model.Query._findOne (D:\PRATHAMESH\My_React\inotebook\backend\node_modules\mongoose\lib\query.js:2630:8)n    at model.Query.exec (D:\PRATHAMESH\My_React\inotebook\backend\node_modules\mongoose\lib\query.js:4438:80)n    at process.processTicksAndRejections (node:internal/process/task_queues:105:5)n    at async D:\PRATHAMESH\My_React\inotebook\backend\controllers\authController.js:43:18"
}

and This one for my getUserProfile function in authController.js:

{
    "message": "Cannot read properties of undefined (reading '_id')",
    "stack": "TypeError: Cannot read properties of undefined (reading '_id')n    at D:\PRATHAMESH\My_React\inotebook\backend\controllers\authController.js:60:47n    at asyncUtilWrap (D:\PRATHAMESH\My_React\inotebook\backend\node_modules\express-async-handler\index.js:3:20)n    at Layer.handle [as handle_request] (D:\PRATHAMESH\My_React\inotebook\backend\node_modules\express\lib\router\layer.js:95:5)n    at next (D:\PRATHAMESH\My_React\inotebook\backend\node_modules\express\lib\router\route.js:149:13)n    at Route.dispatch (D:\PRATHAMESH\My_React\inotebook\backend\node_modules\express\lib\router\route.js:119:3)n    at Layer.handle [as handle_request] (D:\PRATHAMESH\My_React\inotebook\backend\node_modules\express\lib\router\layer.js:95:5)n    at D:\PRATHAMESH\My_React\inotebook\backend\node_modules\express\lib\router\index.js:284:15n    at Function.process_params (D:\PRATHAMESH\My_React\inotebook\backend\node_modules\express\lib\router\index.js:346:12)n    at next (D:\PRATHAMESH\My_React\inotebook\backend\node_modules\express\lib\router\index.js:280:10)n    at Function.handle (D:\PRATHAMESH\My_React\inotebook\backend\node_modules\express\lib\router\index.js:175:3)"
}

But,
registerUser runs quite well. Pls help. Here are my files:

Here controllers/authController.js:



const User = require('../models/User');
const jwt = require('jsonwebtoken');
const bcrypt = require('bcrypt');
const asyncHandler = require('express-async-handler');

const generateToken = (_id) => {
    return jwt.sign({ _id }, process.env.JWT_SECRET, {
        expiresIn: '30d',
    });
};

//Register User
const registerUser = asyncHandler(async (req, res) => {
    const { name, email, password } = req.body;
    const userExists = await User.findOne({ email });
    if(userExists){
        res.status(400);
        throw new Error('User already exits');
    }

    const user = await User.create({
        name,
        email,
        password
    });
    if(user){
        res.status(201).json({
            _id: user._id,
            name: user.name,
            email: user.email,
            token: generateToken(user._id),
        });
    }else{
        res.status(400);
        throw new Error('Invalid User Data');
    }
});

//Authentication user & get token
const authUser = asyncHandler(async (req, res) => {
    const { email, password } = req.body;

    const user = await User.findById({ email });

    if(user && (await user.matchPassword(password))){
        res.json({
            _id: user._id,
            name: user.name,
            email: user.email,
            token: generateToken(user._id),
        });
    }else{
        res.status(401);
        throw new Error('Invalid email or password');
    }
});

//Get User's Profile
const getUserProfile = asyncHandler(async (req, res) => {
    const user = await User.findById(req.user._id);
    if(user){
        res.status(201).json({
            _id: user._id,
            name: user.name,
            email: user.email,
            token: generateToken(user._id),
        });
    }else{
        res.status(404);
        throw new Error('User not found');
    }
});

module.exports = { registerUser, authUser, getUserProfile };

middleware/authMiddleware.js:

const jwt = require('jsonwebtoken');
const asyncHandler = require('express-async-handler');
const User = require('../models/User');

const protect = asyncHandler(async (req, res, next) => {
    let token;

    if(req.headers.authorization && req.headers.authorization.startsWith('Bearer')){
        try{
            token = req.headers.authorization.split('')[1];
            const decoded = jwt.verify(token, process.env.JWT_SECRET);
            req.user = await User.findBy(decoded.id).select('-password');
            next();
        } catch(err){
            console.log(err);
            res.status(401);
            throw new Error('Not authorized, token failed');
        }
    }

    if(!token){
        res.status(401);
        throw new Error('Not authorized, no token');
    }
});

module.exports = { protect };

middleware/errorMiddleware.js:

const notFound = (req, res, next) => {
    const error = new Error(`Not Found - ${req.orginalUrl}`);
    res.status(404);
    next(error);
};

const errorHandler = (err, req, res, next) => {
    const statusCode = res.statusCode === 200 ? 500 : res.statusCode;
    res.status(statusCode);
    res.json({
        message : err.message,
        stack : process.env.NODE_ENV === 'production' ? null : err.stack,
    });
};

module.exports = { notFound, errorHandler };

models/User.js:

const mongoose = require('mongoose');
const bcrypt = require('bcrypt');

// define the User model schema
const UserSchema = new mongoose.Schema({
  name:{
    type: String,
    required: true
  },
  email: {
    type: String,
    index: { unique: true },
    required: true
  },
  password: {
    type: String,
    required: true
  }
});

UserSchema.pre('save', async function (next) {
  if(!this.isModified('password')){
    next();
  }
  const salt = await bcrypt.genSalt(10);
  this.password = await bcrypt.hash(this.password, salt);
})

UserSchema.methods.matchPassword = async function (enteredPassword) {
  return await bcrypt.compare(enteredPassword, this.password);
}

const User = mongoose.model('User', UserSchema);
module.exports = User;

models/Notes.js:

const mongoose = require('mongoose');

const NotesSchema = new mongoose.Schema({
  title:{
    type: String,
    required: true
  },
  content: {
    type: String,
    required: true
  }
});

const Notes = mongoose.model('Notes', UserSchema);
module.exports = Notes;

routes/authRoutes.js:

const express = require('express');
const { registerUser, authUser, getUserProfile } = require('../controllers/authController')
const{ protect } = require('../middleware/authMiddleware');

const router = express.Router();

router.post('/register', registerUser);
router.post('/login', authUser);
router.get('/profile', getUserProfile);

module.exports = router;

db.js:

const mongoose = require('mongoose');

const mongoDBURL = "mongodb://127.0.0.1:27017/iNotebookDatabase?directConnection=true&serverSelectionTimeoutMS=2000&appName=mongosh+2.3.4";
const connectToMongo = mongoose.connect(mongoDBURL)
    .then(() => console.log('Connected to MongoDB'))
    .catch(err => console.error('MongoDB connection error:', err));

module.exports = connectToMongo;

index.js:

const connectToMongo = require('./db');
const express = require('express');
const cors = require('cors');
const authRoutes = require('./routes/authRoutes')
const { notFound, errorHandler } = require('./middleware/errorMiddleware');
const dotenv = require('dotenv'); 
dotenv.config();

const app = express();
const PORT = 5000;
app.use(express.json());


app.use('/api/auth', authRoutes);

app.use(notFound);
app.use(errorHandler);

connectToMongo
      .then(() => {
            app.listen(PORT, () => {
                  console.log(`Server is running on port http://localhost:${PORT}`);
            });
      })
      .catch(err => console.log(err));

.env:

JWT_SECRET="Chaleya";
NODE_ENV="production";

Unique formula validation with regex

I have a unique javascript formula validation question. Here are my basic requirements.

The equation must have only 2 variables, a variable and a number or 2
numbers.
Only addition, subtraction and division are allowed.
Each non numeric variable must have opening and closing double curly
braces.

Some examples:

  • “{{purchase_date}} + {{0-175632-441947}}” // valid

  • “{{purchase_date}}+{{0-175632-441947}}” // valid

  • “{{purchase_date}} + 14” // valid

  • “14 + {{purchase_date}}” // valid

  • “” // not valid – empty

  • “(a * b) / 2” // not valid – includes
    division, and more than 2 variables, not includes curly braces

  • “{{0-175632-441947}} + {{purchase_date}}” // valid

  • “{{0-175632-441947}}+{{purchase_date}}” // valid

  • “{{0-175632-441947}}-{{purchase_date}}” // valid

  • “{{purchase_amount}} + {{discount_amount}} + {{store_credit}}” //
    not valid, more than 2 variables

  • ” {{0-175632-441947}} + {{0-175632-441988}} – {{0-175632-56447}} –
    {{0-175612-246117}}” // not valid, more than 2 variables

  • ” 5+3 ” // valid

  • ” 8 * 10 ” // valid

  • ” 5 * 2 + 1 ” // not valid , more than 2 numbers

  • ” 8 / 2″ // not valid, includes division

  • ” purchase_date + 14 ” // not valid, missing {{ and }}

  • ” {{purchase_date + 14 ” // not valid missing }}

  • ” 14 + purchase_date}} ” // not valid missing {{

  • “{{0-175632-441947}}-purchase_date}}” // not valid missing {{

Using whisper.cpp in SvelteKit

I’m trying to integrate the Whisper.cpp stream web demo into my SvelteKit project for local browser-based speech recognition. I’ve analyzed their implementation which uses WebAssembly with a worker thread setup.

The original implementation consists of several key files:

  • stream.js: This is the core file that manages WebAssembly (WASM) functionality. It handles memory management, file system operations, and provides the interface between JavaScript and the compiled C/C++ code. It’s responsible for initializing the WASM module and managing its runtime environment.
  • index.html: This is the main entry point of the application that provides the user interface and core browser functionality. It contains the UI elements, manages the application’s cache through IndexedDB, handles file uploads and downloads, and coordinates communication between different parts of the application.
  • libstream.worker.js: This is a Web Worker script that runs in a separate thread from the main UI. It handles computationally intensive tasks to prevent the main interface from becoming unresponsive. It’s designed to work in both browser and Node.js environments and manages thread-specific operations and message passing.
  • server.py: A simple Python-based HTTP server that serves the application files and handles Cross-Origin Resource Sharing (CORS) headers. This enables the necessary permissions for WebAssembly to function properly and allows the application to make requests for resources across different origins.

I have tried using the same structure in SvelteKit, moving stream.js and libstream.worker.js to /static and and replacing /src/app.html with my index.html file, but adding %sveltekit.head% to the head and <body data-sveltekit-preload-data="hover"> <div style="display: contents">%sveltekit.body%</div> to the top of the body. disabled ssr rendering with src/routes/+page.ts: export const ssr = false;. Finally, I added src/hooks.server.ts:

import type { Handle } from "@sveltejs/kit";

export const handle: Handle = async ({ event, resolve }) => {
  const response = await resolve(event);

  // Add security headers
  response.headers.set("Cross-Origin-Opener-Policy", "same-origin");
  response.headers.set("Cross-Origin-Embedder-Policy", "require-corp");

  return response;
};

When I try running my code using pnpm dev and navigate to localhost:5173, I get the following error in the browser console:

example of error

One potential reason for my error is that the web worker does not start. In the pure HTML project hosted with python, I see several libstream.worker.js in the sources tab of the dev tools, but I do not see these in my sveltekit implementation.

example of workers running in the browser

How can I fix this so that I am able to run the wasm-version of whisper.cpp in browser?

Part of stream.js where the error is thrown. It is thrown in the worker.onerror part.

loadWasmModuleToWorker: function(worker, onFinishedLoading) {
    worker.onmessage = e => {
        var d = e["data"];
        var cmd = d["cmd"];
        if (worker.pthread_ptr)
            PThread.currentProxiedOperationCallerThread = worker.pthread_ptr;
        if (d["targetThread"] && d["targetThread"] != _pthread_self()) {
            var targetWorker = PThread.pthreads[d.targetThread];
            if (targetWorker) {
                targetWorker.postMessage(d, d["transferList"])
            } else {
                err('Internal error! Worker sent a message "' + cmd + '" to target pthread ' + d["targetThread"] + ", but that thread no longer exists!")
            }
            PThread.currentProxiedOperationCallerThread = undefined;
            return
        }
        if (cmd === "processProxyingQueue") {
            executeNotifiedProxyingQueue(d["queue"])
        } else if (cmd === "spawnThread") {
            spawnThread(d)
        } else if (cmd === "cleanupThread") {
            cleanupThread(d["thread"])
        } else if (cmd === "killThread") {
            killThread(d["thread"])
        } else if (cmd === "cancelThread") {
            cancelThread(d["thread"])
        } else if (cmd === "loaded") {
            worker.loaded = true;
            if (ENVIRONMENT_IS_NODE) {}
            if (onFinishedLoading)
                onFinishedLoading(worker);
            if (worker.runPthread) {
                worker.runPthread()
            }
        } else if (cmd === "print") {
            out("Thread " + d["threadId"] + ": " + d["text"])
        } else if (cmd === "printErr") {
            err("Thread " + d["threadId"] + ": " + d["text"])
        } else if (cmd === "alert") {
            alert("Thread " + d["threadId"] + ": " + d["text"])
        } else if (d.target === "setimmediate") {
            worker.postMessage(d)
        } else if (cmd === "callHandler") {
            Module[d["handler"]](...d["args"])
        } else if (cmd) {
            err("worker sent an unknown command " + cmd)
        }
        PThread.currentProxiedOperationCallerThread = undefined
    }
    ;
    worker.onerror = e => {
        var message = "worker sent an error!";
        err(message + " " + e.filename + ":" + e.lineno + ": " + e.message);
        throw e
    }
    ;
    if (ENVIRONMENT_IS_NODE) {}
    var handlers = [];
    var knownHandlers = ["onExit", "onAbort", "print", "printErr"];
    for (var handler of knownHandlers) {
        if (Module.hasOwnProperty(handler)) {
            handlers.push(handler)
        }
    }
    worker.postMessage({
        "cmd": "load",
        "handlers": handlers,
        "urlOrBlob": Module["mainScriptUrlOrBlob"] || _scriptDir,
        "wasmMemory": wasmMemory,
        "wasmModule": wasmModule
    })
},

Original files:

  • index.html
<!doctype html>
<html lang="en-us">
 <body>
   <div id="model-whisper">
    <span id="model-whisper-status"></span>
    <button id="fetch-whisper-base-en-q5_1"   onclick="loadWhisper('base-en-q5_1')">base.en (Q5_1, 57 MB)</button>
    <span id="fetch-whisper-progress"></span>
   </div>

   <div id="input">
    <button id="start"  onclick="onStart()" disabled>Start</button>
    <button id="stop"   onclick="onStop()" disabled>Stop</button>
   </div>

   <br>

   <div id="state">
    <span id="state-status">not started</span></b>

    <pre id="state-transcribed">[The transcribed text will be displayed here]</pre>
   </div>

   <textarea id="output" rows="20"></textarea>

  <script type="text/javascript">
   // Common Javascript functions used by the examples

   function convertTypedArray(src, type) {
    var buffer = new ArrayBuffer(src.byteLength);
    var baseView = new src.constructor(buffer).set(src);
    return new type(buffer);
   }

   var printTextarea = (function() {
    var element = document.getElementById('output');
    if (element) element.value = ''; // clear browser cache
    return function(text) {
     if (arguments.length > 1) text = Array.prototype.slice.call(arguments).join(' ');
     console.log(text);
     if (element) {
      element.value += text + "n";
      element.scrollTop = element.scrollHeight; // focus on bottom
     }
    };
   })();

   async function clearCache() {
    if (confirm('Are you sure you want to clear the cache?nAll the models will be downloaded again.')) {
     indexedDB.deleteDatabase(dbName);
    }
   }

   // fetch a remote file from remote URL using the Fetch API
   async function fetchRemote(url, cbProgress, cbPrint) {
    cbPrint('fetchRemote: downloading with fetch()...');

    const response = await fetch(
     url,
     {
      method: 'GET',
      headers: {
       'Content-Type': 'application/octet-stream',
      },
     }
    );

    if (!response.ok) {
     cbPrint('fetchRemote: failed to fetch ' + url);
     return;
    }

    const contentLength = response.headers.get('content-length');
    const total = parseInt(contentLength, 10);
    const reader = response.body.getReader();

    var chunks = [];
    var receivedLength = 0;
    var progressLast = -1;

    while (true) {
     const { done, value } = await reader.read();

     if (done) {
      break;
     }

     chunks.push(value);
     receivedLength += value.length;

     if (contentLength) {
      cbProgress(receivedLength/total);

      var progressCur = Math.round((receivedLength / total) * 10);
      if (progressCur != progressLast) {
       cbPrint('fetchRemote: fetching ' + 10*progressCur + '% ...');
       progressLast = progressCur;
      }
     }
    }

    var position = 0;
    var chunksAll = new Uint8Array(receivedLength);

    for (var chunk of chunks) {
     chunksAll.set(chunk, position);
     position += chunk.length;
    }

    return chunksAll;
   }

   // load remote data
   // - check if the data is already in the IndexedDB
   // - if not, fetch it from the remote URL and store it in the IndexedDB
   function loadRemote(url, dst, size_mb, cbProgress, cbReady, cbCancel, cbPrint) {
    if (!navigator.storage || !navigator.storage.estimate) {
     cbPrint('loadRemote: navigator.storage.estimate() is not supported');
    } else {
     // query the storage quota and print it
     navigator.storage.estimate().then(function (estimate) {
      cbPrint('loadRemote: storage quota: ' + estimate.quota + ' bytes');
      cbPrint('loadRemote: storage usage: ' + estimate.usage + ' bytes');
     });
    }

    // check if the data is already in the IndexedDB
    var rq = indexedDB.open(dbName, dbVersion);

    rq.onupgradeneeded = function (event) {
     var db = event.target.result;
     if (db.version == 1) {
      var os = db.createObjectStore('models', { autoIncrement: false });
      cbPrint('loadRemote: created IndexedDB ' + db.name + ' version ' + db.version);
     } else {
      // clear the database
      var os = event.currentTarget.transaction.objectStore('models');
      os.clear();
      cbPrint('loadRemote: cleared IndexedDB ' + db.name + ' version ' + db.version);
     }
    };

    rq.onsuccess = function (event) {
     var db = event.target.result;
     var tx = db.transaction(['models'], 'readonly');
     var os = tx.objectStore('models');
     var rq = os.get(url);

     rq.onsuccess = function (event) {
      if (rq.result) {
       cbPrint('loadRemote: "' + url + '" is already in the IndexedDB');
       cbReady(dst, rq.result);
      } else {
       // data is not in the IndexedDB
       cbPrint('loadRemote: "' + url + '" is not in the IndexedDB');

       // alert and ask the user to confirm
       if (!confirm(
        'You are about to download ' + size_mb + ' MB of data.n' +
        'The model data will be cached in the browser for future use.nn' +
        'Press OK to continue.')) {
        cbCancel();
        return;
       }

       fetchRemote(url, cbProgress, cbPrint).then(function (data) {
        if (data) {
         // store the data in the IndexedDB
         var rq = indexedDB.open(dbName, dbVersion);
         rq.onsuccess = function (event) {
          var db = event.target.result;
          var tx = db.transaction(['models'], 'readwrite');
          var os = tx.objectStore('models');

          var rq = null;
          try {
           var rq = os.put(data, url);
          } catch (e) {
           cbPrint('loadRemote: failed to store "' + url + '" in the IndexedDB: n' + e);
           cbCancel();
           return;
          }

          rq.onsuccess = function (event) {
           cbPrint('loadRemote: "' + url + '" stored in the IndexedDB');
           cbReady(dst, data);
          };

          rq.onerror = function (event) {
           cbPrint('loadRemote: failed to store "' + url + '" in the IndexedDB');
           cbCancel();
          };
         };
        }
       });
      }
     };

     rq.onerror = function (event) {
      cbPrint('loadRemote: failed to get data from the IndexedDB');
      cbCancel();
     };
    };

    rq.onerror = function (event) {
     cbPrint('loadRemote: failed to open IndexedDB');
     cbCancel();
    };

    rq.onblocked = function (event) {
     cbPrint('loadRemote: failed to open IndexedDB: blocked');
     cbCancel();
    };

    rq.onabort = function (event) {
     cbPrint('loadRemote: failed to open IndexedDB: abort');
     cbCancel();
    };
   }
  </script>
  <script type='text/javascript'>
   // web audio context
   var context = null;

   // audio data
   var audio = null;
   var audio0 = null;

   // the stream instance
   var instance = null;

   // model name
   var model_whisper = null;

   var Module = {
    print: printTextarea,
    printErr: printTextarea,
    setStatus: function(text) {
     printTextarea('js: ' + text);
    },
    monitorRunDependencies: function(left) {
    },
    preRun: function() {
     printTextarea('js: Preparing ...');
    },
    postRun: function() {
     printTextarea('js: Initialized successfully!');
    }
   };

   //
   // fetch models
   //

   let dbVersion = 1
   let dbName = 'whisper.ggerganov.com';
   let indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB

   function storeFS(fname, buf) {
    // write to WASM file using FS_createDataFile
    // if the file exists, delete it
    try {
     Module.FS_unlink(fname);
    } catch (e) {
     // ignore
    }

    Module.FS_createDataFile("/", fname, buf, true, true);

    printTextarea('storeFS: stored model: ' + fname + ' size: ' + buf.length);

    document.getElementById('model-whisper-status').innerHTML = 'loaded "' + model_whisper + '"!';

    if (model_whisper != null) {
     document.getElementById('start').disabled = false;
     document.getElementById('stop' ).disabled = true;
    }
   }

   function loadWhisper(model) {
    let urls = {
     'base-en-q5_1':  '/models/ggml-model-whisper-base.en-q5_1.bin',
    };

    let sizes = {
     'base-en-q5_1':   57,
    };

    let url  = urls[model];
    let dst  = 'whisper.bin';
    let size_mb = sizes[model];

    model_whisper = model;

    document.getElementById('fetch-whisper-base-en-q5_1').style.display = 'none';

    document.getElementById('model-whisper-status').innerHTML = 'loading "' + model + '" ... ';

    cbProgress = function(p) {
     let el = document.getElementById('fetch-whisper-progress');
     el.innerHTML = Math.round(100*p) + '%';
    };

    cbCancel = function() {
     var el;
     el = document.getElementById('fetch-whisper-base-en-q5_1'); if (el) el.style.display = 'inline-block';

     el = document.getElementById('model-whisper-status');  if (el) el.innerHTML = '';
    };

    loadRemote(url, dst, size_mb, cbProgress, storeFS, cbCancel, printTextarea);
   }

   //
   // microphone
   //

   const kSampleRate = 16000;
   const kRestartRecording_s = 120;
   const kIntervalAudio_ms = 5000; // pass the recorded audio to the C++ instance at this rate

   var mediaRecorder = null;
   var doRecording = false;
   var startTime = 0;

   window.AudioContext = window.AudioContext || window.webkitAudioContext;
   window.OfflineAudioContext = window.OfflineAudioContext || window.webkitOfflineAudioContext;

   function stopRecording() {
    Module.set_status("paused");
    doRecording = false;
    audio0 = null;
    audio = null;
    context = null;
   }

   function startRecording() {
    if (!context) {
     context = new AudioContext({
      sampleRate: kSampleRate,
      channelCount: 1,
      echoCancellation: false,
      autoGainControl:  true,
      noiseSuppression: true,
     });
    }

    Module.set_status("");

    document.getElementById('start').disabled = true;
    document.getElementById('stop').disabled = false;

    doRecording = true;
    startTime = Date.now();

    var chunks = [];
    var stream = null;

    navigator.mediaDevices.getUserMedia({audio: true, video: false})
     .then(function(s) {
      stream = s;
      mediaRecorder = new MediaRecorder(stream);
      mediaRecorder.ondataavailable = function(e) {
       chunks.push(e.data);

       var blob = new Blob(chunks, { 'type' : 'audio/ogg; codecs=opus' });
       var reader = new FileReader();

       reader.onload = function(event) {
        var buf = new Uint8Array(reader.result);

        if (!context) {
         return;
        }
        context.decodeAudioData(buf.buffer, function(audioBuffer) {
         var offlineContext = new OfflineAudioContext(audioBuffer.numberOfChannels, audioBuffer.length, audioBuffer.sampleRate);
         var source = offlineContext.createBufferSource();
         source.buffer = audioBuffer;
         source.connect(offlineContext.destination);
         source.start(0);

         offlineContext.startRendering().then(function(renderedBuffer) {
          audio = renderedBuffer.getChannelData(0);

          //printTextarea('js: audio recorded, size: ' + audio.length + ', old size: ' + (audio0 == null ? 0 : audio0.length));

          var audioAll = new Float32Array(audio0 == null ? audio.length : audio0.length + audio.length);
          if (audio0 != null) {
           audioAll.set(audio0, 0);
          }
          audioAll.set(audio, audio0 == null ? 0 : audio0.length);

          if (instance) {
           Module.set_audio(instance, audioAll);
          }
         });
        }, function(e) {
         audio = null;
        });
       }

       reader.readAsArrayBuffer(blob);
      };

      mediaRecorder.onstop = function(e) {
       if (doRecording) {
        setTimeout(function() {
         startRecording();
        });
       }
      };

      mediaRecorder.start(kIntervalAudio_ms);
     })
     .catch(function(err) {
      printTextarea('js: error getting audio stream: ' + err);
     });

    var interval = setInterval(function() {
     if (!doRecording) {
      clearInterval(interval);
      mediaRecorder.stop();
      stream.getTracks().forEach(function(track) {
       track.stop();
      });

      document.getElementById('start').disabled = false;
      document.getElementById('stop').disabled  = true;

      mediaRecorder = null;
     }

     // if audio length is more than kRestartRecording_s seconds, restart recording
     if (audio != null && audio.length > kSampleRate*kRestartRecording_s) {
      if (doRecording) {
       //printTextarea('js: restarting recording');

       clearInterval(interval);
       audio0 = audio;
       audio = null;
       mediaRecorder.stop();
       stream.getTracks().forEach(function(track) {
        track.stop();
       });
      }
     }
    }, 100);
   }

   //
   // main
   //

   var nLines = 0;
   var intervalUpdate = null;
   var transcribedAll = '';

   function onStart() {
    if (!instance) {
     instance = Module.init('whisper.bin');

     if (instance) {
      printTextarea("js: whisper initialized, instance: " + instance);
     }
    }

    if (!instance) {
     printTextarea("js: failed to initialize whisper");
     return;
    }

    startRecording();

    intervalUpdate = setInterval(function() {
     var transcribed = Module.get_transcribed();

     if (transcribed != null && transcribed.length > 1) {
      transcribedAll += transcribed + '<br>';
      nLines++;

      // if more than 10 lines, remove the first line
      if (nLines > 10) {
       var i = transcribedAll.indexOf('<br>');
       if (i > 0) {
        transcribedAll = transcribedAll.substring(i + 4);
        nLines--;
       }
      }
     }

     document.getElementById('state-status').innerHTML = Module.get_status();
     document.getElementById('state-transcribed').innerHTML = transcribedAll;
    }, 100);
   }

   function onStop() {
    stopRecording();
   }

  </script>
  <script type="text/javascript" src="stream.js"></script>
 </body>
</html>
  • libstream.worker.js
"use strict";
var Module = {};
var ENVIRONMENT_IS_NODE =
  typeof process == "object" &&
  typeof process.versions == "object" &&
  typeof process.versions.node == "string";
if (ENVIRONMENT_IS_NODE) {
  var nodeWorkerThreads = require("worker_threads");
  var parentPort = nodeWorkerThreads.parentPort;
  parentPort.on("message", (data) =>
    onmessage({
      data: data,
    })
  );
  var fs = require("fs");
  Object.assign(global, {
    self: global,
    require: require,
    Module: Module,
    location: {
      href: __filename,
    },
    Worker: nodeWorkerThreads.Worker,
    importScripts: function (f) {
      (0, eval)(fs.readFileSync(f, "utf8") + "//# sourceURL=" + f);
    },
    postMessage: function (msg) {
      parentPort.postMessage(msg);
    },
    performance: global.performance || {
      now: function () {
        return Date.now();
      },
    },
  });
}
var initializedJS = false;
var pendingNotifiedProxyingQueues = [];
function threadPrintErr() {
  var text = Array.prototype.slice.call(arguments).join(" ");
  if (ENVIRONMENT_IS_NODE) {
    fs.writeSync(2, text + "n");
    return;
  }
  console.error(text);
}
function threadAlert() {
  var text = Array.prototype.slice.call(arguments).join(" ");
  postMessage({
    cmd: "alert",
    text: text,
    threadId: Module["_pthread_self"](),
  });
}
var err = threadPrintErr;
self.alert = threadAlert;
Module["instantiateWasm"] = (info, receiveInstance) => {
  var instance = new WebAssembly.Instance(Module["wasmModule"], info);
  receiveInstance(instance);
  Module["wasmModule"] = null;
  return instance.exports;
};
self.onunhandledrejection = (e) => {
  throw e.reason ?? e;
};
self.onmessage = (e) => {
  try {
    if (e.data.cmd === "load") {
      Module["wasmModule"] = e.data.wasmModule;
      for (const handler of e.data.handlers) {
        Module[handler] = function () {
          postMessage({
            cmd: "callHandler",
            handler: handler,
            args: [...arguments],
          });
        };
      }
      Module["wasmMemory"] = e.data.wasmMemory;
      Module["buffer"] = Module["wasmMemory"].buffer;
      Module["ENVIRONMENT_IS_PTHREAD"] = true;
      if (typeof e.data.urlOrBlob == "string") {
        importScripts(e.data.urlOrBlob);
      } else {
        var objectUrl = URL.createObjectURL(e.data.urlOrBlob);
        importScripts(objectUrl);
        URL.revokeObjectURL(objectUrl);
      }
    } else if (e.data.cmd === "run") {
      Module["__performance_now_clock_drift"] = performance.now() - e.data.time;
      Module["__emscripten_thread_init"](e.data.pthread_ptr, 0, 0, 1);
      Module["establishStackSpace"]();
      Module["PThread"].receiveObjectTransfer(e.data);
      Module["PThread"].threadInitTLS();
      if (!initializedJS) {
        Module["__embind_initialize_bindings"]();
        pendingNotifiedProxyingQueues.forEach((queue) => {
          Module["executeNotifiedProxyingQueue"](queue);
        });
        pendingNotifiedProxyingQueues = [];
        initializedJS = true;
      }
      try {
        Module["invokeEntryPoint"](e.data.start_routine, e.data.arg);
      } catch (ex) {
        if (ex != "unwind") {
          if (ex instanceof Module["ExitStatus"]) {
            if (Module["keepRuntimeAlive"]()) {
            } else {
              Module["__emscripten_thread_exit"](ex.status);
            }
          } else {
            throw ex;
          }
        }
      }
    } else if (e.data.cmd === "cancel") {
      if (Module["_pthread_self"]()) {
        Module["__emscripten_thread_exit"](-1);
      }
    } else if (e.data.target === "setimmediate") {
    } else if (e.data.cmd === "processProxyingQueue") {
      if (initializedJS) {
        Module["executeNotifiedProxyingQueue"](e.data.queue);
      } else {
        pendingNotifiedProxyingQueues.push(e.data.queue);
      }
    } else if (e.data.cmd) {
      err("worker.js received unknown command " + e.data.cmd);
      err(e.data);
    }
  } catch (ex) {
    if (Module["__emscripten_thread_crashed"]) {
      Module["__emscripten_thread_crashed"]();
    }
    throw ex;
  }
};

Full code dump including the 5000 line stream.js: https://gist.github.com/vlashada/445169a9d543e973cc5813d2ec3f2ed1

I have tried my very best to include everything relevant and to make the examples as minimal as possible, but please let me know if I can do anything more to increase clarity.

Mocking an object method of an instance in JEST to use it as a dependency injection

I have the http class:

class http {
constructor() {}

public async request(url: string, options: RequestInit): Promise<Response> {
    const response = await fetch(`${url}`, options)
    return response
}

public async get(url: string): Promise<Response> {
    return this.request(url, { method: 'GET' })
}

public async post(url: string, data?: any): Promise<Response> {
    return this.request(url, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(data),
    })
}

public async put(url: string, data?: any): Promise<Response> {
    return this.request(url, {
        method: 'PUT',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(data),
    })
}

public async delete(url: string): Promise<Response> {
    return this.request(url, { method: 'DELETE' })
}

}

export default http

Then i use the http class inside Core as an injected dependency

export class Core {
public http: http

constructor(http: http) {
    this.http = http
}

public async getUserDomainNameEntry(
    username: string,
    domainUrl: string,
): Promise<IDomainNameEntry | undefined> {
    const response = await this.http.get(
        `${domainUrl}/api/v1/dns/search/username/${username}`,
    )

    if (response.status === 404 || !response.ok) {
        console.log(response)
        return undefined
    }

    const dnsEntry: IDomainNameEntry = await response.json()
    return dnsEntry
}
}

This is my jest test:

import { Core } from '.'
import http from '../http'

it('Domain Name Entry Test', async () => {
    http.prototype.get = jest.fn(async (_url: string) =>
        Promise.resolve({
            ok: true,
            status: 200,
            json: async () => ({ name: 'javierhersan.stw', urls: [], ips: [] }),
        } as Response),
    )

    const core = new Core(new http())
    const domainNameEntry = await core.getUserDomainNameEntry(
        'javierhersan.stw',
        'http://localhost:3000',
    )

    expect(domainNameEntry).toBeDefined()
    if (domainNameEntry) {
        expect(domainNameEntry).toHaveProperty('name')
        expect(domainNameEntry).toHaveProperty('urls')
        expect(domainNameEntry).toHaveProperty('ips')
    }
})

Error

TypeError: fetch failed

  3 |
  4 |       public async request(url: string, options: RequestInit): Promise<Response> {
> 5 |               const response = await fetch(`${url}`, options)
    |                                ^
  6 |               return response
  7 |       }
  8 |

  at http.request (src/http/index.ts:5:20)
  at Core.getUserDomainNameEntry (src/core/index.ts:172:20)
  at Object.<anonymous> (src/core/index.test.ts:116:27)

Why is my mock method not overriding my http get original method. What is the best way of mocking an object method and injecting it as a dependency with jest? I have tested several ways and is not working is always calling the original get method, why?

Custom Browser Shortcuts (not Chromium based or any)

I am looking for an automation of some browser actions, for example: tab switching, copying, removing or pasting objects.

I tried to use AHK but found it too complicated to integrate it in Chrome, then I used AutoControl as it is able to run JS in tabs, but now I’m switching to Firefox which doesn’t support it and I don’t want to do manually what I was automating.

Are there any good alternatives? The closest I have found is using Selenium with Python or another language but I am not sure if it is good for my needs.

Most of information just too old and there may be a better solution like Firefox add-on, library or program I didn’t even think about.

Real-Time Synchronization with Minimal Latency via WebSockets and Edge Computing

I am developing a fleet tracking application where vehicle GPS data is to be monitored in real time on a central PC. Using WebSockets and Edge Computing, GPS data is processed currently on each (people’s) mobile and then transmitted to the PC with minimal latency. This enables efficient real-time information transmission, even in areas with limited network connectivity.

We try to protect GPS data during transmission and local storage specialy on updates.

We currently use WSS which is the secure version of WebSocket, it uses TLS/SSL to encrypt the data exchanged between the client and the server.

const fs = require('fs');
const https = require('https');
const WebSocket = require('ws');

const server = https.createServer({
  cert: fs.readFileSync('path/to/cert.pem'),
  key: fs.readFileSync('path/to/key.pem')
});

const wss = new WebSocket.Server({ server });

wss.on('connection', (ws) => {
  console.log('Client connected');
  ws.on('message', (message) => {
    console.log(`Received: ${message}`);
  });
});

server.listen(8080, () => {
  console.log('WebSocket server is running on wss://localhost:8080');
});

There are other protocols such as Protection against CSRF Attacks (Cross-Site Request Forgery)

The problem with the Socket.IO server is that it uses a fallback mechanism for clients that do not support WebSocket. It can switch to alternative methods like HTTP long-polling. How can I resolve this failover problem during system updates ?

We tried few mobile systems and we are looking for universal and stable protocol