“Regarding handling big numbers or chains of numbers, the current implementation uses BigInt for encryption and decryption, which allows handling large numbers. However, there can be limitations”. which another more reasonable way, except this “BigInt”? do you know any other variants that can be used, without any third-party libraries or frameworks? “Keep in mind that this approach may be more complex and less efficient than using BigInt, especially for complex operations.”. then which method or way are more reasonable? because in the current implementation it cannot encrypt or handle big numbers within P and Q range used. don’t generalizein terms. the purpose for this code is to function within an RSA encryption/decryption needs.: 
      const maxRange = 5000;
      let n, e, d; // define global variables for encryption and decryption

      // Utility function to check if an input is numeric
      function isNumeric(n) {
        return !isNaN(parseFloat(n)) && isFinite(n);
      }

      const maxSize = 1000; // Max size
      const threshold = 5000; // Threshold value
      let maxRangeInput = document.getElementById("maxRange");
      let warningMsg = document.getElementById("maxRangeWarningMsg");

      // Set initial value
      maxRangeInput.value = maxSize;

      maxRangeInput.onchange = function () {
        let value = maxRangeInput.value;
        if (value > threshold) {
          let confirmation = confirm(
            `!!!WARNING!!! Setting Max Prime Size too large (above ${threshold}) may result in crashes! Do you wish to continue?`
          );

          if (!confirmation) {
            maxRangeInput.value = maxSize; // Reset back to maxSize if declined
            warningMsg.textContent =
              "Max Range reset to safe value: " + maxSize;
          }
        } else {
          warningMsg.textContent = "";
        }
      };

      // Utility function to find the closest prime number
      function isPrime(num) {
        for (let i = 2, max = Math.sqrt(num); i <= max; i++) {
          if (num % i === 0) return false;
        }
        return num > 1;
      }

      function modularExponentiation(base, exponent, modulus) {
        if (modulus === 1n) return 0n;
        let result = 1n;
        for (let i = exponent; i > 0n; i /= 2n) {
          if (i % 2n === 1n) result = (result * base) % modulus;
          base = (base * base) % modulus;
        }
        return result;
      }

      function gcd(a, b) {
        while (b !== 0) {
          let t = a;
          a = b;
          b = t % b;
        }
        return a;
      }

      function closestPrime(num) {
        do num--;
        while (!isPrime(num));
        return num;
      }

      function generatePrimeNumbers() {
        const warningMsg = document.getElementById("warningMsg");
        const pBitSizeElement = document.getElementById("pBitSize");
        const qBitSizeElement = document.getElementById("qBitSize");

        let p = document.getElementById("p").value;
        // Check if input is empty or zero
        if (!isNumeric(p) || p == "" || p == "0") {
          warningMsg.textContent =
            "Invalid input: P should be numeric, not zero and max 5 digits.";
          return;
        }
        p = closestPrime(parseInt(p));

        let q = document.getElementById("q").value;
        // Check if input is empty or zero
        if (!isNumeric(q) || q == "" || q == "0") {
          warningMsg.textContent =
            "Invalid input: Q should be numeric, not zero and max 5 digits.";
          return;
        }
        q = closestPrime(parseInt(q));

        if (!isPrime(p) || p > maxRange) {
          warningMsg.textContent = `${p} is not a valid prime number. Prime numbers within the range should not exceed ${maxRange}.`;
          return;
        }
        if (!isPrime(q) || q > maxRange) {
          warningMsg.textContent = `${q} is not a valid prime number. Prime numbers within the range should not exceed ${maxRange}.`;
          return;
        }

        n = p * q;
        document.getElementById("multiplyPrimes").textContent = n;
        const totient = (p - 1) * (q - 1);

        e = 2;
        while (gcd(e, totient) !== 1) {
          e++;
        }
        document.getElementById("encryptionExponent").textContent = e;

        d = 1;
        while ((e * d) % totient !== 1 || e === d) {
          d++;
        }
        document.getElementById("decryptionExponent").textContent = d;
        document.getElementById("p").value = p;
        document.getElementById("q").value = q;

        // Calculate bit size for P and Q
        const pBitSize = Math.ceil(Math.log2(p + 1));
        const qBitSize = Math.ceil(Math.log2(q + 1));

        pBitSizeElement.innerHTML = `${pBitSize} bits`;
        qBitSizeElement.innerHTML = `${qBitSize} bits`;

        const modulusBitSize = Math.ceil(Math.log2(n + 1));
        document.getElementById("modulusBitSize").innerHTML = `${modulusBitSize} bits`;

        warningMsg.textContent = "";
      }

      document
        .getElementById("generate-primes-btn")
        .addEventListener("click", generatePrimeNumbers);

      // Adapting the Encryption function to handle both ASCII and Numeric encryption.
      document.getElementById("encrypt-btn").addEventListener("click", function () {
        let message = document.getElementById("inputMessage").value;
        let warningMsg = document.getElementById("enwarningMsg");

        // Check if input is empty
        if (message == "") {
          warningMsg.textContent =
            "Invalid input. Please input a message for encryption.";
          return;
        }

        if (document.getElementById("messageMode").value === "numeric") {
          // Numeric encryption, so input must not contain non-numeric characters
          if (!/^\d+$/.test(message)) {
            warningMsg.textContent =
              "Invalid input. Please input numeric characters only.";
            return;
          } else {
            warningMsg.textContent = ""; // Reset any previous warning
            let toEncrypt = BigInt(message);
            message = modularExponentiation(
              toEncrypt,
              BigInt(e),
              BigInt(n)
            ).toString();
          }
        } else {
          // ASCII mode
          message = message
            .split("")
            .map((ch) => {
              let toEncrypt = BigInt(ch.charCodeAt(0));
              return modularExponentiation(
                toEncrypt,
                BigInt(e),
                BigInt(n)
              ).toString();
            })
            .join(" ");
        }
        document.getElementById("encryptionResult").textContent = message;
      });

      // Adapting the Decryption function to handle both ASCII and Numeric decryption.
      document
        .getElementById("decrypt-btn")
        .addEventListener("click", function () {
          let encryptedMessage = document.getElementById("encryptionResult")
            .textContent;
          let decryptedMessage = "";

          if (document.getElementById("messageMode").value === "ascii") {
            decryptedMessage = encryptedMessage
              .split(" ")
              .map((element) =>
                String.fromCharCode(
                  Number(
                    modularExponentiation(
                      BigInt(element),
                      BigInt(d),
                      BigInt(n)
                    )
                  )
                )
              )
              .join("");
          } else {
            // Numeric mode
            decryptedMessage = Number(
              modularExponentiation(BigInt(encryptedMessage), BigInt(d), BigInt(n))
            );
          }
          document.getElementById("decryptionResult").textContent =
            decryptedMessage;
        });

      function generateRandomPrimeNumbers() {
        const warningMsg = document.getElementById("warningMsg");
        const pBitSizeElement = document.getElementById("pBitSize");
        const qBitSizeElement = document.getElementById("qBitSize");

        let p = Math.floor(Math.random() * maxRange) + 1;
        p = closestPrime(p);

        let q = Math.floor(Math.random() * maxRange) + 1;
        q = closestPrime(q);

        // Rest of the code for generating primes, calculating n, e, d is same as for manual generation
        n = p * q;
        document.getElementById("multiplyPrimes").textContent = n;
        const totient = (p - 1) * (q - 1);

        e = 2;
        while (gcd(e, totient) !== 1) {
          e++;
        }
        document.getElementById("encryptionExponent").textContent = e;

        d = 1;
        while ((e * d) % totient !== 1 || e === d) {
          d++;
        }
        document.getElementById("decryptionExponent").textContent = d;
        document.getElementById("p").value = p;
        document.getElementById("q").value = q;

        // Calculate bit size for P and Q
        const pBitSize = Math.ceil(Math.log2(p + 1));
        const qBitSize = Math.ceil(Math.log2(q + 1));

        pBitSizeElement.innerHTML = `${pBitSize} bits`;
        qBitSizeElement.innerHTML = `${qBitSize} bits`;

        const modulusBitSize = Math.ceil(Math.log2(n + 1));
        document.getElementById("modulusBitSize").innerHTML = `${modulusBitSize} bits`;

        warningMsg.textContent = "";
      }

      // Add event listener for "Generate Primes Randomly" button
      document
        .getElementById("generate-primes-random-btn")
        .addEventListener("click", generateRandomPrimeNumbers);
      document.getElementById("maxRange").value = maxSize;