Node-OPCUA Issue: ‘Acknowledge Method Not Found’ Error with Alarm Acknowledgment Functions

I am working with Node-OPCUA as an OPC UA client to interact with a Codesys PLC. I’m using node-opcua version 2.115.0 on an ASUS ZenBook, running Windows 11 Pro, version 10.0.22631 Build 22631. My goal is to acknowledge and confirm alarms from my OPC UA server.

• Current Problem:

I successfully connect to my local Codesys PLC, can see and modify values, and view alarms and their current status. However, when trying to use the acknowledgeCondition or confirmCondition functions to acknowledge an alarm, I encounter an error stating: “Error: cannot find Acknowledge Method”. This is perplexing as I am passing the same values (‘ConditionId’ and ‘EventId’) that EventMonitor.on() provides me.

Expected Behavior:

The alarms should be acknowledged and reflected in my Codesys PLC. With UAExpert, I can see my alarms and acknowledge and confirm them without issues, leading me to believe the error lies within node-opcua.

Code:
`

    import express from "express";
    import { createServer } from 'node:http';
    import { AttributeIds, OPCUAClient, TimestampsToReturn, constructEventFilter, ObjectIds } from "node-opcua";
                                                                                              
    const app = express();
    const server = createServer(app);

    const URL = "opc.tcp://ADRIAN-ASUS:4840";

    (async () => {
    try {
         const client = OPCUAClient.create();
        client.on("backoff", (retry, delay) => {
         console.log("Retying to connect to ", URL, " attempt ", retry);
        });
   
    console.log("connecting to ", URL);
    await client.connect(URL);
    console.log("connected to ", URL);

   const session = await client.createSession();
    console.log("session initialized");

    const subscripcion = await session.createSubscription2({
        requestedPublishingInterval: 50,
        requestedMaxKeepAliveCount: 20,
        publishingEnabled: true,
    });

    const fields = [
        "EventId",
        "AckedState",
        "AckedState.Id",
        "ConfirmedState",
        "ConfirmedState.Id",
        "ConditionId",
    ];

    const eventFilter = constructEventFilter(fields);

    const itemToMonitor = {
        nodeId: ObjectIds.Server,
        attributeId: AttributeIds.EventNotifier,
    };

    const parameters = {
        filter: eventFilter,
        discardOldest: true,
        queueSize: 100,
    };

    const EventMonitor = await subscripcion.monitor(
        itemToMonitor,
        parameters,
        TimestampsToReturn.Both
    )

    const alarmData = {
    }

    EventMonitor.on("changed", (events) => {
        for (let i = 0; i < events.length; i++) {
            alarmData[fields[i]] = events[i].value
        }
    });

    setTimeout( async () => {

        try {
            const comment = 'Comment random';

            console.log({conditionId: alarmData.ConditionId, eventId: alarmData.EventId})

            session.acknowledgeCondition(alarmData.ConditionId, alarmData.EventId, comment, (err) => {
                console.log({ err })
            }) 
        } catch (error) {
            console.log(error)
        }

    }, 5000)



    let running = true;
    process.on("SIGINT", async () => {
        if (!running) {
            return; // avoid calling shutdown twice
        }
        console.log("shutting down client");
        running = false;
        await subscripcion.terminate();
        await session.close();
        await client.disconnect();
        console.log("Done");
        process.exit(0);
    });
} catch (error) {
    console.log("ERROR: ", error.message);
    console.log(error);
}

server.listen(4000, () => {
    console.log('server running at http://localhost:4000');
})
     })()`

• Errors and Logs:

Error when attempting to acknowledge the alarm:
Error Log

Output of console.log showing the ‘conditionId’ and ‘eventId’ values:
Console.log conditionId and eventId data

Additional Information:

• I have installed node-opcua as a package using npm.
• Using Node 20.10.0
• I am attempting to connect to an OPCUA system: CODESYS Control Win V3 x64, version 3.5.19.3 (x64).

Try downloading all the previous versions of node.

Check if children components have their own children in React Native

I was trying to check if the children (AssetExample2) of my parent (AssetExample) component have their own children. I would use this pattern for the splashscreen of the app that I’m building to hide when children have loaded but I can’t seem to make it work as the state hasChildren that I created always returns false what am I doing wrong here?

Snack runnable sample code

enter image description here

// App.js

import { Text, SafeAreaView, StyleSheet } from 'react-native';

import { Card } from 'react-native-paper';

import AssetExample from './components/AssetExample';
import AssetExample2 from './components/AssetExample2';

export default function App() {
  return (
    <SafeAreaView>
      <Text>
        I don't have children
      </Text>
      <Card>
        <AssetExample>
          <AssetExample2 />
        </AssetExample>
      </Card>
    </SafeAreaView>
  );
}
// AssetExample

import React, { useState, useEffect } from 'react';
import { Text, View, StyleSheet, Image } from 'react-native';

export default function AssetExample({children}) {
  const [hasChildren, setHasChildren] = useState(false);

  useEffect(() => {
    React.Children.forEach(children, (child) => {
    if (!React.isValidElement(child)) {
      if (child.props.children) {
        setHasChildren(true);
      }
    }
  });
  }, [children]);

  return (hasChildren && 
    <View>
      <Text>
        I have children
      </Text>
    </View>
  );
}
// AssetExample2

import { Text, View } from 'react-native';

export default function AssetExample2() {
  return (<View><Text>I exist</Text></View>);
}

Browser fetch api with async/ await still download large files in parallel

I have met a weird behavior of async/await browser fetch API with large file such as:

  • When using async/ await with fetch api to call rest api → the code is executed sequentially
await fetch("https://jsonplaceholder.typicode.com/todos/1");
console.log("res 1");
await fetch("https://jsonplaceholder.typicode.com/todos/1");
console.log("res 2");
await fetch("https://jsonplaceholder.typicode.com/todos/1");
console.log("res 3");

apis are fetched sequentially (view in Network tab) → it means that the second api just run after the first one is finished, etc …

I also test this behavior by slowing down network → console.log is also executed with the latter wait the former finish.

But

  • When using async/ await with fetch api to download large files → the code is also executed sequentially but the browser fetch (download) files in parallel.
await fetch(
"http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4");
console.log("fetch 1");

await fetch(
"http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ElephantsDream.mp4");

console.log("fetch 2");

await fetch("http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerBlazes.mp4");
console.log("fetch 3");

The weird thing is browser fetch api does not wait until the fetch done:

  • The console.log are print almost immediately (it works as if the await keyword is ignored).

  • Tab network in debug tool show that these files are fetched (downloaded) in parrallel.

P/s: I also test with axios and this library work OK (in both cases the api is just executed after the previous one done)

Need help regarding drag n drop in react-native

I’m looking for assistance with implementing drag-and-drop functionality, including an extra condition for dropping items onto specific locations. While I’ve made progress, I believe there’s room for improvement. Any guidance you can offer would be greatly appreciated as I work towards completing this screen. Thank you in advance.

drag n drop screen for an idea

import { View, Text, SafeAreaView, ImageBackground,StatusBar,Image,Dimensions, TouchableOpacity,ScrollView, FlatList, Animated,  PanResponder } from 'react-native'
import React,{useState,useContext, useRef} from 'react'
import themeContext from '../theme/themeContex';
import { useNavigation } from '@react-navigation/native';
import BackButton from './Componants/BackButton';
import Header from './Componants/Header';
import {DraxView, DraxProvider } from 'react-native-drax';
import { GestureHandlerRootView } from 'react-native-gesture-handler';

const width =Dimensions.get('screen').width
const height = Dimensions.get('screen').height




