自動更新 Linode Object Storage SSL/TLS憑證

前一篇文章,我們了解了如何自訂Linode Object Storage的網域,但因Object Storage需要自己手動上傳SSL憑證,且Let’s Encrypt的憑證90天會到期,因此每到即將過期的時間,勢必就得再手動更新一次。因此,這篇就要繼續來了解,如何自動更新憑證。

首先,我們上次安裝的certbot,會自動排程更新憑證,確保憑證不會過期。而我們要做的就是,將certbot更新後的 fullchain.pem 與 private.pem 透過Linode的API重新上傳到Linode。

於是,我寫了一個nodejs的小工具,來專門處理這件事情。在開始之前,先用 node -v 確認一下是否有安裝 nodejs 並且版本 > 16.20。

  1. 請在之前的教學中,安裝了certbot的那台機器中 clone我的這個repo,執行:git clone git@github.com:boggyjan/linode-object-storage-cert-updater.git
  2. 接著進入linode-object-storage-cert-updater目錄,執行:npm i,安裝相依套件
  3. 複製兩個sample config成為真正的config:
    • 執行:cp pm2.config.cjs.sample pm2.config.cjs
    • 執行:cp updater.config.js.sample updater.config.js
  4. 修改 updater.config.js
    • 填入Linode API Token,可到這裡新增
    • 在certs陣列裡修改成你的 region, bucket名稱,以及這台機器中存放憑證的地方 certPath
    • 範例中為兩個bucket,可視需求新增或移除
  5. 啟動自動更新,因需讀取etc目錄中的檔案需root權限,請用root身份執行pm2:
    • sudo su root
    • pm2 start pm2.config.cjs
  6. 設定開機就執行:pm2 startup && pm2 save

Linode Object Storage 自訂網域設定與大阪region Cyberduck設定

Custom Domain 步驟

開好 Linode 的 Object Storage 之後,常常覺得網址有夠長,查了一下自訂網域的方式。跟 AWS 比起來麻煩多了,還要自己用 Certbot 手動建立 ssl 憑證,而這也意味著會遇到無法自動更新憑證的問題。之後會再介紹用 API 更新憑證的方法,這篇的重點就先放在整個設定的步驟。

設定 Object Storage 的自訂網域,因為會需要用到 certbot 手動驗證,需要仔細檢查每個步驟是否都有確實完成再進行下一步,不然很有可能會在驗證步驟重做很多次。請依照以下的步驟進行設定:

  1. 先建立一個Bucket
    1. Label名稱填寫網域名稱,例如static.abc.com。目前僅能支援子網域
    2. Bucket Access設成Public Read
  2. 到網域設定新增CNAME
    1. hostname 打static
    2. alias to static.abc.com.{這邊填你的object storage的region,例如jp-osa-1}.linodeobjects.com
  3. 接下來要使用certbot建立ssl憑證
    1. 輸入 certbot certonly –manual
    2. 輸入網域 static.abc.com
    3. 在bucket中建立.well-known資料夾,在.well-known資料夾中建立acme-challenge資料夾
    4. 把顯示的code跟指定的檔名上傳到bucket的 .well-known/acme-challenge 資料夾裡,如圖:
    5. 將該檔案的ACL設成Public Read
    6. 回到certbot按下Enter開始驗證
    7. 驗證完成後,會產生金鑰檔案在/etc/letsencrypt/live/static.abc.com資料夾中
    8. 首先執行 cat /etc/letsencrypt/live/static.abc.com/fullchain.pem 複製所有內容
    9. 貼入 bucket 內頁的 SSL/TLS Certificate文字框
    10. 再執行 cat /etc/letsencrypt/live/static.abc.com/privkey.pem 複製所有內容
    11. 貼入 bucket 內頁的 SSL/TLS Private Key文字框
    12. 送出後即可

繼續設定自動更新憑證

大阪 Region 的 Cyberduck 設定

因為目前(2023年9月)Preference > Profile 裡面目前還沒有 Osaka Region 的 Linode 可選,但還是可以連線,請依照以下的步驟進行設定:

  1. 不要點選新增連線,點主畫面左下角的加號
  2. 選擇 Amazone S3
  3. 伺服器填寫:jp-osa-1.linodeobjects.com
  4. 輸入金鑰:
    1. 請先到 Object Storage > Access Keys 建立金鑰
    2. 將金鑰儲存在本機
    3. 填入 Access Key
    4. 填入 Secret Key
  5. 路徑需要先隨便填一個存在的 bucket 的名稱,例如:static.abc.com
  6. 這樣就完成設定了。關閉編輯視窗後,在列表上剛剛建立的項目上點兩下即可
  7. 要變換同一個region中的bucket,請選上方下拉選單的 / 就會出現所有bucket

[歌詞翻訳] Workin‘ Hard – 藤井風

掻っ攫った(かっさらう 「さらう」の乱暴な言い方) 圧巻(あっかん)でらした あらら 世は実に易し
信じ切った 安心し切った あたた 深き喜び
戦うは なぎ倒すは か弱い己自身さ
やり切って胸はって 綺麗に散るのさ~

