sidebar navigation sticky position move little upwards at end of scroll why?

I created a sidebar div and a main content div. The main content contains a large amount of text, making the page scrollable. I want the sidebar to remain sticky while scrolling the page. I achieved this using position: sticky and a top value, but when I scroll, the sidebar sticks in the middle, and at the end of the scroll, it moves up. Why does this happen?

* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

:root {
    --light-color: #EDF4F2;
    --dark-color: #31473A;
    --medium-color: #D3CAE2;
}

body {
    min-height: 100vh;
    min-width: 100vw;
    background-color: var(--light-color);
    display: grid;
    grid-template-columns: 20% 1fr;
    grid-template-rows: auto 1fr auto;
    grid-template-areas:
            'top-nav-area top-nav-area'
            'side-area main-area'
            'side-area main-area'
            'side-area footer-area';


}

.top-navigation {
    top: 0;
    position: sticky;
    grid-area: top-nav-area;
    background-color: var(--medium-color);
    padding: 2em;
}

.side-navigation {
    min-height: calc(100vh - 82px);
    top: 82px;
    position: sticky;
    align-self: start;
    grid-area: side-area;
    background-color: var(--dark-color);
    overflow-y: auto;


}

.main-content {
    grid-area: main-area;
}

.footer {
    grid-area: footer-area;
    background-color: var(--light-color);
}
<body>
    <nav class="top-navigation">Navigation</nav>
    <aside class="side-navigation">side-navigation</aside>
    <main class="main-content">
          <p>large  text</p>
    </main>
    <footer class="footer" id="footer">footer</footer>
</body>

output i get
start
middle
end

Initialize global variable in bokeh and use it in handler code

What I want to achieve here:

  • I want to generate static HTML and do the data initialization exactly once
  • I want to pass a complex data structure to the document and use it by multiple buttons / UI elements
  • I don’t want to pass the same complex data structure to each button / UI element as source property, because it will generate larger HTML file
from bokeh.models import Div, CustomJS
from bokeh.layouts import column
from bokeh.plotting import show
from bokeh.io import curdoc

dummy_div = Div(text="")
init_code = CustomJS(code="""
    window.sharedData = { initialized: true };
    console.log("Data initialized in Div change");
""")
#dummy_div.js_on_change("text", init_code)

button1 = Button(label="Log Complex Data", button_type="success")
button1.js_on_click(CustomJS(code="""
    console.log("Current shared data:", window.sharedData);
"""))

# button_N = ...

layout = column(dummy_div, button1)

curdoc().add_root(layout)
curdoc().on_event('document_ready', lambda event: init_code.execute(curdoc()))

show(layout)

Is it possible to implement something like this with this library?

Unable to upload Bam files to flask backend (Argument must be string, bytes or unicode)

I have been stuck on this problem for some time now. I am trying to upload a BAM file (ranging 0.7GB – 2.3GB) from my website via flask to my back end filesystem. I have tried a couple things already. I started just trying to upload the whole file to no ones surprise got errors instantly with a disconnection error. Some post suggested that this could be due to timeouts of either docker or gunicorn so i increased this timeout to 10min (just to make sure this was no issue). After still getting errors on timeout i tried to upload the files in chunks this seemed to go better except it keeps giving error to one of the chunks, this chunk is never the same but always the last chunk to finish making me think it has to do with merging the chunks back together. I hope a fresh pair of trained eyes can help me out here. The following is parts of the code im working with, unfortunately not the cleanest because of multiple interns working on this project:
HTML:

<div class="gene_box">
    <div class="box_header">
        <h3 class="box_header_title">> Data Import</h3>
        <a href="/static/html/help.html" target="_blank">
            <img class="tooltip_img" src="../static/images/help_icon.png" />
        </a>
    </div>
    <div class="content">
        Data upload<br />
        <select id="file_type" name="file_type" onchange="enableFormElements()">
            <option value="default">Select Data Type</option>
            <option value="genomic_positions">Genomic elements</option>
            <option value="read_map">Read Counts</option>
            <option value="splice_variants">Splice Variants</option>
        </select>
        <input type="file" name="uploaded_file" id="uploaded_file" style="width:210px;"><br />
        <button id="upload_button" class="button">Upload</button>
        <div id="loader"></div>
    </div>
    <div id="read_map" class="checkboxes hidden">
        <div>
            <input type="checkbox" id="read_map_scale" value="forward" name="genomic_element_include"
                class="checkbox" />
            <label id="linear_label" for="read_map_scale" class="checkbox_label">Normal destribution</label>
        </div>
        <div>
            <input type="checkbox" id="read_map_scale" value="reverse" name="genomic_element_include"
                class="checkbox" />
            <label id="log2_label" for="read_map_scale" class="checkbox_label">Log2 destribution</label>
        </div>
        <div>
            <input type="checkbox" id="read_map_scale" value="both" name="genomic_element_include"
                class="checkbox" />
            <label id="log10_label" for="read_map_scale" class="checkbox_label">Log10 destribution</label>
    </div>

    </div>
    <div id="splice_variants" class="checkboxes hidden">
        <h1>Splice Variants</h1>
    </div>
</div>

The Javascript:

document.addEventListener('DOMContentLoaded', function () {
    document.getElementById("upload_button").addEventListener("click", function() {
        event.preventDefault();
        const uploadedFile = document.getElementById("uploaded_file").files[0];
        const mode = document.getElementById("read_map_scale").value; // Get mode
        const fileType = document.getElementById("file_type").value; // Get file type
        var accessionCode = document.querySelector('#gi_codes').value.trim();

        if (!uploadedFile) { alert("No file selected.");
            return;
        }
        if (!mode || mode === "default") { alert("Please select a mode.");
            return;
        }


        if (fileType === "genomic_positions") {
            poscalc(uploadedFile, globalresults_json, accessionCode);
        } else if (fileType === "read_map") {
            // Track uploaded chunks
            file_to_readdata(uploadedFile, mode, fileType);

            
        } else if (fileType === "splice_variantes"){
            alert("Work in progress not funcitonal yet");

        } else{
            alert("Invalid file type selected. (there is no functionality for this option yet)");
        }
    });
});

function file_to_readdata (uploadedFile) {
    const chunkSize = 10 * 1024 * 1024; // 5 MB chunk size
    const totalChunks = Math.ceil(uploadedFile.size / chunkSize);
    let uploadedChunks = 0;
    for (let i = 0; i < totalChunks; i++) {
        const start = i * chunkSize;
        const end = Math.min(start + chunkSize, uploadedFile.size);
        const chunk = uploadedFile.slice(start, end);

        console.log(`Uploading chunk ${i + 1}/${totalChunks}`);
        console.log("Chunk size:", chunk.size);

        const formData = new FormData();
        formData.append("chunk", chunk);
        formData.append("chunkIndex", i);
        formData.append("totalChunks", totalChunks);
        formData.append("fileName", uploadedFile.name);

        fetch(`${$SCRIPT_ROOT}/_upload_file`, {
            method: "POST",
            body: formData,
        })
            .then((response) => response.json())
            .then((data) => {
                console.log(data);
                if (data.status === "success") {
                    console.log(`Chunk ${i + 1}/${totalChunks} uploaded successfully`);
                    uploadedChunks++;

                    // Check if all chunks are uploaded
                    if (uploadedChunks === totalChunks) {
                        console.log("File upload complete");
                        
                    }
                } else {
                    console.error(`Error uploading chunk ${i + 1}:`, data.message);
                }
            })
            .catch((error) => {
                console.error("Error uploading chunk:", error);
            });
        }
}

The flask script:

