How to make media recorder api individual chunks playable by it self

I’m trying to send individual chunks to the server instead of sending the whole chunks at once. This way, I have Ffmpeg on my Rails server to convert these chunks to HLS and upload them to S3 to stream the video instantly. However, I’ve encountered an issue the Media Recorder only provides playable chunks for the first segment after that, they are not playable and need to be concatenated to play.

To avoid this, I’ve taken a different approach where I start a new Media Recorder every 3 seconds so that I get a playable chunk every time. However, this approach has its issues the video glitches a bit due to the delay when I stop and start a new Media Recorder. Is there a way to achieve this with ease? This is my current status. please help!

const startVideoRecording = async (
    screenStream: MediaStream,
    audioStream: MediaStream
  ) => {
    setStartingRecording(true);

    try {
      const res = await getVideoId();
      videoId.current = res;
    } catch (error) {
      console.log(error);
      return;
    }

    const outputStream = new MediaStream();
    outputStream.addTrack(screenStream.getVideoTracks()[0]);
    outputStream.addTrack(audioStream.getAudioTracks()[0]); // Add audio track

    const mimeTypes = [
      "video/webm;codecs=h264",
      "video/webm;codecs=vp9",
      "video/webm;codecs=vp8",
      "video/webm",
      "video/mp4",
    ];

    let selectedMimeType = "";
    for (const mimeType of mimeTypes) {
      if (MediaRecorder.isTypeSupported(mimeType)) {
        selectedMimeType = mimeType;
        break;
      }
    }

    if (!selectedMimeType) {
      console.error("No supported mime type found");
      return;
    }

    const videoRecorderOptions = {
      mimeType: selectedMimeType,
    };

    let chunkIndex = 0;

    const startNewRecording = () => {
      // Stop the current recorder if it's running
      if (
        videoRecorderRef.current &&
        videoRecorderRef.current.state === "recording"
      ) {
        videoRecorderRef.current.stop();
      }

      // Create a new MediaRecorder instance
      const newVideoRecorder = new MediaRecorder(
        outputStream,
        videoRecorderOptions
      );
      videoRecorderRef.current = newVideoRecorder;

      newVideoRecorder.ondataavailable = async (event) => {
        if (event.data.size > 0) {
          chunkIndex++;
          totalSegments.current++;
          const segmentIndex = totalSegments.current;
          console.log(event.data);
          handleUpload({ segmentIndex, chunk: event.data });
        }
      };

      // Start recording with a 3-second interval
      newVideoRecorder.start();
    };

    // Start the first recording
    startNewRecording();

    // Set up an interval to restart the recording every 3 seconds
    recordingIntervalIdRef.current = setInterval(() => {
      startNewRecording();
    }, 3000);

    setIsRecording(true);
    setStartingRecording(false);
  };

Impossible to delete 2 cookies at the same time

I have 2 cookies named : access_token and refresh_token.

I can’t delete these 2 cookies at the same time by:

const logout = (req, res) => { 
    res.clearCookie('access_token', { path: '/' });
    res.clearCookie('refresh_token', { path: '/' });
    return res.status(200).json({
        EM: "logout success",
        EC: 1,
        DT: "",
    });
}

But when I only have 1 cookie, I can still clear it by using clearCookie() method.

I want to delete all cookies in 1 action.

How can I do it? or any suggest please!! Thanks.

Mapbox Geocoder on Safari

The following snippet works perfectly on Chrome displaying a search bar to autofill address results. Unfortunately Safari (17.5 in my case) does not recognize .on method on mapboxGeocoder object. Is there a solution ? (Working in a Rails 7 app using Stimulus controller)

  initMapboxAutofill() {

    mapboxgl.accessToken = window.mapboxAccessToken;

    this.mapboxGeocoder = new MapboxGeocoder({
      accessToken: mapboxgl.accessToken,
      mapboxgl: mapboxgl,
      marker: false,
      autocomplete: true,
      placeholder: 'Search for an address',
    });

    if (this.hasGeocoderAutocompleteTarget) {
      this.geocoderAutocompleteTarget.appendChild(this.mapboxGeocoder.onAdd());

      if (typeof this.mapboxGeocoder.on === 'function') {
        this.mapboxGeocoder.on('result', (event) => {
          const { geometry } = event.result;
          this.populateAddressFields(event);
      
          const coordinates = geometry.coordinates;
          this.displayStaticMap(coordinates);
        });
      } else {
        console.error('Mapbox Geocoder "on" method is not available.'); //Safari flow
      }
    } else {
      this.initStaticMapForExistingHome();
    }
  }
    <script src="https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-geocoder/v5.0.0/mapbox-gl-geocoder.min.js"></script>
    <script id="search-js" defer src="https://api.mapbox.com/search-js/v1.0.0-beta.21/web.js"></script>
    <script src="https://api.mapbox.com/mapbox-gl-js/v3.5.1/mapbox-gl.js"></script>

Isn’t the size of an inline element determined by the size of its child elements?

I’m a beginner.

What I’m curious about is the size of an inline element.

I’ve heard that the size of an inline is determined by the content of the inline element or the size of its child element.