export default function VowelSounds() {
  

  const theme = useContext(themeContext);
  const navigation= useNavigation();
  const [darkMode,setDarkMode] = useState(false)


  const [animatedValue] = useState(new Animated.ValueXY({ x: 0, y: 0 }));

  const handleDrop = (payload, gestureState) => {
    
    console.log('Drop event triggered with payload:', payload, gestureState);
    
    // Update the animated position on drop
   if (gestureState) {
      const { moveX, moveY } = gestureState;
      // Update the animated position on drop
      Animated.spring(animatedValue, {
        toValue: { x:-19, y: -210.53425 },
        useNativeDriver: true,
      }).start();
    }
  };
  const [animatedValue2] = useState(new Animated.ValueXY({ x: 0, y: 0 }));
  const handleDrop2 = (payload, gestureState) => {
    
    console.log('Drop event triggered with payload:', payload, gestureState);
    
    // Update the animated position on drop
   if (gestureState) {
      const { moveX, moveY } = gestureState;
      // Update the animated position on drop
      Animated.spring(animatedValue2, {
        toValue: { x:-170, y: -270.53425 },
        useNativeDriver: true,
      }).start();
    }
  };
  const [animatedValue3] = useState(new Animated.ValueXY({ x: 0, y: 0 }));
  const handleDrop3 = (payload, gestureState) => {
    
    console.log('Drop event triggered with payload:', payload, gestureState);
    
    // Update the animated position on drop
   if (gestureState) {
      const { moveX, moveY } = gestureState;
      // Update the animated position on drop
      Animated.spring(animatedValue3, {
        toValue: { x:-20, y: -180.53425 },
        useNativeDriver: true,
      }).start();
    }
  };
  const [animatedValue4] = useState(new Animated.ValueXY({ x: 0, y: 0 }));
  const handleDrop4 = (payload, gestureState) => {
    
    console.log('Drop event triggered with payload:', payload, gestureState);
    
    // Update the animated position on drop
   if (gestureState) {
      const { moveX, moveY } = gestureState;
      // Update the animated position on drop
      Animated.spring(animatedValue4, {
        toValue: { x:-10, y: -130.53425 },
        useNativeDriver: true,
      }).start();
    }
  };
  const [animatedValue5] = useState(new Animated.ValueXY({ x: 0, y: 0 }));
  const handleDrop5 = (payload, gestureState) => {
    
    console.log('Drop event triggered with payload:', payload, gestureState);
    
    // Update the animated position on drop
   if (gestureState) {
      const { moveX, moveY } = gestureState;
      // Update the animated position on drop
      Animated.spring(animatedValue5, {
        toValue: { x:10, y: -270.53425 },
        useNativeDriver: true,
      }).start();
    }
  };
  const [animatedValue6] = useState(new Animated.ValueXY({ x: 0, y: 0 }));
  const handleDrop6 = (payload, gestureState) => {
    
    console.log('Drop event triggered with payload:', payload, gestureState);
    
    // Update the animated position on drop
   if (gestureState) {
      const { moveX, moveY } = gestureState;
      // Update the animated position on drop
      Animated.spring(animatedValue6, {
        toValue: { x:95, y: -210.53425 },
        useNativeDriver: true,
      }).start();
    }
  };
  const [animatedValue7] = useState(new Animated.ValueXY({ x: 0, y: 0 }));
  const handleDrop7 = (payload, gestureState) => {
    
    console.log('Drop event triggered with payload:', payload, gestureState);
    
    // Update the animated position on drop
   if (gestureState) {
      const { moveX, moveY } = gestureState;
      // Update the animated position on drop
      Animated.spring(animatedValue7, {
        toValue: { x:-70, y: -130.53425 },
        useNativeDriver: true,
      }).start();
    }
  };
  const [animatedValue8] = useState(new Animated.ValueXY({ x: 0, y: 0 }));
  const handleDrop8 = (payload, gestureState) => {
    
    console.log('Drop event triggered with payload:', payload, gestureState);
    
    // Update the animated position on drop
   if (gestureState) {
      const { moveX, moveY } = gestureState;
      // Update the animated position on drop
      Animated.spring(animatedValue8, {
        toValue: { x:175, y: -190.53425 },
        useNativeDriver: true,
      }).start();
    }
  };
    return (
    <GestureHandlerRootView style={{flex:1}}>
      <SafeAreaView style={{flex:1, paddingTop:25}}>
              
        

        <ImageBackground source={require('../../assets/image/read.png')}
        style={{flex:1}}>
          <StatusBar backgroundColor={"#C2EEFF"} translucent={true}/>
      
            <Header />
            <ScrollView>
              <View style={{paddingHorizontal:20}}>
                <Text style={{fontFamily:'BADABB', fontSize:21, color:'#E51F5C', textAlign:'center', width:'100%', letterSpacing:1, lineHeight:21,}}>Level 01</Text>
                <Text style={{fontFamily:'BADABB', fontSize:21, color:'#E51F5C', textAlign:'center', width:'100%', letterSpacing:1, lineHeight:21, marginBottom:15,}}>Aa and Ee Vowel Sounds</Text>
                <Text style={{fontFamily:'Cheesecake', fontSize:14, color:'#000', textAlign:'center', width:'100%', letterSpacing:1, lineHeight:14,}}>Match the pictures of these vowels to their correct words and boxes! </Text>
              </View>
              <DraxProvider>
              <View style={{flexDirection:'row', justifyContent:'space-between', paddingHorizontal:20, marginTop:25,}}>
                  <View  style={{width:'47%', }} >
                    <ImageBackground style={{paddingHorizontal:15, paddingVertical:20,}} source={require('../../assets/image/vs.png')} resizeMode='stretch'>
                      <Text style={{fontFamily:'Cheesecake', fontSize:14, color:'#000', textAlign:'center', width:'100%', letterSpacing:1, lineHeight:14,}}>Short Aa</Text>
                      <View style={{flexDirection:'row', justifyContent:'space-around', flexWrap:'wrap', marginTop:10}}>
                          <View style={{width:'46%', borderWidth:1, borderColor:'#000', height:80, padding:5, marginBottom:5}}>
                            <Text style={{fontFamily:'Cheesecake', fontSize:14, color:'#000', textAlign:'center', width:'100%', letterSpacing:1, lineHeight:14,}}>Cat</Text>
                            {/* <Image source={require('../../assets/image/cat2.png')}  style={{alignSelf:'center'}}/> */}
                            
                                <DraxView
                                  style={{height:60,}}
                                  payloadTarget={['cat']}
                                  onReceiveDragDrop={({ dragged: { payload }, ...gestureState }) => handleDrop(payload, gestureState)}
                                >
                                  
                                </DraxView>
                              
                          </View>
                          <View style={{width:'46%', borderWidth:1, borderColor:'#000', height:80, padding:5, marginBottom:5}}>
                            <Text style={{fontFamily:'Cheesecake', fontSize:14, color:'#000', textAlign:'center', width:'100%', letterSpacing:1, lineHeight:14,}}>Fan</Text>
                            
                                <DraxView
                                  style={{height:60,}}
                                  payloadTarget={['fan']}
                                  onReceiveDragDrop={({ dragged: { payload }, ...gestureState }) => handleDrop2(payload, gestureState)}
                                >
                                  
                                </DraxView>
                              
                          </View>
                          <View style={{width:'46%', borderWidth:1, borderColor:'#000', height:80, padding:5}}>
                            <Text style={{fontFamily:'Cheesecake', fontSize:14, color:'#000', textAlign:'center', width:'100%', letterSpacing:1, lineHeight:14,}}>Jam</Text>
                            
                                <DraxView
                                  style={{height:60,}}
                                  payloadTarget={['jam']}
                                  onReceiveDragDrop={({ dragged: { payload }, ...gestureState }) => handleDrop3(payload, gestureState)}
                                >
                                  
                                </DraxView>
                              
                          </View>
                          <View style={{width:'46%', borderWidth:1, borderColor:'#000', height:80, padding:5}}>
                            <Text style={{fontFamily:'Cheesecake', fontSize:14, color:'#000', textAlign:'center', width:'100%', letterSpacing:1, lineHeight:14,}}>Bat</Text>
                            
                            <DraxView
                                  style={{height:60,}}
                                  payloadTarget={['bat']}
                                  onReceiveDragDrop={({ dragged: { payload }, ...gestureState }) => handleDrop4(payload, gestureState)}
                                >
                                  
                                </DraxView>
                              
                          </View>
                      </View>
                    </ImageBackground>
                  </View>
                  <View  style={{width:'47%', }} >
                    <ImageBackground style={{paddingHorizontal:15, paddingVertical:20,}} source={require('../../assets/image/vs.png')} resizeMode='stretch'>
                      <Text style={{fontFamily:'Cheesecake', fontSize:14, color:'#000', textAlign:'center', width:'100%', letterSpacing:1, lineHeight:14,}}>Long Aa</Text>
                      <View style={{flexDirection:'row', justifyContent:'space-around', flexWrap:'wrap', marginTop:10}}>
                          <View style={{width:'46%', borderWidth:1, borderColor:'#000', height:80, padding:5, marginBottom:5}}>
                            <Text style={{fontFamily:'Cheesecake', fontSize:14, color:'#000', textAlign:'center', width:'100%', letterSpacing:1, lineHeight:14,}}>Drain</Text>
                            
                            <DraxView
                                  style={{height:60,}}
                                  payloadTarget={['drain']}
                                  onReceiveDragDrop={({ dragged: { payload }, ...gestureState }) => handleDrop5(payload, gestureState)}
                                >
                                  
                                </DraxView>
                              
                          </View>
                          <View style={{width:'46%', borderWidth:1, borderColor:'#000', height:80, padding:5, marginBottom:5}}>
                            <Text style={{fontFamily:'Cheesecake', fontSize:14, color:'#000', textAlign:'center', width:'100%', letterSpacing:1, lineHeight:14,}}>Cake</Text>
                            
                            <DraxView
                                  style={{height:60,}}
                                  payloadTarget={['cake']}
                                  onReceiveDragDrop={({ dragged: { payload }, ...gestureState }) => handleDrop6(payload, gestureState)}
                                >
                                  
                                </DraxView>
                              
                          </View>
                          <View style={{width:'46%', borderWidth:1, borderColor:'#000', height:80, padding:5}}>
                            <Text style={{fontFamily:'Cheesecake', fontSize:14, color:'#000', textAlign:'center', width:'100%', letterSpacing:1, lineHeight:14,}}>Rain</Text>
                            
                            <DraxView
                                  style={{height:60,}}
                                  payloadTarget={['rain']}
                                  onReceiveDragDrop={({ dragged: { payload }, ...gestureState }) => handleDrop7(payload, gestureState)}
                                >
                                  
                                </DraxView>
                              
                          </View>
                          <View style={{width:'46%', borderWidth:1, borderColor:'#000', height:80, padding:5}}>
                            <Text style={{fontFamily:'Cheesecake', fontSize:14, color:'#000', textAlign:'center', width:'100%', letterSpacing:1, lineHeight:14,}}>Lake</Text>
                            
                            <DraxView
                                  style={{height:60,}}
                                  payloadTarget={['lake']}
                                  onReceiveDragDrop={({ dragged: { payload }, ...gestureState }) => handleDrop8(payload, gestureState)}
                                >
                                  
                                </DraxView>
                              
                          </View>
                      </View>
                    </ImageBackground>
                  </View>
                  
              </View>
              <View style={{paddingHorizontal:20, marginTop:35,}}>
                  <ImageBackground style={{ paddingVertical:25,  paddingHorizontal:20}} source={require('../../assets/image/vs2.png')} resizeMode='stretch' >
                        <View style={{flexDirection:'row', justifyContent:'space-around', flexWrap:'wrap', marginTop:10}}>
                            <View style={{width:'23%', alignContent:'center', alignItems:'center',  height:55, padding:5, marginBottom:5}}>
                              
                                <DraxView onDragStart={() => console.log('Cat drag started')}  payload="cat"  style={{position: 'absolute',
                transform: [{ translateX: animatedValue.x }, { translateY: animatedValue.y }]}} >
                                 
                                    <Image source={require('../../assets/image/cat2.png')}  />
                                 
                                  </DraxView>
                              
                            </View>
                            <View style={{width:'23%', alignContent:'center', alignItems:'center',  height:55, padding:5, marginBottom:5}}>
                              
                                  <DraxView onDragStart={() => console.log('Bat drag started')}  payload="bat" style={{position: 'absolute',
                transform: [{ translateX: animatedValue4.x }, { translateY: animatedValue4.y }]}}> 
                                    <Image source={require('../../assets/image/bat.png')}  />
                                  </DraxView>
                              
                            </View>
                            <View style={{width:'25%', alignContent:'center', alignItems:'center',  height:55, padding:5}}>
                              
                                <DraxView onDragStart={() => console.log('Cake drag started')}  payload="cake" style={{position: 'absolute',
                transform: [{ translateX: animatedValue6.x }, { translateY: animatedValue6.y }]}}>
                                  <Image source={require('../../assets/image/cake.png')}  />
                                </DraxView>
                              
                            </View>
                            <View style={{width:'23%', alignContent:'center', alignItems:'center',  height:55, padding:5}}>
                              
                                <DraxView onDragStart={() => console.log('Rain drag started')}  payload="rain" style={{position: 'absolute',
                transform: [{ translateX: animatedValue7.x }, { translateY: animatedValue7.y }]}}>
                                  <Image source={require('../../assets/image/rain.png')}  />
                                </DraxView>
                              
                            </View>
                            <View style={{width:'23%', alignContent:'center', alignItems:'center',  height:55, padding:5, marginBottom:5}}>
                              
                                <DraxView onDragStart={() => console.log('Jam drag started')}  payload="jam" style={{position: 'absolute',
                transform: [{ translateX: animatedValue3.x }, { translateY: animatedValue3.y }]}}>
                                  <Image source={require('../../assets/image/jam.png')}  />
                                </DraxView>
                              
                            </View>
                            <View style={{width:'23%', alignContent:'center', alignItems:'center',  height:55, padding:5, marginBottom:5}}>
                              
                                  <DraxView onDragStart={() => console.log('Lake drag started')}  payload="lake" style={{position: 'absolute',
                transform: [{ translateX: animatedValue8.x }, { translateY: animatedValue8.y }]}}>
                                    <Image source={require('../../assets/image/lake.png')} />
                                  </DraxView>
                              
                            </View>
                            <View style={{width:'23%', alignContent:'center', alignItems:'center',  height:55, padding:5}}>
                              
                                  <DraxView onDragStart={() => console.log('Drain drag started')}  payload="drain" style={{position: 'absolute',
                transform: [{ translateX: animatedValue5.x }, { translateY: animatedValue5.y }]}}>
                                    <Image source={require('../../assets/image/drain.png')}  />
                                  </DraxView>
                              
                            </View>
                            <View style={{width:'23%', alignContent:'center', alignItems:'center',  height:55, padding:5}}>
                              
                                  <DraxView onDragStart={() => console.log('Fan drag started')}  payload="fan" style={{position: 'absolute',
                transform: [{ translateX: animatedValue2.x }, { translateY: animatedValue2.y }]}}>
                                    <Image source={require('../../assets/image/fan.png')} />
                                  </DraxView>
                              
                            </View>
                        </View>
                  </ImageBackground>
              </View>
              </DraxProvider>
            </ScrollView>

            <View style={{flex:1, paddingHorizontal:20, marginBottom:30}}>
                  
            </View>
            <BackButton style={{width:'100%',}}/>
        </ImageBackground>
              
      </SafeAreaView>
    </GestureHandlerRootView>
  )
}