@app.route('/_upload_file', methods=['GET', 'POST'])
def process_file():
    """
    When the user uploads a bam or sam file, the file is processed, and the data is returned in a dictionary-like structure to the client.
    """
    UPLOAD_DIR='../uploads'
    try:
            logging.debug("Request Files: %s", request.files)
            logging.debug("Request Form: %s", request.form)

            # Extract form data
            chunk = request.files.get('chunk')
            mode = request.form.get('mode')
            chunk_index = int(request.form.get('chunkIndex', -1))  # Default -1 for debug
            total_chunks = int(request.form.get('totalChunks', -1))
            file_name = request.form.get('fileName')

            logging.debug("Chunk: %s", chunk)
            logging.debug("Mode: %s", mode)
            logging.debug("Chunk Index: %d", chunk_index)
            logging.debug("Total Chunks: %d", total_chunks)
            logging.debug("File Name: %s", file_name)
            
            # Create a temporary file to store chunks
            temp_file_path = os.path.join(UPLOAD_DIR, f"{file_name}.part{chunk_index}")
            chunk.save(temp_file_path)

            # Check if all chunks are uploaded
            uploaded_chunks = [f for f in os.listdir(UPLOAD_DIR) if f.startswith(file_name)]
            if len(uploaded_chunks) == total_chunks:
                # Combine chunks
                complete_file_path = os.path.join(UPLOAD_DIR, file_name)
                with open(complete_file_path, 'wb') as output_file:
                    for i in range(total_chunks):
                        part_path = os.path.join(UPLOAD_DIR, f"{file_name}.part{i}")
                        with open(part_path, 'rb') as part_file:
                            output_file.write(part_file.read())
                        os.remove(part_path)  # Clean up chunk file
                if rcg.is_valid_bam(output_file):  # Use temp_file.name
                    sorted_bam = rcg.sort_and_index_bam(output_file)  # Pass temp_file.name to your helper function
                    coverage = rcg.calculate_full_coverage(sorted_bam, mode)
                else:
                    coverage = rcg.calculate_full_coverage(output_file, mode)
                return jsonify({"status": "success", "message": "File uploaded successfully", "filePath": complete_file_path})
            
            return jsonify({"status": "success", "message": "Chunk uploaded successfully"})
        
    except Exception as ex:
        return jsonify({"status": "error", "message": str(ex)}), 500

The error:

Uploading chunk 72/73 handle_context_submission.js:296:17
Chunk size: 10485760 handle_context_submission.js:297:17
Uploading chunk 73/73 handle_context_submission.js:296:17
Chunk size: 2228747

POST http://0.0.0.0:443/_upload_file   [HTTP/1.1 500 INTERNAL SERVER ERROR 4248ms]
Chunk 72/73 uploaded successfully handle_context_submission.js:313:29
Object { message: "Argument must be string, bytes or unicode.", status: "error" }
Error uploading chunk 73: Argument must be string, bytes or unicode.

Client_Potential_XSS Issue Detected in DOMPurify by Checkmarx

I recently used DOMPurify in my project to sanitize user input and prevent XSS attacks.

However, after running a source code scan using Checkmarx, I encountered an issue labeled as Client_Potential_XSS.

This vulnerability appears to originate from DOMPurify v3.2.3 line 866 where the element.insertBefore is used.

Line 866

return element instanceof HTMLFormElement && (/*some code*/ || typeof element.insertBefore !== 'function' || /*some code*/);

I assume Checkmarx is treating this line of code as the insertBefore() method, does anyone know how to solve this problem?

Error: Failed to load external module @stripe/firestore-stripe-payments: Error [ERR_MODULE_NOT_FOUND]: Cannot find module

This is the full error I’m receiving:

Error: Failed to load external module
@stripe/firestore-stripe-payments: Error [ERR_MODULE_NOT_FOUND]:
Cannot find module
‘C:UsersEliDesktopnetflix-clonenode_modules@stripefirestore-stripe-paymentslibinit’
imported from
C:UsersEliDesktopnetflix-clonenode_modules@stripefirestore-stripe-paymentslibindex.js

