The offset of the data in the column with the IMPORTAGE function

Well, I wrote my own code that works almost well. but unfortunately, the onEdit function does not take into account that the range is changed by the IMPORTAGE function. I had to add a checkbox, when changing which the function starts working. but I would like to automatically track changes, taking into account that the range is changed by the IMPORTAGE function.

The code simply aligns the range AL4:AL103 to the last filled cell in the range AK4:AK103

function onEdit(e) {
if (e && e.source) {
if (e.source.getSheetName() !== 'Calculation') return;
}
if (e) {
if (e.range && e.range.columnStart == 37 && e.range.rowStart >= 1 && e.range.rowEnd <= 1) {
const sheet = e.range.getSheet();
const values = sheet.getDataRange().getValues();
const valuesA = sheet.getRange('AK4:AK102').getValues();
const valuesB = sheet.getRange('AL4:AL102').getValues();
// Здесь обрабатываем filteredValues
// Подсчёт значений во всём диапазоне
const allValuesA = valuesA.flat(); // Сглаживаем массив значений
const stringValuesA = allValuesA.filter(String); // Удаляем нестроковые значения
const countA = stringValuesA.length; // Считаем количество оставшихся значений
const allValuesB = valuesB.flat(); // Сглаживаем массив значений
const stringValuesB = allValuesB.filter(String); // Удаляем нестроковые значения
const countB = stringValuesB.length; // Считаем количество оставшихся значений
// Находим индекс последней строки с данными в диапазоне AK4:A103
const lastRowWithDataIndexA = valuesA.findLastIndex(row => row.join('').trim() !== '')+4;
// Находим индекс последней строки с данными в диапазоне AL4:AL103
const lastRowWithDataIndexB = valuesB.findLastIndex(row => row.join('').trim() !== '')+4;
const firstRowWithDataIndexB = valuesB.findIndex(row => row.join('').trim() !== '')+4;
const firstDataB = lastRowWithDataIndexB-countB+1
const targetFirstDataPosB = lastRowWithDataIndexA-countB+1
const targetRange = sheet.getRange(targetFirstDataPosB, 38, 10, 1); // Целевой диапазон смещен на rowCount строк вниз
sheet.getRange(firstDataB, 38, valuesB.length, 1).copyTo(targetRange, {contentsOnly: true}); // Копирование содержимого столбца B в целевой диапазон
const delData = targetFirstDataPosB-4
if (targetFirstDataPosB >= 4) {
sheet.getRange(4, 38, delData, 1).clear({contentsOnly: true});
}   
}
}
}

I wanted my code to track changes in AK4:AK103 cells. which in turn change the IMPORTAGE functions. the onEdit function did not help me in this, I had to add a checkbox to cell AK1. when changing which, the function started working.

can you tell me how best to implement this?

can the onChange or onSelectionChange functions help me with this? I couldn’t get them to work in my code.

How can I make a transition for appending a child which increases the offset height in HTML, JS, or CSS?

When I try to append a child to an element, it increases the offset height of the element. Even when a transition is used, it just appends the child instantly. I just want to make a transition for that.

const p = document.createElement("p");
p.innerText = "Sample text";
document.getElementById("main").appendChild(p);
div#main {
  transition: all 0.5s ease;
}
<div id="main"></div>

update laravel10->11 livewire 2->3 Error with scripts Uncaught SyntaxError: expected expression, got ‘<'

I have a Laravel project in which I have livewire, I tried to update them (Laravel from 10 to 11 and livewire from 2 to 3) following the guides for Laravel and for livewire.

After updating every packages and configs I started my project with laragon and vite as usual but got this error: Uncaught SyntaxError: expected expression, got ‘<‘, and no js works on any pages!

After 2 days of searching on the internet and trying stuff in my project I found out that the error happened because of @livewireScripts()/@livewireStyles() in my layout, after removing them I didn’t have the error but my js scripts would not work after that (which is normal I guess)

So could someone please help me on this, I really don’t understand this.

Here are some files. I know it is a lot and I am sorry, I don’t even know if those are relevant enough, I am just lost.

app.js before:

import '@fortawesome/fontawesome-free/js/all.js';
import Alpine from 'alpinejs';
import './bootstrap';
import './alpine';
import './data';
import './doc';
import './filter';

import { popoverinit } from './popover';
import '../sass/app.scss';
let colors;
window.Alpine = Alpine;
Alpine.start();

app.js after (deleted alpine start as it comes automatically with livewire 3 as said in the docs):

import '@fortawesome/fontawesome-free/js/all.js';
import './bootstrap';
import './data';
import './doc';
import './filter';

import { popoverinit } from './popover';
import '../sass/app.scss';
import { livewire_hot_reload } from 'virtual:livewire-hot-reload';

livewire_hot_reload();

vite.config.mjs:

import { fileURLToPath, URL } from 'url';
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import laravel from 'laravel-vite-plugin';
import livewire from '@defstudio/vite-livewire-plugin';

