文章列表

重入膠坑2

手機‧電玩
MacauYeah・2024-11-21

水性漆上色 雖然筆者已經砌模型很久了,但很少試著自行上色。但多得模型開模技術的進步,以及水性漆、補色筆的出現,模型預設的分色再加上少量自行補色,就已經效果不錯了。以下是筆者完全使用水性漆+補色筆重塗的作品。打灰底後全部重新上色,白色為水性漆海棉干掃,紅色、藍色、黃色則為Marker筆。 海棉干掃要注意幾點,因為是白色,遮蓋力弱,一定要多層掃。而家每層一定要足夠輕透。筆者太貪,想半小時內就掃第二層,效果不是特別好。有條件的話,放個半天會好一點。感覺上白色遮蓋力弱,掃完第三層後,第四、五層的差別就不太大。大家可以自行取捨。 關於刮漆 大家留意自己的補色筆是不是水性,若果為水性,就跟水油的刮漆情況差不多。再加上小制作的情況下,使用補色筆都是為了方便,九成都不會預先打灰底,所以附著力會更弱。把玩時要更小心。(感謝賢者模型工作室關於水性油的選擇及指導。) 拍照把玩 作為經驗尚淺的筆者來看,老實講,在「上色」與「把玩」之間,還找不到共存的地方。前面已經提到,刮漆是會發生的問題,那怕大家用的是油性漆。更什的是,即使大家只打磨、素組、滲線,把玩多了也是會斷關節的。當花了一百小時精心制作,然後玩壞了,可痛心阿。若換成金錢來衡量,100元的高達模型,找代工精修上色,最後埋單可能要400以上,跟買一隻入門的成品模型差不多。所以大家在把玩之前,一定要做心理準備,斷了,就讓他去吧。塑膠,始㚵是不耐操。 雖然模型易壞,但放著不玩,就跟鹹魚沒有分別。所以筆者就拼著一去無回頭的決心,把高達模型扭下去(但也的確扭壞了兩三隻高達)。在這裏分享一些拍照的姿勢。 支架 拍照環境光不可控的情況下,不要拘泥於背景及支架。有條件搭個攝照棚,打光充足,誰不想。但條件不允許就要要拘泥那些了,找個有燈光的地板,手持拍照就好。選擇手持的原因是,拿得比較穩,重力干涉的因素較少,可以容易地調整模型的面向,使光源看來起比較充足。 構圖 如果是戰鬥模型,例如是高達,盡量選一些對角線構圖,會讓模型看來起更猛。另一個重點就是手機不要貼太近拍照,因為會變型。至少距離一個成人的手位,最後再把圖栽成合適的大小。或者在一個遠的位置,再使用1.5倍或2倍放大,拍出來的效果就跟肉眼感覺得差不多了。手機太近,一定是筆者卡關的問題,好不容易筆者才發現這一點。

概有雲供應商的K8S,為何要自己弄Docker Swarm / 本地K8S ?

科技新知
MacauYeah・2024-11-19

其實筆者寫了這麼多篇docker 的文章,可能有朋友會問,為何要自己從零建立Container環境,使用供應商直接提供的K8S服務不是很好嗎? 按照市場發展,各大雲供應商都越來多,競爭越嚟越激烈,作為用戶方,理應可以得到更合理的價格。不過作為使用VPS多年的筆者,真的沒有覺得雲服務的價格可以便宜到一個不用煩惱的水平,大家還是需要很㥀重地考量自己的業務是不是值得雲端化。 正常來講,在有足夠使用量的前提下,雲端化也是合適的,也真的有產到錢。但問題是大部份情況下公司內部自主開發的應用,都沒有去到這個程度。每個應用去租用一個VPS,即使使用最低配置,用起來的時候覺得不夠快,閒起來的時侯也是浪費錢。 這時,使用 Container 技術,就是讓多個不同的應用,共享同一個或多個VPS的好方法。因為 Container 可以簡易地做到應用之間的隔離,即使不同應用之間有依賴衝突,只要 Contianer 層面沒有衝突就可以共存。 Docker swarm 與 K8S 同為 container 技術,文章最前面,就提到了這個問題,為何不選現有的K8S,反而要自己弄Docker Swarm?其實關鍵亦是價錢的問題。使用K8S固然方便,但就每個節點都得使貴一級的雲端供應商服務,當我們的應用總是流量不足,就更易變得食之無味,棄之可惜。老實講,貴一級的雲端服務,有它存在的價值,很多東西可以做自動化擴展,例如概據流量自動擴容。另外,因為底層 Container 技術有供應商支援,也不用再另外購買支援服務。但這些都是業務有一定流量,才能展現出優勢。 反觀Docker Swarm,就是簡單可入手,初時一個VPS也可以。什至乎不上雲,找幾台舊電腦,實機做也可以。當然K8S也可以實機,不過就簡易程度來講,Docker Swarm 無得輸。待業務真正成長到一個有足夠流量的服務時,才進一步遷移到供應商的原生雲。在初期使用自建的Docker Swarm或小型K8S,可以先加入一些資源統計,以確定是否即裝滿負荷。

Swarm mode 上線 5 - load balancer | 還有那些事該考量?

科技新知
MacauYeah・2024-11-18

