安裝並配置 Fcitx 輸入法

OS: Ubuntu20.04 LTS

剛剛手賤重裝了我的 Ubuntu 系統,发現自帶的輸入法 ibus 中文體驗極差,故更新一篇安裝 fcitx 加配置主題的教程。

iBus 重新定義了 “垃圾”

下載安裝 fcitx

# fcitx-rime 屬於繁體輸入法,可選安裝
sudo apt install fcitx fcitx-googlepinyin fcitx-rime fcitx-module-cloudpinyin

apt 會自動把 fcitx 以及其依賴裝上。

注意! 某些直接安裝 fcitx-googlepinyin 其實是將 fcitx 作為依賴裝上了,這樣會導致依賴樹的關系雜亂,可能在未來 (你想刪除谷歌拼音的時候造成不可預料的事故)

接著輸入以下命令並按照提示配置輸入法為 fcitx.

im-config

現在重啟系統, 重啟完成之後應該可以看到 fcitx 將 ibus 取而代之了。
現在可以卸載 ibus.

sudo apt purge ibus

配置 中州韻

中州韻 不是默認在輸入法列表里,你需要點擊左下角的加號添加。(之後按 Ctrl + Shift 添加。)
而且我發現中州韻比簡體的谷歌拼音真的要好用太多,強烈推薦。

請在這裏下載輸入法的附加詞庫。

請看這裏配置模糊音方案:

如果你想要針對中州韻輸入法的某一個輸入方案(比如明月拼音),你需要在 ~/.config/fcitx/rime/ 目錄下新建一個專門的 yaml 來配置。比如說 朙月拼音的yaml 可以是 luna_pinyin.custom.yaml , 格式請見Github.

以下配置我希望全局生效,所以在 default.custom.yaml 中配置如下幾行:

# default.custom.yaml
patch:
  # 候選詞個數
  "menu/page_size": 9 

(模糊音請參照正則的語法進行查找替換,我是南方人分不清前鼻音後鼻音,所以配置這兩行。如果你不明白正則的語法請點擊 模糊音 參考大神配置。)

# luna_pinyin.custom.yaml
patch:
  # 模糊音
  'speller/algebra':
    - erase/^xx$/  

    # 模糊音定義
    - derive/([ei])n$/$1ng/            # en => eng, in => ing
    - derive/([ei])ng$/$1n/            # eng => en, ing => in

配置主題

主題配置的話我推薦以下這個主題 (個人感覺比較清爽,你也可以自己選擇。)

目前deepin論壇抽風訪問不了,等恢復訪問後我會繼續把步驟補上。
deepin論壇已經恢復訪問,我將兩款主題的壓縮包連同網頁archive放在我的網盤裏了,鏈接就在下方,請自取~

原帖地址: 點擊前往深度BBS論壇
原帖備份: 點擊前往web.archive.org
附件下載: 點擊從博客網盤下載 alaph 亮色主題
附件下載: 點擊從博客網盤下載 darkK 暗色主題

deepin論壇已經翻修完畢,恢復訪問了。這裏是我找到的使用體驗最好的兩款主題,由同一個大神製作,主題取自搜狗。
是的fcitx 是可以裝 搜狗輸入法的,但是出於一種奇怪的心理,我不想讓國產軟件姦污我這一台乾淨的linux機,所以沒有選擇裝 搜狗輸入法。

兩款可愛的主題截圖

請將兩款主題解壓後分別拷貝到 /usr/share/fcitx/skin/ 目錄下。

安裝 Tor 瀏覽器

OS: Ubuntu20.04 LTS

我主要用 tor 來測試我的網站的部署情況和打開一些不太好打開的網站。(很奇怪,像膜乎之類的網站即使在牆外也打開很慢,但是一掛上 Tor 速度就立馬飛起來。)

網上有相當一部分教程建議從軟件源安裝 tor 瀏覽器, 然而我記得在 Tor 官網上聲稱從軟件源獲取的 Tor-Brower 使用了 Tor 軟件包作為依賴, 但是 Tor 已經很長時間沒有更新, 存在安全隱患, 因此強烈不推薦, 所以我直接從官網下載安裝. 理論上之後 Tor-Browser 都能自動更新, 無需這樣手動安裝.

下載安裝 Tor

請猛擊 Tor 官網鏈接點擊 Linux 按鈕自行下載。

下載完畢後,在檔案所在目錄執行以下操作。

tar -xvJf tor-browser-linux64-10.0.2_en-US.tar.xz
sudo mv tor-browser_en-US/ /opt
sudo chown -R $USER:$USER /opt/tor-browser_en-US/
./start-tor-browser.desktop --register-app

