How to merge 2 Function on Apps script

How to merge multiple function for apps script ?
I Try learn from google but I can’t find solution
help me please, Thank you very munch.

var ss = SpreadsheetApp.openByUrl("Test1");
var ss = SpreadsheetApp.openByUrl("Test2");
var sheet = ss.getSheetByName("Product");
var member = ss.getSheetByName("Member");

function doPost(e) {

  var data = JSON.parse(e.postData.contents)
  var userMsg = data.originalDetectIntentRequest.payload.data.message.text;
  var values = sheet.getRange(2, 3, sheet.getLastRow(), sheet.getLastColumn()).getValues();
  for (var i = 0; i < values.length; i++) {

    if (values[i][0] == userMsg) {
      i = i + 2;
      var Product = sheet.getRange(i, 3).getValue(); //Product
      var Data1 = sheet.getRange(i, 4).getValue(); //Price
      var Data2 = sheet.getRange(i, 5).getValue(); //Size
      var Data3 = sheet.getRange(i, 1).getValue(); //Book Name

      var result = {
        "fulfillmentMessages": [{
          "type": "text",
          "text": "Price : " + Data1 + " ฿"
        }, ]
      }

      var replyJSON = ContentService.createTextOutput(JSON.stringify(result)).setMimeType(ContentService.MimeType.JSON);
      return replyJSON;
    }
  }
}

function doPost(e) {

  var diaflow = JSON.parse(e.postData.contents)
  var userMsg = diaflow.originalDetectIntentRequest.payload.data.message.text;
  var valuess = member.getRange(2, 3, member.getLastRow(), member.getLastColumn()).getValues();
  for (var i = 0; i < valuess.length; i++) {

    if (valuess[i][0] == userMsg) {
      i = i + 2;
      var Product = member.getRange(i, 3).getValue(); //Product
      var Data1 = member.getRange(i, 4).getValue(); //Price
      var Data2 = member.getRange(i, 5).getValue(); //Size
      var Data3 = member.getRange(i, 1).getValue(); //Book Name

      var result = {
        "fulfillmentMessages": [{
          "type": "text",
          "text": "Price : " + Data1 + " ฿"
        }, ]
      }

      var replyJSON = ContentService.createTextOutput(JSON.stringify(result)).setMimeType(ContentService.MimeType.JSON);
      return replyJSON;
    }
  }
}

How to merge multiple function for apps script ?
How to use multiple function because i use this code can run one function only.

Why exchanging between javascript FormData and PHP, does not work? [duplicate]

I don’t understand. I have the following JavaScript function that sends a blob object to PHP side:

function createDownloadLink(blob,encoding) {

        fetch('https://localhost:443/process.php', {method: "POST", body: blob}).then( (response) => response.json() ).then( (aidata) => {

                textInputG.value = aidata.text;
        } );
}

On PHP side I catch the blob with the following code and everything simply works:

<?php
    $data = file_get_contents('php://input');
    // PROCESSING HERE //
    $reply = array('text' => $text);
    echo json_encode($reply);
?>

Now the problem is that I need to send MORE THAN ONE OBJECT from the JavaScript side, so I tryed to modify the function using FormData, but on PHP side I’m unable to read the blob:

function createDownloadLink(blob,encoding) {

        const formData = new FormData();
        formData.append('blob', blob);
        formData.append('text', text);
 
        fetch('https://localhost:443/process.php', {method: "POST", body: formData}).then( (response) => response.json() ).then( (aidata) => {

                textInputG.value = aidata.text;
        } );
}

This is what in theory I would have expected to work, but it doesn’t!

<?php
    $blob_data = $_FILES['blob'];  # THIS IS NOT READ CORRECTLY #
    $text_data = $_POST['text'];   # This works instead #
    // PROCESSING HERE //
 

It seems that instead of the bytes of the blob, what I receive on PHP is the string “[object Blob]” inside the $_POST[‘blob’] array, and nothing inside the $_FILES[‘blob’] array.

What am I doing wrong, and how can I fix the issue?

I’m trying to get the JavaScript blob along with the text in FormData on the PHP side.

Visual Studio Code jquery $ not found when using CDN

As the title says I’m using a CDN to get jQuery. I have installed a jsconfig.json file next to my js files.

{
    "typeAcquisition": {
        "include": [
            "jquery"
        ]
    }
}

That fixes Intellisense but not the not found issue. In other words how do I use a CDN and have VSC think jQuery is available/defined?

Decompress zlib/deflate with a shared dictionary in Javascript

Zlib/deflate doesn’t exactly support shared dictionaries but you can “pre-load” the output stream with up to 32kB of data. For example in Python:

>>> from zlib import compressobj
>>> c = compressobj(zdict="abcdefghijklmnopqrstuvwxyz")
>>> c.compress(b"abcdefghijklmnopqrstuvwxyz")
b'xxbbx90x86x0b '
>>> c.flush()
b'Kxc4)x03x00x90x86x0b '