The container(span) doesn’t have the same size as the canvas.

When I checked with the dev tool, the height of the span was only 21px and the size of the canvas was 400px.

I thought the container would take up the same size as its child element, canvas.

What’s wrong?

<body>
    <span class="container">
        <canvas id="screen"></canvas>
    </span>
    <script src="index.js"></script>
</body>
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body {
    background-color: wheat;
    height: 100vh;
    min-height: 100vh;
}
.container {

    position: relative;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
}
#screen {
    position: relative;
    border: 3px solid white;
}
const canvas = document.querySelector("canvas");

canvas.style.width = "600px";
canvas.style.height = "400px";

DiscordAPIError[10062]: Unknown interaction randomly popped up

I’m trying to make a discord bot. for a skyblock server, using the commands it will show for example farming level, etc. this code use to work just fine, the next day when I started it I got this error following. Note: it only breaks in the Farming function that I created I did a dungeon’s functions and slash command and it worked just fine.

Error : DiscordAPIError[10062]: Unknown interaction at handleErrors (C:Usersyy3OneDriveDisktopSkyblockbotnode_modules@discordjsrestdistindex.js:730:13) at process.processTicksAndRejections (node:internal/process/task_queues:95:5) at async BurstHandler.runRequest (C:Usersyy3OneDriveDisktopSkyblockbotnode_modules@discordjsrestdistindex.js:835:23) at async _REST.request (C:Usersyy3OneDriveDisktopSkyblockbotnode_modules@discordjsrestdistindex.js:1278:22) at async ChatInputCommandInteraction.deferReply (C:Usersyy3OneDriveDisktopSkyblockbotnode_modulesdiscord.jssrcstructuresinterfacesInteractionResponses.js:71:5) at async Client.<anonymous> (C:Usersyy3OneDriveDisktopSkyblockbotsrcindex.js:307:9) Emitted 'error' event on Client instance at: at emitUnhandledRejectionOrErr (node:events:402:10) at process.processTicksAndRejections (node:internal/process/task_queues:84:21) { requestBody: { files: undefined, json: { type: 5, data: { flags: undefined } } }, rawError: { message: 'Unknown interaction', code: 10062 }, code: 10062, status: 404, method: 'POST', url: 'https://discord.com/api/v10/interactions/1271726598881804370/aW50ZXJhY3Rpb246MTI3MTcyNjU5ODg4MTgwNDM3MDpoRFlWN1hwODUxVGNLY21lRnk1NWh4UEVOT0tYQllLblZZR0Z5WXJ0eHdZSExiVUlDR0w0Qmc1ak5uUjRvZ3p2a2xpVzRDd3RNb0hDODFlUFhwWVVQNGZOSURGQjlGNnBVMzVlbEpkZzl4MHZLU1VXSVhQT01iUkl3NHd1c1JGRg/callback' }

require('dotenv').config();
const { UserFlags } = require('discord-api-types/v9');
const {Client, GatewayIntentBits, EmbedBuilder, PermissionsBitField, Permissions, SlashCommandBuilder, Events} = require('discord.js');
const { MongoClient } = require('mongodb');


const uri = "mongodb://localhost:27017/";
const dbName = "skyblock";
const collectionUsers = "profiles";

const mongoclient = new MongoClient(uri, { useNewURLParser: true, useUnifiedTopology: true });


// Connecting-Reading Database Collections.
mongoclient.connect()
    .then(() => {
        console.log('Connected to MongoDB');

        const db = mongoclient.db(dbName);

        return db.listCollections().toArray();
    })
    .then(collections => {
        let count = 0
        console.log('Collections in database:');
        collections.forEach(collection => {
            count = count + 1
        });
        console.log(`${count} Collections Loaded`)
    });




const client = new Client({
    intents: [
        GatewayIntentBits.Guilds,
        GatewayIntentBits.GuildMessages,
        GatewayIntentBits.MessageContent
    ]
});


function Mapping(n, mapping) {
    let count = 0;
    for (let i = 0; i < mapping.length; i++) {
        n -= mapping[i];
        if (n < 0) {
            return count;
        }
        count = i + 1;
    }
    return count;
}

function capitalizeUsername(username) {
    if (!username) return ''; // Handle empty or undefined input
    return username.charAt(0).toUpperCase() + username.slice(1).toLowerCase();
}

function catchFarmingMapping(Level) {

    farmingMapping = [50, 125, 200, 300, 500, 750, 1000, 1500, 2000, 3500, 5000, 7500, 10000, 15000, 20000, 30000, 50000, 75000, 100000, 200000, 300000, 400000, 500000, 600000, 700000, 800000, 900000, 1000000, 1100000, 1200000, 1300000, 1400000, 1500000, 1600000, 1700000, 1800000, 1900000, 2000000, 2100000, 2200000, 2300000, 2400000, 2500000, 2600000, 2750000, 2900000, 3100000, 3400000, 3700000, 4000000, 4300000, 4600000, 4900000, 5200000, 5500000, 5800000, 6100000, 6400000, 6700000, 7000000];

    const Farming = Mapping(Level, farmingMapping);
    console.log(Farming)
    return Farming;
}

