2019 Fall 機械設計工程系課程
計算機程式: http://mde.tw/cp2019 (機械設計四技一甲與一乙, 必修課)
Ebooks (使用校內 IP 下載):
Python:
https://link.springer.com/content/pdf/10.1007%2F978-1-4842-3204-0.pdf
https://link.springer.com/content/pdf/10.1007%2F978-3-319-13072-9.pdf
https://link.springer.com/content/pdf/10.1007%2F978-3-030-20290-3.pdf
C:
https://link.springer.com/content/pdf/10.1007%2F978-1-4612-1484-7.pdf
C++:
https://link.springer.com/content/pdf/10.1007%2F978-1-4302-0656-9.pdf
https://link.springer.com/content/pdf/10.1007%2F978-1-349-14449-5.pdf
https://link.springer.com/content/pdf/10.1007%2F978-1-4612-1630-8.pdf
Dart:
https://link.springer.com/content/pdf/10.1007%2F978-1-4842-0556-3.pdf
https://link.springer.com/content/pdf/10.1007%2F978-1-4842-4972-7.pdf
Android:
https://link.springer.com/content/pdf/10.1007%2F978-1-4842-0019-3.pdf
https://link.springer.com/content/pdf/10.1007%2F978-1-4302-4063-1.pdf
https://link.springer.com/content/pdf/10.1007%2F978-1-4842-2259-1.pdf
https://link.springer.com/content/pdf/10.1007%2F978-1-4302-1063-4.pdf
https://link.springer.com/content/pdf/10.1007%2F978-1-4302-3244-5.pdf
https://link.springer.com/content/pdf/10.1007%2F978-1-4842-3333-7.pdf
IOTs:
https://link.springer.com/content/pdf/10.1007%2F978-3-662-54904-9.pdf
電腦輔助設計實習: http://mde.tw/cad2019 (機械設計四技二甲與二乙, 必修課, 相關課程: 計算機程式與網際內容管理)
Ebooks (使用校內 IP 下載):
CAD History:
http://mde.tw/cad2019/downloads/cad_history.pdf
AutoDesk Inventor 2018:
https://link.springer.com/content/pdf/10.1007%2F978-1-4842-3225-5.pdf
Creo:
https://link.springer.com/content/pdf/10.1007%2F978-3-319-23359-8.pdf
Solidworks & NX:
https://link.springer.com/content/pdf/10.1007%2F978-3-319-03862-9.pdf
The NURBs Book:
https://link.springer.com/content/pdf/10.1007%2F978-3-642-59223-2.pdf
Computational Geometry
https://link.springer.com/content/pdf/10.1007%2F978-3-662-03427-9.pdf
Deep Learning:
https://link.springer.com/content/pdf/10.1007%2F978-3-319-94463-0.pdf
https://link.springer.com/content/pdf/10.1007%2F978-1-4842-3516-4.pdf
https://link.springer.com/content/pdf/10.1007%2F978-3-319-73004-2.pdf
https://link.springer.com/content/pdf/10.1007%2F978-1-4842-4261-2.pdf
Problem Solving:
https://link.springer.com/content/pdf/10.1007%2F978-3-030-04254-7.pdf
或登入 @gm 電子郵箱後, 直接下載上述全部電子書.7z
Tuesday, July 30, 2019
Friday, July 12, 2019
AutoDesk Inventor Professional 免費學生三年版本
學生可以免費使用 AutoDesk Inventor
校園下載
以下連結必須在校園網路、使用學校代理主機或 vpn 模式下才可下載
AutoDesk PDSU (Product Design Suite Ultimate edition) 包含:
Autodesk Inventor Professional
AutoCAD Mechanical
AutoCAD Electrical
AutoCAD
Navisworks Simulate
AutoCAD Raster Design
Autodesk Recap
Autodesk Vault Basic
Autodesk Fusion 360
Navisworks Manage
AutoDesk 安裝教學.pdf
官方網站下載
希望在任何地方使用,可以從 https://www.autodesk.com/education/free-software/inventor-professional, 以 @gm 電子郵箱登錄且認證後下載, 取得三年免費使用授權. 允許同時安裝在筆電與桌上型電腦共兩套.
建議安裝流程
利用學校配發的電子郵箱, 連結至 https://www.autodesk.com/education/free-software/inventor-professional, 登記帳號, 驗證 email 後, 取得 AutoDesk Inventor Professional 版本 2019 的 Serial Number 後, 從學校網站中下載 AutoDesk PDSU, 安裝後, 利用前述所取得的序號啟動 AutoDesk Inventor Professional 2019, 之後就可以在任何地方上網使用.
校園下載
以下連結必須在校園網路、使用學校代理主機或 vpn 模式下才可下載
AutoDesk PDSU (Product Design Suite Ultimate edition) 包含:
Autodesk Inventor Professional
AutoCAD Mechanical
AutoCAD Electrical
AutoCAD
Navisworks Simulate
AutoCAD Raster Design
Autodesk Recap
Autodesk Vault Basic
Autodesk Fusion 360
Navisworks Manage
AutoDesk 安裝教學.pdf
官方網站下載
希望在任何地方使用,可以從 https://www.autodesk.com/education/free-software/inventor-professional, 以 @gm 電子郵箱登錄且認證後下載, 取得三年免費使用授權. 允許同時安裝在筆電與桌上型電腦共兩套.
建議安裝流程
利用學校配發的電子郵箱, 連結至 https://www.autodesk.com/education/free-software/inventor-professional, 登記帳號, 驗證 email 後, 取得 AutoDesk Inventor Professional 版本 2019 的 Serial Number 後, 從學校網站中下載 AutoDesk PDSU, 安裝後, 利用前述所取得的序號啟動 AutoDesk Inventor Professional 2019, 之後就可以在任何地方上網使用.
電腦輔助設計室群準複製流程
群準Pro V6 版本複製
電腦輔助設計室目前使用的群準還原卡為 Pro V6 版本, 只能用於 MBR 硬碟規劃, 儘管可能在 2020 Spring 即將換為 Server 版本, 但是 2019 Fall 可能還是必須採用 Pro V6 版本.
目前已知最佳複製模式為 32 位元, 選擇 11 號網路卡 (配合主機板上方的 Intel 網路卡連線), 並且選擇模式 2 執行複製, 可以取得最快 6GB/sec 的傳輸速度, 以目前第三磁區 100 GB 以內的有效資料, 可以在 25 分鐘之內完成複製.
複製流程
1. 首先必須將各電腦開機至群準選單, 然後按下 F10 後輸入管理者密碼, 進入後, 將磁碟複製頁面中的設定選為:
32 位元複製模式
11 號網路卡
2. 之後各電腦完成上述設定後重新開機至選單後, client 端按下 F9 後等待完成登錄.
3. 準備作為來源的電腦, 重新開機至選單後, 按下 F10 後輸入管理者密碼後, 選擇磁碟複製頁面, 啟用登錄流程, 等待各連線電腦登錄完成之後, 即可進入複製選單, 選擇要完整複製或差異複製後, 選擇開始傳送後, 選擇要複製的磁區, 以第三磁區而言, 為 Win10 磁區.
參考資料: https://github.com/mdecourse/wcms2018/issues/7
電腦輔助設計室目前使用的群準還原卡為 Pro V6 版本, 只能用於 MBR 硬碟規劃, 儘管可能在 2020 Spring 即將換為 Server 版本, 但是 2019 Fall 可能還是必須採用 Pro V6 版本.
目前已知最佳複製模式為 32 位元, 選擇 11 號網路卡 (配合主機板上方的 Intel 網路卡連線), 並且選擇模式 2 執行複製, 可以取得最快 6GB/sec 的傳輸速度, 以目前第三磁區 100 GB 以內的有效資料, 可以在 25 分鐘之內完成複製.
複製流程
1. 首先必須將各電腦開機至群準選單, 然後按下 F10 後輸入管理者密碼, 進入後, 將磁碟複製頁面中的設定選為:
32 位元複製模式
11 號網路卡
2. 之後各電腦完成上述設定後重新開機至選單後, client 端按下 F9 後等待完成登錄.
3. 準備作為來源的電腦, 重新開機至選單後, 按下 F10 後輸入管理者密碼後, 選擇磁碟複製頁面, 啟用登錄流程, 等待各連線電腦登錄完成之後, 即可進入複製選單, 選擇要完整複製或差異複製後, 選擇開始傳送後, 選擇要複製的磁區, 以第三磁區而言, 為 Win10 磁區.
參考資料: https://github.com/mdecourse/wcms2018/issues/7
Wednesday, July 3, 2019
UGS NX3
2005 年底, 機械設計工程系導入 UGS NX3, 大約一年半之後, Siemens 以 35 億美元購入 UGS, 期間又經歷了 13 年, 終於又再有機會使用 NX, 這時已經到了 12 版.
當年的 NX3 總共導入 100 套完整教育版本, 花了 9 萬台幣, 經過大約八年閒置期, 想要重新啟動認證主機, 事情當然沒有想像中簡單.
當年所使用的 Windows 操作系統為 XP 32 位元版本, 前後使用大約 6 年, 到 2011 年, 操作系統轉為 Windows 7, 同樣是 32 位元版本, 認證主機的架構除了納入 64 位元系統, IPv6 也在 2012 年正式登場, 但也正在這個時候 NX 來到第八版, 教育版的價位不斷攀升之後, 只得以相同合理的價位換為 PTC Creo 2.0.
於情於理, 一個自認能夠培養未來產業頂尖人才的科技大學, 實在沒有理由花大錢導入商用套件. 反而, 軟體代理商除了應該要贈送軟體, 並且額外付費請學校使用該特定套件教學才對.
2012-2015 年持續使用 Creo 3 之後, 終於在 2015 年底 Onshape 提供全球免費教育版, 於是在最佳化電腦輔助設計室的網路環境之後, 至今的電腦輔助設計與協同產品設計實習課程, 全面採用 Onshape.
至於目前看待 NX3 乃至 NX12 的目的, 僅在於了解其程式基本架構, 當年的 NX3, 已經可以透過 nx3.c:
NX10 之後, 已經直接支援 Python, 只是 NX12 使用的 Python 版本內定為 3.6.1, 比可攜程式系統中的 3.7.3 舊, 因此相容性必須經過測試才能確定.
最後, 學員只要登入 @gm 電子郵箱, 就可以下載 NX3_portable.7z, 解開壓縮檔放入隨身碟, 並且連上網路擷取授權認證後, 就可以使用.
利用 NX3 執行零件繪製與受力變形分析, 請參考:
當年的 NX3 總共導入 100 套完整教育版本, 花了 9 萬台幣, 經過大約八年閒置期, 想要重新啟動認證主機, 事情當然沒有想像中簡單.
當年所使用的 Windows 操作系統為 XP 32 位元版本, 前後使用大約 6 年, 到 2011 年, 操作系統轉為 Windows 7, 同樣是 32 位元版本, 認證主機的架構除了納入 64 位元系統, IPv6 也在 2012 年正式登場, 但也正在這個時候 NX 來到第八版, 教育版的價位不斷攀升之後, 只得以相同合理的價位換為 PTC Creo 2.0.
於情於理, 一個自認能夠培養未來產業頂尖人才的科技大學, 實在沒有理由花大錢導入商用套件. 反而, 軟體代理商除了應該要贈送軟體, 並且額外付費請學校使用該特定套件教學才對.
2012-2015 年持續使用 Creo 3 之後, 終於在 2015 年底 Onshape 提供全球免費教育版, 於是在最佳化電腦輔助設計室的網路環境之後, 至今的電腦輔助設計與協同產品設計實習課程, 全面採用 Onshape.
至於目前看待 NX3 乃至 NX12 的目的, 僅在於了解其程式基本架構, 當年的 NX3, 已經可以透過 nx3.c:
#include所編譯成的動態連結程式庫, nx3.pyd, 讓下列 Python 3 程式呼叫:#include #include #include #include #include #include #include #include #include #include #include // for block creation #include #include // for stl 資料轉出 #include #include // NX initialization extern int nx3init(void) { UF_initialize(); return 0; } static PyObject* mod_nx3init(PyObject *self, PyObject *args) { int fail = 0; // ii 表示兩個輸入變數都是整數 nx3init(); // i 表示 s 為整數 return Py_BuildValue("i",fail); } extern int nx3term(void) { UF_terminate(); return 0; } static PyObject* mod_nx3term(PyObject *self, PyObject *args) { int fail = 0; // ii 表示兩個輸入變數都是整數 nx3term(); // i 表示 s 為整數 return Py_BuildValue("i",fail); } // 定義內部運算的函式內容 extern int nx3(int a, int b) { tag_t part_tag; tag_t reopen_part_tag; /* Open a new part then save it. */ //UF_initialize(); UF_PART_new("a_blank_part.prt",UF_PART_ENGLISH,&part_tag); UF_PART_save(); //UF_terminate(); return a+b; } // sum 函式的 interface static PyObject* mod_nx3(PyObject *self, PyObject *args) { int a; int b; int s; // ii 表示兩個輸入變數都是整數 if (!PyArg_ParseTuple(args,"ii",&a,&b)) return NULL; // 這裡的 sum2 則是內部的函式定義, 與外部呼叫模組或函式名稱沒有直接關係 s = nx3(a,b); // i 表示 s 為整數 return Py_BuildValue("i",s); } // 定義內部運算的函式內容 extern int nx4(int a, int b) { tag_t part_tag; tag_t reopen_part_tag; //UF_initialize(); UF_PART_new("abc_blank_part.prt",UF_PART_ENGLISH,&part_tag); UF_PART_save(); //UF_terminate(); return a-b; } // sum 函式的 interface static PyObject* mod_nx4(PyObject *self, PyObject *args) { int a; int b; int s; // ii 表示兩個輸入變數都是整數 if (!PyArg_ParseTuple(args,"ii",&a,&b)) return NULL; // 這裡的 sum2 則是內部的函式定義, 與外部呼叫模組或函式名稱沒有直接關係 s = nx4(a,b); // i 表示 s 為整數 return Py_BuildValue("i",s); } // 建立 block 的函式處理 extern int nx3block(double corner0, double corner1, double corner2, char* edge0, char* edge1, char* edge2) { double corner[3] ={corner0,corner1,corner2}; // 指定長寬高 char* edge[3] = {edge0,edge1,edge2}; tag_t block_tag; UF_PART_new("abc_blank_part.prt",UF_PART_ENGLISH,&block_tag); UF_MODL_create_block(UF_NULLSIGN,NULL_TAG,corner,edge,&block_tag); return 0; } static PyObject* mod_nx3block(PyObject *self, PyObject *args) { double corner0, corner1, corner2; char *edge0, *edge1, *edge2; int fail = 0; // ii 表示兩個輸入變數都是整數 if (!PyArg_ParseTuple(args,"dddsss",&corner0,&corner1,&corner2,&edge0,&edge1,&edge2)) return NULL; fail = nx3block(corner0,corner1,corner2,edge0,edge1,edge2); // i 表示 fail 為整數 return Py_BuildValue("i",fail); } // 開啟零件檔案 extern int partopen(char* filename) { UF_PART_load_status_t load_status; tag_t part; int ifail = 0; // 根據使用者所要處理的檔案, 將零件檔案打開 ifail = UF_PART_open(filename,&part,&load_status); return ifail; } static PyObject* mod_partopen(PyObject *self, PyObject *args) { char* filename; int fail = 0; if (!PyArg_ParseTuple(args,"s",&filename)) return NULL; fail = partopen(filename); // i 表示 fail 為整數 return Py_BuildValue("i",fail); } // 關閉零件檔案 extern int partclose(char* filename) { int ifail = 0; tag_t part_tag; part_tag = UF_PART_ask_part_tag(filename); ifail = UF_PART_close(part_tag, 1, 1); return ifail; } static PyObject* mod_partclose(PyObject *self, PyObject *args) { char* filename; int fail = 0; if (!PyArg_ParseTuple(args,"s",&filename)) return NULL; fail = partclose(filename); // i 表示 fail 為整數 return Py_BuildValue("i",fail); } extern int partsaveas(char* filename) { UF_PART_save_as(filename); return 0; } static PyObject* mod_partsaveas(PyObject *self, PyObject *args) { char* filename; int fail = 0; // ii 表示兩個輸入變數都是整數 if (!PyArg_ParseTuple(args,"s",&filename)) return NULL; fail = partsaveas(filename); // i 表示 fail 為整數 return Py_BuildValue("i",fail); } extern int editexp(char* exp) { // exp should be something like "p0=10" int ifail = 0; ifail = UF_MODL_edit_exp(exp); return ifail; } static PyObject* mod_editexp(PyObject *self, PyObject *args) { char *exp, *str; double dimension; int fail = 0; // ii 表示兩個輸入變數都是整數 if (!PyArg_ParseTuple(args,"sd",&exp,&dimension)) return NULL; str = malloc(256); sprintf(str,"%s=%G",exp,dimension); fail = editexp(str); free(str); // i 表示 fail 為整數 return Py_BuildValue("i",fail); } extern int modelupdate() { // exp should be something like "p0=10" int ifail = 0; ifail = UF_MODL_update(); return ifail; } static PyObject* mod_modelupdate(PyObject *self, PyObject *args) { int fail = 0; fail = modelupdate(); // i 表示 fail 為整數 return Py_BuildValue("i",fail); } // 計算特定零件的體積資料 // 將零件轉為 STL 檔案, 文字格式或二位元格式 // 開啟文字格式的 STL 檔案 extern int savetextstl(char* filename) { void * file_handle; int ifail = 0; tag_t body_tag; int num_errors; UF_STD_stl_error_p_t error_info; ifail = UF_STD_open_text_stl_file(filename,TRUE,&file_handle); // 擷取零件中的實體 (type=70, subtype=0) 資料 UF_MODL_ask_object(70,0,&body_tag); // 由 UF_MODL_ask_object 取得的 tag 確實為 body tag ifail = UF_STD_put_solid_in_stl_file( file_handle, NULL_TAG, body_tag, 0.1, 0.5, 0.05, &num_errors, &error_info); ifail = UF_STD_close_stl_file (file_handle); return ifail; } static PyObject* mod_savetextstl(PyObject *self, PyObject *args) { char* filename; int fail = 0; if (!PyArg_ParseTuple(args,"s",&filename)) return NULL; fail = savetextstl(filename); // i 表示 fail 為整數 return Py_BuildValue("i",fail); } // 開啟二位元格式的 STL 檔案 extern int savebinstl(char* filename) { void * file_handle; int ifail = 0; tag_t body_tag; int num_errors; UF_STD_stl_error_p_t error_info; // TRUE append // FALSE not append // apply filename as header ifail = UF_STD_open_binary_stl_file(filename,TRUE,filename,&file_handle); /* extern int UF_STD_open_binary_stl_file ( char * file_name, logical append, char * header, void ** file_handle ); char * file_name Input Name of STL file to be written logical append Input Append flag: TRUE = Append FALSE = No append char * header Input Header text for start of binary file void ** file_handle Output Handle of file */ // 擷取零件中的實體 (type=70, subtype=0) 資料 UF_MODL_ask_object(70,0,&body_tag); // 由 UF_MODL_ask_object 取得的 tag 確實為 body tag ifail = UF_STD_put_solid_in_stl_file( file_handle, NULL_TAG, body_tag, 0.1, 0.5, 0.05, &num_errors, &error_info); ifail = UF_STD_close_stl_file (file_handle); return ifail; } static PyObject* mod_savebinstl(PyObject *self, PyObject *args) { char* filename; int fail = 0; if (!PyArg_ParseTuple(args,"s",&filename)) return NULL; fail = savebinstl(filename); // i 表示 fail 為整數 return Py_BuildValue("i",fail); } // ask part volume, 這裡使用的單位為 cm^3 extern double askvolume() { void * file_handle; int ifail = 0; tag_t body_tag; char *str; // 配合設定不同物理條件的精確度 double acc_val[11] = {.01,0,0,0,0,0,0,0,0,0,0}; double massprop[47]; double massprop_stat[13]; // 擷取零件中的實體 (type=70, subtype=0) 資料 UF_MODL_ask_object(70,0,&body_tag); // 這裡假設零件檔案中只有一個實體 //求質量特性, UF_MODL_ask_mass_props_3d(&body_tag,1,1,3,1.0,1,acc_val,massprop,massprop_stat); return massprop[1]; } static PyObject* mod_askvolume(PyObject *self, PyObject *args) { double volume; int fail = 0; volume = askvolume(); // i 表示 fail 為整數 return Py_BuildValue("d",volume); } // 與函式對應的結構定義 static struct PyMethodDef Mod_Nx3[] = { {"nx3", mod_nx3, METH_VARARGS, "Description.."}, {"nx4", mod_nx4, METH_VARARGS, "Description.."}, {"nx3init", mod_nx3init, METH_VARARGS, "NX3 initilization function"}, {"nx3term", mod_nx3term, METH_VARARGS, "NX3 termination function"}, {"nx3block", mod_nx3block, METH_VARARGS, "Block Creation"}, {"partsaveas", mod_partsaveas, METH_VARARGS, "part save as"}, {"partopen", mod_partopen, METH_VARARGS, "part open"}, {"partclose", mod_partclose, METH_VARARGS, "part open"}, {"editexp", mod_editexp, METH_VARARGS, "edit expression"}, {"modelupdate", mod_modelupdate, METH_VARARGS, "model update"}, {"savetextstl", mod_savetextstl, METH_VARARGS, "open text stl"}, {"savebinstl", mod_savebinstl, METH_VARARGS, "open binary stl"}, {"askvolume", mod_askvolume, METH_VARARGS, "ask part volume"}, {NULL,NULL,0,NULL}, }; // 模組結構定義 // 配合 Python 3 新增的模組結構定義 static struct PyModuleDef ModNx3 = { PyModuleDef_HEAD_INIT, "Nx3Module", /* 模組名稱 */ "Nx3Module_doc", /* 模組文件, may be NULL */ -1, /* size of per-interpreter state of the module, or -1 if the module keeps state in global variables. */ Mod_Nx3// 函式結構名稱 }; // 模組起始 // PyInit_ 後必須使用"名稱".pyd 中的模組名稱, 以便啟動 // 換言之, 若編譯連結後的動態模組名稱為 nx3.pyd, 則此地的起始函式名稱必須為 PyInit_nx3 PyMODINIT_FUNC PyInit_nx3(void) { // 建立模組的起始, 輸入為模組結構名稱之 address (void) PyModule_Create(&ModNx3); }
#coding: utf-8 # 導入 nx3.pyd from nx3 import * ############################## # 啟動 nx3 if (nx3init() == 0): print("nx3 啟動") else: print("nx3 無法啟動") ############################## # 開啟既有的零件檔案 partopen("block.prt") # 針對所開啟的零件檔案, 設定其中的尺寸變數 for i in range(1,21): for j in range(1,21): editexp("p0",i*1.6543) editexp("p1",j*1.4563) editexp("p2",6) # 進行零件的資料更新 modelupdate() ''' # 進行相關繪圖函式的呼叫 corner = [10,10,0] edge = ["10","10","10"] nx3block(corner[0],corner[1],corner[2],edge[0],edge[1],edge[2]) ''' # 將尺寸變更後的零件進行存檔 #partsaveas("finalblock.prt") #savebinstl("finalblock.stl") print(askvolume()/2.54/2.54/2.54, "立方英吋") partsaveas("finalblock.prt") partclose("finalblock.prt") ############################## # 終止 nx3 if (nx3term() == 0): print("nx3 終止") else: print("nx3 無法終止") ##############################
NX10 之後, 已經直接支援 Python, 只是 NX12 使用的 Python 版本內定為 3.6.1, 比可攜程式系統中的 3.7.3 舊, 因此相容性必須經過測試才能確定.
最後, 學員只要登入 @gm 電子郵箱, 就可以下載 NX3_portable.7z, 解開壓縮檔放入隨身碟, 並且連上網路擷取授權認證後, 就可以使用.
利用 NX3 執行零件繪製與受力變形分析, 請參考:
Subscribe to:
Posts (Atom)
NX12
NX 12 Help https://docs.plm.automation.siemens.com/tdoc/nx/12/nx_help Python related https://docs.plm.automation.siemens.com/tdoc/nx/...
-
學員期中報告影片錄製 上課鐘聲響後 20 分鐘內, 各學員必須啟動 ShareX, 在電腦教室錄製無語音, 至多五分鐘的期中報告自評影片, 拍攝過程中, 可利用 PowerPoint 或其他文字編輯器, 引導影片觀看者了解影片中所要呈現的網站、倉儲或特定的歷程內容. 影片...
-
2019 Spring Week9 五專網際內容管理 期中考自評影片 請各學員依照 https://2019wcm.blogspot.com/2019/04/2019-spring.html 說明 進行期中考週各項任務. 影片上傳後, 以類似下方的 ancho...
-
2019 Spring Week9 2a 期中考自評影片 請各學員依照 https://2019wcm.blogspot.com/2019/04/2019-spring.html 說明 進行期中考週各項任務. 2a 倉儲: https://github.c...