ตัวสร้างไซต์คงที่แบบ hot-reloadin เล็กน้อยจากเชลล์ ถือว่า Bash 4.4+
คำเตือน: นี่จามรี!
งานของ shite
คือการช่วยฉันสร้างเว็บไซต์ของฉัน: https://evalapply.org ดังนั้น ขอบเขตของ shite
ชุดฟีเจอร์ (ที่ไม่ถูกต้อง) การขัดเงาจะเป็นระดับการผลิตเสมอ โดยที่การผลิตคือ "ทำงานบนเครื่องของฉัน )" :)
สารบัญ
shite
มีเป้าหมายที่จะสร้างเว็บไซต์
มันเป็นระบบการเผยแพร่เล็กๆ น้อยๆ ที่สร้างจากเวิร์กโฟลว์แบบไปป์ไลน์ ซึ่งเป็นทางเลือกที่ขับเคลื่อนโดยสตรีมของเหตุการณ์ไฟล์ (สำหรับบิตของ hotreloadin)
มันจะไม่ทำให้แฮ็กเกอร์สุภาพบุรุษ Perl/PHP จากศตวรรษที่ผ่านมาแปลกใจเลย
มันมีอยู่เพราะคน ๆ หนึ่งผิวปากเล่นเพลงโง่ ๆ และโกนจามรี
นี่คือสิ่งที่ทำโดยพื้นฐาน (อ้างอิง: ฟังก์ชัน shite_templating_publish_sources
)
cat " ${watch_dir} /sources/ ${url_slug} " |
__shite_templating_compile_source_to_html ${file_type} |
__shite_templating_wrap_content_html ${content_type} |
__shite_templating_wrap_page_html |
${html_formatter_fn} |
tee " ${watch_dir} /public/ ${slug} .html "
# The complete "business logic" is 300-ish lines as of this comment,
# counted as all lines except comments and blank lines.
grep -E -v " s?#|^$ "
./bin/{events,metadata,templating,utils,hotreload}.sh |
wc -l
ก่อนที่คุณจะรู้สึกตื่นเต้นจนเกินไป ฉันขอเตือนคุณก่อนว่าใบอนุญาต MIT หมายความว่าฉันไม่ต้องทำอะไรแย่ๆ ถ้าผู้สร้างขี้น้อยรายนี้ล้มเหลวในการทำงานของคุณ การมีส่วนร่วมเต็มไปด้วยคำเตือนเพิ่มเติม
และสุดท้ายแต่ไม่ท้ายสุด ข้าพเจ้าขอประกาศให้อ่านข้อความทั้งหมดในที่นี้ในภาษาฌอน คอนเนอรี
ในความฝัน shite
ของฉัน ฉันปรารถนา...
เหนือสิ่งอื่นใด เพื่อให้มัน ("ตรรกะทางธุรกิจ") มีขนาดเล็ก เล็กพอที่จะแคช ดีบัก และรีแฟคเตอร์ในหัวของฉัน
เพื่อติดตั้งและใช้งานโดยไม่ได้รับอนุญาตจากผู้ใช้ขั้นสูง
เพื่อหลีกเลี่ยง toolchain อย่างยิ่ง และสร้างการพึ่งพา ไม่มี gems / npms / venvs / what-have-yous ดังนั้น Bash จึงเป็นภาษา เพราะ Bash มีอยู่ทุกหนทุกแห่ง และแพ็คเกจมาตรฐาน เช่น pandoc
หรือ tidy
เมื่อเราต้องการฟังก์ชันขั้นสูง เฉพาะ
เทมเพลตที่ไม่ต้องพึ่งพาด้วยชุด HTML ธรรมดาในเอกสาร Heredocs ที่ดี
ระบบเมตาดาต้าอย่างง่าย การกำหนดเนมสเปซของเนื้อหา การจัดระเบียบสินทรัพย์คงที่ ฯลฯ
เว็บเซิร์ฟเวอร์เป็นตัวเลือก (หรือกระบวนการเซิร์ฟเวอร์ประเภทใดก็ได้สำหรับเรื่องนั้น) เรามุ่งเป้าไปที่ไซต์แบบคงที่ ซึ่งทำงานได้ดีกับการนำทาง file://
การสร้างมันขึ้นมาจากชิ้นส่วนเล็กๆ ที่ประกอบได้ ใช้งานได้จริง เหมือนเครื่องมือยูนิกซ์ เพราะฉันชอบอะไรแบบนั้นมาก
เพื่อให้ตัวเองมีเวิร์กโฟลว์การแก้ไข-บันทึก-สร้าง-แสดงตัวอย่างแบบ REPL ที่ราบรื่น
ฉันเริ่มเขียนบล็อกใหม่โดยไม่ได้ตั้งใจหลังจากหายไปนาน ก่อนที่ฉันจะได้พูดคุยเรื่องต่างๆ บนคลาวด์ ฉันก็ยุ่งเกี่ยวกับเครื่องมือสร้างไซต์แบบคงที่ "สมัยใหม่" ก่อน เพราะ WordPress เป็นศตวรรษที่แล้ว (หรืออย่างที่ฉันบอกตัวเอง) จากนั้นฉันก็รู้สึกรำคาญกับเวทมนตร์สร้างเทมเพลต ฯลฯ ของ SSG Jamstack ตอนนี้ฉันอยู่บนเส้นทางที่มืดมนในการทำสิ่งนี้ กำลังถูกบล็อกเกี่ยวกับที่: shite: static sites from shell: ตอนที่ 1/2
ฉันใช้ shite ในโหมด "hotreload" เป็นหลัก โดยส่วนใหญ่จะเขียนโพสต์ (ใน orgmode) และดูตัวอย่างสด (ใน Firefox) ส่วนใหญ่น้อยกว่าคือการแก้ไขตัวอย่างด่วนสำหรับสไตล์และ/หรือเทมเพลตหน้า อย่างน้อยที่สุด หลังจากที่ทำงานหนักกับโพสต์เป็นระยะๆ ฉันใช้มันในโหมด "don't hotreload" เพื่อสร้างไซต์ใหม่ทั้งหมด
ตัวอย่างการสาธิต shite ด้านล่าง
โดยพื้นฐานแล้ว หมายความว่าหากฉันสร้าง อัปเดต ลบไฟล์ใดๆ ภายใต้ sources
ที่มา ไฟล์นั้นจะต้องแปลเป็น HTML โดยอัตโนมัติ ได้รับการเผยแพร่ในเครื่องสู่ public
และทำให้เกิดการนำทางหน้าเว็บที่เหมาะสมหรือดำเนินการโหลดซ้ำในเว็บเบราว์เซอร์ที่ไซต์ของฉันเปิดอยู่
เรียกสคริปต์ "main" ในเซสชันเทอร์มินัลใหม่ทั้งหมดหรือบานหน้าต่าง tmux
./shite.sh
มันเปิดไฟล์ดัชนีใน Firefox ได้อย่างมีประโยชน์ตามค่าเริ่มต้นที่ฉันตั้งไว้ในอาร์เรย์ shite_global_data
ใน . ./shite.sh
ใน Emacs หรือ Vim ของคุณ ให้เปิดไฟล์เนื้อหาบางส่วนภายใต้ sources
แก้ไข บันทึก และดูเนื้อหาที่ปรากฏในเบราว์เซอร์ (ใช่ การระบุ Emacs/Vim นั้นโง่เขลา เพราะฉันเรียกใช้การดำเนินการ ด่วน ตามเหตุการณ์ที่ไม่ระบุตัวตน เห็นได้ชัดว่าผู้แก้ไขที่แตกต่างกันจะอัปเดตไฟล์แตกต่างกัน ฉันใช้ Emacs หรือ Vim ดังนั้นฉันจึงเฝ้าดูเหตุการณ์ที่เกิดขึ้น ดังนั้นมันจึงทำงานบนเครื่องของฉัน : )).
บ่อยครั้งที่เบราว์เซอร์จำตำแหน่งการเลื่อนได้ซึ่งเป็นระเบียบ บางครั้งการ Hotreload ก็เป็นอะไรที่แย่มาก ดังนั้นฉันจึงกดที่ว่างและบันทึกไฟล์เนื้อหาเพื่อทริกเกอร์ hotreload อีกครั้ง
ไปที่เนื้อหาคงที่ เช่น สไตล์ชีต CSS เปลี่ยนแปลงสิ่งต่างๆ เช่น ค่าสีพื้นหลัง บันทึกและดูการเปลี่ยนแปลงสีในเบราว์เซอร์
ปรับแต่งส่วนเทมเพลตบางส่วนใน templates.sh
--- เช่น เทมเพลตโพสต์บล็อก จากนั้นสลับไปที่ไฟล์เนื้อหาโพสต์บนบล็อกและแก้ไขเพื่อทริกเกอร์การสร้างเพจด้วยเทมเพลตที่แก้ไข (เช่น Hit Space และ Save)
นี่คือแฮ็ค หน้า root index.org ใต้แหล่งที่มาเป็นแบบพิเศษ หากฉันแก้ไข นั่นหมายความว่าฉันต้องการสร้างรายการโพสต์ใหม่สำหรับหน้าดัชนี แท็ก และสร้างไฟล์เมตาที่เกี่ยวข้องขึ้นใหม่ เช่น ฟีด RSS, แผนผังเว็บไซต์, robots.txt เป็นต้น
ในเซสชันเทอร์มินัลใหม่ที่สะอาดตาให้เรียก shite.sh
ด้วย "no" และเป็นทางเลือกด้วย base_url
ของสภาพแวดล้อมการปรับใช้:
สร้างไซต์ใหม่ทั้งหมดสำหรับการนำทาง file:/// "local" "ไร้เซิร์ฟเวอร์" อย่างแท้จริง :)
./shite.sh " no "
สร้างไซต์ทั้งหมดขึ้นใหม่เพื่อการเผยแพร่ภายใต้โดเมนของฉัน
./shite.sh " no " " https://evalapply.org "
แฟล็กเหล่านี้เปลี่ยนแปลงพฤติกรรมของระบบ
SHITE_BUILD
เป็น "hot" จะทำให้ระบบเหตุการณ์ทำงานในโหมด "monitor" ซึ่งจะขับเคลื่อนพฤติกรรม hotreload การตั้งค่าเป็น "ไม่" จะระงับเบราว์เซอร์ hotreloadSHITE_DEBUG_TEMPLATES
เป็น "debug" จะทำให้มีแหล่งที่มาของเทมเพลตก่อน ก่อนที่จะเผยแพร่เนื้อหาแหล่งที่มาของเทมเพลตใดๆ shite
ค่อนข้างเป็น Unixy ภายใน หรืออย่างนั้นฉันก็อยากจะคิด
รหัสเป็น Bash สไตล์การเขียนโปรแกรมเชิงฟังก์ชัน ทุกสิ่งทุกอย่างเป็นฟังก์ชัน ฟังก์ชันส่วนใหญ่เป็นฟังก์ชันล้วนๆ---เครื่องมือ Unix เล็กๆ น้อยๆ ในตัวเอง ตรรกะส่วนใหญ่เป็นแบบไปป์ไลน์ สิ่งนี้ใช้ได้ผลดีอย่างน่าประหลาดใจ เพราะเชลล์ไม่ใช่จุดที่ไม่ดีสำหรับ FP
ฉันยังต้องการประสบการณ์แบบ REPL แบบโต้ตอบสดเมื่อเขียนด้วย shite
เพราะฉันชอบทำงานในรันไทม์แบบสด/แบบโต้ตอบเช่น Clojure และ Emacs
ดังนั้น shite
จึงกลายเป็นระบบที่ขับเคลื่อนด้วยเหตุการณ์ที่ตอบสนองได้อย่างเต็มที่ ซึ่งสามารถ build-and-reload-on-save ได้ทันที
มีเนมสเปซไดเรกทอรีหลักสามรายการ:
sources
ซึ่งมีเนื้อหา "แหล่งที่มา" เช่น บล็อกโพสต์ที่เขียนใน orgmode รวมถึง CSS, Javascript และเนื้อหาคงที่อื่นๆpublic
สำหรับสิ่งประดิษฐ์ที่รวบรวม / สร้างขึ้นbin
สำหรับโค้ดการสร้าง shite รูปแบบการตั้งชื่อ URL เป็นไปตามโครงสร้างไดเร็กทอรีย่อยภายใต้ sources
และถูกจำลองแบบตามที่อยู่ภายใต้โครงสร้างไดเร็กทอรี pubilic
เนื่องจากนี่คือรูปแบบเนมสเปซ URL มาตรฐานที่น่ารังเกียจ จึงมีผลโดยตรงกับเนื้อหาที่เผยแพร่ด้วย ชอบเช่นนั้น:
file:///absolute/path/to/shite/posts/slug/index.html
http://localhost:8080/posts/slug/index.html
https://your-domain-name.com/posts/slug/index.html
ฟังก์ชั่น "สาธารณะ" ทั้งหมดมีเนมสเปซเป็น shite_the_func_name
ฟังก์ชั่น "ส่วนตัว" ทั้งหมดมีเนมสเปซเป็น __shite_the_func_name
ฟังก์ชั่นมีไว้เพื่อ:
ในเซสชันเทอร์มินัลใหม่ที่สะอาดตา:
source ./bin/utils_dev.sh
shitTABTAB
หรือ __shiTABTAB
ที่บรรทัดคำสั่งเพื่อเติมข้อความอัตโนมัติtype -a func_name
เพื่อพิมพ์คำจำกัดความของฟังก์ชันและอ่าน APIshite_global_data
และ shite_page_data
ตามต้องการ มีเทมเพลตสำหรับส่วนของหน้า (เช่น ส่วนหัว ส่วนท้าย การนำทาง) และสำหรับคำจำกัดความแบบเต็มหน้า (เช่น เทมเพลตหน้าเริ่มต้น) สิ่งเหล่านี้เขียนเป็น HTML ธรรมดาที่ห่อหุ้มด้วยเอกสารเหล่านี้ ./bin/templates.sh
จัดเตรียมสิ่งเหล่านี้
เทมเพลตเต็มไปด้วยข้อมูลตัวแปรจากแหล่งต่างๆ:
shite_global_data
มีข้อมูลเมตาทั่วทั้งไซต์ และ shite_page_data
มีข้อมูลเมตาเฉพาะหน้า กระบวนการภายนอกบางอย่างต้องตั้งค่าอาร์เรย์เหล่านี้ล่วงหน้าก่อนที่จะประมวลผลหน้าใดๆตัวอย่างเช่น หน้าเต็มอาจถูกสร้างขึ้นดังนี้:
cat ./sample/hello.md |
pandoc -f markdown -t html |
cat << EOF
<!DOCTYPE html>
<html>
<head>
$( shite_template_common_meta )
$( shite_template_common_links )
${shite_page_data[canonical_url]}
</head>
<body ${shite_page_data[page_id]} >
$( shite_template_common_header )
<main>
$( cat - )
</main>
$( shite_template_common_footer )
</body>
</html>
EOF
ระบบข้อมูลเมตาของ shite
ถูกกำหนดให้เป็นคู่คีย์-ค่า คีย์จะตั้งชื่อรายการข้อมูลเมตา และจะเชื่อมโยงกับค่าประเภทใดก็ตาม ตัวอย่างด้านล่าง
ตามที่ระบุไว้ก่อนหน้านี้ ข้อมูลเมตารันไทม์จะดำเนินการในสภาพแวดล้อมโดยอาร์เรย์ที่เชื่อมโยง shite_global_data
และ shite_page_data
สิ่งเหล่านี้อาจสร้างขึ้นโดยการก่อสร้างโดยตรง ตลอดจนได้รับการอัปเดตจากแหล่งข้อมูลภายนอก
แต่ละหน้าอาจระบุข้อมูลเมตาของตนเองใน "ส่วนหน้า" ที่ด้านบนของหน้า สิ่งนี้จะถูกนำไปใช้ในข้อมูลเมตาของหน้าเพิ่มเติมที่ได้มาจากแหล่งอื่น
shite
คาดหวังให้เราเขียนส่วนหน้าโดยใช้ไวยากรณ์ที่เข้ากันได้กับประเภทเนื้อหาที่กำหนดดังนี้
ใช้บรรทัดความคิดเห็น # SHITE_META
เพื่อแบ่งเขตข้อมูลเมตาในรูปแบบองค์กรที่ shite
ควรแยกวิเคราะห์เป็นข้อมูลเมตาเฉพาะหน้า
# SHITE_META
#+title: This is a Title
#+slug: this/is/a/slug
#+date: Friday 26 August 2022 03:38:01 PM IST
#+tags: foo bar baz quxx
# SHITE_META
#+more_org_metadata: but not processed as shite metadata
#+still_more_org_metadata: and still not processed as shite metadata
* this is a top level heading
this is some orgmode content
#+TOC: headlines 1 local
** this is a sub heading
- this is a point
- this is another point
- a third point
เขียนส่วนหน้า YAML สไตล์ Jekyll คั่นระหว่าง ---
ตัวคั่น
---
TITLE : This is a Title
slug : this/is/a/slug
DATE : Friday 26 August 2022 03:38:01 PM IST
TAGS : foo BAR baz QUXX
---
# this is a heading
this is some markdown content
## this is a subheading
- this is a point
- this is another point
- a third point
เราสามารถใช้แท็ก <meta>
มาตรฐานที่เป็นไปตามระเบียบนี้: <meta name="KEY" content="value">
< meta name =" TITLE " content =" This is a Title " >
< meta name =" slug " content =" this/is/a/slug " >
< meta name =" DATE " content =" Friday 26 August 2022 03:38:01 PM IST " >
< meta name =" TAGS " content =" foo BAR baz QUXX " >
< h1 > This is a heading </ h1 >
< p > This is some text </ p >
< h2 > This is a subheading </ h2 >
< p >
< ul >
< li > This is a point </ li >
< li > This is another point. </ li >
< li > This is a third point. </ li >
</ ul >
</ p >
นี่จามจุรี!
เนื่องจากเวิร์กโฟลว์แบบโต้ตอบสดที่สร้างความพึงพอใจให้กับ Clojure/Lisp/Spreadsheet ของ Clojure/Lisp/Spreadsheet ทำให้ฉันผิดหวัง ฉันจึงอยากให้โหลดซ้ำและนำทางด่วนในการสร้างอึด้วย
แต่ดูเหมือนจะไม่มีเซิร์ฟเวอร์ / เครื่องมือการพัฒนาเว็บสดแบบสแตนด์อโลนที่ไม่ต้องการให้ฉันดาวน์โหลดครึ่งหนึ่งของอินเทอร์เน็ตที่รู้จักเป็นการพึ่งพา อย่างที่บอกไปก่อนหน้านี้ว่าเป็นสิ่งที่ฉัน ไม่ อยากทำ อย่างยิ่ง
DuckSearch นำเสนอโหมดใจร้อนของ Emacs ซึ่งค่อนข้างร้อนแรง แต่ฉันไม่ต้องการฮาร์ดไวด์กับ Emacs ของฉัน โชคดีที่มันยังส่งคลื่นสมองที่น่าตื่นเต้นนี้ซึ่งมี 'inotify-tools' และ 'xdotool': github.com/traviscross/inotify-refresh
ฉบับฮอต!
เพราะอะไรจะร้อนแรงไปกว่าคอมพิวเตอร์ของฉันกระแทกปุ่ม F5 นั้น ให้ ฉัน? ราวกับว่ามัน รู้ ว่าจริงๆ แล้วฉันต้องการอะไรลึกๆ ในใจ
ระบบย่อยของเหตุการณ์ตั้งฉากกับทุกสิ่งทุกอย่าง และประกอบเข้ากับส่วนที่เหลือของระบบ
การออกแบบเป็นสถาปัตยกรรมสตรีมมิ่งมาตรฐานที่ลุ่ม ได้แก่ เฝ้าดูเหตุการณ์ระบบไฟล์ จากนั้นกรอง กรองข้อมูลซ้ำ วิเคราะห์ และกำหนดเส้นทาง (ที) ไปยังตัวประมวลผลเหตุการณ์ต่างๆ ปัจจุบันมีโปรเซสเซอร์ดังกล่าวเพียงสองตัวเท่านั้น หนึ่งรายการเพื่อรวบรวมและเผยแพร่เพจหรือเนื้อหาที่เกี่ยวข้องกับเหตุการณ์ อีกรายการหนึ่งเพื่อรีโหลดเบราว์เซอร์ (หรือการนำทางด่วน) ขึ้นอยู่กับเหตุการณ์เดียวกัน
โดยพื้นฐานแล้วสิ่งนี้:
# detect file events
__shite_detect_changes ${watch_dir} ' create,modify,close_write,moved_to,delete ' |
__shite_events_gen_csv ${watch_dir} |
# hot-compile-and-publish content, HTML, static, etc.
tee >( shite_templating_publish_sources > /dev/null ) |
# browser hot-reload
tee >( __shite_hot_cmd_public_events ${window_id} ${base_url} |
__shite_hot_cmd_exec )
กิจกรรมเป็นเพียงสตรีมของบันทึก CSV ที่มีโครงสร้างดังนี้:
unix_epoch_seconds,event_type,base_dir,sub_dir,url_slug,file_type,content_type `
เราใช้ส่วนต่างๆ ของบันทึกเหตุการณ์เพื่อทำให้เกิดการกระทำที่แตกต่างกัน
สคริปต์ inotify-refresh ที่ลิงก์ไว้ก่อนหน้านี้จะพยายามรีเฟรชชุดหน้าต่างเบราว์เซอร์ เป็นระยะ แต่เราต้องการที่จะกระตือรือร้น มาก การแก้ไขใดๆ ในไฟล์เนื้อหาของเราและ/หรือสินทรัพย์คงที่จะต้องกระตุ้นการรีโหลด/นำทางในแท็บเบราว์เซอร์ที่แสดงอึของเรา
เราต้องการกำหนดสถานการณ์การรีโหลดที่แตกต่างกัน: บัคเก็ตที่ครบถ้วนสมบูรณ์ซึ่งแยกจากกันซึ่งเราสามารถแมปเหตุการณ์ไฟล์ที่เราต้องการตรวจสอบได้
หากเราทำเช่นนี้ เราจะสามารถสร้างแบบจำลองการอัปเดตเป็นบันทึกการเขียนล่วงหน้า เจาะเหตุการณ์ผ่านไปป์ไลน์การวิเคราะห์ เชื่อมโยงกับสถานการณ์ที่ตรงกันทุกประการ จากนั้นจึงทำให้เกิดการดำเนินการในที่สุด ตัวอย่างเช่น:
รีเฟรชแท็บปัจจุบันเมื่อ
กลับบ้านเมื่อไร.
นำทางไปยังเนื้อหาเมื่อ
เนื่องจากเรากำลังทำให้คอมพิวเตอร์จำลองการกระทำของแป้นพิมพ์ของเราเอง มันอาจรบกวนการกระทำของเราเองได้ หากเรายังคงเขียนเรื่องไร้สาระในโปรแกรมแก้ไขข้อความของเรา และปล่อยให้คอมพิวเตอร์ทำการโหลดซ้ำ เราก็ไม่ควรรู้สึกรำคาญ
มีจามรีมากมายในโลก
สำหรับโมโจการเผยแพร่หลายไซต์ที่แพร่หลายอย่างแท้จริง:
shite
ควรมีอยู่ใน PATH ของฉันนี่คือจามรีตัวเล็ก ฉันคงจะโกนมันเร็วๆ นี้
แน่นอนว่าเราสามารถใช้งาน CI ของโฮสต์ git ยอดนิยมเพื่อกระตุ้นการสร้าง shite
ได้ แต่ทำไมต้องใช้เทคโนโลยีแห่งศตวรรษปัจจุบันที่เทอะทะ ในเมื่อเราก้าวไปสู่ความล้ำสมัยในช่วงปลายทศวรรษ 1900 แล้ว... สตรีมมิ่งและตอบสนองอย่างเต็มที่?
นอกเหนือจาก Sarcasam แล้ว ฉันไม่เห็นว่าเหตุใดจึงไม่สามารถใช้ระบบเหตุการณ์เดียวกันเพื่อเพิ่มการสนับสนุน hot-deploy บนเครื่องระยะไกลที่ฉันเรียกใช้ได้
บนกล่องรีโมท:
sources
ของไซต์ประดิษฐานอยู่sources
(ลบด้วยการดูเบราว์เซอร์)ในกล่องท้องถิ่นของฉัน:
https://mydomain.com/posts/hello/index.html
ดำเนินการบางอย่างผ่าน SSH เพื่อนำการรีเฟรชเบราว์เซอร์กลับสู่กล่องภายในเครื่อง ในกรณีที่มีการปรับใช้ด่วนกับเซิร์ฟเวอร์ระยะไกล
อาจมีการตั้งค่าเวลา "การพัฒนา / การร่าง" / การแยกส่วนบางสถานการณ์หรือไม่ อาจเป็นฟังก์ชัน 'dev_server' ที่เราใช้เริ่มต้นเซสชันการเขียนอันใหม่ใช่ไหม
หากคุณมาจนสุดทางแล้ว แต่ ยัง ต้องการมีส่วนร่วม...
ทำไม
ทำไมในนามของสิ่งศักดิ์สิทธิ์และความดีคุณถึงอยากทำ? ไม่ชัดเจนเลยหรือว่านี่คือผลงานของคนโง่? คุณไม่เคยได้ยินมาก่อนว่า Bash ไม่ใช่ภาษาโปรแกรมจริงด้วยซ้ำ? และเห็นได้ชัดว่าการตบหน้าไม่ทำให้ PR ของคุณจะอิดโรยไปชั่วนิรันดร์และความคิดเห็นของคุณจะตกอยู่ในความว่างเปล่าที่ไม่ระบุชื่อ?
ใช่ การส่งแพตช์เป็นความคิดที่แย่มาก
แต่ โปรดส่งอีเมลความหวังและความฝันของคุณเกี่ยวกับผู้สร้าง shite ของคุณมาให้ฉันด้วย! ฉันอ่านอีเมลที่ชื่อจริง dot นามสกุลที่ gmail
เราสามารถเป่าเพลงตลก ๆ และโคจามรีโกนจามรีของเราตามลำดับด้วยวิธีพิเศษของเราเอง
ขอให้แหล่งที่มาอยู่กับเรา
งานนี้ได้รับใบอนุญาตแบบคู่ภายใต้ใบอนุญาต MIT และใบอนุญาต CC By-SA 4.0
SPDX-License-Identifier: mit หรือ cc-by-sa-4.0