Firebase v2 forced upgrade increased server costs

A few weeks ago I was forced to upgrade my firebase to v2 and my node.js from version 16 to 22, after I made this update my firebase costs ballooned overnight by 4x, I have had to shut down my server until I can figure out what could have caused this because this isn’t sustainable at this new frustrating cost, the only change I had to make to my code was the way the request handler is written, below I will give the before and after versions of how this code currently looks if anyone can explain to me how this is causing my server to cost 4x as much as it did the day before and how I can fix this would helpful.

Before:

const runtimeRetryOpts = {
  failurePolicy: true,
};

exports.webhook = functions
    .runWith(runtimeRetryOpts)
    .https.onRequest(async (request, response) =>{
// code here is the same
});

After:

exports.webhookV2 = onRequest(
// Configuration options
{
  retryConfig: {
    maxRetryAttempts: 1,
    minBackoffSeconds: 5,
  },
},
async (request, response) => {
// code here is the same
});

ng-repeat disable other repeated HTML Attribute

I am using "ng-repeat" to display 3 elements => Radio buttons- Yes/No, “Save” & “Cancel” buttons.
Objective of this question is to Enable only 1 HTML Attribute at a time in "ng-repeat" functionality.
“Save” button is repeated in each row, hence it should be enabled as soon as user clicks on either Yes or No in a particular row, Row-0 or Row-1 or Row-2.
The list of users (refer to images) contains Columns as Full-Name, Row-Index and Choice-Buttons, which are Radio-Buttons.

    When a user clicks on "Yes" for Row-0, then "Save" button on Row-0 should be enabled,
    and "Save" button on Row-1 should remain as disabled.
    
    As a user clicks on Yes/No radio button, a function-call is made at Controller Side, which checks whether the Row-Index of the current row is same as Row-Index mentioned in the Save-button's id, i.e. ```id="{{$index}}-saveBtn"```.
    
    If this match is found, then ```"var controller.isDisable"``` gets marked as false.
    
    However, when user click on Yes/No of the Row-0, then both the Save buttons on Row-0 & Row-1 gets enabled.
    
    Please suggest any correction in this approach or
    any other better way to achieve this use-case.
    
    As you can notice from the attached image, "Save" button's id is dynamic.
    So, Row-0 Save Button has ```id = "0-saveBtn"``` and
    Row-1 Save Button has ```id = "1-saveBtn"```.
    
    Please refer to the images for more clarification.
    [Image-1][1]
    [Image-2][2]
    [Image-3][3]
    [Save-Button][4]
    
    
      [1]: https://i.sstatic.net/Z4olzZam.png
      [2]: https://i.sstatic.net/ZrcT9vmS.png
      [3]: https://i.sstatic.net/pBZzyysf.png
      [4]: https://i.sstatic.net/xFAKySzi.png

Svelte 5 memory leak in simple example

I’m encountering many memory leaks when using both Svelte 4 and 5 on reasonably complex projects, and having trouble identifying what I’m doing wrong.

Here is an extremely simplified Svelte 5 example (adapted from svelte-7GUIs) that seems to present a memory leak.

<script lang="ts">
    class Circle {
        cx: number;
        cy: number;

        constructor(clientX: number, clientY: number) {
            this.cx = +clientX.toFixed();
            this.cy = +clientY.toFixed();
        }
    }
    
    let circles = $state<Circle[]>([]);
    
    function addCircles() {
        for (let i = 0; i < 2; i++) {
            circles.push(new Circle(Math.random() * 600, Math.random() * 400));
        }
    }

    function deleteCircle() {
        circles.shift();
    }
</script>