React having problems with rendering two mapped arrays to the page

Very new react user here. I am making a react app that displays albums from the spotify API. The problem is when you hit the search genre button it works and then when you hit the search new music button it works BUT when you try to use the search genre button again nothing happens. My code is probably very rough but here it is.

import { useEffect, useState } from "react";
import "./App.css";

const CLIENT_ID = "2a65aa062a2948b09f7af884b5447c3d";
const CLIENT_SECRET = "e93fd764678a4ebe97accd512e302219";

function App() {
  const [accessToken, setAcessToken] = useState("");
  const [albums, setAlbums] = useState([]);
  const [genreAlbums, setGenreAlbums] = useState([]);
  const [searchInput, setSearchInput] = useState("");

  useEffect(() => {
    // API Acess Token
    var authParameters = {
      method: "POST",
      headers: {
        "content-type": "application/x-www-form-urlencoded",
      },
      body:
        "grant_type=client_credentials&client_id=" +
        CLIENT_ID +
        "&client_secret=" +
        CLIENT_SECRET,
    };
    fetch("https://accounts.spotify.com/api/token", authParameters)
      .then((result) => result.json())
      .then((data) => setAcessToken(data.access_token));
  }, []);

  // Get new music
  async function search() {
    var newAlbums = await fetch(
      "https://api.spotify.com/v1/browse/new-releases",
      {
        headers: {
          Authorization: "Bearer " + accessToken,
        },
      }
    )
      .then((response) => response.json())
      .then((data) => setAlbums(data.albums.items));
  }

  // Get specific genre
  async function searchGenre() {
    var newAlbumsGenre = await fetch(
      'https://api.spotify.com/v1/search?type=track&q=genre:"' +
        searchInput +
        '"&limit=50',
      {
        headers: {
          Authorization: "Bearer " + accessToken,
        },
      }
    )
      .then((response) => response.json())
      .then((data) => setGenreAlbums(data.tracks.items));
    console.log(genreAlbums);
  }

  return (
    <div className="App">
      <div>
        <button className="button" type="button" onClick={search}>
          Search for new music!
        </button>
        <form className="form">
          <input
            type="text"
            id="genre"
            autoComplete="off"
            onChange={(event) => setSearchInput(event.target.value)}
          />
        </form>
        <button className="genreButton" type="button" onClick={searchGenre}>
          Search Genre
        </button>
      </div>

      <div>
        {albums.map((album, i) => {
          return (
            <div className="card" key={i}>
              <img src={album.images[0].url} alt="alt text" />
              <div className="container">
                <h4>
                  <b>{album.name}</b>
                </h4>
                <p>{album.artists[0].name}</p>
              </div>
            </div>
          );
        })}
      </div>

      <div>
        {genreAlbums.map((track, i) => {
          return (
            <div className="card" key={i}>
              <img src={track.album.images[0].url} alt="alt text" />
              <div className="container">
                <h4>
                  <b>{track.name}</b>
                </h4>
                <p>{track.artists[0].name}</p>
              </div>
            </div>
          );
        })}
      </div>
    </div>
  );
}

export default App;

I have tried assigning keys to each of the mapped returns but nothing worked.

How to simplify js for multiple passwords

I have “old password, “new password”. “confirm new password”, they have own ID. The below code can work.

<script>
        var state = false;
        function toggle() {
            if (state) {
                document.getElementById("password").setAttribute("type", "password");
                document.getElementById("eye").classList.toggle("fa-eye");
                state = false;
            }
            else {
                document.getElementById("password").setAttribute("type", "text");
                document.getElementById("eye").classList.toggle("fa-eye-slash");
                state = true;
            }
        }
    </script>

<script>
    var state = false;
    function toggle() {
        if (state) {
            document.getElementById("password2").setAttribute("type", "password");
            document.getElementById("eye2").classList.toggle("fa-eye");
            state = false;
        }
        else {
            document.getElementById("password2").setAttribute("type", "text");
            document.getElementById("eye2").classList.toggle("fa-eye-slash");
            state = true;
        }
    }
</script>

<script>
    var state = false;
    function toggle() {
        if (state) {
            document.getElementById("password3").setAttribute("type", "password");
            document.getElementById("eye3").classList.toggle("fa-eye");
            state = false;
        }
        else {
            document.getElementById("password3").setAttribute("type", "text");
            document.getElementById("eye3").classList.toggle("fa-eye-slash");
            state = true;
        }
    }
</script>

HTML

                                    <div class="row align-items-center">
                                        <div class="col-sm-7">
                                            <div class="input-group">
                                                <input id="password" type="password" class="form-control"
                                                    placeholder="Enter new passcode" aria-label="new-passcode"
                                                    aria-describedby="toggleNewPasscode">
                                                <span class="input-group-text">
                                                    <i id="eye" class="fa fa-eye" onclick="toggle()" aria-hidden="true"></i>
                                                </span>
                                            </div>
                                        </div>

                                        <div class="col-sm-7">
                                            <div class="input-group">
                                                <input id="password2" type="password" class="form-control"
                                                    placeholder="Enter new passcode" aria-label="new-passcode"
                                                    aria-describedby="toggleNewPasscode">
                                                <span class="input-group-text">
                                                    <i id="eye2" class="fa fa-eye" onclick="toggle()" aria-hidden="true"></i>
                                                </span>
                                            </div>
                                        </div>

                                        <div class="col-sm-7">
                                            <div class="input-group">
                                                <input id="password3" type="password" class="form-control"
                                                    placeholder="Enter new passcode" aria-label="new-passcode"
                                                    aria-describedby="toggleNewPasscode">
                                                <span class="input-group-text">
                                                    <i id="eye3" class="fa fa-eye" onclick="toggle()" aria-hidden="true"></i>
                                                </span>
                                            </div>
                                        </div>
                                    </div>

But I think the code still can be more simplified, but i am very new to js, and already done many research still cannot found any article talk about this. Anyone could help me? Appreciate! Thanks.

I’d like to find the function declarations from text obtained from Apps Script API

When one makes a request from the App Script API to return all of the files and functions for a given project this is what a source file looks like.

