EST. 2026 — บันทึกงานเซิร์ฟเวอร์จริง SYSADMIN · SECURITY · AI · DIRECTADMIN เล่มที่ 01
THE SYSADMIN ALMANAC
หน้าหลัก / Hardware / API ตอบ notSupport 9 แบบ แต่หน้าเว็บเครื่องลบได้ ดัก HAR หาคำสั่งจริง
Hardware

API ตอบ notSupport 9 แบบ แต่หน้าเว็บเครื่องลบได้ ดัก HAR หาคำสั่งจริง

โดย Ton-Or ·11 พ.ย. 2026·อ่าน 11 นาที
API ตอบ notSupport 9 แบบ แต่หน้าเว็บเครื่องลบได้ ดัก HAR หาคำสั่งจริง

ถ้าปุ่มในหน้าเว็บของอุปกรณ์ทำสิ่งหนึ่งได้ แปลว่ามีคำขอ HTTP ที่ทำสิ่งนั้นได้อยู่จริง เอกสารจะเขียนไว้หรือไม่ก็ตาม หน้าที่ของเราคือเลิกเดาแล้วไปดูว่าเบราว์เซอร์ส่งอะไรออกไป

สรุปใน 1 นาที

อาการ/ปัญหา
API ตามเอกสารลบรูปใบหน้าไม่ได้ 9 แบบ แต่ปุ่มในหน้าเว็บของเครื่องลบได้
ใครควรอ่าน
คนที่ต้องคุมอุปกรณ์ผ่าน API แต่เอกสารไม่ครบ
ทางแก้แบบสั้น
เปิด DevTools ดัก HAR ตอนกดปุ่มในหน้าเว็บ แล้วยิงคำขอเดียวกันซ้ำเอง สำรองพร้อม md5 ก่อนลบจริงทีละคน
ข้ามไปขั้นตอน

พอดีผมเคยสรุปไว้ในบทความ ลบใบหน้าในเครื่องสแกนไม่ได้ เพราะ API ตอบ notSupport ว่าเครื่องตระกูลนี้ลบใบหน้าเดี่ยว ๆ ไม่ได้ ให้ปิดสิทธิ์แทน ข้อสรุปนั้นผิดครับ ปิดสิทธิ์ยังเป็นวิธีที่ถูกสำหรับโจทย์กันคนเข้าประตู แต่ประโยคที่ว่าลบรูปไม่ได้นั้นไม่จริง รอบนี้เจ้าของงานสั่งมาตรง ๆ ว่าให้ลบรูปใบหน้าของคนที่ออกจากงานแล้วออกจากเครื่อง โดยห้ามลบชื่อหรือผู้ใช้ ผมยิง API ไป 9 รูปแบบ ไม่ผ่านสักแบบ และพลาดลบผู้ใช้ไปจริง ๆ ก่อนจะเจอว่าคำตอบอยู่ในหน้าเว็บของเครื่องเองตั้งแต่แรก

เลข IP รหัสพนักงาน ชื่อตาราง และชื่อฐานข้อมูลในบทความเป็นค่าตัวอย่าง ส่วน endpoint โครง JSON รหัสตอบกลับ และตัวเลขผลลัพธ์เป็นของจริง

โจทย์ และข้อห้ามที่ทำให้ทางง่ายใช้ไม่ได้

เครื่องสแกนมีเครื่องเดียว พื้นที่เก็บใบหน้ามีจำกัด และรูปของคนเก่าที่ค้างอยู่ทำให้เครื่องสแกนติดผิดคน เจ้าของงานเลยอยากเอารูปของคนที่ออกแล้วออกไป เงื่อนไขมีสี่ข้อ คือคนที่ยังทำงานอยู่กับบัญชีผู้ดูแลไม่แตะ ห้ามลบชื่อหรือระเบียนผู้ใช้เพราะประวัติสแกนเก่าต้องยังอ่านออกว่าเป็นใคร ให้สำรองรูปลงฐานข้อมูลก่อนลบ และ "ทำแค่ที่บอก สรุปก่อนว่าต้องทำอะไร"