export default defineConfig({
  build: {
    sourcemap: false,
    minify: false,
  },
  plugins: [
    laravel({
      input: ['resources/js/app.js', 'resources/js/update_product.js', 'resources/sass/app.scss', 'resources/js/Vue/main.js', 'resources/js/charts/product.js'],
      refresh: true,
    }),
    vue(),
    livewire({
      refresh: ['resources/sass/app.scss'],
    }),
  ],
  resolve: {
    alias: [
      { find: '@composition', replacement: fileURLToPath(new URL('./resources/js/Vue/composition', import.meta.url)) },
      { find: '@node_modules', replacement: fileURLToPath(new URL('./node_modules', import.meta.url)) },
    ],
  },
});

config/livewire.php:

<?php
return[
    'class_namespace' => 'App\Http\Livewire',
    'view_path' => resource_path('views/livewire'),
    'layout' => 'layouts.app',
    'asset_url' => env('APP_URL', 'http://localhost'),
    // new ones that came with livewire 3
    'legacy_model_binding' => false,
    'inject_assets' => true,
    'inject_morph_markers' => true,
    'navigate' => [
        'show_progress_bar' => true,
        'progress_bar_color' => '#22dd99',
    ],
];

layouts/app-livewire.blade.php before:

<!doctype html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">

<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="csrf-token" content="{{ csrf_token() }}" />
    <title>My site</title>
    <link rel="icon" type="image/png" sizes="96x96" href="{{ asset('favicons/favicon-96x96.png') }}">
    <link rel="icon" type="image/png" sizes="32x32" href="{{ asset('favicons/favicon-32x32.png') }}">
    <link rel="icon" type="image/png" sizes="16x16" href="{{ asset('favicons/favicon-16x16.png') }}">

    @vite(['resources/js/app.js', 'resources/sass/app.scss'])
    <!-- Resources -->
    <script src="https://cdn.amcharts.com/lib/5/index.js"></script>
    <script src="https://cdn.amcharts.com/lib/5/xy.js"></script>
    <script src="https://cdn.amcharts.com/lib/5/themes/Animated.js"></script>
    <script src="//cdn.amcharts.com/lib/5/locales/fr_FR.js"></script>
    <script src="https://cdn.amcharts.com/lib/5/percent.js"></script>

    @livewireStyles()
    @stack('styles')


    <style>
        .swal2-container {
            z-index: 2100;
            margin-top: 4em;
        }
    </style>
</head>

<body>
    @include('partials.header')
    <div class="leftpanel">
        @include('partials.sidebar')
    </div>


    <div class="rightpanel">
        <div class="d-flex flex-column">
            @yield('header')
            <div class="content">

                @yield('content')
            </div>
            @include('partials.footer')
        </div>
    </div>

    @livewireScripts()

    @include('partials.scripts')

    @include('partials.messages')

    @stack('scripts')
</body>

</html>

layouts/app-livewire.blade.php after:
<!doctype html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">

<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="csrf-token" content="{{ csrf_token() }}" />
    <title>My site</title>
    <link rel="icon" type="image/png" sizes="96x96" href="{{ asset('favicons/favicon-96x96.png') }}">
    <link rel="icon" type="image/png" sizes="32x32" href="{{ asset('favicons/favicon-32x32.png') }}">
    <link rel="icon" type="image/png" sizes="16x16" href="{{ asset('favicons/favicon-16x16.png') }}">

    @vite(['resources/js/app.js', 'resources/sass/app.scss'])
    <!-- Resources -->
    <script src="https://cdn.amcharts.com/lib/5/index.js"></script>
    <script src="https://cdn.amcharts.com/lib/5/xy.js"></script>
    <script src="https://cdn.amcharts.com/lib/5/themes/Animated.js"></script>
    <script src="//cdn.amcharts.com/lib/5/locales/fr_FR.js"></script>
    <script src="https://cdn.amcharts.com/lib/5/percent.js"></script>

    @stack('styles')
</head>

<body>
    @include('partials.header')
    <div class="leftpanel">
        @include('partials.sidebar')
    </div>


    <div class="rightpanel">
        <div class="d-flex flex-column">
            @yield('header')
            <div class="content">

                @yield('content')
            </div>
            @include('partials.footer')
        </div>
    </div>

    @include('partials.scripts')

    @include('partials.messages')

    @stack('scripts')
</body>

</html>

view.blade.php (scripts part) before:

