Waiting for response in login function async/await

I have login page on my application.
That’s part of logging function:

this.loginService.doLogin(this.request).then(res => {
 this.storage.set("auth-key", res.token);
 this.authService.identity();
 if (this.authService.isAuthenticated()) 
     this.router.navigate(["expert-profile", this.authService.getCurrentUser().id], { queryParams: { lang: this.lang } });
     return;
 } else {
     this.storage.remove("auth-key");
     this.router.navigateByUrl("/login");
 }
}).catch(err => {
    this.storage.remove("auth-key");
  });

identity() {
   if (this.storage.get("auth-key")) {
     this.fetch().then(res => {
       this.userIdentity = {
         id: res.id,
         isAuthorized: res.isAuthorized
       };
       sessionStorage.setItem("userLoggedId", JSON.stringify(this.userIdentity.id));
       this.authenticated = true;
     }).catch(err => {
       this.storage.remove("auth-key");
       sessionStorage.removeItem("userLoggedId");
       this.authenticated = false;
   });


  public async fetch(): Promise<User> {
     const response = this.http.get<User>(environment.userDetailsUrl, { headers: new HttpHeaders({ "Authorization": "Bearer " + this.storage.get("auth-key") }) });
     return await firstValueFrom(response);

}

I have following problem. To log in I must press login button two times because the first time the response from the fetch function will probably not arrive in time (this.authenticated = false;).
If I click login second time, this.authenticated is true, and user have redirect to proper page
How to make

Sending emoji over email using surrogate pair in NodeJs

I’m trying to send an email with the emoji uD83DuDC49 in the body. This emoji has already been placed inside an AWS SES template. Sourcing the HTML string from SES using the following function:

getAndFillSESEmailTemplate: (templateName, templateData) => {
    return new Promise((resolve, reject) => {
      var params = {
        TemplateName: templateName
      };
      ses.getTemplate(params, (err, data) => {
          if(err){
            return reject(err);
          }
          var templateHTML = data.Template.HtmlPart;
          var templateDataKeys = Object.keys(templateData);
          templateDataKeys.forEach((key)=>{
            console.log(key);
            templateHTML = templateHTML.replaceAll('{{'+key+'}}', templateData[key])
          })
          return resolve(templateHTML);
      });
    });
  },

I’ve set the below as encoding type for the raw email data:

var htmlEntity = mimemessage.factory({
      contentType: "text/html;charset=utf-8",
      body: bodyData, //HTML data from AWS SES Template
    });

When i send the email out it does not display the emoji and instead displays the code uD83DuDC49. However when i copy the exact html into a variable like below the emoji is displayed correctly:

var copiedHTML = `**exact copy of what is being provided by AWS SES HtmlPart**`
var htmlEntity = mimemessage.factory({
      contentType: "text/html;charset=utf-8",
      body: copiedHTML, //Copy paste value from SES Template
    });

I’ve read up thats its related to how string variables are encoded in Javascript but i’m in need of some guidance. I cannot seem to find a solution that explains why the above happens.

Thanks.

How can I sync multiple chatbot conversations (tabs) per user with Firebase (HTML/JS only)

I am building a simple AI chatbot website using only HTML, CSS, and vanilla JavaScript (no frameworks). I’ve already set up Firebase Authentication and Firestore. Users can log in and see a chat interface with multiple tabs (for different conversations).

What I want:

When a user logs in, their existing conversations (tabs) should load from Firestore.
Each conversation should store its title and messages.
When a new conversation is created or updated (with new messages), it should be saved to Firestore under the current user’s UID.
Everything should be synced per user account.
I’m struggling to figure out the best way to structure the Firestore database and handle creating, loading, and updating conversations per user.

Has anyone done this with pure JS (no React/Vue)? What’s the best practice for structuring the Firestore collections and syncing the data correctly?

Thanks in advance!

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Rabbit AI Beta</title>
  <script defer src="https://cdn.tailwindcss.com"></script>
  <link rel="stylesheet" href="style.css" />
  <!-- Firebase SDK -->
  <script type="module">
    import { initializeApp } from "https://www.gstatic.com/firebasejs/10.8.0/firebase-app.js";
    import { getAuth, GoogleAuthProvider, signInWithPopup, signOut, onAuthStateChanged } from "https://www.gstatic.com/firebasejs/10.8.0/firebase-auth.js";
    import { getFirestore, doc, setDoc, getDoc, collection, addDoc, deleteDoc, onSnapshot, Timestamp } from "https://www.gstatic.com/firebasejs/10.8.0/firebase-firestore.js";
    import { firebaseConfig } from "./config.js";
    
    const app = initializeApp(firebaseConfig);
    const auth = getAuth(app);
    const db = getFirestore(app);
    const provider = new GoogleAuthProvider();

    // Array to store chat tabs
    let chatTabs = [];
    let currentTabIndex = 0;
    let unsubscribeFromTabs = null;
    let autoSaveInterval = null;

    // Function to save tabs to Firestore
    async function saveTabsToFirestore(userId) {
      if (!userId) return;
      try {
        const userDoc = doc(db, 'users', userId);
        // Ensure each tab has a unique ID and proper structure
        const tabsToSave = chatTabs.map(tab => ({
          id: tab.id || crypto.randomUUID(), // Generate unique ID if not exists
          title: tab.title || 'New Chat',
          messages: tab.messages || [],
          createdAt: tab.createdAt || Timestamp.now(),
          lastUpdated: Timestamp.now()
        }));
        
        await setDoc(userDoc, { 
          tabs: tabsToSave,
          lastUpdated: Timestamp.now()
        });
      } catch (error) {
        console.error('Error saving tabs:', error);
      }
    }

    // Function to start auto-save
    function startAutoSave(userId) {
      if (autoSaveInterval) {
        clearInterval(autoSaveInterval);
      }
      autoSaveInterval = setInterval(() => {
        if (auth.currentUser) {
          saveTabsToFirestore(userId);
        }
      }, 60000); // Save every minute
    }

    // Function to stop auto-save
    function stopAutoSave() {
      if (autoSaveInterval) {
        clearInterval(autoSaveInterval);
        autoSaveInterval = null;
      }
    }

    // Function to load tabs from Firestore
    async function loadTabsFromFirestore(userId) {
      if (!userId) return;
      
      if (unsubscribeFromTabs) {
        unsubscribeFromTabs();
      }

      try {
        const userDoc = doc(db, 'users', userId);
        
        // First, get the current state
        const docSnap = await getDoc(userDoc);
        if (docSnap.exists()) {
          const data = docSnap.data();
          chatTabs = data.tabs || [];
          updateChatList();
          if (chatTabs.length > 0) {
            loadChatMessages(currentTabIndex);
          }
        }

        // Start auto-save
        startAutoSave(userId);

        // Set up real-time listener
        unsubscribeFromTabs = onSnapshot(userDoc, (docSnap) => {
          if (docSnap.exists()) {
            const data = docSnap.data();
            const newTabs = data.tabs || [];
            
            if (JSON.stringify(chatTabs) !== JSON.stringify(newTabs)) {
              chatTabs = newTabs;
              updateChatList();
              if (chatTabs.length > 0) {
                loadChatMessages(currentTabIndex);
              }
            }
          }
        });
      } catch (error) {
        console.error('Error loading tabs:', error);
      }
    }

    // Function to clear all tabs
    function clearAllTabs() {
      chatTabs = [];
      currentTabIndex = 0;
      updateChatList();
      document.getElementById('chat').innerHTML = '';
      
      // Unsubscribe from real-time updates when clearing tabs
      if (unsubscribeFromTabs) {
        unsubscribeFromTabs();
        unsubscribeFromTabs = null;
      }
      
      // Stop auto-save
      stopAutoSave();
    }

    // Function to update the chat list UI
    function updateChatList() {
      const chatList = document.getElementById('chatList');
      chatList.innerHTML = '';
      
      if (!auth.currentUser) {
        // Show message when not logged in
        const message = document.createElement('div');
        message.className = 'text-center text-gray-500 p-4';
        message.textContent = 'Log in to see your chats';
        chatList.appendChild(message);
        return;
      }

      chatTabs.forEach((tab, index) => {
        const tabElement = document.createElement('div');
        tabElement.className = `flex items-center justify-between p-2 hover:bg-gray-100 rounded cursor-pointer ${index === currentTabIndex ? 'bg-gray-200' : ''}`;
        tabElement.innerHTML = `
          <span>${tab.title || 'New Chat'}</span>
          <button onclick="deleteTab(${index})" class="text-red-500 hover:text-red-700">×</button>
        `;
        tabElement.onclick = () => switchTab(index);
        chatList.appendChild(tabElement);
      });
    }

    // Function to load chat messages for a specific tab
    function loadChatMessages(tabIndex) {
      if (!auth.currentUser || !chatTabs[tabIndex]) return;
      
      const chatContainer = document.getElementById('chat');
      chatContainer.innerHTML = '';
      
      const messages = chatTabs[tabIndex].messages || [];
      messages.forEach(msg => {
        const messageElement = document.createElement('div');
        messageElement.className = `p-4 mb-2 rounded ${msg.role === 'user' ? 'bg-blue-100 ml-4' : 'bg-gray-100 mr-4'}`;
        messageElement.textContent = msg.content;
        chatContainer.appendChild(messageElement);
      });
      
      chatContainer.scrollTop = chatContainer.scrollHeight;
    }

    // Function to add a new message to the current tab
    async function addMessage(content, role) {
      if (!auth.currentUser || !chatTabs[currentTabIndex]) return;
      
      try {
        const message = {
          id: crypto.randomUUID(),
          content,
          role,
          timestamp: Timestamp.now()
        };
        
        if (!chatTabs[currentTabIndex].messages) {
          chatTabs[currentTabIndex].messages = [];
        }
        
        chatTabs[currentTabIndex].messages.push(message);
        await saveTabsToFirestore(auth.currentUser.uid);
      } catch (error) {
        console.error('Error adding message:', error);
      }
    }

    // Handle login button click
    document.getElementById('loginBtn').addEventListener('click', () => {
      const modal = document.getElementById('loginModal');
      modal.classList.remove('hidden');
    });

    // Handle close modal button
    document.getElementById('closeModal').addEventListener('click', () => {
      const modal = document.getElementById('loginModal');
      modal.classList.add('hidden');
    });

    // Handle Google login
    document.getElementById('googleLoginBtn').addEventListener('click', () => {
      signInWithPopup(auth, provider)
        .then((result) => {
          const modal = document.getElementById('loginModal');
          modal.classList.add('hidden');
          loadTabsFromFirestore(result.user.uid);
        })
        .catch((error) => {
          console.error('Error during Google sign-in:', error.message);
          alert('Error during sign-in: ' + error.message);
        });
    });

    // Handle logout
    document.getElementById('logoutBtn').addEventListener('click', () => {
      const user = auth.currentUser;
      if (user) {
        saveTabsToFirestore(user.uid).then(() => {
          signOut(auth).then(() => {
            updateAuthUI();
            clearAllTabs();
          });
        });
      } else {
        signOut(auth);
      }
    });

    // Update UI based on auth state
    function updateAuthUI() {
      const loginBtn = document.getElementById('loginBtn');
      const logoutBtn = document.getElementById('logoutBtn');
      const userDisplay = document.getElementById('userDisplay');

      if (auth.currentUser) {
        loginBtn.classList.add('hidden');
        logoutBtn.classList.remove('hidden');
        userDisplay.textContent = auth.currentUser.displayName || 'User';
        userDisplay.classList.remove('hidden');
      } else {
        loginBtn.classList.remove('hidden');
        logoutBtn.classList.add('hidden');
        userDisplay.classList.add('hidden');
      }
    }

    // Listen for auth state changes
    onAuthStateChanged(auth, (user) => {
      updateAuthUI();
      if (user) {
        console.log('User logged in:', user.uid);
        loadTabsFromFirestore(user.uid);
      } else {
        console.log('User logged out');
        clearAllTabs();
      }
    });

    // Expose functions to window for use in other scripts
    window.createNewChat = function() {
      if (!auth.currentUser) {
        const modal = document.getElementById('loginModal');
        modal.classList.remove('hidden');
        return;
      }
      
      try {
        const newTab = {
          id: crypto.randomUUID(),
          title: 'New Chat',
          messages: [],
          createdAt: Timestamp.now(),
          lastUpdated: Timestamp.now()
        };
        
        chatTabs.push(newTab);
        currentTabIndex = chatTabs.length - 1;
        updateChatList();
        loadChatMessages(currentTabIndex);
        saveTabsToFirestore(auth.currentUser.uid);
      } catch (error) {
        console.error('Error creating new chat:', error);
      }
    };

    window.deleteTab = function(index) {
      if (!auth.currentUser) return;
      
      try {
        chatTabs.splice(index, 1);
        if (currentTabIndex >= chatTabs.length) {
          currentTabIndex = Math.max(0, chatTabs.length - 1);
        }
        updateChatList();
        if (chatTabs.length > 0) {
          loadChatMessages(currentTabIndex);
        } else {
          document.getElementById('chat').innerHTML = '';
        }
        saveTabsToFirestore(auth.currentUser.uid);
        console.log('Tab deleted');
      } catch (error) {
        console.error('Error deleting tab:', error);
      }
    };

    window.switchTab = function(index) {
      if (!auth.currentUser) return;
      currentTabIndex = index;
      updateChatList();
      loadChatMessages(index);
    };

    // Handle sending messages
    window.sendMessage = async function() {
      if (!auth.currentUser) return;
      
      const input = document.getElementById('userInput');
      const message = input.value.trim();
      if (!message) return;
      
      // Add user message
      await addMessage(message, 'user');
      input.value = '';
      
      // Here you would typically add the AI response
      // For now, we'll just echo the message
      await addMessage(`AI: ${message}`, 'assistant');
    };
  </script>
  <script defer src="script.js"></script>
</head>
<body class="bg-white text-black h-screen flex transition-colors" id="body">
  <!-- Login Modal -->
  <div id="loginModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center hidden">
    <div class="bg-white p-8 rounded-lg shadow-lg max-w-md w-full">
      <div class="flex justify-between items-center mb-6">
        <h2 class="text-2xl font-bold">Sign in to RabbitAI</h2>
        <button id="closeModal" class="text-gray-500 hover:text-gray-700">
          <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
            <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
          </svg>
        </button>
      </div>
      <button id="googleLoginBtn" class="w-full bg-white border border-gray-300 rounded-lg px-4 py-2 flex items-center justify-center gap-2 hover:bg-gray-50">
        <img src="https://www.gstatic.com/firebasejs/ui/2.0.0/images/auth/google.svg" alt="Google logo" width="18" height="18">
        Sign in with Google
      </button>
    </div>
  </div>

  <!-- Sidebar -->
  <div id="sidebar" class="w-64 bg-white border-r border-gray-200 flex flex-col p-4">
    <div class="flex justify-between items-center mb-6">
      <h2 class="text-lg font-bold">Tabs</h2>
      <button onclick="createNewChat()" class="bg-pink-500 hover:bg-pink-600 p-2 rounded text-sm text-white" style="color: #ffffff;">
        +
      </button>
    </div>
    <div id="chatList" class="flex-1 space-y-2 overflow-y-auto">
      <!-- Dynamisch geladen chats komen hier -->
    </div>
    <div class="mt-4 text-sm text-gray-400">
      <button onclick="openSettings()" class="hover:underline">Settings</button>
    </div>
  </div>

  <!-- Main Content -->
  <div class="flex flex-col flex-1 h-screen">
    <header class="text-center py-4 border-b border-gray-200 flex justify-between px-4 items-center">
      <div class="flex gap-2 items-center">
        <button onclick="toggleSidebar()" class="text-xl font-bold px-2 py-1">☰</button>
        <h1 class="text-xl font-bold">Rabbit AI</h1>
      </div>
      <div class="flex gap-2 items-center">
        <span id="userDisplay" class="hidden text-sm text-gray-600"></span>
        <button id="loginBtn" class="bg-gray-100 hover:bg-gray-200 text-gray-800 px-3 py-1 rounded text-sm">Guest</button>
        <button id="logoutBtn" class="hidden bg-gray-100 hover:bg-gray-200 text-gray-800 px-3 py-1 rounded text-sm">Log out</button>
        <button onclick="resetChat()" class="bg-pink-500 hover:bg-pink-600 text-white px-3 py-1 rounded text-sm">Reset</button>
      </div>
    </header>

    <main id="chat" class="flex-1 overflow-y-auto p-4 space-y-2"></main>

    <footer class="p-4 border-t border-gray-200">
      <div class="flex gap-2">
        <select id="modelSelect" class="px-3 py-2 rounded bg-gray-100 text-black outline-none border border-gray-300">
          <option value="mistralai/mistral-7b-instruct:free">Censored RabbitAI</option>
          <option value="cognitivecomputations/dolphin3.0-mistral-24b:free">Uncensored RabbitAI</option> 
        </select>
        <input id="userInput" type="text" placeholder="Aks a question privately..." class="flex-1 px-4 py-2 rounded bg-gray-100 text-black outline-none">
        <button onclick="sendMessage()" class="bg-pink-500 hover:bg-pink-600 text-white px-4 py-2 rounded">Send</button>
        <a href="#" class="flex items-center gap-1 font-semibold text-pink-500 hover:underline px-3 py-2 rounded"><span class="text-lg">✨</span>Upgrade to Pro</a>
      </div>
    </footer>
  </div>
</body>
</html>

Please note: when you click ‘run code snnippet’ you’ll get script errors, I don’t have these. I don’t have any errors. that makes it weird.

How can I pass data from multiple HTML tables to a controller using jQuery AJAX?

I’ve created a page with header fields and an HTML table. I’m using jQuery AJAX to send both the header and table data to the controller. Although the request reaches the controller, the action method receives null values.

I’ve tried setting the contentType to both 'application/x-www-form-urlencoded; charset=UTF-8' and 'application/json; charset=UTF-8', but in both cases the controller still receives null.

function addRow() {
  const row = document.createElement("tr");
  row.innerHTML = '<td><input type="text" class="itemNo"></td>' +
    '<td><input type="text" class="itemName"></td>' +
    '<td><input type="number" class="qty" onchange="calculateAmount(this)"></td>' +
    '<td> <input type="number" class="mrp" onchange="calculateAmount(this)"></td>' +
    '<td class="amount"> <label></label></td > ' +
    '<td><button onclick="removeRow(this)">-</button></td>';
  document.getElementById("invoiceTable").appendChild(row);
}

function removeRow(button) {
  button.closest("tr").remove();
}

function MakeSingleModel() {
  const SaleModel = {
    CustomerNo: $("#customerNo").val().trim(),
    CustomerName: $("#customerName").val().trim(),
  };

  const Detail = [];

  $("#invoiceTable tr").each(function() {
    const $row = $(this);
    const SaleList = {
      ItemNo: $row.find("input[name='itemNo']").val().trim(),
      ItemName: $row.find("input[name='itemName']").val().trim(),
      Qty: parseInt($row.find("input[name='qty']").val()) || 0,
      MRP: parseFloat($row.find("input[name='MRP']").val()) || 0,
      Amount: parseFloat($row.find("input[name='Amount']").text()) || 0
    };
    Detail.push(SaleList);
  });

  const alldata = {
    SaleModel: SaleModel,
    DetailList: Detail
  };

  SaveSale(alldata);
}

function SaveSale(data) {
  var data = {
    SaleData: data
  };
  
  $.ajax({
    type: "POST",
    url: "/Home/Create/",
    data: data,

    //contentType: "application/x-www-form-urlencoded; charset=UTF-8",
    contentType: "application/json; charset=UTF-8",
    dataType: "json",
    success: (response) => {
      alert(response.saveStatus === "Success" ? "Data successfully saved!" : "Data not saved.");
    },
    error: (jqXHR, textStatus, errorThrown) => {

      alert("Error saving data. See console for details.");
    }
  });
}

function multi(element) {
  const $row = $(element).closest("tr");
  const qty = parseInt($row.find(".qty").val()) || 0;
  const MRP = parseFloat($row.find(".mrp").val()) || 0;
  const sumAmount = qty * MRP;
  $row.find(".amount label").text(sumAmount.toFixed(2));
}
body {
  font-family: Arial, sans-serif;
  margin: 20px;
}

.container {
  width: 50%;
  margin: auto;
}

table {
  width: 100%;
  border-collapse: collapse;
}

th,
td {
  padding: 10px;
  border: 1px solid #ccc;
}

input {
  width: 100%;
  padding: 5px;
}

button {
  margin-top: 10px;
  padding: 5px 10px;
  cursor: pointer;
}

#invoiceTable td input {
  width: 150px;
}
<div class="">
  <h2>Sale Invoice</h2>

  <label>Customer No:</label>
  <input type="text" id="customerNo">

  <label>Customer Name:</label>
  <input type="text" id="customerName">
  
  <table>
    <thead>
      <tr>
        <th>Item No</th>
        <th>Item Name</th>
        <th>Qty</th>
        <th>MRP</th>
        <th>Amount</th>
        <th>Action</th>
      </tr>
    </thead>
    <tbody id="invoiceTable">
      <tr>
        <td><input type="text" name="itemNo" id="itemNo"></td>
        <td><input type="text" name="itemName" id="itemName"></td>
        <td><input type="number" onchange="multi(this)" name="qty" id="qty" class="qty"></td>
        <td><input type="number" onchange="multi(this)" name="MRP" id="MRP" class="mrp"></td>
        <td class="amount"><label name="Amount" id="Amount"></label></td>
        <td><button onclick="addRow()">+</button></td>
      </tr>
    </tbody>
  </table>
  <button onclick="MakeSingleModel()">Save</button>
</div>
[HttpPost]
public JsonResult Create(SaleModel SaleData)
{
  return Json(new { value = "", Status = "Success" });
}

How is JavaScript able to sort dates when it’s supplied as string?

Consider the following object:

var abc = [
   {"id":"a","date":"2025-05-01T03:02:19Z"}, 
   {"id":"b","date":"2025-05-01T03:15:02Z"}, 
   {"id":"c","date":"2025-04-30T20:49:41Z"}
];

If I apply ascending sort to it, it’s giving me correct result.

var def = abc.sort(function(a, b) {
                var x = a.date;
                var y = b.date;
                return x < y ? -1 : x > y ? 1 : 0;
            });

for(var i = 0; i < def.length; i++){
    gs.print(def[i].date);
}

Output:

*** Script: 2025-04-30T20:49:41Z
*** Script: 2025-05-01T03:02:19Z
*** Script: 2025-05-01T03:15:02Z

How are strings getting sorted correctly?

“How to Properly Dispose Tensors in face-api.js + tfjs-node to Prevent Memory Leak?”

I’m using face-api.js (specifically the @vladmandic/face-api version) for the first time in a Node.js server environment, and while face detection and comparison are working, I’m running into a serious memory management issue.

Even though I try to manually dispose of tensors, memory usage keeps increasing over time on the server. I suspect some tensors are not being released correctly, but I can’t pinpoint where or why. I’ve wrapped tensor creation in try...finally blocks and even log memory using tf.memory(), but the number of active tensors doesn’t go down as expected.

// face-api/src/server.js
const express = require('express');
const multer = require('multer');
const tf = require('@tensorflow/tfjs-node');
const faceapi = require('@vladmandic/face-api');
const { Canvas, Image, ImageData } = require('canvas');
const path = require('path');
const { logger } = require('./logger');

const app = express();
const upload = multer({
  limits: {
    fileSize: 10 * 1024 * 1024,
    fieldSize: 25 * 1024 * 1024
  }
});
const PORT = 3002;

class FaceApiService {
  constructor() {
    this.modelPath = path.join(__dirname, '../models');
    this.isModelLoaded = false;
    this.initializeFaceApi();
  }

  async initializeFaceApi() {
    if (this.isModelLoaded) return;

    faceapi.env.monkeyPatch({ Canvas, Image, ImageData });

    try {
      await Promise.all([
        faceapi.nets.faceRecognitionNet.loadFromDisk(this.modelPath),
        faceapi.nets.faceLandmark68Net.loadFromDisk(this.modelPath),
        faceapi.nets.ssdMobilenetv1.loadFromDisk(this.modelPath)
      ]);

      this.isModelLoaded = true;
      console.log("load model success")
      logger.info('Face recognition models loaded successfully');
    } catch (error) {
      logger.error('Error loading face recognition models: ' + error);
      throw new Error("Error initializing face recognition system");
    }
  }

  disposeTensor(tensor) {
    if (tensor) {
      if (Array.isArray(tensor)) {
        tensor.forEach(t => this.disposeTensor(t));
      } else if (tensor.dispose) {
        try {
          tensor.dispose();
        } catch (err) {
          logger.warn('Error disposing tensor: ' + err);
        }
      }
    }
  }

  async verifyFace(uploadedImage, referenceImages) {
    let mem = tf.memory();
    console.log(`Tensor count: ${mem.numTensors}, Bytes: ${mem.numBytes}`);
    let inputTensor = null;
    const referenceDescriptors = [];
    try {
      console.log("uploadedImage size: ", uploadedImage.length / 1024, "KB");
      inputTensor = tf.node.decodeImage(uploadedImage);
      console.log("decoded imgae uploadedImage success")
      const detection = await faceapi
        .detectSingleFace(inputTensor)
        .withFaceLandmarks()
        .withFaceDescriptor();
      console.log("detection imgae uploadedImage success")

      if (!detection) {
        throw new Error("No face detected in the uploaded photo");
      }

      for (const refImage of referenceImages) {
        let refTensor = null;
        try {
          console.log("referenceImage size: ", refImage.length / 1024, "KB");
          refTensor = tf.node.decodeImage(refImage);
          console.log("decoded imgae refTensor success")
          const refDetection = await faceapi
            .detectSingleFace(refTensor)
            .withFaceLandmarks()
            .withFaceDescriptor();
          console.log("detection imgae refTensor success")

          if (refDetection) {
            referenceDescriptors.push(refDetection.descriptor);
          }
        } catch (refErr) {
          logger.warn('Error processing reference image: ' + refErr);
        } finally {
          this.disposeTensor(refTensor);
        }
      }

      if (referenceDescriptors.length === 0) {
        throw new Error("No valid reference photos available for comparison");
      }

      const faceMatcher = new faceapi.FaceMatcher(
        [new faceapi.LabeledFaceDescriptors('user', referenceDescriptors)],
        0.6
      );
      console.log("faceMatcher success")

      const match = faceMatcher.findBestMatch(detection.descriptor);
      console.log("match success")

      return {
        verified: match.label !== 'unknown',
        confidence: 1 - match.distance
      };

    } catch (err) {
      logger.error('Error in face verification: ' + err);
      throw err;
    } finally {
      console.log("dispose tensor")
      this.disposeTensor(inputTensor);
      // Dispose semua descriptor tensor reference
      for (const desc of referenceDescriptors) {
        this.disposeTensor(desc); // penting!
      }

      console.log("dispose success");
      let mem = tf.memory();
      console.log(`Tensor count: ${mem.numTensors}, Bytes: ${mem.numBytes}`);
    }
  }
}

const faceApiService = new FaceApiService();

app.use((req, res, next) => {
    const waktuAkses = new Date().toISOString();
    logger.info(`${req.method} url:: ${req.url} - accessed at ${waktuAkses}`);
    next();
});

app.get('/', (req, res) => {
  res.json({ status: true });
});

app.post('/verify', upload.single('image'), async (req, res) => {
  try {
    if (!req.file || !req.body.referenceImages) {
      return res.status(400).json({ error: 'Missing required files' });
    }

    const referenceImages = JSON.parse(req.body.referenceImages);
    const referenceBuffers = referenceImages.map(base64 =>
      Buffer.from(base64, 'base64')
    );

    const result = await faceApiService.verifyFace(
      req.file.buffer,
      referenceBuffers
    );

    res.json(result);
  } catch (error) {
    logger.error('Verification error: ' + error);
    res.status(500).json({
      error: error instanceof Error ? error.message : 'Internal server error'
    });
  }
});

app.listen(PORT, '0.0.0.0', () => {
  logger.info(`Face API service running on http://localhost:${PORT}`);
});

module.exports = app;

Receiving 0 ETH after BTC swap using Chainflip — Broadcast fee exactly the same as the amount before broadcast fee

I’m building a cross-chain swap dApp using Unisat Wallet and Chainflip. Users can swap BTC for WUSDT (via ETH as intermediary), and I’m integrating Chainflip’s API to handle the actual swap.

However, I’ve run into a critical issue during testing. When I initiate a BTC -> ETH swap, Chainflip responds with swap metadata like this (trimmed for clarity):

{
  "depositAmount": "100000",
  "intermediateAmount": "42516508",
  "egressAmount": "2797855777158",
  "estimatedPrice": "5.76474664160869368917",
  "includedFees": [
    {
      "type": "INGRESS", "amount": "330", "asset": "BTC"
    },
    {
      "type": "NETWORK", "amount": "42559", "asset": "USDC"
    },
    {
      "type": "EGRESS", "amount": "5742925121914227", "asset": "ETH"
    }
  ]
}

This results in Chainflip depositing approximately 0.00649142 ETH to the destination address. The problem is that Chainflip also deducts a broadcast fee of 0.00649142 ETH, which is exactly the amount they sent me.

The result is that I’m left with 0 ETH in the wallet, making it impossible to use for gas or forward it elsewhere.

Screenshot of the above mentioned issue

AWS Kinesis library is not sending errors [closed]

I am using https://www.npmjs.com/package/@aws-sdk/client-kinesis to connect to aws kinesis. From time to time, I can see that in logs, there is a 400 error being logged on the line that I make client.send() post request. None of the followings worked to show me the reason behind that 400 error.

  • I tried wrapping client.send() in a try catch block, but no error is being captured!
  • using .then().catch(e => console.log(e)) didn’t work either
  • using .then(data => console.log(data), e => console.log(e)) didn’t capture it either

Is it a problem with the library that I am using for JS. Is there any other implementation to read kinesis data?

Selenium doesn’t detect specific item when not being active in the tab in the browser but works if I am active

I am trying to scrape from a very specific site that has two things that doesn’t work as expected: A) reject the cookie banner using reject button and B) enter a specific section to get a view about the profile views.