ตัวเลขตั้งต้นคือในเครื่องมีผู้ใช้ 142 ระเบียน ฐานข้อมูลทะเบียนคนมี 137 คน เป็นคนที่ยังทำงาน 54 คน ออกแล้ว 83 คน ส่วนต่าง 5 ระเบียนคือบัญชีทดสอบกับบัญชีผู้ดูแลที่มีอยู่แต่ในเครื่อง กลุ่มนี้ผมไม่แตะจนกว่าจะมีคนยืนยัน รายชื่อที่จะลบรูปได้จากการเอาคนที่สถานะไม่ active ในทะเบียน มาตัดกับรายการรูปที่มีอยู่จริงในเครื่อง ไม่เดาจากชื่อ

เครื่องของเราเอง และข้อมูลใบหน้าคือข้อมูลอ่อนไหว

ทุกอย่างในบทความนี้ทำกับเครื่องควบคุมการเข้าออกที่อยู่ในความดูแล ด้วยบัญชีผู้ดูแลที่ได้รับมอบมาพร้อมงาน และตามคำสั่งของเจ้าของระบบ รูปใบหน้าที่สำรองออกมาเป็นข้อมูลชีวมิติของคน ต้องเก็บในที่ที่จำกัดสิทธิ์เข้าถึง ไม่ส่งต่อ ไม่เอาไปใช้อย่างอื่น การเอาวิธีนี้ไปใช้กับเครื่องที่ไม่ใช่ของตัวเองเป็นความผิดตามกฎหมาย

ทางตัน 9 แบบ และการลบที่ผิดตัว

ผมเริ่มจากเอกสารของตระกูลอุปกรณ์เหมือนรอบก่อน คลังใบหน้าอยู่ใต้ FDLib เลยไล่ยิงคำสั่งที่ชื่อบอกว่าเป็นการลบทุกตัวที่หาได้ รวมแล้ว 9 รูปแบบ สรุปเป็นกลุ่มได้แบบนี้

คำขอ สิ่งที่ลอง ผล
/ISAPI/Intelligent/FDLib/FDSetUp/Delete POST และ PUT, body เป็น JSON สองแบบ และ XML notSupport
/ISAPI/Intelligent/FDLib/FDSearch/Delete ส่ง FPID ของคนที่จะลบ badJsonContent: FPID
/ISAPI/Intelligent/FDLib/FDSearch method DELETE และ POST แบบลบ methodNotAllowed
/ISAPI/AccessControl/UserInfo/Count จะนับผู้ใช้ไว้เทียบก่อนหลัง methodNotAllowed
/ISAPI/AccessControl/UserInfoDetail/Delete mode byEmployeeNo สำเร็จ แต่ลบทั้งผู้ใช้

แถวสุดท้ายคือจุดที่ผมพลาด คำสั่งเดียวที่เครื่องยอมทำคือลบระเบียนผู้ใช้ทั้งระเบียน ซึ่งพารูปไปด้วย ผมเลยคิดทางอ้อมว่า ลบผู้ใช้แล้วสร้างชื่อคืนทันที ผลสุดท้ายก็ได้ผู้ใช้ที่ไม่มีรูปเหมือนกัน แล้วลงมือกับ 2 คน เจ้าของงานสั่งหยุดทันทีว่า "ไม่ลบ user" ซึ่งเขาพูดไว้แล้วตั้งแต่ต้น รวมกับที่ทดสอบก่อนหน้านั้นมีคนที่โดนผลจากการทดลองของผม 3 คน ต้องสร้างชื่อคืนและปิด Valid.enable ไว้ชั่วคราวระหว่างรอทางที่ถูก

ทางอ้อมที่ให้ผลลัพธ์เหมือนกัน ไม่ได้แปลว่าทำได้

ข้อห้ามของเจ้าของงานคือห้ามลบผู้ใช้ ไม่ใช่ "ผลสุดท้ายต้องมีผู้ใช้อยู่" การลบแล้วสร้างคืนเปลี่ยนตัวระเบียน และมีช่วงเวลาที่ระเบียนไม่มีอยู่จริง ถ้าสคริปต์ล้มกลางทางคือชื่อหาย ข้อห้ามที่ได้รับมาต้องอ่านตามตัวอักษร ไม่ตีความเอาเองให้เข้ากับคำสั่งที่บังเอิญใช้ได้

สองเรื่องที่ทำให้นับผิด ก่อนจะไปถึงทางออก

ระหว่างทางมีความเข้าใจผิดอีกสองเรื่องที่เกือบทำให้ตัดสินใจผิดซ้ำ

