Why did standard built-in objects Function and Object become each other’s instance? And how is this implemented? [duplicate]

The following code snippet shows Function and Object become each other’s instance.

// below code snippet shows Function is an instance of Object
Function instanceof Object;  // true
Object.prototype.isPrototypeOf.call(Function.prototype, Object);  // true
Function.prototype.isPrototypeOf(Object);  // true

// below code snippet shows Object is an instance of Function
Object instanceof Function;  // true
Object.prototype.isPrototypeOf.call(Object.prototype, Function);  // true
Object.prototype.isPrototypeOf(Function);  // true
// below code snippet means both Function.__proto__ and Object.__proto__ reference the same object in memory
Object.is(Function.__proto__, Object.__proto__);  // true
Object.getPrototypeOf(Function) === Object.getPrototypeOf(Object);  // true
Function.constructor.prototype === Object.constructor.prototype;  // true
Function.__proto__ === Object.__proto__;  // true

And also, Function MDN web page and Object MDN web page, shows Function and Object inherit each other?
screenshot of Function MDN web page
screenshot of Object MDN web page

In my opinion, an instance is initialized/generated by a class, but a class should not initialized/generated by an instance.
I know that OOP in js is prototype-based OOP, and it would be a little different from traditional OOP(like python OOP), I still can’t understand Why did Function and Object become each other’s instance? is this kinda wired in logic?

And another question: how to implement that AClass and BClass become each other’s instance?
Is the following example correct?

// example for making `MyClass1` and `MyClass2` become each other's instance

class MyClass1 { constructor() {} }
class MyClass2 { constructor() {} }
Object.setPrototypeOf(MyClass1, MyClass2.prototype);
Object.setPrototypeOf(MyClass2, MyClass1.prototype);

// below code snippet shows MyClass1 is an instance of MyClass2
MyClass1 instanceof MyClass2;  // true
Object.prototype.isPrototypeOf.call(MyClass2.prototype, MyClass1);  // true
MyClass2.prototype.isPrototypeOf(MyClass1);  // true

// below code snippet shows MyClass2 is an instance of MyClass1
MyClass2 instanceof MyClass1;  // true
Object.prototype.isPrototypeOf.call(MyClass1.prototype, MyClass2);  // true
MyClass1.prototype.isPrototypeOf(MyClass2);  // true

Issue with scrolling through WKWebView when direction=rtl

I have an eBook with dir=rtl and I’m using the following css to split the content of the html into columns:

#book {
    width:350px;
    height:750px;

    margin-left:25px;
    margin-right:25px;

    -webkit-column-count:auto;
    -webkit-column-width:350px;

    -webkit-column-gap:50px;
  
    text-align:justify;
    word-wrap: break-word;
}

I use the following line to get the Webview’s Content Width to calculate the number of columns produced:

[myWKWebView stringByEvaluatingJavaScriptFromString:@"document.getElementsByTagName('html')[0].scrollWidth;"]

I use the following to scroll through the WebView horizontally:

[myWKWebView evaluateJavaScript:[NSString stringWithFormat:@"window.scrollTo(%d,0);",xPosition]];

All the above code works perfectly well, until I introduce the direction to the css:

direction:rtl;

Upon adding the direction to the css, scrollWidth stops giving the correct measurement and scrollTo function ceases to work.

I use the direction in the css, to order the columns from right to left.
Is there an alternative that doesn’t affect the scrolling feature and the scrollWidth?

Kindly note, this is the code used to initialize the WebView:

WKWebViewConfiguration *theConfiguration = [[WKWebViewConfiguration alloc] init];
theConfiguration.selectionGranularity = WKSelectionGranularityCharacter;
[theConfiguration.preferences setValue:@"TRUE" forKey:@"allowFileAccessFromFileURLs"];
theConfiguration.preferences.javaScriptEnabled = true;
myWKWebView = [[WKWebView alloc] initWithFrame:self.view.frame configuration:theConfiguration];
myWKWebView.UIDelegate = self;
myWKWebView.userInteractionEnabled = true;
myWKWebView.contentMode = UIViewContentModeScaleAspectFit;
myWKWebView.autoresizesSubviews = true;
myWKWebView.scrollView.scrollEnabled = true;
myWKWebView.multipleTouchEnabled = true;

[self.view addSubview: myWKWebView];

How to add shortcut button in Odoo 17 using javascript?

