Using casting (::) of array elements with pg-promise

I have a domain that represents an array of integers, created with CREATE DOMAIN x AS integer[]. I have a field in a table that has type x[], i.e. an array of arrays of integers. I have done this (as opposed to integer[][]) to allow mixed-length arrays (see this answer).

Inserting the expression {{1, 2}, {3, 4, 5}} would look like:

INSERT INTO table (column) VALUES (ARRAY[ARRAY[1, 2]::x, ARRAY[3, 4, 5]::x])

Without the domain (i.e. when column is of type integer[][]), I can use pg-promise to insert the multidimensional array above:

const arr = [[1, 2], [3, 4, 5]];
await db.query('INSERT INTO table (column) VALUES ($1)', arr);

And select it:

const result = await db.query('SELECT column FROM table');
result[0].column[1][2] // => 5

But this of course has the limitation mentioned at the start, that SQL (or at least Postgres) doesn’t allow multidimensional arrays with different length rows.

Selecting a column of type x[] with pg-promise in the same way as above results in a string, and inserting a raw array (as above) understandably throws an error (“column is of type x[] but expression is of type integer[]”). Adding ::x[] (i.e. INSERT INTO table (column) VALUES ($1::x[]) also throws an error, “cannot cast type integer to x”, which also make sense.

So my question is, what is the best way to select and insert fields that are arrays of a domain with pg-promise? I looked at custom type formatting, but I’m not sure that it would work for selecting. Thanks!

Why is my Angular HTTP Interceptor not working? Async Await is failing

I am trying to use an HttpInterceptor to add my authorization headers but the asnyc/await function is not working with mysetup.

I have spent hours trying various tutorials and searching on here and none will resolve my issue. Any help would be greatly appreciated!

import { Injectable, Injector } from '@angular/core';
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpResponse } from '@angular/common/http';
import { Observable, from} from 'rxjs';
import { switchMap } from 'rxjs/operators';
import {Auth} from 'aws-amplify';


@Injectable()



  export class AuthInterceptor implements HttpInterceptor {
    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        return from(this.handleAccess(req, next));
    }

    async setToken() {
        const cognitoUser = await Auth.currentAuthenticatedUser();
        const currentSession = cognitoUser.signInUserSession;
        await cognitoUser.refreshSession(currentSession.refreshToken, (err, session) => {
            console.log('Spot 2')
            console.log(session.accessToken.jwtToken)
            return session.accessToken.jwtToken
            })
    }

    async handleAccess(req: HttpRequest<any>, next: HttpHandler):
    Promise<HttpEvent<any>> {
    var token;
    console.log('Spot 1')
    token = await this.setToken();
    console.log('Spot 3')
    const changedReq = req.clone({
        setHeaders: {
            'Authorization': token || '{}'
        }
    });
    return next.handle(changedReq).toPromise();
  }
}

In my console I am seeing Spot 1 > Spot 3 and then later Spot 2. Which is why my token is showing and undefined.

The goal is to get the handleAccess to run after setToken has ran.

Accessing a sequelize parent table id from the frontend js

I’m new to sequelize and I’m trying to build an app using 3 tables (User, Topic, Item) with a pretty simple hasMany/belongsTo association.
I’m trying to generate a list of items to display on each of the topics, using sequelize.

My issue is, when I’m posting a new item id doesn’t display on its topic because it’s not associated in the fetch “POST” on my frontend js file.
I’m missing the topic_id.

I tried querying but it doesn’t work. I need to return the topic_id as a stand alone variable.

How do I access the topic id attribute from the frontend side? I couldn’t find anything in the documentation or other questions to help me.

This is my add-item frontend logic, generated by the handlebars:

async function addItemHandler(e) {
  e.preventDefault();
  const name = document.querySelector("#name").value.trim();
  const url = document.querySelector("#url").value.trim();
  const display_url = document.querySelector("#display-url").value.trim();
  const comment_area = document.querySelector("#comment-area").value.trim();
 

  const response = await fetch("/api/items", {
    method: "POST",
    body: JSON.stringify({
      name,
      url,
      display_url,
      comment_area,
    // topic_id missing
    }),
    headers: { "Content-Type": "application/json" },
  });

  if (response.ok) {
    window.location.replace("/dashboard");
  } else {
    alert(response.statusText);
  }
}