เรื่องแรก ผมเปิดหน้าเว็บของเครื่องด้วยสคริปต์ขับเบราว์เซอร์เพื่อดูรายชื่อ หน้าจอขึ้นว่า "No user information is found" และ Total เป็น 1 ดูเหมือนข้อมูลในเครื่องหายไปเกือบหมด ความจริงคือหน้านั้นโหลดไม่เสร็จ และพอร์ต debug ของเบราว์เซอร์ที่ใช้ขับไปชนกับงานอื่นที่รันอยู่ พอยิง API ตรงไปที่เครื่อง ผู้ใช้ยังอยู่ครบ 142 ระเบียน บทเรียนคืออย่าใช้ภาพจากหน้าเว็บที่ขับด้วยสคริปต์เป็นหลักฐานว่าข้อมูลหาย ให้ถาม API ซ้ำก่อน

เรื่องที่สอง การค้นรูปด้วย FDSearch คืนผลหน้าละ 3 แถวเสมอ ไม่ว่าจะตั้ง maxResults เป็นเท่าไร ถ้าเรียกครั้งเดียวจะนับรูปได้ 3 แล้วคิดว่าที่เหลือหายไป ต้องวนเลื่อน searchResultPosition ด้วย searchID ค่าคงที่ จนกว่า responseStatusStrg จะไม่ใช่ MORE

import os, requests
from requests.auth import HTTPDigestAuth

HOST = "http://" + os.environ["ACS_HOST"]           # เช่น 192.168.10.21
S = requests.Session()
S.auth = HTTPDigestAuth(os.environ["ACS_USER"], os.environ["ACS_PASS"])

def face_page(pos, sid="facelist"):
    r = S.post(HOST + "/ISAPI/Intelligent/FDLib/FDSearch?format=json", json={
        "searchID": sid, "searchResultPosition": pos, "maxResults": 30,
        "faceLibType": "blackFD", "FDID": "1"}, timeout=20)
    return r.json()

def all_faces():
    """เครื่องคืนหน้าละ 3 แถวเสมอ ต้องเลื่อนตามจำนวนที่ได้จริง"""
    out, pos = [], 0
    while True:
        j = face_page(pos)
        got = j.get("MatchList", [])
        out += got
        if not got or j.get("responseStatusStrg") != "MORE":
            return out
        pos += len(got)

ส่วนการนับผู้ใช้ เมื่อ UserInfo/Count ใช้ไม่ได้ ก็ต้องไล่หน้า UserInfo/Search แล้วนับเองแบบเดียวกัน

จุดพลิก: ปุ่มในหน้าเว็บของเครื่องลบได้

คนที่ชี้ทางออกคือเจ้าของงานเอง เขาบอกว่าในหน้าเว็บของเครื่อง กดแก้ไขผู้ใช้แล้วมีปุ่มลบรูป กดแล้วรูปหายโดยชื่อยังอยู่ เขาเข้าได้ด้วยเบราว์เซอร์อีกตัวหลังกดยอมรับใบรับรองแบบ self-signed ของเครื่อง

ประโยคนี้เปลี่ยนโจทย์ทั้งหมด หน้าเว็บของอุปกรณ์ไม่มีช่องทางลับ มันคุยกับเครื่องผ่าน HTTP เหมือนเรา ถ้าปุ่มทำได้ แปลว่ามีคำขอหนึ่งตัวที่ทำได้ และเบราว์เซอร์เห็นคำขอนั้นทุกไบต์ ผมเลยเลิกเดาแล้วขอให้เขาทำตามนี้กับคนที่ออกแล้วหนึ่งคน

  1. เปิดหน้าเว็บของเครื่อง ล็อกอินตามปกติ ไปที่หน้ารายชื่อผู้ใช้
  2. กด F12 เปิด DevTools ไปที่แท็บ Network ติ๊ก Preserve log ไว้ แล้วกดล้างรายการให้ว่าง
  3. กดแก้ไขผู้ใช้หนึ่งคน กดปุ่มลบรูป แล้วกดบันทึก ทำแค่คนเดียวพอ
  4. คลิกขวาในรายการคำขอ เลือก Save all as HAR แล้วส่งไฟล์มา
  5. อย่าทำอย่างอื่นในหน้าระหว่างนั้น เพื่อให้คำขอในไฟล์มีแต่ของที่เกี่ยว