前面介紹了 ingress network ,亦介紹了 proxy gateway 。能做到的基本都做到了,再來就是考量安全性的問題。因為加了 proxy gateway ,前述的例子是所有 service ,都放在同一個 yaml 檔中。好處是,所有相關的東西存放在同一個檔中, gateway ,背後的 service 都一眼看到。但壞處就是有其中一個 service 更新,都要改那個 yaml 檔。更大的問題是, stack deploy 的指令,不單只更新其中一個 service ,就連其他 service 都會自動取得最新 image 而 redeploy 。 對於一個緊密的系統來講,同步更新可能不是大問題。但對於一些預定排程發佈的系統可不能這樣因為副作用而更新了。如果你也有這樣的分開管理需求,可以參考下面做法,把 gateway service 及 upstream service 放在不同的檔案中,然後經過 external network把所有 service 串連起來。 # nginx-stack.yaml, docker stack deploy -c nginx-stack.yaml nginx services: http-gateway: image: http-gateway ports: - 8080:8080 deploy: replicas: 1 update_config: delay: 10s restart_policy: condition: on-failure # manager-stack.yaml services: managerhttp: image: bretfisher/httpenv networks: - nginx_default - default deploy: replicas: 3 update_config: delay: 10s restart_policy: condition: on-failure placement: constraints: - node.labels.zone==manager networks: nginx_default: external: true # dmz-stack.yaml services: dmzhttp: image: bretfisher/httpenv networks: - nginx_default - default deploy: replicas: 2 update_config: delay: 10s restart_policy: condition: on-failure placement: constraints: - node.labels.zone==dmz networks: nginx_default: external: true 這樣,不同 service 的維護人員,就可以獨自控制自己的檔案。在第一次發佈時,確認 nginx-stack.yaml 先行發佈就可以了。對應的發佈指令是docker stack deploy -c nginx-stack.yaml nginx,它會自動産生一個 nginx_default (即 stack名字_default )的網絡。之後其他service,就可以經networks的設定找到它了。 services: YOUR_SERVICE: networks: - nginx_default - default networks: nginx_default: external: true 上述即使分離檔案,在安全性考量時還是有一個問題,就是 ingress network 的問題。試想一下,dmzhttp (Demilitarized Zone)原本被設定的原因,就是想限制某些訪問只能一些可以公開的服務。但因為經過 ingress network 之後,它們會在所有機器上開放這些 port。那就是,以下面的例子來講,若 dmzhttp 是公開的服務, intrahttp 是內部服務,即使用 intrahttp 使用不同的port 8889。但一經 swarm mode 預設的 ingress network ,在node.labels.zone==dmz的那些節點,還是可以訪問到 intrahttp 。 services: dmzhttp: image: bretfisher/httpenv ports: - 8888:8888 deploy: replicas: 2 update_config: delay: 10s restart_policy: condition: on-failure placement: constraints: - node.labels.zone==dmz intrahttp: image: bretfisher/httpenv ports: - 8889:8888 deploy: replicas: 3 update_config: delay: 10s restart_policy: condition: on-failure placement: constraints: - node.labels.zone==intra 我們前述介紹的 proxy gateway ,其實已經有一定程度可以解決這個問題。因為 proxy gateway 是根據 http 協定中的 host header 去做分流。在邊界網絡進來的「合法」訪問,道理上會好好地經引導到我們的 dmzhttp 。不過網路的邪惡可容小看, proxy gateway 也會有被騙的一日。有特定能力的攻擊者,只需找到目標域名,還是可以接觸到 intrahttp 。 若要做進一步隔離,在這種情況下,我們可以在 dmz , intra 機器中各設定一套 swarm ,完全獨立,這是最安全的做法。但這樣做的管理成本就會變高,因為兩個網段都會有自己的 manager 節點,而且在 dmz 網段的 manager 節點也有被攻擊的可能。 若我們回到單一 swarm 的方向,可以修改各個 service 中的 port 和 deploy 。利用 post mode 中的「host」,配合 deploy mode 中的「global」,完全跳開 ingress network。 services: dmzhttp: image: nginx ports: - target: 80 published: 8888 mode: host deploy: mode: global update_config: delay: 1s restart_policy: condition: any placement: constraints: - node.labels.zone==dmz intrahttp: image: bretfisher/httpenv ports: - target: 8888 published: 8888 mode: host deploy: mode: global update_config: delay: 10s restart_policy: condition: on-failure placement: constraints: - node.labels.zone==intra 上面的例子中, dmzhttp 會在所有 dmz 的機器中,每個節點只運行一份服務,而且直接使用該機的 8888 port ,外面不會再有 ingress network 的 存在。同樣地,intrahttp 會在 intra 的所有節點,運行一份服務,佔用它們的8888 。這兩個服務,即使使用一個 port ,swarm 也不會說有任何問題。因為它們不會經 ingress network 搶佔其他人的 8888。 可能會有讀者問,如果 host mode 這麼安全,為什麼預設會是 ingress network,那我們就要先了理清 ingress network 與 host mode 有有什麼分別?假設我們只運行一個service,它佔用8888。 功能ingress modehost mode replicas 數 同一個 service replicas 為任意數量,什至比節點的數目多 因為有 port 限制,每個節點最多只能運行一份 Virtual IP Virtual IP 任意在節點中跳轉也可以,因為 ingress 會自動找到對應的 service 所在的節點 Virtual IP必需要與 service 所在節點綁定,其他節點訪問不到 load balance 有 沒有 host mode 就像我們傳統在各自的節點上自行佈署自己的程序,各個節點只有一份。所以不會有自動 load balance 的效果,如果客戶端訪問固定的IP,就會得到是固定的接器接受請求。我們有需要,就要在前面加一個 Proxy Gateway (或 HA proxy )。 Virtual IP 也一樣, host mode 下需要好好地自動跟著 service 的生命期,不過幸運的是, Docker 預設己經有自動重啟 service 功能,即前文中的 restart_policy ,它在 host mode 下也適用。如果大家有配合 deploy 中的 global mode , Virtual IP 的並沒有實際變動。但如果沒有 global mode ,就要再想想辦法了。 最後考慮 load balance 的問題,如果進入點的 service 的真的不太消耗資源,沒有 load balance 也是可以的 ,但若超負荷,就必需要自建 proxy gateway 。經過進入點後,若我有背後的 service 就沒有所謂的 ingress 和 host mode 選擇。

Swarm mode 上線 5 - load balancer | proxy gateway 代理伺服器

科技新知
MacauYeah・2024-11-11