"function traverse(o, func) {n  for (var i in o) {n    func.apply(this, [i, o[i]]);n    if (o[i] !== null && typeof (o[i]) == "object") {n      traverse(o[i], func);n    }n  }n}nnfunction daysInMonth(m = 0) {n  return new Date(new Date().getFullYear(), m + 1, 0).getDate();n}nnfunction getMyDataURI(fileId) {n  const file = DriveApp.getFileById(fileId);n  return file.getBlob().getDataAsString();n}nnfunction dataFromGSheets() {n  const ss = SpreadsheetApp.getActive();n  const sheet = ss.getSheetByName("Sheet1");n  const [header, ...data] = sheet.getDataRange().getDisplayValues();n  const choices = {};n  header.forEach((title, index) =u003e {n    choices[title] = data.map(row =u003e row[index]).filter(e =u003e e)n  });n  return choices;n}nnfunction boldMyWords() {n  const red = SpreadsheetApp.newTextStyle().setForegroundColor('red').setBold(true).build();n  const bold = SpreadsheetApp.newTextStyle().setBold(true).build();n  const ss = SpreadsheetApp.getActive();n  const sh = ss.getActiveSheet();n  const dsr = 3;n  const rg = sh.getRange(3, 1, sh.getLastRow() - dsr + 1, sh.getLastColumn());n  rg.clearFormat().setWrap(true);n  let vs = rg.getDisplayValues();n  let r = SpreadsheetApp.getUi().prompt('Enter words to search for separated by commas', SpreadsheetApp.getUi().ButtonSet.OK_CANCEL);n  if (r.getSelectedButton() == SpreadsheetApp.getUi().Button.OK) {n    let wordA = r.getResponseText().split(',');n    vs.forEach((r, i) =u003e {n      r.forEach((c, j) =u003e {n        let idxObj = { pA: [] };n        wordA.forEach(w =u003e {n          let re = new RegExp('(\\W|^)' + w.trim().toLowerCase() + '(\\W|$)', 'g');n          let found = [...c.toLowerCase().matchAll(re)];n          found.forEach(f =u003e {n            if (!idxObj.hasOwnProperty(w)) {n              idxObj[w] = [];n              idxObj[w].push((f.index u003e 0) ? f.index + 1 : f.index);n              idxObj.pA.push(w);n            } else {n              idxObj[w].push((f.index));n            }n          })n        });n        if (idxObj.pA.length u003e 0) {n          let cell = sh.getRange(i + dsr, j + 1);n          let val = SpreadsheetApp.newRichTextValue().setText(c);n          idxObj.pA.forEach((p, k) =u003e {n            idxObj[p].forEach(idx =u003e {n              val.setTextStyle(idx, idx + p.length, red);n              val.setTextStyle(idx, idx + p.length, bold);n            });n          });n          cell.setRichTextValue(val.build());n        }n      });n    });n  }n  ss.toast('EOF')n}nnfunction boldMyName() {n  const bold = SpreadsheetApp.newTextStyle().setBold(true).build();n  const ss = SpreadsheetApp.getActive();n  const sh = ss.getActiveSheet();n  const dsr = 3;n  const rg = sh.getRange(3, 1, sh.getLastRow() - dsr + 1, sh.getLastColumn());n  rg.clearFormat().setWrap(true);n  let vs = rg.getDisplayValues();n  vs.forEach((r, i) =u003e {n    r.forEach((c, j) =u003e {n      let idx = c.indexOf(':');n      if (~idx) {n        let cell = sh.getRange(i + dsr, j + 1);n        let val = SpreadsheetApp.newRichTextValue().setText(c);n        val.setTextStyle(0, idx, bold);n        cell.setRichTextValue(val.build());n      }n    });n  });n}nnfunction monthArray() {n  const mA = [...Array.from(new Array(12).keys(), x =u003e Utilities.formatDate(new Date(2021, x, 15), Session.getScriptTimeZone(), "MMMM"))];n  Logger.log(mA.join(','));n}nnvar level = 1;nfunction getFnF(folder = DriveApp.getRootFolder()) {n  const ss = SpreadsheetApp.getActive();n  const sh = ss.getSheetByName('Sheet0')n  const files = folder.getFiles();n  sh.getRange(sh.getLastRow() + 1, level).setValue(folder.getName()).setFontWeight('bold');n  if (files.hasNext()) {n    sh.getRange(sh.getLastRow() + 1, level).setValue('Files:');n  }n  while (files.hasNext()) {n    let file = files.next();n    let firg = sh.getRange(sh.getLastRow() + 1, level + 1);n    firg.setValue(Utilities.formatString(file.getName()));n  }n  const subfolders = folder.getFolders()n  while (subfolders.hasNext()) {n    let subfolder = subfolders.next();n    level++;n    getFnF(subfolder);n  }n  level--;n}nnfunction getFilesAndFolders() {n  const fldr = DriveApp.getRootFolder();n  SpreadsheetApp.getActive().getSheetByName('Sheet0').clearContents();n  SpreadsheetApp.getActive().toast('Entry');n  getFnF(fldr);n  SpreadsheetApp.getActive().toast('EOF');n}nnfunction getFnF1(folder = DriveApp.getRootFolder()) {n  let tree = JSON.parse(PropertiesService.getScriptProperties().getProperty('FnF'));n  //Logger.log(JSON.stringify(tree));n  if (tree.level u003c level) {n    tree.level = level;n    PropertiesService.getScriptProperties().setProperty('FnF', JSON.stringify(tree));n  }n  const files = folder.getFiles();n  let row = Array.from([...Array(level).keys()], ((x, i) =u003e { if (i == level - 1) { x = folder.getName(); } else { x = ''; } return x; }));n  tree.txt.push(row);n  row = Array.from([...Array(level).keys()], ((x, i) =u003e { if (i == level - 1) { x = 'bold'; } else { x = 'normal'; } return x; }));n  tree.fwt.push(row);n  PropertiesService.getScriptProperties().setProperty('FnF', JSON.stringify(tree));n  if (files.hasNext()) {n    let row = Array.from([...Array(level).keys()], ((x, i) =u003e { if (i == level - 1) { x = 'Files:'; } else { x = ''; } return x; }));n    tree.txt.push(row);n    tree.fwt.push(['normal']);n    PropertiesService.getScriptProperties().setProperty('FnF', JSON.stringify(tree));n  }n  while (files.hasNext()) {n    let file = files.next();n    let row = Array.from([...Array(level + 1).keys()], ((x, i) =u003e { if (i == level) { x = file.getName(); } else { x = ''; } return x; }));n    tree.txt.push(row);n    tree.fwt.push(['normal']);n    PropertiesService.getScriptProperties().setProperty('FnF', JSON.stringify(tree));n  }n  const subfolders = folder.getFolders()n  while (subfolders.hasNext()) {n    let subfolder = subfolders.next();n    level++;n    getFnF1(subfolder);n  }n  level--;n}nnfunction getFilesAndFolders1() {n  const fldr = null;n  const ss = SpreadsheetApp.getActive();n  ss.toast("Entry");n  const sh = ss.getSheetByName('Sheet1');n  sh.clearContents();n  SpreadsheetApp.flush();n  PropertiesService.getScriptProperties().setProperty('FnF', JSON.stringify({ txt: [], fwt: [], level: 0 }));n  getFnF1();n  //Logger.log(PropertiesService.getScriptProperties().getProperty('FnF'));n  let tree = JSON.parse(PropertiesService.getScriptProperties().getProperty('FnF'));n  const l = tree.level + 1n  tree.txt.forEach(r =u003e {n    if (r.length u003c l) {n      //Array.from(Array(l - r.length).keys()).forEach(e =u003e r.push(''));n      r.splice(r.length, 0, ...Array(l - r.length).fill(''));n    }n  });n  tree.fwt.forEach(r =u003e {n    if (r.length u003c l) {n      //Array.from(Array(l - r.length).keys()).forEach(e =u003e r.push('normal'));n      r.splice(r.length, 0, ...Array(l - r.length).fill('normal'));n    }n  });n  //Logger.log(JSON.stringify(tree));n  sh.getRange(1, 1, tree.txt.length, tree.level + 1).setValues(tree.txt);n  sh.getRange(1, 1, tree.fwt.length, tree.level + 1).setFontWeights(tree.fwt);n  PropertiesService.getScriptProperties().deleteProperty('FnF');n  ss.toast("EOF");n}nnfunction calendarMonthlyForYear() {n  var dA = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];n  var oA = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'];//you can change the first day of the week by shifting the arrayn  //var oA=['Sun','Mon','Tue','Wed','Thu','Fri','Sat'];n  var dObj = {};n  oA.forEach(function (e, i) { dObj[e] = i });n  var mA = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];n  var cA = [];n  var bA = [];n  var wA = [null, null, null, null, null, null, null];n  var ss = SpreadsheetApp.getActive();n  var sh = ss.getSheetByName("Cal");n  if (!sh) { var sh = ss.insertSheet('Cal'); }n  sh.clear();n  var year = new Date().getFullYear();n  for (var i = 0; i u003c 12; i++) {n    var month = new Date(year, i, 1).getMonth();n    var dates = new Date(year, i + 1, 0).getDate();n    cA.push([mA[month], dates, '', '', '', '', '']);n    bA.push(['#ffffff', '#ffffff', '#ffffff', '#ffffff', '#ffffff', '#ffffff', '#ffffff']);n    cA.push(oA)n    bA.push(['#ffff00', '#ffff00', '#ffff00', '#ffff00', '#ffff00', '#ffff00', '#ffff00']);n    var d = [];n    var ddd = [];n    for (var j = 0; j u003c dates; j++) {n      var day = new Date(year, i, j + 1).getDay();n      var date = new Date(year, i, j + 1).getDate();n      if (day u003c wA.length) {n        wA[dObj[dA[day]]] = date;n      }n      //if(day==wA.length-1 || date==dates) {n      if (dA[day] == oA[wA.length - 1] || date == dates) {n        cA.push(wA);n        bA.push(['#ffffff', '#ffffff', '#ffffff', '#ffffff', '#ffffff', '#ffffff', '#ffffff']);n        wA = ['', '', '', '', '', '', ''];n      }n    }n  }n  sh.getRange(1, 1, cA.length, cA[0].length).setValues(cA);n  //sh.getRange(1,1,cA.length,cA[0].length).setBackgrounds(bA);n  sh.getRange(1, 1, cA.length, cA[0].length).setBackground('#ffffff');n}nnfunction monthlyCalendar(m, wsd, ret) {n  var m = m || new Date().getMonth();n  var wsd = wsd || 1;//defaults to Mondayn  var ret = ret || false;n  const td = new Date();n  const [cy, cm, cd] = [td.getFullYear(), td.getMonth(), td.getDate()];n  const dA = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];n  const oA = [...Array.from(Array(7).keys(), idx =u003e dA[(idx + wsd) % 7])]n  let dObj = {};n  let midx = {};n  let rObj = { cA: null, roff: null, coff: null };n  oA.forEach(function (e, i) { dObj[e] = i; });n  const mA = [...Array.from(new Array(12).keys(), x =u003e Utilities.formatDate(new Date(2021, x, 15), Session.getScriptTimeZone(), "MMM"))];n  mA.forEach((e, i) =u003e { midx[i] = i; })n  let cA = [];n  let bA = [];n  let wA = [null, null, null, null, null, null, null];n  const ss = SpreadsheetApp.getActive();n  const sh = ss.getActiveSheet();n  sh.clear();n  const year = new Date().getFullYear();n  let i = midx[m % 12];n  let month = new Date(year, i, 1).getMonth();n  let dates = new Date(year, i + 1, 0).getDate();n  cA.push([mA[month], dates, '', '', '', '', '']);n  bA.push(['#ffffff', '#ffffff', '#ffffff', '#ffffff', '#ffffff', '#ffffff', '#ffffff']);n  cA.push(oA)n  //bA.push(['#ffff00', '#ffff00', '#ffff00', '#ffff00', '#ffff00', '#ffff00', '#ffff00']);n  let d = [];n  let ddd = [];n  for (let j = 0; j u003c dates; j++) {n    let day = new Date(year, i, j + 1).getDay();n    let date = new Date(year, i, j + 1).getDate();n    if (day u003c wA.length) {n      wA[dObj[dA[day]]] = date;n    }n    if (cy == year && cm == month && cd == date) {n      rObj.roff = cA.length;n      rObj.coff = dObj[dA[day]];n    }n    if (dA[day] == oA[wA.length - 1] || date == dates) {n      cA.push(wA);n      //bA.push(['#ffffff', '#ffffff', '#ffffff', '#ffffff', '#ffffff', '#ffffff', '#ffffff']);n      wA = ['', '', '', '', '', '', ''];n    }n  }n  if (!ret) {n    rObj.cA = cA;n    sh.getRange(1, 1, rObj.cA.length, rObj.cA[0].length).setValues(cA);n    if (rObj.roff && rObj.coff) {n      sh.getRange(1, 1).offset(rObj.roff, rObj.coff).setFontWeight('bold').setFontColor('red');n    }n  } else {n    rObj.cA = cA;n    return rObj;n  }n}nnfunction monthlyCalendarWithEvents(obj) {n  var m = obj.m || new Date().getMonth();n  var wsd = obj.wsd || 1;//defaults to Mondayn  const calids = obj.calids || CalendarApp.getAllOwnedCalendars().map(c =u003e c.getId());n  const cals = calids.map(id =u003e CalendarApp.getCalendarById(id));n  const td = new Date();n  const [cy, cm, cd] = [td.getFullYear(), td.getMonth(), td.getDate()];n  const dA = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];n  const oA = [...Array.from(Array(7).keys(), idx =u003e dA[(idx + wsd) % 7])]n  let dObj = {};n  let midx = {};n  let rObj = { cA: null, roff: null, coff: null };n  oA.forEach(function (e, i) { dObj[e] = i; });n  const mA = [...Array.from(new Array(12).keys(), x =u003e Utilities.formatDate(new Date(2021, x, 15), Session.getScriptTimeZone(), "MMM"))];n  mA.forEach((e, i) =u003e { midx[i] = i; })n  let cA = [];n  let bA = [];n  let wA = [null, null, null, null, null, null, null];n  const ss = SpreadsheetApp.getActive();n  const sh = ss.getActiveSheet();n  sh.clear();n  const rtvnull = sh.getRange("A1").getRichTextValue();n  const year = new Date(new Date().getFullYear(), m, 1).getFullYear();n  let i = midx[m % 12];n  let month = new Date(year, i, 1).getMonth();n  let ldom = new Date(year, i + 1, 0).getDate();n  var events = { pA: [] };n  cals.forEach(c =u003e {n    let evs = c.getEvents(new Date(year, month, 1), new Date(year, month, ldom, 23, 59, 59));n    evs.forEach(ev =u003e {n      let st = ev.getStartTime();n      let dd = st.getDate();n      let hh = st.getHours();n      let mm = st.getMinutes();n      let sts = `${hh}:${mm}`;n      if (!events.hasOwnProperty(dd)) {n        events[dd] = [];n        events[dd].push(`${ev.getTitle()} - ${sts}`);n        events.pA.push(dd);n      } else {n        events[dd].push(`${ev.getTitle()} - ${sts}`);n      }n    });n  });n  cA.push([mA[month], ldom, '', '', '', '', '']);n  bA.push(['#ffffff', '#ffffff', '#ffffff', '#ffffff', '#ffffff', '#ffffff', '#ffffff']);n  cA.push(oA)n  //bA.push(['#ffff00', '#ffff00', '#ffff00', '#ffff00', '#ffff00', '#ffff00', '#ffff00']);n  let d = [];n  let ddd = [];n  for (let j = 0; j u003c ldom; j++) {n    let day = new Date(year, i, j + 1).getDay();n    let date = new Date(year, i, j + 1).getDate();n    if (day u003c wA.length) {n      if (events.hasOwnProperty(date)) {n        wA[dObj[dA[day]]] = events[date].join('\n') + '\n' + date;n      } else {n        wA[dObj[dA[day]]] = date;n      }n    }n    if (cy == year && cm == month && cd == date) {n      rObj.roff = cA.length;n      rObj.coff = dObj[dA[day]];n    }n    if (dA[day] == oA[wA.length - 1] || date == ldom) {n      cA.push(wA);n      //bA.push(['#ffffff', '#ffffff', '#ffffff', '#ffffff', '#ffffff', '#ffffff', '#ffffff']);n      wA = ['', '', '', '', '', '', ''];n    }n  }n  const dtnotcur = SpreadsheetApp.newTextStyle().setBold(true).setForegroundColor('black').build();n  const dtcur = SpreadsheetApp.newTextStyle().setBold(true).setForegroundColor('red').build();n  const evsty = SpreadsheetApp.newTextStyle().setFontSize(8).setForegroundColor('black').build();n  rObj.cA = cA;n  rObj.crtA = cA.map((r, i) =u003e {n    let row = [];n    r.map((c, j) =u003e {n      if (c == '' || c == null) {n        row.push(rtvnull);n        return;n        //c = ' ';//heres the current solutionn      }n      if (typeof c != 'string') {n        c = c.toString();n      }n      let idx = c.lastIndexOf('\n');n      let rtv = SpreadsheetApp.newRichTextValue().setText(c);n      if (rObj.roff == i && rObj.coff == j) {n        if (~idx) {n          rtv.setTextStyle(idx + 1, c.length, dtcur);n          rtv.setTextStyle(0, idx, evsty);n          row.push(rtv.build());n        } else {n          rtv.setTextStyle(0, c.length, dtcur);n          row.push(rtv.build());n        }n      } else {n        if (~idx) {n          rtv.setTextStyle(idx + 1, c.length, dtnotcur);n          rtv.setTextStyle(0, idx, evsty);n          row.push(rtv.build());n        } else {n          if (c.length u003e 0) {n            rtv.setTextStyle(0, c.length, dtnotcur);n            row.push(rtv.build());n          } else {n            row.push(rtv.build());n          }n        }n      }n    });n    return row;n  });n  return rObj;n}nnfunction quarterlyCalendarWithEvents() {n  const ss = SpreadsheetApp.getActive()n  const sh = ss.getActiveSheet();n  sh.clear();n  const dt = new Date();n  let oA = [];n  let ids = ['[email protected]', '[email protected]', '[email protected]'];n  oA.push(monthlyCalendarWithEvents({ m: new Date().getMonth() - 2, wsd: null, calids: ids }));n  oA.push(monthlyCalendarWithEvents({ m: new Date().getMonth() - 1, wsd: null, calids: ids }));n  oA.push(monthlyCalendarWithEvents({ m: new Date().getMonth(), wsd: null, calids: ids }));n  oA.push(monthlyCalendarWithEvents({ m: new Date().getMonth() + 1, wsd: null, calids: ids }));n  oA.push(monthlyCalendarWithEvents({ m: new Date().getMonth() + 2, wsd: null, calids: ids }));n  oA.forEach((obj, i) =u003e {n    if (i == 0) {n      sh.getRange(1, 1, obj.crtA.length, obj.crtA[0].length).setRichTextValues(obj.crtA);n    } else {n      let lr = sh.getLastRow();n      sh.getRange(lr + 1, 1, 1, obj.crtA[0].length).setBackground('#c2bbc9');n      let sr = lr + 2;n      sh.getRange(sr, 1, obj.crtA.length, obj.crtA[0].length).setRichTextValues(obj.crtA);n    }n  });n  SpreadsheetApp.flush();n  sh.getDataRange().setWrap(true).setHorizontalAlignment('left');n  sh.setColumnWidths(1, sh.getLastColumn(), 85);n}nnfunction colToletters(num) {n  let a = " ABCDEFGHIJKLMNOPQRSTUVWXYZ";n  if (num u003c 27) return a[num % a.length];n  if (num u003e 26) {n    num--;n    let letters = '';n    while (num u003e= 0) {n      letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'[num % 26] + lettersn      num = Math.floor(num / 26) - 1;n    }n    return letters;n  }n}nnfunction copyto() {n  const dssid = "1Trccc5IszA2cLpUHKr2_I826e216u6is7ZWbD8ecx2U";n  const ss = SpreadsheetApp.getActive()n  const sssid = ss.getId();n  const sh = ss.getSheetByName('Sheet0')n  const sshid = sh.getSheetId();n  const options = { "method": "post", "headers": { "Authorization": "Bearer " + ScriptApp.getOAuthToken() }, "payload": { "destinationSpreadsheetId": "" + dssid } };n  const url = `https://sheets.googleapis.com/v4/spreadsheets/${sssid}/sheets/${sshid}:copyTo`;n  let r = UrlFetchApp.fetch(url, options);n  let title = JSON.parse(r.getContentText()).title;n  const dss = SpreadsheetApp.openById(dssid);n  let s = dss.getSheetByName(sh.getName());n  if (s) dss.deleteSheet(s);n  dss.getSheetByName(title).setName(sh.getName());n}nnfunction breakUpRangeList(ss = SpreadsheetApp.getActive(), sh = ss.getSheetByName("Sheet0"), rgl) {n  let b = [];n  rgl.getRanges().forEach(rg =u003e {n    rg.getValues().forEach((r, i) =u003e {n      let row = rg.getRow() + i;n      r.forEach((c, j) =u003e {n        let col = rg.getColumn() + j;n        b.push(sh.getRange(row, col).getA1Notation())n      })n    })n  })n  b = [...new Set(b)];n  //Logger.log(JSON.stringify(b));n  return sh.getRangeList(b);n}nnfunction flattenRangeArray(rangeArray) {n  const ss = SpreadsheetApp.getActive()n  const sh = ss.getActiveSheet();n  let rgl = sh.getRangeList(rangeArray);n  let b = [];n  rgl.getRanges().forEach(rg =u003e {n    rg.getValues().forEach((r, i) =u003e {n      let row = rg.getRow() + i;n      r.forEach((c, j) =u003e {n        let col = rg.getColumn() + j;n        b.push(sh.getRange(row, col).getA1Notation())n      })n    })n  })n  b = [...new Set(b)];n  //Logger.log(JSON.stringify(b));n  return b;n}nnnn//Drive.Files.update({"parents": [{"id": folder.getId()}]}, file.getId());nnfunction createPDFFromDoc(fileid, folderid) {n  const folder = DriveApp.getFolderById(folderid);n  const file = DriveApp.getFileById(fileid);n  const blob = file.getAs('application/pdf').setName(file.getName());n  const pdffile = DriveApp.createFile(blob);n  Drive.Files.update({ "parents": [{ "id": folder.getId() }] }, pdffile.getId());n}nnfunction makeCopy() {n  var folderid = gobj.globals.folder1id;n  var fileid = "1lITNKyzlyLOWTla9c27x76GRAlAegF68";n  var folder = Drive.Files.get(folderid, { "supportsAllDrives": true });n  var newFile = { "fileId": fileid, "parents": [folder] };n  var args = { "resource": { "parents": [folder], "title": "new Title" }, "supportsAllDrives": true };n  Drive.Files.copy(newFile, fileid, args);n}nnfunction addingcharttoemaildraft() {n  const ss = SpreadsheetApp.getActive();n  const sh = ss.getSheetByName("Sheet0");n  const c = sh.getCharts()[0];n  const img = c.getAs("image/png").setName("myimage");n  const f = DriveApp.getFolderById(gobj.globals.testfolderid).createFile(img);n  let htmltemp = HtmlService.createTemplateFromFile('ah2');n  htmltemp.filename = "myimage";n  let imgObj = { img0: f.getBlob() };n  let html = htmltemp.evaluate().getContent();n  GmailApp.createDraft(gobj.globals.emailpub, "Test File", '', { htmlBody: html, inlineImages: imgObj });n}nnfunction openUrl() {n  let html = 'u003ch1u003eDummy Dialogu003c/h1u003eu003cscriptu003ewindow.onload = function(){google.script.run.withSuccessHandler(function(url){window.open(url,"_blank");google.script.host.close();}).getMyUrl();}u003c/scriptu003e';n  SpreadsheetApp.getUi().showModelessDialog(HtmlService.createHtmlOutput(html), "Dummy Dialog");n}nnfunction getMyUrl() {n  console.log('getting url');n  return "http://www.google.com";n}nnfunction sheetToCsv() {n  const ss = SpreadsheetApp.getActive();n  const sh = ss.getSheetByName("Sheet0")n  const params = { "method": "GET", "headers": { "Authorization": "Bearer " + ScriptApp.getOAuthToken() } };n  const url = "https://docs.google.com/spreadsheets/d/" + ss.getId() + "/export?gid=" + sh.getSheetId() + "&format=csv";n  const r = UrlFetchApp.fetch(url, params);n  const csv = r.getContentText();n  return csv;n}nnfunction unravelpara() {n  const ss = SpreadsheetApp.getActive();n  const sh = ss.getActiveSheet();n  const lists = 12;//number of lists to break it inton  let v = [...Array.from(Array(lists).keys(), x =u003e [''])];n  sh.getRange("A1").getDisplayValue().replace(/([ ]{2,})/g, " ").split(/\s/).forEach((e, i) =u003e {n    v[i % lists][0] += `, ${e}`;n  });n  let a = v.map(r =u003en    r[0].slice(2).split(', ')n  );n  let t = Object.keys(a[0]).map(function (c) { return a.map(function (r) { return r[c]; }); });n  sh.getRange(2, 2, t.length, t[0].length).setValues(t);n}nnfunction groceryList() {n  const ss = SpreadsheetApp.getActive();n  const sh = ss.getSheetByName("Purchase");n  const vs = sh.getDataRange().getValues().filter(r =u003e r[1] == true).map(r =u003e [r[2],r[3]]);n  n  const osh = ss.getSheetByName("Sheet0");n  osh.clear();n  if(vs && vs.length u003e 0) {n    vs.unshift(["Description","Quantity"]);n    osh.getRange(1, 1, vs.length,vs[0].length).setValues(vs);n    osh.getRange(1,1,1,osh.getLastColumn()).setFontWeight("bold");n    osh.autoResizeColumns(1,2);n  }n}nnfunction groceryListEdit(e) {n  const sh = e.range.getSheet();n  if (sh.getName() == "Purchase" && e.range.columnStart u003e 1) {n    if(e.value == "FALSE") {n      e.range.offset(0,2).setValue("");n    }n    groceryList();n  }n}nnnn" 

