3 điểm bởi GN⁺ 2024-08-30 | 1 bình luận | Chia sẻ qua WhatsApp
  • Trong lúc lướt web, tác giả phát hiện một thành phần ASCII art thú vị. Trông rất ấn tượng nhưng khó hiểu được cách triển khai
  • Khi kiểm tra mã nguồn thì thấy mã đã được rút gọn (minified)

Ví dụ về mã đã rút gọn

  • Một phần mã như sau:
    const { floor: ra, abs: KE, min: QE } = Math,  
      O5 = ["reactive.network REACTIVE.NETWORK", "$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/|()1{}[]?-_+~i!lI;:,^`'. .:â–‘â–’â–“â–ˆ"],  
      G7 = Date.now() % 3 ? O5[1] : O5[0],  
      V5 = G7.length,  
      JE = { fps: 60 };  
    

Yêu cầu ChatGPT giải thích mã

  • Tác giả đã yêu cầu ChatGPT "hãy giải thích đoạn mã này"
  • Phản hồi của ChatGPT:

    Đoạn mã được cung cấp khá phức tạp, nhưng tôi sẽ giải thích từng phần và chức năng của nó theo cách dễ hiểu.

Tổng quan

  • Định nghĩa nhiều hàm và thành phần bằng JavaScript
  • Tạo nội dung văn bản động trong một ứng dụng React
  • Tạo hiệu ứng trực quan bằng ASCII art hoặc bộ ký tự được định nghĩa sẵn

Các thành phần và hàm chính

  1. Chọn bộ ký tự:
const { floor: ra, abs: KE, min: QE } = Math;  
const O5 = ["reactive.network REACTIVE.NETWORK", "$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/|()1{}[]?-_+~i!lI;:,^`'. .:â–‘â–’â–“â–ˆ"];  
const G7 = Date.now() % 3 ? O5[1] : O5[0];  
const V5 = G7.length;  
  • Lấy các hàm từ Math và định nghĩa hai bộ ký tự
  • Chọn bộ ký tự theo thời gian hiện tại
  • Lưu độ dài của bộ ký tự đã chọn
  1. Hàm chọn ký tự động:
function eT(e, t, n, r) {  
  const i = t.time * 8e-5;  
  const s = QE(t.cols, t.rows);  
  const o = t.metrics.aspect * 0.2;  
  const l = { x: ((4 * (e.x - t.cols / 6.25)) / s) * o, y: (5 * (e.y - t.rows / 4)) / s };  
  const u = ra(KE(YE(l) - i) * V5 + (ra(e.x / 1) % 2) * 2) % V5;  
  return G7[u];  
}  
  • Hàm eT tạo ký tự dựa trên vị trí đầu vào và thời gian hiện tại
  • Điều chỉnh vị trí rồi chọn một ký tự từ bộ ký tự
  1. Component React hiển thị nội dung động (tT):
const tT = () => {  
  const e = j.useRef(null);  
  const [t, n] = j.useState({ height: null, width: null });  
  j.useEffect(() => {  
    function r() {  
      n({ height: window.innerHeight, width: window.innerWidth });  
    }  
    if (typeof window < "u") {  
      n({ height: window.innerHeight, width: window.innerWidth });  
      window.addEventListener("resize", r);  
      return () => window.removeEventListener("resize", r);  
    }  
  }, []);  
  j.useEffect(() => {  
    const r = e.current;  
    if (!r) return;  
    const i = 12;  
    const s = ra(t.width / i) * 1.6;  
    const o = ra(t.height / i);  
    const l = { aspect: s / o };  
    const u = setInterval(() => {  
      let c = "";  
      for (let d = 0; d < o; d++) {  
        for (let f = 0; f < s; f++) c += eT({ x: f, y: d }, { cols: s, rows: o, metrics: l, time: Date.now() });  
        c += `  `;  
      }  
      r.textContent = c;  
    }, 1e3 / JE.fps);  
    return () => clearInterval(u);  
  }, [t]);  
  return a.jsx("div", { style: { position: "absolute", top: 0, left: 0, width: "100%", height: "100%" }, children: a.jsx("div", { ref: e, style: { width: "100%", height: "100%", whiteSpace: "pre", overflow: "hidden" } }) });  
};  
  • Component React này định kỳ cập nhật nội dung của phần tử div bằng các ký tự được tạo động
  • Tính số cột và số hàng theo kích thước cửa sổ rồi lấp đầy div bằng ký tự