<div>
... my view
@push('scripts')
        <script type="module">
            const regex = /[éèêëïçùô]/i;

            $(document).on('input', '#newName, #editName', function() {
                if (regex.test($(this).val())) {
                    $(this).css('border', '1px solid red');
                    $(this).css('box-shadow', '0 0 0 0.25rem rgba(220, 53, 69, 0.25)');
                } else {
                    $(this).css('border', '1px solid #86b7fe');
                    $(this).css('box-shadow', '0 0 0 0.25rem rgba(13, 110, 253, 0.25)');
                }
            });

            $(document).on('show.bs.modal', '#modal', function(e) {
                const btn = e.relatedTarget;

                if (btn.id === 'editBtn') {
                    $('.modal-title').text('Modifier personnel');
                    $('#newName').hide();

                    const editNameInput = $('#editName');
                    editNameInput.show();
                    editNameInput.val(btn.getAttribute('pName'));
                    editNameInput.attr('pId', btn.getAttribute('pId'));
                } else {
                    $('.modal-title').text('Nouveau personnel');
                    $('#editName').hide();

                    const newNameInput = $('#newName');
                    newNameInput.show();
                    newNameInput.val('');
                }
            });

            $(document).on('shown.bs.modal', '#modal', function(e) {
                const btn = e.relatedTarget;

                if (btn.id === 'editBtn') {
                    $('#editName').trigger('focus');
                } else {
                    $('#newName').trigger('focus');
                }
            });

            $(document).on('keyup', '#newName, #editName', function(e) {
                if (e.key === 'Enter') {
                    if (regex.test($(this).val())) {
                        Swal.fire({
                            icon: 'error',
                            toast: true,
                            text: 'Les caractères spéciaux ne sont pas autorisés',
                            position: 'top-right',
                            showConfirmButton: false,
                            timer: 3000
                        })
                        return;
                    }
                    const modal = bootstrap.Modal.getInstance(document.getElementById('modal'));
                    modal.hide();
                    if ($(this).attr('id') === 'newName') {
                        @this.addPersonnel($(this).val());
                    } else {
                        @this.editPersonnel($(this).attr('pId'), $(this).val());
                    }
                }
            });

            $(document).on('click', '#deleteBtn', function() {
                if (confirm(`Voulez-vous vraiment supprimer ce personnel: ${$(this).attr('pName')}? `)) {
                    @this.deletePersonnel($(this).attr('pId'));
                }
            });
        </script>
    @endpush
</div>

view.blade.php (scripts part) after:

<div>
...my view
</div>
@script
    <script type="module">
            const regex = /[éèêëïçùô]/i;

            $(document).on('input', '#newName, #editName', function() {
                if (regex.test($(this).val())) {
                    $(this).css('border', '1px solid red');
                    $(this).css('box-shadow', '0 0 0 0.25rem rgba(220, 53, 69, 0.25)');
                } else {
                    $(this).css('border', '1px solid #86b7fe');
                    $(this).css('box-shadow', '0 0 0 0.25rem rgba(13, 110, 253, 0.25)');
                }
            });

            $(document).on('show.bs.modal', '#modal', function(e) {
                const btn = e.relatedTarget;

                if (btn.id === 'editBtn') {
                    $('.modal-title').text('Modifier personnel');
                    $('#newName').hide();

                    const editNameInput = $('#editName');
                    editNameInput.show();
                    editNameInput.val(btn.getAttribute('pName'));
                    editNameInput.attr('pId', btn.getAttribute('pId'));
                } else {
                    $('.modal-title').text('Nouveau personnel');
                    $('#editName').hide();

                    const newNameInput = $('#newName');
                    newNameInput.show();
                    newNameInput.val('');
                }
            });

            $(document).on('shown.bs.modal', '#modal', function(e) {
                const btn = e.relatedTarget;

                if (btn.id === 'editBtn') {
                    $('#editName').trigger('focus');
                } else {
                    $('#newName').trigger('focus');
                }
            });

            $(document).on('keyup', '#newName, #editName', function(e) {
                if (e.key === 'Enter') {
                    if (regex.test($(this).val())) {
                        Swal.fire({
                            icon: 'error',
                            toast: true,
                            text: 'Les caractères spéciaux ne sont pas autorisés',
                            position: 'top-right',
                            showConfirmButton: false,
                            timer: 3000
                        })
                        return;
                    }
                    const modal = bootstrap.Modal.getInstance(document.getElementById('modal'));
                    modal.hide();
                    if ($(this).attr('id') === 'newName') {
                        $wire.addPersonnel($(this).val());
                    } else {
                        $wire.editPersonnel($(this).attr('pId'), $(this).val());
                    }
                }
            });

            $(document).on('click', '#deleteBtn', function() {
                if (confirm(`Voulez-vous vraiment supprimer ce personnel: ${$(this).attr('pName')}? `)) {
                    $wire.deletePersonnel($(this).attr('pId'));
                }
            });
    </script>
@endscript

controller.php (just to show the render method) before:

public function render()
    {
        return view('livewire.view')->extends('layouts.app-livewire');
    }

controller.php after:

#[Layout('layouts.app-livewire')]
    public function render()
    {
        return view('livewire.view');
    }

Object mutation [duplicate]

Why does this code error:

const obj = {
  one: 1,
  two: 2
}

obj = {
  one: 11,
  two: 22
}

But this code works:

const obj = {
  one: 1,
  two: 2
}