奪得獎杯了 壓軸的驚人之舉 哎呀 這世界就是這麼簡單
徹底相信 徹底鬆了口氣 溫暖又深刻的喜悅
戰爭要打倒的是軟弱的自己
抬頭挺胸戰到最後 然後美麗地殞落

みんなほんまよーやるわ めっちゃがんばっとるわ
わしかて(=私も)負けんよーに(=負けないように)な ひそかに何かと努めるわ
なんも無くたっていいや 結果なんぞかったりーわ(かったりー=かったるい=麻煩、疲倦、累)

我真的很佩服大家 非常努力工作著
我也不能輸 默默地在各方面努力
就算什麼都沒有也無所謂
結果什麼的煩死了

Better sit back
Take a deep breath
And you’ll know…

你最好坐下放鬆
做個深呼吸
然後你就會明白

You’ve been workin’ hard
Workin’ hard
Maybe you don’t understand
But I know that you’re
Workin’ hard
Workin’ hard
Wish I could give you a hand
Baby you’ve been
Workin’ hard
Workin’ hard
Trust the process and be brave
You’ve been workin’ hard
God you’ve been workin’ hard

你一直努力著
很努力
也許你不懂
但我知道你
很努力
很努力
希望我能幫助到你
寶貝 你一直很努力
很努力
很努力
相信這個過程然後勇敢起來
你一直很努力
老天 你一直很努力

Let’s sit back, time to relax
鼓動に任せて自由に踊って
Bow down, show them respect
敵も味方もここにはねえから
Sit back, time to relax
鼓動に任せて自由に踊って
Bow down, show them respect
敵も味方もほんまはねえから

讓我們坐好放鬆,是時候放鬆了
隨著你內心的鼓動自由舞動
鞠躬 讓他們表示尊敬
因為在這裡沒有敵人沒有夥伴
讓我們坐好放鬆,是時候放鬆了
隨著你內心的鼓動自由舞動
鞠躬 讓他們表示尊敬
因為在這裡沒有敵人沒有夥伴

みんなほんまよーやるわ めっちゃがんばっとるわ
わしかて負けんよーにな ひそかに何かと努めるわ
なんも無くたっていいや 結果なんぞかったりーわ

我真的很佩服大家 非常努力工作著
我也不能輸 默默地在各方面努力
就算什麼都沒有也無所謂
結果什麼的煩死了

Better sit back
Take a deep breath
And you’ll know…

你最好坐下放鬆
做個深呼吸
然後你就會明白

You’ve been workin’ hard
Workin’ hard
Maybe you don’t understand
But I know that you’re
Workin’ hard
Workin’ hard
Wish I could give you a hand
Baby you’ve been
Workin’ hard
Workin’ hard
Trust the process and be brave
You’ve been workin’ hard
God you’ve been workin’ hard

你一直努力著
很努力
也許你不懂
但我知道你
很努力
很努力
希望我能幫助到你
寶貝 你一直很努力
很努力
很努力
相信這個過程然後勇敢起來
你一直很努力
老天 你一直很努力

All we gonna do is to make you happy
All we gonna do is to make you lucky
All we gonna do is
All we gonna do is to make you make you feel alive

我們能做的是讓你開心
我們能做的是給你幸運
我們能做的是…
我們能做的是讓你覺得自己活著

What we gonna do is to make you feel good
What we gonna do is to make you feel ah
It’s all about others
It’s all about brothers
Together we can touch the sky

我們能做的是讓你覺得很好
我們能做的是讓你覺得… 啊
一切都關係到大夥
一切都關係到夥伴們
大家聚在一起 我們便可以觸碰到天空

Cuz you’ve been workin’ hard
Workin’ hard
Maybe you don’t understand
But I know that you’re
Workin’ hard
Workin’ hard
Wish I could give you a hand
Baby you’ve been
Workin’ hard
Workin’ hard
Trust the process and be brave
You’ve been workin’ hard
God you’ve been workin’ hard

因為你一直努力著
很努力
也許你不懂
但我知道你
很努力
很努力
希望我能幫助到你
寶貝 你一直很努力
很努力
很努力
相信這個過程然後勇敢起來
你一直很努力
老天 你一直很努力

*「よーやるわ」是關西腔,可用於褒/貶的情境,歌詞中是褒的情況,意思為「我真的很佩服大家」。若是貶意時為「你還敢做這種事啊」
延伸:よう言うわ = よく言えるね 你少來、你還真敢說啊

[筆記] Critical Render Path 與 Reflow, Repaint

Critical Render Path

讀取 html => 產生 DOM Tree => 產生 CSSOM Tree => 產生 Render Tree => Layout => Paint => Compositing

Layout做的事情

依照樣式表與元素的可視與否,計算每個元素的尺寸、位置

Paint做的事情

繪製每個Layout的文字、顏色、圖片、透明度、transform。也就是把Layout轉為實際視覺上的結果。

Compositing做的事情

組合所有的Layout

Reflow是什麼意思

當我們改變了元素的位置、大小、可視性,會需要重新回到 Critical Render Path 的 Layout 步驟,重新計算所有元素,這個耗費的資源的行為叫做 Reflow。

Repaint