<div class="space-y">
    <div class="actions flex-center">
        <button onclick={addCircles}>Add 2 Circles</button>
        <button onclick={deleteCircle}>Delete Circle</button>
    </div>

    <svg viewBox="0 0 600 400">
        {#each circles as circle}
            <circle {...circle} r={40} fill="#444"></circle>
        {/each}
    </svg>
</div>

Running the above, I press “Add 2 Circles” once and “Delete Circle” twice. The canvas is clear, but inspecting the heap using Chrome dev tools and I can see that an instance of the Circle class remains.

Repeating the process, these lost instances of Circle continue to accumulate.

Repeat the cycle of adding/deleting 5 times, and 5 Circle instance remain on the heap

In this particular example, if I switch circles.shift() to instead use pop or slice, then the memory leak seems to disappear.

For more complex examples, I’ve also seen similar issues when using SvelteMap instead of a $state([]).

Can anyone explain why this is happening?

Is there a Google reCAPTCHA v3 package compatible with Angular 18?

I’m migrating a project from Angular 11 to Angular 18 and need to integrate Google reCAPTCHA v3.

Previously, I used:

"angular-recaptcha3": "^2.0.0"

Now, I’m trying to use:

"ng-recaptcha": "^13.2.1"

But ng-recaptcha officially supports only up to Angular 17, and I’m currently on Angular 18.2.13.

When I run npm install, I get peer dependency errors because ng-recaptcha expects Angular 17.

As a workaround, I’m using the following in package.json:

"overrides": {
  "ng-recaptcha": {
    "@angular/core": "18.2.13",
    "@angular/common": "18.2.13"
  }
}

While this allows the install to succeed, I’m unsure if this is stable or future-proof.

Is there a reCAPTCHA v3 package that officially supports Angular 18?

Or is there a better workaround to make ng-recaptcha work reliably with Angular 18?

Date format different hosts [closed]

I use php(8.1) and fullcalendar. Everything works as expected. The events are displayed correctly. I can add and edit events too. When I use the exact same setup at another host, it does not display the events. The console error is 404 – not finding the start and end date. It works at one host but not another. There are no errors, no logs. I suspect it is to do with datae format between the different hosts, but I cannot seem to pinpoint it. Here is my code:

<!DOCTYPE html>
<html>

<head>
<link rel="stylesheet" href="fullcalendar/fullcalendar.min.css" />
<script src="fullcalendar/lib/jquery.min.js"></script>
<script src="fullcalendar/lib/moment.min.js"></script>
<script src="fullcalendar/fullcalendar.min.js"></script>

<script>

$(document).ready(function () {
 
      
    var calendar = $('#calendar').fullCalendar({
        
        editable: true,
        events: "fetch-event.php",
        displayEventTime: false,
        eventRender: function (event, element, view) {
            if (event.allDay === 'true') {
                event.allDay = true;
            } else {
                event.allDay = false;
            }
        },
        selectable: true,
        selectHelper: true,
        select: function (start, end, allDay) {
            var title = prompt('Event Title:');

            if (title) {
                var start = $.fullCalendar.formatDate(start, 'YYYY-MM-DD HH:mm');
                var end = $.fullCalendar.formatDate(end, 'YYYY-MM-DD HH:mm');

                $.ajax({
                    url: 'add-event.php',
                    data: 'title=' + title + '&start=' + start + '&end=' + end,
                    type: "POST",
                    success: function (data) {
                        displayMessage("Added Successfully");
                    }
                });
                calendar.fullCalendar('renderEvent',
                        {
                            title: title,
                            start: start,
                            end: end,
                            allDay: allDay
                        },
                true
                        );
            }
            calendar.fullCalendar('unselect');
        },
        
        editable: true,
        eventDrop: function (event, delta) {
                    var start = $.fullCalendar.formatDate(event.start, "YYYY-MM-DD HH:mm");
                    var end = $.fullCalendar.formatDate(event.end, "YYYY-MM-DD HH:mm");
                    $.ajax({
                        url: 'edit-event.php',
                        data: 'title=' + event.title + '&start=' + start + '&end=' + end + '&id=' + event.id,
                        type: "POST",
                        success: function (response) {
                            displayMessage("Updated Successfully");
                        }
                    });
                },
        eventClick: function (event) {
            var deleteMsg = confirm("Do you really want to delete?");
            if (deleteMsg) {
                $.ajax({
                    type: "POST",
                    url: "delete-event.php",
                    data: "&id=" + event.id,
                    success: function (response) {
                        if(parseInt(response) > 0) {
                            $('#calendar').fullCalendar('removeEvents', event.id);
                            displayMessage("Deleted Successfully");
                        }
                    }
                });
            }
        }

    });
});

function displayMessage(message) {
        $(".response").html("<div class='success'>"+message+"</div>");
    setInterval(function() { $(".success").fadeOut(); }, 4000);
}
</script>

<style>
body {
    margin-top: 50px;
    text-align: left;
    font-size: 12px;
    font-family: "Lucida Grande", Helvetica, Arial, Verdana, sans-serif;
}

#calendar {
    width: 900px;
    margin: 0 auto;
}