The output is a lot shorter than without the dictionary:

>>> compress(b"abcdefghijklmnopqrstuvwxyz")
b'xx9cKLJNIMKxcfxc8xccxcaxcexc9xcdxcb/(,*.)-+xafxa8xacx02x00x90x86x0b '

The question is: is there any way to decompress the dictionary-compressed output in Javascript using built in web APIs?

I’m 99% sure the answer is no; just checking I haven’t missed something.

Javascript – Download xls file served from backend in blob format

I have a backend service writted in Java that will power the vue frontend app. I need to start the download of a file when it will be provided from the backend. At the moment I’ve noticed that the response fro the backend that will provide the file is an object. The object have this structure:

{
 data: "..." //This is supposed to be a blob
}

How I can convert the response to an xls file correctly? I’ve tried to pass it to the File consctructor but the resulting file seems corrupted.

getXlsFile(data)
 .then( (res) => {
   let file = new File([res?.data], 'report.xls');
   ...
  })

Not sure if I need to convert the response in a blob again?

How to trigger button click event in iframe using javascript

I am working on an application where I need to trigger button click events using javascript.

window.onload = function() {

  // set up event listener on Pay With Card button
  function StartTransaction() {

    var urlParams = getUrlVars();
    var transToken = urlParams["transactionToken"];
    externalTransId = urlParams["externalTransId"];
    var urlPage = emergepayUrlPage.init({
      // (optional) Callback function that gets called after a successful transaction
      onTransactionSuccess: function(approvalData) {
        transactionExecuted = true
        clearTimeout(pollingTimeout);
        postCallbackCPResponse("true", approvalData);

      },
      // (optional) Callback function that gets called after a failure occurs during the transaction (such as a declined card)
      onTransactionFailure: function(failureData) {
        transactionExecuted = true
        clearTimeout(pollingTimeout);
        postCallbackCPResponse("false", failureData);
      }
    });
    // set the source of the iframe to the emergepay page.
    iframe.src = urlPage.getUrl(transToken);
    iframe.style.display = 'block';
    $(".iframeContainer").show();

    //var pollingTimeout = setTimeout(function () {
    //    if (!transactionExecuted) {
    //        startServerPolling();
    //    }
    //}, 3000);

    iframe.onload = function() {
      // Access the iframe document
      const iframeDoc = iframe.contentDocument || iframe.contentWindow.document;

      // Find the submit button within the iframe, for example by its ID
      const submitButton = iframeDoc.querySelector('button[type="submit"]');

      // Trigger a click on the submit button if it exists
      if (submitButton) {
        submitButton.click();
      } else {
        console.log("Submit button not found in the iframe.");
      }
    };
  }

  StartTransaction();
}

How do can I get an array all weekdays in javascript

My application includes Java 21 on the server side and React.js on the client side. According to the Locale, I must get a list/array of weekdays. I have no limits on dependencies to use, as long as they are free/open-source.

I can do that in Java using the following code (didn’t invest too much time writing it) and calling an API from the client to get it, but I want something that is JavaScript and if I can save the API request:

String[] weekDays = DateFormatSymbols.getInstance().getWeekdays();
System.out.print("weekDays:nt");
Arrays.stream(weekDays).forEach(x -> System.out.print(x + ", "));
System.out.println();

**Output:**
daysOfWeek:
    , Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, 

The code in Java for weekdays in German:

    String[] daysOfWeekGER = DateFormatSymbols.getInstance(Locale.GERMAN).getWeekdays();
    System.out.print("daysOfWeekGER:nt");
    Arrays.stream(daysOfWeekGER).forEach(x -> System.out.print(x + ", "));
    System.out.println();
    
    **Output**
    daysOfWeekGER:
        , Sonntag, Montag, Dienstag, Mittwoch, Donnerstag, Freitag, Samstag, 

I am looking for something similar in JavaScript.

Creating a hardcoded array for every language is impractical and wastes time and effort.

My javascript function keeps refreshing yet I use event.preventDefault()

This is my javascript function:

document.addEventListener('DOMContentLoaded', function() {
    // Check if user is logged in
    const loggedInUser = JSON.parse(localStorage.getItem('loggedInUser'));
    if (!loggedInUser) {
        window.location.href = 'login.html';
        return;
    }

    // Display welcome message
    const welcomeMessage = document.getElementById('welcome-message');
    if (welcomeMessage) {
        welcomeMessage.textContent = `Welcome, ${loggedInUser.username}!`;
    }

    const form = document.getElementById('symptom-form');

    if (!form) {
        console.error('Form not found');
        return;
    }
    resultDiv = document.getElementById('result');

    form.addEventListener('submit', function (e) {
        e.preventDefault();
        e.stopImmediatePropagation()
        
        const symptomsInput = document.getElementById('symptoms');
        const symptoms = symptomsInput.value.trim();
        if (!symptoms) {
            alert('Please enter your symptoms.');
            return;
        }

        fetch('http://localhost:5000/diagnose', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'Authorization': `Bearer ${loggedInUser.email}`
            },
            body: JSON.stringify({ symptoms: symptoms, email: loggedInUser.email }),
        })

        .then(response => {
            if (!response.ok) {
                throw new Error('Network response was not ok');
            }
            return response.json();
        })

        .then(data => {
            displayResults(data, symptoms);
        })
        .catch(error => {
            console.error('Error:', error);
            resultDiv.innerHTML = '<p style="color: red;">An error occurred </p>';
        });

    } 
)
    
});

It runs fine, fetches the diagnosis and recommendation but once that’s done the page refreshes and it all happens in a second, in fact the only way I know it refreshes is because of the console message: Navigated to localhost:5500/index.html

Im trying to extract data based on object values in javascript

{
      "id": 6,
      "createdAt": "2024-07-24T11:33:05.749Z",
      "updatedAt": "2024-07-24T11:33:05.749Z",
      "deletedAt": null,
      "name": "vendor_cashier",
      "permissions": [
        {
          "id": 18,
          "createdAt": "2024-07-24T11:33:05.683Z",
          "updatedAt": "2024-07-24T11:33:05.683Z",
          "deletedAt": null,
          "code": "can_read_pos_device"
        },
        {
          "id": 19,
          "createdAt": "2024-07-24T11:33:05.683Z",
          "updatedAt": "2024-07-24T11:33:05.683Z",
          "deletedAt": null,
          "code": "can_update_pos_device"
        }
      ]
    }

And I need the following sample:

{
   "name":"vendor_cashier",
   "page":"pos-device",
   "permissions":"(list)|(edit)|(show)"
}

I have been trying for hourst but can’t think of a solution, can someone help, and Thanks in advance

Issues with generic types and defaults when using TypeScript in strict mode

I’m currently refactoring a codebase to support TypeScript’s strict mode. However, I’ve ran into an issue with functions that leverage generics.

In essence, I have a function that takes an object with a blocks property, this property uses a type that is generic, but has default types.

This is the definition of the object:

export type Context<
  S extends VariableSchema = VariableSchema,
  R extends VariableSchema = VariableSchema,
> = {
  blocks: { [key: string]: Block };
  schema: S;
  result: R;
};

The Block type itself is generic as well and looks like this:

export type Block<
  ParamMap extends BlockParamSchema = BlockParamSchema,
  HandleMap extends { [key: string]: string } = { [key: string]: string },
> = {
  label: string;
  parameters: ParamMap;
  validateParameters: (args: {
    parameters: ConvertVariableSchemaToObjectType<ParamMap>;
    getVariableDefinition: (name: string) => Variable;
  }) => z.AnyZodObject;
  handles: HandleMap;
  execute: (args: BlockExecutionApi<ParamMap, HandleMap>) => Promisable<void>;
};

I then use it in the following manner:

export const deductionCalculationContext = createContext({
  blocks: defaultBlocks,
  schema: {
    deductionYtd: v.number('Deduction YTD'),
    eligibleWages: v.number('Eligible Wages'),
  },
  result: {
    employeeAmount: v.number('Employee Amount'),
    companyAmount: v.number('Company Amount'),
  },
});

All Blocks are declared using a createBlock function which infers the generic types of Block for type safety. Specifically, it ensures that when a developer passes a set of parameters, the validator arguments are typed based on that:

export const conditionBlock = createBlock({
  label: 'If',

  parameters: {
    when: {
      label: 'Condition',
      type: 'unknown',
      required: true,
    },
    equalTo: {
      label: 'Equal to',
      type: 'unknown',
      required: true,
    },
  },

  handles: {
    true: 'True',
    false: 'False',
  },

  execute: async ({ parameters, fireHandle }) => {
    parameters.when === parameters.equalTo ? fireHandle('true') : fireHandle('false');
  },
});

However even though it’s the same type, less the generic args, TS won’t compile, displaying this error:

TypeScript error

I’ve tried the following things:

  • Omitting the blocks and redeclaring it without generics works, but I’m afraid of the type safety issues it’ll bring.

  • Disabling strictFunctionTypes also works, but breaks other type safety features related to functions.

  • Making the blocks property generic.

  • Making the blocks property generic, but without a generic type constraint, and then using a mapped type, conditional types, and inference to get the values of the generics. This worked in concept but I can’t apply it since it’d reference the type recursively.

I’m trying to avoid having to explicitly pass the generic type, and I know there are libraries out there that have accomplished this.

Title: Slider items overlapping when using translateX in JavaScript