前面的例子,我們已經成功設定 ingress Network,也加了 virtual ip 。如果大家的目標是單一 web 應用,應該就已經很足夠。但作為一個足夠節儉的老闆,怎會讓一個 Swarm 只跑一個 Web 應用?但問題來了,一個 docker swarm service 就已經佔用一個公開端口 (例如上述的8888,或是更常見的443)。怎麼可以做到多個 service 分享同一個端口?答案就是回到傳統的 Web Server 當中,使用它們的 virtual host 及 proxy 功能,以達到這一效果。我們就以 Nginx 為例,去建立一個守門口的網關 (gateway) 。 以下就是一個最簡單的例子,最前端的 http-gateway (nginx) 對外公開端口 8080 ,它根據 virtual host,去分派對應的請求去 dmzhttp (bretfisher/httpenv) 及 managerhttp (bretfisher/httpenv) 。構架圖就是以下這樣。 ┌───────────┐ ┌──────────────►│ dmzhttp │ │ └───────────┘ │ ┌───────────────┐ │ http-gateway │ ────────►│ (nginx:8080) │ └──┬────────────┘ │ │ ┌─────────────┐ └─────────────►│ managerhttp │ └─────────────┘ 換成 docker stack ,就大概如下 services: http-gateway: image: http-gateway ports: - 8080:8080 deploy: replicas: 1 update_config: delay: 10s restart_policy: condition: on-failure dmzhttp: image: bretfisher/httpenv deploy: replicas: 2 update_config: delay: 10s restart_policy: condition: on-failure managerhttp: image: bretfisher/httpenv deploy: replicas: 3 update_config: delay: 10s restart_policy: condition: on-failure docker stack有一個很好的功能,就是 service 名會自動成為同一段網絡中的 hostname 。即是http-gateway中,它可以經DNS,找到 dmzhttp 、 managerhttp,也就是它的 nginx 可以設定成如下的樣子。 # default.conf server { listen 8080; listen [::]:8080; server_name managerhttp; resolver 127.0.0.11 valid=30s; location ^~ / { set $upstream_manager managerhttp; proxy_cache off; proxy_pass http://$upstream_manager:8888$request_uri; } } server { listen 8080; listen [::]:8080; server_name dmzhttp; resolver 127.0.0.11 valid=30s; location ^~ / { set $upstream_dmz dmzhttp; proxy_cache off; proxy_pass http://$upstream_dmz:8888$request_uri; } } 上面的例子中,就是一般的 virtual host + nginx proxy 設定。特別要說明的是 resolver 那一行,它指向 docker DNS (127.0.0.11), 而且還可以讓nginx在找不到上游時,不要馬上死亡。這樣 docker swarm 中各個 service 隨時加加減減,有保命的作用。 最後我們的 http-gateway 就是 nginx image + default.conf 上述的 docker 就可以用以下方式打包。 # Dockerfile # docker image build -t http-gateway ./ FROM nginx:latest COPY default.conf /etc/nginx/conf.d/default.conf 上面的 docker stack 和 nginx config,只要同步增加 service 及對應的 proxy pass,就可以o讓同一個端口,根據不同hostname做分流。當然,如果大家可以共用端口及 hostname 也可以,分流就改用 nginx location 來設定,不過這是更加偏向 nginx 的內容,日後有機會再介紹。本篇就先集中於 docker 相關的議題。 在安全性的角度, docker 還有一些配置可以做,就是讓 dmzhttp 和 managerhttp 在不同的機器上發佈。假設我們的網絡分開兩段,一段是 manager 專用,一段是 dmz 專用。在建立 docker swarm 後,我們可以為不同的節點加入對應的標簽。 docker node update --label-add zone=manager YOUR_MANAGER_NODE docker node update --label-add zone=dmz YOUR_DMZ_NODE 然後我們通過修改 docker stakc 中的 placement -> constraints ,限制不同的 service 在不同的節點上運行。 services: http-gateway: image: http-gateway ports: - 8080:8080 deploy: replicas: 1 update_config: delay: 10s restart_policy: condition: on-failure dmzhttp: image: bretfisher/httpenv deploy: replicas: 2 update_config: delay: 10s restart_policy: condition: on-failure + placement: + constraints: + - node.labels.zone==dmz managerhttp: image: bretfisher/httpenv deploy: replicas: 3 update_config: delay: 10s restart_policy: condition: on-failure + placement: + constraints: + - node.labels.zone==manager 使用上面的例子,我們就可以達到簡單分離的效果。但大家緊記,這個分離效果始終是一個規則式功能,它與防火牆的隔離還是有本質上的區別。除了利用傳統的防火牆技術外,我們的docker swarm network,其實也可以做更多隔離,我們日後再慢慢加強這個例子。

Git 歴史修正

科技新知
MacauYeah・2024-10-29

有時候,我們修正一系統檔案,例如某個commit中,多了一個不該放的檔案,又或者想修改該commit的作者,我們就要追搜到某個commit,然後用rebase隨個改。 例如本次repo,有一個githubAction.md,因為錯誤原因,被加到了main中,也藏了很久。如果我們想連根拔起,我們需要加出它第一次出現的commit。 $ git log githubAction.md commit 60ccd70f6b768138cbe23c93ffcfa32574ce895c 那我們就以它前一個commit作為rebase的根據,進行逐個commit修正。 $ git rebase -i 60ccd70f6b768138cbe23c93ffcfa32574ce895c^ pick 60ccd70 draft some content pick e2ee9a3 add some senario. pick b91afc1 refine submodule; pick 98cd366 add notes about submodule specific checkout; pick 064b06f test directly commit in submodule main pick 7b648d2 update git submodules notes pick 556f25e add notes about merge timing pick 5244804 Create git-continuous-integration-strategy.md pick 107e486 add more pratical nodes about ci; pick d93cbee add mono repo challenge pick 1c471b6 add worktree notes pick 9063ccb notes about different of git flow and github flow; pick b72e89e Update github-flow.md, add ref more link pick 0b8f2a9 draft github flow release problem pick 8b333fc finalize github flow release strategy 在rabase選項中,把需要改的commit由pick改為edit。(rebase會以舊到新顯示)。然後儲存。例如 edit 60ccd70 draft some content edit e2ee9a3 add some senario. edit b91afc1 refine submodule; pick 98cd366 add notes about submodule specific checkout; pick 064b06f test directly commit in submodule main pick 7b648d2 update git submodules notes pick 556f25e add notes about merge timing pick 5244804 Create git-continuous-integration-strategy.md pick 107e486 add more pratical nodes about ci; pick d93cbee add mono repo challenge pick 1c471b6 add worktree notes pick 9063ccb notes about different of git flow and github flow; pick b72e89e Update github-flow.md, add ref more link pick 0b8f2a9 draft github flow release problem pick 8b333fc finalize github flow release strategy 我們第一次會在60ccd70,我們作出想要的改動,然後經amend去改掉60ccd70 $ rm githubAction.md $ git add -u $ git commit --amend --author="newuser " 確定無誤的話,就可以去下一步,即是到了e2ee9a3 $ git rebase --continue 因為已經rebase過,你此時看到的不會再是hash不再是e2ee9a3,而是自動rebase完的e2ee9a3。若大家有東西要改,就使用commit --amend。如果沒有東西要改,也沒有conflict,可以繼續rebase --continue下去。

Swarm mode 上線 5 - load balancer | 負載平衡器

科技新知
MacauYeah・2024-10-28