obj.one = 33
console.log(obj);

What does the following sentence mean?

though a const binding to an object can itself not be changed and will continue to point at the same object, the contents of that object might change.

Source

How can I better study what I am trying to follow for my career [closed]

I’m starting an ADS college right now and I’m very interested in information security. Since I was a teenager, I have always dreamed of understanding how a machine and its vulnerabilities work, from data that is not physically stored to understanding how a defense system designed by a group of programmers works. I have a desire to be able to assemble and disassemble these systems. That dream still lives in me, and as time goes on, it continues to be nurtured, but I feel like I still don’t know enough.

Knowing that there is no straight path to this type of learning, I would like to ask the community for tips. What should I study as essential to becoming a good information security programmer or ethical hacker (I don’t know if both are the same thing)?

I hope that someone with experience in programming, development of cyber defense systems, or even with experience in intrusions or intrusion investigations, can guide me.

Saving Annotated PDF Files Using PDF.js

I’ve been working on a project where I need to save a PDF file after annotations have been added using PDF.js. Despite being able to successfully download the file with annotations, I’ve been unable to directly save the annotated file through my implementation.

Is it possible to save a PDF file with annotations using PDF.js? If so, could someone kindly provide a small demo or guide on the method you used to achieve this? Any tips, best practices, or code snippets would be greatly appreciated.

Thank you in advance for your assistance. I believe that if downloading the file with annotations is feasible, then saving it should be possible as well, and I’m eager to learn the right approach.

This is what I have so far, im able to get all the form fields except the annotated file on the backend,

<script>

document.addEventListener('DOMContentLoaded', ()= > {
    const iframe= document.getElementById('iframe_pdfjs')

    iframe.onload= function() {
        const iframeWindow = iframe.contentWindow

        // Listen for pagesloaded event to ensure PDF.js is fully initialized
        iframeWindow.addEventListener('pagesloaded', function() {
            console.log('PDF.js pages loaded')

            // Debugging: Log the PDFViewerApplication and related objects
            console.log('PDFViewerApplication:',
                        iframeWindow.PDFViewerApplication)
            console.log('PDF Viewer:',
                        iframeWindow.PDFViewerApplication.pdfViewer)
            console.log('Annotation Storage:',
                        iframeWindow.PDFViewerApplication.pdfViewer.annotationStorage)
            console.log('Annotation Editor Layer:',
                        iframeWindow.PDFViewerApplication.pdfViewer.annotationEditorLayer)

            // Try to access annotationStorage directly
            const annotationStorage = iframeWindow.PDFViewerApplication.pdfViewer.annotationStorage
            if (!annotationStorage) {
                console.error('Annotation storage not available')
                alert('Annotations could not be retrieved.')
                return
            }

            const annotations = annotationStorage.serialize()
            if (!annotations) {
                console.error('Annotations are null or undefined')
                alert('Failed to serialize annotations.')
                return
            }

            // Proceed to save the document
            document.getElementById('saveForm').addEventListener('submit', async function(event) {
                event.preventDefault()
                try {
                    const pdfDoc = iframeWindow.PDFViewerApplication.pdfDocument
                    const data = await pdfDoc.saveDocument({xfdfString: annotations})
                    const blob = new Blob([new Uint8Array(data)], {type: 'application/pdf'})

                    // Log to confirm the blob was created
                    console.log('Blob created:', blob)
                    console.log('Blob size:', blob.size)

                    const formData = new FormData()
                    formData.append('signed_document', blob,
                                    'signed_document.pdf')
                    formData.append('first_name', document.getElementById(
                        'id_first_name').value)
                    formData.append('last_name', document.getElementById(
                        'id_last_name').value)
                    formData.append(
                        'email', document.getElementById('id_email').value)
                    formData.append(
                        'phone', document.getElementById('id_phone').value)
                    formData.append(
                        'dob', document.getElementById('id_dob').value)
                    formData.append(
                        'gender', document.getElementById('id_gender').value)

                    const response= await axios.post('.', formData, {
                        headers: {
                            'X-CSRFToken': '{{ csrf_token }}',
                            'Content-Type': 'multipart/form-data'
                        }
                    })

                    if (response.status == = 200) {
                        window.location.href = '{% url "sign:thank_you" %}'
                    } else {
                        alert('Failed to save the signed document.')
                    }
                } catch(error) {
                    console.error('There was an error!', error)
                    alert('Failed to save the signed document.')
                }
            })
        })
    }
});
</script>

Cannot update headers after they have been sent to the client

I am working on a blog app for my internship, this is my second project in ExpressJS and I have encountered a problem I did not in the previous one (a library management system project I made for college).