I’ve tried re installing, deleting node_modules and clearing cache etc.

Here’s my repository: https://github.com/efranklin1357/netflix-clone

Handling Dynamic Domains in Android App Links for React Native

I recently implemented the Android App Links functionality in React Native, and it is working fine on Android. However, I know we can set a particular domain or host in the AndroidManifest.xml. I also know it supports multiple hosts and subdomains, like www.example.com and www.abc.com.

But is it possible to declare or use dynamic domains in this functionality? Because as per my requirements, I have a list of domains that are continuously updated. Is it possible to achieve this? As far as I know, the declared domain and host names only redirect to specific screens in the app.

Additionally, is there any way to dynamically fetch and handle the domains via an API call in the JavaScript code? This could allow the app to dynamically handle updated domain lists without requiring changes in the AndroidManifest.xml.

<intent-filter android:autoVerify="true">
                <action android:name="android.intent.action.VIEW" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />
                <data android:scheme="https" />
                <data android:host="exmple.com" />
                <data android:pathPrefix="/stream" />
            </intent-filter>
            <intent-filter android:autoVerify="true">
                <action android:name="android.intent.action.VIEW" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />
                <data android:scheme="https" />
                <data android:host="example1.com" />
                <data android:pathPrefix="/profile" />
            </intent-filter>

Pattern Matching and number extraction

I created the following code to extract numerical information from a user-provided string, which specifies the level or floor in a building. The goal is to accurately extract the numerical value from the input. However, the current implementation does not handle hyphenated numbers correctly. For instance, “twenty-third” is incorrectly resolved as 20 instead of 23.

