Calling a Flutter closure from JavaScript using js_interop

I have a method in Flutter that receives a closure. I want to pass that closure to JS and call it back anytime, from somewhere in JS. I’d also like to use dart:js_interop to be WASM compatible (I have seen an example using setProperty and allowInterop but they come from dart:js which is deprecated).

typedef OnCallbackTFunction = void Function(bool something);

class MyClass {
    [...]
    // This method could be called more than once with different closures
    void doSomething({OnCallbackTFunctio? onSomething})
    {
        // On JS side I should store the [onSomething] closure to be called back.
        // Something like this(?):
        wasmSetCallback(onSomething);
    }
}

On JS I need something to store the callback. Well, this is a C++ class which uses EM_ASM to inline some JS code:

typedef void (*dartCallback_t)(bool something);

// Each call to the Dart `doSomething()` will create only one instance of this class.
class MyCallbackClass {
public:
    void setCallback(dartCallback_t *callback)
    {
        EM_ASM({
            // What to put here?
        });
    }
    
    void callDartMethod()
    {
        EM_ASM({
            // What to put here?
        });
    }
}

This C++ code will be compiled with emscripten to produce also the .js.

All this to achieve something like:

final n = MyClass.instance.doSomething(onSomething: () {print('callback N from JS!');});
final m = MyClass.instance.doSomething(onSomething: () {print('callback M from JS!');});

I read that JSObjectUnsafeUtilExtension could be used to set JS property, maybe a JS function to use for the callback, but I’ve not found docs explaining how to use it.

Any help is greatly appreciated.

Back and Forward buttons not behaving as expected. the buttons cycle correctly but when using only buttons places text at the end. using keyboard ok

This codes behavior is unexpected when you use only the buttons to place chars from the carrot location. It always places the char at the end of the string. If i use the buttons and place the char with the keyboard it does work as expected. Why does this happen and any help with a solution is greatly appreciated.

function getInputSelection(el) {
  var start = 0,
    end = 0,
    normalizedValue, range,
    textInputRange, len, endRange;
  if (typeof el.selectionStart == "number" && typeof el.selectionEnd == "number") {
    start = el.selectionStart;
    end = el.selectionEnd;
  } else {
    range = document.selection.createRange();
    if (range && range.parentElement() == el) {
      len = el.value.length;
      normalizedValue = el.value.replace(/rn/g, "n");
      textInputRange = el.createTextRange();
      textInputRange.moveToBookmark(range.getBookmark());
      endRange = el.createTextRange();
      endRange.collapse(false);
      if (textInputRange.compareEndPoints("StartToEnd", endRange) > -1) {
        start = end = len;
      } else {
        start = -textInputRange.moveStart("character", -len);
        start += normalizedValue.slice(0, start).split("n").length - 1;
        if (textInputRange.compareEndPoints("EndToEnd", endRange) > -1) {
          end = len;
        } else {
          end = -textInputRange.moveEnd("character", -len);
          end += normalizedValue.slice(0, end).split("n").length - 1;
        }
      }
    }
  }
  return {
    start: start,
    end: end
  };
}

function setBack() {
  document.getElementById('user').value =
    document.getElementById('user').value.substring(0,
      document.getElementById('user').value.length - 1);
}


function moveBack(elId) {
  var elem = document.getElementById(elId);
  elem.setSelectionRange(elem.value.length,
    getInputSelection(elem).start - 1);
  elem.focus();
}

function moveForward(elId) {
  var elem = document.getElementById(elId);
  elem.setSelectionRange(elem.value.length,
    getInputSelection(elem).start + 1);
  elem.focus();
}
function focusElem(){
var foo =document.getElementById('user');
foo.focus();
}

function setA(){ document.getElementById('user').value += "A"; focusElem();}
function setB(){ document.getElementById('user').value += "B"; focusElem();}
function setC(){ document.getElementById('user').value += "C"; focusElem();}
function setD(){ document.getElementById('user').value += "D"; focusElem();}
<input id="user" type="text">
<button type="button" onclick="setBack();">backspace</button>
<button type="button" onclick="moveBack('user')">back</button>
<button type="button" onclick="moveForward('user')">forward</button>


<div>
<button type="button" onclick="setA()">A</button>
<button type="button" onclick="setB()">B</button>
<button type="button" onclick="setC()">C</button>
<button type="button" onclick="setD()">D</button>
<div>

Thanks for your time in advance!

Error in Prisma: Unknown argument project_code in prisma.etl_users_project.create() invocation, How to resolve this issue

I’m encountering an error while testing my API in Postman. The error occurs when I try to create a new record in the etl_users_project table using Prisma. Here is the code snippet and the error message:

Invalid `prisma.etl_users_project.create()` invocation:
 
{
  data: {
    user_name: "Arun",
    project_code: "BIS",
    ~~~~~~~~~~~~
    etl_projects: {
      connect: {
        project_code: "BIS"
      }
    },
    etl_user_master: {
      connect: {
        id: 10
      }
    },
?   crt_dtm?: DateTime | Null,
?   crt_user_id?: String | Null,
?   updt_dtm?: DateTime | Null,
?   updt_user_id?: String | Null
  }
}
 
Unknown argument `project_code`. Available options are marked with ?.
    at Dn (C:UsersmendrevDownloadsBISWebAppZipBISWebBackendnode_modules@prismaclientruntimelibrary.js:114:8082) 
    at Mn.handleRequestError (C:UsersmendrevDownloadsBISWebAppZipBISWebBackendnode_modules@prismaclientruntimelibrary.js:121:7396)
    at Mn.handleAndLogRequestError (C:UsersmendrevDownloadsBISWebAppZipBISWebBackendnode_modules@prismaclientruntimelibrary.js:121:7061)
    at Mn.request (C:UsersmendrevDownloadsBISWebAppZipBISWebBackendnode_modules@prismaclientruntimelibrary.js:121:6745)
    at async l (C:UsersmendrevDownloadsBISWebAppZipBISWebBackendnode_modules@prismaclientruntimelibrary.js:130:9633)
    at async saveUserProject (file:///C:/Users/mendrev/Downloads/BISWebAppZip/BISWeb/Backend/controllers/etl_UserProjectNew.js:32:32) {
  clientVersion: '5.21.1'
}

What I’ve Tried:
Verified that project_code is correctly defined in the Prisma schema.
Checked the relationships and connections in the schema.
Ensured that the Prisma Client is up to date.
Schema Snippet:
Here is the relevant part of my Prisma schema:
Schema Prisma:

model etl_user_master {
  id                Int                @id @default(autoincrement())
  network_id        String             @db.VarChar(50)
  name              String             @db.VarChar(100)
  email             String             @unique @db.VarChar(100)
  enabled           Boolean?           @default(true)
  etl_users_project etl_users_project?
}
 
model etl_projects {
  project_code          String              @id @db.VarChar(100)
  project_name          String              @db.VarChar(100)
  owner                 String?             @db.VarChar(100)
  owner_email           String?             @db.VarChar(100)
  secondaryOwner        String?             @db.VarChar(100)
  secondary_owner_email String?             @db.VarChar(100)
  start_date            DateTime?           @db.Date
  enable                Boolean?
  crt_dtm               DateTime?           @db.Timestamp(6)
  crt_user_id           String?             @db.VarChar(20)
  updt_dtm              DateTime?           @db.Timestamp(6)
  updt_user_id          String?             @db.VarChar(20)
  etl_users_project     etl_users_project[]
}
 
model etl_users_project {
  uid             Int             @id @default(autoincrement())
  user_name       String          @db.VarChar(100)
  project_code    String          @db.VarChar(100)
  crt_dtm         DateTime?       @db.Timestamp(6)
  crt_user_id     String?         @db.VarChar(20)
  updt_dtm        DateTime?       @db.Timestamp(6)
  updt_user_id    String?         @db.VarChar(20)
  etl_projects    etl_projects    @relation(fields: [project_code], references: [project_code], onDelete: NoAction, onUpdate: NoAction, map: "fk_project_code")
  etl_user_master etl_user_master @relation(fields: [uid], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "fk_user_id")
}