[Problem Image][1]I’m creating a slider with multiple pages. It appears fine when using CSS alone, but when I add JavaScript to translate the slider-wrapper to -100vw, the images and divs within each slider-item start overlapping. I’d like to have each slider-item move smoothly to the left by -100vw (for the first item), -200vw (for the second item), and so on. However, the content inside each slider-item does not stay positioned correctly.

this is html section
<!-- Slider Section -->
    <div class="slider">
        <div class="slider-wrapper">
        <div class="slider-item">
        <img class="slider-images" src="templates/Monitor1.png">
        <div class="slider-bg"></div>
        <h1 class="SliderTitle">Apple Studio Display</h1>
        <h2 class="SliderPrice">60000INR</h2>
        <button class="Buy-Now">BUY NOW</button>
        </div>
        <div class="slider-item">
            <img clas="slider-images" src="templates/Monitor1.png">
            <div class="slider-bg"></div>
            <h1 class="SliderTitle">Apple Studio Display</h1>
            <div class="sliderPriceBG"><h2 class="SliderPrice">60000INR</h2></div>
            <button class="Buy-Now">BUY NOW</button>
        </div>
        <div class="slider-item">
            <img src="templates/Monitor1.png">
            <div class="slider-bg"></div>
            <h1 class="SliderTitle">Apple Studio Display</h1>
            <h2 class="SliderPrice">60000INR</h2>
            <button class="Buy-Now">BUY NOW</button>
        </div>
        <div class="slider-item">
            <img src="templates/Monitor1.png">
            <div class="slider-bg"></div>
            <h1 class="SliderTitle">Apple Studio Display</h1>
            <h2 class="SliderPrice">60000INR</h2>
            <button class="Buy-Now">BUY NOW</button>
        </div>
        <div class="slider-item">
            <img src="templates/Monitor1.png">
            <div class="slider-bg"></div>
            <h1 class="SliderTitle">Apple Studio Display</h1>
            <h2 class="SliderPrice">60000INR</h2>
            <button class="Buy-Now">BUY NOW</button>
        </div>
    </div>

This is CSS section

.slider{
    background-image: url("templates/Background/Slider_Background_2.jpg");
    /*clip-path: polygon(0 0, 100% 0, 100% 100%, 0 80%);*/
}

.slider-wrapper{
    display: flex;
    width: 500vw;
    position: relative;
}

.slider-item{
    width: 100vw;
    display: flex;
    justify-content: center;
    position: relative;
    align-items: center;
}
.slider-images{
    position: absolute;
    left: 3%;
    
}

.SliderTitle{
    position:absolute;
    top:27%;
    right:13%;
    font-size: 48px;
    font-weight: 900;
    text-align: center;
    color: #2C3E50;
}

.slider-bg{
    height: 500px;
    width: 550px;
    top: 20%;
    background-color: #f5f5dc;
    position: absolute;
    clip-path: circle(50% at 50% 50%);
    right: 10%;
}

.SliderPrice{
    position: absolute;
    right: 21%;
    color: #001A3F;
    top: 40%;
    font-size: 32px;
    background-color: green;
    border-radius: 10px;
    width: 150px;
    height: 50px;
}