function extractLevelFromString(input) {
    // Normalize the input string
    const normalizedInput = input.toLowerCase();

    
    const wordToNumberMap = {
        "one": 1, "first": 1,
        "two": 2, "second": 2,
        "three": 3, "third": 3,
        "four": 4, "fourth": 4,
        "five": 5, "fifth": 5,
        "six": 6, "sixth": 6,
        "seven": 7, "seventh": 7,
        "eight": 8, "eighth": 8,
        "nine": 9, "ninth": 9,
        "ten": 10, "tenth": 10,
        "eleven": 11, "eleventh": 11,
        "twelve": 12, "twelfth": 12,
        "thirteen": 13, "thirteenth": 13,
        "fourteen": 14, "fourteenth": 14,
        "fifteen": 15, "fifteenth": 15,
        "sixteen": 16, "sixteenth": 16,
        "seventeen": 17, "seventeenth": 17,
        "eighteen": 18, "eighteenth": 18,
        "nineteen": 19, "nineteenth": 19,
        "twenty": 20, "twentieth": 20,
        "twenty-one": 21, "twenty-first": 21,
        "twenty-two": 22, "twenty-second": 22,
        "twenty-three": 23, "twenty-third": 23,
        "twenty-four": 24, "twenty-fourth": 24,
        "twenty-five": 25, "twenty-fifth": 25,
        "twenty-six": 26, "twenty-sixth": 26,
        "twenty-seven": 27, "twenty-seventh": 27,
        "twenty-eight": 28, "twenty-eighth": 28,
        "twenty-nine": 29, "twenty-ninth": 29,
        "thirty": 30, "thirtieth": 30,
        "thirty-one": 31, "thirty-first": 31,
        "thirty-two": 32, "thirty-second": 32,
        "thirty-three": 33, "thirty-third": 33,
        "thirty-four": 34, "thirty-fourth": 34,
        "thirty-five": 35, "thirty-fifth": 35,
        "thirty-six": 36, "thirty-sixth": 36,
        "thirty-seven": 37, "thirty-seventh": 37,
        "thirty-eight": 38, "thirty-eighth": 38,
        "thirty-nine": 39, "thirty-ninth": 39,
        "forty": 40, "fortieth": 40,
        "forty-one": 41, "forty-first": 41,
        "forty-two": 42, "forty-second": 42,
        "forty-three": 43, "forty-third": 43,
        "forty-four": 44, "forty-fourth": 44,
        "forty-five": 45, "forty-fifth": 45,
        "forty-six": 46, "forty-sixth": 46,
        "forty-seven": 47, "forty-seventh": 47,
        "forty-eight": 48, "forty-eighth": 48,
        "forty-nine": 49, "forty-ninth": 49,
        "fifty": 50, "fiftieth": 50
    };
    

    const levelRegex = /b(level|floor|on|at)?s*(d+|one|two|three|four|five|six|seven|eight|nine|ten|eleven|twelve|thirteen|fourteen|fifteen|sixteen|seventeen|eighteen|nineteen|twenty|twenty-one|twenty-two|twenty-three|twenty-four|twenty-five|twenty-six|twenty-seven|twenty-eight|twenty-nine|thirty|thirty-one|thirty-two|thirty-three|thirty-four|thirty-five|thirty-six|thirty-seven|thirty-eight|thirty-nine|forty|forty-one|forty-two|forty-three|forty-four|forty-five|forty-six|forty-seven|forty-eight|forty-nine|fifty|first|second|third|fourth|fifth|sixth|seventh|eighth|ninth|tenth|eleventh|twelfth|thirteenth|fourteenth|fifteenth|sixteenth|seventeenth|eighteenth|nineteenth|twentieth|twenty-first|twenty-second|twenty-third|twenty-fourth|twenty-fifth|twenty-sixth|twenty-seventh|twenty-eighth|twenty-ninth|thirtieth|thirty-first|thirty-second|thirty-third|thirty-fourth|thirty-fifth|thirty-sixth|thirty-seventh|thirty-eighth|thirty-ninth|fortieth|forty-first|forty-second|forty-third|forty-fourth|forty-fifth|forty-sixth|forty-seventh|forty-eighth|forty-ninth|fiftieth)(?:st|nd|rd|th)?b/gi;
 
    const matches = normalizedInput.matchAll(levelRegex);

    // Process matches
    for (const match of matches) {
        const levelCandidate = match[2]; // Get the potential level part

        // If numeric, return directly
        if (!isNaN(levelCandidate)) {
            return parseInt(levelCandidate, 10);
        }

        // If word-based, map to a number
        if (wordToNumberMap[levelCandidate]) {
            return wordToNumberMap[levelCandidate];
        }
    }

    // Return null if no level found
    return null;
}

I tried this using regex pattern matching and was expecting the resolution of numbers from the input string.

Issue found: Missing prominent disclosure

Issue found: Missing prominent disclosure
We were unable to approve your app because we could not locate prominent disclosure of your use of the AccessibilityService API in your app.

Please update your app so that the prominent disclosure meets all the requirements as defined in the User Data Policy.

About the Accessibility API Policy
The Accessibility API cannot be used to:

Change user settings without their permission or prevent the ability for users to disable or uninstall any app or service unless authorized by a parent or guardian through a parental control app or by authorized administrators through enterprise management software.
Work around Android built-in privacy controls and notifications or
Change or leverage the user interface in a way that is deceptive or otherwise violates Play Developer Policies.
The accessibility API is not designed and cannot be requested for remote call audio recording.

The use of the Accessibility API must be documented in the Play Store listing. Please remember to include in the Play Console, a link to an updated video showcasing the core functionality feature that uses the AccessibilityService API with each new app submission.

Apps with a core functionality intended to directly support people with disabilities are eligible to use the IsAccessibilityTool to appropriately publicly designate themselves as an accessibility app. Apps not eligible for IsAccessibilityTool may not use the flag and must meet prominent disclosure and consent requirements as outlined in the User Data policy as the accessibility related functionality is not obvious to the user. Please refer to the AccessibilityService API help center article for more information.

Apps must use limited, more narrowly scoped APIs and permissions in lieu of the Accessibility API when possible to achieve the desired functionality.