function catchCatacombMapping(Level) {

    dungeonmapping = [ 50, 75, 110, 160, 230, 330, 470, 670, 950, 1340, 1890, 2665, 3760, 5260, 7380, 10300, 14400, 20000, 27600, 38000, 52500, 71500, 97000, 132000, 180000, 243000, 328000, 445000, 600000, 800000, 1065000, 1410000, 1900000, 2500000, 3300000, 4300000, 5600000, 7200000, 9200000, 12000000, 15000000, 19000000, 24000000, 30000000, 38000000, 48000000, 60000000, 75000000, 93000000, 116250000 ]

    const Catacomb = Mapping(Level, dungeonmapping);
    console.log(Catacomb);
    return Catacomb;
}

async function catchDungeonLevel(User) {
    const database = mongoclient.db('skyblock');
    const usersCollection = database.collection('users');
    const profileMemCollection = database.collection('profile_members');

    const user = await usersCollection.findOne({ lowercase_name: User });

    if (!user) {
        console.log('User not found');
        return null;
    }

    const activeProfile = user.active_profile;
    console.log('Active Profile:', activeProfile);

    const profile = await profileMemCollection.findOne({ profile_id: activeProfile });

    if (!profile) {
        console.log('Profile not found');
        return null;
    }

    const CatacombExperience = profile.data?.dungeons?.dungeon_types?.CATACOMBS?.experience;

    console.log(CatacombExperience);

    if (CatacombExperience !== undefined) {
        const DungeonLevel = Math.floor(CatacombExperience);
        return DungeonLevel;
    } else {
        console.log('Farming experience not found');
        return null;
    }
}

async function catchFarmingMedals(User) {

    const database = mongoclient.db('skyblock');
    const usersCollection = database.collection('users');
    const profileMemCollection = database.collection('profile_members');

    const filter = { lowercase_name: User };
    const user = await usersCollection.findOne(filter);

    console.log(filter)
    activeProfile = user.active_profile
    console.log(activeProfile)

    if (User) {

        const filter = { profile_id: activeProfile };
        const Profile = await profileMemCollection.findOne(filter);
        
        if (Profile) {
            Gold = Profile.data?.farming?.gold
            Silver = Profile.data?.farming?.silver
            Bronze = Profile.data?.farming?.bronze

            console.log(`Gold ${Gold}, Silver ${Silver}, Bronze ${Bronze}`)
        }
    }

}

async function catchFarmingLevel(User) {
    const database = mongoclient.db('skyblock');
    const usersCollection = database.collection('users');
    const profileMemCollection = database.collection('profile_members');

    const user = await usersCollection.findOne({ lowercase_name: User });

    if (!user) {
        console.log('User not found');
        return null;
    }

    const activeProfile = user.active_profile;
    console.log('Active Profile:', activeProfile);

    const profile = await profileMemCollection.findOne({ profile_id: activeProfile });

    if (!profile) {
        console.log('Profile not found');
        return null;
    }

    const farmingExperience = profile.data?.experience_skill_farming;

    if (farmingExperience !== undefined) {
        const farmingLevel = Math.floor(farmingExperience);
        return farmingLevel;
    } else {
        console.log('Farming experience not found');
        return null;
    }
}

async function catchFarmingContests(User) {

    const database = mongoclient.db('skyblock');
    const usersCollection = database.collection('users');
    const profileMemCollection = database.collection('profile_members');

    const filter = { lowercase_name: User };
    const user = await usersCollection.findOne(filter);

    console.log(filter)
    activeProfile = user.active_profile
    console.log(activeProfile)

    if (User) {

        const filter = { profile_id: activeProfile };
        const Profile = await profileMemCollection.findOne(filter);
        
        if (Profile) {
            Contests = Profile.data?.farming?.contests;

            if (Profile.data?.farming?.contests && typeof Profile.data?.farming?.contests === 'object') {
                const numberOfContests = Object.keys(Profile.data?.farming?.contests).length;
                console.log(`Number of contests: ${numberOfContests}`);
                return numberOfContests;
            } else {
                console.log('Contests data is either undefined or not an object');
                return null;
            }
        }
    }

}

client.on(Events.ClientReady, (e) => {
    console.log(`✅ ${e.user.tag} is ready!`);

    const farming = new SlashCommandBuilder()
    .setName ('farming')
    .setDescription ('View a players farming statistics!')
    .addStringOption(option =>
        option
        .setName('username')
        .setDescription('Minecraft Username')
        .setRequired(true)
    )

    const support = new SlashCommandBuilder()
    .setName ('support')
    .setDescription ('Supporting fakepixel')

    const dungeons = new SlashCommandBuilder()
    .setName ('dungeons')
    .setDescription ('View dungeon stats')
    .addStringOption(option =>
        option
        .setName('username')
        .setDescription('Minecraft Username')
        .setRequired(true)
    )

    client.application.commands.create(farming);
    client.application.commands.create(support);
    client.application.commands.create(dungeons);

});