前面我們一直談 swarm 的設定,但對於真實的服務,我們還要考慮客戶端是如何連接我們的伺服器群集。通常網路服務,客戶端都會經過域名轉換成IP,然而通過IP連線服務。 Ingress Network 假設我們 swarm 內有5個節點,那到底域名應該指向我們哪一個節點的 IP 呢? 如果我們不考慮節點死機的話,其實5個節點的IP都可以。因為 swarm 會自動把同一個公開的 port ,在每一個節點上都可以訪問到。 以下例子,即使只有一個 container 運行,佔用 port 8888,它還是會在5個節點上全開。 swarm 通過自己的 ingress network,它所有節點的 8888 串連起來。 services: http: image: bretfisher/httpenv ports: - 8888:8888 deploy: replicas: 1 update_config: delay: 10s restart_policy: condition: on-failure 我們可以在每個節點上,都會找到這個 ingress network,而且那個Network ID,應該是一樣的 > docker network ls | grep ingress t7rmk6g9zybm ingress overlay swarm 如果上述的 service 的 replicas 調成大於1的數量, ingress network 還會方便地自動 round robin (輪替) 地分派流量,達到最簡單的負載平衡。 Virtual IP 前述的設定,我們有一最大的假設,就是節點不會死機。但實際情況下,各種原因,例如安全性更新、重啟中,都會讓節點暫時無法使用。即使所有 service 都是會自動 failover (故障轉移),但客戶端還是用舊機 IP ,它還是無法訪問。因為該機 IP 已無法使用,除非我們連 IP 也懂 failover。這時, Virtual IP 就是我們的救命靈藥。 在 ubuntu 上,我們可以經過 keepalived 去設定 Virtual IP apt-get update && apt-get install keepalived -y 然後設定 keepalived , 假設 172.22.1.5 是我們的 Virtual IP 。 然後每個節點都要加入conf # vim /etc/keepalived/keepalived.conf # assume failover ip is 172.22.1.5 vrrp_instance VI_1 { # change interface according to machine status interface eth1 state MASTER # 101 for node1, 102 for node2 # you can start seq from other value, remind unqiue for each node is ok; virtual_router_id 101 # lower value will become master # ex, node1 priority 100, node2 priority 200, node3 priority 150. # if node 1, 2, 3 alive, node2 will become master. # if node 2 gone, node 3 will become master. priority 100 advert_int 1 authentication { auth_type PASS auth_pass YOUR_RANDOM_PASSWORD } virtual_ipaddress { 172.22.1.5 } } 上述需要特別注意的是 virtual_router_id : 每個節點應該都要不一樣,以作唯一標識。 priority : 每個節點應該都要不一樣,最大的那個節點,就會優先使用 Virtual IP 。 auth_pass : 每個節點都相同,但大家在抄時,記得更改。 還有的是開通 iptables ,讓各個節點可以經網絡廣播的方式互相看到對方。 iptables -I INPUT -d 224.0.0.0/8 -j ACCEPT iptables -I INPUT -p vrrp -j ACCEPT systemctl restart keepalived

Docker Tag 命名

科技新知
MacauYeah・2024-10-24

一般來講,同一個docker image會提供多個不同的版本,每個版本會附予不同的tag,以作標識。但以docker image的維護者來講,它的tag通常代表的是自己程式的版本號。不過這個版本號卻存在很多變數,就讓筆者好好地逐一說明。 程式的版本號 在沒有Docker的年代,其實所有軟件在發佈時,都會標示版本號,方便使用方明確追蹤問題,自行選擇升級、降級以解決相容性問題。大家要重現問題,也能清清楚地重現。所以docker image的tag,在某程度,都是代表發佈自己的程式版本號。但以前的年代,軟件底層的依賴,例如OS層面的共享程式庫,則不在發佈的管控中,所以過去的程式,在跨電腦安裝時,都會出現缺少某些共享庫的問題。而使用了Docker後,image以內的共享庫的都會在打包的那一刻固定和發佈,就不會有漏的問題。 庫更新,怎麼辦 上面說到image可以打包共享庫,但問題是共享庫也會有安全性更新問題,那麼對docker image的維護者來講,它自己的tag又該如何命名? 因為庫的量可大可少,所以一般來說,都不可能完全把各個庫的版本號寫在自己的tag上。退而求其次,就是用"版本號+日期",庫的細版本號,就存在原始碼當中。Ubuntu 就是這樣的例子。 不過"版本號+日期"的命名方式真的方便嗎?每次下遊用戶想更新去最近版本,都要自己找一次最近的日期。這樣對很多用戶來講都不夠方便。所以docker又提供了一個重tag的功能。例如ubuntu:noble,在早些時候指著noble-20240904.1,然後過幾天,又指向更新的noble-20241009。更常見的是latest,每次image都預設會存在,docker也希望大家會定期更新這個tag,讓大家可以更易地找到最新版本。 註: 這跟git tag有所不同,git tag並不預期會變的。當協作者收到tag後,那怕上遊刻意更新tag指針,協作者沒有刪除原tag之前,都不會知道tag更新去了哪裏。 我們該如何選 在發佈方和引用方來講,引用時可以明確使用唯一的"版本號+日期",對穩定性來講是有意義的。不過多多少少,會產生額外的時間成本。發佈方來說,就是多用了一些儲存空間,方便引用方可以隨時找到舊(庫)版本。而引用方,就要手動修改引用號,作為驗收依據,自動更新的難度比較大。 但對於自動更新要求比較大的情況下,可能就是使用latest或者會隨時更新的share tag(共用tag)比較實際。但我們也依然要定一些方式去版本更新記錄,例如:同時使用 beta latest archive 每日自動更新beta,只有所有測試都通過時,才把archive指向現在的latest,再把latest指向現在的beta。這樣做的好處是,核心的docker stack檔案改變的機會較少,也可以免除docker swarm做太細緻的權限管理。

重入膠坑

手機‧電玩
MacauYeah・2024-10-21