Additionally, follow these steps to bring your app into compliance: Read more about AccessibilityService API Capability and Prominent Disclosure best practices

Action required: Submit an updated app for review
Here’s what to do to help get your app on Google Play:
Make sure to read the applicable policies or requirements listed below:
Accessibility API Policy
Make appropriate changes to your app (if possible), and be sure to address the issue described above. You may also want to check your app’s store listing for compliance, if applicable.
Double check that your app is compliant with all other Developer Program Policies.
If you made changes to your app bundle, store listing, or APK, please sign in to your Play Console and submit the update(s).
Submit an Appeal
Make sure you have followed the instructions provided on this page to quickly address this issue. If you have fixed the violation, you do not need to appeal and can directly make an updated submission. If you believe our decision may be incorrect, you can appeal. It may take up to 7 days to receive a response, or longer in exceptional cases.

Learn More
Visit the Enforcement Process article to learn more about how different enforcement actions can impact your apps in different ways. Check out the latest Google Play policy updates on Privacy, Deception and Device Abuse, Health Content and Services, Enforcement Process, Mobile Unwanted Software, and more!
Watch this #PolicyBytes video! Choose your preferred language by changing the audio track in the settings.

I tried many times but rejected same reason please help

How can I use the version information from appsettings.json in client-side JavaScript within a .NET Web API application?

In my .NET Web API project, I store the version number of my JavaScript file in appsettings.json like this:

{
  "JSSettings": {
    "Version": "1.0.0"
  }
}

The version number will change over time, and I need to ensure that the JavaScript file is always loaded with the correct version for cache busting. For example, the script tag should look like this:

<script src="/js/app.js?v={//this we get from appsettings}"></script>

How can I dynamically retrieve this version from appsettings.json and inject it into my HTML/JavaScript so that the correct version is always used, without manually updating the HTML each time the version changes?

Did anyone tried to integrate dialogflow chatbot with firebase authentication in order for users to sign in using provided email and password?

I am trying to integrate firebase authentication with sign-in using email and password in dialogflow es chatbot. I am facing an issue with pre-deployment lint error and I don’t understand what to fill in webhook details in fulfillment. Can anyone please help me with it.Also would be helpful if anyone could provide a javascript or typescript function for email and password log-in throught firebase authentication..

Wrote a js function to send in email and password info to firebase authentication to verify and inform dialogflow whether if its true or false. Problem with deployment, showing lint error.

Can anyone provide a sample js function for it.

Chrome Extension is failing to sendMessasge() from chrome.storage.onChange handler

I am developing a Chrome V3 extension with an options page that uses chrome.storage to persist user prefs.

On the background script js I have a listener that handles chrome.storage updates by firing sendMessage to the content script and awaiting confirmation back. The goal is to immediately fire scripts from the content script as soon as user preferences are updated, but sendMessage appears to not be firing.

The code I’m using is below:

// background.js 

chrome.storage.onChanged.addListener( async ( changes, namespace ) => {
  const queryOptions = { active: true, lastFocusedWindow: true }
  const [ tab ] = await chrome.tabs.query( queryOptions )
  for ( const [ key, { newValue } ] of Object.entries( changes ) ) {
    const message = JSON.parse( `{ "${ key }":${ newValue }}` )
    chrome.tabs.sendMessage( tab.id, { message }, function ( response ) {
      if ( !chrome.runtime.lastError ) {
        if ( typeof response !== 'undefined' ) {
          console.log( { response } )
        }
      }
    } )
  }
} )

// content.js

chrome.runtime.onMessage.addListener( function ( message, sender, sendResponse ) { 
  console.log( { message } ) 
  const response = 'got it'
  sendResponse( { response } ) 
} )

Since I’m using an options page instead of embedded options UI, the chrome.tabs API is available, however, I misread the docs and initially used chrome.runtime.sendMessage. Still, I’m able to capture the tab that I want from the background script, ie. I’m able to get an object representing the active tab that contains id keys for tab and window.