Why am I getting this error, and how can I resolve it? Any help would be greatly appreciated
My React Js Backend Code :

import { PrismaClient } from '@prisma/client';
 
const prisma = new PrismaClient();
 
// Save User and Project Code
const saveUserProject = async (req, res) => {
    const { user_name, project_code } = req.body;
    try {
        if (!user_name || !project_code) {
            return res.status(400).json({ msg: 'User name and project code are required' });
        }
 
        // Find the user by name
        const user = await prisma.etl_user_master.findFirst({
            where: { name: user_name }
        });
 
        if (!user) {
            return res.status(404).json({ msg: 'User not found' });
        }
 
        // Ensure the project exists
        const project = await prisma.etl_projects.findUnique({
            where: { project_code: project_code }
        });
 
        if (!project) {
            return res.status(404).json({ msg: 'Project not found' });
        }
 
        // Create the user project
        const newUserProject = await prisma.etl_users_project.create({
            data: {
                user_name: user_name,
                project_code: project_code,
                etl_projects: {
                    connect: { project_code: project_code }
                },
                etl_user_master: {
                    connect: { id: user.id }
                }
            }
        });
        res.json({ status: 'success', data: newUserProject });
    } catch (error) {
        console.error(error);
        res.status(500).json({ msg: 'Internal Server Error' });
    }
};

 
export {
   saveUserProject,
    
};

Game development: how do I implement a camera system to follow characters (js)

This is my HTML code, and my server.js code is below it. I’m looking for any tips on how to make my code better because it’s a bit buggy in terms of actually deleting players, and more importantly a camera system so I can create a more extensive map with checkpoints. I can’t find any good guides online.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Multiplayer Game</title>
  <style>
    body { margin: 0; overflow: hidden; }
    canvas { background-color: #eee; display: block; }
    #startScreen {
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      background: white;
      padding: 20px;
      border: 1px solid #000;
      z-index: 10;
      display: flex;
      flex-direction: column;
      align-items: center;
    }
    #iconSelection img {
      width: 50px;
      height: 50px;
      margin: 5px;
      cursor: pointer;
      border: 2px solid transparent;
    }
    #iconSelection img.selected {
      border: 2px solid blue;
    }
  </style>
</head>
<body>
  <div id="startScreen">
    <h2>Enter Your Name</h2>
    <input type="text" id="playerNameInput" placeholder="Player Name" />
    <h3>Select an Icon</h3>
    <div id="iconSelection">
      <img src="image1.png" alt="Icon 1" class="icon" data-icon="image1.png">
      <img src="image2.webp" alt="Icon 2" class="icon" data-icon="image2.webp">
      <img src="image3.png" alt="Icon 3" class="icon" data-icon="image3.png">
      <!-- Add more icons as needed -->
    </div>
    <button id="startGameButton">Start Game</button>
  </div>
  <canvas id="gameCanvas"></canvas>

  <script>
    const canvas = document.getElementById('gameCanvas');
    const ctx = canvas.getContext('2d');
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;

    const GRASS_HEIGHT = 50; // Height of the grass section

    let playerName = "";
    let playerIcon = "";
    let players = {}; // Store all players keyed by their socket ID
    let myPlayerId = null; // Store the current player's ID
    let gameStarted = false;

    class Player {
      constructor(id, x, y, w, h, spritePath, name, opacity = 1) {
        this.id = id; // Unique ID for each player
        this.x = x;
        this.y = y;
        this.w = w;
        this.h = h;
        this.speedX = 0;
        this.speedY = 0;
        this.gravity = 1; // Gravity strength
        this.jumpSpeed = -15; // Jump speed
        this.sprite = new Image();
        this.sprite.src = spritePath;
        this.loaded = false;
        this.opacity = opacity; // Set opacity for players
        this.name = name; // Player's name
        this.onObject = false; // Track if the player is on a parkour object

        this.sprite.onload = () => {
          this.loaded = true;
        };
      }

      draw() {
        if (this.loaded) {
          ctx.globalAlpha = this.opacity; // Set opacity for drawing
          ctx.drawImage(this.sprite, this.x, this.y, this.w, this.h);
          ctx.globalAlpha = 1; // Reset opacity back to full

          // Draw the player's name above the character
          ctx.fillStyle = 'black';
          ctx.font = '16px Arial';
          ctx.textAlign = 'center';
          ctx.fillText(this.name, this.x + this.w / 2, this.y - 10); // Positioning the name above the player
        }
      }

      update(parkourObjects) {
        // Check horizontal collisions first
        this.x += this.speedX; // Update horizontal position

        // Handle collisions with parkour objects when moving horizontally
        for (let obj of parkourObjects) {
          if (this.collidesWith(obj)) {
            if (this.speedX > 0) { // Moving right
              this.x = obj.x - this.w; // Move player to the left of the object
            } else if (this.speedX < 0) { // Moving left
              this.x = obj.x + obj.w; // Move player to the right of the object
            }
          }
        }

        // Apply gravity
        this.y += this.speedY; // Apply current vertical speed
        this.speedY += this.gravity; // Apply gravity to vertical speed

        // Ground check
        if (this.y + this.h >= canvas.height - GRASS_HEIGHT) {
          this.y = canvas.height - this.h - GRASS_HEIGHT; // Position on the grass
          this.speedY = 0; // Reset vertical speed
          this.onObject = false; // Reset onObject flag
        }

        // Reset onObject flag before checking collisions
        this.onObject = false;

        // Check collision with parkour objects
        for (let obj of parkourObjects) {
          if (this.collidesWith(obj)) {
            // Collision response for falling onto an object
            if (this.speedY > 0 && this.y + this.h <= obj.y + obj.h) {
              this.y = obj.y - this.h; // Position on top of the object
              this.speedY = 0; // Reset vertical speed
              this.onObject = true; // Set onObject to true
            }
            // Stop upward movement if colliding with the bottom of the parkour object
            if (this.speedY < 0 && this.y <= obj.y + obj.h && this.y + this.h > obj.y) {
              this.y = obj.y + obj.h; // Position just below the object
              this.speedY = 0; // Stop vertical movement
            }
          }
        }

        this.draw();
      }

      collidesWith(obj) {
        return this.x < obj.x + obj.w &&
               this.x + this.w > obj.x &&
               this.y < obj.y + obj.h &&
               this.y + this.h > obj.y;
      }

      jump() {
        // Allow jumping if on the ground or on top of any parkour object
        const onGround = this.y + this.h >= canvas.height - GRASS_HEIGHT; // Check if on ground (grass)

        // Allow jump if on the ground or on a parkour object
        if (onGround || this.onObject) {
          this.speedY = this.jumpSpeed; // Set the jump speed
        }
      }
    }

    class ParkourObject {
      constructor(x, y, w, h, color) {
        this.x = x;
        this.y = y;
        this.w = w;
        this.h = h;
        this.color = color;
      }

      draw() {
        ctx.fillStyle = this.color;
        ctx.fillRect(this.x, this.y, this.w, this.h);
      }
    }

    class Controller {
      constructor() {
        this.up = false;
        this.right = false;
        this.left = false;

        let keyEvent = (e) => {
          if (e.code === "KeyW" || e.code === "ArrowUp") { this.up = e.type === 'keydown'; }
          if (e.code === "KeyD" || e.code === "ArrowRight") { this.right = e.type === 'keydown'; }
          if (e.code === "KeyA" || e.code === "ArrowLeft") { this.left = e.type === 'keydown'; }
        };

        addEventListener('keydown', keyEvent);
        addEventListener('keyup', keyEvent);
      }
    }

    // Create parkour objects
    const parkourObjects = [
      new ParkourObject(200, canvas.height - GRASS_HEIGHT - 100, 100, 20, 'brown'), // Parkour box 1
      new ParkourObject(400, canvas.height - GRASS_HEIGHT - 50, 100, 20, 'brown'), // Parkour box 2
    ];

    // Initialize controller
    const controller1 = new Controller();

    // WebSocket connection
       // WebSocket connection
       const socket = new WebSocket('ws://localhost:8080');