document.querySelector("#add-item").addEventListener("submit", addItemHandler);

This is the client side route:

router.get("/", withAuth, (req, res) => {
  Item.findAll({
    where: {
      user_id: req.session.user_id,
    },
    attributes: [
      "id",
      "name",
      "url",
      "display_url",
      "comment_area",
    ],
    include: [
      {
        model: Topic,
        attributes: ["id", "name"],
        include: {
          model: User,
          attributes: ["username"],
        },
      },
      {
        model: User,
        attributes: ["username"],
      },
    ],
  })
    .then((dbItemData) => {
      const items = dbItemData.map((item) => item.get({ plain: true }));
      res.render("dashboard", { items, loggedIn: true });
    })
    .catch((err) => res.status(500).json(err));
});

and the api route:

router.post("/", (req, res) => {
  Item.create({
    name: req.body.name,
    url: req.body.url,
    display_url: req.body.display_url,
    comment_area: req.body.comment_area,
  })
    .then((dbItemData) => res.json(dbItemData))
    .catch((err) => res.status(500).json(err));
});

How to intercept all network request made from my website to block a specific domain?

I’m working on a project that would allow someone to just preview their own website within mine, and to simplify things I’m just injecting their HTML, CSS, and js code into my site within a container.

What I need to prevent is relative links to resources because that would then be polling my server, where none of their resources will be stored.

I need a way to check all outgoing network requests, check if they are to my domain, and ideally even be able to give a custom response (as in replacing the network response).

I know browsers have browser-specific webRequest APIs but that’s for running extensions, so it doesn’t help. I’ve seen mention of service workers but I only found a reference to one that can intercept use of the fetch API only.

I also found this question where the answers say there is no way to do this across the whole site, and I would have to make some kind of solution for every method of making network requests. It’s over 10 years old now so I’m hoping there might be a solution now.

If there is nothing then does anyone have a guide or something that lists every possible way that a network request can be made in web?

Any answer is appreciated, thanks.

JavaScript Websocket does not close on WebSocket.close()

I am using Websockets for a chat I am trying to set up. When I connect to the websocket it works fine but when I try to close the socket after two seconds and there was no connection I still get an onerror – even when closing the WebSocket with Websocket.close();

This is my function to set up the websocket:

  reconnectTimeout = null;

  function setupWebSocket(roomId) {
    console.log('setupWebSocket: ' + roomId);


    let ws_path = 'ws://192.168.2.105:8000/chat/' + chatid + '/';

    console.log('Connecting to ' + ws_path);
    chatSocket = new WebSocket(ws_path);

    // Handle incoming messages
    chatSocket.onmessage = function (socketMessage) {
      // Decode the JSON
      // console.log('Got websocket message.');

      let data = JSON.parse(socketMessage.data);

      // Handle joining (Client perspective)
      if (data.join) {
        console.log('Joining room ' + data.join);
      }
      // Handle leaving (client perspective)
      if (data.leave) {
        // do nothing - leave the room
        console.log('Leaving room ' + data.leave);
      }

      if (data.msg_type == "CHATMESSAGE") {
        console.log(data.message);
      }
      if (data.messages_payload) {
        console.log(data.messages);
      }
    };

    chatSocket.addEventListener('open', function () {
      console.log('ChatSocket OPEN');
      if (reconnectTimeout){
        clearTimeout(reconnectTimeout);
        reconnectTimeout = null;
      };
      // if the websocket is really ready to receive messages
      if (chatSocket.readyState == WebSocket.OPEN) {
        chatSocket.send(
          JSON.stringify({
            command: 'join',
            room: roomId,
          }),
        );
      }
    });

    // If websocket get closed set chatSocket to null. Only for security purposes
    chatSocket.onclose = function (e) {
      console.log('ChatSocket onClose.', e.code);
      
      // just in case the websocket didn't close like wanted
      chatSocket = null;
      chatSocket.close();
    };

    // Do nothing if the websocket opens
    chatSocket.onOpen = function (e) {
      console.log('ChatSocket on open', e);
    };

    chatSocket.onerror = function (e) {
      console.log('ChatSocket on error', e);
      chatSocket.close();
    };

    if (chatSocket.readyState == WebSocket.OPEN) {
      console.log('ChatSocket OPEN');
    } else if (chatSocket.readyState == WebSocket.CONNECTING) {
      console.log('ChatSocket connecting..');
    }
  }