t has the following menu declaration code:

<button name="action_qc_pass" string="Pass" type="object" class="oe_highlight"
                                                id="button_qc_pass"/>

I want to automatically call this button when I press the Enter key. How can I do that? I think I need to write javascript for this event. Can someone help me write it? I don’t know much about owl in Odoo?

getElementsByClassName with square brackets [closed]

I’m writing a simple search for elements on a page, and in one place I need to find an image reference that only has the class “sm:cap-h-[210px]”.

When writing such a request, for some reason I get the error “Uncaught SyntaxError: Unexpected token ‘[ ‘”.

document.getElementsByClassName('.sm:cap-h-[210px]').[0].src

Webpage not available. The webpage at tel:1000 could not be loaded because: net::ERR_UNKNOWN_URL_SCHEME

i’m building a mobile app using phoenix framework, i want when the user press on the call number button it dials that number.

what i tried:

  1. <a class="text-zinc-900 text-sm font-medium" href="tel:10000" target="_blank"><%= gettext("10000") %></a>

  2. <a class="text-zinc-900 text-sm font-medium" href="tel:10000""><%= gettext("10000") %></a

3. <a onclick="window.open('tel:10000')" class="external">10000</a>

  1. <button class ="bg-red-500" id="dial_button" phx-hook="Dial" >Call 10000</button>
    and in the javascript file
    `const Dial ={
    mounted(){
    const call = document.getElementById(“dial_button”)

    call.addEventListener("click", function(){        
             window.location.href = "tel:10000";
    })
    

    }
    }
    export default Dial;`

please if you have any ideas how can I do it with a different approach please advise me.

Web vitals onINP reporting elements that do not have any click functionality or handlers attached

In order to improve INP of my application, I integrated web-vitals@3/dist/web-vitals.attribution.iife.js to get field data and work on actual interactions causing poor INP score. However in my data I see a lot of elements reported actually dont have click functionality/handlers attached. For instance there are many div/span/p elements reported in the report. What is the reason behind such a behaviour. This basically makes improvement exercise very ineffective and lengthy. I am collecting attribution.eventTarget for the elements on which interactions happen.

attribution.eventTarget

function sendToAnalytics({name, value, rating, attribution}) {
  // here I am creating req payload with element as attribution.eventTarget 
}

onINP(sendToAnalytics);

react-router v6 throws hooks error on a previously working app

I know that this question has been asked before but I have a hard time determining what is the correct path for me here.

I am trying to add a router to an already working application.

I am new to react-router v6 and haven’t be using react for a while.

After adding react router to the index page I get this message:

react.development.js:209 Warning: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
 1. You might have mismatching versions of React and the renderer (such as React DOM)
 2. You might be breaking the Rules of Hooks
 3. You might have more than one copy of React in the same app

As the code was working fine before I tend to think that the addition of react router is the issue.

It does not seem like the existing code has anything to do with reason 2, which leaves 1 and 3, but an npm ls react showed that the only version all dependencies points to is react 18.2.0

❯ npm ls react
@comp/[email protected] /user/PROJECTS/service/webapp/client
├─┬ @emotion/[email protected]
│ ├─┬ @emotion/[email protected]
│ │ └── [email protected] deduped
│ └── [email protected] deduped
├─┬ @emotion/[email protected]
│ └── [email protected] deduped
├─┬ @mui/[email protected]
│ └── [email protected] deduped
├─┬ @mui/[email protected]
│ ├─┬ @mui/[email protected]
│ │ └── [email protected] deduped
│ ├─┬ @mui/[email protected]
│ │ └── [email protected] deduped
│ ├─┬ [email protected]
│ │ └── [email protected] deduped
│ └── [email protected] deduped
├─┬ @mui/[email protected]
│ ├─┬ @mui/[email protected]
│ │ └── [email protected] deduped
│ ├─┬ @mui/[email protected]
│ │ └── [email protected] deduped
│ └── [email protected] deduped
├─┬ @mui/[email protected]
│ ├─┬ @mui/[email protected]
│ │ └── [email protected] deduped
│ └── [email protected] deduped
├─┬ @testing-library/[email protected]
│ └── [email protected] deduped
├─┬ [email protected]
│ └── [email protected] deduped
├─┬ [email protected]
│ └── [email protected] deduped
└── [email protected]

Now I guess my introduction of react-router is indeed the issue but I can’t figure out what went wrong.

Here is the code

index.js

import React from "react";
import {createRoot} from 'react-dom/client';
import {
    createBrowserRouter,
    RouterProvider,
  } from "react-router-dom";
import "./index.css";
import ServiceUI from "./app/components/ui/ServiceUI";

const router = createBrowserRouter([
    {
      path: "/",
      element: <ServiceUI/>,
    },
]);

const domNode = document.getElementById('serviceUI');
const root = createRoot(domNode);
root.render(
    <React.StrictMode>
        <RouterProvider router={router} />
    </React.StrictMode>
);

ServiceUI.jsx

import React from 'react';
import PropTypes from "prop-types";
import AppBar from "../header/AppBar";
import AppTabContainer from "../tabs/AppTabContainer";

const ServiceUI = () => {
    return <div>
        <AppBar/>
        <AppTabContainer/>
    </div>;
};

ServiceUI.propTypes = {
    apiBaseUrl: PropTypes.string,
};

ServiceUI.defaultProps = {
    apiBaseUrl: "",
};

export default ServiceUI;

AppTabContainer.jsx

import React, {useEffect, useState} from 'react';
import AppTabs from './AppTabs';
import ElementTable from "../element/ElementTable";
import {Chip} from '@mui/material';
import apiService from "../../services/apiService";
import TextTable from "../text/TextTable";

const AppTabContainer = () => {
    const [selectedTab, setSelectedTab] = useState(0);
    const [appVersion, setAppVersion] = useState(null);

    const handleTabChange = (event, newValue) => {
        setSelectedTab(newValue);
    };

    const getSelectedView = (tabIndex) => {
        if (tabIndex === 1) {
            return <TextTable/>;
        }

        return <ElementTable/>;
    };

    useEffect(() => {
        apiService.fetchAppVersion().then(json => {
            setAppVersion(json);
        }).catch(e => {
            setAppVersion(null);
        });
    }, []);


    return (
        <div>
            <div style={{margin: '20px'}}>
                {appVersion ? <Chip label={"Version: " + appVersion.version}/> : <div/>}
            </div>
            <AppTabs selectedTab={selectedTab} handleTabChange={handleTabChange}/>
            <div style={{display: 'flex', flexFlow: 'row nowrap'}}>
                <div style={{flex: '555 1 220px'}}>
                    {getSelectedView(selectedTab)}
                </div>
            </div>
        </div>
    );
};

export default AppTabContainer;

AppBar.jsx

import React, {useEffect, useState} from 'react';
import {Box, AppBar, Toolbar, Typography, Button} from '@mui/material';
import apiService from "../../services/apiService";

const Bar = () => {

    const [userData, setUserData] = useState(null);

    useEffect(() => {
        apiService.fetchUserInfo().then(json => {
            setUserData(json);
        }).catch(e => {
            setUserData(null);
        });
    }, []);

    return (
        <Box sx={{flexGrow: 1}}>
            <AppBar position="static" sx={{bgcolor: "#004572"}}>
                <Toolbar>
                    <Typography variant="h6" component="div" sx={{flexGrow: 1}}>
                        Service
                    </Typography>
                    <Button color="inherit">{userData ? userData.nameWithoutRoleId : "Login"}</Button>
                </Toolbar>
            </AppBar>
        </Box>
    );
};

export default Bar;

Obviously I am missing something, just don’t know what.

How to convert USD amounts to ETH for transactions in my Ethereum dApp?

I am building a dApp where supermarkets send Ethereum tokens to customers as change after purchases. I want to make my frontend user-friendly by allowing users to input amounts in USD instead of ETH.

Here is my code for sending ETH to customers for my smart contract:

function sendMoneyToCustomer(address payable customer) public payable  { 
    balances[customer] += msg.value;
    customer.transfer(msg.value);
}


and this is code where I interact with the smart contract 

async sendMoneyToCustomer(signer, customerAddress, amount) {
    const contract = new ethers.Contract(this.contractAddress, this.abi, signer);
    const ethValue = ethers.parseEther(amount);
    const tx = await contract.sendMoneyToCustomer(customerAddress, { value: ethValue });
    await tx.wait();
}

I would like guidance on how to:

  1. Fetch the current ETH to USD exchange rate.

  2. Convert a user-provided USD amount to ETH before sending it.

  3. Display user balances in USD instead of ETH.

Any help or code snippets would be appreciated!

how can i get device name?

can we get the device name of the user who accesses our website, like in google account connectivity service?

code for programming language from PHP or Javascript can help me to get device name, like “Windows Evan” or “Pixel Bruno”

I have a problem when making POST requests using Firebase Hosting and Functions

enter image description here
I am sending a POST request to the URL shown in the picture, but I’m encountering a CORS error. However, I have configured it to allow any address. Everything worked fine when running locally, but I am having issues after deployment.

const functions = require('firebase-functions');
const express = require('express');
const bodyParser = require('body-parser');
const cors = require('cors');
const OpenAI = require('openai');

const app = express();


app.use(cors({ origin: true }));
app.use(bodyParser.json());


const OPENAI_API_KEY = functions.config().openai.key;
const client = new OpenAI({
  apiKey: OPENAI_API_KEY,
});

app.post('/api', async (req, res) => {
  const { name } = req.body;

  if (!name) {
    console.error('Name is missing from request body');
    return res.status(400).json({ error: 'Name is required' });
  }

  try {
    console.log(`Request received with name: ${name}`);

    const response = await client.chat.completions.create({
      model: 'gpt-3.5-turbo',
      messages: [{ role: 'user', content: `Translate this name to Korean: ${name}` }],
    });

    console.log('OpenAI API response:', response);

    const translatedName = response.choices[0].message.content.trim();
    console.log(`Translated name: ${translatedName}`);

    return res.json({ translatedName });
  } catch (error) {
    console.error('Error communicating with OpenAI:', error.response?.data || error.message || error);
    return res.status(500).json({ error: 'Failed to translate name' });
  }
});

exports.api = functions.https.onRequest(app);

Request URL:
https://us-central1-nulligpt.cloudfunctions.net/api

Referrer Policy:
strict-origin-when-cross-origin

content-type:
application/json; charset=utf-8

referer:
https://nulligpt.web.app/

sec-ch-ua:
“Google Chrome”;v=”129″, “Not=A?Brand”;v=”8″, “Chromium”;v=”129″

sec-ch-ua-mobile:
?0
sec-ch-ua-platform:
“Windows”

user-agent:

Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36

want to create a seperate member route

Suppose in the listing(includes other attributes like title, price as well) i give a set of 20 members with their name and phone number.I need to automatically check whether these members already exists in the member list, if they exist then add return the price of the listing else add the member to the member list.
I am not able to define a particular schema for member model whether array or string or key value pair for member name and member phone number.if i define also i am not able to retrieve it from the database and compare it
So basically i want a member list like member 1 member2 … and when i create the listing these listing members should get compared with the members are return price if they exist else create a new member with that particular name and phone number

listing model

    const listingSchema = new Schema({
    title: { type: String },
    price: { type: Number },
    startDate: {
      type: Date,
    },
    currentMonth: { type: Number },
    endDate: {
      type: Date,
    },

    member: { type: String },
    phone: { type: Number },
    });

member model

    const memberSchema = new Schema({
      member: "String",
      phone: "Number",
    });

listing controller

    const newListing = new listing({
      title: req.body.title,
      price: req.body.price,
      startDate: req.body.startDate,
      currentMonth: req.body.currentMonth,
      endDate: req.body.endDate,
    member: req.body.member,
    });

    let member = newListing.member;
    // console.log(member);
    let present = await members.findOne([member]);
    console.log(present);

    member.forEach(async (e) => {
      // console.log(e);
      let existingMember = await members.findOne({ name: e });
      if (existingMember) {
        console.log("yes");
        console.log(req.body.price)
      } else {
        console.log("no");
        //createmember;
      }
    });

member.controller

    try {
    const newMember = new member({
      member: [{ name: req.body.name, phone: req.body.phone }],
    });
    console.log(newMember);
    // let savedMember = await newMember.save();
    // console.log(savedMember);
    return res.json({ message: "New Members Created!" });
    } catch (error) {
    console.log(error);
    res.status(404).json(error, "cannot create new member");
    }

How i can find a tutorial or keyword for me to learn Role Based Access using Prisma ORM Mysql as the database

So in my application needed 3 account with different usage and previlege access. where it a regular user, admin and superadmin. Where i can learn such thing? or any article and video you can provide for me to learn.

also its a commerce like and its for my school project. your help is meaningful pls dont judge me i am very novice in this field. cant ask teacher they dont know such things F.

I been trying reading article from medium and watching videos on youtube but i really dont understand where i need to start as i dont have the foundation or underlying to build such things sorry.

Audio Visualizer/Analyzer Vanilla JavaScript issue or possibly CORS

So I’m working on an app that compares heavy metal vocals from popular artists (fundamental freq. key, dB, all that good stuff). However my audio recorder works (which was some of the harder work so that’s good), but my audio visualizer (canvas) and audio element on the left which is loaded by by src=”” but I think something in my JS is making it bug out because it was working in the beginning. It wasn’t until I got to messing with the harmonics, decibels, key, pitch, etc. did things go wrong. And this is after forgetting to save the better working version of the code. Now I’m completely lost. I’m also running an apache server with XAMPP. If you guys have any questions about my code or what I’m trying to accomplish, feel free to ask. Also I should mentioned I did half to coding and I use chatGPT for some of the more technical issues. Which also keeps messy up my code as well so I thought I’d rejoin this site and see if I can get any help. I’m really passionate about about sound engineering and heavy music so I would really like to see this site/app come to life for people to practice their vocals. Any help would be awesome!!! This my code.

<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Audio Visualizer</title>
    <style>
        body {
            margin: 0;
            overflow: hidden;
        }
        
        @font-face {
            font-family: 'Deathcore';
            src: url('fonts/Faceless.ttf') format('truetype');
        }

        @font-face {
            font-family: 'Crunk';
            src: url('fonts/TheDark.ttf') format('truetype');
        }
        
        div#content-1 {
            display: block;
            width: 100%;
            height: 100%;
            background-color: #000000;
        }
        div#nav-bar {
            position: fixed;
            width: 100%;
            height: 50px;
            background-color: #131313;
            border-bottom: solid 1px #ff0000;
        }
        select {
            border-radius: 15px;
            border: 2px solid #ffffff;
            color: #ffffff;
            background-color: #000000;
            width: 175px;
            height: 36px;
            margin-top: 9px;
            margin-left: 20px;
        }
        img#profile-picture {
            margin-top: 30px;
            width: 350px;
            height: 300px;
            border: 1px solid #ffffff;
        }
        audio {
            height: 45px;
            border-radius: 0px;
            border: 2px solid #ffffff;
            background-color: #131313;
        }
        canvas {
            width: 48%;
            height: 135px;
            display: block;
            background-color: #000000;
        }
        #controls {
            position: absolute;
            bottom: 193px;
            right: 30px;
        }
        button {
            margin-left: 5px;
            padding: 10px;
            background-color: #ff0000;
            border: none;
            color: white;
            cursor: pointer;
            border-radius: 5px;
        }
        button:hover {
            background-color: #cc0000;
        }
        /* New styles for info divs */
        .info {
            font-family: Arial;
            position: absolute;
            width: 320px;
            height: 150px;
            background-color: #808080;
            color: #ffffff;
            padding: 10px;
            border-radius: 5px;
            font-size: 18px;
        }
        #info-artist {
            bottom: 235px;
            left: 30px;
        }
        #info-user {
            bottom: 235px;
            right: 30px;
        }
        
        div#bio {
            float: left;
        }
        div#name-info {
            margin-left: 20px;
            font-size: 30px;
            font-family: Deathcore;
            color: #ffffff;
        
        }
        div#band-info {
            margin-left: 28px;
            font-size: 20px;
            font-family: Arial;
            color: #ffffff;
        
        }
        div#lyrics {
            position: absolute;
            left: 500px;
            width: 930px;
            height: 350px;
            border-radius: 15px;
            background-color: #131313;
            color: #ffffff;
            font-family: Arial;
        }
    </style>