socket.addEventListener('open', () => {
  console.log('WebSocket connection established');
});

// Listen for messages
socket.onmessage = (event) => {
  event.data.text().then((text) => {
    const data = JSON.parse(text);
    if (data.type === 'positionUpdate') {
      // Update player positions
      if (!players[data.id]) {
        players[data.id] = new Player(data.id, data.x, data.y, 50, 50, data.icon, data.name, 0.5);
      } else {
        players[data.id].x = data.x;
        players[data.id].y = data.y;
      }
    } else if (data.type === 'playerDisconnected') {
      // Remove player when they disconnect
      delete players[data.id];
    }
  }).catch((error) => console.error("Error parsing message:", error));
};

// Handle page unload event to notify server of disconnection
window.addEventListener('beforeunload', () => {
  if (myPlayerId) {
    socket.send(JSON.stringify({
      type: 'disconnect',
      id: myPlayerId
    }));
  }
});

    // Function to update positions based on controls
    function updatePosition() {
      if (myPlayerId) {
        const player = players[myPlayerId];
        if (controller1.up) {
          player.jump();
        }
        if (controller1.right) {
          player.speedX = 5; // Move right
        } else if (controller1.left) {
          player.speedX = -5; // Move left
        } else {
          player.speedX = 0; // Stop moving
        }
      }
    }

    // Main game loop
    function gameLoop() {
      ctx.clearRect(0, 0, canvas.width, canvas.height); // Clear canvas
      ctx.fillStyle = 'green'; // Grass color
      ctx.fillRect(0, canvas.height - GRASS_HEIGHT, canvas.width, GRASS_HEIGHT); // Draw grass

      // Draw parkour objects
      parkourObjects.forEach(obj => obj.draw());

      // Update and draw all players
      for (const id in players) {
        players[id].update(parkourObjects);
      }

      updatePosition(); // Update my player position

      // Send position updates if WebSocket is open
      if (socket.readyState === WebSocket.OPEN && myPlayerId) {
        socket.send(JSON.stringify({
          type: 'positionUpdate',
          id: myPlayerId,
          x: players[myPlayerId].x,
          y: players[myPlayerId].y,
          icon: playerIcon,
          name: playerName
        }));
      }

      requestAnimationFrame(gameLoop); // Continue the game loop
    }

    // Start the game once the player enters their name and selects an icon
    document.getElementById('startGameButton').addEventListener('click', () => {
      playerName = document.getElementById('playerNameInput').value;
      playerIcon = document.querySelector('.icon.selected')?.dataset.icon || 'defaultIcon.png'; // Default if not selected

      // Initialize player with selected icon
      const groundLevel = canvas.height - GRASS_HEIGHT;
      myPlayerId = Date.now(); // Generate a unique ID based on timestamp
      players[myPlayerId] = new Player(myPlayerId, 50, groundLevel, 50, 50, playerIcon, playerName, 1); // Opaque for this player

      // Hide the start screen and start the game
      document.getElementById('startScreen').style.display = 'none';
      gameLoop(); // Start the game loop
    });

    // Handle icon selection
    document.querySelectorAll('.icon').forEach(icon => {
      icon.addEventListener('click', () => {
        // Deselect all icons
        document.querySelectorAll('.icon').forEach(i => i.classList.remove('selected'));
        // Select the clicked icon
        icon.classList.add('selected');
      });
    });

    // Resize canvas on window resize
    window.addEventListener('resize', () => {
      canvas.width = window.innerWidth;
      canvas.height = window.innerHeight;
    });
  </script>
</body>
</html>

server-side code

const WebSocket = require('ws');

const server = new WebSocket.Server({ port: 8080 });

const players = {}; // Object to hold connected players

server.on('connection', (socket) => {
  let playerId = Date.now(); // Generate a unique ID for the player
  players[playerId] = { socket }; // Store the player's socket

  // Notify all players of the new player
  for (const id in players) {
    if (players[id].socket.readyState === WebSocket.OPEN) {
      players[id].socket.send(JSON.stringify({
        type: 'playerConnected',
        id: playerId,
        name: "Player " + playerId, // Placeholder for player name
        icon: 'icon1.png' // Placeholder for player icon
      }));
    }
  }

  socket.on('message', (message) => {
    const data = JSON.parse(message);

    if (data.type === 'positionUpdate') {
      // Broadcast updated player position to all players
      for (const id in players) {
        if (players[id].socket.readyState === WebSocket.OPEN) {
          players[id].socket.send(JSON.stringify({
            type: 'positionUpdate',
            id: data.id,
            x: data.x,
            y: data.y,
            icon: data.icon,
            name: data.name
          }));
        }
      }
    } else if (data.type === 'disconnect') {
      // Handle player disconnection
      delete players[data.id]; // Remove player from the players object
      // Notify all remaining players about the disconnection
      for (const id in players) {
        if (players[id].socket.readyState === WebSocket.OPEN) {
          players[id].socket.send(JSON.stringify({
            type: 'playerDisconnected',
            id: data.id
          }));
        }
      }
    }
  });

  socket.on('close', () => {
    // Handle cleanup when the socket closes unexpectedly
    delete players[playerId];
  });
});

Unable to retrieve publicUrl from supabase api even with no RLS enabled

I am learning to use Supabase storage to store files (images) and retrieve the public url and store them in my database to save space. but the issue is that I am able to upload it to supabase but when variable that stored the retrieved publicUrl is undefined. Not sure what I did wrong or if I have to configure the supabase policy. So far browsing through the internet I haven’t seen anyone else experience the same problem as me. I hope to get some input on this.

Here’s my snippet of code

try {
    
    const filePath = `product_images/${Date.now()}-${file.originalname}`;
    const { data, error } = await supabase.storage
      .from("product_image")
      .upload(filePath, file.buffer, {
        contentType: file.mimetype,
        cacheControl: "3600",
        upsert: false,
      });

    if (error) {
      console.error("Error uploading to Supabase:", error.message);
      return res.status(500).json({ error: "Failed to upload image" });
    }
    console.log(data);
    
    const { publicURL } = supabase.storage
      .from("product_image")
      .getPublicUrl(data.path);

    
    console.log(publicURL);
} catch (error) {
    console.error("Error adding product:", error);
    res.status(500).json({ error: "Failed to add product" });
}

I tried ChatGPT, changing my API keys around, don’t understand much RLS yet but tried to remove all RLS and auth access restriction as much as I know, tried messing with the data.path and hardcodes the path to get the public url but nothing works.

How do I calculate the color RGB code in a color picker?

I’m trying to make a reusable color color picker component in react, I want to calculate the RGB color code using the mouse coordinates on a 256 by 256 div, the div has a white background color and it has two css gradients, in it the first one is black from the bottom and transparent to the top, the second is blue to the right and transparent to the top, I’m currently assuming that blue is being picked I want to make it dynamic later, in my calculateColor function I assume that the blue channel is y - 255 please correct me if i’m wrong, but I don’t know how to calculate the red and green channel.

function calculateColor(x: number, y: number) {
  const r = // ???
  const g = // ???
  const b = 255 - y
          
  return `rgb(${r}, ${g}, ${b})`;
}

JSX