const register = asyncHandler(async (req, res) => {
  try {
    const { email, username, name, password } = req.body;
    if (!email || !username || !name || !password) {
      res.status(400).json({ message: "please enter credentials" });
      throw new Error();
    }

    const checkEmail = await User.findOne(email);
    if (checkEmail) {
      res.status(400).json({ message: "email already registered" });
      throw new Error();
    }

    const checkUsername = await User.findOne({ username });
    if (checkUsername) {
      res.status(400).json({ message: "username already exists" });
      throw new Error();
    }

    const salt = await bcrypt.genSalt(69);
    const hashedPassword = await bcrypt.hash(password, salt);

    const user = User.create({
      email,
      username,
      name,
      hashedPassword,
    });

    res.status(200).json(user);
  } catch (error) {
    res.status(500).json({ message: "something happened, try again" });
    throw new Error();
  }
});

When I try to test this controller function, it runs the first response statement regardless of whether I enter the credentials or not (I am testing using postman), the terminal shows the following error

Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client

I am literally following the same method as I did in my first project where I did not encounter this error.

I tried looking for solutions on YouTube, the solution suggested in most of the videos was to return the response statement but I can’t use return since I cannot do “throw new Error” after that.

an idea to make an image of a manufacturing process interactive…though at first thought it seems like a css nightmare. Would you agree? [closed]

I have an image of a manufacturing process where ideally I’d like the boxes to be interactive and link to the subsequent areas.
I figured building it within a site (or in my case a proprietary software) would be easiest but I may lose the finer details of the image i.e. process flow lines etc.

My second thought was to create transparent divs/buttons over the image processes to make them seemingly interactable…could use a grid and go row by row and that doesn’t seem too bad. however, if I were to consider responsiveness…this seems like it could be something short of css nightmare fuel

Anyone have any other ideas that I may be forgetting…though keep in mind that being in a proprietary environment, using third party tools will likely not be possible.

This is the process diagram I was hoping to use:
manufacturing process

Navbar menu-icon and menu-items not behaving as expected

The menu Item should be hidden for default larger screens as for my stylesheet, and the menu-icon should be clickable as for my . The output should be a Menu Icon appearing in smaller screens 800px below then shows Menu items when clicked.

Here are the relevant codes:
html:

<div class="navbar">
                <div class="logo">
                    <img src="images/New Project.png" alt="" width="125px">
                </div>
                <nav class="nav" id="MenuItems">
                    <ul>
                        <li><a href="">Home</a></li>
                        <li><a href="">Products</a></li>
                        <li><a href="">Contacts</a></li>
                        <li><a href="">Account</a></li>
                    </ul>
                </nav>
                <img src="images/cart.png" width="30px" height="30px" alt="">
                <img src="images/menu.png" class="menu-icon" onclick="menutoggle()">
            </div>

js:

 <!-- js for toggle menu -->

    <script>
        var MenuItems = document.getElementById("MenuItems");

        MenuItems.style.maxHeight = "0px";

        function menutoggle()
        {
            if(MenuItems.style.maxHeight == "0px")
                {
                    MenuItems.style.maxHeight = "200px"      
                }
            else
                {
                    MenuItems.style.maxHeight = "0px" 
                }
        }
    </script>

css:

.menu-icon{
    width: 28px;
    margin-left: 20px;
    display: none;
}

/* Navbar for smaller screens */

@media only screen and (max-width: 800px){
    nav ul{
        position: absolute;
        top: 70px;
        left: 0;
        background: #333;
        width: 100px;
    }

    nav ul li{
        display: block;
        margin-right: 50px;
        margin-top: 10px;
        margin-bottom: 10px;
    }

    nav ul li a{
        color: #fff;
    }

    .menu-icon{
        display: block;
        cursor: pointer;
    }

}

I am having trouble debugging my code, I cannot find and Identify if it’s my script or style.css that causes the issue.

Here are the full codes in case someone need it.
index.html
style.css

The navbar should appear with a menu icon that is clickable and shows the contents (menu-items)
but I can’t seem to find the issue because of my spaghetti code, I am sorry.

How do i create this look?

I am trying to clone eat-curious website for personal practice. But here I am stuck at the drooling yet? section.

enter image description here

I tried understanding the code in developer console, where i got the svg for drooling yet text. So this is how it looks now.

enter image description here

This is probably a very basic designing question but how do i curve the green section to match the text?