當我們改變了字色、圖片路徑、透明度、transform…等等,因不會影響到元素的真正位置與大小,我們僅需要重新繪製畫面即可,這個行為叫做 Repaint。

[歌詞翻訳] 地球儀 – 米津玄師

僕が生まれた日の空は
高く遠く晴れ渡っていた
行っておいでと背中を撫でる
声を聞いたあの日

在我出生的那天
天空又高又遠晴空萬里
我聽見了那天你輕拍我的背
一邊說了「去吧!」

季節の中ですれ違い
時に人を傷つけながら
光に触れて影を伸ばして
更に空は遠く

在季節中擦身而過
有時一邊傷害人
一邊碰觸光線讓影子投射
天空更遠了

風を受け走り出す
瓦礫を越えていく
この道の行く先に
誰かが待っている
光さす夢を見る いつの日も
扉を今開け放つ
秘密を暴くように
飽き足らず思い馳せる
地球儀を回すように

迎著風奔跑
越過瓦礫
在這條路的盡頭
有人在等待著
無論何時都能夢見光線照射的夢
現在把門敞開
像是要暴露秘密一樣
不厭其煩地讓想法奔馳著
彷彿轉動地球儀一般

僕が愛したあの人は
誰も知らないところへ行った
あの日のままの優しい顔で
今もどこか遠く

那個我愛的人
去了沒人知道的地方
帶著那天的溫柔表情
如今仍在遙遠的某處

雨を受け歌い出す
人目も構わず
この道が続くのは
続けと願ったから
また出会う夢を見る いつまでも
一欠片(ひとかけら)握り込んだ
秘密を忘れぬように
最後まで思い馳せる
地球儀を回すように

淋著雨唱出來
也不在意他人眼光
這條路會繼續延續
是因為我祈求著他繼續延續
無論何時都能夢見我們再相遇
緊握著一個小碎片
像是不要忘記秘密一樣
讓想法奔馳直到最後
彷彿轉動地球儀一般

小さな自分の
正しい願いから始まるもの
ひとつ寂しさを抱え
僕は道を曲がる

這是從我許下的一個小小的真心的願望開始
帶著一份孤獨
我改變了方向

風を受け走り出す
瓦礫を越えていく
この道の行く先に
誰かが待っている
光さす夢を見る いつの日も
扉を今開け放つ
秘密を暴くように
手が触れ合う喜びも
手放した悲しみも
飽き足らず描いていく
地球儀を回すように

迎著風奔跑
越過瓦礫
在這條路的盡頭
有人在等待著
無論何時都能夢見光線照射的夢
現在把門敞開
像是要暴露秘密一樣
能觸碰到彼此的手的喜悅
與必須放手的悲傷
不厭其煩地去描繪
彷彿轉動地球儀一般

[歌詞翻訳] ガーデン – 藤井風

鳥は春を告げて
私は恋をして
素敵な温度だけ
触れさせて この肌で

鳥兒捎來春的的消息
我正墜入愛河
只讓這美好的氣溫
觸碰這肌膚

雲は夏を帯びて
私は目を閉じて
綺麗な時間だけ
追いかけて 尽きるまで

雲朵帶著夏天的氛圍
我閉上雙眼
只追逐著這美好的時間
直到結束

花は咲いては枯れ
あなたに心奪われ
それでも守り続けたくて
私のガーデン 果てるまで

花朵綻放然後凋謝
我的心被你奪取
即便如此我仍想繼續守護著我的花園
直到最後

人は出会い別れ
失くしてはまた手に入れ
それでも守り続けたくて
私のガーデン 果てるまで

人生就是相遇又離別
失去了又會再次得到
即便如此我仍想繼續守護著我的花園
直到最後

夜が秋を呼んで
私は旅に出て
素敵な出会いだけ
待っていて その日まで

夜晚呼喚著秋天的到來
我踏上了一段旅程
只等待著美好的相遇
直到那一天

だから冬よおいで
私を抱きしめて hey
その手の温もりで
生きさせて 溶けるまで

所以,冬天請來吧
緊緊抱住我 嘿
用那雙手的溫度讓我活著
直到溶化為止

花は咲いては枯れ
あなたに心奪われ
それでも守り続けたくて
私のガーデン 果てるまで

花朵綻放然後凋謝
我的心被你奪取
即便如此我仍想繼續守護著我的花園
直到最後

人は出会い別れ
失くしてはまた手に入れ
それでも守り続けたくて
私のガーデン 果てるまで

人生就是相遇又離別
失去了又會再次得到
即便如此我仍想繼續守護著我的花園
直到最後

季節に身を置いて
流れに身を任せ
なるようになるだけ
受け入れて そのままで

置身在季節之中
讓身體隨波逐流
隨遇而安
就這樣地接受一切

流した涙だけ
ふりまいた愛だけ hey
豊かになる庭で
掴んだ手 解き放て 空の果て

只有流下的眼淚
只有我播下種子的愛 嘿
在要變的豐富的庭院裡
握緊的手放開了 天空的盡頭

Whoa, ooh, yeah
Ah-ah-ah, ah-ah-ah, ah-ah-ah, ah-ah