<div className="colors" onMouseDown={e => colorsMouseDown(e, "colors")} ref={colorsRef}>
  <div className="gradient1"></div>
  <div className="gradient2"></div>
  <div className="picker" draggable="false" ref={colorsPickerRef} />
</div>

I tried to calculate red and green channel using Math.max but it doesn’t seem to be right because I took a screenshot of it and I picked the picked color in and it doesn’t match the calculated color in the red and green channel, but it does match the blue channel.

function calculateColor(x: number, y: number) {
  const r = 255 - Math.max(x, y);
  const g = 255 - Math.max(x, y);
  const b = 255 - y
          
  return `rgb(${r}, ${g}, ${b})`;
}

if you put this picture in another color picker and pick the color in the circle it would be rgb(32, 32, 99) which is different than the color shown

How to create service available globally within the application not just nitro or nuxtapp?

I tried several options but couldn’t find appropriate way of registering a singleton service which itself registers several functionality. For example, I’ve a Service called “Workflow” and I want to register activities inside this workflow, something like:

import {Activity1, Activity2, ....} from "/path/to/activities".
...
workflowService.register([Activity1, Activity2, ....]);

I need to run this only once, as it is expensive to call at every api call or cron jobs, or any other background stuffs. Remember I need this to only work in the server side, client side is not needed. I tried registering it with plugins/<plugin>.server.ts, and server/plugins/<plugin>.ts none of them works, as the context is completely different when using the service inside a cron job.

I couldn’t understand the underlying concept here, what is the best way to do this?

PLEASE HELP!!!

Face API can´t compare two images, even if they are the same image

I’m working on a project for university, which involves a facial recognition system integrated with an electronic gate. I created a registration for people, and now I need to compare received faces with stored faces. To do this, I created two folders with identical photos and two detection methods: one that takes the image URL to be stored in my Amazon S3 bucket, and another that takes the image from the to_compare folder. However, even if the images are identical, the system does not recognize them as the same person. One possibility is that the images have arrays of different sizes, but I already filtered the array to have only 100 elements.

const mongoose = require('mongoose');

const personSchema = new mongoose.Schema({
  name: { type: String, required: true },
  cpf: { type: String, required: true, unique: true },
  birthDate: { type: Date, required: true },
  photoUrl: { type: String },
  biometrics: { type: Object }, // Dados biométricos processados da imagem
  employee: { type: Boolean, required: true, default: false },
  position: {
    type: {
      title: { type: String, required: true },
      department: { type: String, required: true },
      hireDate: { type: Date, required: true }
    },
    default: null,
    validate: {
      validator: function () {
        return this.employee || this.position === null;
      },
      message: 'Position should be null if employee is false'
    }
  },
  active: { type: Boolean, default: true } // Campo indicando se a pessoa está ativa
});

// Método para ativar a pessoa
personSchema.methods.activate = function () {
  this.active = true;
  return this.save();
};

// Método para desativar a pessoa
personSchema.methods.deactivate = function () {
  this.active = false;
  return this.save();
};

module.exports = mongoose.model('Person', personSchema);
// src/controller/personController.js

const Person = require('../model/personModel');
const { processBiometrics, compareBiometrics, compareWithRegisteredImages } = require('../util/biometricsUtils');

/**
 * Creates a new person in the system with processed biometric data.
 * @param {Object} req - Request object containing person data in the body.
 * @param {Object} res - Response object.
 */
exports.createPerson = async (req, res) => {
    try {
        console.log("Creating person with data:", req.body);
        const { name, cpf, birthDate, photoUrl, employee, position } = req.body;

        // Processes biometrics if an image is provided
        const biometrics = photoUrl ? await processBiometrics(photoUrl) : null;
        console.log("Biometrics processed:", biometrics);

        // Creates a new person
        const person = new Person({
            name,
            cpf,
            birthDate,
            photoUrl,
            biometrics,
            employee,
            position: employee ? position : null,
        });

        await person.save();
        console.log("Person created successfully:", person);
        res.status(201).json({ message: 'Person created successfully', person });
    } catch (error) {
        console.error("Error creating person:", error);
        res.status(500).json({ error: 'Error creating person' });
    }
};

/**
 * Retrieves a person by ID.
 * @param {Object} req - Request object containing the person's ID in the parameters.
 * @param {Object} res - Response object.
 */
exports.getPersonById = async (req, res) => {
    try {
        console.log("Fetching person by ID:", req.params.id);
        const person = await Person.findById(req.params.id);
        if (!person) {
            console.warn("Person not found with ID:", req.params.id);
            return res.status(404).json({ error: 'Person not found' });
        }

        console.log("Person fetched:", person);
        res.status(200).json(person);
    } catch (error) {
        console.error("Error fetching person:", error);
        res.status(500).json({ error: 'Error fetching person' });
    }
};

/**
 * Updates a person's data by ID and reactivates them.
 * @param {Object} req - Request object with the person's ID in the parameters and new data in the body.
 * @param {Object} res - Response object.
 */
exports.updatePerson = async (req, res) => {
    try {
        console.log("Updating person with ID:", req.params.id);
        const { name, cpf, birthDate, photoUrl, employee, position } = req.body;

        const person = await Person.findById(req.params.id);
        if (!person) {
            console.warn("Person not found with ID:", req.params.id);
            return res.status(404).json({ error: 'Person not found' });
        }

        person.name = name || person.name;
        person.cpf = cpf || person.cpf;
        person.birthDate = birthDate || person.birthDate;
        person.photoUrl = photoUrl || person.photoUrl;
        person.employee = employee !== undefined ? employee : person.employee;
        person.position = employee ? position : null;

        // Updates biometrics if a new photo is provided
        if (photoUrl) {
            console.log("Processing new biometrics for update...");
            person.biometrics = await processBiometrics(photoUrl);
        }

        // Reactivates the person on update
        await person.activate();
        console.log("Person updated and activated successfully:", person);

        res.status(200).json({ message: 'Person updated and activated successfully', person });
    } catch (error) {
        console.error("Error updating person:", error);
        res.status(500).json({ error: 'Error updating person' });
    }
};

/**
 * Deactivates a person by ID, instead of deleting them from the database.
 * @param {Object} req - Request object with the person's ID in the parameters.
 * @param {Object} res - Response object.
 */
exports.deletePerson = async (req, res) => {
    try {
        console.log("Deactivating person with ID:", req.params.id);
        const person = await Person.findById(req.params.id);
        if (!person) {
            console.warn("Person not found with ID:", req.params.id);
            return res.status(404).json({ error: 'Person not found' });
        }

        await person.deactivate();
        console.log("Person deactivated successfully:", person);
        res.status(200).json({ message: 'Person deactivated successfully' });
    } catch (error) {
        console.error("Error deactivating person:", error);
        res.status(500).json({ error: 'Error deactivating person' });
    }
};

/**
 * Lists all persons registered in the system.
 * @param {Object} req - Request object.
 * @param {Object} res - Response object.
 */
exports.getAllPersons = async (req, res) => {
    try {
        console.log("Fetching all persons...");
        const persons = await Person.find();
        console.log("Persons fetched:", persons);
        res.status(200).json(persons);
    } catch (error) {
        console.error("Error fetching persons:", error);
        res.status(500).json({ error: 'Error fetching persons' });
    }
};

/**
 * Verifies an image provided by URL and compares it with the biometrics of active persons.
 * @param {Object} req - Request object containing the image URL in the body.
 * @param {Object} res - Response object.
 */