setUpWebsocket(3);
setTimeout(() => {
  chatSocket.close();
  chatSocket = null;
}, 2000)

So what I do:
I am setting up the websocket and closing it after 2 seconds. When the connection can be build up it works just as I want it to, but when having e.g. no internet the socket does not close after 2 seconds as I want it to but I get this after 10 seconds:

ChatSocket on error {"isTrusted": false, "message": "failed to connect to /192.168.2.105 (port 8000) from /10.0.2.16 (port 51638) after 10000ms"}

Even After I set the chatSocket to null :/

Axios response returning empty string

 axios.post(
                    'http://localhost:3001/users',
                    {
                      username:user.username
                    }
                  ).then((res)=> console.log(res.data))

Response From FrontEnd : data: “”

Response i get from postman :

[
    {
      
        "Username": "john4",
        "Password": "",
        "Email": "",
        "ProfileImg": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAOEAAADhCAMAAAAJbSJIAAAAM1BMVEXk5ueutLeqsbTn6eqpr7PJzc/j5ebf4eLZ3N2wtrnBxsjN0NLGysy6v8HT1tissra8wMNxTKO9AAAFDklEQVR4nO2d3XqDIAxAlfivoO//tEOZWzvbVTEpic252W3PF0gAIcsyRVEURVEURVEURVEURVEURVEURVEURVEURVEURflgAFL/AirAqzXO9R7XNBVcy9TbuMHmxjN6lr92cNVVLKEurVfK/zCORVvW8iUBnC02dj+Wpu0z0Y6QlaN5phcwZqjkOkK5HZyPAjkIjSO4fIdfcOwFKkJlX4zPu7Ha1tIcwR3wWxyFhRG6g4Je0YpSPDJCV8a2Sv2zd1O1x/2WMDZCwljH+clRrHfWCLGK8REMiql//2si5+DKWKcWeAGcFMzzNrXC/0TUwQ2s6+LhlcwjTMlYsUIQzPOCb7YBiyHopyLXIEKPEkI/TgeuiidK/R9FniUDOjRDpvm0RhqjMyyXNjDhCfIMYl1gGjIMIuYsnGEYRMRZOMMunaLVwpWRW008v6fYKDIzxCwVAeNSO90BJW6emelYBRF/kHpYGVaoxTDAaxOFsfP9y8hpJ4xd7gOcij7JNGQ1EYFgkPJa1jQEiYZXRaRINKxSDUW9n+FT82lSKadkiru9/4XPqSLWOekGPoY05TAvLm9orm+YWuwHoBHkZKijNBJGmeb61eL6Ff/6q7bLr7yvv3vKGhpDRjvgjGaPz+gUg6YgcvpyAR2FIZ9U6nEEyZRTovmEU32KichpGn7C17XrfyH9gK/c0CMP05HZIM2uf9sEveizKveBy9/6Qt7o89ne33D525cfcIMW6ab+TMEukQbQbu+xu7X3A9bChmWaCeAkG17bpntwXgWxHaMzGPmUaR5dQZiKqRVeUZ3047fi3nAu28h4CHxCsZAgmEH8Y27jJAhm8c+5RQzRQNVGhVFSfxOYIjp/pP7RxzjevYXVGf4eLt+BJ1vCuLuLkrgABgCGXZ2wik5uty+oBvNirI6mkzhAf4Gsb58Hcm67Jzd+KwD10BYPLL3e0MjvKrgAULnOfveF/O4N2Xb9BZom3gJes3F9X5Zze8/6Yt09b4CrqsEjUv8oFBaR2rl+6CZr2xVrp24o/WitBKuGrrpl1+bFkmK2qXTON4VpbdfLa7o7y/WdLxG7lm2Lqh2clOwTegbvc/vj2U78CwhA87Bn8G5Nk3eOb0Nsr9flz3sG78UUtue4kpv1xvjg3TMay62BMlTlP+vrOMnJsRmt/ze0jsfkPPYdAH57hK+34PeOyc8XIXu5xT2HsUkdZz+adwg8HGFfQ3K5jtDvbUiO4Di9/ywHGrL88pDizZ++oTp+an+SMX/ndymUCwmHMdO7yuOx83pUx/eEMU0AvxWndwgidAqOZ8ypCwdEfvvEo6D9HwpA8wzvmOJEqAg9ySu8g4x0Hb9hSB/BANEKJ+LbPBU0lzbAJs4xt1AoshKkUGQmiH8/jJ0gdhTTLmSegHlPE0oOdXALnqDjKYh3px//fSgSWG8UqfrrIICzYYSJXRr9BSPbpNzw7gBjKjKOYI7ReIGqQRIap5+5MdjyvuDkExvGeXSlONWZAP3/AZBwJohU7QJRGU+cTVH18ELmRPNBmibW6MT/k1b0XhdkRBvyT6SB6EYv/GvhSmRNpGngRULsAlxMCGNXp7w3FfdEbTEEDdLI9TdIKRUzUesa3I461ER8cpNT7gMRhpKmYVS9ELOgCUQsa4SsulciKiLbY+AnHD8cpuhISsnxpamI84sbDq9qYJgf8wiiOBrC7Ml7M7ZECCqKoiiKoiiKoiiKoijv5AvJxlZRyNWWLwAAAABJRU5ErkJggg==",
        "Followers": [],
        "Following": [],
        "__v": 0
    }

]