屋~~屋~~~嗯嗯
啊~~~啊~~~哈啊~~~啊~~~

花は咲いては枯れ
あなたに心奪われ
それでも守り続けたくて
ガーデン 果てるまで

花朵綻放然後凋謝
我的心被你奪取
即便如此我仍想繼續守護著我的花園
直到最後

人は出会い別れ
失くしてはまた手に入れ
それでも守り続けたくて
私のガーデン 果てるまで

人生就是相遇又離別
失去了又會再次得到
即便如此我仍想繼續守護著我的花園
直到最後

Nuxt Hydration Fails – SSR與CSR的比對錯誤

在 Nuxt 中,當我們 refresh 頁面時,寫在 data 或 computed 中的程式碼,在 server 端與 client 端都會各執行一次,並且在前端會進行html tag的比對,若兩者不相符會噴錯,甚至沒有辦法進行接下來的操作。

因此,當我們用了 new Date().getTime(), Math.random() 這類的程式碼在data中,是一定會造成錯誤的。甚至 new Date().getDay() 也是有可能,因為 server time 有很大的可能性,跟 client 端的時區不同。最後我們再來看看如何解決,我們先來看看相同的程式碼,在 Nuxt2 與 Nuxt3 分別會導出怎樣的結果。

建立測試頁面

我們先分別開 Nuxt2 與 Nuxt3 兩個環境,分別給 Nuxt2 & Nuxt3 建立一個 Option API 的頁面,原始碼如下:

<template>
  <div>
    Test Render Error
    <hr>
    <div v-if="isMonday">
      isMonday: {{ isMonday }}
      <hr>
    </div>

    <button
      type="button"
      class="btn"
      @click="doSomething()"
    >
      doSomething()
    </button>
  </div>
</template>

<script>
export default {
  data () {
    const isMonday = process.server
      ? new Date(new Date().getTime() - 18 * 60 * 60 * 1000).getDay() === 1
      : new Date().getDay() === 1

    console.log(isMonday)

    return {
      isMonday
    }
  },

  methods: {
    doSomething () {
      console.log('doSomething()')
    }
  }
}
</script>

isMonday 的部分為了在 server 模擬不同時區,給他 new Date(new Date().getTime() – 18 * 60 * 60 * 1000).getDay() === 1,而 client 端就是 new Date().getDay() === 1,這部分各位在測試時,可以依照時間做調整。

另外我們在,Nuxt3環境中,另外建立一頁 Composition API 的頁面,用於測試 Composition API 是否會得到不同的結果,原始碼如下:

<template>
  <div>
    Test Render Error
    <hr>
    <div v-if="isMonday">
      isMonday: {{ isMonday }}
      <hr>
    </div>

    <button
      type="button"
      class="btn"
      @click="doSomething()"
    >
      doSomething()
    </button>
  </div>
</template>

<script setup>
const isMonday = process.server
  ? new Date(new Date().getTime() - 18 * 60 * 60 * 1000).getDay() === 1
  : new Date().getDay() === 1

console.log(isMonday)

function doSomething () {
  console.log('doSomething()')
}
</script>

測試結果 Nuxt2 與 Nuxt3 結果大不同

在 Nuxt2 的開發環境中,若發生render錯誤,會出現類似下圖的錯誤訊息,但 method 還是可被執行

而在正式環境中,情況就比較不妙。當發生錯誤時,會出現下圖的錯誤訊息,雖然 NuxtLink 還可以正常換頁,但 call method 時卻毫無反應。假設我們的頁面主要功能都是以 methods 做反饋,一但 render 錯誤,這一頁就會死掉。也就是說,在測試環境中若沒注意到錯誤訊息、沒有解決,在正式環境中會導致使用者無法操作。

而在 Nuxt3 中,無論是用 composition API、option API ,無論是正式或是測試環境,都可以正常運作,僅僅在測試環境會噴警告而已,如下圖:

下圖是 Nuxt3 正式環境,一樣可以執行 doSomething()

下圖是 Nuxt3 測試環境,我們可以看到,即使 isMonday 與前台不同,給了 false,還是沒有造成前台會無法繼續操作的嚴重錯誤。

結論

目前看起來,這種情況的 render 錯誤,需要在 Nuxt2 上多加注意,一個不小心可能會導致使用者無法操作的這種低級錯誤,而在 Nuxt3 上目前沒有看得出來的影響。

Nuxt2的解決方式

如前述,在 Nuxt 中,當我們 refresh 頁面時,寫在 data 或 computed 中的程式碼,在 server 端與 client 端都會各執行一次。因此,我們可以用 asyncData 來設定有用到 Math.random(), new Date().getTime() 這類的資料,這樣 refresh 時就不會在 client side render 時重複跑一次。當然,在只有 client sider render 的換頁情況下也不會有問題。

PM2 watch 造成的無限迴圈

pm2 的 watch 是用於監聽檔案變動,自動重啟服務的一個功能。我們可以透過在 pm2.config.js 檔案中設定 watch: true 來開啟此功能。這樣一旦進了新 code 就會自動重啟,不用手動 pm2 restart {id} 非常方便。