client.on('interactionCreate', async (interaction) => {
    if(!interaction.isChatInputCommand()) return;

    if(interaction.commandName==='dungeons') {
        const username = interaction.options.getString('username');

        if(username) {
            const Username = username
            const username_lowercase = Username.toLowerCase();

            try {

                const FetchDungeonExperience = await catchDungeonLevel(username_lowercase);
                const FetchDungeonLevel = await catchCatacombMapping(FetchDungeonExperience);
                console.log(FetchDungeonExperience);
                console.log(FetchDungeonLevel);

                interaction.reply(`Catacomb :${FetchDungeonLevel}`);

            } catch (error) {

                console.error('Error handling Dungeons command:', error);
                interaction.reply('Please provide a valid username to fetch Dungeons details.');

            }
        }

    } else {
        interaction.reply('Please provide a valid username to fetch farming details.');
    }
})


client.on('interactionCreate', async (interaction) => {
    if(!interaction.isChatInputCommand()) return;

    if(interaction.commandName==='support') {

        const supportEmbed = new EmbedBuilder()
        .setTitle(`Fakepixel Support`)
        .setDescription(`Fakepixel is a thriving Minecraft server that thrives on the support of its community. By supporting Fakepixel, you help keep the server running and enable us to continually provide exciting updates and new features. As a token of our gratitude, supporters receive a range of exclusive perks that enhance your in-game experience.`)
        .setColor('#347deb')
        .addFields({
            name: 'Features:',
            value: `• **Cool Prefix & Chat Customization** - Stand out with a unique prefix and a custom chat color.
            • **Custom Commands** - Gain access to special command like /fly, /vanish to enhance your gameplay.
            • **Support the Server** - Show your dedication and help Fakepixel grow stronger.
            • **Discord Perks** - Share media files in the Discord server and connect with the community.
            • **Exclusive Beta Tester Access** - Be among the first to try out new features and content before anyone else.
            `,
            inline: true
        })
        .setImage('https://i.imgur.com/8ObuWiL.png')
        .setFooter({text: 'by @Dyamonic', iconURL: 'https://i.imgur.com/dVdkH9y.gif'})

        interaction.reply({embeds: [supportEmbed]});
    }
})


client.on('interactionCreate', async (interaction) => {
    if(!interaction.isChatInputCommand()) return;

    if(interaction.commandName==='farming') {
        await interaction.deferReply({})
        const username = interaction.options.getString('username');

        if(username) {
            const username_lowercase = username.toLowerCase();
            const Username_Capitial = capitalizeUsername(Username);

            try {

            const FetchFarmingLevel = await catchFarmingLevel(username_lowercase);
            const FetchFarmingMapping = await catchFarmingMapping(FetchFarmingLevel);
            const FetchFarmingMedals = await catchFarmingMedals(username_lowercase);
            const FetchFarmingContests = await catchFarmingContests(username_lowercase);


            await interaction.editReply(`
                Username : ${Username_Capitial}
                Farming : ${FetchFarmingMapping}
                Gold : ${Gold}
                Silver : ${Silver}
                Bronze : ${Bronze}
                Contests : ${FetchFarmingContests}`);

            //const farmingEmbed = new EmbedBuilder()
            //.setTitle(`${Username_Capitial}'s Farming Skill on Profile`)
            //.setDescription(`<:Iron_hoe:1268545041735876704> Farming: **${FetchFarmingMapping}**
            //    <:Farming_Contest:1268545029509742623> Contests: **${FetchFarmingContests}**`)
            //.setColor('#347deb')
            //.setThumbnail(`https://visage.surgeplay.com/full/${username_lowercase}`)
            //.addFields({
            //    name: 'Medals',
            //    value: `<:Gold_Ingot:1268544990510972949> Gold: ${Gold}
            //    <:Iron_Ingot:1268545007422275645>  Silver: ${Silver}
            //    <:Clay_Brick:1268545018688180276> Bronze: ${Bronze}`,
            //    inline: true
            //})
            //.setFooter({text: 'by @Dyamonic | Support by using /support', iconURL: 'https://i.imgur.com/dVdkH9y.gif'})
    
            //interaction.reply({embeds: [farmingEmbed]});

            } catch (error) {

                console.error('Error handling farming command:', error);
                interaction.reply('Please provide a valid username to fetch farming details.');

            }

        }
        else {
            interaction.reply('Please provide a valid username to fetch farming details.');
        }
    }
})

client.login(process.env.TOKEN);

How to hide an already open browser in Puppeter?

You need to open the browser and close it after 3 seconds

const browser = await (require('puppeteer')).launch({headless: false, defaultViewport: null,args: ['--start-maximized'] });
const page = await browser.newPage();
//
page.goto('https://web.telegram.org/a/', {timeout: -1});
//
setTimeout(() => {
    console.log('how to hide browser?')
}, 3000);

I already know how to initially launch it with a hidden browser. But the problem is that I need to close it after a while

Livewire action restricting 3rd part plugin intialization

i’m using a 3rd party scrollbar plugin (smooth-scrollbar) in my php code and it is working fine when loading page, after any livewire click or action happened (like pagination or sorting) inside a table happened suddenly the scrollbar plugin content is getting removed. Any idea what is the issue behind this. Any fix for that?