.response {
    height: 60px;
}

.success {
    background: #cdf3cd;
    padding: 10px 60px;
    border: #c3e6c3 1px solid;
    display: inline-block;
}
</style>
</head>
<body>
    <h2>Basic Calendar Demo - no GUI.</h2>
        <ul>
            <li>Click date to add event.</li>
            <li>Click-and-drag for multiple days</li>
        </ul>
    <div class="response"></div>
    <div id='calendar'></div>
</body>


</html>

It works correctly at one host, but not at another.

cannot go into admin side of website anymore

i manage a website for a local youth organization and am suddenly not allow to enter the admin page anymore for some reason. i didnt build the website myself, but have taken over from the former person who managed it earlier this year. normally i’d log in to the admin page by simply adding “/admin” after the normal url, but all of a sudden when i do this it gives me an error instead of going to the wordpress login page.
Image of the error

after looking online for a bit i saw that it was probably the .htacces file. i havent changed anything to it so i doubt its the problem, also dont really see anything in there that would lock me out.

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress

I’ve also tried disabling cache, changing browsers and using incognito mode but none of these worked.

After all of this i asked help from one of my friends who is a bit better with this stuff than me, but for some reason he didnt get the error when he tried it on his pc. So after that i tried doing it on my phone using mobile data, but this also went straight to the error page.

Is it possible that somehow my phone and computer got locked out? how would this happen and can it be fixed?

PHP connect to hidden share network path

I’m trying to connect to a hidden network drive using ftp_connect, but I’m getting an error message when I try ftp_login.
Is this even possible with PHP?
Thank you!

$ftp_server = 'server02.abc.def.com/c$';
$ftp_user = 'abc/name.user';
$ftp_pass = 'userpwd123';

// set up a connection or die
$ftp = ftp_connect($ftp_server) or die("Couldn't connect to $ftp_server");

// try to login
if (@ftp_login($ftp, $ftp_user, $ftp_pass)) {
echo "Connected as $ftp_user@$ftp_servern";
} else {
 echo "Couldn't connect as $ftp_usern";
}

// close the connection
ftp_close($ftp);

In WooCommerce product reviews the comment is not automatically marked as approved

Issue:
In WooCommerce product reviews, when an admin replies to a comment, the comment is not automatically marked as approved, unlike regular WordPress posts. The comment remains colored (indicating it is unapproved) even after approval, and the admin has to refresh the page to see the changes.

What I’m looking for:
A solution that automatically marks the parent comment as approved (and removes the “unapproved” color) when an admin replies to it in the WooCommerce product reviews section, without the need for a page refresh

Why does each call to this socket server give a unique list of peers?

I’m trying to create a kind of signalling server. What I’m attempting to do is allow socket connections and respond to 'helo' with a list of already connected peers:

<?php

use SwooleWebSocketServer;

$host = '0.0.0.0';
$port = 9090;

$server = new Server($host, $port, SWOOLE_PROCESS, SWOOLE_SOCK_TCP);

$connectedPeers = [];

function get_request_key($request) {
    return $request->server['remote_addr'] . ':' . (string)$request->server['remote_port'];
}

$server->on('open', function (Server $server, $request) use(&$connectedPeers) {
    echo "New connection: #{$request->fd}n";
    $connectedPeers[] = get_request_key($request);
    echo var_dump($connectedPeers);
});

$server->on('message', function (Server $server, $frame) use(&$connectedPeers) {
    echo "Received from #{$frame->fd}: {$frame->data}n";
   // echo var_dump($frame);
    $msg = $frame->data;

    if($msg === 'helo'){
        /* in this instance, reply with a list of peers */
        $server->push($frame->fd, '{"type":"peers", "peers":' . json_encode($connectedPeers) . '}');
    }
    else
    // Broadcast message to all connected clients
    foreach ($server->connections as $fd) {
        if ($fd !== $frame->fd) {
            $server->push($fd, $msg);
        }
    }
});

$server->on('close', function (Server $server, $fd) {
    echo "Connection #{$fd} closedn";
});

