Setting dynamically created QML rectangle’s drag.target property via JavaScript

I have dynamically created some QML rectangles on a Canvas. I wish to toggle whether the rectangles can be dragged around or not via the drag.target property, which is declared upon creation inside MouseArea. If the rectangles are draggable, I set drag.target to “parent”. If not, I set it to “undefined”.

The rectangles are stored in an array called verts[]. When I try to access the drag.target property, I get an error:
TypeError: Value is undefined and could not be converted to an object

Here is the function that produces the error. I am feeding it an array of rectangles (verts) and a boolean.

function setVertsDraggable(verts, draggable) {
    for (var i=0; i<verts.length; i++) {
        if (draggable) {
            verts[i].drag.target = "parent”;
        }
        else {
            verts[i].drag.target = "undefined”;
        }
    }
}

I have tried feeding it the values of “parent” and “undefined” in quotes, without quotes, by setting another variable to undefined and passing that variable, and an empty string. Perhaps there are values defined in QML somewhere, such as QtQuick.(SomeClassOfEnums).undefined

But I suspect that the bigger problem is that it is not recognizing vert[i].drag.target as a property. Perhaps my path is wrong. I have tried

vert[i].drag.target
vert[i].MouseArea.drag.target
vert[i].Rectangle.MouseArea.drag.target
vert[i].Rectangle.drag.target

Additionally, I am able to set the color of those rectangles via javascript. The same syntax allows me to set the color without any error:

function setVertsColor(verts, color) {
    for (var i=0;i<verts.length; i++) {
        verts[i].color = color;
    }
}

So if this syntax works with color, what is the problem with the drag.target property?

If it helps, here is the command I use to dynamically create the rectangles:

var component = Qt.createComponent("Vertex.qml");
var vertex = component.createObject(parent, {x: xPos, y: yPos, width: size, color:"yellow"});

And here is the Vertex.qml which contains the definition of the rectangles, called by component.createObject(…)

import QtQuick

Rectangle {
    width: 8
    height: 8
    color: yellow
    property string tag: “"
    MouseArea {
        anchors.fill: parent
        drag.target: undefined
        drag.smoothed: false
        onReleased: {
            polyCanvas.requestPaint()
        }
    }
}

Please let me know if you have any ideas. I’m fresh out of ’em.

Question regarding making multiple buttons changing what embed shows up on one same HTML page

A little backstory before we start, if that’s fine.

I’m currently in high school, and have begun noticing the large influx of unblocked game sites and proxy sites for chromebooks. I decided to make one myself, just to dip my toes in the water, but I decided instead of using Google Sites to do it, I decided to use my very limited knowledge of HTML, CSS, and JS to make it. A practice for my knowledge, if you will.

However, after making proxy pages, I wanted to add some games. However, the amount of game links I have (50+) would be too much to add all individually, with a button containing the link to another page, where the user would be playing via an embed of the site, since I do not want the user actually travelling to the site, which would theoretically cause the administration to figure out the link to the game, and eventually, blocking it.

I just want to know, is there a way to have a long list of buttons, each with a uniqueonclick or id, that when pressed, opens a tab to a singular page (same page if you click any other button), and based on the button pressed on the game hub, decides which game site embed shows up. Kind of confusing, but I hope this is possible!

managing multi-step registration errors

I have the following in my RegistrationController

if @user.save
      session_record = @user.sessions.create!
      cookies.signed.permanent[:session_token] = { value: session_record.id, httponly: true }
      send_email_verification
      redirect_to root_path, notice: "Welcome! You have signed up successfully"
else
      render :new, status: :unprocessable_entity 
end

when it doesn’t save it re-renders new but should have all of the user information from the failed attempt, but because the multiple stages via javascript everything gets screwed up.

How do I send an event to my javascript to reset the stages?
Is it possible to pass something with the unhappy path render that can be used to trigger a js reset? Or do I have to go all the way to Action Cable.

Any help appreciated.

Catch-all route with a default static page In Next.js

I have a catch-all route on which i wish to render different pages depending on the slugs – this is not hard to achieve. The following is my structure:


app/  
├── (home)/  
│   ├── layout.tsx  
│   └── page.tsx  
└── [...slug]/
    ├── layout.tsx
    └── page.tsx
├── layout.tsx  
└── page.tsx

Now my question is, how can I – or can I – have a home page on the root URL ‘/’ and all the other routes handled by the […slug] catcher? The reason I am asking is because during `next build`:


