備忘錄_20160105(定位) 修改 回首頁

程式 2025-08-30 00:19:25 1756484365 100
javascript 與 python 搭配,讀取儲存檔案

javascript 與 python 搭配,讀取儲存檔案

<!doctype html>
<html lang="zh-Hant-TW">
  <head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8">
    <title>與 python 搭配</title>
    <style>
#divResult
{
  word-wrap: break-word;  /* 遇到長單字或 URL 也會換行 */
  word-break: break-word; /* 舊語法,兼容性好 */
  white-space: pre-wrap; /* 保留空格與換行,遇到容器寬度自動換行 */
}

button, span
{
  display: inline;
}
    </style>
  </head>
  <body>
    <div>
      <button type="button" onclick="saveTextAsFile('main.py', atob_utf8(strBase64Crlf));">另存 main.py (crlf)</button>
      <button type="button" onclick="saveTextAsFile('main.py', atob_utf8(strBase64Lf));">另存 main.py (lf)</button>
      <span>python main.py</span>
      <button type="button" onclick="exit();">關閉 main.py 程式</button>
      &nbsp;&nbsp;
      <button type="button" onclick="readfile();">讀取檔案</button>
      <button type="button" onclick="savefile();">儲存檔案</button>
      <button type="button" onclick="saveasnewfile();">另存新檔</button>
      <br>
      <div id="divFilename"></div>
      <textarea id="ta1" rows="20" cols="160"></textarea>
      <div id="divResult"></div>
    </div>
    <script>
function gebi(strId)
{
  return document.getElementById(strId);
}

async function exit()
{
  var strUrl="http://127.0.0.1:16384/action/";
  var oInputData={ "strAction": "exit" };
  
  try 
  {
    var oResponse=await fetch(
      strUrl, 
      {
        method: "POST",
        headers: {"Content-Type": "application/json"},
        body: JSON.stringify(oInputData)
      }
    );
  }
  catch(oErr)
  {
    console.error("發送失敗:", oErr);
  }
}

function atob_utf8(strBase64)
{
  var binaryString=window.atob(strBase64);
  
  // 將每個字元的 charCode 轉成 byte array
  var ba1 = Uint8Array.from(binaryString, oCharacterCode => oCharacterCode.charCodeAt(0));
  // 用 TextDecoder 轉 UTF-8 字串
  var oDecoder = new TextDecoder("utf-8");
  return oDecoder.decode(ba1);
}

async function readfile()
{
  var strUrl="http://127.0.0.1:16384/action/";
  var oInputData={ "strAction": "readfile" };
  
  try 
  {
    var oResponse=await fetch(
      strUrl, 
      {
        method: "POST",
        headers: {"Content-Type": "application/json"},
        body: JSON.stringify(oInputData)
      }
    );

    var oResult=await oResponse.json();
    if(oResult.strError!="")
    {
      gebi('divResult').textContent=JSON.stringify(oResult);
    }
    else
    {
      var strContent=atob_utf8(oResult.strBase64);
      gebi('divFilename').textContent=oResult.strFilename;
      gebi('ta1').value=strContent
    }
  }
  catch(oErr)
  {
    alert("發送失敗:"+oErr);
    console.error("發送失敗:", oErr);
  }
}

async function savefile()
{
  var strFilename=gebi('divFilename').textContent.trim();
  if(strFilename=='')
  {
    alert('抱歉,沒有先讀取檔案(沒有舊的檔案名稱與路徑),不能直接存檔喔!');
    return;
  }
  
  var strUrl="http://127.0.0.1:16384/action/";
  var oInputData={ "strAction": "savefile", "strFilename": gebi('divFilename').textContent, "strContent": gebi('ta1').value };
  
  try 
  {
    var oResponse=await fetch(
      strUrl, 
      {
        method: "POST",
        headers: {"Content-Type": "application/json"},
        body: JSON.stringify(oInputData)
      }
    );

    var oResult=await oResponse.json();
    if(oResult.strError!="")
    {
      gebi('divResult').textContent=JSON.stringify(oResult);
    }
    else
    {
      alert("存檔成功!");
    }
  }
  catch(oErr)
  {
    alert("發送失敗:"+oErr);
    console.error("發送失敗:", oErr);
  }
}