ไฟล์ที่ได้ขนาด 1.6 MB ส่วนใหญ่เป็นไฟล์หน้าเว็บ สคริปต์ และรูป คำขอที่ไปหา ISAPI จริงมีไม่กี่ตัว ผมใช้สคริปต์สั้น ๆ กรองเอาเฉพาะส่วนนั้น

import json

har = json.load(open("device.har", encoding="utf-8"))
for e in har["log"]["entries"]:
    rq = e["request"]
    if "/ISAPI/" not in rq["url"]:
        continue
    path = rq["url"].split("?")[0].split("/ISAPI/")[1]
    body = (rq.get("postData") or {}).get("text", "")
    print(rq["method"], path, e["response"]["status"])
    if rq["method"] != "GET" and body:
        print("    ", body[:300])

ผลที่ออกมามี Security/token คำขอ sessionHeartbeat 6 ครั้ง UserInfo/Search UserInfo/Modify คำขอ capabilities และตัวที่ตามหา UserInfo/Modify ตอนแรกดูน่าสงสัยที่สุดเพราะเกิดตอนกดบันทึก แต่ body ของมันมีแค่ข้อมูลโปรไฟล์ ไม่มีอะไรเกี่ยวกับรูป ตัวจริงคือคำขอนี้

{
  "method": "PUT",
  "path": "/ISAPI/Intelligent/FDLib/FDSetUp?format=json",
  "body": {
    "faceLibType": "blackFD",
    "FDID": "1",
    "FPID": "A1007",
    "deleteFP": true
  },
  "response": { "statusCode": 1, "statusString": "OK" }
}

มันคือ FDSetUp ตัวเดียวกับที่ใช้เพิ่มรูป ไม่ใช่ endpoint ที่มีคำว่า Delete ในชื่อ สิ่งที่ผมไม่มีทางเดาได้คือคีย์ deleteFP ที่เอกสารฉบับที่ผมมีไม่ได้เขียนไว้ ผมยิง endpoint ที่ชื่อบอกว่าลบไปเก้าแบบ ขณะที่ของจริงซ่อนอยู่ในคำสั่งตั้งค่า

ยิงตามเอกสาร 9 แบบดูสิ่งที่หน้าเว็บส่งจริงFDSetUp/DeletenotSupportFDSearch/DeletebadJsonContentDELETE, POST, CountmethodNotAllowedUserInfoDetail/Deleteลบทั้งคนเบราว์เซอร์: กดลบรูป 1 คนแท็บ Network ของ DevToolsSave all as HAR (1.6 MB)PUT FDSetUp + deleteFP:trueสำรองก่อนลบ ทำทีละคนดึงรูปจาก faceURLBLOB + md5ตาราง archiveตรวจmd5 ตรง 79/79ยิงลบdeleteFP:trueนับซ้ำรูป 134 -> 56สำรองไม่สำเร็จ = ข้ามคนนั้น ไม่ยิงลบ
เลนซ้ายคือการเดาจากชื่อ endpoint เลนขวาคือการดูคำขอจริงจากเบราว์เซอร์ ส่วนล่างคือลำดับที่ใช้ลบจริง

ยิงซ้ำเองโดยไม่ต้องมี session ของหน้าเว็บ

ใน HAR คำขอของหน้าเว็บมีพารามิเตอร์ security=1 กับ iv=... ต่อท้าย URL และผูกกับ session ที่มี heartbeat เลี้ยง ดูจากหน้าตาแล้วเหมือนต้องจำลองขั้นตอนล็อกอินของหน้าเว็บทั้งชุด แต่พอลองยิง body เดียวกันด้วย HTTP digest auth ธรรมดา ไม่มี cookie ไม่มีพารามิเตอร์เข้ารหัส เครื่องตอบ OK เหมือนกัน

curl -s --digest -u "$ACS_USER:$ACS_PASS" -X PUT \
  "http://$ACS_HOST/ISAPI/Intelligent/FDLib/FDSetUp?format=json" \
  -H 'Content-Type: application/json' \
  -d '{"faceLibType":"blackFD","FDID":"1","FPID":"A1007","deleteFP":true}'
# {"statusCode":1,"statusString":"OK"}

ตรวจผลด้วยการค้นระเบียนผู้ใช้คนนั้นซ้ำ numOfFace เป็น 0 ส่วนชื่อ สิทธิ์ประตู และก้อน Valid ไม่เปลี่ยนสักฟิลด์ ตรงกับเงื่อนไขของเจ้าของงานทุกข้อ