function scrollInitialize() {
    var elements = document.getElementsByClassName('scroll');
    for (var i = 0; i < elements.length; i++) {
        var scrollbar = Scrollbar.init(elements[i], {
            damping: 0.5, // Set damping to 0.5
            renderByPixels: true, // Render scrollbars by pixels
            continuousScrolling: true, // Enable continuous scrolling
            alwaysShowTracks: true
        });

        
    }
}

function init() {
    // ========================================================
    // Condition based on screen width
    // ========================================================
    if (mq.matches) {
        
        // ========================================================
        // Smooth Scrollbar
        // ========================================================

        // Initialize Smooth Scrollbar for all elements with the class 'scroll'
        scrollInitialize();

    }
}

This is the initilization code

HTML Code:

<div class="table-responsive scroll">
     <table class="cs-table table caption-top main-listing" id="dropdown-options-table"></table>
</div>

Google Apps Script Error: ‘Script function onSubmitOpening could not be found’ Despite Correct Setup

I am working on a little project for a restaurant, where I am using Chat GPT to write a code for an opening and closing task list on Google Apps Script. I have a submit button on the sheet triggers notification, my code on the “employer” side are as follow. The code works fine on the “employer side”, where I can get notif and stuff, but when I use a dummy account to be an “employee”, it states “Script function onSubmitOpening could not be found”. What’s wrong with the code?

Error Message
Excel structure

`
function onSubmitOpening() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(“Opening”);

  // Define the range for the "CHECK" and "INITIALS" columns
  var checkColIndex = 3; // Index for the "CHECK" column (assuming it's the 5th column)
  var initialsColIndex = 4; // Index for the "INITIALS" column (assuming it's the 6th column)
  var itemColIndex = 1; // Index for the "ITEM" column (assuming it's the 2nd column)

  // Find the cell next to "Submitted by:"
  var submittedByRange = sheet.createTextFinder("Submitted by:").findNext();
  if (!submittedByRange) {
    SpreadsheetApp.getUi().alert("Could not find the 'Submitted by:' cell.");
    return;
  }
  var submittedByName = sheet.getRange(submittedByRange.getRow(), submittedByRange.getColumn() + 1).getValue().toString().trim();

  // Check completion and notify
  checkCompletionAndNotify(sheet, itemColIndex, checkColIndex, initialsColIndex, "Opening Checklist", submittedByName);

  // Protect the sheet, allowing only "CHECK" and "INITIALS" columns to be edited
  protectSheet(sheet, checkColIndex, initialsColIndex);
}

function checkCompletionAndNotify(sheet, itemColIndex, checkColIndex, initialsColIndex, sheetName, submittedByName) {
  var dataRange = sheet.getDataRange();
  var data = dataRange.getValues();
  var incompleteTasks = [];
  var allTasksCompleted = true;

  // Ensure that all "CHECK" and "INITIALS" columns are filled only for rows where ITEM exists
  for (var i = 2; i < data.length; i++) { // Start from row 3 (index 2)
    var itemValue = (data[i][itemColIndex] || "").toString().trim();
    var checkValue = (data[i][checkColIndex] || "").toString().trim().toLowerCase();
    var initialsValue = (data[i][initialsColIndex] || "").toString().trim();

    // Skip rows where ITEM is empty
    if (itemValue === "") {
      Logger.log("Row " + (i + 1) + " skipped because ITEM is empty.");
      continue;
    }

    // Log the values being checked
    Logger.log("Row " + (i + 1) + " - ITEM: " + itemValue + ", CHECK: " + checkValue + ", INITIALS: " + initialsValue);

    if (checkValue === "" || initialsValue === "") {
      allTasksCompleted = false;
      SpreadsheetApp.getUi().alert("Please complete all required fields then submit.");
      return;
    }

    if (checkValue !== "yes") {
      incompleteTasks.push(itemValue); // Use itemValue directly for logging incomplete tasks
      allTasksCompleted = false;
    }
  }

  // Send an email notification and generate a PDF based on the completion status
  var emailAddress = "[email protected]";
  var now = new Date();
  var year = now.getFullYear();
  var month = now.getMonth() + 1;
  var day = now.getDate();
  var hour = now.getHours();
  var minute = now.getMinutes();

  var emailSubject = sheetName + " Submission Notification";
  var emailBody;

  if (allTasksCompleted) {
    emailBody = "All the items have been successfully submitted at " + year + "/" + month + "/" + day + " at " + hour + ":" + minute + " by " + submittedByName;
  } else {
    // Format incomplete tasks as a list, each item on a new line
    var itemList = incompleteTasks.map(function(task) {
      return task;
    }).join("n");

    emailBody = "Good day! Kindly find attached the " + sheetName + " report, submitted at " + year + "/" + month + "/" + day + " at " + hour + ":" + minute + ". The following items in the " + sheetName + " still need to be completed by " + submittedByName + ":n" + itemList;
  }

  // Generate the PDF
  var pdfBlob = createPDF(sheet);

  // Send the email with the attached PDF
  MailApp.sendEmail({
    to: emailAddress,
    subject: emailSubject,
    body: emailBody,
    attachments: [pdfBlob]
  });

  // Clear the "CHECK" and "INITIALS" columns after submission, leaving the headings intact
  clearColumns(sheet, checkColIndex, initialsColIndex);
}

function createPDF(sheet) {
  var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  var sheetId = sheet.getSheetId();
  var url = "https://docs.google.com/spreadsheets/d/" + spreadsheet.getId() + "/export?format=pdf&size=A4&portrait=true&sheetnames=false&printtitle=false&pagenumbers=false&gridlines=true&fzr=false&gid=" + sheetId;

  var token = ScriptApp.getOAuthToken();
  var response = UrlFetchApp.fetch(url, {
    headers: {
      'Authorization': 'Bearer ' + token
    }
  });

  return response.getBlob().setName(sheet.getName() + ".pdf");
}

function clearColumns(sheet, checkColIndex, initialsColIndex) {
  var lastRow = sheet.getLastRow();
  sheet.getRange(3, checkColIndex + 1, lastRow - 2, 2).clearContent(); // Clears "CHECK" and "INITIALS" columns from row 3 downwards
}

function protectSheet(sheet, checkColIndex, initialsColIndex) {
  // Protect the entire sheet
  var protection = sheet.protect().setDescription('Protect sheet except CHECK and INITIALS columns');

  // Unprotect the "CHECK" and "INITIALS" columns
  var unprotectedRange = sheet.getRange(3, checkColIndex + 1, sheet.getLastRow() - 2, 2);
  protection.setUnprotectedRanges([unprotectedRange]);

  // Set the owner of the sheet
  var me = Session.getEffectiveUser();
  protection.addEditor(me);
  protection.removeEditors(protection.getEditors());
  if (protection.canDomainEdit()) {
    protection.setDomainEdit(false);
  }
}`

