Why am I getting “Unexpected token'” when trying to update an old extension?

I’m trying to update an older extension that has not been updated in a long time and has been abandoned. The manifest is:

 "manifest_version": 3,
  "name": "BL photo grabber",
  "version": "4.5.14",
  "description": "Downloader Bricklink images.",
  "icons": {
    "128": "/assets/icon128.png",
    "48": "/assets/icon48.png",
    "16": "/assets/icon16.png"
  },
  "browser_action": {
    "default_icon": "/assets/icon16.png",
    "default_popup": "popup.html"
  },
  "content_scripts": [
    {
      "matches": [
        "*://*.bricklink.com/*"
      ],
      "js": [
        "content.js",
        "jquery-3.4.1.min.js"
      ],
      "run_at": "document_start"
    }
  ],
"content_security_policy": {
    "script-src": 'self',
    "object-src": 'self'
 }

    "storage",
    "webRequest",
    "downloads",
    "*://*.bricklink.com/*"
  ],
  "background": {
    "service_worker":"b.js"
  }
}

I update the manifest_version": 3 from manifest_version": 2 then fixed the "background": { service_worker":"b.js" to be compatible with 3 but when I tried to do the same for "content_security_policy": { i keep getting the Unexpected token error and cant seem to find what is causing it.
Any help?

can someone explain about undefined in my code and about passport-local

enter image description here

guys I have 2 question

  1. what is “local-register , local-login” where is come from. My route is /login and /register so how is it come. It’s from passport-local right? And this make me to type “local-login” like this right?

  2. can someone explain this the 1st passport.use(local-register)
    when I console.log(user) const user = undefined
    but 2nd passport.use (local-login) when I use console.log(user) is not equal undefined although I have used same code in the 2 first-line but why Unequal values.` sorry for post Image I can’t post code.

json FeatureCollection to threejs polygon concave or sharp view

I have JSON data like this. I have to show a 3d polygon with js exactly like the example. Can’t change anything in the data. Need to fix it functionally. Have more similar data.

// 2 features data
{
    "type": "FeatureCollection",
    "features": [
        {
            "id": "2",
            "type": "Feature",
            "properties": {
                "type": "wall",
                "sf_tilt": 90.0,
                "sf_orient": -32.0
            },
            "geometry": {
                "type": "Polygon",
                "coordinates": [
                    [
                        [
                            2683852.4747061506,
                            1252231.906523199,
                            432.63800066187565
                        ],
                        [
                            2683852.4747061506,
                            1252231.906523199,
                            439.65200066187566
                        ],
                        [
                            2683852.200003838,
                            1252232.076997624,
                            439.39600066187137
                        ],
                        [
                            2683852.200003838,
                            1252232.076997624,
                            435.1080006618714
                        ],
                        [
                            2683850.956000865,
                            1252232.8489994688,
                            435.10800066185215
                        ],
                        [
                            2683850.956000865,
                            1252232.8489994688,
                            433.2940106618521
                        ],
                        [
                            2683852.4747061506,
                            1252231.906523199,
                            432.63800066187565
                        ]
                    ]
                ]
            }
        },
        {
            "id": "5",
            "type": "Feature",
            "properties": {
                "type": "wall",
                "sf_tilt": 90.0,
                "sf_orient": 146.0
            },
            "geometry": {
                "type": "Polygon",
                "coordinates": [
                    [
                        [
                            2683853.20506449,
                            1252236.2645763762,
                            435.108
                        ],
                        [
                            2683854.3609999996,
                            1252235.484,
                            435.108
                        ],
                        [
                            2683854.3609999996,
                            1252235.4839999997,
                            439.3960000002033
                        ],
                        [
                            2683854.6319999998,
                            1252235.301,
                            439.6550000030672
                        ],
                        [
                            2683854.632,
                            1252235.3009999997,
                            433.7652148642271
                        ],
                        [
                            2683853.2050644904,
                            1252236.264576376,
                            433.74104702266015
                        ],
                        [
                            2683853.20506449,
                            1252236.2645763762,
                            435.108
                        ]
                    ]
                ]
            }
        }
    ]
}

Here I have tried with threejs but not getting satisfied result.

function createBufferGeometry(feature) {
   const coordinates = feature.geometry.coordinates[0];
   const coords = coordinates.map((coord) => [coord[0] - offsets.x, coord[1] - offsets.y, coord[2] - offsets.z]);

   const geometry = new THREE.BufferGeometry();
   const vertices = [];

   for (const coord of coords) {
      vertices.push(coord[0], coord[1], coord[2]);
   }

   const positionAttribute = new THREE.Float32BufferAttribute(vertices, 3);
   geometry.setAttribute("position", positionAttribute);

   const indices = [];
   for (let i = 0; i < coords.length - 2; i++) {
      indices.push(0, i + 1, i + 2);
   }
   geometry.setIndex(indices);
   geometry.computeVertexNormals();

   return geometry;
}

const meshGeometry = createBufferGeometry(coords);
const mesh = new THREE.Mesh(meshGeometry, meshMaterial);
scene.add(mesh);

My result with threejs, here for id 5 L shape not clear, adding an extra triangle also this tringle blinking.
enter image description here

Result with python from mpl_toolkits.mplot3d.art3d import Poly3DCollection here L shape clear with same data.
enter image description here

Anyone please can help me with how can I get a similar result?

How to have multiple images show randomly in a game in Javascript

Is it possible to fix my code so that there are multiple balls showing up randomly and constantly in the game at the same time? Currently the balls are showing up one at a time every 1.5 seconds. I think I might need to change the interval in the start function possibly.

I’m still new at coding and I’m not quite sure how to achieve this. Thank you in advance

Here is my Javascript code:

    // Declaring the images to use
    var imagesArray = [
    "./green-ball.png",
    "./yellow-ball.png",
    "./blue-ball.png",
    "./light-pink-ball.png",
    "./purple-ball.png",
    ];

    // Declaring the starting points
    let score = 0;
    let timer = 15;
    var interval;
    let timeLeft = 15;
    let lastScore = 0;

    // Setting game and images
    var img = document.createElement("img")
    const images = document.getElementsByClassName(imagesArray);
    var game = document.getElementById("game");
    const scoreElement = document.getElementById("score");
    const timerElement = document.getElementById("timer");

    // Game over function - clearing the info and resetting variables and updating the last score
    function gameOver() {
        var lastScoreElement = document.getElementById("lastScore");
        clearInterval(timer);
        clearInterval(interval);
        $("#playAgainButton").show();
        $("#lastScore").show(
            lastScoreElement.textContent = " " + score
        );
        ResetGlobalVariables;
    }

    // Making the random function
    function random(min, max) {
        return Math.floor(Math.random() * (max - min + 1)) + min;
    }

    //Creating the images to show up in random positions
    function createImage() {
        img.src = imagesArray[random(0, imagesArray.length - 1)];
        img.width = random(50, 200);
        img.height = random(50, 200);
        img.style.left = random(0, 800 - img.width) + "px";
        img.style.top = random(0, 600 - img.height) + "px";
        img.alt = img.src.split('/').pop(); // to show the colour
        return img;
    }

    // Creating the updateTimer function - once timer runs out, game is over
    function updateTimer() {
        timeLeft = timeLeft - 1;
        if(timeLeft >= 0)
            $("#timer").html(timeLeft);
        else {
            gameOver();
        }; 1000;
    }

    // Creating the start of the game - setting the timer and creating the balls
    function start() {
        timer = setInterval(updateTimer, 1000);
        updateTimer();
        $("#playAgainButton").hide();
        interval = setInterval(function() {
            var img = createImage();
            game.appendChild(img);
        }, 1500);
    }

    // Function to reset the global variables - clean slate
    function ResetGlobalVariables() {
        score = 0;
        scoreElement.innerHTML = "Current Score: " + score;
        timer = 15;
        timerElement.innerHTML = timer;
        timeLeft = 15;
    }

    // Update when the reset button is clicked
    const resetBtn = document.querySelector(".reset-button")
    resetBtn.addEventListener("click", ResetGlobalVariables)

    // Add event listener - if the ball is green update the score, if the ball is any other colour    lose a point
    game.addEventListener("click", function(e) {
        const tgt = e.target;
        if (!tgt.matches('img')) return; // not a ball
        if (!tgt.src.includes('green'))score--; // not green
        else
            score++;
        scoreElement.innerHTML = "Current Score: " + score;
      });

Here is my HTML:

    <!DOCTYPE html>
    <html>
        <head>
            <meta charset="UTF-8">
            <title>Find Greenie</title>
            <link rel="stylesheet" href="find.css">
            <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
        </head>
  
        <body>
            <table>
                <tr>
                    <td>
                        <div id="game"></div>
                    </td>
                    <td id="text">
                        <p id="gameTitle">Find Greenie!<img src="green-ball.png" alt="Logo"></p>
                        <p id="score">Current Score: 0</p>
                        <p> You have: <span id="timer">15</span> seconds remaining!</p>
                        <button id="playAgainButton" onclick="start()">Go!</button>
                        <input id="reset" type="button" class="reset-button" value="Reset">
                        <p> You scored: <span id="lastScore"></span></p>
                        <br>
                        <br>
                        <p>Click on Greenie the green ball to score points</p>
                        <p>But click on any other ball and lose a point!</p>
                        <p>Click Reset and then Go! to restart</p>
                        <script src="find.js"></script>
                    </td>
                </tr>
            </table>
        </body>
    </html>

     

React Downshift useCombobox Hook: Dropdown Not Closing on Outside Clicks

For some reason clicking outside the dropdown with out selecting item, dropdown is not closing

Doesn’t downshift by default closes when click outside the rendered dropdown?
I am using react-virtual to render the option. As i am looking over, i feel like isOpen prop that downshift provide is not getting applied properly, but i don’t know where to use it.

import React, { useState, useRef, ReactNode, useCallback, forwardRef } from 'react'
import { useCombobox } from 'downshift'
import { useVirtual } from 'react-virtual'
import cx from 'classnames'
import './single-select.css'
import { getSingleSelectFilteredItems, groupItemsByKey } from './helpers'
import { SearchSmall, SortArrownDown } from '../icons'
import { TextInput } from '../form'

export interface ComboBoxProps<T> {
  filterKeys: string[]
  groupBy: string
  items: T[]
  itemToString: (item: any | null) => string
  optionListWindowHeight: number
  placeholder: string
  renderRow: (item: T, index: number, props: any) => ReactNode
  setOpenDropdown: (value: boolean) => void
}
const SingleSelectDropdownWithAccordions = forwardRef(<T extends { id: string }>({
  filterKeys,
  groupBy,
  items,
  itemToString,
  optionListWindowHeight,
  placeholder,
  renderRow,
  setOpenDropdown,
}: ComboBoxProps<T>, ref) => {
  const listRef = useRef(null)
  const processedItems = groupBy ? groupItemsByKey(items, groupBy) : items
  const [inputItems, setInputItems] = useState(processedItems)
  const [expandedHeaders, setExpandedHeaders] = useState<Record<string, boolean>>({})
  const rowVirtualizer = useVirtual({
    size: inputItems.length,
    parentRef: listRef,
    estimateSize: useCallback(() => 35, []),
    overscan: inputItems.length,
  })

  const {
    isOpen = false,
    getMenuProps,
    getInputProps,
    getItemProps,
    highlightedIndex,
    selectedItem,
  } = useCombobox({
    items: inputItems,
    itemToString,
    onInputValueChange: ({ inputValue }) => {
      let newItems
      if (inputValue) {
        newItems = getSingleSelectFilteredItems(inputValue, items, groupBy, filterKeys)
      } else {
        newItems = groupBy ? groupItemsByKey(items, groupBy) : items
      }
      setInputItems(newItems)
    },
    scrollIntoView() { },
  })

  return (
    <div className="cz-single-select">
      <TextInput
        icon={<SearchSmall />}
        {...getInputProps()}
        placeholder={placeholder}
      />
      <ul
        {...getMenuProps({ ref })}
        className={`cz-single-select__window ${isOpen ? '' : 'hidden'}`}
        style={{ maxHeight: optionListWindowHeight }}
      >
        {rowVirtualizer.virtualItems.map((virtualItem) => {
          const itemProps = getItemProps({
            item: inputItems[virtualItem.index],
            index: virtualItem.index,
          })
          const item = inputItems[virtualItem.index]

          if (item.header) {
            const isExpanded = expandedHeaders[item.header]

            const handleHeaderClick = () => {
              setExpandedHeaders((prev) => ({
                ...prev,
                [item.header]: !prev[item.header],
              }))
            }
            return (
              <>
                <div
                  {...itemProps}
                  className="cz-single-select__window--accordion-header"
                  role="menuitem"
                  tabIndex={0}
                  key={virtualItem.index}
                  onClick={handleHeaderClick}
                  onKeyDown={handleHeaderClick}
                >
                  {item.header}
                  <span className="cz-single-select__expander-indicator">
                    {isExpanded ? <SortArrownDown /> : <SortArrownDown />}
                  </span>
                </div>
                <p>hi</p>
              </>
            )
          } else if (!expandedHeaders[item[groupBy]]) {
            return renderRow(item, virtualItem.index, {
              ...itemProps,
              className: cx(
                'cz-single-select__option-row',
                highlightedIndex === virtualItem.index && 'cz-single-select__highlighted',
                selectedItem === inputItems[virtualItem.index] && 'cz-single-select__selected',
              ),
              onClick: () => setOpenDropdown(false),
              onKeyDown: () => setOpenDropdown(false),
            })
          }
          return null
        })}
      </ul>
    </div>
  )
})

export { SingleSelectDropdownWithAccordions }

usages

  const [openDropdown, setOpenDropdown] = useState(false)

{openDropdown && (
                    <SingleSelectDropdownWithAccordions
                      items={items}
                      itemToString={
                        (item) => (item ? item.name : '')}
                      renderRow={(item, index, props) => {
                        return (
                          <li
                            {...props}
                            key={index}
                            tabIndex={0}
                            role="menuitem"
                            onClick={() => handleItemSelected(item)}
                            onKeyDown={() => handleItemSelected(item)}
                          >
                            <span>{item.name}</span>
                          </li>
                        )
                      }}
                      groupBy="group"
                      filterKeys={['name']}
                    />
                  )}
    ```

How to copy a canvas present on one webpage to another

I am attempting to get a canvas from a webpage and display it elsewhere.
The canvas itself is not obtainable through an url, I get the webpage and grab the canvas from there.

That being said, when attempting to display that same canvas elsewhere, it’s blank.
I understand that canvases behave differently than other HTML Elements, however I was unable to figure out how to achieve what it is I am trying to do (if possible at all).

I am making a chrome extension and the concerned code is as follows.

service_worker:

chrome.runtime.onMessage.addListener(function(url, _sender, onSuccess) {
    fetch(url)
    .then(response => response.text())
    .then(responseText => onSuccess(responseText))

    return true;
});

script:

await chrome.runtime.sendMessage(url, response => {
    const responseParsed = domParser.parseFromString(response, 'text/html');

    const graphContainer = responseParsed.getElementsByClassName("chart-container")[0];
    if (graphContainer == undefined) throw Error("Failed to get the graph container");

    parentContainer.insertBefore(graphContainer, parentContainer.childNodes[1])
});

What works:

  • I obtain the full webpage and am able to get the chart-container element.

What doesn’t:

  • When inserting that same graph onto my other webpage, the graph is empty.

Unable to fetch with formData using nextJS

I’m new to NextJS and I’m trying to figure out server action.

I have this request.


import { revalidatePath } from "next/cache";

export async function submitIPCR(prevState: any, formData: FormData) {
  // @ts-ignore
  try {
    console.log(Object.fromEntries(formData), 'waaa', formData)
    const res = await fetch("http://localhost:8000/ipcr", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      credentials: 'same-origin',
      body: formData
    });

    console.log(res.statusText)
    if (!res.ok) throw new Error('Something wrong')

    await res.json()
    revalidatePath('/ipcr/new');
    return { message: 'Successfully' }
  } catch (error) {
    console.log(error)
    return { message: 'Error' }
  }

}