im trying to post data and get a response from my server , the server is returning the right data when i use postman but when i use axios i get an empty string any help?

Call function from sibling component React hooks

How can I call a function that belongs to a sibling component either with props or context?

I’ve been trying to to this using props and context but I’m getting confused because I’m not passing variables but an actual function with parameters

I want to call the function handleSelectedUser that is inside the List component when I click the delete button in the Card component

Here it is in action in Replit

here is my code

App component:

function App() {
  const [currentUser, setCurrentUser] = useState(null)
  
   
  return (
    <main>
        <List 
          setCurrentUser={setCurrentUser} />
        <Card 
          currentUser={currentUser} 
          setCurrentUser={setCurrentUser}
          />
    </main>  );
}

List Component

function List({setCurrentUser}) {
  const [users, setUsers] = useState([])

  useEffect(() => {
    getUsers()
  }, [])

  async function getUsers(){
    const apiUrl = "https://randomuser.me/api?results=40"
    const result = await fetch(apiUrl)
    const data = await result.json()
    setUsers(data.results)
  }

  function handleDeleteSelectedUser(userToDelete){
    users.filter(user => user.phone != userToDelete.phone)
  }

  function handleSelectedUser(selectedUser){
    setCurrentUser(selectedUser)
  }
  
  
  return(
    <>
      <div>
        <h1>List</h1>
        {
          users.map((user) => 
          <li onClick={() => handleSelectedUser(user)} key={user.phone}>
          {user.name.first} {user.name.last}</li>)
        }
      </div>
    </>
  )
}

Card Component

function Card({currentUser, setCurrentUser}){
  
  function handleDelete(user){
    //Call handleSelectedUser in <List />
    setCurrentUser(null)
  }
  
  return (
    <div className="container">
      {currentUser && 
      <>
        <h2>{currentUser.name.first}'s Details</h2>
        <p>{currentUser.phone}</p>
        <button onClick={() => handleDelete(currentUser)}>Delete</button>
      </>
      }
    </div>
  )
}

Draw on Canvas by sketch jQuery plugin not work in Mobile

I am using this jQuery plugin to make free drawing over a canvas.

It work fine on computer, but in Mobile or IPad not work properly,
In Mobile or IPad, when I draw something and if I touch canvas again with pin, the old drawing is removed and cleared

 $('#canvasDrawing').sketch();


 <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
 <script src="https://cdn.jsdelivr.net/gh/mobomo/sketch.js@master/lib/sketch.min.js"></script>

 <canvas id="canvasDrawing">

client width and height always returning 0.75 after image is loaded

Here’s my code:

const images = document.getElementsByTagName('img')
for (let i = 0; i < images.length; i++) {
    const currentImage = document.getElementById(`${i}`)
    currentImage.onload = () => {
        const flex = document.getElementById(`${i}`).clientWidth / document.getElementById(`${i}`).clientHeight
        console.log(flex)
        document.getElementById(`${i}`).style.flex = flex
    }
}

And the console.log statement always returns 0.75.

Set the max height of one child div as the height of another child of the same parent div

The div structure is –

<div class="parent">
    <div class="left float-start"></div>
    <div class="right float-end overflow-y"></div>
<div>

