---
# System prepended metadata

title: JS

---

```=csharp
protected void Page_Load(object sender, EventArgs e)
{
    var sm = ScriptManager.GetCurrent(Page);
    if (sm != null) sm.EnablePageMethods = true;   // 不用動 MasterPage 標記
}
[System.Web.Services.WebMethod]
public static object Search(string q, int take) { /* 回 { ok,data } */ }
```


```=SQL
-- [Feature] Article Chunked Upload Schema
-- 主表：文章主體 (儲存壓縮後 HTML)
CREATE TABLE fwpdb.article (
  article_id      VARCHAR2(64 CHAR) NOT NULL,   
  title           VARCHAR2(200 CHAR) NOT NULL, 
  version_no      NUMBER DEFAULT 1 NOT NULL,    -- 目前版本號
  content_gz      BLOB NOT NULL,                -- 壓縮後 HTML
  created_by      VARCHAR2(50 CHAR),
  created_at      DATE DEFAULT SYSDATE,
  updated_at      DATE DEFAULT SYSDATE,
  CONSTRAINT pk_article_id primary key (article_id)
);
/
--版本交易表：記錄每次上傳的完整版本資訊
CREATE TABLE fwpdb.article_version_tx (
  version_id      VARCHAR2(64 CHAR) NOT NULL,   -- 公開唯一 ID
  article_id      VARCHAR2(64 CHAR) NOT NULL,
  version_no      NUMBER NOT NULL,  -- 對應主表版本
  total_chunks    NUMBER NOT NULL,  -- 分段總數
  received_chunks NUMBER,           -- 已上傳段數
  chunk_size      NUMBER,           -- 每段大小
  sha256_hex      VARCHAR2(64),     -- 壓縮內容 Hash
  orig_bytes      NUMBER,           -- 原始大小
  gzip_bytes      NUMBER,           -- 壓縮大小
  completed       CHAR(1) DEFAULT 'N' CHECK (completed IN ('Y','N')),
  uploaded_by     VARCHAR2(50 CHAR),
  created_at      DATE DEFAULT SYSDATE NOT NULL,
  updated_at      DATE DEFAULT SYSDATE NOT NULL,
  CONSTRAINT pk_version_id primary key (version_id),
  CONSTRAINT uq_article_version UNIQUE (article_id, version_no),
  CONSTRAINT uq_article_version_id UNIQUE (article_id)
)
/
--  分段紀錄表：追蹤每個上傳分段
CREATE TABLE fwpdb.article_chunk_tx (
  chunk_id        VARCHAR2(64 CHAR) NOT NULL,   -- 公開唯一 ID
  article_id      VARCHAR2(64 CHAR) NOT NULL,
  version_no      NUMBER NOT NULL,
  chunk_seq       NUMBER NOT NULL,           -- 第幾段 (1-based)
  chunk_data      BLOB,                      -- 暫存上傳分段
  chunk_size      NUMBER,                    -- 實際段大小
  uploaded_by     VARCHAR2(50 CHAR),
  created_at      DATE DEFAULT SYSDATE,
  CONSTRAINT uq_article_chunk UNIQUE (article_id, version_no, chunk_seq),
  CONSTRAINT uq_article_chunk_id UNIQUE (chunk_id)
)
/
COMMENT ON TABLE fwpdb.article IS 'HELEPER CENTER 主文章表';
COMMENT ON COLUMN fwpdb.article.article_id IS '文章唯一識別碼 (UUID)';
COMMENT ON COLUMN fwpdb.article.title IS '文章標題';
COMMENT ON COLUMN fwpdb.article.version_no IS '當前版本號';
COMMENT ON COLUMN fwpdb.article.content_gz IS 'Gzip 壓縮 HTML 內容';
COMMENT ON COLUMN fwpdb.article.created_by IS '建立者';
COMMENT ON COLUMN fwpdb.article.created_at IS '建立時間';
COMMENT ON COLUMN fwpdb.article.updated_at IS '更新時間';
/
COMMENT ON TABLE fwpdb.article_version_tx IS '文章版本交易紀錄表';
COMMENT ON COLUMN fwpdb.article_version_tx.version_no IS '版本號';
COMMENT ON COLUMN fwpdb.article_version_tx.total_chunks IS '分段總數';
COMMENT ON COLUMN fwpdb.article_version_tx.received_chunks IS '已上傳段數';
COMMENT ON COLUMN fwpdb.article_version_tx.completed IS '是否完成 (Y/N)';
/
COMMENT ON TABLE fwpdb.article_chunk_tx IS '文章分段上傳紀錄表';
COMMENT ON COLUMN fwpdb.article_chunk_tx.chunk_seq IS '分段順序 (1-based)';
COMMENT ON COLUMN fwpdb.article_chunk_tx.chunk_data IS '分段資料 (BLOB)';
COMMENT ON COLUMN fwpdb.article_chunk_tx.uploaded_by IS '上傳使用者';
/
SELECT * FROM fwpdb.article
/
SELECT * FROM fwpdb.article_version_tx
/
SELECT * FROM fwpdb.article_chunk_tx
```