If I am active in the browser tab everything works as expected but if I am not the button for reject is found but the move_element(…).click().perform() doesnt’ reject the cookie banner and B) the section is not found.

Is this some bot-detection mechanism?

How to find the shortest path in a multigraph with dynamic edge costs based on bus line changes? [closed]

I’m working with a multigraph in JavaScript where each edge represents a bus route and includes both a weight (e.g., travel time or distance) and a busLine identifier.

I want to calculate the shortest path between two nodes, but with the following rule:

If a traveler switches bus lines from one edge to the next, a fixed penalty (e.g. +5) is added to the total cost.

Here is a simplified structure of my graph:
Example Visual Graph

const graph = {
  A: [
    { to: 'B', weight: 10, busLine: '2' },
    { to: 'B', weight: 10, busLine: '1' },
    { to: 'B', weight: 10, busLine: '3' },
  ],
  B: [
    { to: 'C', weight: 10, busLine: '1' },
    { to: 'D', weight: 10, busLine: '2' },
    { to: 'D', weight: 10, busLine: '3' },
    { to: 'D', weight: 10, busLine: '4' },
  ],
  C: [],
  D: [
    { to: 'E', weight: 10, busLine: '4' },
    { to: 'E', weight: 10, busLine: '3' },
  ],
};

For example:

A -> C [1, 1]

A -> D [2, 2] or [3, 3]

A -> E [2, 2, 4] or [3, 3, 4]

What I’m looking for:

  1. What is the best way to model or approach this problem?
  2. Is there a known algorithm (or variation of Dijkstra/A*) that supports dynamic edge costs based on previous edge metadata like busLine?
  3. Any recommended libraries or techniques to make this efficient on large graphs?
    Thanks in advance!

How can I restore a page to its initial state, if website state is saved to Local Storage?

I want to add a reset button to the website below, which will return the webpage to its initial state.

Reloading the web browser is not possible because the actions performed are stored in Local Storage.

I tried it via Gemeni but it gives the wrong answer. Can someone help me with this?

Thanks in advance.

<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
  body {
    margin: 0;
    background: #000000;
  }

  div.removable {
    color: #ffffff;
    font-size: 25px;
    font-family: Arial;
    padding: 12px 8px 12px 10px;
    cursor: pointer;
  }

  button {
    padding: 10px 15px;
    font-size: 16px;
    cursor: pointer;
    margin-top: 10px;
    position: fixed;
    top: 10px; /* Pas deze waarde aan om de verticale positie te bepalen */
    right: 10px; /* Pas deze waarde aan om de horizontale positie te bepalen */
    padding: 10px 15px;
    font-size: 16px;
    cursor: pointer;
    z-index: 1000; /* Zorg ervoor dat de knop boven andere elementen ligt */
  }