配置完畢之後你可能需要重啓設備。

Tor-Browser 已經能夠啓動了

如果你的代理在歐美,建議直接鏈接到 tor 網路。如果你的代理在日韓, 你可能需要使用網橋。不建議在大陸直接使用tor ( 又被重點關注的風險 ) , 而網橋在大陸也被 Ban 的差不多, 請搭配雙重代理獲得最佳手感.

偶然發現學長的機場

今天剛剛基友告訴我說,他发現了一個 “疑似是我校大神” 搭建的機場。 我正好無聊,就去瞄了幾眼。。。將結果記錄在這里,覺得還蠻有意思的。

首先把我 無聊隨便 幹出來的結果放在這里,聊勝與無嘛…


  • 機場名稱: 2MB Cloud
  • 機場地址: 2mb.network
  • 真实IP: 47.57.13.58(阿里云)
  • 注冊時間: 2020年三月29號
  • 注冊站點: namecheap
  • 托管服務: cloudflare
  • 機場框架: sspanel + malio 主題
  • 建站框架: 寶塔 (8767 端口)

機場框架是從 /staff頁面看出來的。。現在的機場基本都是用sspanel做的,主題是malio 的都會有這個staff頁面,還不給刪,煩的一忒。

網站截圖:

可以看出來,首頁斌沒有太大的變化。上面那個tofel和頁腳的幾個友連都直接指向自己,沒有什麽好玩的。網站並沒有綁定TG.

Whois截圖

基本沒什麽有用的信息。(別去定這個玩意的包年套餐,說不定域名一到期就跑路,just kidding…)

然后通过对这个网站443端口的证书进行全网搜索,可以搜出来这个服务器的真实地址是 47.57.13.58

所以说这个看到的机场是用阿里云搭建的吗…真的不怕被喝茶吗?
然后就没有意思了。我和他无怨无仇,也不打算进行下一步,大概率也不可能成功(以我的半吊子水平)。那就先点到为之吧,希望这位老兄耗子尾汁,别用lets encrypt的证书了–用cloudflare的服务器证书+clouflare的代理服务难道他不香吗?(你的阿里云服务器地址都给人扒出来了,怕不是别想混了哦)

PS: 我還沒有這個網站的邀請碼,回頭問朋友要一下。下面是基友的截圖。

我不知道這是什麽鬼,不過服務名稱好像就是在瞎填。。。

C語言多線程編程實戰

我沒有專門學習過多線程,非常可能有更簡單的方法,我說了一大堆廢話只是繞了遠路。不過這次嘗試中應該還是有很多自己的感悟的,所以如果你是大神,覺得很滑稽,這個家夥寫得都是什麽垃圾啊,笑一笑就好啦 : ) 如果你是和我一樣的小白,歡迎共勉共同進步。

想要實現一個Text UI (我對命令行情有獨鐘,因為我做不出圖形界面) ,要控制光標同時繪制多個區域以及時響應。那麽這個就很明顯用到多線程了,奈何我對多線程一竅不通,於是…

  • 這是我理想中的窗體:
  • 實際畫出來的效果是這樣的:

這一坨坨條形碼,讓我頓時感到世界對自己充滿了惡意…

第一次排錯

這個其實很明顯。控制台的標準輸出就一個,多個線程控制著光標滿屏亂跑,A線程抱著光標鉆到草叢里還沒幹事請呢就被B線程橫刀奪愛,最後搞出來的東西自然是誰都不像。

我於是用了一個隊列,思路是這樣的:

  • 新建一個隊列q,函數queLock()、函數queUnlock()、Bool類型變量queueLock
  • 當A函數想要執行敏感操作(比如修改同一個變量)的時候,就去使用queLock()。這個函數會給它添加一個標識到隊列尾部。然後不斷檢查隊列頭和queueLock,如果queueLock變成false且隊頭輪到這個標識符了,就瞬間取出這個標識符然後鎖上queueLock
  • 當敏感操作完畢後,用queUnlock取消queueLock的鎖。
  • 這就相當於queLock()暫時鎖住了這個線程。雖然降低了部分效率,但是還是可以體現多線程的優勢的。

我的代碼是這樣的。

bool queueLock=false;
int ident=0;
queue<int> q;
inline void queLock(){
    int id=++ident;
    q.push(id);
    while(1){
        if(!queueLock&&q.front()==id){
            queueLock=true;
            q.pop();
            return;
        }
    }
}
inline void queUnlock(){
    queueLock=false; //inline會在編譯的時候直接插入代碼,因此無需擔心調用費時。
}