exports.verifyPerson = async (req, res) => {
    try {
        console.log("Verifying person with photoUrl:", req.body.photoUrl);
        const { photoUrl } = req.body;

        // Processes the image to obtain biometric data
        const biometrics = await processBiometrics(photoUrl);
        if (!biometrics) {
            console.warn("No biometric data found in provided image.");
            return res.status(404).json({ match: false });
        }

        console.log("Processed biometrics for verification:", biometrics);

        // Compares biometrics with registered persons
        const persons = await Person.find({ active: true });
        console.log("Comparing biometrics with active persons...");

        for (let person of persons) {
            if (person.biometrics && compareBiometrics(biometrics, person.biometrics)) {
                console.log("Match found:", person);
                return res.status(299).json({ match: true, person });
            }
        }

        console.log("No match found.");
        res.status(404).json({ match: false });
    } catch (error) {
        console.error("Error verifying person:", error);
        res.status(500).json({ error: 'Error verifying person' });
    }
};

/**
 * Verifies a test image from the 'to_compare' folder by comparing it with registered images.
 * Receives the image name and compares it with stored biometrics in the 'registered' folder.
 * @param {Object} req - Request object containing the image name in the body.
 * @param {Object} res - Response object.
 */
exports.verifyPersonWithImage = async (req, res) => {
    try {
        const { imageName } = req.body;
        console.log("Verifying person with image:", imageName);

        // Calls the comparison function with registered images
        const result = await compareWithRegisteredImages(imageName);

        // Responds with comparison results
        if (result.match) {
            res.status(299).json({ match: true, fileName: result.fileName });
        } else {
            res.status(404).json({ match: false });
        }
    } catch (error) {
        console.error("Error verifying person:", error);
        res.status(500).json({ error: 'Error verifying person' });
    }
};

// src/util/biometricsUtils.js

const faceapi = require('face-api.js'); // Library for facial recognition
const tf = require('@tensorflow/tfjs-node'); // TensorFlow for data processing
const { Canvas, Image, ImageData } = require('canvas'); // Canvas for image manipulation
const canvas = require('canvas');
const path = require('path');
const fs = require('fs');

// Configures face-api.js to use canvas and manipulate images
faceapi.env.monkeyPatch({ Canvas, Image, ImageData });

/**
 * Loads the necessary facial recognition models for detection,
 * facial landmarks extraction, and facial descriptor.
 */
const loadModels = async () => {
    const modelPath = './models'; // Path where models are stored
    await faceapi.nets.ssdMobilenetv1.loadFromDisk(modelPath);
    await faceapi.nets.faceLandmark68Net.loadFromDisk(modelPath);
    await faceapi.nets.faceRecognitionNet.loadFromDisk(modelPath);
};

/**
 * Processes a local image to extract biometric data with the first 100 elements.
 * @param {string} imagePath - Path to the local image to be processed.
 * @returns {Float32Array | null} Extracted biometric data (100 elements) or null if no face is detected.
 */
const processBiometrics = async (imagePath) => {
    try {
        console.log("Processing biometrics for image:", imagePath);

        // Loads models if not already loaded
        await loadModels();

        // Loads the image from the specified path
        const img = await canvas.loadImage(imagePath);
        const detections = await faceapi.detectSingleFace(img)
            .withFaceLandmarks()
            .withFaceDescriptor();

        if (!detections) {
            console.warn("No face detected in image.");
            return null;
        }

        // Returns only the first 100 elements of the facial descriptor
        const biometrics = detections.descriptor.slice(0, 100);
        if (biometrics && biometrics.length === 100) {
            console.log("Biometric data loaded successfully with 100 elements.");
        } else {
            console.warn("Biometric data not loaded correctly or has an incorrect length.");
        }
        return biometrics;
    } catch (error) {
        console.error("Error processing biometrics:", error);
        return null;
    }
};

/**
 * Compares two sets of biometric data to check for a match.
 * @param {Float32Array} biometrics1 - First set of biometric data (100 points).
 * @param {Float32Array} biometrics2 - Second set of biometric data (100 points).
 * @returns {boolean} Returns true if data matches, false otherwise.
 */
const compareBiometrics = (biometrics1, biometrics2) => {
    if (!biometrics1 || !biometrics2) {
        console.warn("One of the biometric arrays is null.");
        return false;
    }
    if (biometrics1.length !== 100 || biometrics2.length !== 100) {
        console.warn("Biometric data length mismatch. Expected 100 elements.");
        return false;
    }

    try {
        // Calculates the Euclidean distance between the descriptors
        const distance = faceapi.euclideanDistance(biometrics1, biometrics2);
        const threshold = 0.7; // Adjusted threshold for more flexible matching
        return distance < threshold;
    } catch (error) {
        console.error("Error comparing biometrics:", error);
        return false;
    }
};

/**
 * Compares two sets of biometric data multiple times to check for match consistency.
 * @param {Float32Array} biometrics1 - First set of biometric data.
 * @param {Float32Array} biometrics2 - Second set of biometric data.
 * @param {number} attempts - Number of verification attempts.
 * @returns {boolean} Returns true if there is a match in all attempts, false otherwise.
 */
const verifyBiometricsMultipleAttempts = (biometrics1, biometrics2, attempts = 3) => {
    let matches = 0;
    for (let i = 0; i < attempts; i++) {
        if (compareBiometrics(biometrics1, biometrics2)) {
            matches++;
        }
    }
    return matches >= attempts;
};

/**
 * Loads and processes all images in the 'registered' folder for storing biometric data.
 * @returns {Object} An object containing biometric data for each registered image.
 */
const loadRegisteredBiometrics = async () => {
    const registeredPath = path.join(__dirname, '../../images/registered');
    const registeredBiometrics = {};

    const files = fs.readdirSync(registeredPath);
    for (const file of files) {
        const imagePath = path.join(registeredPath, file);
        const biometricData = await processBiometrics(imagePath);
        if (biometricData) {
            registeredBiometrics[file] = biometricData;
        }
    }
    return registeredBiometrics;
};

/**
 * Compares an image from the 'to_compare' folder with all registered images in the 'registered' folder.
 * Checks each comparison multiple times to ensure the match.
 * @param {string} compareImageName - Name of the image to be compared.
 * @returns {Object} An object indicating if there was a match and the name of the corresponding image.
 */
const compareWithRegisteredImages = async (compareImageName) => {
    const registeredBiometrics = await loadRegisteredBiometrics();
    const compareImagePath = path.join(__dirname, '../../images/to_compare', compareImageName);
    const compareBiometricsData = await processBiometrics(compareImagePath);

    if (!compareBiometricsData) {
        console.warn("No biometric data found in comparison image.");
        return { match: false };
    }

    for (const [fileName, registeredBiometricsData] of Object.entries(registeredBiometrics)) {
        // Checks for a match with at least 3 attempts
        if (verifyBiometricsMultipleAttempts(compareBiometricsData, registeredBiometricsData, 3)) {
            console.log(`Match found with registered image: ${fileName}`);
            return { match: true, fileName };
        }
    }

    console.log("No match found.");
    return { match: false };
};

module.exports = {
    processBiometrics,
    compareBiometrics,
    loadRegisteredBiometrics,
    compareWithRegisteredImages
};
// src/route/personRoutes.js

const express = require('express');
const personController = require('../controller/personController');
const router = express.Router();

/**
 * Route to create a new person.
 * Method: POST
 * Endpoint: /persons
 * Request Body: JSON with person data (name, cpf, birthDate, photoUrl, etc.)
 */
router.post('/', personController.createPerson);

/**
 * Route to retrieve a person by ID.
 * Method: GET
 * Endpoint: /persons/:id
 * Parameter: Person's ID in the URL.
 */
router.get('/:id', personController.getPersonById);

/**
 * Route to update a person's data by ID.
 * Method: PUT
 * Endpoint: /persons/:id
 * Parameter: Person's ID in the URL.
 * Request Body: JSON with the data to be updated.
 */
router.put('/:id', personController.updatePerson);

/**
 * Route to deactivate a person by ID.
 * Method: DELETE
 * Endpoint: /persons/:id
 * Parameter: Person's ID in the URL.
 */
router.delete('/:id', personController.deletePerson);