This one is fairly large. I’ve been using the code for a while but recently I noticed some of the functions were missing so I began to search for a better solution.

I can get an array of objects from the functionSet of the same return from the API so I can loop through the functionSet and recover the exact function names but this one function named breakUpRangeList is giving me problems that I’m having trouble resolving.

This version only contains the function before and the function after:

"function copyto() {n  const dssid = "1Trccc5IszA2cLpUHKr2_I826e216u6is7ZWbD8ecx2U";n  const ss = SpreadsheetApp.getActive()n  const sssid = ss.getId();n  const sh = ss.getSheetByName('Sheet0')n  const sshid = sh.getSheetId();n  const options = { "method": "post", "headers": { "Authorization": "Bearer " + ScriptApp.getOAuthToken() }, "payload": { "destinationSpreadsheetId": "" + dssid } };n  const url = `https://sheets.googleapis.com/v4/spreadsheets/${sssid}/sheets/${sshid}:copyTo`;n  let r = UrlFetchApp.fetch(url, options);n  let title = JSON.parse(r.getContentText()).title;n  const dss = SpreadsheetApp.openById(dssid);n  let s = dss.getSheetByName(sh.getName());n  if (s) dss.deleteSheet(s);n  dss.getSheetByName(title).setName(sh.getName());n}nnfunction breakUpRangeList(ss = SpreadsheetApp.getActive(), sh = ss.getSheetByName("Sheet0"), rgl) {n  let b = [];n  rgl.getRanges().forEach(rg =u003e {n    rg.getValues().forEach((r, i) =u003e {n      let row = rg.getRow() + i;n      r.forEach((c, j) =u003e {n        let col = rg.getColumn() + j;n        b.push(sh.getRange(row, col).getA1Notation())n      })n    })n  })n  b = [...new Set(b)];n  //Logger.log(JSON.stringify(b));n  return sh.getRangeList(b);n}nnfunction flattenRangeArray(rangeArray) {n  const ss = SpreadsheetApp.getActive()n  const sh = ss.getActiveSheet();n  let rgl = sh.getRangeList(rangeArray);n  let b = [];n  rgl.getRanges().forEach(rg =u003e {n    rg.getValues().forEach((r, i) =u003e {n      let row = rg.getRow() + i;n      r.forEach((c, j) =u003e {n        let col = rg.getColumn() + j;n        b.push(sh.getRange(row, col).getA1Notation())n      })n    })n  })n  b = [...new Set(b)];n  //Logger.log(JSON.stringify(b));n  return b;n}nnnn//Drive.Files.update({"parents": [{"id": folder.getId()}]}, file.getId());nn"