<div className="w-full h-screen bg-[#042f1a] flex flex-col">
  <svg className="w-full transform translate-y-1/3" class="tiles__title" width="1224" height="312" viewBox="0 0 1224 312" fill="none" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="none">
            <g clip-path="url(#clip0_587_15588)">
              <path
                d="M53.5642 159.552C95.363 133.013 98.7096 180.342 100.383 212.379C102.173 246.706 109.753 311.182 58.0486 309.41C38.8225 309.611 19.5964 309.795 0.353516 310.012C0.671441 290.86 0.738378 271.708 0.738378 252.555C0.738378 233.403 0.637975 214.218 0.353516 195.065C17.7223 182.698 35.4759 170.85 53.5642 159.552ZM53.9658 231.532C53.1124 205.962 51.2383 203.572 47.4734 205.26C46.7204 205.594 46.1013 205.878 45.3483 206.413C45.3818 215.939 45.683 225.899 45.9842 236.061C46.2854 246.222 46.5364 254.461 46.8878 261.547C47.6575 261.38 48.4439 261.229 49.2136 261.062C53.2295 260.226 54.8024 256.516 53.9658 231.548V231.532Z"
                fill="#FFF6F6"></path>
              <path
                d="M186.422 217.225C207.455 218.613 211.12 246.572 212.241 262.315C213.094 274.214 215.219 296.608 216.608 308.09C200.795 308.207 192.897 308.257 177.085 308.374C170.291 308.424 167.882 303.21 166.777 289.255C165.84 277.456 167.714 252.689 157.926 244.182C157.608 244.232 157.457 244.249 157.139 244.299C158.562 265.724 160.034 287.133 162.326 308.491C146.096 308.624 129.865 308.758 113.634 308.909C112.529 278.944 111.291 248.945 109.869 219.014C108.446 189.166 106.94 159.268 105.066 129.403C125.146 118.39 145.594 108.045 166.359 98.385C200.21 78.2134 205.313 124.774 206.987 145.831C208.693 167.239 211.421 204.374 186.305 215.22C186.355 216.022 186.372 216.423 186.405 217.242L186.422 217.225ZM161.657 175.746C160.754 158.432 158.98 154.872 155.081 156.276C154.429 156.51 152.437 157.028 152.103 157.63C148.84 163.629 153.609 186.726 154.479 200.981C155.516 200.714 156.57 200.446 157.742 200.146C161.674 199.143 162.544 193.076 161.64 175.763L161.657 175.746Z"
                fill="#FFF6F6"></path>
              <path
                d="M276.965 311.666C219.421 311.499 218.333 226.334 216.359 187.06C214.033 140.901 212.075 73.8682 264.75 54.4152C324.738 32.2715 324.637 134.049 326.076 166.587C327.666 202.702 339.195 311.85 276.965 311.666ZM274.941 173.907C273.033 135.887 271.761 130.038 268.432 130.857C265.085 131.692 264.349 138.093 266.005 175.595C266.541 187.879 271.494 224.362 272.916 224.261C275.811 224.044 275.593 186.943 274.941 173.907Z"
                fill="#FFF6F6"></path>
              <path
                d="M393.327 311.633C331.716 311.55 334.611 203.79 333.071 165.519C331.281 120.914 324.203 34.0939 383.421 20.3064C447.207 5.44921 443.408 117.989 444.362 152.182C445.416 189.668 457.648 311.734 393.327 311.65V311.633ZM392.59 156.026C392.239 144.094 388.139 106.759 386.416 106.876C383.387 107.076 382.986 144.094 383.521 157.129C384.14 171.802 389.294 212.68 390.064 212.647C392.724 212.513 393.042 171.184 392.607 156.026H392.59Z"
                fill="#FFF6F6"></path>
              <path
                d="M506.525 172.585C511.411 171.95 516.849 171.298 522.555 170.663C522.789 193.275 523.074 215.903 523.392 238.515C523.726 261.26 524.094 284.006 524.513 306.751C502.124 306.784 479.752 306.834 457.364 306.901C456.427 257.784 455.439 208.667 454.218 159.583C452.996 110.533 451.875 61.4158 449.984 12.3655C468.073 9.74166 486.077 7.41866 504.232 5.39648C504.534 55.9007 505.504 106.422 506.24 156.926C506.341 163.193 506.408 166.335 506.508 172.602L506.525 172.585Z"
                fill="#FFF6F6"></path>
              <path
                d="M533.312 306.736C532.961 256.131 532.275 205.51 531.605 154.905C530.953 104.301 530.334 53.713 529.363 3.10843C547.017 1.68789 564.804 0.735298 582.507 0.300781C582.407 51.2228 582.708 102.162 582.942 153.084C583.193 204.273 583.528 255.479 583.929 306.685C567.046 306.685 550.179 306.702 533.296 306.736H533.312Z"
                fill="#FFF6F6"></path>
              <path
                d="M701.881 3.71026C700.141 54.0474 699.773 104.451 699.07 154.789C698.35 205.426 697.464 256.081 697.48 306.736C681.099 306.702 664.7 306.686 648.319 306.686C646.211 286.798 644.035 266.844 641.944 247.04C639.718 226.016 637.928 204.825 636.271 183.667C636.104 183.667 636.02 183.667 635.87 183.667C636.288 207.516 636.656 231.364 636.807 255.195C636.924 272.342 636.79 289.522 637.125 306.686C620.224 306.686 611.774 306.686 594.891 306.686C594.907 255.58 594.991 204.457 594.857 153.351C594.723 102.262 594.79 51.1395 594.004 0.0502858C612.209 -0.100124 630.281 0.0502858 648.47 0.518227C650.109 26.3386 652.82 52.3595 654.945 77.8623C656.317 94.4241 657.873 111.37 658.861 128.133C659.028 127.982 659.112 127.899 659.279 127.731C659.078 110.468 658.861 93.1706 658.844 75.9404C658.827 50.9724 658.877 25.9041 658.559 0.902608C675.912 1.67137 684.579 2.22287 701.898 3.69354L701.881 3.71026Z"
                fill="#FFF6F6"></path>
              <path
                d="M764.144 205.695C764.479 197.823 765.048 173.808 765.248 165.535C765.516 154.505 765.767 143.876 765.817 136.389C774.535 137.96 783.387 138.812 789.796 139.464C797.56 140.266 807.633 141.353 817.84 141.804C817.02 183.501 829.252 311.466 760.496 311.984C696.091 312.469 708.223 188.364 708.808 151.196C709.394 114.881 701.58 -4.91252 768.428 6.3515C818.191 14.7243 820.701 65.0113 819.229 106.725C818.995 113.193 818.677 119.677 818.308 126.913C810.31 125.108 800.906 123.554 791.77 122.518C783.169 121.549 774.97 121.081 768.662 121.248C768.796 115.75 768.863 112.992 768.997 107.477C769.432 89.7788 767.24 82.5925 766.152 83.0939C757.083 87.3054 759.793 136.389 759.342 155.976C758.923 174.075 754.004 220.919 763.91 226.134C765.483 226.969 768.746 221.237 769.817 205.578C767.541 205.611 766.403 205.628 764.127 205.661L764.144 205.695Z"
                fill="#FFF6F6"></path>
              <path
                d="M961.726 59.3444C953.142 115.063 942.433 173.639 937.296 226.717C934.82 252.22 935.071 280.865 934.167 307.955C925.55 307.236 911.979 306.802 901.99 306.735C892.134 306.685 878.263 306.952 869.846 307.654C871.77 278.257 874.23 247.457 874.163 219.347C873.996 159.216 868.307 93.4038 864.709 30.4824C880.906 34.4265 897.07 38.8051 913.034 43.5848C911.729 69.0876 911.059 94.7074 910.658 120.127C910.356 139.479 910.306 158.999 910.273 178.435C910.708 178.502 910.925 178.536 911.344 178.603C913 159.517 914.673 140.365 916.163 121.33C918.137 96.3118 919.71 71.1098 920.865 45.9579C937.296 50.9716 945.479 53.6622 961.743 59.3611L961.726 59.3444Z"
                fill="#FFF6F6"></path>
              <path
                d="M1048.02 93.9556C1047.47 101.894 1046.53 114.662 1045.94 125.809C1045.32 137.541 1044.79 150.443 1044.62 158.532C1032.98 154.554 1021.15 150.677 1011.26 147.802C1010.97 153.284 1010.84 156.025 1010.55 161.506C1021.91 164.531 1033.24 167.389 1043 169.378C1041.88 187.41 1040.86 205.443 1040.04 223.475C1030.72 220.935 1018.99 218.244 1007.73 216.339C1007.42 222.071 1007.27 224.929 1006.99 230.661C1017.33 232.149 1030.18 233.77 1040.62 235.124C1039.87 244.516 1039.12 258.821 1038.43 271.974C1037.79 284.274 1037.06 298.279 1036.79 308.29C1009.2 308.072 981.589 307.888 953.996 307.721C956.456 266.626 958.531 225.481 960.522 184.369C962.53 143.223 964.454 102.028 965.977 60.832C993.737 70.993 1020.98 81.9897 1048 93.9389L1048.02 93.9556Z"
                fill="#FFF6F6"></path>
              <path
                d="M1132.77 137.122C1132.08 146.615 1131.4 161.756 1130.78 175.293C1130.16 188.83 1129.46 204.656 1129.22 215.519C1124.12 213.781 1121.58 212.912 1116.47 211.207C1115.02 243.846 1113.29 276.502 1112.36 309.174C1105.35 308.405 1093.63 308.272 1085.13 308.188C1076.61 308.104 1065.19 307.987 1057.82 308.756C1060.35 271.404 1062.27 234.003 1064.32 196.617C1059.08 195.464 1056.45 194.896 1051.18 193.793C1052.18 177.432 1053.02 161.037 1053.87 144.693C1054.69 129.067 1055.53 113.391 1056.2 97.748C1082.19 110.082 1107.62 123.184 1132.77 137.155V137.122Z"
                fill="#FFF6F6"></path>
              <path
                d="M1182.03 164.565C1203.25 179.055 1223.85 199.176 1223.65 227.085C1223.53 243.53 1220.2 249.647 1210.06 254.059C1205.56 256.683 1204.09 259.958 1204 264.888C1204 265.908 1203.97 266.76 1204.09 267.98C1197.01 266.108 1186.3 263.434 1178.27 261.763C1168.56 259.741 1161.8 258.738 1152.67 258.036C1152.62 256.115 1152.68 254.209 1152.78 251.903C1153.67 229.141 1158.67 223.726 1169.55 222.924C1179.17 222.222 1180.17 215.003 1180.43 206.814C1180.56 202.234 1179.62 199.661 1178 198.875C1175.25 197.555 1174.22 202.034 1173.92 211.426C1173.85 213.381 1173.65 215.872 1173.82 218.713C1170.9 217.409 1166.22 215.604 1160.75 213.565C1153.12 210.724 1143.13 207.749 1137.3 207.098C1137.42 201.232 1137.62 195.516 1137.76 190.67C1138.64 158.064 1152.06 144.093 1182.03 164.565ZM1206.75 291.578C1206.56 305.299 1196.77 311.482 1176.81 311.432C1157.12 311.382 1147.71 303.477 1148.42 286.013C1149.1 268.749 1158.94 262.733 1178.15 266.376C1197.61 270.069 1206.93 278.024 1206.76 291.595L1206.75 291.578Z"
                fill="#FFF6F6"></path>
            </g>
            <defs>
              <clipPath id="clip0_587_15588">
                <rect
                  width="1224"
                  height="312"
                  fill="white"></rect>
              </clipPath>
            </defs>
          </svg>