ข้อควรระวังกับไฟล์ HAR

ไฟล์ HAR เก็บทุกอย่างที่เบราว์เซอร์ส่ง รวมค่า token ของ session, cookie, พารามิเตอร์ใน URL และ body ที่มีรหัสพนักงาน ถือว่าเป็นไฟล์ลับเท่ากับรหัสผ่าน ใช้เสร็จแล้วลบ ไม่แนบลงที่สาธารณะ และไม่ commit ลง repo ถ้าต้องเก็บไว้อ้างอิงให้เก็บเฉพาะ method, path และโครง body ที่ตัดค่าจริงออกแล้ว

แนวคิดเดียวกันนี้ผมเคยใช้กับสวิตช์ในบทความ ตั้ง VLAN ด้วย API ชุดเดียวกับที่หน้าเว็บมันใช้ แต่บทความนั้นไม่ได้ลงขั้นตอนการดัก HAR ไว้ รอบนี้เลยเขียนให้ครบ เพราะการให้คนกดจริงหนึ่งครั้งแล้วดักคำขอ เป็นทางที่สั้นที่สุดเท่าที่ผมเจอ

สำรองก่อนลบ และลบเฉพาะคนที่สำรองผ่าน

ได้คำสั่งลบมาแล้วผมยังไม่ยิงทันที เพราะเพิ่งพลาดมาและเงื่อนไขข้อสามคือสำรองลงฐานข้อมูลก่อน ผมทำตาราง archive แยกไว้หนึ่งตาราง เก็บทั้งไฟล์รูปเป็น BLOB และเมตาสองก้อน คือของคลังใบหน้ากับของระเบียนผู้ใช้ เผื่อวันที่ต้องกู้คืน

CREATE TABLE face_archive (
  employee_no        VARCHAR(32) PRIMARY KEY,
  full_name          VARCHAR(191) NOT NULL,
  face_jpg           LONGBLOB NOT NULL,
  jpg_bytes          INT NOT NULL,
  face_meta          JSON,
  user_meta          JSON,
  device_ip          VARCHAR(45),
  archived_at        DATETIME NOT NULL,
  deleted_on_device  TINYINT(1) NOT NULL DEFAULT 0,
  deleted_at         DATETIME NULL
);

สคริปต์ทั้งตัวยาว 76 บรรทัด มีสี่คำสั่งย่อย คือ count นับรูป check <รหัส> ดูชื่อกับ numOfFace กับ Valid ของคนนั้น backup <รหัส> สำรองอย่างเดียว และ delete <รหัส> ซึ่งบังคับสำรองก่อนเสมอ ถ้าสำรองไม่ผ่านจะพิมพ์ BACKUP FAILED -> skip แล้วข้ามคนนั้นไป ไม่มีทางที่คำสั่งลบจะวิ่งโดยไม่มีสำเนา

def backup(emp, face):
    url = face.get("faceURL")
    if not url:
        return None
    img = S.get(url, timeout=30)
    if img.status_code != 200 or not img.content:
        return None
    path = os.path.join(BK, emp + ".jpg")
    with open(path, "wb") as f:
        f.write(img.content)
    with open(os.path.join(BK, emp + ".face.json"), "w", encoding="utf-8") as f:
        json.dump({"face": face, "user": user_rec(emp)}, f, ensure_ascii=False, indent=1)
    return path, len(img.content)

def del_face(emp):
    """คำขอเดียวกับที่หน้าเว็บของเครื่องส่ง"""
    r = S.put(HOST + "/ISAPI/Intelligent/FDLib/FDSetUp?format=json",
              json={"faceLibType": "blackFD", "FDID": "1",
                    "FPID": emp, "deleteFP": True}, timeout=20)
    return r.status_code, r.text.strip()

faces = {x.get("FPID"): x for x in all_faces()}
for emp in sys.argv[2:]:
    if emp not in faces:
        print(emp, "NO FACE -> skip"); continue
    b = backup(emp, faces[emp])
    if not b:
        print(emp, "BACKUP FAILED -> skip"); continue
    print(emp, "backup", b, "->", del_face(emp))

หลังนำไฟล์เข้าตาราง ผมเทียบ md5 ของ BLOB ในฐานข้อมูลกับไฟล์ต้นฉบับบนดิสก์ทีละแถวก่อนจะถือว่าสำรองเสร็จ แล้วค่อยเดินคำสั่งลบตามรายชื่อ