but I always get this error when I check the network.

Error: Bad request

{"message":"Unexpected token - in JSON at position 0","error":"Bad Request","statusCode":400}

I use the fetch on form like this.

const NewIPCR = () => {
  const [state, formAction] = useFormState(submitIPCR, initState);

  return (
    <div>
      <form action={formAction}>
       {redacted}
      </form>
    </div>
  );
};

export default NewIPCR;

And the confusing part is, it’s not even hitting my server. I use https://hoppscotch.io/ and my request is fine, but when I’m on nextJS I have an error. Not sure how to fix since the response is not coming from my server.

Also when I try to format the fetch request body to.

 const res = await fetch("http://localhost:8000/ipcr", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      credentials: 'same-origin',
      body: {
        ratee: ''
      }
    });

I get an overload error:

No overload matches this call.
  Overload 1 of 2, '(input: RequestInfo, init?: RequestInit | undefined): Promise<Response>', gave the following error.
    Object literal may only specify known properties, and 'ratee' does not exist in type 'ReadableStream<any> | Blob | ArrayBufferView | ArrayBuffer | FormData | URLSearchParams'.
  Overload 2 of 2, '(input: RequestInfo | URL, init?: RequestInit | undefined): Promise<Response>', gave the following error.
    Object literal may only specify known properties, and 'ratee' does not exist in type 'ReadableStream<any> | Blob | ArrayBufferView | ArrayBuffer | FormData | URLSearchParams'.ts(2769)