/**
 * Route to list all registered persons.
 * Method: GET
 * Endpoint: /persons
 */
router.get('/', personController.getAllPersons);

/**
 * Route to verify a person's biometrics using an image URL.
 * Method: POST
 * Endpoint: /persons/verify
 * Request Body: JSON with the image URL (photoUrl).
 */
router.post('/verify', personController.verifyPerson);

/**
 * Route to verify a person's biometrics using a local image from the 'to_compare' folder.
 * Method: POST
 * Endpoint: /persons/verify-image
 * Request Body: JSON with the name of the image to be compared (imageName).
 */
router.post('/verify-image', personController.verifyPersonWithImage);

module.exports = router;

I tried checking with ChatGPT, but I keep going in circles with it.

I used ChatGPT to add comments to the code for better understanding, and I’d like to know where I might be going wrong. If anyone could help, I’d be very grateful.

Why doesn’t the statement after await continue to execute after promise resolves?

I want to implement an asynchronous task scheduling. This is my code:

let gameTick = 0;

const tasks: Record<string, Function[]> = {};

function sleep(t: number) {
    const targetTick = gameTick + t;
    if (!tasks[targetTick]) {
        tasks[targetTick] = [];
    }
    return new Promise<void>(resolve => {
        tasks[targetTick].push(resolve);
    });
}

async function task1() {
  print('start task1');
  for (let i = 0; i < 3; i++) {
    print(`execute: ${i}`);
    await sleep(2);
  }
}

// task1();

for (gameTick = 0; gameTick < 10; gameTick++) {
    print(`tick: ${gameTick}`);
    tasks[gameTick]?.forEach(f => f())
    if (gameTick == 2) task1();
}

This code behaves differently in the TypeScriptToLua environment and in the node.js environment, which confuses me.

TypeScriptToLua nodejs
tick: 0 tick: 0
tick: 1 tick: 1
tick: 2 tick: 2
start task1 start task1
execute: 0 execute: 0
tick: 3 tick: 3
tick: 4 tick: 4
execute: 1 tick: 5
tick: 5 tick: 6
tick: 6 tick: 7
execute: 2 tick: 8
tick: 7 tick: 9
tick: 8 execute: 1
tick: 9

I can understand the process of TypeScriptToLua, which is equivalent to resuming the coroutine after resolve and immediately executing the code after await. But I don’t understand NodeJs. Why does it continue to execute after the loop ends, and only execute once?

How to execute a statement inside a proxied function within a specific scope?

I have a function which takes a function as an argument write(fn) {...}.

I would like to manipulate the function’s execution and execute some statements while proxying its arguments. Here is my code idea:

  ...
  const handler = {
    apply(target, thisArg, argumentsList) {
      let params = getParamNames(target);
      let statements = splitFunctionContent(target);

      statements.forEach((statement) => {
        let placeholders = refreshPlaceholders(params);
        // Create a function with placeholders as parameters
        const func = new Function(...Object.keys(placeholders), statement);
        // Execute the function with placeholders as arguments
        func(...Object.values(placeholders));
        console.log(result);
        result = "";
      });
    }
  };

  // Create a proxy for `fn` with the handler
  const p = new Proxy(fn, handler);

  // Call the proxied function
  p();

The above handling is giving a reference error, whenever there is a functioncall of a function inside the proxied function. This means that, as expected very well, the current scope of the function defined by new Function is different than the original’s fn‘s scope.

I would like to execute every statement within fn‘s scope. Any idea how to do that ?

One way of dealing with this is to execute:

target.apply(thisArg, argumentsList);

But with this, we don’t have the freedom in deciding which statement to execute.

How to achieve my goal in defining either of the following:

  1. Either define a function (just like I am doing) that has the same scope as fn (i.e, it sees all the variables that fn itself sees).
  2. Make fn execute a very specific statement within it (Since fn itself is executing it, we have no scope problem).

Instance vs prototype methods for methods parametrized by the state of the object

tl;dr

Is the suggestion of preferring prototype methods to instance method a general one, or does it apply only to the cases where the method in question is indeed independent of other instance properties?

Or, in other words, if I’m wishing to use instance methods because I want such a method to be parametrised by the individual object on which it is invoked, am I misdesigning my JavaScript application, because there are better ways to achieve this (i.e. methods that depend on the state of the object, e.g. on its instance variables)?


Longer version

In §7.2.1 from Secrets of the JavaScript Ninja – 2nd ed., the difference is explained between defining an instance method

function Ninja() {
  this.swung = false;
  this.swingSword = function() {
    return 'swing';
  };
}

const n1 = new Ninja();
const n2 = new Ninja();

console.log(n1.swingSword())
console.log(n2.swingSword())

vs defining a prototype method

function Ninja() {
  this.swung = false;
}
Ninja.prototype.swingSword = function() {
  return 'swing';
}

const n1 = new Ninja();
const n2 = new Ninja();

console.log(n1.swingSword())
console.log(n2.swingSword())

Besides the fact that, if both are defined, the former takes precedence, the claim is made that the former also imposes a performance penalty (at least if the number of created objects is large enough), because a new copy of the method will be created for each new Ninja() invocation.

And I understand that, but that claim is not meant to apply to this simple toy example, but to be of general guidance (at least that’s the way I interpret the text of the book!), and I don’t understand why things should be like that.

Indeed, I can’t help but thinking of a slightly more complex example, where the constructor has some parameters which are captured by the closures of the instance methods, which means that effectively the function will be different for every object:

function Ninja(foo) {
  this.swung = foo;
  this.swingSword = function() {
    return foo;
  };
}

const n1 = new Ninja('one');
const n2 = new Ninja('two');

console.log(n1.swingSword()) // this calls function() { return 'one'; };
console.log(n2.swingSword()) // this calls function() { return 'two'; };

In this case, I think, a prototype method is not an option, because it would be common across the object, and so it couldn’t be customized by each object, no?

And this also applies to member variables, e.g. swung in the last example must be an instance property, but in the original example could well be a prototype property, because it’s just false, it doesn’t change.

function Ninja() {}
Ninja.prototype.swung = false;
Ninja.prototype.swingSword = function() {
  return 'swing';
}

const n1 = new Ninja();
const n2 = new Ninja();

console.log(n1.swung)
console.log(n2.swung)

Upload image buttons in flask app don’t work anymore

I have a flask app, running locally, that I am trying to debug. There is some sort of issue with the response I am sending to the frontend, since the most recent commit (not related to the upload image buttons). I have cloned the repo with the code that works into a separate folder on my machine so I can gradually introduce changes until I find where I introduced problems in the response. I have been running this working app in the different folder fine. But now, when I switch to the original app that is ahead of the recent commit, I can’t even run it to reproduce the issue anymore because for whatever reason, the upload image button is now unresponsive. Somehow, running the copied code made the upload image buttons no longer work.

I have:
1.) Confirmed the copied working code is no longer running.
2.) Cleared the FireFox cache
3.) Tried using a different port
4.) Restarted my machine

I am on Ubuntu 20 if that matters.

Also, in the console, I see an error message pointing to a line in one of my template html files, but it is a line that does not exist (higher line number than lines in the file):

Uncaught SyntaxError: redeclaration of const msg
note: Previously declared at line 613, column 11

What else could be going wrong here?

How can I position a object in the centre of screen with respect to viewport in css?

This is a code of a game, in this I am not able to position the character in centre of the screen (which is visible) dynamically. When the size of the screen or window changes then the character gets displaced to different positions, I want that it should remain in centre, whatever the size,

html code

<div class="game-screen">
    <div class="map pixel-art">
        <div class="character" facing="down" walking="true">
            <div class="shadow pixel-art"></div>
            <div class="character_spritesheet pixel-art"></div>
        </div>
        <!-- Your map content -->
    </div>
</div>

css code