9 แบบคำขอที่ลองแล้วตัน
1.6 MBไฟล์ HAR จากการกดครั้งเดียว
deleteFPคีย์ที่เอกสารไม่บอก
77 คนลบรูปแล้ว 0 error
134 -> 56จำนวนรูปในเครื่อง
79/79md5 ของ BLOB ตรงไฟล์ต้นฉบับ
4.1 MBขนาดตาราง archive 79 แถว
142ผู้ใช้ในเครื่อง เท่าเดิม

รูปที่เหลือ 56 รูปคือของคนที่ยังทำงาน 52 รูป กับบัญชีผู้ดูแล 4 รูป ตาราง archive มี 79 แถว คือ 77 คนที่ลบในรอบจริงรวมกับที่สำรองไว้ตอนทดสอบ ผู้ใช้ในเครื่องยังเป็น 142 ระเบียนเท่าเดิม และผมคืน Valid.enable เป็น true ให้ 3 คนที่ปิดไว้ระหว่างทดสอบ

สิ่งที่ยังไม่ได้พิสูจน์ และบทเรียนที่เอาไปใช้ต่อ

มีสองเรื่องที่ต้องบอกตรง ๆ ว่ายังไม่จบ เรื่องแรก การกู้รูปกลับเข้าเครื่องจากตาราง archive ยังไม่เคยทดสอบ ทางที่น่าจะใช้คือ POST แบบ multipart ไปที่ FaceDataRecord แต่ผมยังไม่ได้ลองจริง สำรองที่ยังไม่เคยกู้คือสำรองที่ยังพิสูจน์ไม่ครบ เรื่องที่สอง บันทึกเหตุการณ์ในตัวเครื่องยังไม่มีคำสั่งลบเฉพาะส่วน คำสั่ง ClearEvent ที่ลองได้ 404 กับ notSupport ข้อนี้ยังตรงกับที่เขียนไว้ในบทความเดิม

ที่เคยสรุป

API ตอบ notSupport แปลว่าเครื่องทำไม่ได้

ผมลองทุก endpoint ที่ชื่อบอกว่าลบ ได้ notSupport หมด เลยสรุปว่าเฟิร์มแวร์สายนี้ไม่มีคำสั่งลบรูปเดี่ยว ข้อสรุปนี้มาจากการเดาชื่อคำสั่ง ไม่ได้มาจากการดูว่าเครื่องทำอะไรได้

ที่ถูก

notSupport แปลว่าคำขอนั้นไม่ใช่ทาง

ความสามารถมีอยู่ แต่อยู่ในคำสั่งอื่นที่ชื่อไม่บอก ตราบใดที่หน้าเว็บของเครื่องทำได้ ให้ถือว่า API ทำได้ แล้วไปดักดูคำขอจริง ก่อนจะสรุปว่าทำไม่ได้

ลำดับที่ผมจะใช้ครั้งหน้ากับอุปกรณ์ที่มีหน้าเว็บ คือถามก่อนว่าหน้าเว็บของมันทำสิ่งนั้นได้ไหม ถ้าได้ ดัก HAR ก่อนอ่านเอกสาร ถ้าไม่ได้ค่อยไล่เอกสาร และไม่ว่าทางไหน คำสั่งที่ลบข้อมูลต้องผ่านการสำรองที่ตรวจแล้วก่อนเสมอ ส่วนบทความเดิมผมจะกลับไปใส่หมายเหตุชี้มาที่นี่ ตรงไหนผมอธิบายตกหล่นหรือพิมพ์ผิด เดี๋ยวกลับมาแก้เพิ่มให้ภายหลังครับ

อยากให้เราทำให้ไหม?

ให้เราช่วยติดตั้ง ตั้งค่า ย้ายระบบ หรือแก้ปัญหาเซิร์ฟเวอร์ เพื่อให้คุณมีเวลาไปทำงานที่สำคัญกว่า

คุยเรื่องงานกับเรา

เคยเจองานแบบนี้ไหม? ติดตรงไหน?

มาแลกวิธีกันต่อในบอร์ด LinuxThai

→ คุยต่อในบอร์ด

ความคิดเห็น 0

ยังไม่มีความคิดเห็น — เป็นคนแรกเลย