echo "WebSocket Secure Server started on wss://$host:$portn";
$server->start();
?>

The problem is that if I run this with php server.php, and then connect with two different clients, the response to each is a unique list of peers.

I.e. Client A gets a list with just itself. Client B gets a list with just itself. Client A and B never see each other.

I’m sure it has to do with reference/copy of $connectedPeers but I’m very new to PHP and don’t really understand how lifetime works in this instance.

How to implement my web app’s back button?

Let’s say we have a web app with the following structure:

- news feed page
- articles list page
-- article details page

On the article details page, in the top-left corner, there is a back button. The problem?

  1. If the user navigates news feed > article details, then the back button should lead back to the news feed page.

  2. But if the user navigates articles list > article details, then the back button should lead back to the articles list page.

  3. Lastly, if the user arrives at the article details page from an external link, the back button should lead to the articles list page.

So basically, I want it to be like a navigation stack, like a mobile app, but with an optional default. And ideally, I don’t want to have to hardcode all of the above cases for each page. Plus, the browser’s back button should trigger my custom back behaviour.

I’m using Next.js with app router.

How can I reset createResource() .error to null?

I want to implement a refetch function manually when user clicked the button.

Currently whenever I got an error from API, I’m showing a toast when the error appear, now I want to add “Retry” button next to a toast message and disappear after 3 second, the problem is toast component always show because of <Show when={data.error}/>

import { render } from "solid-js/web";
import { Show, createResource } from "solid-js";

const fetcher = async () => {
  await new Promise((resolve) => setTimeout(resolve, 3000));
  throw new Error("Something went wrong");
};

function App() {
  const [data] = createResource(fetcher);

  return (
    <div>
      <p>HELLO WORLD</p>
      <Show when={data.error}>
        <p>{data.error.message}| try again</p>
      </Show>
    </div>
  );
}

render(() => <App />, document.getElementById("app")!);

Playground

How do I reset the .error value to null manually? I don’t want to show Toast forever until refetch resolve.

Why my audio is nuted while capturing in chrome extension?

PROBLEM : I am trying to capture the audio for my chrome extension but it is muting the audio for the user.

WHAT I WANT : I want the audio should be available for both the user(speaker output) and for my extension for processing.

I have tried most of the methods none working for me you may also try I might be missing something. I would really appreciate your help.

NOTE: You can reproduce the same below is the complete code.

//manifest.json

{
    "name": "Audio Capture Test",
    "description": "Records tab audio with transcription.",
    "version": "1",
    "manifest_version": 3,
    "minimum_chrome_version": "116",
    "background": {
        "service_worker": "service-worker.js",
        "type": "module"
    },
    "action": {
        "default_popup": "popup.html",
        "default_title": "Capture Audio"
    },
    "permissions": [
        "tabCapture",
        "activeTab",
        "scripting"
    ],
    "host_permissions": [
        "http://*/*",
        "https://*/*"
    ]
}

//popup.js

document.getElementById("startCapture").addEventListener("click", async () => {
    const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });

    if (tab) {
        alert("start recording called")
        chrome.runtime.sendMessage({ type: "start-recording", tabId: tab.id });
    }
});


chrome.runtime.onMessage.addListener(async (message, sender, sendResponse) => {
    if (message.type === 'message') {
        alert(message.mes)
    }
})

//service-worker.js

chrome.runtime.onMessage.addListener(async (message, sender, sendResponse) => {
    if (message.type === "start-recording") {
        try {
            console.log("Requesting tab media stream...");
            const streamId = await chrome.tabCapture.getMediaStreamId({
                consumerTabId: message.tabId
            });

            console.log("Stream ID received:", streamId);

            // Inject content script
            await chrome.scripting.executeScript({
                target: { tabId: message.tabId },
                files: ["content.js"]
            });

            // Send stream ID to content script
            await chrome.tabs.sendMessage(message.tabId, {
                type: "process-stream",
                streamId: streamId
            });

        } catch (error) {
            console.error("Error starting tab capture:", error);
        }
    }
});

//content.js