I didn’t even add a type on body or fetch. not sure where is this coming from.

React setState in class component not updating state

Good day; I’m in need of assistance with the following problem:

A React class component (extending React.Component) exposes a method to set it’s state on command. I know that using a prop on the component instead could probably solve this problem, but this public method is extremely helpful in my specific scenario and I’m not willing to give up on it just yet.

The method looks like this:

public setContent = (newDoc: IDocsEntry) => {
    console.log('Updating with', newDoc);
    this.setState(() => ({doc: newDoc}), () => console.log(this.state.doc));
  };

and I’ve also tried

public setContent = (newDoc: IDocsEntry) => {
    console.log('Updating with', doc);
    this.setState(() => ({newDoc: {id: doc.id, path: doc.path, title: doc.title, content: doc.content}}), () => console.log(this.state.doc));
  };

The issue is as following:

  • on initially setting this state using this method, everything works as expected
  • when I then close this component (it lives in a modal), do something else and then try to update the state using this method, it simply does not update

In my console logs, I can see that the method is called with the new and correct object, but the callback of setState simply shows the old state from the first invocation of this function.

Angle between 3 vectors in 3d space

As per the solution(s) in this post Angle between 3 points in 3d space I have a java script function that takes 3 vectors(not just points/coords technically) & calculates the angles between them. The function’s uses its 2nd argument to calculate the angle between the other two(1 & 3). I run the function 3 times with 3 different orders of the input vectors to get 3 angles & it works fine. I’ll show it usage soon. In the program I’m using the function in, the input vecs are just positions on the surface of a sphere that I can position anywhere on it with lat/lon sliders, which I connect by lines(arcs actually) that creates a spherical triangle wherever I position the vecs(as like vertexes of the triangle. Anyway, that was just some background info so its clear. So, even though the faction in Q its a 3D solution, apparently it assumes the vectors are all co-planar, which they are not. It finds the angles of each vertex & the 3 angles obtained always just add up to 180 deg. But on a sphere, it should always be at least 180 & upto just under 540(pretty sure). So, I think I just have to get the function to take into account that the input vectors z components are what is tangent to/always lie flat on the sphere, which they are, as I also use them to position a 2D circle of any radius anywhere on the sphere. Here is the function:

function ang3D2(v1, v2, v3) {
      // Copy and normalize the input vectors
      let V1 = v1.copy().normalize();
      let V2 = v2.copy().normalize();
      let V3 = v3.copy().normalize();
  
      let Va = p5.Vector.sub(v1,v2).normalize();
      let Vb = p5.Vector.sub(v3,v2).normalize();
  
      let dots = p5.Vector.dot(Va,Vb);
  
      //let crosses = p5.Vector.sub(Va,Vb);
      //let crossesMag = crosses.mag();
  
      let angle = (Math.acos(dots) * 180.0) / Math.PI;
  
      //let angle2 = (Math.acos(crossesMag) * 180.0) / Math.PI;
      //let angle3 = (Math.acos(crossesMag) * 180.0) / Math.PI;
      //let angle4 = (Math.atan2(angle3,dots) * 180.0) / Math.PI;
      //let angle5 = (Math.atan2(crossesMag,dots) * 180.0) / Math.PI;
  
      return Math.round(angle * 1000) / 1000;  // just change angle to angle2,3,4,5 etc

    }//ang3d2()  

    //based off of https://gist.github.com/andfaulkner/c4ad12a72d29bcd653eb4b8cca2ae476 

    //& its usage:

    function angs() {
      if (cyl1V && cyl2V && cyl3V) {
        //let angs;
        ang1 = ang3D2(cyl2V, cyl1V, cyl3V);
        ang2 = ang3D2(cyl1V, cyl2V, cyl3V);
        ang3 = ang3D2(cyl1V, cyl3V, cyl2V);
        angS = ang1 + ang2 + ang3;
        console.log(angS);
      } //fi
    } //angs  

So, the function works as it is(almost in the way I need it to) but, in my case the input vecs are NOT coplanar(though it is a 3D solution?!). & I hope its clear as to what I’ve been trying. Using cross product instead of just cos dot etc. Cany anyone PLEASE steer me in the right direction ? For some reason I can’t fund much info about this in particular yet I’m sure its probably on the trivial side, though I’m not a professional programmer by any means. Thanks in advance.

How to split a single-object array-item into an array of three objects?

Given is the response data’s following data structure …

const res = {
  data: [{
    name: 'c2',
    ipaddr: '192.168.1.5',
    port: 4435,
    sshuser: "abc",
    sshpass: "xyz",
    sshport: 22,
    license: 'license.txt',
  }],
};

I want to convert it to …

const newState = [{
  name: 'c2',
  ipaddr: '192.168.1.5',
  port: 4435,
}, {
  sshuser: "abc",
  sshpass: "xyz",
  sshport: 22,
}, {
  license: 'license.txt',
}]

The below posted code does achieve the expected result …

var obj1 = {
  name: res.data[0].name,
  ipaddr: res.data[0].ipaddr,
  port: res.data[0].port,
};
var obj2 = {
  sshuser: res.data[0].sshuser,
  sshpass: res.data[0].sshpass,
  sshport: res.data[0].sshport,
};
var obj3 = {
  license: res.data[0].license,
};
const newState = [obj1, obj2, obj3];

What are other ways of achieving the same result, maybe using a shorter syntax?

RTCPeerConnection Issue: Uncaught DOMException – Failed to execute ‘setRemoteDescription’ on ‘RTCPeerConnection Django

I am encountering an issue with my WebRTC implementation in Django using Django Channels. The error I am facing is:

“Uncaught (in promise) DOMException: Failed to execute ‘setRemoteDescription’ on ‘RTCPeerConnection’: Failed to set remote answer sdp: Called in wrong state: stable”

After some research, I found a possible explanation for this error on Stack Overflow. It seems to be related to the fact that when a third user joins, it sends an offer to the two previously connected users, resulting in two answers. As a single RTCPeerConnection can only establish one peer-to-peer connection, attempting to setRemoteDescription on the second answer fails.

The suggested solution is to instantiate a new RTCPeerConnection for every remote peer. However, I’m unsure how to implement this in my existing code. Below is the relevant portion of my consumers.py and JavaScript code.

consumers.py and JavaScript code

import json
from typing import Text

from django.contrib.auth import authenticate
from Program.models import ChatRoom, Message
from channels.generic.websocket import AsyncWebsocketConsumer
from .service import add_remove_online_user, updateLocationList, add_remove_room_user
from asgiref.sync import sync_to_async
from channels.db import database_sync_to_async

class ChatRoomConsumer(AsyncWebsocketConsumer):
    
    async def connect(self):
        self.room_name = self.scope['url_route']['kwargs']['room_code']
        self.room_group_name = self.room_name
        print(self.room_group_name)
        await self.channel_layer.group_add(
            self.room_group_name,
            self.channel_name
        )
        await self.accept()
        await self.authenticate_user()
        await self.channel_layer.group_send(
            self.room_group_name,
            {
                'type' : 'chatroom_message',
                'message' : "add",
                'to' : "all",
                'from' : self.user,
                "event" : "online_traffic",
            }
        )
    
    async def disconnect(self, close_code):      
        await self.channel_layer.group_send(
            self.room_group_name,
            {
                'type' : 'chatroom_message',
                'to' : "all",
                'from' : self.user,
                'event' : 'online_traffic',
                'message' : "remove"
            }
        )
        await self.authenticate_user(add=False)
        await self.channel_layer.group_discard(
            self.room_group_name,
            self.channel_name
        )


    @sync_to_async
    def get_user_profile(self):
        user = self.scope['user']
        return user.user_profile

    @database_sync_to_async
    def authenticate_user(self, add=True):
        if self.scope['user'].is_authenticated:
            self.room = ChatRoom.objects.get(room_id=self.room_group_name)
            user = self.scope["user"]
            profile = user.user_profile
            self.user = {"id": user.user_profile.unique_id, "name": user.first_name if user.first_name else user.username, "profile_pic": user.user_profile.profile_pic.url}
            if add:
                profile.active = True
                profile.save()
                self.room.online.add(user)
                add_remove_online_user(self.room, user)  # Update the list of active users
            else:
                profile.active = False
                profile.save()
                self.room.online.remove(user)
                add_remove_online_user(self.room, user)  # Update the list of active users
            self.room.save()


    async def receive(self, text_data):
        text_data_json = json.loads(text_data)
        print(text_data_json)
        msgType = text_data_json.get("type")
        to = text_data_json.get("to")
        from_ = text_data_json.get("from")
        # user_profile = await self.get_user_profile()
        if msgType == "login":
            print(f"[ {from_['id']} logged in. ]")

        elif msgType == "offer":
            await self.channel_layer.group_send(
                self.room_group_name,
                {
                    'type' : 'offer',
                    'offer' : text_data_json["offer"],
                    'to' : to,
                    'from' : from_
                }
            )
        
        elif msgType == "answer":
            await self.channel_layer.group_send(
                self.room_group_name,
                {
                    'type' : 'answer',
                    'answer' : text_data_json["answer"],
                    'to' : to,
                    'from' : from_
                }
            )
        
        elif msgType == "candidate":
            await self.channel_layer.group_send(
                self.room_group_name,
                {
                    'type' : 'candidate',
                    'candidate' : text_data_json["candidate"],
                    'to' : to,
                    'from' : from_
                }
            )
        
        elif msgType == "joiner":
            await self.channel_layer.group_send(
                self.room_group_name,
                {
                    'type' : 'joiner',
                    "to" : "all",
                    "from" : from_
                }
            )
        
        elif msgType == "success_join":
            await self.channel_layer.group_send(
                self.room_group_name,
                {
                    'type' : 'success_join',
                    "to" : to,
                    "from" : from_
                }
            )
        elif msgType == "chat_message":
            await self.save_message(text_data_json["message"])
            await self.channel_layer.group_send(
                self.room_group_name,
                {
                    'type' : 'chatroom_message',
                    'message' : text_data_json["message"],
                    'to' : from_,
                    'from' : from_,
                    "event" : "chat_message"
                }
            )

        elif msgType == "join_request":
            if self.room.admin.user_profile.unique_id == self.user.id:
                from_ = text_data_json.get("user")
                await self.channel_layer.group_send(
                    self.room_group_name,
                    {
                        'type' : 'join_request',
                        'to' : self.user,
                        'from' : from_
                    }
                )

    async def chatroom_message(self, event):
        message = event['message']
        await self.send(text_data=json.dumps({
            'type' : event["event"],
            'message': message,
            'to': event["to"],
            'from': event['from']
        }))

    async def offer(self, event):
        await self.send(text_data=json.dumps({
            'type' : 'offer',
            'offer': event['offer'],
            'to': event["to"],
            'from': event['from']
        }))

    async def answer(self, event):
        await self.send(text_data=json.dumps({
            'type' : 'answer',
            'answer': event['answer'],
            'to': event["to"],
            'from': event['from']
        }))

    async def candidate(self, event):
        await self.send(text_data=json.dumps({
            'type' : 'candidate',
            'candidate': event['candidate'],
            'to': event["to"],
            'from': event['from']
        }))
    
    async def joiner(self, event):
        await self.send(text_data=json.dumps({
            'type' : 'joiner',
            'to': event["to"],
            'from': event['from']
        }))

    async def success_join(self, event):
        await self.send(text_data=json.dumps({
            'type' : 'success_join',
            'to': event["to"],
            'from': event['from']
        }))

    
    async def join_request(self, event):
        if event["to"]== self.user["id"]:
            from_ = event.get("user")
            await self.send(text_data=json.dumps({
                'type' : 'join_request',
                'to': self.user,
                'from': from_
            }))


    @database_sync_to_async
    def save_message(self, message):
        msg = Message(user=self.scope['user'], to=self.room, text=message)
        msg.save()

JavaScript

<script>
function updateTime() {
  document.getElementById('date-time').innerText = moment(Date.now()).format('Do MMMM, YYYY h:mm a');
}
setInterval(updateTime, 1000);

let myDetails = {
  "id": '{{request.user.user_profile.unique_id}}',
  "name": '{% if user.first_name %}{{user.first_name}}{% else %}{{user.username}}{% endif %}',
  "profile_pic":'{{request.user.user_profile.profile_pic.url}}',
};
let chatSocket;
let onlineList = document.getElementById("participantsList");
let chatList = document.getElementById("messages");
let audioBtn = document.getElementById("audioBtn");
let videoBtn = document.getElementById("videoBtn");
let screenBtn = document.getElementById("screen-btn");
let localVideoStream;
let localScreenStream;
let localStream;
let call_to;
let peerConnection = {};
let remoteOffer;
let numVideos = 0;
let showVideo = true;
let playAudio = true;
let videoDialog = document.getElementById("video-div");
let videoElement;
let waitList = [];
let showScreen = false;
screenBtn.style.color = "red";

function getLocation() {
  if (navigator.geolocation) {
      navigator.geolocation.getCurrentPosition(showPosition);
  } else {
      myPosition.innerHTML = "Geolocation is not supported by this browser.";
  }
}

// document.getElementById("location").style.display = "block";
function showPosition(position) {
  myPosition.style.display = "block";
  myPosition.innerHTML = "<i class='fas fa-map-marker-alt'></i> " + position.coords.latitude +
      ", " + position.coords.longitude;
}


let ICEconfig = {
  iceServers: [{
          urls: ["stun:bn-turn1.xirsys.com"]
      },
      {
          username: "WtJcHNTgNpN90FSvMVmZtWWVztiHEhbFfsdRyMS1f_PoMfbjWJSW_rVXiivC4VCOAAAAAGGZQvNhc2hpc2hzYXNtYWwx",
          credential: "6e26a8e4-4a32-11ec-8f0c-0242ac140004",
          urls: [
              "turn:bn-turn1.xirsys.com:80?transport=udp",
              "turn:bn-turn1.xirsys.com:3478?transport=udp",
              "turn:bn-turn1.xirsys.com:80?transport=tcp",
              "turn:bn-turn1.xirsys.com:3478?transport=tcp",
              "turns:bn-turn1.xirsys.com:443?transport=tcp",
              "turns:bn-turn1.xirsys.com:5349?transport=tcp"
          ]
      }
  ]
}
{% if request.user == room.admin %}
const mediaConstraints = {
  "video": true,
  audio: true
}
{% else %}
const mediaConstraints = {
  "video": false,
  audio: false
}
{% endif %}
const screenConstraints = {
  "video": {
      mediaSource: "screen"
  },
  audio: {
      echoCancellation: true,
      noiseSuppression: true
  }
}

let iceCandidatesList = {};
let conn = [];

function play() {
  var audio = new Audio('https://2u039f-a.akamaihd.net/downloads/ringtones/files/mp3/xperia-artic-54206.mp3');
  audio.play();
}

function playEnterRoom() {
  var audio = new Audio('https://www.setasringtones.com/storage/ringtones/9/aa925f907affb2e0998254d360689a2f.mp3');
  audio.play();
}

function accessMedia(user, screen = false) {
  console.log("access media " + myDetails.id)
  console.log(mediaConstraints)
  return navigator.mediaDevices.getUserMedia(mediaConstraints)
      .then(stream => {
          localVideoStream = stream;
          localStream = stream;
          muteAudio();
          muteVideo();
          onVideoAdd(user, localVideoStream);
      }).catch(function(error) {
          console.log(error)
      });
}

async function accessScreen(user) {
  console.log("access media " + myDetails.id)
  console.log(mediaConstraints)
  return navigator.mediaDevices.getDisplayMedia(screenConstraints)
      .then(stream => {
          localScreenStream = stream;
          localStream = stream;
          muteAudio(screen = false);
          muteVideo(screen = true);
          console.log(localScreenStream);
      }).catch(function(error) {
          console.log(error)
      });
}

function connectWebSocket() {
  var ws_scheme = window.location.protocol == "https:" ? "wss" : "ws";
  chatSocket = new WebSocket(ws_scheme + '://' + window.location.host + '/ws/chat/{{room.room_id}}/');
  console.log("Websocket connected");

  chatSocket.onopen = event => {
      chatSocket.send(JSON.stringify({
          "type": "login",
          "to": myDetails,
          "from": myDetails
      }));

      accessMedia(myDetails).then(
          bool => {
              playEnterRoom();
              chatSocket.send(JSON.stringify({
                  "type": "joiner",
                  "to": "all",
                  "from": myDetails,
              }));
          })

  }

  chatSocket.onmessage = async (e) => {
      const data = JSON.parse(e.data);
      console.log(data);

      let type = data.type;
      let user = data.from;
      if (data.to == "all") {
          if (type == "online_traffic") {
              let action = data.message;
              if (action == "remove") {
                  var elem = document.getElementById(user.id);
                  if (elem) {
                      elem.parentNode.removeChild(elem);
                  }
              } else if (action == "add") {
                if (!document.getElementById(user.id)){
                  onlineList.innerHTML +=`
                  <li id='${user.id}'>
                    <img src="${user.profile_pic}" alt="${user.name}">
                    <span class="participant-name">${user.name}</span>
                  </li>`;
                }
                  
              }
          }
          if (type == "joiner" && user.id != myDetails.id) {
              iceCandidatesList[user.id] = [];
              await call(user);
          }
      } else if (data.to.id == myDetails.id) {
          if (type == "success_join") {
              iceCandidatesList[user.id] = [];
              call(user);
          } else if (type == "offer") {
              iceCandidatesList[user.id] = [];
              console.log("Receiving call from " + user);
              await handleIncomingcall(user, data);
          } else if (type == "answer") {
              console.log("Call answered");
              peerConnection[user.id].pc.setRemoteDescription(data.answer);
          } else if (type == "candidate") {
              console.log("ICE candidate received");
              handleIncomingICEcandidate(user, data);
          }
      } else {
          if (type == "chat_message") {
              chatList.innerHTML +=
              `<div class="message">
                <div class="user-info">
                  <img
                    src="${user.profile_pic}"
                    alt="User">
                  <span class="user-name">${user.name}</span>
                </div>
                <div class="message-content">${data.message}</div>
              </div>`
          }
      }
  }
  }


if (chatSocket) {
  chatSocket.onclose = (e) => {
      alert("Socket disconnected");
      connectWebSocket();
  }
}


function sendSocket(data, to, from) {
  if (chatSocket) {
      data.to = to;
      data.from = from;
      chatSocket.send(JSON.stringify(
          data
      ));
  } else {
      console.log("Chat socket not connected")
  }
}
connectWebSocket();

function handleIncomingICEcandidate(user, data) {
  if (peerConnection[user.id] && data.candidate) {
      peerConnection[user.id].pc.addIceCandidate(new RTCIceCandidate(data.candidate));
  } else {
      console.log("RTC peer connection not set");
      iceCandidatesList[user.id].push(data.candidate);
  }
}

async function handleIncomingcall(user, data) {
  await createRTCPeerConnection(user);
  await createAndSendAnswer(user, data.offer);
}

function manageSocket() {
  if (activeBtn.checked) {
      connectWebSocket();
  } else {
      if (chatSocket) {
          chatSocket.close();
          console.log("Socket closed")
      } else {
          console.log("Socket not connected");
      }
  }
}


function createAndSendAnswer(user, remoteOffer) {
  console.log("hello")
  peerConnection[user.id].pc.setRemoteDescription(new RTCSessionDescription(remoteOffer));
  peerConnection[user.id].pc.createAnswer((answer) => {
      peerConnection[user.id].pc.setLocalDescription(new RTCSessionDescription(answer));
      sendSocket({
          type: "answer",
          answer: answer
      }, user, myDetails)
  }, error => {
      console.log(error);
  })
}

async function createAndSendOffer(user) {
  console.log("offer true")
  peerConnection[user.id].pc.createOffer((offer) => {
      console.log("hello")
      peerConnection[user.id].pc.setLocalDescription(new RTCSessionDescription(offer));
      sendSocket({
          type: "offer",
          offer: offer
      }, user, myDetails)
  }, (error) => {
      console.log("Error");
  });
}


async function call(user) {
  await createRTCPeerConnection(user);
  await createAndSendOffer(user);
}


async function createRTCPeerConnection(user, offer = false) {
  console.log("RTCPeerConnection connected");
  peerConnection[user.id] = {
      "name": user.name,
      "id": user.id,
      "pc": new RTCPeerConnection(ICEconfig)
  };
  // peerConnection = new RTCPeerConnection(null);
  if (localVideoStream) {
      localVideoStream.getTracks().forEach((track) => {
          peerConnection[user.id].pc.addTrack(track, localVideoStream);
      });
  }

  if (offer) {
      console.log("Creating Offer");
      peerConnection[user.id].pc.onnegotiationneeded = async (event) => createAndSendOffer(user);
  }
  peerConnection[user.id].pc.onicecandidate = (event) => handleICEcandidate(user, event);
  peerConnection[user.id].pc.ontrack = event => handleAddStream(user, event);
  return;
}


function handleAddStream(user, event) {
  console.log("track received");
  let stream = event.streams[0];
  onVideoAdd(user, stream);
}


function handleICEcandidate(user, event) {
  if (event.candidate == null)
      return;
  sendSocket({
      type: "candidate",
      candidate: event.candidate
  }, user, myDetails)
}


function muteAudio(screen = false) {
  if (localStream) {
      playAudio = !playAudio;
      if (playAudio) {
        const audiobtncolour = document.getElementById('audiobtncolour');
        audiobtncolour.style.fill  = "#2870de";
      } else {
        audiobtncolour.style.fill  = "red";
      }
      if (localStream.getAudioTracks()[0])
          localStream.getAudioTracks()[0].enabled = playAudio;
  }
}


function muteVideo(screen = false) {
  if (localStream) {
      showVideo = !showVideo;
      console.log(showVideo)
      if (showVideo) {
          if (showScreen){
              showScreen = false;
              localStream = localVideoStream;
              broadcast(localStream);
          }
          const videobtncolour = document.getElementById('videobtncolour');
          videobtncolour.style.fill  = "#2870de";
          onVideoAdd(myDetails, localVideoStream);
      } else {
        videobtncolour.style.fill  = "red";
      }
      localStream.getVideoTracks()[0].enabled = showVideo;
      
  } else {
      alert("Please allow video permission.");
  }
}


function broadcast(stream){
let track = stream.getVideoTracks()[0];
  for (let p in peerConnection) {
      let sender = peerConnection[p].pc.getSenders ? peerConnection[p].pc.getSenders().find(s => s.track && s.track.kind === track.kind) : false;

      if (sender) {
          console.log("hello " + track)
          sender.replaceTrack(track);
      }

  }
}

if (localScreenStream){
  localScreenStream.getVideoTracks()[0].onended = function () {
      screenBtn.style.color = "red";
};
}


async function shareScreen() {
if (showScreen){
      localScreenStream = await navigator.mediaDevices.getDisplayMedia();
      localStream = localScreenStream;
}
  else if (!localScreenStream) {
      localScreenStream = await navigator.mediaDevices.getDisplayMedia();
      localStream = localScreenStream;
  }
  muteVideo();
  localStream.getVideoTracks()[0].enabled = true;
  console.log(peerConnection);
  broadcast(localScreenStream);
  onVideoAdd(myDetails, localScreenStream);
  // senders.find(sender => sender.track.kind === 'video').replaceTrack(localScreenStream.getTracks()[0]);
  showScreen = true;
  screenBtn.style.color = "#2870de";
}


function replaceStreamTrack(stream) {
  for (let p in peerConnection) {
      if (p.pc) {
          p.pc.getSenders().forEach(function(sender) {
              console.log(sender);
              stream.getTracks.forEach(function(track) {
                  if (track == sender.track) {
                      p.pc.removeTrack(sender);
                  }
              })
          });
          createAndSendOffer({
              "name": pc.name,
              "id": pc.id
          });
      }
  }
}


function onVideoAdd(user, stream) {
  if (document.getElementById(`vid-${user.id}`)) {
      document.getElementById(`vid-${user.id}`).srcObject = stream;
  } else {
      var vidElement = document.createElement("video");
      vidElement.setAttribute('autoplay', '');
      vidElement.setAttribute('muted', '');
      vidElement.setAttribute('class', 'video-container video-js');
      vidElement.setAttribute('id', `vid-${user.id}`);
      vidElement.srcObject = stream;
      
      var videoContainer = document.querySelector(".video-container");
      videoContainer.innerHTML = ''; // Clear existing content
      videoContainer.appendChild(vidElement);
  }

  if (user.id == myDetails.id) {
      document.getElementById(`vid-${user.id}`).volume = 0;
  }
}



function sendMessage() {
  msg = document.getElementById("inputMsg").value;
  if (msg) {
      chatList.innerHTML +=
        `<div class="message">
          <div class="user-info">
            <img src="${myDetails.profile_pic}" alt="User">
            <span class="user-name">${myDetails.name}</span>
          </div>
          <div class="message-content">${msg}</div>
        </div>`
      sendSocket({
          "type": "chat_message",
          "message": msg
      }, "all", myDetails)
  }
  document.getElementById("inputMsg").value = "";
}

// Store connection information before refresh
function storeConnectionInfo() {
  // Store relevant connection information in local storage
  const connectionInfo = {
      peerConnections: peerConnection,
      localStream: localStream,
      showVideo: showVideo,
      playAudio: playAudio,
      showScreen: showScreen,
      localScreenStream: localScreenStream
  };
  localStorage.setItem('connectionInfo', JSON.stringify(connectionInfo));
}
// Event listener for page refresh
window.addEventListener('beforeunload', storeConnectionInfo);

// Event listener for page load


var input = document.getElementById("inputMsg");
input.addEventListener("keyup", function(event) {
  if (event.keyCode === 13) {
      event.preventDefault();
      sendMessage();
  }
});
let recorder; // Global variable to store the recorder instance
let isRecording = false;

function toggleRecording() {
const recordIcon = document.getElementById('recordIcon');

if (!isRecording) {
  startRecording();
  recordIcon.style.fill = 'red'; // Change the fill color to indicate recording
} else {
  stopRecording();
  recordIcon.style.fill = '#292d32'; // Change the fill color back to default
}
isRecording = !isRecording;
}


function startRecording() {
// Create a media stream that combines both video and audio
const combinedStream = new MediaStream();
localStream.getTracks().forEach(track => combinedStream.addTrack(track));

// Create a recorder instance
recorder = new RecordRTC(combinedStream, {
  type: 'video', // or 'audio' for audio-only recording
});

// Start recording
recorder.startRecording();
}

function stopRecording() {
if (recorder) {
  // Stop recording
  recorder.stopRecording(function() {
    const recordedBlob = recorder.getBlob();
    
    // Create a download link for the recorded file
    const downloadLink = document.createElement('a');
    downloadLink.href = URL.createObjectURL(recordedBlob);
    downloadLink.download = 'recorded-meeting.mp4'; // Change the filename as needed
    downloadLink.innerHTML = '<svg viewBox="0 0 72 72" xmlns="http://www.w3.org/2000/svg"><g style="fill:none;stroke:#000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;stroke-width:2"><path d="m36.0851 17.1466v18.8699"/><path d="m42.24 29.8951-6.14 6.14"/><path d="m29.91 29.8951 6.14 6.14"/><path d="m56.8961 54.9782h-41.8193c-1.65 0-3-1.35-3-3v-7.5762c0-1.65 1.35-3 3-3h41.8194c1.65 0 3 1.35 3 3v7.5762c-.0001 1.65-1.3501 3-3.0001 3z"/><circle cx="19.0173" cy="48.2886" r="2"/></g>Download </svg>';
    
    // Add the download link to the page
    const downloadContainer = document.getElementById('download-container');
    downloadContainer.appendChild(downloadLink);

    recorder = null;
  });
}
}

  </script>

I would appreciate any guidance or code examples on how to modify my implementation to create a new RTCPeerConnection for each remote peer and avoid the mentioned error. Here’s the github repo https://github.com/Codewithshagbaor/Extra/tree/main Thank you!

aurelia validation display errors

i am using aurelia-validation and i have 2 input field the problem when i display error , error show together , i want if error for input one show on span with class input-one
and i want if error for input tow show on span with class input-tow , i don’t want use bootstrap ,
please help me how do that

i am using aurelia-validation and i have 2 input field the problem when i display error , error show together , i want if error for input one show on span with class input-one
and i want if error for input tow show on span with class input-tow , i don’t want use bootstrap ,
please help me how do that

How To Capture Form Data using OnChange

I built up a page on my website as a place to perform testing of functions that I write (30 or 40 of them to date). I use a drop-down box to list the functions out by function name. When one of them is selected, I use an onChange with “window.location” to fire that function via a Select Case structure, passing the index on the query string via this.selectedIndex in the OnChange. All of this worked fine until I decided that I would also like the value of the selected option (name of the function being tested) as well (not just the index value). I found through study that the window.location does not post any form values back, so they are not available. I kept on researching and found that the “location.reload” is supposed to post back the data, but that doesn’t work either.

So, I figured that I could pass the option value data via the query string perhaps by using “this.selectedOptions”, but that doesn’t work either. I have cut and paste a snippet of the code below, which again, works fine, but I can’t get the text value of the selected option.

enter code here
<form name="ThisForm" action="<%=Request.ServerVariables("SCRIPT_NAME")%> method="post">

            <b>Select Test Category:<b>&nbsp;
                            
            <select class="rounded" name="cboSearchCategories" id="cboSearchCategories" onChange='window.location="<%=sRootDomain%>/testcode/template/testcodepage.asp?TestCategory=" + this.selectedIndex;'                
                <option value="Select One">Select One</option>
                <option value="SearchEquipmentDB()">SearchEquipmentDB()-Case #1</option>
                <option value="DisplaySingleItem()">DisplaySingleItem()-Case #2</option>
                <option value="CreateJSONSchema()">CreateJSONSchema()-Case #3</option>
                <option value="UnlockChilkatAPI()">UnlockChilkatAPI()-Case #4</option>
            </select>
</form>

Please let me know if there is a way to make this work, without using a submit button. Much appreciated! Note that this code is written using ASP Classic, but would be pertinent for any form submission.

Writing terminal emulator in react, and ls command is not working in subfolder in root folder

I am trying to write a terminal emulator in a react app, for a personal coding website. I’m trying to create basic functionality, namely ‘pwd’, ‘ls’, ‘cat’ and ‘cd’. I have a react component that does all the work for the file explorer, which is basically used to keep track of the current folder. Here is the code:

import React, { useState } from 'react';

const FileExplorer = () => {
  const [currentDirectory, setCurrentDirectory] = useState('/home/user');
  const [fileContents, setFileContents] = useState({
    '/home/user/file1.txt': 'Content of file1.txt',
    '/home/user/file2.txt': 'Content of file2.txt',
    '/home/user/folder1': {
      '/home/user/file3.txt': 'Content of file3.txt',
    },
  });

  const [parentDirectory, setParentDirectory] = useState(null);

  const getCurrentDirectoryContents = () => {
    return listDirectory(currentDirectory);
  };

  const listDirectory = (directory) => {
    const entries = Object.keys(fileContents);
    const currentDirectoryEntries = entries.filter((path) =>
      path.startsWith(directory)
    );

    console.log('Current Directory Entries:', currentDirectoryEntries);

    const subdirectoryEntries = currentDirectoryEntries.filter(
      (path) => typeof fileContents[path] === 'object'
    );
    subdirectoryEntries.forEach((subdirectory) => {
      const subdirectoryPath = subdirectory + '/';
      const subdirectoryContents = listDirectory(subdirectoryPath);
      currentDirectoryEntries.push(...subdirectoryContents);
    });

    return currentDirectoryEntries;
  };

  const changeDirectory = (newDirectory) => {
    if (newDirectory === '..') {
      if (parentDirectory) {
        setCurrentDirectory(parentDirectory);
        setParentDirectory(null);
      } else {
        return 'cd: ../: No such file or directory';
      }
    } else if (newDirectory.startsWith('/')) {
      if (fileContents[newDirectory] && typeof fileContents[newDirectory] === 'object') {
        setParentDirectory(currentDirectory);
        setCurrentDirectory(newDirectory);
      } else {
        return `cd: ${newDirectory}: Not a directory`;
      }
    } else {
      const newPath = currentDirectory + '/' + newDirectory;
      if (fileContents[newPath] && typeof fileContents[newPath] === 'object') {
        setParentDirectory(currentDirectory);
        setCurrentDirectory(newPath);
      } else {
        return `cd: ${newDirectory}: Not a directory`;
      }
    }
  };

  const readFile = (filePath) => {
    if (filePath.startsWith('/')) {
      if (fileContents[filePath]) {
        return fileContents[filePath];
      } else {
        return `cat: ${filePath}: No such file or directory`;
      }
    } else {
      const fullPath = currentDirectory + '/' + filePath;
      if (fileContents[fullPath]) {
        return fileContents[fullPath];
      } else {
        return `cat: ${filePath}: No such file or directory`;
      }
    }
  };

  const ls = () => {
    const currentDirContents = getCurrentDirectoryContents();
    const relativePaths = currentDirContents.map((path) =>
      path.substring(currentDirectory.length)
    );
    return relativePaths.join(' ');
  };

  return { currentDirectory, getCurrentDirectoryContents, changeDirectory, readFile, ls };
};

export default FileExplorer;

The issue is, when I ‘cd’ into folder1, the file directory knows it’s in folder1 (pwd returns /home/user/folder1) but when I type ‘ls’, it does not print out that file3 is in the folder. Nor can I ‘open’ file3 using the cat command like I can the files in the root folders. What am I doing wrong here?

I’ve tried changing the folder structure around, and changing some of the functions, but no avail.

Display an element generated inside the canvas outside of the canvas – fabricjs

Now when pointing at the intersection of lines, a black square dot is displayed. Inside the canvas everything is fine, it is displayed completely, but if you point at the edge of the block where there is also an intersection, the square dot is displayed strictly on the borders of the canvas. Is there any way to display a black square point when hovering outside the canvas on either side.

How it works now
The way it should be displayed

const canvasSize = { width: 500, height: 500 }
const cellDimensions = { width: 50, height: 50 }
const borderStrokeWidth = 3
const objectTypes = {
    frame: 'frame',
    gridPoint: 'point',
    gridLine: 'line',
}

let drawingCanvas

initCanvas()

function initCanvas(id = 'canvas') {

    drawingCanvas = new fabric.Canvas(id, {
        height: canvasSize.height + borderStrokeWidth,
        width: canvasSize.width + borderStrokeWidth,
        hoverCursor: 'default',
        backgroundColor: 'gray',
        selection: false,
    })

   drawingCanvas.on('mouse:over', (e) => {
        if (e.target?.type === objectTypes.gridPoint) {
            drawingCanvas.bringToFront(e.target)
            e.target.set('opacity', 1)
            drawingCanvas.renderAll()
        }
    })

    drawingCanvas.on('mouse:out', (e) => {
        if (e.target?.type === objectTypes.gridPoint) {
            e.target.set('opacity', 0)
            drawingCanvas.renderAll()
        }
    })

    drawingCanvas.on('object:modified', (e) => {
        const obj = e.target
        const { y: top, x: left } = obj.getPointByOrigin('left', 'top')
        obj.set({ top, left, originX: 'left', originY: 'top' })
        drawingCanvas.renderAll()
    })

    drawGrid()
}

function drawGrid() {
    const { width: colSize, height: rowSize } = cellDimensions

    const makePoint = (x, y) => {
        const r = 8
        const point = new fabric.Rect({
            top: y - r,
            left: x - r,
            width: r * 2,
            height: r * 2,
            rx: 1,
            ry: 1,
            fill: 'black',
            hasControls: false,
            hasBorders: false,
            selectable: false,
            opacity: 0,
            type: objectTypes.gridPoint,
            hoverCursor: 'pointer',
        })

        drawingCanvas.add(point)
    }

    const drawLine = (params) => {
        const line = new fabric.Line(params, {
            stroke: 'yellow',
            strokeWidth: borderStrokeWidth,
            selectable: false,
            evented: false,
            type: objectTypes.gridLine,
        })
        drawingCanvas.add(line)
    }

    const makeRows = () => {
        const rowsCount = canvasSize.height / rowSize
        for (let i = 0; i <= rowsCount; i++) {
            const y = i * rowSize
            drawLine([0, y, canvasSize.width, y])
        }
    }

    const makeCols = () => {
        const colsCount = canvasSize.width / colSize
        for (let i = 0; i <= colsCount; i++) {
            const x = i * colSize
            drawLine([x, 0, x, canvasSize.height])
        }
    }

    const makePoints = () => {
        const rowsCount = canvasSize.height / rowSize
        const colsCount = canvasSize.width / colSize
        for (let i = 0; i <= colsCount; i++) {
            const x = i * colSize
            for (let j = 0; j <= rowsCount; j++) {
                const y = j * rowSize
                makePoint(x, y)
            }
        }
    }

    makeRows()
    makeCols()
    makePoints()
}

<canvas id="canvas"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/4.4.0/fabric.min.js"></script>

Tried increasing the padding at the canvas, but that didn’t produce any results.