I followed Chat GPT’s instruction to set up a trigger but it doesn’t seem to work.

trigger set up

On submission

Event Coding Exercise on mdn web docs

Mdn Web Docs Event Exercises I am new to coding exercises from JavaScript, i m doing event exercises for first time trying no to cram it ,kindly help

I need to create a simple event handler that causes the text inside the button (btn) to change when it is clicked on, and change back when it is clicked again.

The HTML should not be changed; just the JavaScript.

const btn = document.querySelector('.off');

// Add your code here
btn.addEventListener(onclick, () => {
btn.innerHTML = changeText;
});

TypeError: Router.use() requires a middleware function but got a Object at Function.use

I checking some code on NodeJS but here is the error I am getting and notable to resolve it.

  throw new TypeError('Router.use() requires a middleware function but got a ' + gettype(fn))
  ^

TypeError: Router.use() requires a middleware function but got a
Object
at Function.use (D:Reactfeedback-appnode_modulesexpresslibrouterindex.js:469:13)
at Function. (D:Reactfeedback-appnode_modulesexpresslibapplication.js:227:21)
at Array.forEach ()
at Function.use (D:Reactfeedback-appnode_modulesexpresslibapplication.js:224:7)
at Object. (D:Reactfeedback-appserver.js:27:5)
at Module._compile (node:internal/modules/cjs/loader:1378:14)
at Module._extensions..js (node:internal/modules/cjs/loader:1437:10)
at Module.load (node:internal/modules/cjs/loader:1212:32)
at Module._load (node:internal/modules/cjs/loader:1028:12)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:142:12)

Node.js v21.6.2

Here is my auth.js

const express = require('express');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const User = require('../models/User');

const router = express.Router();

// Register a new user
router.post('/register', async (req, res) => {
    const { username, email, password } = req.body;

    try {
        // Check if the user already exists
        let user = await User.findOne({ email });
        if (user) {
            return res.status(400).json({ msg: 'User already exists' });
        }

        // Create a new user
        user = new User({ username, email, password });

        // Hash the password before saving the user
        const salt = await bcrypt.genSalt(10);
        user.password = await bcrypt.hash(password, salt);

        await user.save();

        // Create and return JWT token
        const payload = { user: { id: user.id } };
        jwt.sign(payload, process.env.JWT_SECRET, { expiresIn: '1h' }, (err, token) => {
            if (err) throw err;
            res.json({ token });
        });

    } catch (err) {
        console.error(err.message);
        res.status(500).send('Server error');
    }
});

// Login a user
router.post('/login', async (req, res) => {
    const { email, password } = req.body;

    try {
        // Check if the user exists
        let user = await User.findOne({ email });
        if (!user) {
            return res.status(400).json({ msg: 'Invalid credentials' });
        }

        // Compare the entered password with the hashed password
        const isMatch = await bcrypt.compare(password, user.password);
        if (!isMatch) {
            return res.status(400).json({ msg: 'Invalid credentials' });
        }

        // Create and return JWT token
        const payload = { user: { id: user.id } };
        jwt.sign(payload, process.env.JWT_SECRET, { expiresIn: '1h' }, (err, token) => {
            if (err) throw err;
            res.json({ token });
        });

    } catch (err) {
        console.error(err.message);
        res.status(500).send('Server error');
    }
});

module.exports = router;

This is my server.js