上期講到,筆者因為機緣之下,認識到賢者模型工作室,也很感謝他們幫忙修復了筆者那斷椿的模型(斷樁是膠老永遠都要面對的難題) 不知道大家看了筆者的爛尾舊模之後,有沒有也心動想把自己的舊模拿出來再繼前緣?概然有這個麼好的地方,有人指路,何不帶著大家的模型或問題,去賢者問一問。筆者就在最近一個月,就乾脆一口氣做一隻新模,翻新一隻舊模。 筆者也來分享一下最近的素組+補色的制作心得 剪鉗 - 新模 如果大家有機會做新模,看大家有沒有打磨的需求。打磨是很花時間的,但成品通過打磨後,即使不上色,只噴保護漆,已經超級美觀的。但時間成本也真的很高。 為什麼明明標題講剪鉗,但開篇卻在講打磨。因為第一步把模型從流道剪下來的那一刻,就間接地影響了日後能不能打磨。也根據大家要求的打磨完美度,去決定剪鉗要買多貴。 不論大家想不想打磨,但買一把實用的剪鉗,不要在剪下來取件的一刻令水口位花了,是很重要的。雖然有時留了位置打磨,但若水口花了,有時還是會傷到零件本身,不論表面怎樣打磨,都救不了。那時不是使用補土,就是要打磨到缺肉。家裏環境不方便上色的話,補土的做法就不適合了,還是好好地選剪鉗吧。 完全不打磨,可以買薄刃單刃剪。薄刃單刃剪可以極大地讓水口切割平整,又讓水口細小,之後不想打磨,也不會大刺刺地看到。筆者有試過這個方案,筆者還有一些更奇妙的想法:一開始開心剪,先素組/假組再說,後期有機會再打磨。但這個不是賢者老闆的推薦方案,而筆者慢慢地也發現了一些問題,果然不聽老人言,吃虧在眼前。我們有機會實際操作再詳述。 進行打磨,可以買田宮的雙刃剪,雙刃剪也有薄刃的,但鋒利程度不單刃。賢者老闆比較推這款,因為價格宜人,也耐用。不過筆者都有聽一些其他朋友的建議,一把粗剪,一把薄刃,這樣薄刃剪比較耐用。因為薄刃剪不論多便宜,也要 MOP 200起跳。但壞處就是時間成本越來越多,所以到頭來,可能賢者老闆推薦的田宮的雙刃剪 + 自行打磨,才是長久的做法。 打磨 - 新舊模 若果大家選擇打磨的話,就需要不同號數的砂紙。筆者就直接買了老闆推薦的海棉砂紙套裝:400, 600, 1000, 1500, 3000。省心,好用。 不過對於有需求的朋友,可能要另外再散買800和1200號。另外400,600號,也要加構砂紙+打磨板的版本。因為400,600號切削力強,不分情況全用海棉的話,很易磨到出現曲面。800和1200則作為600、1000、1500之間的過渡。有時太粗心,部份地方沒有足夠用1000打磨,噴保護漆後,還是會有明顯的傷痕。 手塗補色 - 新舊模 不論大家有多痛恨Bandai的貼色,筆者都不建議大面積手塗補色。因為市面上手塗的marker筆,多為水性塗,附著力本來就低,沒有底色補土的情況下,水性塗很易刮塗。筆者之前不知道,刮了又塗,塗了又刮,惡夢。經向賢者請教之後,才放棄這一方向。 而中、細型面積的補色,軟頭的Marker補色筆,實在太好用。除了白色這類遮蓋力不強的顏色,其他遮蓋力強的顏色,例如藍色、紅色,在補土加成之下,筆者塗得很滿意,不過刮漆還是會有。

Tmux - 繼 Screen以後的Linux多工神器

科技新知
MacauYeah・2024-10-08