The following function is the function I use to load a spreadsheet that makes it easier to find functions I want but I’ve noticed that some are missing and that’s what I’d like to fix.

GS:

function getAllProjectFunctions() {
  const ss = SpreadsheetApp.getActive();
  const sh = ss.getSheetByName("ProjectFunctions");
  const file = DriveApp.getFileById(gobj.globals.SOFJSONId);
  var jOb = JSON.parse(file.getBlob().getDataAsString());
  let files = jOb.files;
  if (files && files.length > 0) {
    var cOb = files.reduce((a, f, i) => {
      //Logger.log(f.name);
      a.table.push([f.name, f.type, "", ""]);
      if (f.type == "SERVER_JS" && f.source != null) {
        //a.source = JSON.stringify(f.source);//The is where I stringified the file source code
        a.source = f.source;
        //Logger.log('a.source: %s',a.source);
      }
      if (f.functionSet && f.functionSet.values) {
        f.functionSet.values.forEach(obj => {
          //let re = new RegExp(`function\s+${obj.name}\([^)]*\)\s*\{.*?\\n\}\\n`, "g");
          //let re = new RegExp(`function.*?${obj.name}.*?\(.*\).*\{(.|\n)*?\n\}`, "g");

This is the line I’m working on:

          let re = new RegExp(`function\s+${obj.name}\([^)]*\)[ rn]*\{(.|\n)*?\n\}`, "g");//This is the regex that I wish to replace


          if (a.source.match(re)) {
            let src = a.source.match(re)[0];//once I began to stringy from above then this start functioning
            a.table.push([f.name, f.type, obj.name, src])
          }
        });
      }
      if((f.type == "HTML" || f.type == "JSON")&& f.source != null) {
        a.table.push([f.name,f.type,f.name,f.source])
      }
      return a;
    }, { source: "", table: [["File Name", "File Type", "Function Name", "Source"]] });
  }
  if (cOb.table && cOb.table.length > 0) {
    sh.clearContents();
    sh.getRange(1, 1, cOb.table.length, cOb.table[0].length).setValues(cOb.table);
  }
}

This is the line I wish to replace:

let re = new RegExp(`function\s+${obj.name}\([^)]*\)[ rn]*\{(.|\n)*?\n\}`, "g");

This is the regex I’ve been working on:

functions+breakUpRangeList(?!n}nn)[^]*n}nn

I have not been able to get either the negative look behind nor the negative look ahead to operate in this application. So I haven’t gotten to the point of converting it to be used in a RegExp.

So the question I’m trying to ask is how to get everything from the end of the function name to the end of the declaration which ends with n}nn

This is what the function looks like in the project source file:

function breakUpRangeList(ss = SpreadsheetApp.getActive(), sh = ss.getSheetByName("Sheet0"), rgl) {
  let b = [];
  rgl.getRanges().forEach(rg => {
    rg.getValues().forEach((r, i) => {
      let row = rg.getRow() + i;
      r.forEach((c, j) => {
        let col = rg.getColumn() + j;
        b.push(sh.getRange(row, col).getA1Notation())
      })
    })
  })
  b = [...new Set(b)];
  //Logger.log(JSON.stringify(b));
  return sh.getRangeList(b);
}

CKEditor – How to add dynamic custom mentions?

my goal is to type anything with # beforehand and CKEditor to highlight it as mention.

It currently works with predefined mentions but that’s not sufficient for me:

Further thing I am trying to achieve it to hyperlink it to a webpage based on the mention.

Example user types: #test

This gets mentioned and hyperlink to https://example.com/test

I have spent hours trying to work it out but can’t come to mind how could I Implement that, so even ideas would be very beneficial.

Below is the code I currently have:

Thank you in advance even if you at least give me an idea how could I move forward..