Error occurred prerendering page "/". Read more: [https://nextjs.org/docs/messages/prerender-error](https://nextjs.org/docs/messages/prerender-error)

Error: The provided export path '/' doesn't match the '/[...slug]' page.

Read more: [https://nextjs.org/docs/messages/export-path-mismatch](https://nextjs.org/docs/messages/export-path-mismatch)

at getParams (C:\git\adinsure-docs-fumadocs-portal\node_modules\next\dist\export\helpers\get-params.js:27:15)

at exportPageImpl (C:\git\adinsure-docs-fumadocs-portal\node_modules\next\dist\export\worker.js:108:43)

at C:\git\adinsure-docs-fumadocs-portal\node_modules\next\dist\export\worker.js:350:108

at turborepoTraceAccess (C:\git\adinsure-docs-fumadocs-portal\node_modules\next\dist\build\turborepo-access-trace\helpers.js:36:51)

at C:\git\adinsure-docs-fumadocs-portal\node_modules\next\dist\export\worker.js:350:103

at Span.traceAsyncFn (C:\git\adinsure-docs-fumadocs-portal\node_modules\next\dist\trace\trace.js:157:26)

at exportPage (C:\git\adinsure-docs-fumadocs-portal\node_modules\next\dist\export\worker.js:350:39)

at exportPageWithRetry (C:\git\adinsure-docs-fumadocs-portal\node_modules\next\dist\export\worker.js:239:21)

at C:\git\adinsure-docs-fumadocs-portal\node_modules\next\dist\export\worker.js:321:72

at [Array.map](http://Array.map) (<anonymous>)

Export encountered an error on /[...slug]/page: /, exiting the build.

⨯ Static worker exited with code: 1 and signal: null

error Command failed with exit code 1  

(It might seem weird, but the setup was working, for some reason, it dropped again, and now I’m looking for a more proper solution)

My Next version is: 15.0.1

How can I insert objects(products) in a json server(db.json) using react and javascript?

so im just stuck on a problem.

Im using json-server 0.17.4, i have installed multer and im making a website as an excersice and following an udemy course. Im trying to create a product/object using a submit form, which will then insert it into the db.json. Port is at 4000, while the website is at 3000.

This is my CreateProduct.js file:

import { useState } from "react";
import { Link, useNavigate } from "react-router-dom";

export default function CreateProduct(){

    const [validationErrors, setValidationErrors] = useState({})

    const navigate = useNavigate()
    
    async function handleSubmit(event){
        event.preventDefault()

        const formData = new FormData(event.target)
        const product = Object.fromEntries(formData.entries())
        
        console.log('Form data contents:')

        if(!product.name || !product.brand || !product.category || !product.price
            || !product.description || !product.image.name){
                alert("Please fill out all the fields")
                return
            }

        try{
            const response = await fetch("http://localhost:4000/products",{
                method: "POST",
                body: formData
            })

            const data = await response.json()
            console.log('Server response:', data)

            
            if(response.ok){
                navigate("/admin/products")
            }
            else if(response.status === 400){
                setValidationErrors(data)
            }
            else{
                alert("Unable to create product")
            }
        }catch{
            alert("Unable to connect to the server")
        }
    }
    return(
        <div className="container my-4">
            <div className="row">
                <div className="col-md-8 mx-auto rounded border p-4">
                    <h2 className="text-center mb-5">Create Product</h2>

            <form onSubmit={handleSubmit}>
                <div className="row mb-3">
                    <label className="col-sm-4 col-form-label">Name</label>
                    <div className="col-sm-8">
                        <input className="form-control" name="name" />
                        <span className="text-danger">{validationErrors.name}</span>
                    </div>                    
                </div>
                <div className="row mb-3">
                    <label className="col-sm-4 col-form-label">Brand</label>
                    <div className="col-sm-8">
                        <input className="form-control" name="brand" />
                        <span className="text-danger">{validationErrors.brand}</span>
                    </div>                    
                </div>
                
                <div className="row mb-3">
                    <label className="col-sm-4 col-form-label">Category</label>
                    <div className="col-sm-8">
                        <select className="form-select" name="category">
                            <option value='Other'>Other</option>
                            <option value='Phones'>Phones</option>
                            <option value='Computers'>Computers</option>
                            <option value='Accessories'>Accessories</option>
                            <option value='Printers'>Printers</option>
                            <option value='Cameras'>Cameras</option>
                        </select>
                        <span className="text-danger">{validationErrors.category}</span>
                    </div>                    
                </div>

                <div className="row mb-3">
                    <label className="col-sm-4 col-form-label">Price</label>
                    <div className="col-sm-8">
                        <input className="form-control" name="price" type="number" step="0.01" min="1"/>
                        <span className="text-danger">{validationErrors.price}</span>
                    </div>                    
                </div>

                <div className="row mb-3">
                    <label className="col-sm-4 col-form-label">Description</label>
                    <div className="col-sm-8">
                        <textarea className="form-control" name="description" rows = "4"/>
                        <span className="text-danger">{validationErrors.description}</span>
                    </div>                    
                </div>
                <div className="row mb-3">
                    <label className="col-sm-4 col-form-label">Image</label>
                    <div className="col-sm-8">
                        <input className="form-control" type="file" name="image"/>
                        <span className="text-danger">{validationErrors.image}</span>
                    </div>                    
                </div>
                <div className="row mb-3">
                   <div className="offset-sm-4 col-sm-4 d-grid">
                    <button type="submit" className="btn btn-primary">Submit</button>
                    </div> 
                    <div className="col-sm-4 d-grid">
                        <Link className="btn btn-secondary" to='/admin/products' role="button">Cancel</Link>
                    </div>            
                </div>
            </form>
                </div>
            </div>
        </div>
    )
}
```, the thing is, there are no items when i submit in db, only ids.

[here is the example of it not working](https://i.sstatic.net/TI4j3QJj.png),

and here is whats showing at the website:

[example of whats showing at the website](https://i.sstatic.net/foQJlS6t.png),

i should also note this is my server.js file:


const jsonServer = require(‘json-server’)
const multer = require(‘multer’)
const path = require(‘path’);
const server = jsonServer.create()
const router = jsonServer.router(‘db.json’)
const middlewares = jsonServer.defaults()

// Set default middlewares (logger, static, cors and no-cache)
server.use(middlewares)

// /! Bind the router db to the app
server.db = router.db

const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, ‘public/images’)
},
filename: function (req, file, cb) {
let date = new Date()
let imageFilename = date.getTime() + “_” + file.originalname
req.body.imageFilename = imageFilename
cb(null, imageFilename)
}
})

const bodyParser = multer({ storage: storage }).any()

// To handle POST, PUT and PATCH you need to use a body-parser
// You can use the one used by JSON Server
server.use(bodyParser)
server.post(“/products”, (req, res, next) => {
let date = new Date()
req.body.createdAt = date.toISOString()

if (req.body.price) {
req.body.price = Number(req.body.price)
}

let hasErrors = false
let errors = {}

if (req.body.name.length < 2) {
hasErrors = true
errors.name = “The name length should be at least 2 characters”
}
if (req.body.brand.length < 2) {
hasErrors = true
errors.brand = “The brand length should be at least 2 characters”
}
if (req.body.category.length < 2) {
hasErrors = true
errors.category = “The category length should be at least 2 characters”
}
if (req.body.price <= 0) {
hasErrors = true
errors.price = “The price is not valid”
}
if (req.body.description.length < 10) {
hasErrors = true
errors.description = “The description length should be at least 10 characters”
}

if (hasErrors) {
// return bad request (400) with validation errors
res.status(400).jsonp(errors)
return
}

// Continue to JSON Server router
next()
})

// Use default router
server.use(router)
server.listen(4000, () => {
console.log(‘JSON Server is running’)
})




Im new at frontend development and i need some guidance please.

I have been stuck on this problem for a few days...

How to handle hover effect of 3D flip card on mobile phone screens?

Basically, I’m using this 3D hover effect on my page:
https://uiverse.io/ElSombrero2/tricky-robin-67

Hover works fine on my laptop and bigger screens in general, but on my mobile phone I want it to flip when I tap (which already work) and then flip back when I press it again.
At the moment it flip back only if I press another card or anywhere else on the screen.

I tried ChatGPT and Google already.

I would prefer some simple CSS solution. Like @media (hover: none) {...} but JavaScript is also welcome if needed.

JavaScript regex to sanitize URL

My code is calling azure functions using API key for authentication, so the URL looks like: https://func-provwcl-dev-job-xyz-qa53.azurewebsites.net/api/list?code=Q......0&input=%7B%22limit%22%3A25%7D.

To prevent logger from dumping access keys, I added a function to sanitize URLs.

The below regex mostly does the job of replacing the code with ***.

val.replace(/code=.*&/,'code=***&')

However, if there is no & this regex will not work. Can it be re-written so that if there is an & character, it will replace those, otherwise the entire end of the string starting with code=?

react-paypal-js does not expand guest checkout properly in production

I’m using the PayPal React TypeScript SDK for accepting payment on the frontend.

My React component is defined as follows:

import { PayPalButtons, PayPalScriptProvider } from "@paypal/react-paypal-js";
import React, { Suspense } from "react";

interface PayPalCheckoutProps {
    currencyCode: string;
    totalAmount: string;
    handleApprove: (data: any) => Promise<void>;
    handleError: (error: any) => void;
}

const PayPalCheckout: React.FC<PayPalCheckoutProps> = ({ currencyCode, totalAmount, handleApprove, handleError }) => {
    return (
        <PayPalScriptProvider options={{ clientId: import.meta.env.VITE_PAYPAL_CLIENT_ID, currency: currencyCode }}>
            <Suspense fallback={<div>Loading PayPal...</div>}>
                <PayPalButtons
                    style={{ layout: "vertical" }}
                    createOrder={(_data, actions) => {
                        return actions.order.create({
                            intent: "CAPTURE",
                            purchase_units: [
                                {
                                    amount: {
                                        currency_code: currencyCode,
                                        value: totalAmount,
                                    },
                                    shipping: {}, // No shipping details
                                },
                            ],
                            application_context: {
                                shipping_preference: "NO_SHIPPING",
                            },
                        });
                    }}
                    onApprove={async (data, actions) => {
                        if (!actions.order) {
                            return Promise.reject(new Error("Order object is undefined"));
                        }

                        try {
                            await actions.order.capture();
                            await handleApprove(data);
                        } catch (err: any) {
                            handleError(err);
                        }
                    }}
                    onError={handleError}
                />
            </Suspense>
        </PayPalScriptProvider>
    );
};

export default PayPalCheckout;

It’s implemented on my checkout page like this:

<div className={"justify-center items-center flex"}>
    <PayPalCheckout
        currencyCode={currencyCode}
        totalAmount={totalAmount}
        handleApprove={handleApprove}
        handleError={handleError}
    />
</div>

In development mode (npm run dev), when I click on the “Debit or Credit Card” button provided by the PayPalScriptProvider on the frontend…

… it expands correctly downwards as follows:

However, if I compile my project to production using Vite via e.g. tsc -b && vite build --base=./, I get no warnings and it completes successfully. After serving the frontend via npm serve -s dist and clicking the same “Debit or Credit Card” button, it does not expand properly:

I also noticed that the buttons appear a bit bigger in production compared to development.

Questions:

  • Why is the appearance of the buttons not the same in development and production? My CSS is the same and does not use any conditional logic (I use Tailwind CSS v4.0). Disabling minifying CSS etc. did not help.
  • Why does the “Debit or Credit Card” form not expand properly in production? In both cases my CLIENT_ID is the same for now. This form issue makes it hard to use the form since only a small window of the form is visible at a time. Jumping downwards can be done with tabbing but it’s very user friendly. Maybe there is a bug with the way the JavaScript is compiled for production? Is there any way I can track this issue down further? Using chunking or not did not matter either but I prefer to use chunking rather than not.

vite.config.ts:

import {defineConfig} from 'vite'
import react from '@vitejs/plugin-react'
import tailwindcss from '@tailwindcss/vite'

// https://vite.dev/config/
export default defineConfig({
    plugins: [react(), tailwindcss()],
    server: {
        port: 3000
    },
})

Livewire wierd behavior, unexpected multi root root

context: i am using laravel and livewire to built a gen AI chatbot system, so if someone also got some advice, they are very welcome….

when i am creating a div in my livewire comp, with using JS’s innerhtml:

newMessage.innerHTML = `<div class="bg-black text-white p-3 rounded-lg max-w-[70%]">${questionText}</div>`;

it is giving “Livewire only supports one HTML element per component….” error,

but it works fine when i do this with another approach,by something like this:

        const messageText = document.createElement('p');
            messageText.classList.add("mb-1");
            messageText.textContent = questionText;

why? please answer, if anyone has explanation….Thanks

Check if a bit is true or false in a bitmask integer [duplicate]

I looked into bitmasks and bitewise operations, but nothing seem to answer exactly what I’m looking for. I’d like to store multiple booleans into a single integer, where each boolean is represented by a power of two which makes them distinguishable when added to a single number. I’ve seen other code do this but not the procedure to do it myself in languages like JavaScript / Python / LUA, currently I plan to use it in a HTML5 / JS based engine.

Example: I store 4 bits, meaning each is represented by the numbers 1, 2, 4, 8. If my integer is 0 all values are off, if it’s 4 only the third value is on, if it’s 9 then 1 and 8 are enabled, if it’s 7 only 1 + 2 + 4, if it’s 15 all four are on.

I’m looking for the simplest universal procedure to detect if an integer contains a particular bit. Is there something that returns a true or false result, say x &= 4 to determine if the 3rd bit is on? It might be cleaner to get an array of booleans in the form [true, false, false, true] since I can work with each value individually.

VueJS 2 strange behavior when declaring data in separate file [duplicate]

I maintain a vuejs2 webapp and found a weird bug in a component I just updated. Here’s how the component worked in the past:

  1. There’s an array in data() called headers
  2. There were 5 objects written to that array right in data() declaration
  3. created() method checked if user is admin and in that case pushed 1 more object to headers

Component worked as expected for ages. But last week I tried to organize it better, so I created a my-headers.js file that exports the same 5 objects in an array, written like this: export const myHeaders = [{obj1}, {obj2}, ...]. So in data() I changed the declaration to headers: myHeaders,, imported it correctly etc.

Now comes the part I never saw happening before: At first run the page behaves the same way as before, starting with array 5 and going size 6 during created() hook. Then if I navigate to any other route and goes back to this page/component, either using browser’s back button or the side menu my app has, it get’s initialized with size 6, created hook runs and increases it to 7. And it goes over and over if I keep doing this. I tried navigating to 10 other different routes before going back to my buggy component, but it’s status seems to be saved no matter what. Except for refreshing, good and old F5 fixes eveything.

I’m not even close to being deep in Vue’s inner workings, but I’m using this framework for over 5 years and frankly I’m used to move data to separate components in some situations. I never saw it happening. I just never did it to this specific project, and now I feel puzzled about what is happening in here. I see the destroyed() hook is executed whenever I change route. Shouldn’t my data() be cleared in that moment?

I’m thinking that maybe I’m writing to a browser’s copy of my-headers.js file when I push something to the array, and that I could fix it by doing a slightly different attribution, like headers: [...myHeaders],, am I correct?

Create document tree from array of nested PDF bookmarks (from Adobe PDF Embed API) with tree view navigation

I am using Adobe PDF Embed API to display a PDF and using their API to extract an array of multi-level bookmarks and then using JavaScript to display a document tree using this method.

I successfully adapted the document tree to the bookmarks however, I am having issues with multi-level bookmarks where after a 3rd level bookmark ends, the next bookmark which is second level is still being outputted under the previous 3rd level bookmark.

This is my array of bookmarks:

[
    {
        "id": "0",
        "title": "Revision History",
        "children": []
    },
    {
        "id": "1",
        "title": "Introduction",
        "children": [
            {
                "id": "2",
                "title": "The P.O.S. System",
                "children": []
            }
        ]
    },
    {
        "id": "3",
        "title": "Troubleshooting",
        "children": [
            {
                "id": "4",
                "title": "P.O.S. Technical Support",
                "children": []
            },
            {
                "id": "5",
                "title": "“Something is not working”",
                "children": []
            },
            {
                "id": "6",
                "title": "Invoices not downloading or suggested retails prefixed with “S”, instead of “C”",
                "children": []
            },
            {
                "id": "7",
                "title": "Debit/ Credit Terminal not Working",
                "children": []
            },
            {
                "id": "8",
                "title": "Items not Included in Session when Scanning the Order",
                "children": []
            }
        ]
    },
    {
        "id": "9",
        "title": "Creating Verification Sessions",
        "children": [
            {
                "id": "10",
                "title": "Processing 275 Invoices",
                "children": []
            }
        ]
    },
    {
        "id": "11",
        "title": "Order Receiving",
        "children": [
            {
                "id": "12",
                "title": "Completing the Order Verification Session",
                "children": []
            },
            {
                "id": "13",
                "title": "Downloading Invoices",
                "children": []
            },
            {
                "id": "14",
                "title": "Receiving Inventory",
                "children": []
            }
        ]
    },
    {
        "id": "15",
        "title": "Product Management",
        "children": [
            {
                "id": "16",
                "title": "Bin Locations",
                "children": []
            },
            {
                "id": "17",
                "title": "Bin Location Management and Upkeep",
                "children": [
                    {
                        "id": "18",
                        "title": "Assigning Bin Locations (Bulk)",
                        "children": []
                    },
                    {
                        "id": "19",
                        "title": "Assigning Bin Locations (Individual)",
                        "children": []
                    },
                    {
                        "id": "20",
                        "title": "Bin Location Substitutions",
                        "children": []
                    }
                ]
            },
            {
                "id": "21",
                "title": "Product Substitutions",
                "children": []
            },
            {
                "id": "22",
                "title": "Inactivating Products",
                "children": []
            },
            {
                "id": "23",
                "title": "Batch Editor",
                "children": [
                    {
                        "id": "24",
                        "title": "Processing Batches",
                        "children": []
                    }
                ]
            }
        ]
    },
    {
        "id": "25",
        "title": "Labels",
        "children": [
            {
                "id": "26",
                "title": "Loading Batch Labels",
                "children": []
            },
            {
                "id": "27",
                "title": "Manual (Scanning) Labels",
                "children": []
            },
            {
                "id": "28",
                "title": "Printing Labels",
                "children": []
            },
            {
                "id": "29",
                "title": "Printing Promo Labels",
                "children": []
            },
            {
                "id": "30",
                "title": "Printing Additional Promo Labels",
                "children": []
            }
        ]
    },
    {
        "id": "31",
        "title": "PharmaClik",
        "children": [
            {
                "id": "32",
                "title": "Getting Barcode from V.I.N.",
                "children": []
            }
        ]
    },
    {
        "id": "33",
        "title": "BlackHawk Gift Cards",
        "children": [
            {
                "id": "34",
                "title": "General Information",
                "children": []
            },
            {
                "id": "35",
                "title": "BlackHawk Portal",
                "children": []
            },
            {
                "id": "36",
                "title": "Printing Gift Card Planogram",
                "children": []
            },
            {
                "id": "37",
                "title": "Gift Card Barcode Database",
                "children": []
            },
            {
                "id": "38",
                "title": "Inventory Counting",
                "children": [
                    {
                        "id": "39",
                        "title": "Scanning the Cards",
                        "children": []
                    },
                    {
                        "id": "40",
                        "title": "Printing the Inventory Counting Report",
                        "children": []
                    },
                    {
                        "id": "41",
                        "title": "Updating Inventory on the BlackHawk Portal",
                        "children": []
                    }
                ]
            }
        ]
    }
]

and this is the JS code which I adapted from Adobe’s GitHub samples

/* Function to get the list of bookmarks. */
var getBookmarks = function() {
    var bookmarkPaneItem = document.getElementById("bookmark-pane");
    viewerApis.getBookmarkAPIs().getBookmarks()
    .then(function(bookmarks) {
        console.log(bookmarks);
        if (bookmarks.length === 0) {
/* Check when there is no bookmark. */
            console.log("No bookmark available in the PDF");
            var label = document.createElement("label");
            label.innerText = "No bookmark available in the PDF";
            label.style.color = "#777";
            label.style.fontFamily = "Lato, sans-serif;";
            label.style.fontWeight = "bold";
            bookmarkPaneItem.replaceChildren(label);
        } else {
/* Create the list of bookmarks. */
            var list = document.createElement("ul");
            list.classList.add("tree")
            bookmarks.forEach(function(element) {
                createBookmarkList(list, element);
            });
            bookmarkPaneItem.replaceChildren(list);
            console.log("Bookmarks displayed in the left-hand pane.");
            var toggler = document.getElementsByClassName("caret");
            var i;

            for (i = 0; i < toggler.length; i++) {
                toggler[i].addEventListener("click", function() {
                    this.parentElement.querySelector(".nested").classList.toggle("active");
                    this.classList.toggle("caret-down");
                });
            }
        }
    })
    .catch(function(error) {
        console.log(error);
    })
}

/* Create the list of bookmarks and display in the left-hand custom pane. */
var createBookmarkList = function(bookmarkList, bookmarkItem) {
    var listItem = document.createElement("li");
    var subList;
    listItem.id = bookmarkItem.id;
    if (bookmarkItem.children.length != 0) { //has children
        details = document.createElement("details");
        details.innerHTML = "<summary>"+bookmarkItem.title+"</summary>";
        ul = document.createElement("ul");
        //ul.id = bookmarkItem.id;
        details.appendChild(ul);
        listItem.appendChild(details);
    } else { //doesn't have children
        listItem.innerText = bookmarkItem.title;
    }
    bookmarkList.appendChild(listItem);
/*------------------------------------ I THINK THE ISSUE LIES SOMEWHERE HERE: -----------------------------------*/
    bookmarkItem.children.forEach(function(child, index, arr) {
        createBookmarkList(ul, child);            
    }, bookmarkList);

    listItem.onclick = function (e) {
        e.stopImmediatePropagation();
        openBookmark(listItem.id);
    };
}

/* Open any bookmark in the PDF. */
var openBookmark = function(bookmarkID) {
    viewerApis.getBookmarkAPIs().openBookmark(bookmarkID)
    .then(function() {
        console.log("Bookmark with ID " + bookmarkID + " opened.");
        bsOffcanvas.hide();
    })
    .catch(function(error) {
        console.log(error);
    })
}

This is what is being outputted. The red boxes indicate where the list level changes but as you can see “Product Substitutions” is outputted as a 3rd level bookmark even though it is a 2nd level bookmark.

How do I calculate Uniswap V3 gas units to token1 ? Response from Uniswap V3 quoteExactInputSingle

I’m using Uniswap V3 to quoteSingleInput of how many token1 I get for token1. WETH/ARB in this case, both having 18 decimals. I’ve asked ChatGPT how I do it, and it keeps trying to get me to get the gas price in wei

const gasPriceData = (await provider.getFeeData()).gasPrice

But I want the gas price in ARB not wei, to minus it from the the amountOut. Has anyone come across this ? Do I multiply the gasPriceData by anything ? I’m really confused

async function fetchGasToToken(_gasUnits, _token1) {try {const gasCost = new BigNumber(_gasUnits);const gasCostInToken = gasCost.div(new BigNumber(10).pow(_token1.decimals));return gasCostInToken;} catch (error) {console.error("❌ Error converting gas to token1:", error);throw error;}}
const params = {tokenIn: _token0.address,tokenOut: _token1.address,fee: p.fee,amountIn: _amount,sqrtPriceLimitX96: 0,}
const [amountOut, sqrtPriceX96After, initializedTicksCrossed, gasEstimate] =await withTimeout(uniswap_v3.quoter.quoteExactInputSingle.staticCall(params),10000 // 10-second timeout)
const gasInToken = await fetchGasToToken(gasEstimate, _token1) // gasEsimate is 102848
const finalAmount = BigNumber(amountOut).minus(gasInToken);`

I tried dividing gasUnits by the token1 Decimals after multiplying by the power of 10.

Sticky navigation doesn’t work properly on safari

I have sticky navigation class like this:

.sticky {
  position: -webkit-sticky;
  position: fixed;
  top: 0;
  left: 0;
  padding: 0 8rem 0 8rem;
  background-color: var(--border-color);
  width: 100%;
  z-index: 9999;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
} 

and js like this:

const navHeight = mainNav.getBoundingClientRect().height;
const obsCallback = function (entries) {
  const [entry] = entries;
  if (!entry.isIntersecting) {
    mainNav.classList.add(`sticky`);
  } else {
    mainNav.classList.remove(`sticky`);
  }
};
const headerObserver = new IntersectionObserver(obsCallback, {
  root: null,
  threshold: 0.01,
  rootMargin: `-${navHeight}px`,
});
headerObserver.observe(header);

but in safari sticky nav is alwayse sticked to the top.

How to load multiple JSON Bodymovin / Lottie animation?

I am trying to load multiple JSON / Lottie animation in one page but different element. Since I’m clueless about Javascript, I can’t get it to work.

I already have working code for loading single JSON, and I am trying to duplicate and modify by adding another JSON.

var logoSvgData = 
// Here's JSON Bodymovin code for logo
;

const animation = bodymovin.loadAnimation({
  container: document.getElementById('logo'),
  renderer: 'svg',
  loop: true,
  autoplay: true,
  animationData: logoSvgData
})

var introSvgData = 
// Here's JSON Bodymovin JSON Bodymovin code for intro
;

const animation = bodymovin.loadAnimation({
  container: document.getElementById('intro'),
  renderer: 'svg',
  loop: true,
  autoplay: true,
  animationData: introSvgData
})

I know I am doing it wrong, the animation didn’t load at all.

Here’s the original code that works for single JSON.

var logoSvgData = 
{"assets":[{"id":"13","layers":[{"ind":12,"ty":4,"ks":{},"ip":0,"op":121,"st":0,"shapes":[{"ty":"rc","p":{"a":0,"k":[4.5,18.5]},"r":{"a":0,"k":0},"s":{"a":0,"k":[9,37]}},{"ty":"fl","c":{"a":0,"k":[0,0,0,0]},"o":{"a":0,"k":0}}]},{"ind":0,"ty":4,"ks":{"s":{"a":0,"k":[133.33,133.33]}},"ip":0,"op":121,"st":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"sh","ks":{"a":0,"k":{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[0,27.27],[0,0],[6.31,0],[6.31,2.09],[2.39,2.09],[2.39,25.18],[6.31,25.18],[6.31,27.27]]}}},{"ty":"fl","c":{"a":0,"k":[0,0,0,1]},"o":{"a":0,"k":100}},{"ty":"tr","o":{"a":0,"k":100}}]},{"ty":"tr","o":{"a":0,"k":100}}]}]}]},{"id":"18","layers":[{"ind":17,"ty":4,"ks":{},"ip":0,"op":121,"st":0,"shapes":[{"ty":"rc","p":{"a":0,"k":[4.5,18.5]},"r":{"a":0,"k":0},"s":{"a":0,"k":[9,37]}},{"ty":"fl","c":{"a":0,"k":[0,0,0,0]},"o":{"a":0,"k":0}}]},{"ind":0,"ty":4,"ks":{"s":{"a":0,"k":[133.33,133.33]}},"ip":0,"op":121,"st":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"sh","ks":{"a":0,"k":{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[6.75,27.27],[6.75,0],[0.44,0],[0.44,2.09],[4.36,2.09],[4.36,25.18],[0.44,25.18],[0.44,27.27]]}}},{"ty":"fl","c":{"a":0,"k":[0,0,0,1]},"o":{"a":0,"k":100}},{"ty":"tr","o":{"a":0,"k":100}}]},{"ty":"tr","o":{"a":0,"k":100}}]}]}]},{"id":"21","layers":[{"ind":15,"ty":0,"parent":11,"ks":{},"w":9,"h":37,"ip":0,"op":121,"st":0,"refId":"13"},{"ind":11,"ty":3,"parent":10,"ks":{"p":{"a":1,"k":[{"t":0,"s":[0,0],"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"t":60,"s":[0,0],"i":{"x":[0,1],"y":[1,1]},"o":{"x":[0.5,0],"y":[0,0]}},{"t":120,"s":[-79,0],"h":1}]}},"ip":0,"op":121,"st":0},{"ind":20,"ty":0,"parent":16,"ks":{},"w":9,"h":37,"ip":0,"op":121,"st":0,"refId":"18"},{"ind":16,"ty":3,"parent":10,"ks":{"p":{"a":1,"k":[{"t":0,"s":[19,0],"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"t":60,"s":[19,0],"i":{"x":[0,1],"y":[1,1]},"o":{"x":[0.5,0],"y":[0,0]}},{"t":120,"s":[97,0],"h":1}]}},"ip":0,"op":121,"st":0},{"ind":10,"ty":3,"parent":9,"ks":{"a":{"a":0,"k":[14,18.5]},"p":{"a":0,"k":[93,18.5]}},"ip":0,"op":121,"st":0},{"ind":9,"ty":3,"ks":{"p":{"a":0,"k":[79,0]}},"ip":0,"op":121,"st":0}]},{"id":"6","layers":[{"ind":5,"ty":4,"parent":4,"ks":{},"ip":0,"op":121,"st":0,"shapes":[{"ty":"rc","p":{"a":0,"k":[96,50]},"r":{"a":0,"k":0},"s":{"a":0,"k":[192,100]}},{"ty":"fl","c":{"a":0,"k":[1,1,1]},"o":{"a":0,"k":100}}]},{"ind":4,"ty":3,"parent":3,"ks":{"a":{"a":0,"k":[96,50]},"p":{"a":0,"k":[93,18]}},"ip":0,"op":121,"st":0},{"ind":3,"ty":3,"ks":{"p":{"a":0,"k":[3,32]}},"ip":0,"op":121,"st":0}]},{"id":"34","layers":[{"ind":33,"ty":4,"ks":{},"ip":0,"op":121,"st":0,"shapes":[{"ty":"rc","p":{"a":0,"k":[9,15]},"r":{"a":0,"k":0},"s":{"a":0,"k":[18,30]}},{"ty":"fl","c":{"a":0,"k":[0,0,0,0]},"o":{"a":0,"k":0}}]},{"ind":0,"ty":4,"ks":{"s":{"a":0,"k":[133.33,133.33]}},"ip":0,"op":121,"st":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"sh","ks":{"a":0,"k":{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[0,22.12],[0,0.3],[13.08,0.3],[13.08,2.64],[2.64,2.64],[2.64,10.02],[12.1,10.02],[12.1,12.36],[2.64,12.36],[2.64,22.12]]}}},{"ty":"fl","c":{"a":0,"k":[0,0,0,1]},"o":{"a":0,"k":100}},{"ty":"tr","o":{"a":0,"k":100}}]},{"ty":"tr","o":{"a":0,"k":100}}]}]}]},{"id":"39","layers":[{"ind":38,"ty":4,"ks":{},"ip":0,"op":121,"st":0,"shapes":[{"ty":"rc","p":{"a":0,"k":[11,15]},"r":{"a":0,"k":0},"s":{"a":0,"k":[22,30]}},{"ty":"fl","c":{"a":0,"k":[0,0,0,0]},"o":{"a":0,"k":0}}]},{"ind":0,"ty":4,"ks":{"s":{"a":0,"k":[133.33,133.33]}},"ip":0,"op":121,"st":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"sh","ks":{"a":0,"k":{"c":true,"i":[[0,0],[0,0],[0,0],[-1.09,-0.58],[-0.52,-1.01],[0,-1.29],[0.53,-0.99],[1.09,-0.57],[1.69,0],[0,0],[0,0],[0,0],[-0.71,0.34],[-0.32,0.63],[0,0.88],[0.33,0.65],[0.72,0.36],[1.18,0],[0,0],[0,0]],"o":[[0,0],[0,0],[1.7,0],[1.09,0.57],[0.53,1.01],[0,1.29],[-0.52,1],[-1.09,0.56],[0,0],[0,0],[0,0],[1.16,0],[0.71,-0.34],[0.33,-0.63],[0,-0.87],[-0.33,-0.66],[-0.72,-0.36],[0,0],[0,0],[0,0]],"v":[[0.36,22.12],[0.36,0.3],[7.73,0.3],[11.93,1.17],[14.36,3.55],[15.14,6.99],[14.36,10.41],[11.94,12.75],[7.77,13.59],[1.8,13.59],[1.8,11.21],[7.69,11.21],[10.5,10.7],[12.05,9.25],[12.55,6.99],[12.05,4.7],[10.49,3.18],[7.64,2.64],[3,2.64],[3,22.12]]}}},{"ty":"sh","ks":{"a":0,"k":{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[10.63,12.32],[16,22.12],[12.93,22.12],[7.64,12.32]]}}},{"ty":"fl","c":{"a":0,"k":[0,0,0,1]},"o":{"a":0,"k":100}},{"ty":"tr","o":{"a":0,"k":100}}]},{"ty":"tr","o":{"a":0,"k":100}}]},{"ty":"tr","o":{"a":0,"k":100}}]}]}]},{"id":"44","layers":[{"ind":43,"ty":4,"ks":{},"ip":0,"op":121,"st":0,"shapes":[{"ty":"rc","p":{"a":0,"k":[13,15]},"r":{"a":0,"k":0},"s":{"a":0,"k":[26,30]}},{"ty":"fl","c":{"a":0,"k":[0,0,0,0]},"o":{"a":0,"k":0}}]},{"ind":0,"ty":4,"ks":{"s":{"a":0,"k":[133.33,133.33]}},"ip":0,"op":121,"st":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"sh","ks":{"a":0,"k":{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[3.19,22.12],[0.42,22.12],[8.43,0.3],[11.16,0.3],[19.17,22.12],[16.4,22.12],[9.88,3.75],[9.71,3.75]]}}},{"ty":"sh","ks":{"a":0,"k":{"c":true,"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[4.21,13.59],[15.38,13.59],[15.38,15.94],[4.21,15.94]]}}},{"ty":"fl","c":{"a":0,"k":[0,0,0,1]},"o":{"a":0,"k":100}},{"ty":"tr","o":{"a":0,"k":100}}]},{"ty":"tr","o":{"a":0,"k":100}}]}]}]},{"id":"49","layers":[{"ind":48,"ty":4,"ks":{},"ip":0,"op":121,"st":0,"shapes":[{"ty":"rc","p":{"a":0,"k":[14.5,15]},"r":{"a":0,"k":0},"s":{"a":0,"k":[29,30]}},{"ty":"fl","c":{"a":0,"k":[0,0,0,0]},"o":{"a":0,"k":0}}]},{"ind":0,"ty":4,"ks":{"s":{"a":0,"k":[133.33,133.33]}},"ip":0,"op":121,"st":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"sh","ks":{"a":0,"k":{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[0.07,0.3],[3.22,0.3],[10.64,18.41],[10.89,18.41],[18.31,0.3],[21.46,0.3],[21.46,22.12],[18.99,22.12],[18.99,5.54],[18.78,5.54],[11.96,22.12],[9.57,22.12],[2.75,5.54],[2.54,5.54],[2.54,22.12],[0.07,22.12]]}}},{"ty":"fl","c":{"a":0,"k":[0,0,0,1]},"o":{"a":0,"k":100}},{"ty":"tr","o":{"a":0,"k":100}}]},{"ty":"tr","o":{"a":0,"k":100}}]}]}]},{"id":"54","layers":[{"ind":53,"ty":4,"ks":{},"ip":0,"op":121,"st":0,"shapes":[{"ty":"rc","p":{"a":0,"k":[9.5,15]},"r":{"a":0,"k":0},"s":{"a":0,"k":[19,30]}},{"ty":"fl","c":{"a":0,"k":[0,0,0,0]},"o":{"a":0,"k":0}}]},{"ind":0,"ty":4,"ks":{"s":{"a":0,"k":[133.33,133.33]}},"ip":0,"op":121,"st":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"sh","ks":{"a":0,"k":{"c":true,"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[0.51,22.12],[0.51,0.3],[13.68,0.3],[13.68,2.64],[3.15,2.64],[3.15,10.02],[13,10.02],[13,12.36],[3.15,12.36],[3.15,19.77],[13.85,19.77],[13.85,22.12]]}}},{"ty":"fl","c":{"a":0,"k":[0,0,0,1]},"o":{"a":0,"k":100}},{"ty":"tr","o":{"a":0,"k":100}}]},{"ty":"tr","o":{"a":0,"k":100}}]},{"ty":"tr","o":{"a":0,"k":100}}]}]}]},{"id":"59","layers":[{"ind":58,"ty":4,"ks":{},"ip":0,"op":121,"st":0,"shapes":[{"ty":"rc","p":{"a":0,"k":[11,15]},"r":{"a":0,"k":0},"s":{"a":0,"k":[22,30]}},{"ty":"fl","c":{"a":0,"k":[0,0,0,0]},"o":{"a":0,"k":0}}]},{"ind":0,"ty":4,"ks":{"s":{"a":0,"k":[133.33,133.33]}},"ip":0,"op":121,"st":0,"shapes":[{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"gr","it":[{"ty":"sh","ks":{"a":0,"k":{"c":true,"i":[[0,0],[0.91,0.6],[1.32,0],[0.73,-0.31],[0.4,-0.55],[0,-0.7],[-0.28,-0.42],[-0.44,-0.28],[-0.48,-0.18],[-0.41,-0.11],[0,0],[-0.7,-0.26],[-0.64,-0.45],[-0.42,-0.7],[0,-1.02],[0.62,-0.95],[1.18,-0.56],[1.68,0],[1.14,0.5],[0.66,0.9],[0.08,1.19],[0,0],[-0.48,-0.54],[-0.75,-0.26],[-0.87,0],[-0.8,0.32],[-0.47,0.59],[0,0.79],[0.41,0.45],[0.66,0.29],[0.77,0.21],[0,0],[1,0.91],[0,1.47],[-0.66,0.91],[-1.12,0.5],[-1.39,0],[-1.09,-0.5],[-0.64,-0.87],[-0.04,-1.1]],"o":[[-0.13,-1.08],[-0.91,-0.6],[-0.96,0],[-0.71,0.31],[-0.4,0.55],[0,0.58],[0.29,0.41],[0.44,0.27],[0.48,0.17],[0,0],[0.57,0.15],[0.7,0.27],[0.64,0.45],[0.42,0.7],[0,1.18],[-0.61,0.95],[-1.17,0.56],[-1.56,0],[-1.14,-0.5],[-0.64,-0.9],[0,0],[0.07,0.82],[0.49,0.54],[0.75,0.25],[1.01,0],[0.8,-0.34],[0.47,-0.6],[0,-0.73],[-0.41,-0.46],[-0.66,-0.29],[0,0],[-1.7,-0.49],[-0.99,-0.91],[0,-1.22],[0.67,-0.92],[1.13,-0.51],[1.41,0],[1.09,0.5],[0.64,0.87],[0,0]],"v":[[13.12,5.75],[11.57,3.24],[8.22,2.34],[5.68,2.81],[4,4.1],[3.41,5.96],[3.82,7.47],[4.91,8.5],[6.29,9.17],[7.63,9.59],[9.84,10.18],[11.73,10.8],[13.75,11.88],[15.35,13.61],[15.98,16.19],[15.05,19.39],[12.36,21.66],[8.09,22.5],[4.04,21.74],[1.35,19.63],[0.25,16.49],[2.98,16.49],[3.81,18.54],[5.66,19.73],[8.09,20.11],[10.81,19.63],[12.71,18.24],[13.42,16.15],[12.81,14.38],[11.21,13.27],[9.07,12.53],[6.39,11.76],[2.34,9.66],[0.85,6.09],[1.84,2.9],[4.52,0.77],[8.3,0],[12.05,0.76],[14.66,2.8],[15.68,5.75]]}}},{"ty":"fl","c":{"a":0,"k":[0,0,0,1]},"o":{"a":0,"k":100}},{"ty":"tr","o":{"a":0,"k":100}}]},{"ty":"tr","o":{"a":0,"k":100}}]},{"ty":"tr","o":{"a":0,"k":100}}]}]}]},{"id":"62","layers":[{"ind":36,"ty":0,"parent":32,"ks":{},"w":18,"h":30,"ip":0,"op":121,"st":0,"refId":"34"},{"ind":32,"ty":3,"parent":31,"ks":{},"ip":0,"op":121,"st":0},{"ind":41,"ty":0,"parent":37,"ks":{},"w":22,"h":30,"ip":0,"op":121,"st":0,"refId":"39"},{"ind":37,"ty":3,"parent":31,"ks":{"p":{"a":0,"k":[23,0]}},"ip":0,"op":121,"st":0},{"ind":46,"ty":0,"parent":42,"ks":{},"w":26,"h":30,"ip":0,"op":121,"st":0,"refId":"44"},{"ind":42,"ty":3,"parent":31,"ks":{"p":{"a":0,"k":[46,0]}},"ip":0,"op":121,"st":0},{"ind":51,"ty":0,"parent":47,"ks":{},"w":29,"h":30,"ip":0,"op":121,"st":0,"refId":"49"},{"ind":47,"ty":3,"parent":31,"ks":{"p":{"a":0,"k":[76,0]}},"ip":0,"op":121,"st":0},{"ind":56,"ty":0,"parent":52,"ks":{},"w":19,"h":30,"ip":0,"op":121,"st":0,"refId":"54"},{"ind":52,"ty":3,"parent":31,"ks":{"p":{"a":0,"k":[111,0]}},"ip":0,"op":121,"st":0},{"ind":61,"ty":0,"parent":57,"ks":{},"w":22,"h":30,"ip":0,"op":121,"st":0,"refId":"59"},{"ind":57,"ty":3,"parent":31,"ks":{"p":{"a":0,"k":[134,0]}},"ip":0,"op":121,"st":0},{"ind":31,"ty":3,"ks":{"a":{"a":0,"k":[77.651,15]},"p":{"a":0,"k":[92.651,18]}},"ip":0,"op":121,"st":0}]},{"id":"28","layers":[{"ind":27,"ty":4,"parent":26,"ks":{},"ip":0,"op":121,"st":0,"shapes":[{"ty":"rc","p":{"a":1,"k":[{"t":0,"s":[0,21],"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"t":60,"s":[0,21],"i":{"x":[0,1],"y":[1,1]},"o":{"x":[0.5,0],"y":[0,0]}},{"t":120,"s":[79,21],"h":1}]},"r":{"a":0,"k":0},"s":{"a":1,"k":[{"t":0,"s":[0,42],"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"t":60,"s":[0,42],"i":{"x":[0,1],"y":[1,1]},"o":{"x":[0.5,0],"y":[0,0]}},{"t":120,"s":[158,42],"h":1}]}},{"ty":"fl","c":{"a":0,"k":[1,1,1]},"o":{"a":0,"k":100}}]},{"ind":26,"ty":3,"parent":25,"ks":{"a":{"a":1,"k":[{"t":0,"s":[0,21],"i":{"x":[1,1],"y":[1,1]},"o":{"x":[0,0],"y":[0,0]}},{"t":60,"s":[0,21],"i":{"x":[0,1],"y":[1,1]},"o":{"x":[0.5,0],"y":[0,0]}},{"t":120,"s":[79,21],"h":1}]},"p":{"a":0,"k":[93,18]}},"ip":0,"op":121,"st":0},{"ind":25,"ty":3,"ks":{"p":{"a":0,"k":[79,3]}},"ip":0,"op":121,"st":0}]}],"fr":60,"h":36,"ip":0,"layers":[{"ind":23,"ty":0,"td":1,"parent":2,"ks":{"a":{"a":0,"k":[79,0]}},"w":264,"h":37,"ip":0,"op":121,"st":0,"refId":"21"},{"ind":8,"ty":0,"tt":1,"parent":2,"ks":{"a":{"a":0,"k":[3,32]}},"w":195,"h":132,"ip":0,"op":121,"st":0,"refId":"6"},{"ind":2,"ty":3,"parent":1,"ks":{},"ip":0,"op":121,"st":0},{"ind":64,"ty":0,"td":1,"parent":24,"ks":{},"w":171,"h":33,"ip":0,"op":121,"st":0,"refId":"62"},{"ind":30,"ty":0,"tt":1,"parent":24,"ks":{"a":{"a":0,"k":[79,3]}},"w":330,"h":45,"ip":0,"op":121,"st":0,"refId":"28"},{"ind":24,"ty":3,"parent":1,"ks":{},"ip":0,"op":121,"st":0},{"ind":1,"ty":3,"parent":0,"ks":{},"ip":0,"op":121,"st":0},{"ind":0,"ty":3,"ks":{},"ip":0,"op":121,"st":0}],"meta":{"g":"https://jitter.video"},"op":120,"v":"5.7.4","w":185}
;

const animation = bodymovin.loadAnimation({
  container: document.getElementById('logo'),
  renderer: 'svg',
  loop: true,
  autoplay: true,
  animationData: logoSvgData
})
body {
  background:black;

}
#logo {
  width: 100px;
  height: auto;
  margin: 0 auto;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/bodymovin/5.5.3/lottie.js"></script>
<body>
<div id="logo"></div>
</body>