Additionally I’ve commented out all code except for what’s needed for messaging, but still the same results.

I’ve previously designed an extension that sends messages between background and content scripts that uses nearly this same code but something seems to be preventing that in this case.

I’m mostly certain that it can’t be code from the site my extension’s acting on that’s preventing sendMessage but cannot be certain

Stroybook build using vite: ReferenceError: require is not defined

I’m using storybook and vite to build the components. On prod I’m getting this error:

ReferenceError: require is not defined

So I build the project on local and started serving this using http-server. Thus, I’m able to produce this on local as well. Appreciate any help.

I tried adding

import commonjs from 'vite-plugin-commonjs';

into the plugins

But it didn’t resolve.

Here’s my vite.config

import { UserConfig, defineConfig } from 'vite';
import { resolve } from 'path';
import react from '@vitejs/plugin-react';
import commonjs from 'vite-plugin-commonjs';
import { visualizer } from 'rollup-plugin-visualizer';
import svgr from 'vite-plugin-svgr';
import dts from 'vite-plugin-dts';
import { libInjectCss } from 'vite-plugin-lib-inject-css';
import tsconfigPaths from 'vite-tsconfig-paths';
import packageJson from './package.json';
import tsConfig from './tsconfig.json';
import { nodeResolve } from '@rollup/plugin-node-resolve';
import peerDepsExternal from 'rollup-plugin-peer-deps-external';
// https://vitejs.dev/config/
export default defineConfig((): UserConfig => {
  return {
    plugins: [
      react(),
      commonjs(),
      tsconfigPaths(),
      libInjectCss(),
      visualizer({ filename: 'stats/stats.html' }),
      svgr(),
      dts({
        exclude: [
          '**/*.stories.tsx',
          '**/*.test.tsx',
          '**/*.test.ts',
          '**/*.stories.ts',
          'src/test-utils/**',
          'src/mock/**',
          'src/setupTests.ts',
          '**/*._test.tsx',
        ],
        tsconfigPath: './tsconfig.json',
        compilerOptions: {
          baseUrl: tsConfig.compilerOptions.baseUrl,
          paths: tsConfig.compilerOptions.paths,
        },
      }),
    ],
    build: {
      copyPublicDir: false,
      sourcemap: true,
      emptyOutDir: true,
      lib: {
        entry: resolve(__dirname, 'src/index.ts'),
        formats: ['es'],
        name: 'te-components',
      },
      
      rollupOptions: {
        plugins: [
          peerDepsExternal({ includeDependencies: true }),
          nodeResolve({
            mainFields: ['module', 'main', 'browser'],
            extensions: ['.js', '.jsx', '.ts', '.tsx', '.json'],
          }),
        ],
        external: [
          ...Object.keys(packageJson.dependencies),
          ...Object.keys(packageJson.peerDependencies),
          'react/jsx-runtime',
          '@babel/runtime',
          'prop-types',
          'lodash',
          '@mui/system',
          '@mui/material',
          '@mui/icons-material',
        ],
        output: {
          assetFileNames: 'assets/[name][extname]',
          entryFileNames: '[name].js',
          chunkFileNames: '[name].js',
          preserveModules: true,
          preserveModulesRoot: 'src',
        },
      },
    },
    optimizeDeps: {
      include: ['vite-plugin-commonjs'], // List the packages here
      esbuildOptions: {
        // Ensure that require statements are transformed for ES modules
        loader: {
          '.js': 'jsx',
        },
      },
    },
  };
});

enter image description here

Javascript function returning wrong encoding

I have a web page with UTF-8 charset set via the usual meta:

<meta http-equiv="Content-Type" content="text/html; charset=utf-8">

Then there is a javascript function exif that returns some UTF-8 text contained in an image EXIF (ImageDescription tag). But when I try to show this data in a popup, I see the usual crazy characters

En 1978 llegó proveniente de Pisba, Boyacá. Por su mochila...