</head>
<body>
    <div id='content-1'>
        <div id='nav-bar'>
            <select id='vocal-style'>
                <option>Fry</option>
                <option>False Chord</option>
                <option>Gutterals</option>
            </select>
            <select id='vocal-artist'>
                <option>Danny Worsnop</option>
                <option>Alex Terrible</option>
                <option>Cj McCreery</option>
            </select>
            <button id="generateSampleBtn">Generate New Sample</button>
            <button id="downloadSampleBtn">Download Sample</button>
        </div>
        <br>
        
        <div style='margin-top: 20px;margin-left: 10px;'>
            <img id='profile-picture' src='profile_pics/CJ_McCreery.jpg'>
        </div>
        <div id='bio'>
            <div id='name-info'>
                Alex Terrible
            </div>
            <div id='band-info'>
                Band: Slaughter to Prevail
            </div>
        </div>
        
        <div id="controls">
            <button id="recordBtn">Record</button>
            <button id="stopBtn" disabled>Stop</button>
            <button id="downloadBtn" disabled>Download</button>
            <button id="compareBtn" disabled>Compare Audio</button>
        </div>
        <div style='position: absolute; bottom: 5px;width:100%;left: 30px;'>
            <canvas style='margin-left: 932px; margin-bottom: -135px;' id='canvas-user'></canvas>
            <canvas style='margin-left: 2px;' id='canvas-artist'></canvas>
            <audio id='artist-audio' style='width:48%;' src='samples/false_chord/alex_terrible/sample-1.mp3' controls></audio>
            <audio id='user-audio' style='width:48%;' controls></audio>
        </div>
        
        <!-- New divs for displaying audio info -->
        <div id="info-artist" class="info">
            <strong>Artist Audio:</strong>
            <div id="dB-artist">dB: </div>
            <div id="fundamental-artist">Fundamental Frequency: </div>
            <div id="harmonics-artist">Harmonics: </div>
            <div id="pitch-artist">Pitch: </div>
            <div id="key-artist">Key: </div>
        </div>
        <div id="info-user" class="info">
            <strong>User Audio:</strong>
            <div id="dB-user">dB: </div>
            <div id="fundamental-user">Fundamental Frequency: </div>
            <div id="harmonics-user">Harmonics: </div>
            <div id="pitch-user">Pitch: </div>
            <div id="key-user">Key: </div>
        </div>
        <div id='lyrics'>
            Hell is right here! You've been abandoned, you've been abandoned! Hell is right here! Kingdom of storm and thunder
        </div>
    </div>

    <script>
    window.onload = function () {
    // All your JavaScript code goes here

    let isRecording = false; // State for recording
    let mediaRecorder;
    let recordedChunks = [];

    // Record functionality
    recordBtn.addEventListener('click', function () {
        recordedChunks = []; // Reset recorded chunks
        navigator.mediaDevices.getUserMedia({ audio: true }).then(stream => {
            mediaRecorder = new MediaRecorder(stream);
            mediaRecorder.start();
            isRecording = true;
            recordBtn.disabled = true;
            stopBtn.disabled = false;

            // Save audio data chunks
            mediaRecorder.ondataavailable = function (event) {
                recordedChunks.push(event.data);
            };

            // Handle media recorder stop event
            mediaRecorder.onstop = function () {
                const blob = new Blob(recordedChunks, { type: 'audio/webm' });
                userAudio.src = URL.createObjectURL(blob);
                downloadBtn.disabled = false;
            };
        });
    });

    stopBtn.addEventListener('click', function () {
        if (isRecording) {
            mediaRecorder.stop();
            isRecording = false;
            recordBtn.disabled = false;
            stopBtn.disabled = true;
        }
    });

    // Download functionality
    downloadBtn.addEventListener('click', function () {
        const blob = new Blob(recordedChunks, { type: 'audio/webm' });
        const url = URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.style.display = 'none';
        a.href = url;
        a.download = 'recording.webm';
        document.body.appendChild(a);
        a.click();
        window.URL.revokeObjectURL(url);
    });

    const artistAudio = document.getElementById('artist-audio');
    const userAudio = document.getElementById('user-audio');
    const canvasArtist = document.getElementById('canvas-artist');
    const canvasUser = document.getElementById('canvas-user');
    const ctxArtist = canvasArtist.getContext('2d');
    const ctxUser = canvasUser.getContext('2d');

    // Set canvas dimensions based on their offset sizes
    canvasArtist.width = canvasArtist.offsetWidth;
    canvasArtist.height = canvasArtist.offsetHeight;
    canvasUser.width = canvasUser.offsetWidth;
    canvasUser.height = canvasUser.offsetHeight;

    // Function to calculate and update audio information
    function calculateAudioSpecs(analyser, dataArray, bufferLength, infoPrefix) {
        analyser.getByteFrequencyData(dataArray);

        let sum = 0;
        for (let i = 0; i < bufferLength; i++) {
            sum += dataArray[i] ** 2;
        }
        const rms = Math.sqrt(sum / bufferLength);
        const dB = 20 * Math.log10(rms / 255);
        document.getElementById(`dB-${infoPrefix}`).innerText = `dB: ${dB.toFixed(2)}`;

        let maxIndex = 0;
        let maxValue = -Infinity;
        for (let i = 0; i < bufferLength; i++) {
            if (dataArray[i] > maxValue) {
                maxValue = dataArray[i];
                maxIndex = i;
            }
        }
        const fundamentalFreq = maxIndex * analyser.context.sampleRate / analyser.fftSize;
        document.getElementById(`fundamental-${infoPrefix}`).innerText = `Fundamental Frequency: ${fundamentalFreq.toFixed(2)} Hz`;

        const harmonics = maxValue / 255;
        document.getElementById(`harmonics-${infoPrefix}`).innerText = `Harmonics: ${harmonics.toFixed(2)}`;

        const pitch = fundamentalFreq;
        document.getElementById(`pitch-${infoPrefix}`).innerText = `Pitch: ${pitch.toFixed(2)} Hz`;

        const key = determineKey(fundamentalFreq);
        document.getElementById(`key-${infoPrefix}`).innerText = `Key: ${key}`;
    }

    // Function to determine musical key from frequency
    function determineKey(frequency) {
        const keys = [
            { note: "C", frequency: 261.63 },
            { note: "C#", frequency: 277.18 },
            { note: "D", frequency: 293.66 },
            { note: "D#", frequency: 311.13 },
            { note: "E", frequency: 329.63 },
            { note: "F", frequency: 349.23 },
            { note: "F#", frequency: 369.99 },
            { note: "G", frequency: 392.00 },
            { note: "G#", frequency: 415.30 },
            { note: "A", frequency: 440.00 },
            { note: "A#", frequency: 466.16 },
            { note: "B", frequency: 493.88 }
        ];

        let closestKey = keys[0].note;
        let closestFreqDiff = Math.abs(frequency - keys[0].frequency);

        keys.forEach(key => {
            const freqDiff = Math.abs(frequency - key.frequency);
            if (freqDiff < closestFreqDiff) {
                closestFreqDiff = freqDiff;
                closestKey = key.note;
            }
        });

        return closestKey;
    }

    // AudioContext setup for Artist audio
    const audioContextArtist = new (window.AudioContext || window.webkitAudioContext)();
    const analyserArtist = audioContextArtist.createAnalyser();
    const sourceArtist = audioContextArtist.createMediaElementSource(artistAudio);
    sourceArtist.connect(analyserArtist);
    analyserArtist.connect(audioContextArtist.destination);

    const bufferLengthArtist = analyserArtist.frequencyBinCount;
    const dataArrayArtist = new Uint8Array(bufferLengthArtist);
    analyserArtist.fftSize = 2048;

    // AudioContext setup for User audio
    const audioContextUser = new (window.AudioContext || window.webkitAudioContext)();
    const analyserUser = audioContextUser.createAnalyser();
    const sourceUser = audioContextUser.createMediaElementSource(userAudio);
    sourceUser.connect(analyserUser);
    analyserUser.connect(audioContextUser.destination);

    const bufferLengthUser = analyserUser.frequencyBinCount;
    const dataArrayUser = new Uint8Array(bufferLengthUser);
    analyserUser.fftSize = 2048;

    // Function to draw visualization and update audio info
    function draw() {
        requestAnimationFrame(draw);

        // Clear canvas for Artist
        ctxArtist.clearRect(0, 0, canvasArtist.width, canvasArtist.height);
        analyserArtist.getByteFrequencyData(dataArrayArtist);

        ctxArtist.fillStyle = '#ff0000';
        for (let i = 0; i < bufferLengthArtist; i++) {
            const barHeight = dataArrayArtist[i] / 2;
            ctxArtist.fillRect(i * 2, canvasArtist.height - barHeight, 1, barHeight);
        }

        // Clear canvas for User
        ctxUser.clearRect(0, 0, canvasUser.width, canvasUser.height);
        analyserUser.getByteFrequencyData(dataArrayUser);

        ctxUser.fillStyle = '#ff0000';
        for (let i = 0; i < bufferLengthUser; i++) {
            const barHeight = dataArrayUser[i] / 2;
            ctxUser.fillRect(i * 2, canvasUser.height - barHeight, 1, barHeight);
        }

        // Update audio info for Artist
        calculateAudioSpecs(analyserArtist, dataArrayArtist, bufferLengthArtist, 'artist');

        // Update audio info for User
        calculateAudioSpecs(analyserUser, dataArrayUser, bufferLengthUser, 'user');
    }

    draw();
};

    </script>