chrome.runtime.onMessage.addListener(async (message, sender, sendResponse) => {
    if (message.type === 'process-stream') {
        try {
            const audioContext = new AudioContext({
                sampleRate: 48000,
                latencyHint: 'interactive'
            });

            // Get tab audio stream
            let tabStream = await navigator.mediaDevices.getUserMedia({
                audio: {
                    mandatory: {
                        chromeMediaSource: 'tab',
                        chromeMediaSourceId: message.streamId
                    }
                },
                video: false
            });

            chrome.runtime.sendMessage({ type: "message", mes: "starting hte capture" });

            // Load the AudioWorklet Processor
            await audioContext.audioWorklet.addModule("processor.js");

            const audioProcessor = new AudioWorkletNode(audioContext, "audio-processor");
            const source = audioContext.createMediaStreamSource(tabStream);

            source.connect(audioProcessor).connect(audioContext.destination);

        } catch (error) {
            console.error("Error capturing audio:", error.message || error);
        }
    }
    return true;
});

//processor.js

class AudioProcessor extends AudioWorkletProcessor {
    process(inputs, outputs, parameters) {
      const input = inputs[0];
      const output = outputs[0];

      if (input.length > 0) {
        for (let channel = 0; channel < input.length; channel++) {
          output[channel].set(input[channel]); // Forward audio to keep it audible
        }
      }

      return true; // Keep the processor running
    }
}

registerProcessor('audio-processor', AudioProcessor);

// popup.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Audio Capture</title>
    <link rel="stylesheet" href="popup.css">
</head>
<body>
    <button id="startCapture">Start Capture</button>
    <script src="popup.js"></script>
</body>
</html>

Checkboxes to select/check groups of checkboxes with Javascript

i have a form with a table in and each row has a checkbox. The n-rows show potentialy 3 types of entries (fruit/meat/vegetable). What i like to provide is 4 more Check Boxes on top of the Table so the user can

  1. check/select all rows,
  2. The fruit rows
  3. The meat rows
  4. The vegetable rows
    It should be possible to check/select fruit and meat (for example).
    I find code for Check/uncheck all rows but i am lost with check/select “groups” of rows.
    Any ideas?
    Many thanks in advice!
<FORM name="sel" action="nextpage.html" method=post>
  <table border="0" cellpadding="0" cellspacing="0" width="210px">
    <thead>
      <tr>
        <th with=50px></th>
        <th with=80px>NAME</th>
        <th with=80px>TYPE</th>
      </tr>
    </thead>
    <tbody>
      <TR>
        <TD with=50px><input type="checkbox" name="target[]" id="target" value="Banana;fruit" /> <label for="target"></label></td>
        <TD with=80px>Banana</TD>
        <TD with=80px>fruit</TD>
      <TR>
      <TR>
        <TD with=50px><input type="checkbox" name="target[]" id="target" value="Steak;meat" /> <label for="target"></label></td>
        <TD with=80px>Steak</TD>
        <TD with=80px>meat</TD>
      <TR>
      <TR>
        <TD with=50px><input type="checkbox" name="target[]" id="target" value="Apple;fruit" /> <label for="target"></label></td>
        <TD with=80px>Apple</TD>
        <TD with=80px>fruit</TD>
      <TR>
      <TR>
        <TD with=50px><input type="checkbox" name="target[]" id="target" value="Chicken breast;meat" /> <label for="target"></label></td>
        <TD with=80px>Chicken breast</TD>
        <TD with=80px>meat</TD>
      <TR>
      <TR>
        <TD with=50px><input type="checkbox" name="target[]" id="target" value="Potato;vegetable" /> <label for="target"></label></td>
        <TD with=80px>Potato</TD>
        <TD with=80px>vegetable</TD>
      <TR>
      <TR>
        <TD with=50px><input type="checkbox" name="target[]" id="target" value="Onion;vegetable" /> <label for="target"></label></td>
        <TD with=80px>Onion</TD>
        <TD with=80px>vegetable</TD>
      <TR>
      <TR>
        <TD with=50px><input type="checkbox" name="target[]" id="target" value="pineapple;fruit" /> <label for="target"></label></td>
        <TD with=80px>Pineapple</TD>
        <TD with=80px>fruit</TD>
      <TR>
    </tbody>
  </table>
  </div>
  <BR />
  <BUTTON TYPE="SUBMIT" VALUE='Weiter!' />Weiter</BUTTON>
</FORM>