因為各硬件/軟件的發難,筆者又不得不回到那個只有純純linux tty console的世界。很多時候,那怕使用tty,我們在Desktop mode,也有現代terminal 可以用,需要多分頁,滑鼠選取文字、複制、貼上,都可以輕易做到。 但在mobile / tablet device 上,手指操作真的很不方便。又或者你像筆者一樣,即使有電腦,但要操作一些Linux VM,它們連ssh都沒有,只能直接登入它們的tty,那麼懂得使用Tmux進行分頁及複制、貼上,就變得很重要。 Tmux 是什麼? Tmux 就是可以在Linux Terminal 同一個窗口中,實現多工處理的小程式。就像我們利用多分頁一樣,不同分頁做不同的事。不過最大的差異就是,生成分頁,排列分頁,我們都要使用鍵盤來完成。有時筆者也會用它來作為背景程式,以免不小心關了Terminal就會把所有運行中的指令都停掉。 我們就馬上來看實際例子吧 前置事項: 安裝Tmux及運行Tmux Debain & Ubuntu 安裝: sudo apt-get update && sudo apt-get install tmux 運行:tmux 進入tmux後,你就會至少有一個分頁,而且不會因為Terminal關閘而中斷 用法一: 建立兩個分頁,並切換 增加分頁: 先按 “Ctrl + b” (前置鍵),再按”c” (create) 切換分頁: 在多於一個分頁的情況下,先按 “Ctrl + b” (前置鍵),再按”n” (next) 用法二: 同一個分頁中,建立左右並排的窗口 增加水平窗口: 先按 “Ctrl + b” (前置鍵),再按 “ (雙引號) 切換窗口: 在多於一個窗口的情況下,先按 “Ctrl + b” (前置鍵),再按方向鍵左或右 用法三: 回到前一個tmux session中 因為不小必關閉了terminal,又或是remote ssh中,ssh斷線後,需要回到之前的工作狀態 未進入tmux 的狀態下:tmux attach 要留意tmux 可以有很多個session,要去到指定的session,就要為session命名。但這個不是筆者常用的情境,原本多個分頁已經很夠用,還要多個session,會很混亂。但不排除它在某些情況下有特別用途,有興趣的朋友可以自行挖挖看。 進階: 回頭看過去的terminal screen output 在現代的Terminal中,原本按滑鼠滑輪向上滾,就可以看到過去的資訊,但tmux下反而不行,所以我們需要進入特殊模式 進入Copy Mode: 先按 “Ctrl + b” (前置鍵),再按 [ (開括號中括號) 向上翻頁: 上方向鍵或PageUp 離開Copy Mode: Copy Mode中任何時候按”q” 進階: 複制貼上 進入Copy Mode: 先按 “Ctrl + b” (前置鍵),再按 [ (開括號中括號) 選擇範圍: 移到需要複制的文字起點,“Ctrl + Space” ,然後再移動到結束點,再按”Ctrl + w” 複制 貼上: 離開Copy Mode後,再按”Ctrl + b” ,然後 ] (關括號中括號) 進行貼上 進階: 複制貼上2 某些情況下,我們不允許使用“Ctrl + Space” 或 ”Ctrl + w”,因為它們可能跟系統的組合鍵有衝突,所以需要改為單鍵。 讓tmux使用類似vim的操作模式: echo “set-window-option -g mode-keys vi” >> ~/.tmux.conf 關掉所有使用中的tmux,重開tmux 進入Copy Mode: 先按 “Ctrl + b” (前置鍵),再按 [ (開括號中括號) 選擇範圍: 移到需要複制的文字起點,按單鍵“Space” ,然後再移動到結束點,再按”Enter” 複制 貼上: 離開Copy Mode後,再按”Ctrl + b” ,然後 ] (關括號中括號) 進行貼上 筆者常用的功能就這些,有興趣的朋友可以再深挖一下。 Reference https://tmuxcheatsheet.com/

Ceph Storage 水很深

科技新知
MacauYeah・2024-09-25

筆者不才,早前為大家介紹了一篇關於Ceph Storage的最入門安裝教學。但在後續測試中,發現了一些概念上的問題,需要盡早說明,不然就會像筆者一樣,要砍掉重來很多次。 OSD HDD Ceph Storage的主要功能,就是為Contiainer提供外置儲存空間,它對儲存空間有特定的要求。我們最好在建立ceph cluster(cephadm bootstrap)之前,就為每個node上增加合適的HDD 引述官方說明: OSD (Object Storage Daemons) The device must have no partitions. The device must not have any LVM state. The device must not be mounted. The device must not contain a file system. The device must not contain a Ceph BlueStore OSD. The device must be larger than 5 GB. 簡而言之,大家需要準備新的HDD,不要做任何格式化,讓OS見到HDD但不作任何操作。筆者試過,使用hyper-v VM + hyper-v HDD,也是可以做到的。不過之前筆者於教學中用的 multipass 就沒有這個模擬HDD功能,我們需要使用比較強大的VM作為實驗。 若然HDD是在ceph cluster(cephadm bootstrap)建立之前,就存在的。我們可以經過ceph的網頁介面,或經指令自動加入。 ceph orch apply osd --all-available-devices 若然HDD是在ceph cluster(cephadm bootstrap)建立之後,才加入的。那麼ceph有機會沒法自動發現它,筆者當前的dev版本就出現這問題。我們就需要經指令手動增加 ceph orch daemon add osd NODENAME:/dev/sdb OSD 官方說明文件 https://docs.ceph.com/en/reef/cephadm/services/osd/#cephadm-deploy-osds Reset 在我們做實驗時,若我們想回復到上一個狀態,測試不同的參數差異,Ceph指令並不會即時執行。例如前一句的add osd,想倒回來自行刪掉一些osd,即 ceph orch osd rm OSDID 它就會排隊慢慢做刪除。 但這個過程筆者未有成功過,OSD一直處於繁忙狀態。有機會是因為系統需要保持同步狀態,待成功遷移資料前,什麼都不能動,所以一直都在待刪除的狀態中。 同樣地,當我們想要刪除一些node時,我們使用以下指令 ceph orch host drain NODENAME ceph orch host rm NODENAME 最後也是會卡在刪除OSD的情況 Removing Hosts 官方說明文件 https://docs.ceph.com/en/reef/cephadm/host-management/ Static IP 因為 container 技術,很多都需要固定 IP ,我們做實驗之前,最好先了解你的VM engine如果提供Static ip 。以 hyper-v 建立的 VM ,其實可以同時建立兩張網卡的,一張為預設網卡,用於連網用,另一張則設定為內部網絡。在安裝 ceph 時,經 cephadm bootstrap 所引用的IP則設定為內部網絡的IP。之後基本上使用任何一張網卡的 ip ,也可以訪問到cephadm的網頁介面。如果不是在一開始的階段上準備Static IP ,我們又會在重設/解綁cluster時,同樣因為機器繁忙而卡在不上不下的狀況。

純文字圖案 | 懶人出圖工具

科技新知
MacauYeah・2024-09-20

早前,筆者就介紹過 Markdown / mdbook 等說明檔編寫工具,也分享過用於制於遊戲攻略時,如何加上插圖的情況。那怕是教學、說明、遊戲攻略,使用圖表的方式表達,的確有助於讀者理解。 在Markdown的技術上,圖文並茂是可以的,只是不太方便而已。以制作及修改的成本來講,出【圖】可能都不算最難,更麻煩的是管理。 怎樣教對?點開圖檔整個閱讀?。怎樣搜尋圖片,可以加附註嗎?更新後名字該怎樣取? 老實講,如果可以,有些【圖】,直接經文字轉譯成圖表就最好。 mermaid Markdown 轉成圖,其實坊間早就有一些免費的工具,筆者選擇了 Github 也預設支援的 mermaid 。廢話不多說,直接送出 web 版的編輯工具。 https://mermaid.live/ mermaid 官網 使用它的好處 Github markdown 直接支援,mdbook經插件也可以使用。 易於編寫,也易於閱讀 有支援IT其他範疇的圖表,例如ER,State。 有支援更多其他範疇的圖表,例如gantt,mindmap。 使用它的問題 不支援手動調整位置,全部靠自動調整 ascii chart 若想要更多的位置掌控,其實我們可以回到過去BBS的年代,用文字方塊來砌圖。這個方法很有局限,但也不是完全不能用。 廢話不多說,直接送出 web 版的編輯工具。 https://asciiflow.com/#/ https://kirilllive.github.io/ASCII_Art_Paint/ascii_paint.html 可以選擇中文字符 使用它的好處 任意手繪圖表 使用它的問題 使用中文等字元,還要考慮是否等寛字型問題。 修改文字長度,邊界要重畫。 筆者有試過用來制作遊戲簡略地圖說明,這是比不斷截圖來要得更直觀。但限制就是不要在圖中加入文字,加入英數等符號就算了,再於其他地方加以解釋。如果我們必需在圖中使文字,我們就要控制輸出字型為等寛字型,例如使用【細明體】,就無問題了。不然就要全部使用中文字元(全型符號),不要混合英數。 .-=. .:*%%+.:. :#%%%%%+#. :#%%%%%%%%%%*. .*%%%%%%%%%%%%%%%*+-.. .-%%%%%%%%%%%%%%%%%%%%%%*:. .-%%%%%%%%%%%%%%%%%%%%%%%%%%-. .=%%%%%%*=-::::::::::::::-=#%%#: :#%%*-:::::::::::::::::::::::-*%+. .*#=-:::::::::::--=========-::::-#+. .=#==-::::-=*%%%%%%%%%%%%%%%%%%=::-#-. .#*==--#%%%%%%%%%%%%%%%#..#%%%%%+::**. :#+==#%%%=.+%%%%%%%%%#-:**::+%%%#-:=--*= .-+#*=+%%#.=%+.+%%%%%%%#--====*%%%#-::::-*. :*====+%%%%#.-%%%%%%%%%%%%-:+%%%%%*::::-*: .*=====#%%%%%%%%%####%%%%%%%%%%%%*::-%+. .:##==#%%%%+-:::::::::::--===-::::##. .##====-::::::::::::=#-:::::::-##. .*%*====---==+**#*+=::::::::+%+. .-#%#+====-:-----::::::-+%%#:. :#%%%%#*+===---+*%%%%%*. ..:=#%%%%%%%%%%%%%+:. ..::---:...

感謝賢者模型工作室 - 修復那些年還沒建好就斷樁的模型

手機‧電玩
MacauYeah・2024-09-13

不知道80、90後的朋友們,今年年初有沒有留意Gundam電影? 一向熱愛Gundam的朋友們,一定知道這套大熱作品Gundam Seed Freedom的出現。那是原本的Seed Destiny的後逐全身劇情,正因如此,玩具商也馬不停蹄地推出新模型。在電影加持的情況下,其實很多老模型,都推出重賣(再販)。筆者也不例外,在看過電影後的,不斷翻老模的格價。 不過,最佔上心頭的,並不是購買欲,而是筆者過去,有一台模型組裝到一半就斷臂的MG脈衝高達(Impluse Gundam)。 上網找模型群友求助,不外乎都是找補件或當殺肉(即係給他人當補件或改件用)。但這次勾起回憶,不如就來個修復吧,死馬當活馬醫,實在救不了,就當殺肉吧。 筆者的情況,是因為模型手臂連結點斷裂,用膠水是無法修復的。經一位網友的指點,這必需靠打樁修復。 打樁,基本上有三要素:手鑽(連鑽頭)、銅棒、萬能膠。萬能膠很易可以解決,在本澳各大超市及文具店均有售。手鑽(連鑽頭)、銅棒,就麻煩一點,五金店的都很大,不適合模型玩具用。當然,有何事,去萬能的淘寶就有售。 在淘寶購物車當下,筆者還是很猶豫。萬一買錯了怎辦?淘寶單價不貴,但運費可很要命。是不是找個懂修復的大師,幫忙看看情況,再由大師下單比較適合。 就是這樣,筆者就不斷在網路上找,到底澳門有沒有模型工作室。一找,還真有一家【賢者模型工作室】,主打噴塗裝備的工作室。當時筆者還厚顏地私信問店家,如果不噴塗只素組的話,有免費位置嗎?店家還很慷慨的回答,是的,素組不收費。收費部份,就是耗材購買、噴塗裝備租用。坐位上,只是租客優先。 所以筆者就在本年的八月份,去【賢者模型工作室】朝聖一下,順便帶著斷臂的脈衝,看看有沒有路過的大師幫忙指點一下。【賢者】就如當初對話中了解的一樣,主打噴塗。筆者雖然對噴塗了解不多,但見在場裝備,一定是專業級。賢者不單是提供上色工具,還解決了很多抽風問題,在家想要一個這樣安全的制作環境,一定價值不菲。因為家庭環境問題,放棄噴塗的朋友們,真的可以去【賢者】現場看一看,應該會有所得著。 說回筆者原本的脈衝高達,剛好當晚店長【賢者】在場,拿起筆者的模型細看了一翻,然後就講了一句:"簡單,我幫你修吧"。筆者原本還以為只是來取經,然後再逐一買工具,想不到熱心的店長,突然出手幫忙,實在喜出望外。 手鑽開孔 上銅樁,最後插入主體中 回家再組裝外肩甲,浴火重生 在整個修復過程中,慷慨的店長用的都是他自己的工具,只是他手中沒有已開封的銅樁,筆者就現場買一份吧,其餘一分錢都沒有收取筆者的。店長不但為筆者修復了模型,還省下了工具錢,還傳授了補樁的要點,筆者實在收穫巨大。想不到,澳門玩具業中,還有這麼良心的店存在,實在值得支持。 若然讀者們跟筆者一樣,因為任何原因,有一些未完成的作品(模型、GK),不妨一齊帶上去【賢者】,看看模友們能不能為你帶來新的方向。店長不一定在店,有需要可以加入他們的交流群,打聽一下店長的駐店時間。交流群也不會有店家的推銷產品,不過群友們會推坑團購,大家要管好自己的心。 【賢者模型工作室】 官方專頁 https://www.facebook.com/insmws/

排版之於文字創作者的重要性

手機‧電玩
MacauYeah・2024-09-05

筆者已經很少再買遊戲相關的書藉,一來因為筆者已漸漸遠離遊戲新作,二來發現某些紙媒的資訊瑕疵越來越多,所以就沒有再看。但因為家裏土地資源問題,筆者需要再斷捨離一些收藏,所以就再拿起舊的遊戲雜誌來重新審閱。 說實在,在過去、現在,很多傳媒的資訊都無法確認正確性,其資訊價值難似證明,但某些紙媒一直存在至今,一定是有些地方,很受市場歡迎。那些地方,大家也不妨去借鑑一下,或者對自己的作品會有幫助。 之前某一期,筆者也表明過,UCG的攻略有著抄襲問題,所以筆者已不再購買他們的新攻略。但重翻他們家的百期特輯,內容的確不錯。 主題的選擇 作為百期特輯,他們會選擇一些回顧的主題。而這些回顧也的確實表現出時間的演變。 排版 現時網絡資訊,品質好的,會配以圖文表示。但因為結構單一,所以新鮮感不足。最差的什至會滿頁廣告,閱讀感很差。但以百期特輯的雜誌式的排序,每頁配圖位置稍有不一,亦有主題轉變,風格相似又不盡相同,真的耐看。 匯整 雖然資訊不能保證百分百正確。但以匯整的角度來說,有一讀的價值。好比ChatGPT,它的資訊也不是完全正確,但它可以省略你在搜尋引擎中四處查看、逐一對比的過程。 對於各位文字創作者,有條件,當然可以嘗試以圖文方式豐富視覺內容。那怕沒有時間挑圖,也可以試試定制不同章節的排版風格,來讓故事/文章變得比較有過程的變化或是段落感。 不過,說到尾,筆者並不是對抄襲問題作出認同,我們應對原創有更多的支持,抄襲只會讓原創更難生存。但某些二次整理,也有它的價值。就像筆者的知識分享一樣,重複以不同的方式,更易理解的角度,去重述一些議題,倒是不會嫌多。

推坑SFC的神作

手機‧電玩
MacauYeah・2024-09-03

因為年紀漸大,筆者玩遊戲的機會越來越少。一方面是因為家庭,一方面則是因為身體大不如前,腦袋開始跟不上3D遊戲的場境,常常不是玩一玩就累了,就是玩一玩就暈了,那怕連手遊都一樣。 所以筆者現在什少會再開新坑試新世代遊戲,反而專注在舊世代中,體驗一下過去的名著。值得一提的是,過去的遊戲體量通常比較少但完整,對於繁忙的生活節奏,是適合的。相比手遊,舊世代的遊戲更無抽蛋要素,更沒有那種玩個空虛的感覺。所以若然大家主機有買會員,趁會籍到期之前,快試一試那些年被你跳過的遊戲,應該有所收獲。 今日筆者就選了NS online會員的SFC舊遊戲,《薩爾達 眾神的三角力量》。只要大家有NSO,應該都可以順利重玩這個遊戲。 向大家推坑這遊戲的原因主要有幾個。 薩爾達 Switch 兩作稱霸天下。過去的作品,很值得一試。 眾神的三角力量是平面遊戲,不會暈,而且 Switch 隨時待機,玩玩停停沒有壓力。 玩後的優點: 那個古早的年代,已經發展出到處鼓勵四處探索的玩法。那怕只是2D平面,都感覺到世界的大。 攻略好找好看。薩爾達在 Switch 中的最後兩,好玩歸好玩,但攻略真的難攪,難以用文字來表達。即使各大出版社如何編制圖文包,還不如直接看影片攻略來得直接。眾神的三角力量,那怕筆者不看圖,筆者也知道攻略制作人想表達的意思和方向。不知道下一步去哪?不用怕,看一看網上攻略就攪掂。 偏向動作遊戲,穿插少量劇情。筆者過去都是接觸以劇情量為主的JRPG,以現在的生活形態,要好好地讀完一個新的JRPG故事真的很難。 沒有壓力。這真的很重要。Switch 兩代,都有一個很麻煩的資源系統。武器、道具、盾,都是會快速消耗的。除非大家對操作很有信心,不然每次戰鬥,那怕打贏了,也會覺得消耗過多,選擇重讀存檔重打。這樣的遊戲玩下去很有壓力,跟魂系遊戲有得比。多磨幾次,人也會累。但SFC 舊作,只有副武器為消耗性。你的劍和盾,可以一直用,副武用光,誰怕誰。 參考連結: 筆者遊玩時看的攻略(https://lasjargon.blogspot.com/2014/12/legend-of-zelda-link-to-past-chapter01.html?m=1),雖然覺得不全,但至少讀得懂 由 本封面圖像可由任天堂處取得。, Fair use, https://zh.wikipedia.org/w/index.php?curid=7663843

為何Python這麼熱門?

科技新知
MacauYeah・2024-08-27

在資料處理、資料科學領域,什麼是最近的AI模型,Python都是做這些事的熱門選擇。對於以前從未用過Python來處理業務的筆者來講,實在不懂為何Python會那麼大熱。不過最近,筆者實戰過後,真心覺得它是提高生產力的重要工具,而且並不限於資料科學上面,一些簡單的腳本操作也是很有優勢的。 筆者前述有討論過 型別對程式語言的重要性,到現時這一刻,筆者都會覺得【型別】是有助於長期的程式開發。而Python這個語言,大部份人都會介紹它是動態語言,可以使用弱型別,然後,就沒有其他講法了。動態弱型別,筆者一直都不認為它的根本上的原因。就像Javascript一樣,它亦發展出類靜態強型別的Typescript版本,而且它亦不因此而被人棄用。所以Python的強大,動態語言並不一最重要的原因,它也可以模疑寫出有規有距的type hinting。 或者用另一個方向問,大家覺得 Excel / SpreadSheet 好用嗎?它們可以很簡易地做出資料計算、篩選。而且可以一邊做,一邊調整公式。例如要大家做一個陣列的總和,大家會想打開一個Javascript,初始化陣列的每個數字,然後寫個For迴圈去計算總和嗎?還是打開 Excel / SpreadSheet,打下一欄或一列的數字,然後叫出Sum函數?筆者一定會選擇後者,不單止因為寫函數比較方便,那怕之後要調整數字,也比較方便。 大家有感受到差異嗎?筆者想表達的是,在操作 Excel / SpreadSheet 我們並不是整個程式重新執行一次,我們是修改完一部份,那上看到結果。但傳統的語言,例如C、Java、那怕是Javascript,我們都難以局部地更新或執行特定某一個區塊。那怕是現在我們有hot reload,但其實我們編寫的思維,都是讓我們完整執行起一個頁面,再人手輸入,看結果。如果我們只想運行某個單一Function函數,我們只能寫test case測試,但寫test case又是一個很大的入門門檻。 但大家如果看看Python,在古早的年代,Python已經有Python shell,那就像是Linux Shell或Window CMD一樣,可以一邊寫腳本,一邊看結果。寫了10行的程式,發現在第10行引用第5行的部份有問題,修正並執行第5行後,就可以回來馬上重跑第10行的語句,就馬上有結果了。第6至9行,因為沒有關聯性,就不需要逐一重新執行,那是多麼的方便阿。道理上,我們若沒有完整執行整個程式,可能還是有一些盲點,開發重要的,需要長期維護的程式,還是要像傳統一樣,有test case,有程式進入點,整個運行。但對於臨時性的操作,看看效果,我們實在無必要寫一個原整程式。 舉個例子,假如我們臨時有需要,要取得某個政府網站的即時數據,例如澳門的停車場資訊,空位的上下限是多少,我們絕對可以用python寫幾行就取得結果,然後順便做個資料運算。我們沒有必要很嚴僅地為考慮不同數據的出現情況,我們什至可以hard code - 硬編碼地計算某個Array的元素。直到突然有一天,這個操作變得恆常化,我們還是有條件把之前的python程式碼,改寫成一個規規矩矩的完整腳本,包括異常處理,函數複用。(其實Javascript在改用 NodeJs 作為引擎後,我們還是可以經過 Node.js REPL,來做互動操作,只是Python Shell出現得更早,也是官方支援的功能。) Python這個臨時操作的便利,對於資訊爆炸的年代來講,實在很幫得上忙。再加上現在除了Python Shell以前,還有Jupter Notebook,讓大家可以在Web頁面上,執行像Python Shell的互動操作,對於修過特定區域的程式碼,就更加方便。這些便利,都是不是因為動態語言來創造的優勢,而是實實在在的Coding Anywhere。