I would ideally want to use CKEditor, further alternative I thought of is to use JS to look input field change and go from there

ClassicEditor
    .create( document.querySelector( '#snippet-mention-customization' ), {
        plugins: [ Mention, MentionCustomization, /* ... */ ],
        mention: {
            dropdownLimit: 4,
            feeds: [
                {
                            marker: '#',
                            feed: getFeedItems,
                            itemRenderer: customItemRenderer,
                },
            ]
        }
    } )
    .then( editor => {
        window.editor = editor;
    } )
    .catch( err => {
        console.error( err.stack );
    } );

.

const items = [
  {
    id: "@swarley",
    userId: "1",
    name: "Barney Stinson",
    link: "https://www.imdb.com/title/tt0460649/characters/nm0000439",
  },
];

function getFeedItems(queryText) {
  return new Promise((resolve) => {
    setTimeout(() => {
      console.log("Items:", items, Array.isArray(items)); // Check if items is an array
      const itemsToDisplay = items
        .filter((item) => isItemMatching(item, queryText))
        .map((item) => ({
          ...item,
          link: "https://example.com/search?q=" + encodeURIComponent(queryText),
        }))
        .slice(0, 10);

      resolve(itemsToDisplay);
    }, 100);
  });
}

function isItemMatching(item, queryText) {
  if (typeof queryText === "string") {
    const searchString = queryText.toLowerCase();
    return (
      item.name.toLowerCase().includes(searchString) ||
      item.id.toLowerCase().includes(searchString)
    );
  } else {
    return true;
  }
}

function customItemRenderer(item) {
  const itemElement = document.createElement("span");
  itemElement.classList.add("custom-item");
  itemElement.id = `mention-list-item-id-${item.userId}`;
  itemElement.textContent = `${item.name} (${item.link}) `;

  const linkElement = document.createElement("span");
  linkElement.classList.add("custom-item-link");
  linkElement.textContent = `[Link]`;

  itemElement.appendChild(linkElement);

  return itemElement;
}

function MentionCustomization(editor) {
  // The upcast converter will convert <a class="mention" href="" data-user-id="">
  // elements to the model 'mention' attribute.
  editor.conversion.for("upcast").elementToAttribute({
    view: {
      name: "a",
      key: "data-mention",
      classes: "mention",
      attributes: {
        href: true,
        "data-user-id": true,
      },
    },
    model: {
      key: "mention",
      value: (viewItem) => {
        // The mention feature expects that the mention attribute value
        // in the model is a plain object with a set of additional attributes.
        // In order to create a proper object, use the toMentionAttribute helper method:
        const mentionAttribute = editor.plugins
          .get("Mention")
          .toMentionAttribute(viewItem, {
            // Add any other properties that you need.
            link: viewItem.getAttribute("href"),
            userId: viewItem.getAttribute("data-user-id"),
          });

        return mentionAttribute;
      },
    },
    converterPriority: "high",
  });

  // Downcast the model 'mention' text attribute to a view <a> element.
  editor.conversion.for("downcast").attributeToElement({
    model: "mention",
    view: (modelAttributeValue, { writer }) => {
      // Do not convert empty attributes (lack of value means no mention).
      if (!modelAttributeValue) {
        return;
      }

      return writer.createAttributeElement(
        "a",
        {
          class: "mention",
          "data-mention": modelAttributeValue.id,
          "data-user-id": modelAttributeValue.userId,
          href: modelAttributeValue.link,
        },
        {
          // Make mention attribute to be wrapped by other attribute elements.
          priority: 20,
          // Prevent merging mentions together.
          id: modelAttributeValue.uid,
        }
      );
    },
    converterPriority: "high",
  });
}

connecting multiple static html pages to a single js file

I am trying to recreate the halo 3 UI with vanilla js, html, and css as my first solo adventure into front end web dev. Currently, I have the main menu and links to other html files. I have a single js file to handle event listeners and whatnot. I am running into an issue where i am getting a NULL reference error when trying to access elements on another page. This makes sense to me as those elements have not been rendered but the NULL error is not allowing the event listeners for the current page to work. code bellow:

/** main menu vars */
const trailer_btn = document.getElementById('show-trailer-btn');
const trailer = document.getElementById('trailer');
const trailer_escape_btn = document.getElementById('trailer-escape-btn');

/** theater menu vars */
const film_list_btn = document.getElementById('change-film-btn');
const film_list = document.getElementById('film-menu');




let trailer_playing = false;
let film_list_visible = false;



/**    MAIN MENU     */

/** event listener for trailer */
trailer_btn.addEventListener('click', ()=>{
    trailer.style.visibility='visible';
    trailer_escape_btn.style.visibility='visible';
    trailer_playing = true;
    trailer.play();
})

/**event listener to stop trailer */
trailer_escape_btn.addEventListener('click',()=>{
    trailer_playing = false;
    trailer.pause();
    trailer.currentTime = 0;
    trailer.style.visibility='hidden';
    trailer_escape_btn.style.visibility='hidden';
})


/**     THEATER PAGE     */

film_list_btn.addEventListener('click', ()=>{
    console.log('click')
    film_list.style.visibility = 'visible'
})

if i were to comment out the main menu event listeners, then the theater page event listeners will work.

so to summarize i want a single js file that will be able to handle the interactivity for all the static html pages.

I’ve commented out the main menu event listeners and because those elements are not on the theater page, it will work but if i leave them uncommented, i get a null reference error because the elements from the main menu are not rendered.

Unable to Decrypt using crypto.subtle in node

I’m trying to encrypt and decrypt some string data on my application, but I really don’t know what I’m doing wrong.

I’ve create one example script, absolutely separate from any other problems, but it seems not solving anything.

I’m using Node 18, Windows and I need it to be runnable in Node and Browser

Here is my key pair generation block:
(It works like spected)


const StringToArrayBuffer = (str) => {
    const buf = new ArrayBuffer(str.length);
    const bufView = new Uint8Array(buf);
    for (let i=0; i<str.length; i++) {
        bufView[i] = str.charCodeAt(i);
    }
    return buf;
}

const exp = new Uint8Array([1, 0, 1]);
crypto.subtle.generateKey({
    name: 'RSA-OAEP',
    modulusLength: 2048,
    publicExponent: exp,
    hash: 'SHA-256',
}, true, ['encrypt','decrypt']).then(async ({publicKey, privateKey}) => {
    const publicKeyStr = Buffer.from((await crypto.subtle.exportKey('spki', publicKey))).toString("base64");
    const privateKeyStr = Buffer.from((await crypto.subtle.exportKey('pkcs8', privateKey))).toString("base64");

    console.log('-----BEGIN PUBLIC KEY-----');
    for(let i=0; i<publicKeyStr.length; i+=64)
        console.log(publicKeyStr.substring(i,i+64));
    console.log('-----END PUBLIC KEY-----');
    console.log('----------------------------');
    console.log('-----BEGIN PRIVATE KEY-----');
    for(let i=0; i<privateKeyStr.length; i+=64)
        console.log(privateKeyStr.substring(i,i+64));
    console.log('-----END PRIVATE KEY-----');
});

Here is my encrypt block:
(Paste generated public key from previous block. It also works like spected)

let pem = `-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAi4RhcvypSg0d2+4nUnIn
l6KyOM+xEYN8MAIqq6HPwrHebyI0e4XoA6uA6kDhHykwlN/yB2ma9B2P8ME+YPEm
bDV1e9vJlIWB4VDfxlg/h+q5d41JovW4mMyRGLHI423TtAxgpX0sRe3afh8h/H3L
9V32UN3seXWt9lKeTUTrslJw3wDfKGiB1Yjeliyvlmif2+B3v1NqX1HNtgYYDlEF
T+pUlsIxmKB5CchcRhv1d3sNo34h7RkS3E3mHYR9erjNuPZedhO/RVAydp/HDIQh
G/3SnvUAsyVFEAksGukGTQicW8C9p+F6ypQlqGzqkPFlPk2jsjuc7p7FKVw6rglU
vQIDAQAB
-----END PUBLIC KEY-----`;

const pemHeader = "-----BEGIN PUBLIC KEY-----";
const pemFooter = "-----END PUBLIC KEY-----";
const pemContents = pem.substring(pemHeader.length, pem.length - pemFooter.length);
const binaryDerString = atob(pemContents);
const binaryDer = StringToArrayBuffer(binaryDerString);

const toEncrypt = "Here goes what you want to encrypt";

crypto.subtle.importKey("spki", binaryDer, { name: "RSA-OAEP", hash: "SHA-256" }, true, ["encrypt"]).then(key => {
    const dataToEncrypt = StringToArrayBuffer(toEncrypt);
    crypto.subtle.encrypt({name: "RSA-OAEP"}, key, dataToEncrypt).then((encoded) => {
        console.log('encoded', encoded);
        console.log('base64', btoa(String.fromCharCode.apply(null, new Uint8Array(encoded))));
    });
});

Then, It’s my decrypt block:
(Past a generated private key and previous base64 encrypt result section. Here’s where everything blows)