-------------
```=javaScript 
             //init
        const editor = CKEDITOR.replace('editor1');

        const getData = async (apiUrl, payload) => {
            try {
                const res = await fetch(apiUrl, {
                    method: "POST",
                    headers: {
                        "Content-Type": "application/json; charset=utf-8",
                    },
                    body: JSON.stringify(payload),
                })
                return res?.d
            } catch (e) {
                console.error(e.errorMessage);
            }
        }

        function htmlToTextWithoutBase64(html) {
            const parser = new DOMParser();
            const doc = parser.parseFromString(html, 'text/html');

            doc.querySelectorAll('script,style,noscript,img[src^="data:image"]').forEach(el => el.remove());
            const text = (doc.body.textContent || '').replace(/\u00A0/g, ' ').trim();

            return text;
        }

        // main
        const sumbitBtn = document.querySelector('.btn');


        // 將 ArrayBuffer 的 SHA-256 轉成 hex 字串
        function bytesToHex(buffer) {
            return [...new Uint8Array(buffer)]
                .map(b => b.toString(16).padStart(2, "0"))
                .join("");
        }

        //加壓Gzip(Binary) 轉 base64
        async function compressionStream(html) {
            const encoder = new TextEncoder();
            const htmlBytes = encoder.encode(html);   //轉 Uint8Array

            //壓縮
            const stream = new Blob([htmlBytes]).stream().pipeThrough(new CompressionStream("gzip"));
            //轉 ArrayBuffer
            const gzipBytes = await new Response(stream).arrayBuffer();
            //將 Uint8Array 轉 base64
            const base64 = btoa(String.fromCharCode(...new Uint8Array(gzipBytes)));

            // 計算 SHA-256（對 gzip bytes）
            const hashBuffer = await crypto.subtle.digest("SHA-256", gzipBytes);
            const sha256_hex = bytesToHex(hashBuffer);


            return { base64, sha256_hex }
;
        }

        //切分 base64 chunks
        function getUploadChuncks(chunkSize = 512 * KB) {
            const KB = 1024;
            const MB = 1024 * KB;
            const totalChunks = Math.ceil(base64Data.length / chunkSize);
            const chunks = [];

            for (let i = 0; i < totalChunks; i++) {
                const chunk = base64Data.slice(i * chunkSize, (i + 1) * chunkSize);
                chunk.push({
                    article_uid: crypto.randomUUID(),
                    chunkIndex: i + 1,
                    totalChunks,
                    chunkSize,
                    chunk,
                });
            }

            return { chunks, chunkSize, totalChunks }
        }

        // 解碼base64
        async function ungzipBase64(base64Str) {
            const binary = atob(base64Str); //base64 to binary string
            const bytes = new Uint8Array(binary.length); //new uint8array

            for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
            const ds = new DecompressionStream("gzip");

            const decompressedStream = new Response(
                new Blob([bytes]).stream().pipeThrough(ds)
            );

            return await decompressedStream.text();
        }

        //base64 to html
        function getFormData() {
            const title = document.querySelector('.title').textContent;
            const html = editor.getData();
            const text = htmlToTextWithoutBase64(html);


            return {
                title, html, text
            };
        }

        sumbitBtn.addEventListener('click', async (e) => {
            try {
                const formData = getFormData();
                //1. 加壓範例
                const { base64, sha256_hex } = await compressionStream(formData.html);
                console.log('加壓準備傳送Base64:', base64, 'sha-256 給後端驗證文件碼要先轉譯 Gzip:', sha256_hex);

                //2. chuncks upload
                const { chunks, chunkSize, totalChunks } = getUploadChuncks();
                console.log('這裡要寫分段Call API, insert Version Table, 分段上傳chunk size');
                console.log(chunks, chunkSize, totalChunks);

                //3. call upload api 
                chunks.forEach(async (chunk) => {
                    //fetch('/UploadChunck')
                });

                //4. verify complete api call
                //fetch('/VerifyUploadComplete') body: {articleId}

                //解壓
                const unGzipBase64 = await ungzipBase64(base64);
                console.log(unGzipBase64);

                //chuncks forEach call api



                //const res = getData('Default2.aspx/GetData', {
                //    data: JSON.stringify(formData)
                //});
                //console.log(res);
            } catch (e) {
                console.error(e);
            }
        });



```