.game-screen {
    /* aspect-ratio: 16/9; */
    height: 110vh;
    width: 100vw;
    overflow: hidden;
    background: #46a6da;
    position: relative;
}

.map {
    image-rendering: pixelated;
    background-image: url("now.png");
    background-size: 100%;
    top: 0vh; /* Centering vertically */
    left: 0vw; /* Centering horizontally */
    width: calc(13 * var(--grid-cell) * 3);
    height: calc(10 * var(--grid-cell) * 3);
    position: absolute;
    transform: translate(-50%, -50%); 
}

.character {
    position: fixed;
    width: calc(var(--grid-cell) * 2);
    height: calc(var(--grid-cell) * 2);
    top: 50vh;
    left: 50vw; 
    transform: translate(-50%, -50%); 
    overflow: hidden;
    z-index: 2;
}



.shadow {
    width: calc(var(--grid-cell) * 2);
    height: calc(var(--grid-cell) * 2);
    position: absolute;
    left: 0;
    top: 0;
    background: url("1718700427772.png") no-repeat no-repeat;
    background-size: 100%;
}

.character_spritesheet {
    position: absolute;
    background: url("1718700512677.png") no-repeat no-repeat;
    background-size: 100%;
    width: calc(var(--grid-cell) * 8);
    height: calc(var(--grid-cell) * 8);
}

.character[facing="right"] .character_spritesheet {
    background-position-y: calc(var(--pixel-size) * -32);
}
.character[facing="up"] .character_spritesheet {
    background-position-y: calc(var(--pixel-size) * -64);
}
.character[facing="left"] .character_spritesheet {
    background-position-y: calc(var(--pixel-size) * -96);
}
.character[walking="true"] .character_spritesheet {
    animation: walkAnimation 0.6s steps(4) infinite; 
}

What I tried,
I used viewport height and width to centre the character but does not work.
you can check it out here link

=> I want that irrespective of the screen size the character should always be in centre

As a student I am not able to figure out the problem, please help me!!!

Flatpickr is highlighting the day after

I have a club trial session with date: 06/11/2024
but the calendar is highlighting the day after: 07/11/2024

The javascript code:

document.addEventListener('DOMContentLoaded', function() {
    // Pass session dates directly from Laravel to JavaScript
    const sessionSchedules = @json($sessionSchedules);
    console.log("Session Schedules:", sessionSchedules); // Log session schedules to inspect data

    // Initialize Flatpickr with session dates highlighted in green
    flatpickr("#session-date-input", {
        dateFormat: "Y-m-d",
        minDate: "today", // Ensures user cannot pick past dates
        disable: [
            date => !sessionSchedules.some(schedule =>
                // Check if the date is in sessionSchedules
                schedule.day === date.toISOString().split('T')[0] // Ensure proper date comparison
            )
        ],
        onDayCreate: function(dObj, dStr, fp, dayElem) {
            const dateStr = dayElem.dateObj.toISOString().split('T')[0]; // Format the date as YYYY-MM-DD
            console.log("The day being checked: ", dateStr); // Log the date being checked

            let isColored = false; // Track if the day has already been colored

            // Check each session schedule for a match
            sessionSchedules.forEach(schedule => {
                console.log("Checking against schedule day: ", schedule.day); // Log schedule days for debugging
                // Ensure both dates are in the same format before comparison
                if (schedule.day === dateStr && !isColored) {
                    dayElem.style.backgroundColor = "lightgreen"; // Highlight the matching day
                    dayElem.style.color = "black";
                    console.log("Colored Day Element: ", dayElem); // Log the day element being colored
                    console.log("Matched with Schedule Day: ", schedule.day); // Log the matched schedule day

                    isColored = true; // Set flag to prevent further coloring
                    return; // Exit the forEach loop after coloring the matched day
                }
            });
        },
        onChange: function(selectedDates) {
            const sessionSelect = document.getElementById("session-schedule-select");
            sessionSelect.innerHTML = '<option selected disabled>{{ __('frontpages.trialSession.session_date') }}</option>';

            if (selectedDates.length > 0) {
                const selectedDate = selectedDates[0].toISOString().split('T')[0]; // Get selected date in YYYY-MM-DD

                // Filter schedules based on the selected date
                sessionSchedules.forEach(schedule => {
                    if (schedule.day === selectedDate) {
                        const option = document.createElement("option");
                        option.value = schedule.id;
                        option.textContent = `${schedule.day} / ${schedule.start_at} / {{ __('frontpages.trialSession.duration') }} ${schedule.duration} {{ __('frontpages.trialSession.minute') }}`;
                        option.dataset.day = schedule.day;
                        option.dataset.time = schedule.start_at;
                        sessionSelect.appendChild(option);
                    }
                });
            }
        }
    });
});

I get in the console:
Checking against schedule day: 2024-11-06
trialsession:282 Colored Day Element: <span class=​”flatpickr-day” aria-label=​”November 7, 2024″ tabindex=​”-1″ style=​”background-color:​ lightgreen;​ color:​ black;​”>​7​​
trialsession:283 Matched with Schedule Day: 2024-11-06
trialsession:271 The day being checked: 2024-11-07

So how the November 7, 2024 is matched with 06/11/2024!!

I tried to check the date from database which is 06/11/2024 but it matched with November 7, 2024

How do I overcome a lwz compressed string that causes problems in a js file? [closed]

I need to store some very large preset arrays in a javascript file. Each array needs to be compressed separately and the javascript file needs to be as small as possible. One of those arrays needs to be unpacked very quickly at run time (when the user chooses which array is needed).

The problem is the Visual Studio Code complains about carriage returns and lines not being ended correctly. This is due to the lzw compression.

Compression is needed because the original array appears about 600KB, the JSON string appears about 30KB and the final compressed string is just 14KB.

I do not want to use a database, as the call and return for that would in itself put notable delays when that array is called. It has to be fast (it is critical to the program).

So, I used JSON to make the array into a string. Then I used lzw compression to compress that string. That string (and the other strings of similarly compressed arrays) are then put into the javascript file.

(NOTE: In the following code, the array is just a small fraction of the real array which is about 32 times larger.)

function lzw_encode(s) {
    let i, dict = {}, data = (s + "").split(""),
        out = [], currChar, phrase = data[0], code = 256;
    for (i = 1, len = data.length; i < len; i++) {
        currChar = data[i];
        if (dict[phrase + currChar] != null) {
            phrase += currChar;
        }
        else {
            out.push(phrase.length > 1 ? dict[phrase] : phrase.charCodeAt(0));
            dict[phrase + currChar] = code;
            code++;
            phrase = currChar;
        }
    }
    out.push(phrase.length > 1 ? dict[phrase] : phrase.charCodeAt(0));
    for (i = 0, len = out.length; i < len; i++) {
        out[i] = String.fromCharCode(out[i]);
    }
    return out.join("");
}