</style>
</head>
<body>
<div style="padding-top: 60px;"></div>
  <div class="removable" onclick="removeElement(this)">Task 1</div>
  <div class="removable" onclick="removeElement(this)">Task 2</div>
  <div class="removable" onclick="removeElement(this)">Task 3</div>

  <button id="undoButton" onclick="undoLastRemoval()" disabled>Undo</button>



  <script type="text/javascript">
    const removalHistory = []; // Array om verwijderde elementen en hun posities op te slaan
    const listContainer = document.body; // De container van de verwijderbare elementen

    // Functie om de huidige staat van de lijst op te slaan in Local Storage
    function saveListState() {
      const remainingItems = Array.from(document.querySelectorAll('.removable')).map(item => item.textContent);
      localStorage.setItem('todoListState', JSON.stringify(remainingItems));
    }

    // Functie om de opgeslagen staat van de lijst te laden
    function loadListState() {
      const savedState = localStorage.getItem('todoListState');
      if (savedState) {
        const items = JSON.parse(savedState);
        // Verwijder alle bestaande items
        document.querySelectorAll('.removable').forEach(item => item.remove());
        // Voeg de opgeslagen items opnieuw toe
        items.forEach(text => {
          const newDiv = document.createElement('div');
          newDiv.className = 'removable';
          newDiv.textContent = text;
          newDiv.onclick = function() { removeElement(this); };
          listContainer.insertBefore(newDiv, document.getElementById('undoButton'));
        });
        // Reset de undo geschiedenis omdat de pagina opnieuw is geladen
        removalHistory.length = 0;
        document.getElementById('undoButton').disabled = true;
      }
    }

    function removeElement(el) {
      removalHistory.push({
        element: el,
        previousSibling: el.previousElementSibling
      });
      el.remove();
      document.getElementById('undoButton').disabled = false;
      saveListState(); // Sla de staat op na een verwijdering
    }

    function undoLastRemoval() {
      if (removalHistory.length > 0) {
        const lastRemoval = removalHistory.pop(); // Haal de laatste verwijdering uit de geschiedenis
        const elementToRestore = lastRemoval.element;
        const previousSibling = lastRemoval.previousSibling;

        if (previousSibling) {
          previousSibling.insertAdjacentElement('afterend', elementToRestore);
        } else {
          listContainer.insertBefore(elementToRestore, listContainer.firstChild);
        }

        // Schakel de undo knop uit als er geen verwijderingen meer zijn om ongedaan te maken
        document.getElementById('undoButton').disabled = removalHistory.length === 0;
        saveListState(); // Sla de staat op na een undo
      }
    }

    // Laad de opgeslagen staat wanneer de pagina geladen is
    window.onload = loadListState;
  </script>