</body>
</html>

I’ve tried different approaches of loading the audio element, I’ve tried changing the cross-origin header on my apache server, I’ve even tried using chatGPT, and now I’m here and I’ll be honest I’m not the best programmer either, I’m better at sound engineering and music production but thought I’d give it a shot.

Passing JavaScript test #13 in my JavaScript caluclator

I’m seeking assistance with passing JavaScript test #13 in my JavaScript Calculator project. You can view my work here: CodePen. Test can be run on codepen fo JavaScript Calculator.

13. If 2 or more operators are entered consecutively, the operation performed should be the last operator entered (excluding the negative (-) sign.

document.addEventListener("DOMContentLoaded", () => {
  let currentInput = "0";
  let previousInput = "";
  let operator = null;
  let justEvaluated = false;
  let expression = "";
  let lastInputWasOperator = false;

  const display = document.getElementById("display");
  const numbers = document.querySelectorAll(".number");
  const operators = document.querySelectorAll(".operator");
  const decimalButton = document.getElementById("decimal");

  const clearDisplay = () => {
    currentInput = "0";
    previousInput = "";
    justEvaluated = false;
    expression = "";
    lastInputWasOperator = false;
    updateDisplay();
  };

  const updateDisplay = () => {
    display.innerText = currentInput;
  };

  const handleNumberClick = (e) => {
    const value = e.target.innerText;

    if (justEvaluated) {
      currentInput = value;
      justEvaluated = false;
    } else {
      if (currentInput === "0" && value !== "0") {
        currentInput = value;
      } else if (currentInput !== "0") {
        currentInput += value;
      }
    }

    lastInputWasOperator = false;
    updateDisplay();
  };

  const handleDecimalClick = () => {
    if (!currentInput.includes(".")) {
      currentInput += ".";
      updateDisplay();
    }
  };

  const handleOperatorClick = (e) => {
    const value = e.target.innerText;

    if (justEvaluated) {
      previousInput = currentInput;
      justEvaluated = false;
      expression = "";
    }

    if (value === "-" && (currentInput === "0" || lastInputWasOperator)) {
      currentInput = currentInput === "-" ? "0" : "-";
      lastInputWasOperator = false;
      updateDisplay();
      return;
    }

    if (lastInputWasOperator) {
      if (value !== "-" && operator !== null) {
        operator = value;
        expression = expression.slice(0, -1) + operator;
      }
      return;
    } else {
      if (previousInput === "") {
        previousInput = currentInput;
      } else {
        handleEquals();
        previousInput = currentInput;
      }

      expression += currentInput + value;
      operator = value;
      currentInput = "0";
    }

    lastInputWasOperator = true;
    updateDisplay();
  };

  const handleEquals = () => {
    if (currentInput === "") return;

    expression += currentInput;

    try {
      expression = expression.replace(
        /([-+*/]){2,}/g,
        (match) => match[match.length - 1]
      );

      if (/^[*/]/.test(expression)) {
        expression = expression.substring(1);
      }

      currentInput = eval(expression).toString();

      currentInput = parseFloat(currentInput)
        .toFixed(4)
        .replace(/.?0+$/, "");

      expression = "";
      operator = null;
      previousInput = "";
      justEvaluated = true;
    } catch (e) {
      currentInput = "Error";
    }

    if (isNaN(currentInput)) {
      currentInput = "Error";
    }

    updateDisplay();
  };

  numbers.forEach((button) => {
    button.addEventListener("click", handleNumberClick);
  });

  operators.forEach((button) => {
    button.addEventListener("click", handleOperatorClick);
  });

  decimalButton.addEventListener("click", handleDecimalClick);

  document.getElementById("equals").addEventListener("click", handleEquals);
  document.getElementById("clear").addEventListener("click", clearDisplay);
});

I’ve tried several approaches to handle negative numbers, but I still have one test failing. Currently, I’m passing 15 out of 16 tests and would greatly appreciate any guidance or solutions you might have to help me get that last one passed!