let pem = `-----BEGIN PRIVATE KEY-----
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCpy6X0gZ/S0daU
In0lT11ZCqhoUNPJNbGehIjyY6tK96Ek402sA19Pt7qDkRtT5VMvzx8zclUU3Jzy
zy66lUeTkWytUYqsWihEp0/VXKIO1vJrBBqGv4BEWlXJEW20j3O6507KeyZkuNbq
zUR+y36ED3HnYcpibWmS78movTIVH7uE8OhU+SHJAaLhKSOwIahmjTKeiRERb430
hktqnEHDpVw5ypJ2aiojS1i17dmmXyfgK9sSH8RCZ0VMBl2iQswiEtkD0Xpp+biC
f64KBxa/FXF/uf5B623ljkSIEgZPiOxqnbIySJ4fUS6OhG8GkP6rRn9DoBT6t/Xc
MR0JB1ubAgMBAAECggEASAXJHEDLoWo+4dELUoMqrnVV4AHBBA1RjVLcoCxk4UTO
xs3gCYHYsQDXDa3EcL7KnXH24ySxMEswC9KUGLLvjInYFmCLOPZ5ND3gIDnNyAun
AnvYIKYka1oCH2rUJQ3gYjxxcHPyYjEBgNGXJ018GdpPT31sknmkmZ465Odz0f9V
Uh6+U1xJhLLmSVnME5f6bzfxSHTssLGLLELVEJao/Cgoq2jf+0SpVKDSbw82e/lX
pw0dz+50Oj2fkLHCNwIvHTPSM8osxTwvMeqpKclp9zCifgzNYCdTSJS9/Cw/oW2o
eZK2DQqYTiXiQMgN/9dkIIsOn8haYkEjBCrRy9pA6QKBgQDi7Swlf36IjK+pMRrG
TEODE9jFJXudkfJspGA97xbXWnHuU+NHirrb9uqSkoicZlRApYOow/Wg6DgtKb64
yHd0oU7HfGWo8PG1l0c0M1PjSSq7nkBuMXGANjIUkPHedqks/78eMupjWV7QEhzW
aOhqCl1K7aZ1REeUSkohUSqddQKBgQC/jKvUC2RJT6e6tuqATDWcvjwBr/3Gsf9w
LjH09IUweqHT9K3JzOlmMmY3RX/gM3lU1KIOLZlolozTLJv9XDn1cT/Xqdc+r/Q3
pf+G5u4alOZD9aYjsZSmGsXydZ4njjIkJvX467zipVOtMFhSDGuburHBdvY5Z5ij
5jiX7HaizwKBgCjOb3baw104t0nce60W/7jtc7iX8e+20/o3YNsiSGA3cm9iBGfU
CaAOecYbtZcyS4pIeTF684uY1qlAbXx7CAggDbOPqhREJ6L47iPz6uzfNmEApyNp
nrhohn7uRaA0hF2EK9D5ZO6ynnsaFrdzq/+Nl5Mmwx0pRxnidgwhtWEVAoGAA67E
rvL5Hp+1bdWOdKECdt0Bclbb3jIV4yZAN6Fr3h69dcHChZq28gwOAwoHB1x1/LeJ
1hPyWxxp4LV+2kQnqRxgSdkuFjpzy44Zd5KBCWnLc4sJgq4rWXYyUBMK01/cfu1w
1TRTEVh0X2QKjqlGeFwChuGuojPnr18Bv4oATekCgYASK2ihWaCISwgVUhlSkzX/
2Lq+4VMkSwiNebja3CLjvSZ4VmzwkHIymrz9aGhd6+FwBNfqOtu3E2urkKBG9LBR
2o+3ypK2wKEgsmVtq5zQUx7hRtcsm/I/N4KDLE+1to+ouw4VXo5+Hv0aEziRJ3qK
ISPxbv2X9RfKrykBcf6e9g==
-----END PRIVATE KEY-----`;

const toDecrypt = "hN5/WIfroULCJqngEb10qn0LN/ET+OywKgbV/oEYReezKlImHo6TIcMJDF3fXTLiNLrTjBlnVBUyLEfdlsFj/0FeKVCBkaySGn/e3EsYQArjOdCD2DuNpiAdMR89CSmWLi1aPLU52MlX6h0VsE3TzdNyumAsimq3Eo8Ga8zdc9O8NCQED7gydHiogYG32uP79e/V/A4I44pPjSJhoeY0NAtLTMbU894GdBcES6/seEh5izROt7yb3F21T39jaY1M6sK6wMgEaGZojb6LLMI4EuMvIJ+TVjiWO0em6aZvjTkB+r0alArHmsAOyGWLFwqVHQ8dEu42EuMfSelPsUlZzg==";


const pemHeader = "-----BEGIN PRIVATE KEY-----";
const pemFooter = "-----END PRIVATE KEY-----";
const pemContents = pem.substring(pemHeader.length, pem.length - pemFooter.length);
const binaryDerString = atob(pemContents);
const binaryDer = StringToArrayBuffer(binaryDerString);

crypto.subtle.importKey("pkcs8", binaryDer, { name: "RSA-OAEP", hash: "SHA-256" }, true, ["decrypt"]).then(key => {
    const dataToDecrypt = StringToArrayBuffer(atob(toDecrypt));
    console.log(dataToDecrypt);
    crypto.subtle.decrypt({name: "RSA-OAEP"}, key, dataToDecrypt).then((decoded) => {
        console.log('It never logs, there is some error decrypting');
        console.log('decoded', decoded);
        console.log('utf-8', atob((new TextDecoder).decode(decoded))); // Here should be what you defined in previous block's variable toEncrypt
    }).catch(err => console.error(err));
});

What I’m doing wrong?
Almost three days lost in this whole thing… 🙁

Is there a better way to combine 2 objects into 1 new array of objects?

I have 2 objects, as such:

costsObj = {
  Honda: 24000,
  BMW: 55000,
  Toyota: 22000
};

stockObj = {
  Honda: 5,
  BMW: 1,
  Toyota: 2
}

I want to combine the 2 objects into 1 array of objects that looks like:

carsArr = [
  {brand: "Honda", cost: 24000, stock: 5},
  {brand: "BMW", cost: 55000, stock: 1},
  {brand: "Toyota", cost: 22000, stock: 2}
]

I have achieved this by using map(), for(), and forEach():

  // Use costsObj to create new array
  carsArr = Object.keys(costsObj).map(brand => {
    return { brand, cost: costsObj[brand], stock: 0 };
  });

  // Add data from stockObj to new carsArr
  for (const [key, value] of Object.entries(stockObj)) {
    carsArr.forEach((item, index)=>{
      if(item.term == key) {
        carsArr[index].stock = value;
      }
    })
  };

But this feels clunky and that there could/should be a better way, especially if I want to combine data from more objects in the future, eg:

carsArr = [
  {brand: "Honda", model: "Accord", cost: 24000, stock: 5},
  {brand: "BMW", model: "3 series", cost: 55000, stock: 1},
  {brand: "Toyota", model: "Camry", cost: 22000, stock: 2}
]

Does anyone know if there is a better way to combine the data from many objects into one array of objects?

AOS is not working and not getting error in nextjs 13.5

why aos not wroking?
before it worked, after I used chakraUI it didn’t work

...

  
      <body className={inter.className}>
        <ChakraProvider>
          <AOSInit />
          {children}
        </ChakraProvider>
      </body>

below are the file for AOS, this file is separate:

> "use client";
...
export const AOSInit = () => {
  useEffect(() => {
    AOS.init({
      easing: "ease-out-quad",
      duration: 1000,
      once: false,
    });
  }, []);

  return null;
};

please help how to fix this ?

jQuery Image Draggable with Marker Draggable

I’m trying to use jQuery Draggable on image background and it’s work.

I can drag the image everywhere.

Now I have div marker to identify every location on the image. In example code I put Michael Office that should be on Michael area (see on the image). But I can’t figure it out how to make the marker place into Michael Area.

My question is it possible to put the marker into Michael Area and also when I drag anywhere, the Michael Area marker should be keep there.

$(document).ready(function(){
    const container = document.querySelector('.img');
    const containerSize = container.getBoundingClientRect();

    let imagePosition = { x: 50, y: 50 };
    let cursorPosBefore = { x: 0, y: 0 };
    let imagePosBefore = null;
    let imagePosAfter = imagePosition;

    // Helpers
    const minMax = (pos) => (pos < 0) ? 0 : (pos > 100) ? 100 : pos;
    const setNewCenter = (x, y) => {
      imagePosAfter = { x: x, y: y }; 
      container.style.backgroundPosition = `${x}% ${y}%`;
    };

    const getImageZoom = () => {
      return new Promise((resolve, reject) => {
        let actualImage = new Image();
        actualImage.src = $('#img').css('background-image').replace(/"/g,"").replace(/url(|)$/ig, "");
        actualImage.onload = function() {
          resolve({
            x: zoomX = this.width / containerSize.width - 1,
            y: zoomY = this.height / containerSize.height - 1
          });
        }
      });
    }
        
    const addEventListeners = (zoomLevels) => {container.addEventListener('mousedown', function(event) {
          cursorPosBefore = { x: event.clientX, y: event.clientY };
          imagePosBefore = imagePosAfter; // Get current image position
        });

        container.addEventListener('mousemove', function(event) {
            event.preventDefault();
            
            if (event.buttons === 0) return;

            let newXPos = imagePosBefore.x + ((cursorPosBefore.x - event.clientX) / containerSize.width * 100 / zoomLevels.x);
            let newYPos = imagePosBefore.y + ((cursorPosBefore.y - event.clientY) / containerSize.height * 100 / zoomLevels.y);

            setNewCenter(minMax(newXPos), minMax(newYPos));
        });
    };

    getImageZoom().then(zoom => addEventListeners(zoom));
});
<!DOCTYPE html>
<html lang="en">
    <head>
        <style>
        body {
            margin: 0;
            padding: 0;
            font-family: 'Manrope';
            -webkit-user-select: none;
            -moz-user-select: none;
            -ms-user-select: none;
            user-select: none;
        }
        
        #page {
            margin: 10px;
            display: flex;
        }
        
        #page .summary {
            width: 450px;
        }
        
        #page .summary .map-location {
            font-size: 25px;
            font-weight: bold;
            padding: 10px;
            letter-spacing: 1px;
            text-transform: uppercase;
        }
        
        #page .summary table {
            width: 100%;
            border-collapse: collapse;
        }
        
        #page .summary table th {
            background: #f1f1f1;
            padding: 10px;
            border-bottom: 1px solid #c0c0c0;
            font-size: 14px;
        }
        
        #page .summary table td {
            padding: 10px;
        }
        
        #img {
            position: relative;
            width: calc(100% - 50px);
            height: calc(100vh - 25px);
            background-position: 50% 50%;
            background-image: url('https://live.staticflickr.com/3312/3642071233_162baf0108_h.jpg');
            cursor: move;
            border: 3px solid #5e5e5e;
        }

        #img:active {
            border-color: #007fff;
        }
        
        .table {
            display: flex;
            flex-flow: column;
        }
        
        .table-details {
            display: flex;
            justify-content: space-between;
            font-size: 14px;
        }
        
        .scroll-helper {
            height: calc(100vh - 75px);
            overflow-y: scroll;
        }
        
        .tbl-data th {
            position: sticky;
            top: 0;
        }
        
        .tbl-data tr {
            border-bottom: 1px solid #e7e7e7;
        }
        
        .pin {
            position: absolute;
            left: 10px;
        }
        </style>
    
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
    </head>
    
    <body>
        <div id="page">
            <div class="img" id="img">
                <div class="pin" id="pin">Michael Office</div>
            </div>
            
        </div>
    </body>
</html>