</body>
</html>

TypeError: The ‘data’ argument must be of type string or Buffer in Node.js crypto.update() for Password Reset

I am working on a password reset feature in a Node.js/Express application using Sequelize and the crypto module to hash passwords. When I send a POST request to my /reset-password endpoint, I get the following error:

Error in resetPassword: The “data” argument must be of type string or an instance of Buffer, TypedArray, or DataView. Received undefined.

Here’s the relevant code for the resetPassword function:

import crypto from "crypto";
import { User } from "../models/user.js"; // Sequelize model
import { Op } from "sequelize";
import logger from "../utils/logger.js";

export const resetPassword = async (req, res) => {
  try {
    const { token, password } = req.body;

    // Find user by reset token
    const user = await User.findOne({
      where: {
        reset_token: token,
        reset_token_expires: { [Op.gt]: new Date() },
      },
    });

    if (!user) {
      return res.status(400).json({ message: "Invalid or expired reset token" });
    }

    // Hash new password
    const hashedPassword = crypto
      .createHash("sha256")
      .update(password)
      .digest("hex");

    // Update user password and clear reset token
    await user.update({
      password: hashedPassword,
      reset_token: null,
      reset_token_expires: null,
    });

    res.status(200).json({ message: "Password reset successful" });
  } catch (error) {
    logger.error("Error in resetPassword:", error);
    res.status(500).json({ message: "Error resetting password" });
  }
};