let a = [
  [
    [
      [
        [
          [
            770,
            784,
            795,
          ],
          [
            804,
            816,
            830,
          ],
          [
            770,
            784,
            795,
          ],
        ],
        [
          [
            672,
            695,
            721,
          ],
          [
            738,
            750,
            761,
          ],
          [
            672,
            695,
            721,
          ],
        ],
      ],
      [
        [
          [
            672,
            695,
            721,
          ],
          [
            738,
            750,
            761,
          ],
          [
            672,
            695,
            721,
          ],
        ],
        [
          [
            555,
            572,
            592,
          ],
          [
            606,
            626,
            649,
          ],
          [
            555,
            572,
            592,
          ],
        ],
      ],
      [
        [
          [
            744,
            755,
            764,
          ],
          [
            770,
            784,
            795,
          ],
          [
            744,
            755,
            764,
          ],
        ],
        [
          [
            612,
            635,
            655,
          ],
          [
            672,
            695,
            721,
          ],
          [
            612,
            635,
            655,
          ],
        ],
      ],
    ],
    [
      [
        [
          [
            655,
            678,
            704,
          ],
          [
            655,
            678,
            704,
          ],
          [
            738,
            750,
            761,
          ],
        ],
        [
          [
            540,
            560,
            577,
          ],
          [
            540,
            560,
            577,
          ],
          [
            606,
            626,
            649,
          ],
        ],
      ],
      [
        [
          [
            540,
            560,
            577,
          ],
          [
            540,
            560,
            577,
          ],
          [
            606,
            626,
            649,
          ],
        ],
        [
          [
            454,
            468,
            480,
          ],
          [
            454,
            468,
            480,
          ],
          [
            503,
            520,
            534,
          ],
        ],
      ],
      [
        [
          [
            598,
            618,
            641,
          ],
          [
            598,
            618,
            641,
          ],
          [
            672,
            695,
            721,
          ],
        ],
        [
          [
            497,
            514,
            529,
          ],
          [
            497,
            514,
            529,
          ],
          [
            555,
            572,
            592,
          ],
        ],
      ],
    ],
  ],
  [
    [
      [
        [
          [
            638,
            652,
            663,
          ],
          [
            672,
            684,
            698,
          ],
          [
            638,
            652,
            663,
          ],
        ],
        [
          [
            540,
            563,
            589,
          ],
          [
            606,
            618,
            629,
          ],
          [
            540,
            563,
            589,
          ],
        ],
      ],
      [
        [
          [
            540,
            563,
            589,
          ],
          [
            606,
            618,
            629,
          ],
          [
            540,
            563,
            589,
          ],
        ],
        [
          [
            423,
            440,
            460,
          ],
          [
            474,
            494,
            517,
          ],
          [
            423,
            440,
            460,
          ],
        ],
      ],
      [
        [
          [
            612,
            623,
            632,
          ],
          [
            638,
            652,
            663,
          ],
          [
            612,
            623,
            632,
          ],
        ],
        [
          [
            480,
            503,
            523,
          ],
          [
            540,
            563,
            589,
          ],
          [
            480,
            503,
            523,
          ],
        ],
      ],
    ],
    [
      [
        [
          [
            523,
            546,
            572,
          ],
          [
            523,
            546,
            572,
          ],
          [
            606,
            618,
            629,
          ],
        ],
        [
          [
            408,
            428,
            445,
          ],
          [
            408,
            428,
            445,
          ],
          [
            474,
            494,
            517,
          ],
        ],
      ],
      [
        [
          [
            408,
            428,
            445,
          ],
          [
            408,
            428,
            445,
          ],
          [
            474,
            494,
            517,
          ],
        ],
        [
          [
            322,
            336,
            348,
          ],
          [
            322,
            336,
            348,
          ],
          [
            371,
            388,
            402,
          ],
        ],
      ],
      [
        [
          [
            466,
            486,
            509,
          ],
          [
            466,
            486,
            509,
          ],
          [
            540,
            563,
            589,
          ],
        ],
        [
          [
            365,
            382,
            397,
          ],
          [
            365,
            382,
            397,
          ],
          [
            423,
            440,
            460,
          ],
        ],
      ],
    ],
  ],
  [
    [
      [
        [
          [
            551,
            565,
            576,
          ],
          [
            585,
            597,
            611,
          ],
          [
            551,
            565,
            576,
          ],
        ],
        [
          [
            496,
            505,
            513,
          ],
          [
            522,
            531,
            542,
          ],
          [
            496,
            505,
            513,
          ],
        ],
      ],
      [
        [
          [
            496,
            505,
            513,
          ],
          [
            522,
            531,
            542,
          ],
          [
            496,
            505,
            513,
          ],
        ],
        [
          [
            456,
            462,
            467,
          ],
          [
            473,
            482,
            487,
          ],
          [
            456,
            462,
            467,
          ],
        ],
      ],
      [
        [
          [
            525,
            536,
            545,
          ],
          [
            551,
            565,
            576,
          ],
          [
            525,
            536,
            545,
          ],
        ],
        [
          [
            476,
            485,
            490,
          ],
          [
            496,
            505,
            513,
          ],
          [
            476,
            485,
            490,
          ],
        ],
      ],
    ],
    [
      [
        [
          [
            490,
            499,
            508,
          ],
          [
            490,
            499,
            508,
          ],
          [
            522,
            531,
            542,
          ],
        ],
        [
          [
            450,
            456,
            465,
          ],
          [
            450,
            456,
            465,
          ],
          [
            473,
            482,
            487,
          ],
        ],
      ],
      [
        [
          [
            450,
            456,
            465,
          ],
          [
            450,
            456,
            465,
          ],
          [
            473,
            482,
            487,
          ],
        ],
        [
          [
            419,
            424,
            430,
          ],
          [
            419,
            424,
            430,
          ],
          [
            439,
            444,
            450,
          ],
        ],
      ],
      [
        [
          [
            470,
            479,
            485,
          ],
          [
            470,
            479,
            485,
          ],
          [
            496,
            505,
            513,
          ],
        ],
        [
          [
            436,
            442,
            447,
          ],
          [
            436,
            442,
            447,
          ],
          [
            456,
            462,
            467,
          ],
        ],
      ],
    ],
  ],
  [
    [
      [
        [
          [
            462,
            476,
            487,
          ],
          [
            496,
            508,
            522,
          ],
          [
            462,
            476,
            487,
          ],
        ],
        [
          [
            407,
            416,
            424,
          ],
          [
            433,
            442,
            453,
          ],
          [
            407,
            416,
            424,
          ],
        ],
      ],
      [
        [
          [
            407,
            416,
            424,
          ],
          [
            433,
            442,
            453,
          ],
          [
            407,
            416,
            424,
          ],
        ],
        [
          [
            367,
            373,
            378,
          ],
          [
            384,
            393,
            398,
          ],
          [
            367,
            373,
            378,
          ],
        ],
      ],
      [
        [
          [
            436,
            447,
            456,
          ],
          [
            462,
            476,
            487,
          ],
          [
            436,
            447,
            456,
          ],
        ],
        [
          [
            387,
            396,
            401,
          ],
          [
            407,
            416,
            424,
          ],
          [
            387,
            396,
            401,
          ],
        ],
      ],
    ],
    [
      [
        [
          [
            401,
            410,
            419,
          ],
          [
            401,
            410,
            419,
          ],
          [
            433,
            442,
            453,
          ],
        ],
        [
          [
            361,
            367,
            376,
          ],
          [
            361,
            367,
            376,
          ],
          [
            384,
            393,
            398,
          ],
        ],
      ],
      [
        [
          [
            361,
            367,
            376,
          ],
          [
            361,
            367,
            376,
          ],
          [
            384,
            393,
            398,
          ],
        ],
        [
          [
            330,
            335,
            341,
          ],
          [
            330,
            335,
            341,
          ],
          [
            350,
            355,
            361,
          ],
        ],
      ],
      [
        [
          [
            381,
            390,
            396,
          ],
          [
            381,
            390,
            396,
          ],
          [
            407,
            416,
            424,
          ],
        ],
        [
          [
            347,
            353,
            358,
          ],
          [
            347,
            353,
            358,
          ],
          [
            367,
            373,
            378,
          ],
        ],
      ],
    ],
  ],
];
let str = JSON.stringify(a);
let strComp = lzw_encode(str);
document.getElementById("lab").innerHTML = strComp;
<label id="lab"></label>

The compressed string starting “[Āā770,784Ć95],….” is the genuine result. I then unpack this at run time when the array is called by doing the reverse. Its all FAST, so it does what it is meant to do.

This appears to work in production, so is not a major issue.

BUT, is there another FAST compression and unpacking that does not cause problems with carriage returns etc?

I wrote my own with just a standard character set, but it was a lot slower and did not compress as much.