這應該解決了吧?

然鵝…

基本沒有變化!

圖樣圖森破啊!

第二次排錯

經過研究,我終於发現了問題所在。如果你正在看(且你不是我),你估計早就发現問題了。

int id=++ident;

這個完美無缺的函數第一行就出現了問題。

這個操作先給ident+1,然後將此時的ident賦值給id。這個連在一起寫可能看不出來,那麽我分開。

//上面的代碼等價於:
ident++;
int id;
id=ident;

這就很明顯了吧。另外一個線程完全有可能在前兩行或者後兩行中間橫插一腿。

所以這個id放在這里就是個花瓶。等於把問題從stdout的訪問沖突轉嫁到了ident的訪問沖突上。確實訪問效率更高了,但是沒有從根本上解決問題。

解決方案其實也很簡單。關鍵在於ident訪問沖突,這個ident是幹什麽的啊?用來區別線程的。區別線程我幹嘛要專門弄一個標識符,這不是畫蛇添足嗎??

直接上改正過的代碼了。

bool queueLock=false;
queue<HANDLE> q;
inline void queLock(HANDLE hThread){ //排隊+加鎖
    q.push(hThread);
    while(1){
        if(!queueLock&&q.front()==hThread){ 
            queueLock=true;
            q.pop();
            CloseHandle(hThread); 
            return;
        }
    }
}
inline void queUnlock(){
    queueLock=false;
}

經過這次調整,效果很明顯。发生問題的幾率降低了50%,錯亂也含蓄了很多,從大塊錯亂變成了標題移位。

還是不給力啊!百分之五十算個毛線??標題移位算個毛線???

第三次排錯

經過又一翻的 苦(拔) 思(禿) 冥(頭) 想(发) ,終於OK了。

仔細看下第二次的代碼,先留出一炷香的時間思考那里有問題。



想出來了嗎?

這個if語句看起來與世無爭,屬於誰都不會去考慮的類型,在一般的程序中是絕對沒有任何問題的。但是這是多線程編程,即使代碼寫的再緊湊,每條語句中間還是有延遲的。

上面的if語句可以拆解成下面的語句:

//與上面的語句等價
if(!queueLock){  //第一個判斷 
    if(q.front()==hThread){ //第二個判斷
            queueLock=true;
            q.pop();
            CloseHandle(hThread); 
            return;
    }
 }
inline void queUnlock(){
    queueLock=false;
}

那麽,如果甲線程在執行第一個判斷的時候,丙線程剛剛執行完畢,把queueLock給取消掉了。這個時候甲和乙齊頭並進,都完成了第一重判斷。這個時候甲線程率先完成第二重判斷並pop掉了自己,於是乙再次完成第二重判斷,和甲線程一起進入了多線程狀態。
(這里的乙可以換成任意一個非甲線程,丙丁戊己庚辛 隨便那個都可以。在這個程序里面肯定有一堆線程等著要出這個頭。)

解決方案就是,把if中的兩個條件調換一下順序。理解了BUG存在的原因,那麽怎麽去掉他就非常容易了。

代碼我就不貼了,直接貼圖我方便,你看著也方便。

那麽這樣運行出來之後就穩定的得到了本文的第一張圖,多次測試沒有變過,應該是成功了。

現在可以來驗證一下我的猜想,到底是不是這樣。

如果我的猜想成立的的話,那麽這個BUG发生的條件是”同時存在三個及以上的線程“。我於是去掉了一個線程(框框)反覆嘗試,確實,一直都沒有发生問題。

為什麽出現錯誤時只有標題移位我還沒有搞清楚。我猜想是系統提供的輸出函數會使用自己的方法去後移坐標位置,方法應該比我的SetCursorPosition()更加基礎,也更快一點。這種速度跟我的慢速沖突了,所以系統的輸出爭先恐後的湧到前面來導致了錯亂。

總結

在這個程序里我完成的事請事實上是在特定條件下把並行改為並发,用了隊列的這個結構。隊列中其實同時存在的元素上限恒等於同時存在的進程數上限。這個是使用了隊列結構的特性。

第一個問題(第零次排錯)的发生,只是用來作為本文的開頭提出問題的。可以對問題有個直觀認識,我畢竟還沒蠢到那個程度。

第二個問題(第一次排錯所引发的)是沒有認清楚解決問題的本質。我實際上幹了轉移問題的操作,而沒有從實質解決問題。問題從進程搶光標變成了進程搶標識符。