.Buy-Now{
    position: absolute;
    right: 21%;
    top: 55%;
    font-size: 31px;
    border-radius: 33px;
    background-color: blue;
}```

This is JS section which is giving error after insertion

const wrapper = document.querySelector('.slider-wrapper');
wrapper.style.transform="translateX(-100vw)"

I have overflow: hidden on the .slider container to prevent elements from overflowing, but the images and divs inside each slider-item don’t seem to stay aligned when I translate the slider-wrapper.

My Goal: To have each slider-item move to the left smoothly without overlapping or losing alignment. Any ideas on what might be causing this issue or how I can fix it?
[1]: https://i.sstatic.net/V0MAX7Zt.png

Vocal Coach domain based AI scoring system / Web App, keeps giving a 10 out of 10 and 5 star rating consistently

My Web App

So I have two audio elements that are designed to compare against each other musically, utilizing dbs, gain, fundamental freq., key, harmonics, and pitch comparison. I’ve done this through utilizing the fourier series, using audio analyzers, promixety scores, as well implementing the circle of fifths to make sure to scale across all frequencies.

My Problem
It seems to be going through the whole algorithm but no matter what it keeps giving me a consistent 10 out of 10 and 5 star (my rating system), no matter if I play it with an identical vocal track or and off key key or pitch

The Algorithm (My Code Is Printed Right After)

**Frequency Score:**

fartist​: Average frequency of the artist’s chunk
fuserfuser​: Average frequency of the user's chunk

Frequency Scorei​=max(0.2,1−Frequency Tolerance∣fartist​−fuser​∣​)

The **Harmonic Score** I did the *same thing as above*

kartist​: Key of the artist's chunk
kuserkuser​: Key of the user's chunk

Distance between kartistkartist​ and kuserkuser​ in the Circle of Fifths, denoted as d(kartist,kuser)d(kartist​,kuser​)

**The Key Proximity Score uses the Circle of Fifths distance:**

Key Proximity Scorei=max⁡(0.2,1−0.1×d(kartist,kuser))
Key Proximity Scorei​=max(0.2,1−0.1×d(kartist​,kuser​))

Chunk Scorei​=(0.3×Frequency Scorei​)+(0.35×Harmonics Sco

rei​)+(0.35×Key Proximity Scorei​)

**Final Score:**

Final Score = min((n∑i=1n​Chunk Scorei​​)×10,10)

**Weighed values**
Harmonics=35%, Key=35%, Frequency=30%`

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');
        }
        
        @font-face {
            font-family: 'Sakana';
            src: url('fonts/Sakana.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;
        }
        .info {
            font-family: Arial;
            position: absolute;
            width: 320px;
            height: 180px; /* Adjusted height to fit the gain */
            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: Sakana;
            font-size: 26px;
        }
    </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>
            <select id='vocal-song'>
                <option>Example 1</option>
                <option>Example 2</option>
                <option>Example 3</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'>
                Bands: 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">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%;' src='samples/false_chord/alex_terrible/sample-1.mp3' controls></audio>
        </div>
        
        <!-- Updated divs for displaying audio info, including gain -->
        <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 id="gain-artist">Gain: </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 id="gain-user">Gain: </div>
        </div>
        <div id='lyrics'>
            <div style='margin-top: 20px;'>
                <center>Hell is right here! You've been abandoned, you've been abandoned! Hell is right here! Kingdom of storm and thunder</center>
                <br>
                <div id='score-result'></div>
            
            </div>
        </div>
    </div>

<script>
window.onload = function () {
    let isRecording = false;
    let mediaRecorder;
    let recordedChunks = [];
    const recordBtn = document.getElementById('recordBtn');
    const stopBtn = document.getElementById('stopBtn');
    const downloadBtn = document.getElementById('downloadBtn');
    const userAudio = document.getElementById('user-audio');
    const artistAudio = document.getElementById('artist-audio');
    const canvasArtist = document.getElementById('canvas-artist');
    const canvasUser = document.getElementById('canvas-user');
    const ctxArtist = canvasArtist.getContext('2d');
    const ctxUser = canvasUser.getContext('2d');
    
    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;

    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;

    let isArtistPlaying = false;
    let isUserPlaying = false;

    function calculateGain(dataArray) {
        return Math.max(...dataArray) / 255;
    }

    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}`;

        const gain = calculateGain(dataArray);
        document.getElementById(`gain-${infoPrefix}`).innerText = `Gain: ${gain.toFixed(2)}`;
    }

    const circleOfFifths = ["C", "G", "D", "A", "E", "B", "F#", "C#", "G#", "D#", "A#", "F"];
    
    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;
    }

    function getKeyProximityScore(artistKey, userKey) {
        const artistIndex = circleOfFifths.indexOf(artistKey);
        const userIndex = circleOfFifths.indexOf(userKey);

        if (artistIndex === -1 || userIndex === -1) return 0.2;

        const distance = Math.min(
            Math.abs(artistIndex - userIndex),
            12 - Math.abs(artistIndex - userIndex)
        );

        return Math.max(0.2, 1 - distance * 0.1);
    }

    function draw() {
        if (isArtistPlaying) {
            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);
            }

            calculateAudioSpecs(analyserArtist, dataArrayArtist, bufferLengthArtist, 'artist');
        }

        if (isUserPlaying) {
            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);
            }

            calculateAudioSpecs(analyserUser, dataArrayUser, bufferLengthUser, 'user');
        }

        if (isArtistPlaying || isUserPlaying) {
            requestAnimationFrame(draw);
        }
    }

    artistAudio.addEventListener('play', function () {
        isArtistPlaying = true;
        draw();
    });

    artistAudio.addEventListener('pause', function () {
        isArtistPlaying = false;
    });

    artistAudio.addEventListener('ended', function () {
        ctxArtist.clearRect(0, 0, canvasArtist.width, canvasArtist.height);
        isArtistPlaying = false;
    });

    userAudio.addEventListener('play', function () {
        isUserPlaying = true;
        draw();
    });

    userAudio.addEventListener('pause', function () {
        isUserPlaying = false;
    });

    userAudio.addEventListener('ended', function () {
        ctxUser.clearRect(0, 0, canvasUser.width, canvasUser.height);
        isUserPlaying = false;
    });

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

            mediaRecorder.ondataavailable = function (event) {
                recordedChunks.push(event.data);
            };

            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;
        }
    });

    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);
    });
};

let artistAudioChunks = [];
let userAudioChunks = [];
let isComparisonReady = false;

function resetAudioChunksForComparison() {
    artistAudioChunks = [];
    userAudioChunks = [];
    isComparisonReady = false;
    console.log("Chunks reset for new comparison.");
}

function processAudioChunks(analyser, bufferLength, dataArray) {
    const chunks = [];
    const interval = setInterval(() => {
        analyser.getByteFrequencyData(dataArray);
        chunks.push([...dataArray]);
    }, 100);
    return { stop: () => clearInterval(interval), getChunks: () => chunks };
}

function analyzeArtistAudio() {
    const artistAudio = document.getElementById('artist-audio');
    const context = new (window.AudioContext || window.webkitAudioContext)();
    const analyser = context.createAnalyser();
    const source = context.createMediaElementSource(artistAudio);
    source.connect(analyser);
    analyser.connect(context.destination);

    const processor = processAudioChunks(analyser, analyser.frequencyBinCount, new Uint8Array(analyser.frequencyBinCount));
    artistAudio.addEventListener('ended', () => {
        processor.stop();
        artistAudioChunks = processor.getChunks();
        console.log("Artist audio processing complete. Chunks collected:", artistAudioChunks.length);
        if (userAudioChunks.length > 0) isComparisonReady = true;
    });
}

function analyzeUserAudio() {
    const userAudio = document.getElementById('user-audio');
    const context = new (window.AudioContext || window.webkitAudioContext)();
    const analyser = context.createAnalyser();
    const source = context.createMediaElementSource(userAudio);
    source.connect(analyser);
    analyser.connect(context.destination);

    const processor = processAudioChunks(analyser, analyser.frequencyBinCount, new Uint8Array(analyser.frequencyBinCount));
    userAudio.addEventListener('ended', () => {
        processor.stop();
        userAudioChunks = processor.getChunks();
        console.log("User audio processing complete. Chunks collected:", userAudioChunks.length);
        if (artistAudioChunks.length > 0) isComparisonReady = true;
    });
}
// Circle of Fifths array
const circleOfFifths = ["C", "G", "D", "A", "E", "B", "F#", "C#", "G#", "D#", "A#", "F"];

// Function to calculate key proximity based on the Circle of Fifths
function getKeyProximityScore(artistKey, userKey) {
    const artistIndex = circleOfFifths.indexOf(artistKey);
    const userIndex = circleOfFifths.indexOf(userKey);

    // If either key is not found in the Circle of Fifths, return a minimal score
    if (artistIndex === -1 || userIndex === -1) return 0.2;

    // Calculate the minimum distance on the Circle of Fifths (wrap-around)
    const distance = Math.min(
        Math.abs(artistIndex - userIndex),
        12 - Math.abs(artistIndex - userIndex)
    );

    // Scale proximity to range [1.0, 0.2] based on distance (exact match = 1.0, max distance = 0.2)
    return Math.max(0.2, 1 - distance * 0.1);
}

// 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;
}

function calculateFinalScore() {
    if (!isComparisonReady) {
        alert('Play both audios completely before comparing.');
        return;
    }

    let totalFrequencyScore = 0, totalHarmonicsScore = 0, totalKeyScore = 0;
    const minChunks = Math.min(artistAudioChunks.length, userAudioChunks.length);
    const minChunkScore = 0.2;

    for (let i = 0; i < minChunks; i++) {
        const artistData = artistAudioChunks[i];
        const userData = userAudioChunks[i];

        const avgArtistFreq = artistData.reduce((a, b) => a + b, 0) / artistData.length;
        const avgUserFreq = userData.reduce((a, b) => a + b, 0) / userData.length;

        const freqDiff = Math.abs(avgArtistFreq - avgUserFreq);
        let freqScore = Math.max(0, 1 - (freqDiff / 1500));
        freqScore = Math.max(freqScore, minChunkScore);
        totalFrequencyScore += freqScore * 0.3;

        const artistHarmonics = Math.max(...artistData) / 255;
        const userHarmonics = Math.max(...userData) / 255;
        const harmonicsDiff = Math.abs(artistHarmonics - userHarmonics);
        let harmonicsScore = Math.max(0, 1 - (harmonicsDiff / 1.5));
        harmonicsScore = Math.max(harmonicsScore, minChunkScore);
        totalHarmonicsScore += harmonicsScore * 0.35;

        const artistKey = determineKey(avgArtistFreq);
        const userKey = determineKey(avgUserFreq);
        const keyProximityScore = getKeyProximityScore(artistKey, userKey);
        totalKeyScore += Math.max(keyProximityScore, minChunkScore) * 0.35;
    }

    const finalScore = Math.min(Math.ceil((totalFrequencyScore + totalHarmonicsScore + totalKeyScore) / minChunks * 10), 10);
    displayFinalScore(finalScore);
}

function displayFinalScore(score) {
    let starRating = '★☆☆☆☆';
    if (score >= 9) starRating = '★★★★★';
    else if (score >= 7) starRating = '★★★★☆';
    else if (score >= 5) starRating = '★★★☆☆';
    else if (score >= 3) starRating = '★★☆☆☆';

    document.getElementById('score-result').innerHTML = `Score: ${score}/10 <br> Rating: ${starRating}`;
}

document.getElementById('compareBtn').addEventListener('click', calculateFinalScore);
document.getElementById('artist-audio').addEventListener('play', analyzeArtistAudio);
document.getElementById('user-audio').addEventListener('play', analyzeUserAudio);
</script>




</body>
</html>

I’ve tried alerting and logging throughout all of my code, I’ve adjusted the weights and normalization of the calculations but in my opinion I think it’s the way the scoring system is handling everything because no matter what I adjust the Score stays at a 10/10 5-star rating.

I’ve tried looking for errors and logs, none found and usually appears everything is running

I’ve tried messing around using and comparing identical audio files as well as different samples that don’t match, and my own recordings. So when I’m hitting notes that don’t match the vocal track I still recieve a high score.

What I’m expecting is, I’m expecting that notes that are matching or close to matching as well as harmonics, and frequency will result in a higher score while the opposite resulting in a lower score based off the algorithm.

bootstrap v5.3 modal not closing dynamically but closes dynamically with other submissions

I have a bootstrap modal which has an id=”dynModal”. I dynamically add the content to dynModal using jquery and after the action or ajax request is completed successfully the modal gets emptied and then executes code to then close it. The issue is that it works with certain buttons that executes the modal and then does not work at all for other buttons.

$(function () {
    var dynModal = new bootstrap.Modal(document.getElementById('dynModal'), { backdrop: 'static' });

$("body").on("click", ".editProxyHost", function(e) {
    $("#dynModal .modal-dialog").addClass("modal-lg");
    $("#modalTitle").empty().append("Edit Proxy Host");
    $.ajax({
        headers: {
            'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr("content")
        },
        type: 'POST',
        url: '/url/fetch',
        dataType: "json",
        data: {
            hostID: $(this).attr("data-host-id")
        },
        success: function(response) {
            $("#dynModal .modal-dialog").addClass("modal-lg");            
            $("#dynModal .modal-body").empty().append(`
                <form action="javascript:void(0);" id="proxyHostForm" method="POST">
                    // formdata
                </form>
            `);
            $("#dynModal .modal-footer").empty().append(`
                <button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">Cancel</button>
                <button type="submit" id="saveModal" data-mode="updateProxyHost" class="btn btn-success">Save</button>
            `);
            dynModal.show();
        },
        error: function(response) {
            // Handle error response
            console.error('Error:', response);
            alert('An error occurred while submitting the form. Please try again.');
        }
    });
});

$("body").on("click", "#saveModal", function(e) {
    switch ($(this).attr("data-mode")) {
        case 'editProxyHost':
            var form = $("#proxyHostForm");
            var formData = form.serializeArray();
            if (form[0].reportValidity()) {
                var serializedData = $.param(formData);

                $.ajax({
                    headers: {
                        'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr("content")
                    },
                    type: 'POST',
                    url: '/url',
                    dataType: "json",
                    data: serializedData,
                    success: function(response) {
                        console.log(response);
                        const modalInstance = bootstrap.Modal.getInstance("#dynModal");
                        modalInstance.hide();
                        $("#modalTitle").empty();
                        $("#dynModal .modal-body").empty();
                        $("#dynModal .modal-footer").empty();
                    },
                    error: function(response) {
                        console.error('Error:', response);
                        alert('An error occurred while submitting the form. Please try again.');
                    }
                });
            } else {
                let firstInvalidElement = form.find(':invalid').first();
                let firstInvalidTabPane = firstInvalidElement.closest(".tab-pane");
                let firstInvalidTabId = firstInvalidTabPane.attr("id");
                let firstInvalidTabTrigger = document.querySelector(`button[data-bs-target="#${firstInvalidTabId}"]`);
                if (firstInvalidTabTrigger) {
                    let tabInstance = new bootstrap.Tab(firstInvalidTabTrigger);
                    tabInstance.show();
                }
                form[0].reportValidity();
            }
            break;
    }
});
});

This is one of the modals that does not close after it saves but it empties the modal.

I use this method for quite a few modals and they all close except for this one:

The following just refuses to execute:

const modalInstance = bootstrap.Modal.getInstance("#dynModal");
modalInstance.hide();

The modal should simply close then empty but this one just does not. I have other buttons that trigger the same modal and after #saveModal is clicked and the ajax forms response is successful they close the modal dynamically except for this one.

Accessing iFrame within iFrame with webdriver, JS

Simply put, for some reason the site I’m working with has set up this section of inputs as follows:

<iframe title="parentIframe">
#document (https://www.website.com)
    <!DOCTYPE html>
    <html lang="en">
        <head></head>
        <body>
            <div id="root">
                <div id="firstDiv">
                    ... //the iframes are within an arbitrary number of divs
                    <iframe title="firstChildIframe">
                        #document (https://www.website.com/subsite1)
                            <!DOCTYPE html>
                            <html lang="en">
                                <head></head>
                                <body>
                                    <input name="firstInput" />
                                </body>
                            </html>
                    </iframe>
                    ...
                </div>
                <div id="secondDiv">
                    ...
                    <iframe title="secondChildIframe">
                        #document (https://www.website.com/subsite2)
                            <!DOCTYPE html>
                            <html lang="en">
                                <head></head>
                                <body>
                                    <input name="secondInput" />
                                </body>
                            </html>
                    </iframe>
                    ...
                </div>
                <div id="thirdDiv">
                    ...
                    <iframe title="thirdChildIframe">
                        #document (https://www.website.com/subsite3)
                            <!DOCTYPE html>
                            <html lang="en">
                                <head></head>
                                <body>
                                    <input name="thirdInput" />
                                </body>
                            </html>
                    </iframe>
                    ...
                </div>
            </div>
        </body>
    </html>
</iframe>

For automated testing, we are using some fork of webdriver with nodeJS, and I have hit a wall.

I have tried using this.focusFrame() and browser.switchToFrame() with //iframe[@title="____ChildIframe"] and iframe[title="____ChildIframe"], both of which work in the Inspect/Elements search bar of Chrome, but I just can’t seem to find a way to make this work.

Once inside the parent iframe using this.focusFrame('//iframe[@title="parentIframe"]'), the runner stays frozen and doesn’t do anything, probably looking for the first iframe child on a loop and never finding it. I have no idea what I’m missing. Perhaps, since the iFrame contents are being loaded in a different site or are part of a different HTML, the runner doesn’t know what to do? What am I missing?

Thanks for your help!

How to solve not changing page when activate a tab in sidebar

I am new to HTML and JS and have this dashboard with a sidebar but I could not change the page when I click on next tab, for example it shows empty page when I click on analytics. Please help me so I can add my charts in analytics tab and other tabs.
I use chart js for charts and have styles.css file

// Function to change content
function changeContent(tabName) {
  // Hide all tab contents
  var tabPanes = document.querySelectorAll('.tab-pane');
  tabPanes.forEach(pane => {
    pane.classList.remove('active');
    pane.style.display = 'none';
  });

  // Show the clicked tab
  var activePane = document.getElementById(tabName);
  if (activePane) {
    activePane.classList.add('active');
    activePane.style.display = 'block';

    // If it's the analytics tab and it's empty, load the content
    if (tabName === 'analytics' && activePane.innerHTML.trim() === '') {
      loadAnalyticsContent();
    }
  }

  // Remove active class from all buttons
  var tabButtons = document.querySelectorAll('.tab-button');
  tabButtons.forEach(button => button.classList.remove('active'));

  // Add active class to the clicked button
  var activeButton = document.querySelector(`.tab-button[data-tab="${tabName}"]`);
  if (activeButton) {
    activeButton.classList.add('active');
  }
}

// Tab functionality
const tabButtons = document.querySelectorAll('.sidebar a');

tabButtons.forEach(button => {
  button.addEventListener('click', function(e) {
    e.preventDefault();
    const tabId = this.getAttribute('data-tab');
    if (tabId) {
      changeContent(tabId);
    }
  });
});
<main>
  <div id="dashboard" class="tab-pane active">
    <h1>Dashboard</h1>
    <div class="analyse">
      <div class="sales">
        <div class="status">
          <div class="info">
            <h3>Total Sales</h3>
            <h1>$65,024</h1>
          </div>
          <div class="progresss">
            <svg>
                                <circle cx="38" cy="38" r="36"></circle>
                            </svg>
            <div class="percentage">
              <p>+81%</p>
            </div>
          </div>
        </div>
      </div>
      <div id="users" class="tab-pane">
        <h1>Users</h1>
        <!-- Users content -->
      </div>
      <div id="history" class="tab-pane">
        <h1>History</h1>
        <!-- History content -->
      </div>
      <div id="analytics" class="tab-pane">
        <h2>Analytics Dashboard</h2>
        <div id="date-range-picker">
          <input type="date" id="start-date">
          <input type="date" id="end-date">
          <button id="apply-date-range">Apply</button>
        </div>
        <div class="chart-container">
          <canvas id="user-activity-chart"></canvas>
        </div>
        <div class="chart-container">
          <canvas id="revenue-chart"></canvas>
        </div>
      </div>
</main>