const express = require("express");
const mongoose = require("mongoose");
require('dotenv').config();

const app = express();

app.use(express.json());//middleware

mongoose.connect(process.env.MONGO_URI,{
    useNewUrlParser: true,
    useUnifiedTopology: true,
}).then(() => {
    console.log('Connected to MongoDB');
}).catch(err => {
    console.error('Error connecting to MongoDB:', err.message);
});

app.get('/', (req, res) => {
    res.send('Welcome to the Feedback App!');
});

const authRoutes = require('./routes/auth');
console.log("test");
console.log(authRoutes);
console.log("test");
// Routes
app.use('/api/auth', authRoutes); // Add the auth routes



const PORT = process.env.PORT || 5000;
app.listen(PORT, () => {
    console.log(`Server is running on port ${PORT}`);
});

WordPress: How to prevent the function in one plugin used by another?

I create WordPress Plugin A with button whose id is ‘convert-button’ and there is a JS function like below:

$(‘#convert-button’).on(‘click’, function() {

However, in Plugin B, there is also a button with id ‘convert-button’, and it also has a function like below:

$(‘#convert-button’).on(‘click’, function() {

Now the problem is when I click the “convert” button in Plugin A, both onclick functions in two plugins will be called. How to prevent this? One way is to rename the id of the button, but there are many such buttons and it is time-consuming to rename all of them. Is there better solution for such a case?

What is the best scalable way to implement a ContextProvider to fetch and filter data

I have been working on a project that requires fetching a bunch of data and provides multiple ways to filter/search the data, and I though about keeping filtering on the server-side considering I’ll be using pagination.

I started using React Context recently and tried an approach that didn’t work.

here’s the custom React hook I’m using to fetch data

import { useState, useEffect } from 'react';

const useFetch = (url, url_params) => {
    const [data, setData] = useState(null);
    const [loading, setLoading] = useState(true);
    const [error, setError] = useState(null);
    const [refresh, setRefresh] = useState(0);

    if (url_params) {
        url = url + '?' + url_params.toString();
    }

    const refreshData = () => {
        setRefresh((prev) => prev + 1);
    }

    useEffect(() => {
        const fetchData = async () => {
            try {
                const response = await fetch(url);
                if (!response.ok) {
                    throw new Error('Network response was not ok');
                }
                const result = await response.json();
                setData(result);
            } catch (error) {
                setError(error);
            } finally {
                setLoading(false);
            }
        };

        fetchData();
    }, [refresh, url]);

    return { data, loading, error, refreshData };
};

export default useFetch;

and here is the contextProvider:

import { createContext, useState, useEffect, useContext } from "react";
import { listing_url } from "../../Hooks/api_endpoints";
import useFetch from "../../Hooks/useFetch";
import { useSearchParams } from "react-router-dom";

export const HouseContext = createContext();

export const HouseProvider = ({ children }) => {
    const [selectedHouse, setSelectedHouse] = useState(null);
    // I have tried multiple approaches for searchParams (one is search params and the other is testParams
    const [searchParams, setSearchparams] = useState({
        address__icontains: '',
        apartment_no__icontains: '',
        block__iexact: '',
        currency__iexact: '',
        floor__iexact: '',
        gross__gte: '',
        gross__lte: '',
        net__gte: '',
        net__lte: '',
        num_of_floors__iexact: '',
        num_of_rooms__iexact: '',
        owner__icontains: '',
        owner_phone_num__icontains: '',
        price__gte: '',
        price__lte: '',
        status__iexact: '',
        view__icontains: '',
    });

    // second attempt at implementing searchParams
    const testParams = new URLSearchParams({
        address__icontains: '',
        apartment_no__icontains: '',
        block__iexact: '',
        currency__iexact: '',
        floor__iexact: '',
        gross__gte: '',
        gross__lte: '',
        net__gte: '',
        net__lte: '',
        num_of_floors__iexact: '',
        num_of_rooms__iexact: '',
        owner__icontains: '',
        owner_phone_num__icontains: '',
        price__gte: '',
        price__lte: '',
        status__iexact: '',
        view__icontains: '',
    });

    const { data: houses, error: housesError, loading: housesLoading, refreshData: houseRefresh } = useFetch(listing_url, testParams);

    const createHouse = async (house) => {

        const newHouse = await fetch(listing_url, {
            method: "POST",
            body: JSON.stringify(houseData),
        });
        setHouses([...houses, newHouse]);
    }

    // useEffect(() => {
    //     console.log("houses were updated")
    //     console.log(' search params were updated')
    // }, [houses, testParams])

    const updateSearchParams = (key, value) => {
        console.log("firing updateSearchParams")
        houseRefresh();
        testParams.set(key, value);
    }

    return (
        <HouseContext.Provider value={{ houses, selectedHouse, housesError, housesLoading, setSelectedHouse, createHouse, testParams, updateSearchParams }}>
            {children}
        </HouseContext.Provider>
    )
}

and here’s how I tried to use the filtering options in my Homepage:

import { HouseContext } from '../../Context/House/House';

// .....

export default function Home() {
// .....

    const { testParams, updateSearchParams } = useContext(HouseContext)

    // ......
    return (
          // ......

          <div className='flex'>
            <span className='text-sm/3 my-auto pr-2 dark:text-white'>floor</span>
            <input type='number' placeholder='floor' min={0} onChange={(e) => { updateSearchParams('floor__iexact', e.target.value) }} className='w-14 rounded border border-black' />
          </div>
    // .....

now I have 2 questions about this:

  1. why is the houses list not getting updated when updateSearchParams is firing?
  2. is this approach valid or should I just resort to fetching the data and then filtering client-side? and if so, how will I do so once pagination is added?

Stripe Manual Capture with Apple Pay

I’m working on a web application where a seller needs to authorize buyer’s credit card and then charge it when the item is shipped, I’m using Stripe’s PaymentIntent.create with manual capture, first I create a PaymentMethod and then use it to create the PaymentIntent:

async function createPaymentIntent(paymentMethodId) {
  try {
    const paymentIntent = await stripe.paymentIntents.create({
      amount: price, // Amount in cents
      currency: 'usd',
      payment_method: paymentMethodId,
      capture_method: 'manual',
    });

    console.log('Payment Intent:', paymentIntent);
    return paymentIntent.client_secret;
  } catch (error) {
    console.error('Error creating PaymentIntent:', error);
    throw error;
  }
}

Now, I need to add Apple Pay support. Stripe’s documentation mentions that authorization and capture with Apple Pay is possible (link), but I couldn’t find any detailed instructions on how to actually implement it.

How should I approach adding Apple Pay to this setup to ensure proper authorization and capture flow? Any guidance or advise is greatly appreciated!

Vercel Rewrites for Serverless Sites

I’m building a static html css and js site, and I’m essentially using Vercel rewrites to do stuff like this:

getbrandkit.com/b/brandkit, should be given to the JavaScript as getbrandkit.com/b/main.html?b=brandkit. BUT, I never want the user to see the url parameters in their URL bar.

getbrandkit.com/b/brandkit is NOT an existent file in my code.

I’m using Vercel rewrites:

{
  "rewrites": [
    {
      "source": "/b/:b",
      "destination": "/b/main.html?b=:b"
    }
  ]
}

^^ This is clearly doing something because it is loading main.html when I visit getbrandkit.com/b/brandkit, but, I’m not able to get the b value using URL parameters, unless I physically type, getbrandkit.com/b/main.html?b=brandkit.

Ultimately, going to: getbrandkit.com/b/brandkit should console.log brandkit, and getbrandkit.com/b/anything should console.log anything.

TLDR: How do I get the value from getbrandkit.com/b/ANYTHING, on a serverless site, even though the file doesn’t exist.

Using async in googlescripts webapp

I am building a small web service version inside google scripts

I have 2 questions I couldn’t find an answer to,

  1. Logging, I have tried Logger.log and Console.log
    But whenever I am calling the script using API, it runs but not logging
    And the execution record is not expandable to see any logs.

How can it be logged? in order to debug and so.

  1. I have noticed that I can’t use ‘async’ functions,
    (from some other posts and by getting errors myself)
    Now, I need some of the requests to use fetch, which will require await,
    How can it be approached?

Here’s a code of mine using a simple post-request
which is meant to shorten a URL

    function doPost(e) {
    logSpreadsheet(e)
    Logger.log("doPost initiated");

    let reqbody = e.postData.contents
    reqbody = reqbody ? JSON.parse(reqbody): reqbody;
    
    let action = reqbody.action;

    if (action === "shorten_url") {
        Logger.log("shorten_url function initiated")
        if (reqbody.url) {
            let shortened_url = shorten_url(reqbody.url)
            return ContentService.createTextOutput(
                JSON.stringify({"shortened_url": shortened_url}))
        }
        else {
            return ContentService.createTextOutput(
                JSON.stringify({"error": "`url` parameter is missing"}))
        }
    }
    else {
        return ContentService.createTextOutput(JSON.stringify(
            {"error": "`action` parameter is missing"}))
    }

}

function logSpreadsheet (e) {
    let ss = SpreadsheetApp.getActiveSpreadsheet();
    let sheet = ss.getSheetByName("Logs")
    sheet.getRange(sheet.getLastRow()+1,1).setValue("test")
}


const shorten_url = async (source_url) => {
    console.log("shortening_url")

    encoded_url = source_url ? encodeURIComponent(source_url) : "";

    let res;
    let shortened_url;
    let cuttly_apikey = '***'
    let url = `https://cutt.ly/api/api.php`
    let params = `?key=${cuttly_apikey}&short=${encoded_url}`
    let options = {
        method: "get",
        mode: "no-cors",
        headers: { 'Content-Type': 'application/json' }
    }
    try {
        response = await UrlFetchApp.fetch(url + params, options)
        let resData = response.getContentText();
        if (resData) {
            response = JSON.parse(response);
            console.log('cuttly response:', response)
            shortened_url = response.url.shortLink
        }
    }
    catch (err) {
        console.log(`Error getting user data!n${err} `);
    }

    return shortened_url ? shortened_url : source_url;
}

Thank you for helping.