Now,

  1. For the left child –

    • the height should be based on dynamic content
    • displayed entirely with no overflow scroll
  2. For the right child –

    • height is also based on dynamic content but
    • max height should be the height of the left child
    • set to overflow-y scroll and so it’s never longer than the left child but can be shorter

How do i do this only using css?

Any help would be appreciated!!

bind(this), in React

I’m wondering if someone can break down what is actually happening here, as substantive information is lacking, even on React’s own documentation.

I understand that ‘this’ is an object, which points to functions and data, within the scope of it’s context. So context.bind(function/data), for example. However i’m struggling to understand how this relates to binding ‘this’, to ‘this’, in React.

I don’t understand the logical process that is happening in the following:

this.changeColor = this.changeColor.bind(this) 

To me, it would make logical sense, to bind the function changeColor, to the context. I don’t understand why ‘this’ is being bound to the ‘this’ of changeColor, it seems backwards to me? Everywhere i look doesn’t actually provide a detailed explanation of what is actually happening here, just what and how ‘this’ and ‘bind’, are used in a standard way and that it’s the way to do it.

When this.changeColor is called by an eventListner, does the above code simultaneously execute changeColor and ‘bind’ ‘this’, also what is the context of ‘this’ that is being bound to changeColor? All my questions, would be happening inside of a React Component instance.

Thank you for any clarification and answers.

Openlayers | ol-ext filter – change filter mask with radiobutton

I’m trying to build a map which change the mask’s feature with help of radiobutton and ol-ext.

Thing is, when changing the radiobutton it keeps adding new filter without removing the precedent one.

When trying to remove the precedent filter before adding the new one, it says that the object doesn’t exist (because the object exist only within the ajax call)

Any idea on how to solve this ?

//Base layer
var osm = new ol.layer.Tile({
    source: new ol.source.OSM()
});

//Point layer
var point =
    new ol.layer.Vector({
        source: new ol.source.Vector({
            url: "https://santegraphie.fr/geoserver/GCS/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=GCS:DAC_ES&outputFormat=application%2Fjson",
            format: new ol.format.GeoJSON()
        }),
        style: (feature) => {
            return new ol.style.Style({
                image: new ol.style.Circle({
                    radius: 8,
                    fill: new ol.style.Fill({
                        color: "turquoise"
                    }),
                    stroke: new ol.style.Stroke({
                        color: 'white',
                        width: 2
                    })
                })
            })
        }
    })

// The map
var map = new ol.Map({
    target: 'map',
    view: new ol.View({
        zoom: 8,
        center: [255000, 6266791]
    }),
    layers: [
        osm,
        point
    ]
});

const url_json_reg = "https://wxs.ign.fr/administratif/geoportail/wfs?SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&srsName=EPSG:3857&typenames=ADMINEXPRESS-COG-CARTO.LATEST:region&outputformat=application/json&CQL_FILTER=insee_reg=11"

const emptylayer = new ol.layer.Vector({
    source: new ol.source.Vector({
        url: url_json_reg,
        format: new ol.format.GeoJSON()
    }),
    style: new ol.style.Style({
        fill: new ol.style.Fill({
            color : 'rgba(255, 255, 255, 0)'
          })
    }),
    zIndex: 999
});

map.addLayer(emptylayer);

$.getJSON(url_json_reg, function(json_masque) {
                let coords = json_masque.features[0].geometry.coordinates

                //Création du coupe
                var f = new ol.Feature(new ol.geom.MultiPolygon(coords));
                var mask = new ol.filter.Mask({
                    feature: f,
                    inner: false,
                    fill: new ol.style.Fill({
                        color: [255, 255, 255, 0.7]
                    })
                });

                //Application du masque sur la couche vide
                emptylayer.addFilter(mask);
});