</div>

Please help me out.

Issues with Tic-Tac-Toe Game Implementation in JavaScript [duplicate]

I’m developing a Tic-Tac-Toe game in JavaScript and facing a few issues:

Switching Players: The currentPlayer isn’t switching correctly after each move. I expect playGame to alternate between player1 and player2.

Updating Game Board State: I have a gameBoard array to track game state, but it’s not updating as expected when a player makes a move.

Game Logic for Winning Conditions: I’m struggling to implement logic for checking winning conditions.

Specific Issues:
Player Switching: How can I ensure currentPlayer switches properly in the playGame function?

Game Board State: How do I correctly update and access the gameBoard array to reflect moves?

Winning Conditions: What’s the best way to structure the logic to check for wins?

Here’s a snippet of my code for context:

    // DOM elements
    const playerInput1 = document.querySelector("#player-select1");
    const playerButton = document.querySelector(".add-player");
    const playerInput2 = document.querySelector("#player-select2");
    const playerPara1 = document.querySelector(".player1");
    const playerPara2 = document.querySelector(".player2");
    const showPlayers = document.querySelector(".player-shows");
    const boxes = document.querySelectorAll(".box");

    // Game state
    const gameBoard = [
        [null, null, null],
        [null, null, null],
        [null, null, null]
    ];
    let currentPlayer;
    let player1, player2;

    // Player factory function
    const playerSelection = (name, marker) => {
        let score = 0;
        return {
            name,
            marker,
            getScore: () => score,
            scorePlus: () => ++score
        };
    };

    // Initialize players
    player1 = playerSelection("Name", "X");
    player2 = playerSelection("Name", "O");

    // Event listener for player names
    playerButton.addEventListener("click", () => {
        player2.name = playerInput2.value.trim();
        player1.name = playerInput1.value.trim();

        if (!player1.name || !player2.name) {
            alert("Please enter a name");
            return;
        }
        
        playerPara1.textContent = `First Player is: ${player1.name} (${player1.marker})`;
        playerPara2.textContent = `Second Player is: ${player2.name} (${player2.marker})`;
        showPlayers.innerHTML = "";
        showPlayers.append(playerPara1);
        showPlayers.append(playerPara2);

        playGame();
    });

    // Box event listeners
    boxes.forEach(box => {
        box.addEventListener("click", () => {
            if (!box.textContent && currentPlayer) {
                box.textContent = currentPlayer.marker;
                box.style.color = "white";
                box.style.textAlign = "center";
                box.style.fontSize = "55px";
                box.style.cursor = "pointer";

                playGame();
            }
        });
    });

    // Switch current player
    const playGame = () => {
        currentPlayer = currentPlayer === player1 ? player2 : player1;

        // Check game board state (this part is problematic)
        if (gameBoard[0][0] === currentPlayer.marker) {
            console.log("Testing if it works");
        }
    };

    return {
        playerSelection,
        playGame
    };
})();

Console.warn does not work in express routing file

I’m trying to log/debug this issue I’m having, when i open adminPanel in a browser i get the html, js and css. But it does not log annything in console.

server.js

const express = require('express');
const router = express.Router();
const cors = require('cors');
const path = require('path');

app.use(cors());

const publicPath = path.join(__dirname, './../public');
app.use(express.static(publicPath));

const adminRoutes = require('./routes/adminRoutes');
app.use('/adminpanel', adminRoutes);

app.listen(4200);

adminRoutes.js

const express = require('express');
const path = require('path');
const router = express.Router();

// Serve the admin panel
router.get('/', (req, res) => {
    console.error("userDataPath") // THIS DOES NOT LOG FOR SOME REASON
    res.sendFile(path.join(__dirname, '../public/adminpanel/index.html'));
});

module.exports = router;

I tried log, warn and error, but none of them worked…