但也就是因為這麼方便,所以常常會忘了他的存在。

前陣子做了一個透過排程,自動到某處去下載json檔案回來存放,再提供一隻API來吐出篩選過的資料的小工具。在開發環境完成後,一樣就很順手的在正式環境用PM2跑起來。

但卻不知道為什麼,每次Call API的時候,並非都成功,常常遇到噴 500 的狀況。為此還一直驗證程式碼的各個細節,但卻找不到原因。此時我執行了 pm2 stop {id},然後再重啟 pm2 start {id},卻發現剛剛的問題消失了!

當過了幾天,我用 pm2 status 發現,這個專案的 pm2 watch 不知道為什麼變成 disabled,於是我將它先 delete,再重新用 pm2 start pm2.config.js 重啟,這時候 watch 就恢復正常了。

但這時候竟然又發生之前那個會噴 500 的狀況!!!

當我打開 PM2 monit 的時候才發現原來他一直在被反覆關掉重啟、關掉重啟…,此時才意識到應該是 watch 的關係。

這個工具每次啟動時,就會直接去拉一次資料。再來會用排程每天去拉資料。而 watch 機制在啟動後抓完資料存檔完畢時,偵測到檔案變動,就又立刻重啟。重啟後因為又再一次執行下載檔案,pm2又再次偵測到檔案變動,因此再次重啟。就這樣變成無限迴圈的抓資料然後重啟。

但為什麼之前先 pm2 stop {id} 後再 pm2 start {id} 會正常呢?因為在這個情況下,watch會被關掉。要透過 pm2 start pm2.config.js 才會啟動 watch。

回到問題本身,該如何解決不要 watch 特定目錄的的問題。很簡單,只要在 pm2.config.js 裡加上 ignore_watch: [‘你想忽略的目錄’]即可,例如:

module.exports = {
  apps: [
    {
      name: "App Name",
      script: "npm start",
      watch: true,
      ignore_watch: [".temp"],
      env: {
        ...
      }
    }
  ]
}

在dockerfiles中使用aws ecr image

這篇文章主要是筆記如何在本機使用AWS ECR上已存在的image,以及所需要的驗證方式。

首先到AWS ECR選擇你的repo,進入映像列表後選擇一個映像,在內頁複製他的URI,像是:735675645655.dkr.ecr.ap-northeast-1.amazonaws.com/my_project:23f4b2a。打開你的Dockerfile,將FROM後面的映像名稱改成這個URI