$('.radio').on('click', function(e) {

//applique le filtre à l'ensemble de la région
if ($('#tous').is(':checked')) {
    
    //emptylayer.removeFilter(mask);

    $.getJSON(url_json_reg, function(json_masque) {
        let coords = json_masque.features[0].geometry.coordinates

        //Création du coupe
        var f = new ol.Feature(new ol.geom.MultiPolygon(coords));
        var mask = new ol.filter.Mask({
            feature: f,
            inner: false,
            fill: new ol.style.Fill({
                color: [255, 255, 255, 0.7]
            })
        });
        //Application du masque sur la couche vide
        emptylayer.addFilter(mask);
    });
}else{

    //emptylayer.removeFilter(mask);

    //Récupérer le json qui sert de masque
    var url_json_dpt = "https://wxs.ign.fr/administratif/geoportail/wfs?SERVICE=WFS&VERSION=2.0.0&REQUEST=GetFeature&srsName=EPSG:3857&typenames=ADMINEXPRESS-COG-CARTO.LATEST:departement&outputformat=application/json&CQL_FILTER=insee_dep=" + $('input[name="dpt"]:checked').val()
    $.getJSON(url_json_dpt, function(json_masque) {
        let coords = json_masque.features[0].geometry.coordinates

        //Création du coupe
        var f = new ol.Feature(new ol.geom.MultiPolygon(coords));
        var mask = new ol.filter.Mask({
            feature: f,
            inner: false,
            fill: new ol.style.Fill({
                color: [255, 255, 255, 0.7]
            })
        });
        //Application du masque sur la couche vide
        emptylayer.addFilter(mask);
    });
}
});  
    <head>
        <!-- OpenLayer -->
        <link rel="stylesheet" href="https://openlayers.org/en/latest/css/ol.css">
        <script type="text/javascript" src="https://openlayers.org/en/latest/build/ol.js"></script>
        <!-- JQuery -->
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
        <!-- ol-ext -->
        <script type="text/javascript" src="https://cdn.rawgit.com/Viglino/ol-ext/master/dist/ol-ext.min.js"></script>
    </head>
    
    <div id="map" style="width:100%; height:600px;">
    
    
        <div id="radioIDFcontainer">
            <input class="radio" type="radio" id="tous" name="dpt" value="tous" checked>
            <label for="tous">All</label>
            <input class="radio" type="radio" id="75" name="dpt" value="75">
            <label for="75">Area 1</label>
            <input class="radio" type="radio" id="77" name="dpt" value="77">
            <label for="77">Area 2</label>
            <input class="radio" type="radio" id="78" name="dpt" value="78">
            <label for="78">Area 3</label>
            <input class="radio" type="radio" id="91" name="dpt" value="91">
            <label for="91">Area 4</label>
            <input class="radio" type="radio" id="92" name="dpt" value="92">
            <label for="92">Area 5</label>
            <input class="radio" type="radio" id="93" name="dpt" value="93">
            <label for="93">Area 6</label>
            <input class="radio" type="radio" id="94" name="dpt" value="94">
            <label for="94">Area 7</label>
            <input class="radio" type="radio" id="95" name="dpt" value="95">
            <label for="95">Area 8</label>
        </div> 

Puppeteer Div Tag null values

Trying to scrape asins from an Amazon search. they are in a div tag like below.

Example: <div data-asin=”B007Q13M2Y”

Currently my code does return some , but mostly null’s. Is there something i missing here?

const puppeteer = require('puppeteer');



(async () => {

const browser = await puppeteer.launch({
    headless: false, 
   
  });

const page = await browser.newPage();

var url = await page.goto('https://www.amazon.co.uk/s?k=TAKPART+Brass+Diff+Filler+Plug+Kit+Compatible+for+Discovery+2+Td5+%26+V8&crid=SCY3QG71TBS9&sprefix=takpart+brass+diff+filler+plug+kit+compatible+for+discovery+2+td5+%26+v8%2Caps%2C77&ref=nb_sb_noss#');






 const data = await page.evaluate(() => 
Array.from(document.querySelectorAll(".s-main-slot.s-result-list.s-search-results.sg- 
row")).map(d => d.getAttribute("data-asin"))
)


console.log(data)




})()

Output:
”, null, null, null, null,
null, null, null, null, null,
null, null, null, null, null,
null, null, null, null, null,
null, ”, null, null, null,
null, ‘B07957YMTG’, null, null, null,
null, null, null, null, null,
null, null, null, null, null,
null, null, null, null, null,
null, null, null, null, null,
null, null, null, null, null,
‘B07SJGJVXR’, null, null, null, null,
null, null, null, null, null,
null, null, null, null, null,
null, null, null, null, null,
null, null, null, null, null,
null, null, null, null, null,
null, null, null, null, null,
null, null, ‘B07WS9VMX6’, null, null,
null, null, null, null, null,
… 673 more items