第三個問題(第二次排錯所引发的)是沒有細節。多線程編程是很講究細節的,if判斷還是建議分開來寫,不然大大延長出現bug後拔頭发的時間。

而且多線程編程還是對調試不太友好的(特別是命令行情況下)。你不能開一個調試窗格去搞它,你一開,結果又不一樣了。你不能去增大延時去仔細看輸出順序,因為你開延時之後就沒問題了。這個有點像薛定諤的貓,開箱之後你最終只能看到貓的死活,你看不到貓是怎麽死掉的。所以處理這種問題的時候還是建議自己開思維導圖逐行的推斷,給自己大腦編個碼,也許問題就解決了。

後話

剛剛发現,手動的一遍遍穩定性測試弱爆了….

其實如果真的要測試到底有沒有問題,寫一個線程不停搶資源就是了。

void cpu_eater(void*){
    while(1){
        queLock(getHandle());
        queUnlock();
    }
}
int main(void)  
{  
    _beginthread(win_playlist,0,NULL);
    _beginthread(win_menu,0,NULL); 
    _beginthread(win_progressbar,0,NULL);
    //下面是搶資源線程
    _beginthread(cpu_eater,0,NULL);
    _beginthread(cpu_eater,0,NULL);
    _beginthread(cpu_eater,0,NULL);
    //上面是搶資源線程
    sleep(LIFETIME_DELAY);
    return 0;  
}

一旦有問題,在三個線程不停跟他搶資源的情況下肯定立即就暴露出來了。這樣可以非常方便的一遍檢出問題。我剛剛寫完才发現有此等操作,真是冤煞我的Ctrl+F5。

下面是開了三個搶資源線程的動圖。

還蠻美觀的蛤。(這就完全沒問題了)

思考題

留一道思考題。

如果你不像我這樣戰五渣就試試看這道題。

上面的代碼我通過修正判斷的順序解決了問題。但是我如果不去修正判斷順序,而是修正執行順序,即:

調換這兩行順序,能不能一樣達成目的呢?

(偷偷透露下,不行。)

那麽為什麽不行呢?

答案:image-20200407183057649

自製 Goose 愚人節小病毒

愚人節前我亂翻小衆軟件,突然發現了這個東西,於是就有了靈感:
點擊前往: Desktop-Goose 小衆軟件

這是什麽

程序全屏運行示意圖

這是一個可以瘋狂啓動上述 呆鵝 的小程序,只有按照指令敲入句子才可以將其關掉。
簡而言之,這是一個 啓動器,用來啓動和關閉 Goose 程序,僅此而已。

技術細節

整個程序是我用蹩脚的 C++ 編寫的,使用了 辣鷄 DevC++ ,因此你可以猜到這個東西跑起來是什麽樣子。
代碼比較凌亂。而且因爲我是趕出來的,直接一個文件解決問題,相信我你絕對不會想要去讀這個代碼的 🙂

Debug 模式下可以看到 Daemon

一些值得 Mark的 小技巧有:

  • 適當使用了 Windows Api, 實現了自由控制 文字顔色 和窗口 全屏
  • 用命令控制開啓和 一次性 關閉所有進程
  • 不同的 啓動參數 可以改變程序的行爲
  • 可以通過改變 預編譯 命令 來決定程序的惡心程度
  • 簡單的多綫程實現
  • 開啓了一個 守護進程 來檢查並阻止關閉程序(守護進程也無法關閉)
  • 檢測到嘗試關閉程序會有 懲罰
  • 長時間沒有輸入也有懲罰(多綫程實現)
  • 隱藏了一個 “上帝指令” 允許優雅的關閉程序

下載程序

在下載前,你需要知道:

  • 壓縮包裏只有 文本文件和圖片資源,你需要自己編譯 main.cpp
  • Goose程序需要分別下載,下載完之後放到程序的同級目錄

Goose: 跳轉至官網
程序源碼: 點擊下載

程序沒有任何的傳播性(不會自我複製),隱藏性(不會僞裝),破壞性(不會讀寫其他文件),且不會自動運行(若想達到這一點你可以讓程序自己複製到啓動),因此嚴格來説這個東西并不能被稱作病毒。請在編譯前仔細閲讀代碼,確定沒有問題后運行,一切後果 雨我無瓜.

病毒一般具有 传播性、隐蔽性、感染性、潜伏性、可激发性、表现性或破坏性, 一般具有兩種即以上就可以被稱作電腦病毒。具體請參考 維基百科 – 計算機病毒的特徵