If I also do

console.log("########### "+ImageDescription);

I see the same incorrect characters.

I tried to add charset="UTF-8" to the javascript code without success.

How do I force/tell the javascript function exif, or the HTML, to interpret correctly this characters?

Google Apps Script: sendFileToEmail() not being called via google.script.run

I’m creating a Google Apps Script project to send quiz files via email. The sendFileToEmail() function works when run directly in the Apps Script editor, but it doesn’t execute when called through google.script.run from my HTML interface.
HTML Code:

<button id="reStartButton" disabled="disabled" onclick="start1()">Send files to your email</button>

<script>
  var start1 = async () => {
    document.getElementById("reStartButton").disabled = true;
    var response = await new Promise(resolve => google.script.run.withSuccessHandler(resolve).sendFileToEmail());
    console.log("Email sent: ", response);
  };
</script>

Apps Script Code:

function sendFileToEmail() {
  Logger.log("Function called.");
  var myEmail = Session.getActiveUser().getEmail();
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var solId = ss.getSheetByName('title').getRange('A77').getValue();
  var sol = UrlFetchApp.fetch(`https://docs.google.com/spreadsheets/d/${solId}/export?format=xlsx&id=${solId}`, {
    method: "GET",
    headers: { "authorization": "Bearer " + ScriptApp.getOAuthToken() }
  }).getBlob();
  MailApp.sendEmail(myEmail, 'Quiz', 'See attached.', { attachments: [sol] });
}

Issue:
The Logger.log(“Function called.”) message never appears, suggesting the function isn’t called. When run directly in the Apps Script editor, the function works fine.

Scopes:
My appsscript.json includes:

"oauthScopes": [
  "https://www.googleapis.com/auth/spreadsheets",
  "https://www.googleapis.com/auth/drive",
  "https://www.googleapis.com/auth/script.send_mail",
  "https://www.googleapis.com/auth/gmail.send"
]

What could prevent google.script.run from invoking the function? How can I resolve this?

I can’t login to agora service RTM even though i generate token in the backend

I can’t login to agora service RTM even though i generate token in the backend and also i set up my appId and certificateId correctly

I get this error:

Ins#2 RTM:ERROR [UTC_Time: 01-06 01:12:48.603][uid: 10]get edge info error Error Code -10012, server Code 26 – Login RTM service was rejected due to server error.apCode is 26, unexpected code.. +0ms

Rtm.jsx:21 RtmUnavailableError: Error Code -10012, server Code 26 – Login RTM service was rejected due to server error.apCode is 26, unexpected code.

here is the component where i try to login to RTM service:

const { RTM } = AgoraRTM;
  const rtmClient = new RTM("dca3bcedaaeb4bde9f618461df7f2aff","10");

  const initRtm = async () => {
    const response = await fetch('http://localhost:4000/realtime-token');
    const token = await response.json();
    rtmClient.login({token})
      .then(() => {
        console.log("RTM client logged in successfully");
      })
      .catch((error) => {
        console.log(error);
      });
  }
  initRtm();

the code below i generate the token via buildToken function:

app.get('/realtime-token', (req, res) => {
    const APP_ID = 'dca3bcedaaeb4bde9f618461df7f2aff';
    const APP_CERTIFICATE = 'db54959bc19e4b78a3ae948c76da6b86';
    try {
        const uid = "10";
        const currentTimestamp = Math.floor(Date.now() / 1000);
        const privilegeExpiredTs = currentTimestamp + 36000; // Reduced to 1 hour for testing
        
        const token = RtmTokenBuilder.buildToken(
            APP_ID,
            APP_CERTIFICATE,
            uid,
            privilegeExpiredTs
        );
        
        console.log('Generated token:', token);
        console.log('Token expiry:', new Date(privilegeExpiredTs * 1000));
        return res.json(token);
    } catch (error) {
        console.error('Token generation error:', error);
        return res.status(500).json({ error: error.message });
    }
});