Additional info:
Node.js version: 18.x
Express version: 4.x
Sequelize version: 6.x

Code Completion Fails for Destructured Variables in WebStorm

WebStorm code completion does not work with destructured objects. See the example.

Successful type inference

Failed type inference

In the line

const { autoSkedDay, row } = currentHeader;

the IDE correctly infers that autoSkedDay: AutoSkedDay. However, in the subsequent line

const { endRow } = autoSkedDay;

the IDE incorrectly infers that autoSkedDay: any. In other words, it has forgotten what it used to know about the variable.

Has anyone had a similar issue and know how to fix it?

I tried not destructuring objects, and everything worked fine. For example, the following works:

const autoSkedDay = currentHeader.autoSkedDay;

In other words, this time the IDE recognizes that autoSkedDay: AutoSkedDay. However, when I abbreviate my code using object destructuring, type inference fails.

This issue happens all over the place in my code, despite extensive documentation (JSDoc) and it is very frustrating.

Problem with node.js: ReferenceError: window is not defined

ReferenceError: window is not defined
    at Object.<anonymous> (c:UsersLEDiSON BiZDesktoptestJavaScriptacceptUserInput.js:8:1)
    at Module._compile (node:internal/modules/cjs/loader:1554:14)
    at Object..js (node:internal/modules/cjs/loader:1706:10)
    at Module.load (node:internal/modules/cjs/loader:1289:32)
    at Function._load (node:internal/modules/cjs/loader:1108:12)
    at TracingChannel.traceSync (node:diagnostics_channel:322:14)
    at wrapModuleLoad (node:internal/modules/cjs/loader:220:24)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:170:5)
    at node:internal/main/run_main_module:36:49

I tried reviewing folders in the modules and diagnostic_channel but all was to no avail