Mã đã được chuyển sang TypeScript

  • Tác giả yêu cầu ChatGPT chuyển mã sang TypeScript
  • Phản hồi của ChatGPT:
    import React, { useEffect, useRef, useState } from 'react';  
    const selectedCharacterSet = "$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/|()1{}[]?-_+~i!lI;:,^`'. .:â–‘â–’â–“â–ˆ";  
    const characterSetLength = selectedCharacterSet.length;  
    
    const calculateCharacter = (  
      x: number,  
      y: number,  
      cols: number,  
      rows: number,  
      aspect: number,  
      time: number,  
    ): string => {  
      const timeFactor = time * 0.000_08;  
      const size = Math.min(cols, rows);  
      const aspectRatio = aspect * 0.2;  
      const position = {  
        x: ((4 * (x - cols / 6.25)) / size) * aspectRatio,  
        y: (5 * (y - rows / 4)) / size,  
      };  
      const index = Math.floor(  
        Math.abs(  
          Math.cos(position.x * position.x - position.y * position.y) - timeFactor,  
        ) * characterSetLength + (Math.floor(x) % 2) * 2,  
      ) % characterSetLength;  
      return selectedCharacterSet[index];  
    };  
    
    type Size = {  
      height: null | number;  
      width: null | number;  
    };  
    
    const AsciiArtGenerator: React.FC = () => {  
      const textRef = useRef(null);  
      const [size, setSize] = useState({ height: null, width: null });  
    
      useEffect(() => {  
        const handleResize = () => {  
          setSize({ height: window.innerHeight, width: window.innerWidth });  
        };  
        handleResize();  
        window.addEventListener('resize', handleResize);  
        return () => {  
          window.removeEventListener('resize', handleResize);  
        };  
      }, []);  
    
      useEffect(() => {  
        const element = textRef.current;  
        if (!element || !size.width || !size.height) return undefined;  
    
        const cols = Math.floor(size.width / 12) * 1.6;  
        const rows = Math.floor(size.height / 12);  
        const aspectRatio = cols / rows;  
    
        const intervalId = setInterval(() => {  
          let content = '';  
          for (let y = 0; y < rows; y++) {  
            for (let x = 0; x < cols; x++) {  
              content += calculateCharacter(x, y, cols, rows, aspectRatio, Date.now());  
            }  
            content += '\n';  
          }  
          element.textContent = content;  
        }, 1_000 / 60);  
    
        return () => {  
          clearInterval(intervalId);  
        };  
      }, [size]);  
    
      return (  
    
      );  
    };  
    
    export default () => {  
      return ;  
    };  
    

Tóm tắt của GN⁺

  • Bài viết này giải thích cách hiểu và khôi phục mã đã được rút gọn
  • Cho thấy quá trình dùng ChatGPT để giải thích mã phức tạp và chuyển nó sang TypeScript
  • Đề xuất cách tận dụng các công cụ AI để hỗ trợ việc khôi phục và hiểu mã nguồn
  • Các dự án có chức năng tương tự gồm PrettierUglifyJS

1 bình luận

 
GN⁺ 2024-08-30
Ý kiến trên Hacker News
  • Tác giả của HumanifyJS đã phát triển một công cụ dựa trên LLM. Công cụ này sử dụng LLM ở cấp độ AST để đảm bảo mã vẫn hoạt động sau khi được unminification

  • Việc JS minification mang tính cơ học và tương đối đơn giản. Dù khá phiền nếu làm thủ công, bản thân phép biến đổi này bị giới hạn nên vẫn có thể đọc được bằng cách ghi chú lại một số định danh để theo dõi

  • Unminification hay unobfuscation nói chung vẫn là một bài toán chưa được giải quyết. Trước đây có người từng viết các chương trình bị làm rối có chủ đích, nhưng ChatGPT thậm chí không hiểu được cả ở mức bề mặt

    • Ví dụ: GPT-4 từng cố giải thích một trình thông dịch Brainfuck dài 160 byte, nhưng kết quả hoàn toàn không giống với mã gốc
    • Liên kết mã ví dụ
  • Một số nhà phát triển có thể không hài lòng vì họ dùng minification để làm rối mã. Công cụ "mã hóa" mã do các phiên bản cũ của ColdFusion cung cấp từng sử dụng một thuật toán yếu, nhưng vẫn có người tin rằng nó an toàn và dùng nó

  • Trong tiêu đề, có lẽ dùng ChatGPT hoặc gpt-4 thay vì OpenAI sẽ phù hợp hơn

  • Đây là một ví dụ về năng lực trí tuệ vượt trội hơn con người. LLM hiểu được unminification, và trong chủ đề cụ thể này, chúng vượt trội hơn con người

  • LLM rất giỏi trong việc biến đổi văn bản. Đây là thế mạnh cốt lõi của chúng

  • Khoảng 1 năm trước, có người đã thử dùng GPT để gỡ rối mã độc nhưng thấy tự phân tích mã vẫn tốt hơn. Khi thử lại gần đây, GPT đã có thể hiểu được ở mức độ nào đó

    • Ví dụ: nhận ra logic phát hiện tải trang, thực hiện tính toán và chuyển hướng đến trang độc hại
    • Liên kết báo cáo
  • Dùng LLM để làm cho mã phức tạp dễ đọc hơn mang lại cảm giác rất giải phóng. Đôi khi chúng bỏ sót chi tiết, nhưng điều đó có thể tự kiểm tra lại

    • Bạn có thể hiểu mục đích của đoạn mã, nhưng khi không hiểu vì sao nó được viết theo cách cụ thể đó thì có thể hỏi LLM để có thêm góc nhìn mới
    • Liên kết ví dụ sử dụng
  • Nếu mã đã unminified không khớp với mã minified thì tính hữu dụng sẽ giảm đi rất nhiều. Trong nhiều trường hợp, sau khi chạy mã cũng không thể kiểm tra được sự khác biệt

  • Khi muốn biết thuật toán tính toán của một website, chỉ cần đưa JS đã minified vào ChatGPT là có thể nắm được khá dễ dàng. Có thể hình dung một tương lai nơi LLM có thể clone toàn bộ một ứng dụng SAAS

    • Ví dụ: để tạo một bản sao HubSpot, LLM có thể tương tác với trình duyệt, phân tích UI và đề xuất kiến trúc backend
    • AI sẽ là một yếu tố giảm phát mạnh trong tương lai