async function saveasnewfile()
{
  var strUrl="http://127.0.0.1:16384/action/";
  var oInputData={ "strAction": "saveasnewfile", "strContent": gebi('ta1').value };
  
  try 
  {
    var oResponse=await fetch(
      strUrl, 
      {
        method: "POST",
        headers: {"Content-Type": "application/json"},
        body: JSON.stringify(oInputData)
      }
    );

    var oResult=await oResponse.json();
    if(oResult.strError!="")
    {
      gebi('divResult').textContent=JSON.stringify(oResult);
    }
    else
    {
      gebi('divFilename').textContent=oResult['strFilename'];
      alert("另存新檔成功!");
    }
  }
  catch(oErr)
  {
    alert("發送失敗:"+oErr);
    console.error("發送失敗:", oErr);
  }
}

    </script>
    <script>
var strBase64Lf="IyBwaXAgaW5zdGFsbCBmYXN0YXBpIHV2aWNvcm4KIyAod3JpdGUgdGhpcyBwcm9ncmFtOm1haW4ucHkpCgojIOWft+ihjOeoi+W8jwojIHB5dGhvbiBtYWluLnB5CgojIOiugOWPluaqlOahiAojIGN1cmwgLVggUE9TVCBodHRwOi8vMTI3LjAuMC4xOjE2Mzg0L2FjdGlvbi8gLUggIkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24vanNvbiIgLWQgIntcInN0ckFjdGlvblwiOlwicmVhZGZpbGVcIn0iCiMg5aSx5pWX5Zue5YKzIHsgInN0ckVycm9yIjoiLi4uLi4uIiB9CiMg5oiQ5Yqf5Zue5YKzIHsgInN0ckVycm9yIjoiIiwgInN0ckJhc2U2NCI6Ii4uLi4uLiIgfQoKIyDpm6LplovnqIvlvI8KIyBjdXJsIC1YIFBPU1QgaHR0cDovLzEyNy4wLjAuMToxNjM4NC9hY3Rpb24vIC1IICJDb250ZW50LVR5cGU6IGFwcGxpY2F0aW9uL2pzb24iIC1kICJ7XCJzdHJBY3Rpb25cIjpcImV4aXRcIn0iCgppbXBvcnQgc3lzCgppbXBvcnQgdGhyZWFkaW5nCmltcG9ydCBxdWV1ZQoKaW1wb3J0IHRraW50ZXIgYXMgdGsKaW1wb3J0IHRraW50ZXIuZmlsZWRpYWxvZyBhcyBmaWxlZGlhbG9nCmltcG9ydCBiYXNlNjQKCmltcG9ydCB1dmljb3JuCmZyb20gZmFzdGFwaSBpbXBvcnQgRmFzdEFQSSwgUmVxdWVzdApmcm9tIGZhc3RhcGkucmVzcG9uc2VzIGltcG9ydCBKU09OUmVzcG9uc2UKZnJvbSBmYXN0YXBpLm1pZGRsZXdhcmUuY29ycyBpbXBvcnQgQ09SU01pZGRsZXdhcmUKCm9BcHAgPSBGYXN0QVBJKCkKb1F1ZXVlSW49cXVldWUuUXVldWUoKQpvUXVldWVPdXQ9cXVldWUuUXVldWUoKQoKCgoKb0FwcC5hZGRfbWlkZGxld2FyZSgKICAgIENPUlNNaWRkbGV3YXJlLAogICAgYWxsb3dfb3JpZ2lucz1bIioiXSwgICMg5oiWIFsiaHR0cDovL2xvY2FsaG9zdDozMDAwIl0KICAgIGFsbG93X2NyZWRlbnRpYWxzPVRydWUsCiAgICBhbGxvd19tZXRob2RzPVsiKiJdLAogICAgYWxsb3dfaGVhZGVycz1bIioiXSwKKQoKQG9BcHAucG9zdCgiL2FjdGlvbi8iKQphc3luYyBkZWYgZnVuY0FjdGlvbihvUmVxdWVzdDogUmVxdWVzdCk6CiAgCiAgdHJ5OgogICAgb0lucHV0RGF0YSA9IGF3YWl0IG9SZXF1ZXN0Lmpzb24oKQogIGV4Y2VwdCBFeGNlcHRpb246CiAgICByZXR1cm4gSlNPTlJlc3BvbnNlKGNvbnRlbnQ9eyJzdHJFcnJvciI6ICJpbnZhbGlkIGpzb24ifSwgc3RhdHVzX2NvZGU9NDAwKQogIAogIG9RdWV1ZUluLnB1dChvSW5wdXREYXRhKQogIHJldHVybiBvUXVldWVPdXQuZ2V0KCkKCmRlZiBydW5faHR0cF9zZXJ2ZXIoKToKICBvQ29uZmlnPXV2aWNvcm4uQ29uZmlnKG9BcHAsIGhvc3Q9IjEyNy4wLjAuMSIsIHBvcnQ9MTYzODQsIGxvZ19sZXZlbD0iaW5mbyIpCiAgb1NlcnZlcj11dmljb3JuLlNlcnZlcihvQ29uZmlnKQogIG9TZXJ2ZXIucnVuKCkKCgoKCmRlZiBydW5fdGtpbnRlcl90aHJlYWQoKToKICBvV2luZG93PXRrLlRrKCkKICBvV2luZG93LndpdGhkcmF3KCkgIyDkuI3poa/npLrkuLvoppbnqpcKICAKICB3aGlsZSBUcnVlOgogICAgCiAgICBvSW5wdXREYXRhPW9RdWV1ZUluLmdldCgpCiAgICAKICAgIHN0ckFjdGlvbj0iIgogICAgaWYgInN0ckFjdGlvbiIgaW4gb0lucHV0RGF0YToKICAgICAgc3RyQWN0aW9uPW9JbnB1dERhdGFbInN0ckFjdGlvbiJdCiAgICAKICAgIGlmIHN0ckFjdGlvbj09ImV4aXQiOgogICAgICBicmVhawogICAgZWxpZiBzdHJBY3Rpb249PSJyZWFkZmlsZSI6CiAgICAgIG9XaW5kb3cuYXR0cmlidXRlcygnLXRvcG1vc3QnLCBUcnVlKQogICAgICBvV2luZG93LmZvY3VzX2ZvcmNlKCkKICAgICAgc3RyRmlsZW5hbWU9ZmlsZWRpYWxvZy5hc2tvcGVuZmlsZW5hbWUodGl0bGU9J+mWi+WVn+iIiuaqlCcpCiAgICAgIG9XaW5kb3cuYXR0cmlidXRlcygnLXRvcG1vc3QnLCBGYWxzZSkKICAgICAgaWYgc3RyRmlsZW5hbWU9PSIiOgogICAgICAgIG9RdWV1ZU91dC5wdXQoeyJzdHJFcnJvciI6IuS9v+eUqOiAheWPlua2iOiugOWPluaqlOahiCJ9KQogICAgICBlbHNlOgogICAgICAgIG9GaWxlPW9wZW4oc3RyRmlsZW5hbWUsICdyYicpCiAgICAgICAgc3RyQmFzZTY0PWJhc2U2NC5iNjRlbmNvZGUob0ZpbGUucmVhZCgpKS5kZWNvZGUoInV0Zi04IikKICAgICAgICBvRmlsZS5jbG9zZSgpCiAgICAgICAgb1F1ZXVlT3V0LnB1dCh7InN0ckVycm9yIjoiIiwic3RyRmlsZW5hbWUiOnN0ckZpbGVuYW1lLCJzdHJCYXNlNjQiOnN0ckJhc2U2NH0pCiAgICBlbGlmIHN0ckFjdGlvbj09InNhdmVmaWxlIjoKICAgICAgc3RyRmlsZW5hbWU9b0lucHV0RGF0YVsic3RyRmlsZW5hbWUiXQogICAgICBvRmlsZT1vcGVuKHN0ckZpbGVuYW1lLCAndycsIGVuY29kaW5nPSd1dGYtOCcpCiAgICAgIG9GaWxlLndyaXRlKG9JbnB1dERhdGFbInN0ckNvbnRlbnQiXSkKICAgICAgb0ZpbGUuY2xvc2UoKQogICAgICBvUXVldWVPdXQucHV0KHsic3RyRXJyb3IiOiIiLCAic3RyRmlsZW5hbWUiOnN0ckZpbGVuYW1lfSkKICAgIGVsaWYgc3RyQWN0aW9uPT0ic2F2ZWFzbmV3ZmlsZSI6CiAgICAgIHN0ckZpbGVuYW1lPWZpbGVkaWFsb2cuYXNrc2F2ZWFzZmlsZW5hbWUodGl0bGU9IuWPpuWtmOaWsOaqlCIsIGRlZmF1bHRleHRlbnNpb249Ii50eHQiLCBmaWxldHlwZXM9Wygi5paH5a2X5qqUIiwgIioudHh0IiksICgi5omA5pyJ5qqU5qGIIiwgIiouKiIpXSkKICAgICAgaWYgc3RyRmlsZW5hbWU9PSIiOgogICAgICAgIG9RdWV1ZU91dC5wdXQoeyJzdHJFcnJvciI6IuS9v+eUqOiAheWPlua2iOWPpuWtmOaWsOaqlCJ9KQogICAgICBlbHNlOgogICAgICAgIG9GaWxlPW9wZW4oc3RyRmlsZW5hbWUsICd3JywgZW5jb2Rpbmc9J3V0Zi04JykKICAgICAgICBvRmlsZS53cml0ZShvSW5wdXREYXRhWyJzdHJDb250ZW50Il0pCiAgICAgICAgb0ZpbGUuY2xvc2UoKQogICAgICAgIG9RdWV1ZU91dC5wdXQoeyJzdHJFcnJvciI6IiIsICJzdHJGaWxlbmFtZSI6c3RyRmlsZW5hbWV9KQogICAgZWxzZToKICAgICAgb1F1ZXVlT3V0LnB1dCh7InN0ckVycm9yIjoi5LiN5pSv5o+055qE5oyH5LukLSIrc3RyKG9JbnB1dERhdGEpfSkKICAKICBzeXMuZXhpdCgwKQoKCgoKdGtpbnRlcl90aHJlYWQ9dGhyZWFkaW5nLlRocmVhZCh0YXJnZXQ9cnVuX3RraW50ZXJfdGhyZWFkLCBkYWVtb249VHJ1ZSkKdGtpbnRlcl90aHJlYWQuc3RhcnQoKQoKaHR0cF9zZXJ2ZXJfdGhyZWFkPXRocmVhZGluZy5UaHJlYWQodGFyZ2V0PXJ1bl9odHRwX3NlcnZlciwgZGFlbW9uPVRydWUpCmh0dHBfc2VydmVyX3RocmVhZC5zdGFydCgpCgp0a2ludGVyX3RocmVhZC5qb2luKCkK";
var strBase64Crlf="IyBwaXAgaW5zdGFsbCBmYXN0YXBpIHV2aWNvcm4NCiMgKHdyaXRlIHRoaXMgcHJvZ3JhbTptYWluLnB5KQ0KDQojIOWft+ihjOeoi+W8jw0KIyBweXRob24gbWFpbi5weQ0KDQojIOiugOWPluaqlOahiA0KIyBjdXJsIC1YIFBPU1QgaHR0cDovLzEyNy4wLjAuMToxNjM4NC9hY3Rpb24vIC1IICJDb250ZW50LVR5cGU6IGFwcGxpY2F0aW9uL2pzb24iIC1kICJ7XCJzdHJBY3Rpb25cIjpcInJlYWRmaWxlXCJ9Ig0KIyDlpLHmlZflm57lgrMgeyAic3RyRXJyb3IiOiIuLi4uLi4iIH0NCiMg5oiQ5Yqf5Zue5YKzIHsgInN0ckVycm9yIjoiIiwgInN0ckJhc2U2NCI6Ii4uLi4uLiIgfQ0KDQojIOmboumWi+eoi+W8jw0KIyBjdXJsIC1YIFBPU1QgaHR0cDovLzEyNy4wLjAuMToxNjM4NC9hY3Rpb24vIC1IICJDb250ZW50LVR5cGU6IGFwcGxpY2F0aW9uL2pzb24iIC1kICJ7XCJzdHJBY3Rpb25cIjpcImV4aXRcIn0iDQoNCmltcG9ydCBzeXMNCg0KaW1wb3J0IHRocmVhZGluZw0KaW1wb3J0IHF1ZXVlDQoNCmltcG9ydCB0a2ludGVyIGFzIHRrDQppbXBvcnQgdGtpbnRlci5maWxlZGlhbG9nIGFzIGZpbGVkaWFsb2cNCmltcG9ydCBiYXNlNjQNCg0KaW1wb3J0IHV2aWNvcm4NCmZyb20gZmFzdGFwaSBpbXBvcnQgRmFzdEFQSSwgUmVxdWVzdA0KZnJvbSBmYXN0YXBpLnJlc3BvbnNlcyBpbXBvcnQgSlNPTlJlc3BvbnNlDQpmcm9tIGZhc3RhcGkubWlkZGxld2FyZS5jb3JzIGltcG9ydCBDT1JTTWlkZGxld2FyZQ0KDQpvQXBwID0gRmFzdEFQSSgpDQpvUXVldWVJbj1xdWV1ZS5RdWV1ZSgpDQpvUXVldWVPdXQ9cXVldWUuUXVldWUoKQ0KDQoNCg0KDQpvQXBwLmFkZF9taWRkbGV3YXJlKA0KICAgIENPUlNNaWRkbGV3YXJlLA0KICAgIGFsbG93X29yaWdpbnM9WyIqIl0sICAjIOaIliBbImh0dHA6Ly9sb2NhbGhvc3Q6MzAwMCJdDQogICAgYWxsb3dfY3JlZGVudGlhbHM9VHJ1ZSwNCiAgICBhbGxvd19tZXRob2RzPVsiKiJdLA0KICAgIGFsbG93X2hlYWRlcnM9WyIqIl0sDQopDQoNCkBvQXBwLnBvc3QoIi9hY3Rpb24vIikNCmFzeW5jIGRlZiBmdW5jQWN0aW9uKG9SZXF1ZXN0OiBSZXF1ZXN0KToNCiAgDQogIHRyeToNCiAgICBvSW5wdXREYXRhID0gYXdhaXQgb1JlcXVlc3QuanNvbigpDQogIGV4Y2VwdCBFeGNlcHRpb246DQogICAgcmV0dXJuIEpTT05SZXNwb25zZShjb250ZW50PXsic3RyRXJyb3IiOiAiaW52YWxpZCBqc29uIn0sIHN0YXR1c19jb2RlPTQwMCkNCiAgDQogIG9RdWV1ZUluLnB1dChvSW5wdXREYXRhKQ0KICByZXR1cm4gb1F1ZXVlT3V0LmdldCgpDQoNCmRlZiBydW5faHR0cF9zZXJ2ZXIoKToNCiAgb0NvbmZpZz11dmljb3JuLkNvbmZpZyhvQXBwLCBob3N0PSIxMjcuMC4wLjEiLCBwb3J0PTE2Mzg0LCBsb2dfbGV2ZWw9ImluZm8iKQ0KICBvU2VydmVyPXV2aWNvcm4uU2VydmVyKG9Db25maWcpDQogIG9TZXJ2ZXIucnVuKCkNCg0KDQoNCg0KZGVmIHJ1bl90a2ludGVyX3RocmVhZCgpOg0KICBvV2luZG93PXRrLlRrKCkNCiAgb1dpbmRvdy53aXRoZHJhdygpICMg5LiN6aGv56S65Li76KaW56qXDQogIA0KICB3aGlsZSBUcnVlOg0KICAgIA0KICAgIG9JbnB1dERhdGE9b1F1ZXVlSW4uZ2V0KCkNCiAgICANCiAgICBzdHJBY3Rpb249IiINCiAgICBpZiAic3RyQWN0aW9uIiBpbiBvSW5wdXREYXRhOg0KICAgICAgc3RyQWN0aW9uPW9JbnB1dERhdGFbInN0ckFjdGlvbiJdDQogICAgDQogICAgaWYgc3RyQWN0aW9uPT0iZXhpdCI6DQogICAgICBicmVhaw0KICAgIGVsaWYgc3RyQWN0aW9uPT0icmVhZGZpbGUiOg0KICAgICAgb1dpbmRvdy5hdHRyaWJ1dGVzKCctdG9wbW9zdCcsIFRydWUpDQogICAgICBvV2luZG93LmZvY3VzX2ZvcmNlKCkNCiAgICAgIHN0ckZpbGVuYW1lPWZpbGVkaWFsb2cuYXNrb3BlbmZpbGVuYW1lKHRpdGxlPSfplovllZ/oiIrmqpQnKQ0KICAgICAgb1dpbmRvdy5hdHRyaWJ1dGVzKCctdG9wbW9zdCcsIEZhbHNlKQ0KICAgICAgaWYgc3RyRmlsZW5hbWU9PSIiOg0KICAgICAgICBvUXVldWVPdXQucHV0KHsic3RyRXJyb3IiOiLkvb/nlKjogIXlj5bmtojoroDlj5bmqpTmoYgifSkNCiAgICAgIGVsc2U6DQogICAgICAgIG9GaWxlPW9wZW4oc3RyRmlsZW5hbWUsICdyYicpDQogICAgICAgIHN0ckJhc2U2ND1iYXNlNjQuYjY0ZW5jb2RlKG9GaWxlLnJlYWQoKSkuZGVjb2RlKCJ1dGYtOCIpDQogICAgICAgIG9GaWxlLmNsb3NlKCkNCiAgICAgICAgb1F1ZXVlT3V0LnB1dCh7InN0ckVycm9yIjoiIiwic3RyRmlsZW5hbWUiOnN0ckZpbGVuYW1lLCJzdHJCYXNlNjQiOnN0ckJhc2U2NH0pDQogICAgZWxpZiBzdHJBY3Rpb249PSJzYXZlZmlsZSI6DQogICAgICBzdHJGaWxlbmFtZT1vSW5wdXREYXRhWyJzdHJGaWxlbmFtZSJdDQogICAgICBvRmlsZT1vcGVuKHN0ckZpbGVuYW1lLCAndycsIGVuY29kaW5nPSd1dGYtOCcpDQogICAgICBvRmlsZS53cml0ZShvSW5wdXREYXRhWyJzdHJDb250ZW50Il0pDQogICAgICBvRmlsZS5jbG9zZSgpDQogICAgICBvUXVldWVPdXQucHV0KHsic3RyRXJyb3IiOiIiLCAic3RyRmlsZW5hbWUiOnN0ckZpbGVuYW1lfSkNCiAgICBlbGlmIHN0ckFjdGlvbj09InNhdmVhc25ld2ZpbGUiOg0KICAgICAgc3RyRmlsZW5hbWU9ZmlsZWRpYWxvZy5hc2tzYXZlYXNmaWxlbmFtZSh0aXRsZT0i5Y+m5a2Y5paw5qqUIiwgZGVmYXVsdGV4dGVuc2lvbj0iLnR4dCIsIGZpbGV0eXBlcz1bKCLmloflrZfmqpQiLCAiKi50eHQiKSwgKCLmiYDmnInmqpTmoYgiLCAiKi4qIildKQ0KICAgICAgaWYgc3RyRmlsZW5hbWU9PSIiOg0KICAgICAgICBvUXVldWVPdXQucHV0KHsic3RyRXJyb3IiOiLkvb/nlKjogIXlj5bmtojlj6blrZjmlrDmqpQifSkNCiAgICAgIGVsc2U6DQogICAgICAgIG9GaWxlPW9wZW4oc3RyRmlsZW5hbWUsICd3JywgZW5jb2Rpbmc9J3V0Zi04JykNCiAgICAgICAgb0ZpbGUud3JpdGUob0lucHV0RGF0YVsic3RyQ29udGVudCJdKQ0KICAgICAgICBvRmlsZS5jbG9zZSgpDQogICAgICAgIG9RdWV1ZU91dC5wdXQoeyJzdHJFcnJvciI6IiIsICJzdHJGaWxlbmFtZSI6c3RyRmlsZW5hbWV9KQ0KICAgIGVsc2U6DQogICAgICBvUXVldWVPdXQucHV0KHsic3RyRXJyb3IiOiLkuI3mlK/mj7TnmoTmjIfku6QtIitzdHIob0lucHV0RGF0YSl9KQ0KICANCiAgc3lzLmV4aXQoMCkNCg0KDQoNCg0KdGtpbnRlcl90aHJlYWQ9dGhyZWFkaW5nLlRocmVhZCh0YXJnZXQ9cnVuX3RraW50ZXJfdGhyZWFkLCBkYWVtb249VHJ1ZSkNCnRraW50ZXJfdGhyZWFkLnN0YXJ0KCkNCg0KaHR0cF9zZXJ2ZXJfdGhyZWFkPXRocmVhZGluZy5UaHJlYWQodGFyZ2V0PXJ1bl9odHRwX3NlcnZlciwgZGFlbW9uPVRydWUpDQpodHRwX3NlcnZlcl90aHJlYWQuc3RhcnQoKQ0KDQp0a2ludGVyX3RocmVhZC5qb2luKCkNCg==";

function saveTextAsFile(strFilename, strContent)
{
  // 建立 Blob 物件
  var oBlob=new Blob([strContent], { type: "text/plain;charset=utf-8" });
  
  // 建立臨時 URL
  const oUrl=URL.createObjectURL(oBlob);
  
  // 建立 a 標籤下載
  const oAnchor=document.createElement("a");
  oAnchor.href=oUrl;
  oAnchor.download=strFilename;
  document.body.appendChild(oAnchor); // 必須加到 DOM 才能觸發點擊
  oAnchor.click();                    // 模擬點擊
  document.body.removeChild(oAnchor); // 移除標籤
  
  // 釋放 URL
  URL.revokeObjectURL(oUrl);
}
    </script>
  </body>
</html>