接下來,docker需要登入aws,才有權限可以取得aws ecr上的映像。這邊我們需要先安裝aws cli,並透過aws cli來登入。請依照下面的步驟進行:

  1. 安裝 aws cli
  2. 到AWS IAM 選擇使用者,然後從列表中選擇自己的帳號,進入內頁
    • 在「許可」頁籤的「政策」中新增ECR
      • 在「安全憑證」頁籤中新增「存取金鑰」,完成後選擇「下載CSV」
  3. 回到 command line 執行 aws configure
    • 在剛剛下載的CSV中,複製 Access Key ID 與 secret access key 並貼入
    • 完成後會發現在 .aws資料夾中已被建立了一個 cretencial 檔案
  4. 驗證登入:執行 aws ecr get-login-password | docker login -u AWS --password-stdin "https://$(aws sts get-caller-identity --query 'Account' --output text).dkr.ecr.ap-northeast-1.amazonaws.com"(黃色底色處改成你的origin
    • 成功後會顯示 Login Succeeded

登入成功後,我們就能照平常的指令 docker-compose -f docker-compose.yml up 來執行image了。

補充

透過aws cli取得最新的image tag,請輸入:

aws ecr describe-images --repository-name 儲存庫名稱 --query 'sort_by(imageDetails,& imagePushedAt)[-1].imageTags[0]' --output text | head -n 1

虎蘭市的貓咪祭典:一場別具風味的活動

每年的11月,在日本埼玉縣的虎蘭市,都會舉行一個別具風味的祭典「にゃんにゃん祭り」(喵喵祭)主題也就是貓咪。這個祭典吸引了大量的遊客和當地居民,讓他們能夠欣賞到一場獨特而令人興奮的活動。這個祭典集結了山車遊行、攤販市集和寵物認養活動,讓人們能夠在這一天與貓咪們共度美好時光。

一到了祭典的那一天,整個虎蘭市都被貓咪的氛圍所包圍。大街小巷裡,隨處可見以貓咪造型為主題的山車或花車,有些以傳統山車的形式呈現,但都以貓咪為靈感,栩栩如生。山車會以貓奔跑的速度高速在街上來回奔馳,給人一種刺激又有點小小的危險的感覺。也因此,拉山車的工作人員在活動開始前,都要先上虎蘭山上祈求貓神保佑,以確保活動的順利舉行。

除了山車遊行,祭典的晚上更是一個精彩的時刻。主要會場設有一個巨大的貓咪造型帳篷,吸引了眾多的遊客。在這個帳篷裡,聚集了各式各樣的攤販,販賣的商品也都與貓咪有關。你可以找到貓咪手掌造型的鯛魚燒,或是貓耳朵造型的豆皮烏龍麵等等,這些美食都充滿了趣味和創意,絕對能夠滿足你的味蕾。

除了美食之外,這個帳篷還舉辦寵物認養活動,給想要收養寵物的人們提供一個機會。當然,除了可愛的貓咪之外,你還可以找到其他的動物,例如老虎和豹。這些動物是由當地的多個動物保護組織負責收留與照顧。

看完連我都想去了呢!但很可惜的是,這只是一場夢,根本沒有這個活動,連虎蘭市這個地方都是瞎掰的,這篇文章全都是用AI做出來的假旅遊文,千萬不要跑去結果落空呦!

鳥羽周作出軌事件道歉全文翻譯

皆樣

この度は、私の軽率な行動によって世間をお騒がせしており、誠に申し訳ございません。
一部報道のあった広末涼子さんとの件についてお詫びをさせてください。

各位,這次因為我輕率的行為造成騷動,誠摯的向大家道歉。
有一些關於我跟廣末涼子的報導,我深表歉意。

まず、報道された内容は、概ねその通りです。
多くの方にご迷惑をかける行為だと頭では理解していながら、
相手のご家族や自分の家族、 周りの皆様にどういうことが起こるのかを想像できないまま、
僕は冷静な判断を欠く行動をしました。

首先,被報導的內容大致上就是這樣沒錯。
雖然我理解這個行為會造成很多人的困擾,
但仍然沒對想到會對對方的家庭或自己的家庭、周遭的人造成怎樣的事情,
我在欠缺冷靜的判斷之下,做出了這樣的行為。

すべては、 僕の弱さ、 社会に身を置くひとりの人間としての未熟さに原因があります。
ご迷惑をおかけしたすべての方々に心よりお詫びいたします。
誠に申し訳ございませんでした。

全都是因為我的懦弱且不成熟所造成的。
對於所有被我帶來困擾的人,我誠心道歉。
真的非常抱歉。

広末さんのご家族や関係者の皆様、お店のお客様やクライアント様、スタッフなど、
多くの方に大変なご迷惑をおかけしてしまいました。
今後、心を尽くし、誠意が伝わるまで、お詫びをしてまいります。
そして、自分の家族には、 夫として、父として、本当に愚かな姿を見せました。
今後家族に対して、できるかぎりの償いをしていきます。

廣末小姐的家庭或各位相關人,店裡的客人與客戶、店員等等,
不小心給這麼多人帶來這麼大的困擾。
今後,我會盡我最大努力道歉,直到我的誠意傳達到。
然後,對於我的家庭,身為丈夫、身為父親,真的讓他們看到我愚昧的行為了。
今後對於家庭,我也會盡力補償他們。

もうひとつ、皆様にお詫びしなくてはいけないことがあります。
最初に報道があったときに、 不倫の事実はない、 と嘘をついたことです。
知らない番号からかかってきた電話に出たところ、
記事に掲載されていた通りの内容の質問をされ、事実に反する受け答えをしてしまいました。 自分の弱さ、そして何よりずるさが出た結果です。 深く反省しています。

還有一件事情想跟各位道歉。
一剛開始報導出來時,我謊稱了不倫不是事實。
當時,不認識的電話打過來
我被質問了報導中的內容,不小心做了與事實相反的回答。
這是因我的狡猾與懦弱所導致的結果。我深刻的反省中。

今後は、改めてゼロから料理に向き合いたいと思います。
自分が一番世の中にできることは何かと考えましたが、 やっぱり料理しかありませんでした。 少しずつでも、失った信用を取り戻せるよう、努力を重ねてまいります。

今後,我想從零開始面對料理。
我思考了我在這個世界上能做些什麼?但我就只會料理而已。
我會不斷努力,拿回我失去的信任,即使只有一點點也好。

最後に、お願いができる立場でないことは重々承知しておりますが、
幼い子供や妻など、 家族への取材や接触はお控えいただけますよう、
取材関係者の方々のご配慮をお願い申し上げます。

最後,雖然我完全知道我沒有任何立場拜託各位,
希望各位不要採訪或接觸我還小的孩子跟妻子等家庭成員,
感謝各位記者朋友的關心。

2023年6月14日
鳥羽周作

[歌詞翻訳] Higher Love – MISIA

届け higher love
この手にhigher love
この身の中に宿る確かな愛を引き上げて
届け higher love
その手にhigher love
二度ともう離したくないの
So give me higher love

傳遞吧,至高無上的愛
將至高無上的愛傳遞到這雙手
將這體內的真愛提升
傳遞吧,至高無上的愛
將至高無上的愛傳遞到這雙手
我不想再離開一次了
所以,給我至高無上的愛吧

この声を誰に届けよう
行き場のない寄る辺もない沈む私へ

這個聲音要傳遞給誰
請傳遞給無處可去,無依無靠,鬱悶消沈的我

この体を誰に委ね(ゆだねる)よう
汚れのない終わりのないあなたへ

把這個身體託付給誰
託付給一塵不染永生的你

遥か遠く遠く
いるような気がしてたけど
本当はいつも一緒だったのね
深い眠りから
目を覚ました今
静かにあなたに叫びます

雖然注意到了你好像在遠方
但因為我們的心一直都在一起
從深沈的睡眠
甦醒過來的現在
我靜靜地向你呼喊

届け higher love
この手にhigher love
この身の中に宿る確かな愛を引き上げて
届け higher love
その手にhigher love
何度も転んで私見つけたの
だからもう離したくないの
So give me higher love

傳遞吧,至高無上的愛
將至高無上的愛傳遞到這雙手
將這體內的真愛提升
傳遞吧,至高無上的愛
將至高無上的愛傳遞到這雙手
因為你好多次找到了跌倒的我
所以我不想再離開了
所以,給我至高無上的愛吧

この声をどこに響かそう
救いのない光もない暗闇の中へ

讓這個聲音在某處響著
深入無助且黑暗的深淵中

この体を誰に委ねよう
汚れのない終わりのないあなたへ

把這個身體託付給誰
託付給一塵不染永生的你

遥か遠く遠く
いるような気がしてたけど
本当はいつも一緒だったのね
深い眠りから
目を覚ました今
静かにあなたに叫びます

雖然注意到了你好像在遠方
但因為我們的心一直都在一起
從深沈的睡眠
甦醒過來的現在
我靜靜地向你呼喊

届け higher love
この手にhigher love
この身に与えられし果てしなき道かけ抜けて
届け higher love
その手にhigher love
何度も転んで私見つけたの
だからもう離したくないの
So give me higher love

傳遞吧,至高無上的愛
將至高無上的愛傳遞到這雙手
跑過這條被賦予在身上的無盡的道路
傳遞吧,至高無上的愛
將至高無上的愛傳遞到這雙手
因為你好多次找到了跌倒的我
所以我不想再離開了
所以,給我至高無上的愛吧

何も知らぬまま 何度も傷ついたけど
先なんて見えなかった
雲に覆われた世界をはらってくれたものは

雖然在不知不覺之中,被傷了好幾次
我看不到前方
幫我撥開雲霧世界的人是(你

自行修正Site Kit AdSense錯誤

我部落格的網址是用子網域,先前裝Site Kit的時候,已經驗證過AdSense。但最近不知道何時開始,卻出現以下的畫面,告訴你要完成設定。但不管怎麼點,卻都會顯示錯誤。

以下是出現錯誤的流程

下圖是點選Site Kit > Setting之後出現的畫面。在已連接的服務中,AdSense的區塊右邊顯示了一顆要你完成設定的按鈕 “Complete setup for AdSense”。

點選之後,就會開始跑進度條

但最後會顯示錯誤:Invalid site state null

即使回到Setting這邊,把AdSense移除,再連接一次也是會失敗

解決方法

我本來以爲錯誤訊息”Invalid site state null”中的這個site state是指我的部落格有什麼問題,但我看控制台 > 工具 > 網站狀態的測試結果,似乎也沒有什麼奇怪的地方。

於是打開瀏覽器Console重新跑一次剛剛的流程。當我按下”Complete setup for AdSense”時,會call一隻API “/wp-json/google-site-kit/v1/modules/adsense/data/sites?accountID=pub-xxxxxxxxxxxxx&_locale=user”,這隻API會去AdSense撈所有我設定的網域。

但我記得今年三月還四月的時候,AdSense「網站」單元改版,從那之後應該就沒有設定子網域的地方了,但API撈回來的卻包含了子網域,且在這份資料中,我其他所有子網域的state與autoAdsEnabled 跟錯誤訊息一樣是顯示null。那就有可能猜中問題了!

於是我打開了外掛檔案編輯器,找到 “google-site-kit/third-party/google/apiclient-services/src/Adsense/ListSitesResponse.php” 在 getSites function 裏面針對剛剛部落格的那個subdomain給了autoAdsEnabled = true(允許自動廣告)與state = “READY”(網站驗證狀態)。

public function getSites()
{
    $this->sites[1]['autoAdsEnabled'] = true; // 自動廣告
    $this->sites[1]['state'] = 'READY'; // 網站驗證狀態
    // 上面兩行的 $this->sites[1] 的1要改成剛剛API中部落格網域的索引
    return $this->sites;
}

再重新去點一次”Complete setup for AdSense”,這次API所回的內容就會是被我們修改過的內容。

接著就會顯示連結成功的畫面了!

連結成功之後,記得回到外掛檔案編輯器把剛剛修改的東西復原。

這個方式只建議給之前就連結AdSense且成功的人這樣做,我想應該只是Site Kit驗證AdSense網域的部分沒有同步到改版後的AdSense網域規則。不過不處理其實好像也都很正常,只是看到有個提示在那邊,真讓人不舒服啊。

2023/06/14 更新

過沒幾天 “Complete setup for AdSense” 又出現了… 這次我改完外掛並且complete setup之後,先不移除,看看之後會怎樣。

[歌詞翻訳] 三国駅 – aiko

もしもあなたがいなくなったら
あたしはどうなってしまうだろう?
持ち上がらない位(くらい)に
首をもたげて泣くのかなぁ

若你不在了
我會怎樣呢?
我大概會頭抬不起來
然後哭了吧

寒さに堪えきれずに
温もり求めた先に
あなたの指と腕がある
それでいい それだけでいい

抵擋不完的寒冷
尋找溫暖的地方
那個地方有你的手指跟手臂
那樣就夠了,只要那樣就夠了

毎日が昨日の様だったのに
なにを焦っていたの?
変わらない街並み
あそこのボーリング場
焦っていたのは自分で
煮詰まってみたり 怖がってみたり
繋いだ手を離したくない

明明每天都跟昨天一樣
我在焦急什麼?
不變的街景
那邊的保齡球場
焦急的是我自己一個人陷入僵局、感覺害怕
不想放開握住的手

「苦しい時は助けてあげる
だから安心しなさい」
自由に舞う 声がする
それでいい それだけでいい

「當你痛苦的時候,我會幫助你,所以請你放心」
聽到自由盤旋的聲音
那樣就夠了,只要那樣就夠了

息を吸おうとする意志
真っ直ぐに あなたを見つめる為
育ってく小さな心を
見落とさないでね
少しならこぼしていいけど
スカート揺れる光の中の
あの日に決して恥じない様に

想深呼吸的念頭,是為了要直直地注視著你
請不要忽視了我雖然小小的,但慢慢在長大的愛
流出一點眼淚也沒關係
希望裙擺搖曳的光線中的那一天不會出糗

変わらない街並み
あそこのボーリング場
焦っていたのは自分で
煮詰まってみたり 怖がってみたり
繋いだ手を離したくない

不變的街景
那邊的保齡球場
焦急的是我自己一個人陷入僵局、感覺害怕
不想放開握住的手

指折り数えた
芽吹いた日々と2人の
帰り道

掐指算了
發芽的這些日子
與我們兩個人的歸途

[歌詞翻訳] 青春病 – 藤井風

青春の病に侵され
儚いものばかり求めて
いつの日か粉になって散るだけ
青春はどどめ色
青春にサヨナラを

被青春病侵襲
只追尋曇花一現的東西
我們有天都會化作塵土飛散
青春是黑紫色
再見了青春

ヤメた あんなことあの日でもうヤメた
と思ってた でも違った
僕は 自分が思うほど強くはなかった
ムリだ 絶ち切ってしまうなんてムリだ
と思ってた でも違った
僕は 自分が思うほど弱くはなかった

放棄了 那種事情,我以為我在那天就已經放棄了
但不是的
我沒有我想的那麼強
沒辦法 我以為沒辦法就這樣跟我的青春一刀兩段
但不是的
我沒有我想的那麼弱

君の声が 君の声が
頭かすめては焦る
こんなままじゃ こんなままじゃ
僕はここで息絶える

你的聲音 你的聲音
每次掠過我的腦海 都讓我著急
再這樣下去的話 再這樣下去的話
我會死在這裡

止まることなく走り続けてきた
本当はそんな風に思いたいだけだった
ちょっと進んでまたちょっと下がっては
気付けばもう暗い空

從未停下,持續地跑到現在
我以前真的只是想要這樣想
稍微前進了一些,就又後退了一點
注意到時,已經天黑

青春の病に侵され
儚いものばかり求めて
いつの日か粉になって散るだけ
青春はどどめ色
青春にサヨナラを

被青春病侵襲
只追尋曇花一現的東西
我們有天都會化作塵土飛散
青春是黑紫色
再見了青春

そうか 結局は皆つながってるから
寂しいよね 苦しいよね
なんて 自分をなだめてるヒマなんて無かった

是嗎,最後大家都一樣
很寂寞吧,很痛苦吧
連對自己說這類的安慰自己的話的時間都沒有

君の声が 君の声が
僕の中で叫び出す
耳すませば 耳すませば
何もかもがよみがえる

你的聲音 你的聲音
在我體內呼喊
注意聽的話 注意聽的話
萬物將會復甦

止まることなく走り続けてゆけ
何かが僕にいつでも急かすけど
どこへ向かって走り続けんだっけ
気付けばまた明ける空

從未停下,持續地跑到未來
老是有東西在催促著我
有點忘記我本來是要跑向哪邊?
注意到時,又是天亮

無常の水面が波立てば
ため息混じりの朝焼けが
いつかは消えゆく身であれば
こだわらせるな罰当たりが

若在無常的水面起了漣漪
混入了嘆氣聲的朝霞
若軀體終將消失
這就是使我不拘泥的原罪

切れど切れど纏わりつく泥の渦に生きてる
この体は先も見えぬ熱を持て余してる
野ざらしにされた場所でただ漂う獣に
心奪われたことなど一度たりと無いのに

在即使斬斷卻還是糾纏著的泥沼漩渦中活著
這個身體剩餘太多看不見未來的熱情
明明我的心即使一次都沒有對被丟在荒野遊蕩的野獸著迷

青春のきらめきの中に
永遠の光を見ないで
いつの日か粉になって知るだけ
青春の儚さを
Oh oh oh oh oh oh
Ah ah ah

在青春的耀眼光彩中
別看那永恆的光芒
只知道我們有天都會化作塵土
青春的稍縱即逝…
Oh oh oh oh oh oh
Ah ah ah