-------------------------------
![messageImage_1746622104751](https://hackmd.io/_uploads/SygTQeFllg.jpg)

![StanleyBF_MachineGuid](https://hackmd.io/_uploads/Syp-b1YCJl.jpg)



MachineGuid    REG_SZ    edafb182-9c50-4cb3-ab8d-7a5b2b1f7bda

## WebFrom
```=HTML
<asp:Content ID="BodyContent" ContentPlaceHolderID="MainContent" runat="server">

    <style>
        .d-flex {
            display: flex;
        }

        .justify-content-center {
            justify-content: center;
        }

        .align-items-center {
            align-items: center;
        }

        .gap-1 {
            gap: 1rem;
        }

        label {
            padding: 8px 16px;
            border-radius: 2px;
            cursor: pointer;
            margin-bottom: 4px;
            border:1px solid #d2cece;
        }

        input[type='radio'] {
            display: none;
        }

            input[type='radio']:checked + label {
                background: #0d6efd;
                color: white;
            }
    </style>
    <div>
        <h1>Test Webfrom form BarCode Demo</h1>
    </div>

    <!-- Release 選擇項目 -->
    <asp:RadioButtonList ID="ReleaseItem" runat="server" RepeatDirection="Horizontal" >
        <asp:ListItem Text="LotId" Value="LotId" Selected="True" />
        <asp:ListItem Text="MagazineId" Value="MagazineId" />
    </asp:RadioButtonList>

    <!-- Release 輸入框 -->
    <div>
        <asp:TextBox CssClass="form-control" ID="ReleaseId" runat="server" placeholder="請輸入LotID" />
        <asp:Button ID="ReleaseSearchBtn" Style="display: none" runat="server" Text="查詢" OnClick="ReleaseSearchBtn_Click" />
    </div>

    <!-- 表格 -->
    <asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
        OnRowCommand="GridView1_RowCommand" EditRowStyle-HorizontalAlign="Justify">
        <Columns>
            <asp:TemplateField HeaderText="項目">
                <ItemTemplate>
                    <asp:Label ID="lblSeqNo" runat="server" Text='<%# Container.DataItemIndex + 1 %>' />
                </ItemTemplate>
            </asp:TemplateField>
            <asp:TemplateField HeaderText="選擇">
                <ItemTemplate>
                    <asp:CheckBox ID="chkSelect" runat="server" />
                </ItemTemplate>
            </asp:TemplateField>
            <asp:BoundField DataField="LotId" HeaderText="LotId" />
            <asp:BoundField DataField="MagazineId" HeaderText="MagazineId" />
            <asp:TemplateField>
                <ItemTemplate>
                    <asp:Button ID="btnDetails" runat="server" Text="詳細" CommandName="Details" CommandArgument='<%# Container.DataItemIndex %>' />
                </ItemTemplate>
            </asp:TemplateField>
            <asp:TemplateField HeaderText="刪除">
                <ItemTemplate>
                    <asp:Button ID="btnDelete" runat="server" Text="刪除" CommandName="Delete" CommandArgument='<%# Container.DataItemIndex %>' />
                </ItemTemplate>
            </asp:TemplateField>
        </Columns>
    </asp:GridView>

    <script>
        const releaseItem = document.querySelector("#<%= ReleaseItem.ClientID%>");
        const releaseInput = document.querySelector("#<%= ReleaseId.ClientID%>");
        const releaseSearchBtn = document.querySelector("#<%= ReleaseSearchBtn.ClientID%>");

        releaseInput.value = "";
        releaseItem.addEventListener('click', (e) => {
            releaseInput.value = "";
            releaseInput.focus();
            releaseInput.placeholder = e.target.value === 'LotId' ? '請輸入LotID' : '請輸入MagazinID';
        })

        releaseSearchBtn.addEventListener("keydown", (e) => {
            if (e.keyCode == 13) {
                releaseSearchBtn.click();
            }
        })

    </script>

</asp:Content>
```

```=csharp 
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Xml.Linq;

public partial class About : Page
{

    public static List<ReleaseRow> DataBase = new List<ReleaseRow>() {
               new ReleaseRow { LotId = "lotId1", MagazineId = "Magazine1" },
                new ReleaseRow { LotId = "lotId2", MagazineId = "Magazine2" }
    };

    [Serializable]
    public class ReleaseRow
    {
        public string LotId { get; set; }
        public string MagazineId { get; set; }

    }


    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            //UpdateReleaseGridView();
        }
    }

    protected void UpdateReleaseGridView()
    {
        List<ReleaseRow> updateData = (List<ReleaseRow>)ViewState["releaseData"];
        try
        {
            if (updateData == null || updateData.Count == 0) return;

            GridView1.DataSource = updateData;
            GridView1.DataBind();
        }
        catch (Exception ex)
        {
        }
    }


    protected void GridView1_RowCommand(object sender, GridViewCommandEventArgs e)
    {
        if (e.CommandName == "Details")
        {
            //rowId
            int rowIndex = Convert.ToInt32(e.CommandArgument);

            // Get rowData
            GridViewRow row = GridView1.Rows[rowIndex];
            Console.WriteLine(row);
            CheckBox chkSelect = (CheckBox)row.FindControl("chkSelect");
            string c2 = row.Cells[2].Text;
            string c3 = row.Cells[3].Text;


            // 測試得到該行數據
            string lotId = ((Label)row.FindControl("LotId")).Text;
            string magazineId = ((Label)row.FindControl("MagazineId")).Text;

            // 顯示詳細資訊
            //Response.Write("<script>alert('LotId: " + lotId + ", MagazineId: " + magazineId + "');</script>");
        }
    }

    private void ShowDetails(int id)
    {
        // 彈窗handler
        string message = $"彈窗{id}";
        // 測試call bootstrap modal
        Response.Write("<script>alert('" + message + "');</script>");
    }


    protected void btnSubmit_Click(object sender, EventArgs e)
    {
        // 拿出選中的資料
        foreach (GridViewRow row in GridView1.Rows)
        {
            CheckBox chkSelect = (CheckBox)row.FindControl("chkSelect");
            if (chkSelect != null && chkSelect.Checked)
            {
                // 獲取行ID
                int id = Convert.ToInt32(GridView1.DataKeys[row.RowIndex].Value);
                // 執行Release Handler
                HandleSelectedData(id);
            }
        }
    }

    //後端Release處理
    private void HandleSelectedData(int id)
    {
        // 模拟执行处理
        Response.Write("<script>alert('處理 " + id + " 的資料');</script>");
    }



    protected void ReleaseSearchBtn_Click(object sender, EventArgs e)
    {
        string releaseItem = string.Empty;

        try
        {
            List<ReleaseRow> searchReleaseData = new List<ReleaseRow>();


            //DateBase Call
            if (ReleaseItem.SelectedItem.ToString() == "LotId")
            {
                searchReleaseData = DataBase.Where(item => item.LotId == ReleaseId.Text).ToList();
            }

            if (ReleaseItem.SelectedItem.ToString() == "MagazineId")
            {
                searchReleaseData = DataBase.Where(item => item.MagazineId == ReleaseId.Text).ToList();
            }

            List<ReleaseRow> updateData = (List<ReleaseRow>)ViewState["releaseData"] ?? new List<ReleaseRow>();

            foreach (ReleaseRow item in searchReleaseData)
            {
                updateData.Add(item);
            }

            List<ReleaseRow> distinctList = updateData
          .GroupBy(item => new { item.LotId, item.MagazineId })
          .Select(group => group.First())
          .ToList();


            Console.WriteLine(distinctList);
            ViewState["releaseData"] = distinctList;
            UpdateReleaseGridView();
            //var listData = DataBase.Where(item => x.LotId == ReleaseId.Text).ToList();
            //ReleaseId.Text

            //search DataBase

            ReleaseId.Focus();

        }
        catch (Exception ex)
        {
            Console.WriteLine(ex);
        }


    }
}
```


## Demo

```=css
*,
*::after,
*::before {
  padding: 0;
  margin: 0;
  box-sizing: border-box;
  font-family: Arial, Helvetica, sans-serif;
}

body::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  /* background: linear-gradient(180deg, rgb(21, 19, 59), rgb(132, 130, 209)); */
  background-color: #fafbffff;
  z-index: -1;
}

/* width */
::-webkit-scrollbar {
  width: 0.5rem;
}

/* Track */
::-webkit-scrollbar-track {
  box-shadow: inset 0 0 5px grey;
  border-radius: 0.25rem;
}

/* Handle */
::-webkit-scrollbar-thumb {
  background: rgb(62, 59, 135);
  border-radius: 0.25rem;
  transition: all 0.3s ease-in;
}

/* Handle on hover */
::-webkit-scrollbar-thumb:hover {
  background: rgb(51, 47, 170);
}

ul {
  list-style: none;
}

.logo {
  display: flex;
  align-items: center;
}

.logo-text {
  font-size: large;
}

.logo-img {
  position: relative;
}

.img-1 {
  max-height: 56px;
  position: relative;
  top: 0;
  object-fit: cover;
}

.img-2 {
  max-height: 56px;
  object-fit: cover;
  position: absolute;
  left: 50%;
}

.svg {
  pointer-events: none;
}

input {
  all: unset;
  position: relative;
}

input::placeholder {
  font-weight: bold;
  font-size: large;
}

button {
  all: unset;
  cursor: pointer;
}

a {
  display: block;
}

.ft-white {
  color: white;
}

.bg-primary {
  background-color: rgb(10, 8, 59);
}

.font-white {
  color: white;
}

.log-image {
  width: 48px;
  height: 48px;
  object-fit: cover;
}

.container {
  max-width: 95%;
  /* padding-left: 12px; */
  /* padding-right: 12px; */
  margin: 0 auto;
}

.header {
  position: sticky;
  top: 0;
  padding-right: 24px;
  padding-left: 24px;
  padding-top: 0.5rem;
  padding-bottom: 0.5rem;
  display: flex;
  align-items: center;
  gap: 2rem;
  box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
}

.btn {
  padding: 0.25rem 0.5rem;
  border-radius: 0.25rem;
  background-color: rgb(62, 59, 135);
}

.btn:hover {
  background-color: rgb(51, 47, 170);
}

.nav-bar_list[disabled='true'] {
  position: relative;
  pointer-events: none;
}

.nav-bar_list[disabled='true']::after {
  display: block;
  position: absolute;
  content: '';
  background-color: gray;
  border-radius: 0.25rem 0.25rem 0 0;
  opacity: 0.8;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
}

.nav-bar_list[disabled='true'] .list-item input {
  color: gray;
}

.nav-bar {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
}

.ml-auto {
  margin-left: auto;
}

.nav-bar_list {
  border-bottom: 2px solid gray;
}

.nav-bar_list:hover {
  border-bottom: 2px solid rgb(86, 81, 225);
}

.nav-bar_list .list-item {
  background-color: transparent;
  border-radius: 0.25rem;
  padding: 0.5rem 0.5rem;
  transition: all 0.25s ease-in;
  cursor: pointer;
}

.nav-bar_list .list-item:hover {
  background-color: rgb(62, 59, 135);
}

.input-box {
  padding: 0.5rem 0.5rem;
}

.arrow::after {
  content: '▼'; /* Unicode 向下箭頭 */
  font-size: 12px;
  margin-left: 5px;
}

.nav-bar_list {
  position: relative;
  transition: all 0.25s ease-in;
}

.nav-bar_list ul {
  position: absolute;
  color: white;
  top: 105%;
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  padding: 0.5rem;
  list-style: none;
  background-color: rgb(10, 8, 59);
  box-shadow: 0px 4px 6px rgba(0, 0, 0, 0.1);
  border-radius: 5px;
  right: 0;
  left: 0;
  opacity: 0;
  transform: translateY(-10px);
  transition: all 0.3s ease;
  z-index: 20;
  visibility: hidden;
  max-height: 220px;
  overflow-y: scroll;
}

/* 顯示下拉內容 */
.nav-bar_list:hover ul {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}

.user-section {
  display: flex;
  align-items: center;
  gap: 0.25rem;
}

.user-section p {
  color: white;
}

.avatar {
  width: 50px;
  height: 50px;
  border-radius: 50%;
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
}

/* navbar-上的按鈕 */
.search-section {
  position: relative;
}

.search-btn {
  padding: 0.25rem 0.5rem;
  border-radius: 0.25rem;
  background-color: transparent;
  transition: all 0.3 ease;
}

.search-btn:hover {
  background-color: rgb(62, 59, 135);
}

.search-btn:hover .search-filter {
  background-color: rgb(62, 59, 135);
}

/* btn 叫出視窗效果 */
.search-filter.showFilter {
  min-width: 320px;
  min-height: 36px;
  opacity: 1;
  visibility: visible;
}

/* 按下搜索 Btn 的方框 */
.search-filter {
  min-width: 0;
  min-height: 0;
  overflow: hidden;
  opacity: 0;
  visibility: hidden;
  background-color: rgb(10, 8, 59);
  position: absolute;
  border: 1px solid gray;
  padding: 0.5rem;
  right: 0;
  transition: all 0.75s ease;
}

.search-input {
  all: unset;
  display: block;
  border-bottom: 1px solid white;
  width: 100%;
  color: white;
  font-size: 1.25rem;
}

.search-input-icon {
  position: absolute;
  right: 0.5rem;
}

/* 機台列表 */

.line-area {
  display: flex;
  flex-direction: column;
  gap: 2rem;
}

.mach-card__List {
  display: flex;
  gap: 2rem;
  box-shadow: 0 20px 25px -5px rgb(0 0 0 / 0.1),
    0 8px 10px -6px rgb(0 0 0 / 0.1);
  border: 1px solid rgb(233, 233, 233);

  border-radius: 0.75rem;
  padding: 1rem;
}

.mach-card {
  box-shadow: 0 20px 25px -5px rgb(0 0 0 / 0.1),
    0 8px 10px -6px rgb(0 0 0 / 0.1);
  border: 1px solid rgb(233, 233, 233);

  padding: 0.5rem;
}

.line-title {
  display: inline-block;
  border-radius: 0.25rem;
  padding: 0.25rem;
  margin-bottom: 0.75rem;
  box-shadow: 0 20px 25px -5px rgb(0 0 0 / 0.1),
    0 8px 10px -6px rgb(0 0 0 / 0.1);
  border: 1px solid rgb(233, 233, 233);
}

.mt-40 {
  margin-top: 40px;
}
```
# JS

```
////////utils///////////
//call api
async function getData(methodName, method = 'GET', data = {}) {
  if (!methodName) return;
  const domain = 'http://localhost:3000/'; //EQP_DashBoard.aspx/

  const setting = {
    method, //POST
    headers: {
      'Content-Type': 'application/json',
    },
  };

  if (method === 'POST') {
    setting.body = JSON.stringify(data);
  }

  try {
    const res = await fetch(`${domain}${methodName}`, setting);
    const data = await res.json();

    if (!data?.d) throw Error('找不到data');
    return data?.d;
    // return JSON.parse(data?.d);
  } catch (err) {
    console.error(`[${methodName} Error] ${err}`);
  }
}

class NavBarDropDownList {
  constructor(containerClass, name, initData) {
    this.containerClass = containerClass;
    this.name = name;
    this.state = {};

    this.create(initData);
  }

  init(data) {
    this.ItemList.innerHTML = '';
    this.input.value = '';
    this.disable(false);

    if (data) this.setListItems(data);
  }

  create(initData) {
    //createElement
    this.container = document.querySelector(`.${this.containerClass}`);
    this.machBox = document.createElement('div');
    this.inputBox = document.createElement('div');
    this.input = document.createElement('input');
    this.ItemList = document.createElement('ul');
    this.machBox.classList.add('nav-bar_list');
    this.inputBox.classList.add('input-box', 'arrow', 'font-white');

    //input setting
    this.input.type = 'text';
    this.input.placeholder = this.name;
    this.input.oninput = (e) => this.onInputHandler(e);
    this.machBox.onclick = (e) => this.onClickHandler(e);
    this.inputBox.append(this.input);

    ///init item list
    this.setListItems(initData);

    //append mach component div
    this.machBox.append(this.inputBox);
    this.machBox.append(this.ItemList);

    //final append dom to html
    this.container.append(this.machBox);
  }

  //設定下拉選單顯示data
  setListItems(data) {
    if (!data?.length) return;
    this.ItemList.innerHTML = '';
    data?.forEach((mach) => {
      const li = document.createElement('li');
      li.classList.add('list-item');
      li.textContent = mach;

      this.ItemList.append(li);
    });
    this.machBox.append(this.ItemList);
  }

  addSearchFilter(outFilterData, targetValue) {
    this.input.value = targetValue;
    this.disable(true);
    outFilterData[this.name] = targetValue;
  }

  //切換 input disable 樣式
  disable(isDisable) {
    this.machBox.setAttribute('disabled', isDisable);
  }

  //click callback
  onClickHandler = (e) => {
    if (this.clickCallBack) {
      this.clickCallBack(e);
    }
  };

  onClickHandlerCallBack = (cb) => {
    this.clickCallBack = cb;
  };

  //input callback
  onInputHandler = (e) => {
    if (this.inputCallback) {
      this.inputCallback(e);
    }
  };

  onInputHandlerCallback(cb) {
    this.inputCallback = cb;
  }
}

//搜索 Array 顯示邏輯
function searchItems(arr, searchWord) {
  const filterItems = [...arr].filter((item) =>
    item.toUpperCase().includes(searchWord.toUpperCase())
  );

  if (searchWord.length === 0) {
    return arr;
  }

  return filterItems;
}

//Avatar 頭像區域
async function avatarCreate() {
  const empData = await getData('GetEmpData');
  const empName = document.querySelector('.empName');
  const avatar = document.querySelector('.avatar');
  empName.textContent = empData?.empName;
  // avatar.setAttribute(
  //   'src',
  //   `https://myvf.kh.asegroup.com/utility/get_emp_photo.asp?emp_no=${empData?.empNo}`
  // );
}

////////主程式///////////

async function main() {
  //def
  let filterData = {}; //[feature] 這裡之後要改成, url search ?=...
  const buildDropList = new NavBarDropDownList('mach-list', '棟別');
  const floorDropList = new NavBarDropDownList('mach-list', '樓層');

  //origin data
  const areaData = await getData('initDropDownData');
  const buildListData = Object.keys(areaData).map((item) => item);
  buildDropList.setListItems(buildListData);

  // 搜索邏輯
  buildDropList.onInputHandlerCallback((e) => {
    const searchWord = e.target.value;
    buildDropList.setListItems(searchItems(buildListData, searchWord));
  });

  buildDropList.onClickHandlerCallBack((e) => {
    if (e.target.classList.contains('list-item')) {
      const target = e.target.textContent;
      buildDropList.addSearchFilter(filterData, target);
      floorDropList.setListItems(areaData[target]);
    }
  });

  floorDropList.onInputHandlerCallback((e) => {
    const searchWord = e.target.value;
    if (areaData[filterData[buildDropList.name]]) {
      floorDropList.setListItems(
        searchItems(areaData[filterData[buildDropList.name]], searchWord)
      );
    }
  });

  floorDropList.onClickHandlerCallBack((e) => {
    const target = e.target.textContent;
    if (e.target.classList.contains('list-item')) {
      floorDropList.addSearchFilter(filterData, target);
    }
  });

  //search 搜索關鍵字Search bar
  //search button
  document.querySelector('.search-btn').addEventListener('click', (e) => {
    const filter = document.querySelector('.search-filter');
    filter.classList.toggle('showFilter');
  });

  // 搜索下方 Tree Table
  document.querySelector('.search-input').addEventListener('input', (e) => {
    const keyword = e.target.value;

    console.log(filterData);

    if (
      Object.keys(filterData)?.map((item) => filterData?.[item] !== '')
        ?.length === 2
    ) {
      console.log('call API', filterData);
    }
  });

  //clear filter
  document.querySelector('.filterclearBtn').addEventListener('click', (e) => {
    buildDropList.init(buildListData);
    floorDropList.init();
    filterData = {};
  });
}

main();


```


```


```


```

```












## NavBar Demo

```
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Demo Navbar</title>
    <link rel="stylesheet" href="style.css" />
  </head>
  <body>
    <section class="bg-primary">
      <header class="header container">
        <!-- Logo -->
        <h1 class="font-white">Logo</h1>
        <!-- nav list -->
        <nav class="nav-bar mach-list"></nav>
        <!-- search btn -->
        <div class="ml-auto search-section">
          <button class="search-btn" type="button">
            <!-- 放大鏡ICON -->
            <svg
              stroke="white"
              fill="white"
              stroke-width="1"
              version="1.1"
              id="search"
              x="0px"
              y="0px"
              viewBox="0 0 24 24"
              height="24px"
              width="24px"
              xmlns="http://www.w3.org/2000/svg"
            >
              <g>
                <path
                  d="M20.031,20.79c0.46,0.46,1.17-0.25,0.71-0.7l-3.75-3.76c1.27-1.41,2.04-3.27,2.04-5.31
                  c0-4.39-3.57-7.96-7.96-7.96s-7.96,3.57-7.96,7.96c0,4.39,3.57,7.96,7.96,7.96c1.98,0,3.81-0.73,5.21-1.94L20.031,20.79z
                   M4.11,11.02c0-3.84,3.13-6.96,6.96-6.96c3.84,0,6.96,3.12,6.96,6.96c0,3.84-3.12,6.96-6.96,6.96C7.24,17.98,4.11,14.86,4.11,11.02
                  z"
                ></path>
              </g>
            </svg>
          </button>
          <div class="search-filter">
            <!-- 放大鏡ICON -->
            <div class="search-input-icon">
              <svg
                stroke="white"
                fill="white"
                stroke-width="1"
                version="1.1"
                id="search"
                x="0px"
                y="0px"
                viewBox="0 0 24 24"
                height="12px"
                width="12px"
                xmlns="http://www.w3.org/2000/svg"
              >
                <g>
                  <path
                    d="M20.031,20.79c0.46,0.46,1.17-0.25,0.71-0.7l-3.75-3.76c1.27-1.41,2.04-3.27,2.04-5.31
                        c0-4.39-3.57-7.96-7.96-7.96s-7.96,3.57-7.96,7.96c0,4.39,3.57,7.96,7.96,7.96c1.98,0,3.81-0.73,5.21-1.94L20.031,20.79z
                         M4.11,11.02c0-3.84,3.13-6.96,6.96-6.96c3.84,0,6.96,3.12,6.96,6.96c0,3.84-3.12,6.96-6.96,6.96C7.24,17.98,4.11,14.86,4.11,11.02
                        z"
                  ></path>
                </g>
              </svg>
            </div>
            <input class="search-input" placeholder="搜索關鍵字" type="text" />
          </div>
        </div>
        <!-- user avatar -->
        <section class="user-section">
          <img
            class="avatar"
            src="https://myvf.kh.asegroup.com/utility/get_emp_photo.asp?emp_no=K14814"
            alt="user-avatar"
          />
          <p>username</p>
        </section>
      </header>
    </section>

    <button class="getBtn">setExsample</button>
    <button class="clearBtn">clearExsample</button>

    <script src="./app.js"></script>
  </body>
</html>


```

```
// 各元件產生function
/**
 *
 * @param {*} className
 * @param {*} name
 * @param {*} list
 * @returns {Array} [HTMLDOM, targetString]
 */
function navDropDownList(className, name, list) {
  const container = document.querySelector(`.${className}`);
  const machList = document.createElement("div");
  const btn = document.createElement("button");
  const ul = document.createElement("ul");
  let targetItem = { [`${name}`]: "" };

  const setValueHandler = (value) => {
    if (!value) return targetItem;
    targetItem = { [`${name}`]: value };
    btn.textContent = value;
    return targetItem;
  };

  const clearValueHandler = () => {
    btn.textContent = name;
    targetItem = { [`${name}`]: "" };
  };

  machList.classList.add("nav-bar_list");
  btn.classList.add("arrow", "list-item", "font-white");
  btn.textContent = name;

  list.forEach((mach) => {
    const li = document.createElement("li");
    li.classList.add("list-item");
    li.textContent = mach;
    li.onclick = handler;
    function handler(e) {
      let item = e?.target?.textContent;
      btn.textContent = item;
      targetItem = item;
      targetItem = {
        [`${name}`]: item,
      };
    }
    ul.append(li);
  });

  machList.append(btn);
  machList.append(ul);
  container.append(machList);

  return [setValueHandler, clearValueHandler];
}

////////////////////////////使用範例/////////////////////////////////

// 範例一:產生下拉選單範例
const [setList1Value, clearList1Value] = navDropDownList("mach-list", "區域", [
  "test1",
  "test2",
]);
const [setList2Value, clearList2Value] = navDropDownList("mach-list", "樓層", [
  "test1",
  "test2",
]);
const [setList3Value, clearList3Value] = navDropDownList("mach-list", "群組", [
  "test1",
  "test2",
]);

// 範例二: 拿到下拉選單目前, 選中的值方法
document.querySelector(".getBtn").addEventListener("click", (e) => {
  let value1 = setList1Value("123");
  let value2 = setList2Value("13123");
  let value3 = setList3Value("2222");

  console.log(value1, value2, value3);
});

// 範例三: 清除下拉選單的值
document.querySelector(".clearBtn").addEventListener("click", (e) => {
  //清除
  clearList1Value();
  clearList2Value();
  clearList3Value();

  //單存拿到目前值 不要帶任何參數即可
  let value1 = setList1Value();
  let value2 = setList2Value();
  let value3 = setList3Value();

  console.log(value1, value2, value3);
});

//search 搜索關鍵字Search bar
document.querySelector(".search-btn").addEventListener("click", (e) => {
  const filter = document.querySelector(".search-filter");
  filter.classList.toggle("showFilter");
});


```


```
*,
*::after,
*::before {
  padding: 0;
  margin: 0;
  box-sizing: border-box;
  font-family: Arial, Helvetica, sans-serif;
}

svg {
  pointer-events: none;
}

button {
  all: unset;
  cursor: pointer;
}

a {
  display: block;
}

.ft-white {
  color: white;
}

.bg-primary {
  background-color: #3450c1;
}

.font-white {
  color: white;
}

.container {
  max-width: 1320px;
  padding-left: 12px;
  padding-right: 12px;
  margin: 0 auto;
  /* border: 1px solid black; */
}

.header {
  padding-top: 0.5rem;
  padding-bottom: 0.5rem;
  display: flex;
  align-items: center;
  gap: 2rem;
}

.nav-bar {
  display: flex;
  gap: 1rem;
}

.ml-auto {
  margin-left: auto;
}

.nav-bar_list .list-item {
  background-color: transparent;
  border-radius: 0.25rem;
  padding: 0.5rem 0.5rem;
  transition: all 0.25s ease-in;
  cursor: pointer;
}
.nav-bar_list .list-item:hover {
  background-color: rgba(140, 140, 140, 0.5);
}

.arrow::after {
  content: "▼"; /* Unicode 向下箭頭 */
  font-size: 12px;
  margin-left: 5px;
}

.nav-bar_list {
  position: relative;
  transition: all 0.25s ease-in;
}

.nav-bar_list ul {
  position: absolute;
  top: 105%;
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  padding: 0.5rem;
  list-style: none;
  background-color: white;
  box-shadow: 0px 4px 6px rgba(0, 0, 0, 0.1);
  border-radius: 5px;
  visibility: hidden;
  /* overflow: hidden; */
  opacity: 0;
  transform: translateY(-10px);
  transition: all 0.3s ease;
}

/* 顯示下拉內容 */
.nav-bar_list:hover ul {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}

.user-section {
  display: flex;
  align-items: center;
  gap: 0.25rem;
}

.user-section p {
  color: white;
}

.avatar {
  width: 48px;
  height: 48px;
  border-radius: 100%;
  object-fit: cover;
}

/* navbar-上的按鈕 */
.search-section {
  position: relative;
}

.search-btn {
  padding: 0.25rem 0.5rem;
  border-radius: 0.25rem;
  transition: all 0.3 ease;
}

.search-btn:hover .search-filter {
  background-color: rgba(140, 140, 140, 0.5);
}

/* btn 叫出視窗效果 */
.search-filter.showFilter {
  min-width: 320px;
  min-height: 36px;
  opacity: 1;
  visibility: visible;
}

/* 按下搜索 Btn 的方框 */
.search-filter {
  min-width: 0;
  min-height: 0;
  overflow: hidden;
  opacity: 0;
  visibility: hidden;
  background-color: #3450c1;
  position: absolute;
  border: 1px solid gray;
  padding: 0.5rem;
  right: 0;
  transition: all 0.75s ease;
}

.search-input {
  all: unset;
  display: block;
  border-bottom: 1px solid white;
  width: 100%;
  color: white;
  font-size: 1.25rem;
}

.search-input-icon {
  position: absolute;
  right: 0.5rem;
}

```













```
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Vite App</title>
    <link rel="stylesheet" href="style.css" />
  </head>
  <body>
    <div id="app">
      <div class="cardView header"></div>
    </div>
    <script type="module" src="/main.js"></script>
  </body>
</html>
```


```
.container {
  max-width: 1140px;
  padding-left: 16px;
  padding-right: 16px;
  margin-right: 8px;
  margin-left: 8px;
}

.cardView {
  display: flex;
  gap: 1.25rem;
  flex-wrap: wrap;
}

.card {
  cursor: pointer;
  max-width: 256px;
}

.list {
  max-height: 0;
  transform: scaleY(0);
  transform-origin: top;
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  overflow: hidden;
  border-left: 6px solid #662d8c;
  padding-left: 0.8rem;
  transition: all 0.15s ease-in;
}

.list-active {
  max-height: fit-content;
  transform: scaleY(100%);
}

.list li {
  list-style: none;
  font-size: 1.25rem;
  border-radius: 0.25rem;
  padding: 0.25rem 0.5rem;
  background-color: #ed1e79;
  color: white;
}

.btn {
  all: unset;
  color: white;
  font-weight: 700;
  font-size: 1.25rem;
  position: relative;
  background: transparent;
  padding: 0.5rem 1rem;
  border-radius: 0.15rem;
  box-shadow: 10px 10px 20px rgba(0, 0, 0, 0.2);
  border-radius: 0.25rem;
  background: linear-gradient(45deg, #662d8c, #ed1e79);
}

.btn:hover {
  animation: Animation 0.25s ease;
}


```


```
const data = [
  { root: 'root1', machExs: ['item1', 'item2'] },
  ,
  { root: 'root2', machExs: ['item1', 'item2'] },
  { root: 'root2', machExs: ['item1', 'item2'] },
  { root: 'root2', machExs: ['item1', 'item2'] },
  { root: 'root2', machExs: ['item1', 'item2'] },
  { root: 'root2', machExs: ['item1', 'item2'] },
  { root: 'root2', machExs: ['item1', 'item2'] },
  { root: 'root2', machExs: ['item1', 'item2'] },
  { root: 'root2', machExs: ['item1', 'item2'] },
  { root: 'root2', machExs: ['item1', 'item2'] },
  { root: 'root2', machExs: ['item1', 'item2'] },
  { root: 'root2', machExs: ['item1', 'item2'] },
  { root: 'root2', machExs: ['item1', 'item2'] },
  { root: 'root2', machExs: ['item1', 'item2'] },
  { root: 'root2', machExs: ['item1', 'item2'] },
  { root: 'root2', machExs: ['item1', 'item2'] },
];

function cardView(data) {
  const container = document?.querySelector('.cardView');
  if (!container) {
    throw Error('element class name:cardView, not found!');
  }

  data.forEach((cardData) => {
    const card = document.createElement('div');
    const btn = document.createElement('button');
    const list = document.createElement('ul');

    card.classList.add('card');
    btn.classList.add('btn');
    list.classList.add('list');

    btn.textContent = cardData?.root;
    btn.addEventListener('click', (e) => {
      const target = e.target.parentElement;
      const list = target.children[1];
      list.classList.toggle('list-active');
      target.classList.toggle('card-active');
    });

    cardData?.machExs.forEach((it) => {
      const listItem = document.createElement('li');
      const link = document.createElement('a');
      listItem.classList.add('item');
      link.classList.add('link');
      listItem.textContent = it;
      list.append(listItem);
    });

    card.append(btn, list);
    container.append(card);
  });
}

cardView(data);


```







windows 11 vb open IE


https://www.perplexity.ai/
https://github.com/jgraph/drawio-desktop/releases/tag/v24.6.1

```
const fs = require('node:fs');

const str = fs.readFileSync('./test.json', 'utf-8', (err) => console.log(err));
const data = JSON.parse(str);

console.log(data?.results[0].columns);

const TABLE_NAME = 'TABLE_NAME';
const columnDefine = data?.results[0].columns;
const dataItems = data?.results[0].items;

dataItems.forEach((it) => {
  //Number -> 不用單引號
  //DATE -> to_DATE();
  //VARCHAR2

  switch (key) {
    case 'DATE':
      break;
    case 'VARCHAR2':
      break;
    case 'NUMBER':
      break;
    default:
      console.error('請檢查JS欄位定義有缺少');
      break;
  }
});
```


IE11.vbs
```vb=
CreateObject("InternetExplorer.Application").Visible=true
```



```javascript=
        $(document).ready(function(){
            $("#openModal").click(function(){
                $("#myModal").modal({
                    backdrop: 'static',
                    keyboard: false
                });
            });
        });
```


```csharp=
ScriptManager.RegisterStartupScript(this, this.GetType(), "model", "window.addEventListener('load', function () {const modal = new bootstrap.Modal(document.getElementById('exampleModal'));modal.show();});", true);

```



```htmlembedded=
        <!-- Button trigger modal -->
        <asp:Button type="button" class="btn btn-primary"  Text="Model" runat="server"  OnClick="Unnamed3_Click"/>

        <!-- Modal -->
        <div class="modal fade" id="exampleModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
            <div class="modal-dialog modal-dialog-centered">
                <div class="modal-content">
                    <div class="modal-header">
                        <h5 class="modal-title" id="exampleModalLabel">Modal title</h5>
                        <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                            <span aria-hidden="true">&times;</span>
                        </button>
                    </div>
                    <div class="modal-body">
                              <asp:Button type="button" class="btn btn-primary" Text="Q" runat="server"/>
                    </div>
                    <div class="modal-footer">
                        <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
                        <button type="button" class="btn btn-primary">Save changes</button>
                    </div>
                </div>
            </div>
        </div>
```


https://blog.csdn.net/zhu_zhu_xia/article/details/132354488
![圖片](https://hackmd.io/_uploads/r1FBRogSA.png)

-------------------------------------------------
JavaScirpt Call C# using PageMethods (ajax)

要確定是否啟用 FriendlyUrlSetting()
RouteConfig.cs ->　看要沒有註解掉它
```csharp=
//routes.EnableFriendlyUrls(settings);
```

-------------------------------------------------
自動化工具筆記 Electron

https://electron-vite.org/guide/
https://tailwindcss.com/docs/installation/using-postcss
https://ui.shadcn.com/docs/installation/vite

-------------------------------------------
myOA -> Self Service -> 居家辦公SSLVPN -> 個人家用電腦

----------------------
## 表達式 目標範例
20240616140200>><S:XXXXXXX><C:XXXXXXXX-WXX> | XXXXXXXXXXX | MESAGE

## 一. 文字辨識
1. 辨認日期
2. Server name
3. Clinet 裝置名稱
4. Sequence(編碼)
5. 訊息
    - (Eazy)辨認時間: 取得數字為固定14碼時間
    ```
        \d{14}
    ```
    - (Eazy)辨認Server name
    ```
        (?<=<S:)[^>]+
    ```
    - (Eazy)辨認Client name  
    ```
        (?<=<C:)[^>]+
    ```
    - (Hard)辨認Sch: 字串前後為非英文及數字的6 或 9 長度字串

```javascript=
/*
 * 這個正則表達式解釋如下：
    (?<![a-zA-Z0-9]) 確保字串前不是英文或數字。
    (?=\w*[a-zA-Z]) 確保字串中至少包含一個字母。
    (?=\w*\d) 確保字串中至少包含一個數字。
    \w{6} 或 \w{9} 表示字串長度為6或9。
    (?![a-zA-Z0-9]) 確保字串後不是英文或數字。
 * 
 * */
const regex = /(?<![a-zA-Z0-9])(?=\w*[a-zA-Z])(?=\w*\d)\w{6}(?![a-zA-Z0-9])|(?<![a-zA-Z0-9])(?=\w*[a-zA-Z])(?=\w*\d)\w{9}(?![a-zA-Z0-9])/g;

```

## 二. 內部寄信
 1. nodemailer
```javascript=  
  const transporter = nodemailer.createTransport({
  host: "smtp.forwardemail.net",
  port: 465,
  secure: true,
  auth: {
    // TODO: replace `user` and `pass` values from 
    //<https://forwardemail.net>
    user: 'REPLACE-WITH-YOUR-ALIAS@YOURDOMAIN.COM',
    pass: 'REPLACE-WITH-YOUR-GENERATED-PASSWORD'
  }
});
```
## 三.Server 資料夾內文件讀寫流程
1. 複製檔案至新資料夾ServerLogBak
2. 建立JSON來讀取, 紀錄上次讀取
    - normal -> 依照日期時間排序 整理檔案
    - 中途關閉 -> 讀取紀錄為reading 的檔案, 砍掉再來一遍
```json=
[
    {
        fileName:'XXXXXX.log',
        createAt: '',
        status:'', // start, reading, end
    }
]
```

## 程式執行時間規則
1. 每次執行主程式紀錄起始時間
    - Case 1 程式執行完成後總結時間低於1小時, 等待一小時後重新執行
    - Case 2 執行程式超過等於1小時直接執行



## 環境變設置
1. 定時多長時間執行一次
2. config.env 若可以跨Server 建立一個做統整
3. 不行by server 放置15個

-----
瘋狂版
```javascript=
const fs = require("node:fs");
const readline = require("node:readline");

const fsWrite = fs.createWriteStream("output.txt");
const fileStream = fs.createReadStream(
  "C:\\Users\\s3394\\OneDrive\\桌面\\wirteText\\large_log_file.txt",
  {
    highWaterMark: 16 * 1024, // 16KB
  }
);

const rl = readline.createInterface({
  input: fileStream,
  crlfDelay: Infinity,
});

rl.on("line", (line) => {
  // console.log(`Received: ${line}`);
  fsWrite.write(`mod ${line}\n`);
});

rl.on("close", () => {
  console.log("File reading completed.");
});

```

CPU 等等版
```javascript=
const fs = require("node:fs");
const readline = require("node:readline");

const fsWrite = fs.createWriteStream("output.txt");
const fileStream = fs.createReadStream(
  "C:\\Users\\s3394\\OneDrive\\桌面\\wirteText\\large_log_file.txt",
  {
    highWaterMark: 16 * 1024, // 16KB
  }
);

const rl = readline.createInterface({
  input: fileStream,
  crlfDelay: Infinity,
});

rl.on("line", (line) => {
  rl.pause(); // 暫停接收新的行

  setTimeout(() => {
    const modifiedLine = `Modified: ${line}\n`;
    fsWrite.write(modifiedLine);
    rl.resume(); // 繼續接收新的行
  }, 10); // 增加延遲以減少 CPU 使用
});

rl.on("close", () => {
  console.log("File reading completed.");
});

```


```javascript=
const fs = require('fs');
const path = require('path');

const directoryPath = path.join(__dirname, 'your-directory-name');

fs.readdir(directoryPath, (err, files) => {
  if (err) {
    console.log('無法讀取目錄: ', err);
    return;
  }
  files.forEach(file => {
    console.log(file); // 這裡你可以獲取到檔案名，如果需要完整路徑可以使用 path.join(directoryPath, file)
  });
});
```

```javascript=
const fs = require("fs");
const path = require("path");

const directoryPath = "C:\\Users\\s3394\\OneDrive\\桌面\\wirteText";

try {
  const files = fs.readdirSync(directoryPath);
  files.forEach((item) => {
    console.log(item);
    fs.stat(path.join(directoryPath, item), (err, stats) => console.log(stats));
  });
} catch (err) {
  console.log("無法讀取目錄: ", err);
}


```


隨機產生LOG(不考慮中文做判斷), 做單元測試
```javascript=
const fs = require("node:fs");
const fsPromises = require("node:fs/promises");
const readline = require("node:readline");

//20240616140200>><S:XXXXXXX><C:XXXXXXXX-WXX> | XXXXXXXXXXX | MESAGE

//隨機文字
const CH = ["中1文", "中2文", "中3文"];
const ENG_UPPERCASE = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const ENG_LOWERERCASE = "abcdefghijklmnopqrstuvwxyz";

//隨機數字
const getRadomInt = (len) => Math.floor(Math.random() * len);

//隨機產生Sch
function generateRandomSch(len) {
  let result = "";
  for (let index of Array.from(Array(len).keys())) {
    result +=
      getRadomInt(2) > 0
        ? getRadomInt(10)
        : ENG_UPPERCASE[getRadomInt(ENG_UPPERCASE.length)];
  }
  return result;
}

//Time stemp
function generateTime() {
  const date = new Date();
  return (
    date.toLocaleDateString().split("/").join("") +
    date.toTimeString().split(" ")[0].split(":").join("") +
    "0"
  );
}

function generateTestLog() {
  const taskCount = getRadomInt(99);
  let msg = "";
  for (let index of Array.from(Array(taskCount).keys())) {
    getRadomInt(2) > 0
      ? (msg += ` ${generateRandomSch()} `)
      : (msg += `${ENG_UPPERCASE[getRadomInt(ENG_UPPERCASE.length)]}`);
  }
  return `${generateTime()}>><S:Server${getRadomInt(14)}><C:CLient${getRadomInt(
    17
  )}> | |${msg}`;
}

console.log(generateTestLog());
console.log(generateTestLog());

```


```javascript=
const fs = require('fs');
const path = require('path');

function generateRandomLogEntry() {
    const logLevels = ['INFO', 'WARN', 'ERROR', 'DEBUG'];
    const messages = [
        'User login successful',
        'User login failed',
        'Database connection established',
        'Database connection failed',
        'File not found',
        'File uploaded successfully',
        'Unauthorized access attempt',
        'User password changed',
    ];
    const timestamp = new Date().toISOString();
    const logLevel = logLevels[Math.floor(Math.random() * logLevels.length)];
    const message = messages[Math.floor(Math.random() * messages.length)];
    return `[${timestamp}] ${logLevel}: ${message}\n`;
}

function generateLargeTextFile(filePath, sizeInMB) {
    const sizeInBytes = sizeInMB * 1024 * 1024;
    let totalWritten = 0;

    const stream = fs.createWriteStream(filePath, { flags: 'w' });

    function writeChunk() {
        if (totalWritten < sizeInBytes) {
            let chunk = '';
            while (chunk.length < 1024 * 1024 && totalWritten + chunk.length < sizeInBytes) {
                chunk += generateRandomLogEntry();
            }
            stream.write(chunk, () => {
                totalWritten += chunk.length;
                console.log(`Written ${Math.round(totalWritten / (1024 * 1024))} MB...`);
                writeChunk();
            });
        } else {
            stream.end();
            console.log(`File ${filePath} generated with size ${Math.round(totalWritten / (1024 * 1024))} MB`);
        }
    }

    writeChunk();
}

const filePath = path.join(__dirname, 'large_log_file.txt');
const sizeInMB = 500;  // Set the size in MB

generateLargeTextFile(filePath, sizeInMB);

```

### 要求SRE 也使用 C# 轉譯版本

```csharp=
using System;
using System.IO;
using System.Threading.Tasks;

class Program
{
    static async Task Main(string[] args)
    {
        string inputFilePath = @"C:\Users\s3394\OneDrive\桌面\wirteText\large_log_file.txt";
        string outputFilePath = "output.txt";

        using (var fsRead = new FileStream(inputFilePath, FileMode.Open, FileAccess.Read, FileShare.Read, 16 * 1024, FileOptions.SequentialScan))
        using (var fsWrite = new StreamWriter(outputFilePath))
        using (var sr = new StreamReader(fsRead))
        {
            string line;
            while ((line = await sr.ReadLineAsync()) != null)
            {
                await Task.Delay(10); // 增加延遲以減少 CPU 使用
                string modifiedLine = $"Modified: {line}";
                await fsWrite.WriteLineAsync(modifiedLine);
            }
        }

        Console.WriteLine("File reading completed.");
    }
}
```