This commit is contained in:
2024-01-21 15:44:48 +08:00
parent 3618328a0b
commit 33b475a3a0
23 changed files with 12 additions and 927 deletions

3
.gitignore vendored
View File

@@ -1,3 +1,4 @@
public public
resources resources
.hugo_build.lock .hugo_build.lock
themes/*

View File

@@ -1,237 +0,0 @@
---
slug: "[C++ 筆記] Lambda"
title: "[C++ 筆記] Lambda"
description:
toc: true
authors:
- awin
tags:
- c++
categories:
- Programming
series:
- C++ 筆記
date: 2019-12-15T00:00:00
lastmod: 2019-12-15T00:00:00
featuredVideo:
featuredImage:
draft: false
enableComment: true
---
一個簡單的 Lamdba 運算式:
```cpp
[] (int x, int y) -> bool {
return x < y;
}
```
<!--more-->
- 以中括號開頭,中括號被稱為*lamdba 導入器lamdba introducer*
- 小括號裡面是*lamdba 參數列表lambda parameter list*
- 如果沒有參數,小括號可以省略,`[] () {...}` 可以簡寫成 `[] {...}`
- 箭號(`->`)後面是回傳的型別,如果沒寫就由 `return` 自動推斷
將 Lamdba 運算式指定給變數:
```cpp
auto comapre = [] (int x, int y) -> bool {
return x < y;
};
```
## Lamdba的擷取子句
以中括號開頭的 *lamdba 導入器* 可以將外部的變數傳給 Lamdba 運算式正式名稱是「擷取子句capture clause」。
`[=]` 表示它們會以值擷取captured by value。Scope內的變數可以在 lamdba 內使用,但是不可以改變。
`[&]` 表示它們會以參考擷取captured by reference。Scope內的變數可以在 lamdba 內使用,可以改變。
## 以值擷取captured by value
假設有一段程式如下:
```cpp
void testLambda() {
float notUsed = 1.0f;
std::vector<int32_t> numlist{10, 20, 30, 50, 60};
auto findInRange = [=](int32_t start, int32_t end) {
for (auto num : numlist) {
if (num >= start && num <= end) return true;
}
return false;
};
std::cout << "Result: " << findInRange(25, 35) << "\n";
}
```
`[=]`可以用來擷取 lamdba scope 範圍所及的變數,沒有在 Lamdba 運算式裡面被用到的變數就不會被擷取,例如 `float notUsed = 1.0f;`
另一個重點是:**被擷取的變數是不可以更改的**。例如,不能在 lambda 裡面這樣寫:
```cpp
auto findInRange = [=](int32_t start, int32_t end) {
numlist.push_back(5); // ERROR!
for (auto num : numlist) {
if (num >= start && num <= end) return true;
}
return false;
};
```
如果一定要在 lambda 內改變擷取的變數,那必須指名 lambda 為 `mutable`
```cpp
auto findInRange = [=](int32_t start, int32_t end) mutable { // <-- assign mutable
numlist.push_back(5);
for (auto num : numlist) {
if (num >= start && num <= end) return true;
}
return false;
};
```
根據書上解釋 ,可以裡解為 compiler 會將 lamdba 編為一個 class像是
```cpp
class __Lambda8C1A5 {
public:
__Lambda8C1A5(const std::vector<int32_t>& arg1) : numlist(arg1) {}
auto operator()(int32_t start, int32_t end) const { // const!
for (auto num : numlist) {
if (num >= start && num <= end) return true;
}
return false;
}
private:
std::vector<int32_t> numlist;
};
```
這也解釋了 lamdba 的擷取範圍與原理。而 `mutable` 則是讓 `operator()` 不為 `const`,如下:
```cpp
auto findInRange = [=](int32_t start, int32_t end) mutable { // <-- assign mutable
numlist.push_back(5);
for (auto num : numlist) {
if (num >= start && num <= end) return true;
}
return false;
};
...
class __Lambda8C1A5 {
public:
__Lambda8C1A5(const std::vector<int32_t>& arg1) : numlist(arg1) {}
auto operator()(int32_t start, int32_t end) { // No const here
for (auto num : numlist) {
if (num >= start && num <= end) return true;
}
return false;
}
private:
std::vector<int32_t> numlist;
};
```
## 以值擷取特定的變數
若只需要擷取特定的變數,那就直接在 lamdba 導入器(就是`[]`)寫入變數名稱,例如:
```cpp
int var1 = 10;
int var2 = 20;
int var3 = 30;
auto afunc = [var1, var2] () {
...
};
```
## 以參考擷取captured by reference
`[&]` 會擷取 scope 內的所有外部變數,而且可以修改:
```cpp
void testLambda() {
float notUsed = 1.0f;
std::vector<int32_t> numlist{ 10, 20, 30, 50, 60 };
auto findInRange = [&](int32_t start, int32_t end) { // Use & here
numlist.push_back(100); // OK
for (auto num : numlist) {
if (num >= start && num <= end) return true;
}
return false;
};
std::cout << "Result: " << findInRange(25, 35) << "\n";
std::cout << "numlist: ";
for (auto n : numlist) {
std::cout << n << " ";
}
std::cout << "\n"; // Output numlist: 10 20 30 50 60 100
}
```
## 以參考擷取特定的變數
但是直接參考全部的外部變數不是好的作法,這讓你有機會做出一些意外的修改,所以請擷取有需要的變數就好:
```cpp
void testLambda() {
float notUsed = 1.0f;
std::vector<int32_t> numlist{ 10, 20, 30, 50, 60 };
auto findInRange = [&numlist](int32_t start, int32_t end) {
numlist.push_back(100); // OK
for (auto num : numlist) {
if (num >= start && num <= end) return true;
}
return false;
};
...
}
```
如果有多個變數需要擷取,那就用 `,` 分開:
```cpp
auto findInRange = [&numlist, &var1, &var2](int32_t start, int32_t end) {
...
};
```
## 混合擷取
以值擷取跟參考擷取也可以寫在一起:
```cpp
auto findInRange = [=, &numlist](int32_t start, int32_t end) {
...
};
```
上面的例子中,`numlist` 會是參考擷取,其他的外部變數則是以值擷取。
或是:
```cpp
auto findInRange = [&, numlist](int32_t start, int32_t end) {
...
};
```
上面的例子中,`numlist` 會以值擷取,其他的外部變數則是參考擷取。
但是,如果已經使用了 `=` ,就不可以再以值擷取其他變數,像是 `[=, numlist]` 就是不合法的。
反之,如果已經使用了 `&`,就不可以再參考擷取其他變數,像是 `[&, &var1]` 就是不合法的。
## 存取 class
Lamdba 寫在 class 裡面的時候,不論[「以值擷取 」](#以值擷取captured-by-value)或是[「以參考擷取」](#以參考擷取captured-by-reference)都沒辦法傳遞成員變數member variable只能傳遞 `this`,透過 `this` 來存取成員變數。例:
```cpp
class BigBuffer {
public:
void modify(int x, int y, ...) {
auto modifyBuffer = [this] () { // Use this
if (buffer) { // equal to this->buffer
// do something with buffer
}
};
...
}
private:
uint32_t bufferSize = 0;
std::unique_ptr<uint8_t[]> buffer = nullptr;
};
```

View File

@@ -1,234 +0,0 @@
---
slug: "[C++ 筆記] rvalue reference"
title: "[C++ 筆記] rvalue reference"
description:
toc: true
authors:
- awin
tags:
- c++
categories:
- Programming
series:
- C++ 筆記
date: 2019-12-08T00:00:00
lastmod: 2019-12-08T00:00:00
featuredVideo:
featuredImage:
draft: false
enableComment: true
---
rvalue 是指:
- 等號右邊的值
- 臨時的值,例如運算的結果
- 無法被取址address-of的物件
<!--more-->
## rvalue reference
一般的參考只能參考[[lvalue]]如下的程式是ok的
```cpp
int a = 10;
int& b = a;
```
但是像這樣就不行了:
```cpp
int a = 10;
int b = 5;
int& c = a + b;
```
因為`a+b`是一個 rvalue臨時的值沒辦法取址所以無法參考。
但是可以用`&&`來參考 rvalue。例如
```cpp
int a = 10;
int b = 5;
int&& c = a + b; // c = 15
```
而不用這樣:
```cpp
int a = 10;
int b = 5;
int r = a + b;
int& c = r;
```
了解 rvalue reference 之後,就可以實作類別的 move constructor 跟 move assignment operator。這可以減少複製的成本。
## Move constructor
假設我們有一個 class 叫 BigBuffer定義如下
```cpp
class BigBuffer {
public:
BigBuffer(int size=100*1024*1024) :
bufferSize(size)
{
std::cout << "BigBuffer constructor\n";
this->buffer = std::make_unique<uint8_t[]>(bufferSize);
}
~BigBuffer() {
std::cout << "BigBuffer destructor\n";
}
BigBuffer(const BigBuffer& src) {
std::cout << "BigBuffer copy constructor\n";
bufferSize = src.bufferSize;
buffer = std::make_unique<uint8_t[]>(bufferSize);
std::memcpy(buffer.get(), src.buffer.get(), bufferSize);
}
BigBuffer& operator= (BigBuffer& src) {
std::cout << "BigBuffer copy operator\n";
bufferSize = src.bufferSize;
buffer = std::make_unique<uint8_t[]>(bufferSize);
std::memcpy(buffer.get(), src.buffer.get(), bufferSize);
return *this;
}
private:
int bufferSize = 0;
std::unique_ptr<uint8_t[]> buffer = nullptr;
};
```
這個 class 的特色就是每一次使用都會佔用100MB的記憶體空間想像下面的程式的動作
```cpp
BigBuffer buf1;
// Do something with buf1
// Assign to buf2
BigBuffer buf2 = buf1;
```
執行訊息:
```
BigBuffer constructor // create buf1
BigBuffer copy constructor, copy 104857600Bytes // copy buf1 to buf2
...
```
這會先產生 `buf1`,然後把 `buf1` copy 給 `buf2`。如果我們想要省下 copy 的成本,這時候 Move constructor 就可以派上用場了。
`BigBuffer` 加一個 Move constructor
```cpp
class BigBuffer {
public:
...
BigBuffer(BigBuffer&& src) noexcept {
std::cout << "BigBuffer move constructor\n";
bufferSize = src.bufferSize;
buffer = std::move(src.buffer);
src.buffer.reset();
src.bufferSize = 0;
}
...
};
```
這個 move constructor 的參數就是一個 rvalue reference我們把來源的 bufferSize 跟 buffer 指標「移到」我們這邊,而不是完整的複製一份。在轉移之後呢,當然也要把來源清空,讓轉移更加明確。
有了 Move assignment operator 之後,在執行一次原本的程式,你會發現訊息......沒有變,還是一樣呼叫 copy constructor 來複製了100MB 的 buffer這時我們需要明確的告訴 compiler 我們要「移動」物件,而不是複製它,把原本的程式改為:
```cpp
BigBuffer buf1;
// Do something with buf1
// Assign to buf2
BigBuffer buf2 = std::move(buf1);
```
我們用 `std::move()` 來「移動」物件,這時輸出變成
```
BigBuffer constructor // create buf1
BigBuffer move constructor // move buf1 to buf2, buf1 has nullptr now
...
```
另外一個情形也可以受益於此,假如我們有個 function 會產生 `BigBuffer`,如下:
```cpp
BigBuffer BigBufferCreator() {
std::cout << "BigBufferCreator: Create a BigBuffer!\n";
BigBuffer tempb;
// do something
std::cout << "BigBufferCreator: return\n";
return tempb;
}
BigBuffer b = BigBufferCreator(); // copy tempb to b
```
在沒有 Move constructor 的情況下,上面的程式會先產生一個 `tempb`,然後複製給 `b`,訊息:
```
BigBufferCreator: Create a BigBuffer!
BigBuffer constructor
BigBufferCreator: return
BigBuffer copy constructor, copy 104857600Bytes // Copy 100MB!
...
```
在有 Move constructor 的情況下,訊息就變成:
```
BigBufferCreator: Create a BigBuffer!
BigBuffer constructor
BigBufferCreator: return
BigBuffer move constructor // Use MOVE!
BigBuffer destructor
BigBuffer destructor
```
因為 `BigBufferCreator()` 產生的就是一個 `BigBuffer` rvalue所以 compiler 會使用 move constructor`BigBuffer(BigBuffer&& src)` 而不是 copy constructor。
## Move assignment operator(`=`)
Move assignment operator 的行為跟 move constructor 是一樣的,幫 `BigBuffer` 加入 move assignment operator
```cpp
class BigBuffer {
public:
...
BigBuffer& operator=(BigBuffer&& src) noexcept {
std::cout << "BigBuffer move operator\n";
bufferSize = src.bufferSize;
buffer = std::move(src.buffer);
src.buffer.reset();
src.bufferSize = 0;
return *this;
}
...
};
```
測試程式:
```cpp
BigBuffer b1, b2;
b2 = b1;
```
訊息:
```
BigBuffer constructor
BigBuffer constructor
BigBuffer copy operator, copy 104857600Bytes
```
還是使用 copy assignment operator 來複製,理由是一樣的,需要一個明確的 `std::move()` 來表示「轉移」的行動,把程式改成:
```cpp
BigBuffer b1, b2;
b2 = std::move(b1);
```
這樣就可以了。訊息:
```
BigBuffer constructor
BigBuffer constructor
BigBuffer move operator // Use MOVE!
```
## 參考
- [Value categories - cppreference.com](https://en.cppreference.com/w/cpp/language/value_category)
- [rvalue 參考](https://openhome.cc/Gossip/CppGossip/RvalueReference.html)
- [Move constructors - cppreference.com](https://en.cppreference.com/w/cpp/language/move_constructor)
- [Move assignment operator - cppreference.com](https://en.cppreference.com/w/cpp/language/move_assignment)

View File

@@ -1,130 +0,0 @@
---
slug: "[C++ 筆記] 好用的 std::optional"
title: "[C++ 筆記] 好用的 std::optional"
description:
toc: true
authors:
- awin
tags:
- c++
categories:
- Programming
series:
- C++ 筆記
date: 2019-12-22T00:00:00
lastmod: 2019-12-22T00:00:00
featuredVideo:
featuredImage:
draft: false
enableComment: true
---
> since C++17
[`std::optional`](https://en.cppreference.com/w/cpp/utility/optional) 讓 function 的回傳值多了一個選擇:**有值**或是 `nullopt`
<!--more-->
例如我們有一個 function 要從某個檔案讀值出來(或是去 DB 查一個東西之類的需求),就假設我們要讀一個 int我們也許會這樣寫
```cpp
int readData(std::string filePath) {
...
int data = readFromFile(...);
...
return data;
}
```
但如果要讀的檔案不存在呢?這時候要 return 什麼呢?所以這時候我們會改成這樣寫:
```cpp
bool readData(std::string filePath, int& readData) {
FILE* file = fopen(...)
if (!file) {
return false;
}
readData = readFromFile(...);
return true;
}
```
我們用一個回傳值代表檔案讀取失敗與否,要是檔案存在且開啟成功,那麼 `readData` 這個回傳值就代表我們讀到的值。要是回傳值是 `false`,那 `readData` 就沒有意義。
但是這樣會讓傳入跟傳出的參數混在一起,第一時間也不容易直覺的分辨出來,像這種情況 Python 就清楚很多:
```python
def readData(filePath):
data = None
try:
with open(filePath, "rb") as f:
data = f.read(...)
return data
except FileNotFoundError as e:
return None
value = readData("123.txt")
if value:
pass # Do something...
```
可以像 Python 那樣都從回傳值來判斷嗎? `std::optional` 可以達到這個目的:
```cpp
std::optional<int> readData(std::string filePath) {
FILE* file = nullptr;
fopen_s(&file, filePath.c_str(), "rb");
if (!file) {
return std::nullopt;
}
int readData;
fread(&readData, 1, sizeof(readData), file);
fclose(file)
return readData;
}
auto result = readData("123.txt");
if (result) {
auto value = result.value();
// Use value here...
}
// 或是這樣寫也可以
if (result == std::nullopt) {
// Error handle here
} else {
auto value = result.value();
// Use value here...
}
```
雖然用起來沒辦法讓 C++ 像 Python 那麼簡單,但是 `std::optional` 確實讓整段 code 看起來更清楚了。
除了 [`std::optional<T>::value()`](https://en.cppreference.com/w/cpp/utility/optional/value) 以外,還有其他的取值方法:
```cpp
std::optional<std::string> name;
// Some process...
if (name)
{
printf("name = %s\n", (*name).c_str());
}
```
如果 `std::optional` 包含的是 struct 或是 class也可以用 `->` 來直接存取 member或 member function
```cpp
struct User {
uint32_t id;
std::string name;
int32_t age;
};
std::optional<User> user;
// Some process...
if (user) {
printf("id = %d\n", user->id);
printf("name = %s\n", user->name.c_str());
printf("age = %d\n", user->age);
}
```

View File

@@ -1,140 +0,0 @@
---
slug: "[C++ 筆記] 智慧指標unique_ptr & shared_ptr"
title: "[C++ 筆記] 智慧指標unique_ptr & shared_ptr"
description:
toc: true
authors:
- awin
tags:
- c++
- memory
categories:
- Programming
series:
- C++ 筆記
date: 2019-12-01T00:00:00
lastmod: 2019-12-01T00:00:00
featuredVideo:
featuredImage:
draft: false
enableComment: true
---
[`unique_ptr`](https://en.cppreference.com/w/cpp/memory/unique_ptr)與[`shared_ptr`](https://en.cppreference.com/w/cpp/memory/shared_ptr)都是智慧指標箱對於原本的raw pointer智慧指標使用起來更方便也不用擔心delete的問題。
<!--more-->
## unique_ptr
`unique_ptr` 的特點是,它保證在一個時間內,只會有一個指標的擁有者,也就是這個指標不能被複製跟移動,當 `unique_ptr` 離開它的scope時候它所擁有的指標也隨之被delete。這讓你不用擔心memory leak的問題。
假設我們有一個class叫 `BigBuffer` ,原本分配記憶體的方法:
```cpp
BigBuffer* bigBuf = new BigBuffer(bufferSize);
// Use buffer here
delete bigBuf;
```
`unique_ptr`
```cpp
auto bigBuf = std::make_unique<BigBuffer>(bufferSize);
// Use buffer here
// bigBuf will be released when exiting scope
```
我們統一用[`std::make_unique<>`](https://en.cppreference.com/w/cpp/memory/unique_ptr/make_unique)這個template function來建立 `unique_ptr` ,角括號 `<>` 裡面要帶入你要建立的型別,後面的括號 `()` 就是型別的constructor使用起來跟 `new` 是一樣的。
因為 `std::make_unique<>` 裡面已經有表明型別了,所以變數就用 `auto` 就可以了,不用再寫一次型別。
一旦 `unique_ptr` 建立之後,使用起來就跟一般指標沒有兩樣,都是用 `->` 來操作,例如:
```cpp
bigBuf->setXXX();
bigBuf->getXXX();
```
但是別忘記 `unique_ptr` 本身還是一個local variable所以我們可以用 `.` 來操作 `unique_ptr` ,例如我們可以用 `.reset()` 重新配一個指標:
```cpp
BigBuffer* pBuffer = new BigBuffer();
bigBuf.reset(pBuffer);
```
這時候舊指標會自動delete如果記憶體分配有成功的話bigBuf會接管剛剛new出來的指標或者變成 `nullptr` (記憶體分配失敗)。
如果單純想要釋放指標,那就單純的呼叫 `reset()` 就好。
```cpp
bigBuf.reset(); // Now I'm nullptr
```
如果要分配陣列的話:
```cpp
auto intArray = std::make_unique<int[]>(1024);
```
使用方式也是一樣的:
```cpp
intArray[5] = 555;
```
不過對於陣列的操作更建議使用 `std::array`
如果有什麼特殊原因讓你決定不再讓 `unique_ptr` 來幫你管理指標,可以用 `release()` 來讓出指標:
```cpp
auto intArray = std::make_unique<int[]>(1024);
int* intArrayRaw = intArray.release(); // Now I don't care anymore
```
但是這時候呼叫 `delete[]` (或 `delete` )的責任又回到你身上了。所以千萬不要把 `release()``reset()` 搞混了。
`unique_ptr` 不能被複製跟移動,所以下列的寫法都編不過:
```cpp
auto ptr1 = std::make_unique<int>(5);
std::unique_ptr<int> ptr2(ptr1); // Error
std::unique_ptr<int> ptr2 = ptr1; // Error
```
在Visual Studio 2017上錯誤訊息是這樣`error C2280: 'std::unique_ptr<int,std::default_delete<int>>::unique_ptr(const std::unique_ptr<int,std::default_delete<int>> &)': attempting to reference a deleted function`
其實就是`unique_ptr`的copy constructor跟assignment operator都被標記為delete了。
### Move a unique_ptr
如果一定要把 `unique_ptr` 指定給別人可以嗎?可以的,用 `std::move()` 來轉移:
```cpp
auto ptr1 = std::make_unique<int>(5);
// do something
auto anotherPtr = std::move(ptr1);
```
`ptr1` 原本所管理的指標會轉移給 `anotherPtr``ptr1` 會變成 `nullptr。`
## shared_ptr
建立一個 `shared_ptr` 是使用[`std::make_shared()`](https://en.cppreference.com/w/cpp/memory/shared_ptr/make_shared)
```cpp
auto myBuf = std::make_shared<BigBuffer>(bufferSize);
```
但是 `shared_ptr` 可以被複製與移動,這是跟 `unique_ptr` 的差別:
```cpp
auto myBuf = std::make_shared<BigBuffer>(bufferSize);
std::shared_ptr<BigBuffer> bufCopy = myBuf;
```
現在 bufCopy 跟 myBuf 都指向同一個指標,他們都可以操作這個指標:
```cpp
myBuf->setZero(startAddr, endAddr);
bufCopy->setOne(startAddr, endAddr);
```
`shared_ptr` 內部有一個參考記數reference count來紀錄它所擁有的指標已經分享給幾個變數了只要有變數離開了他的scope參考記數就會減少反之要是像上面那樣有人複製指標參考記數就會增加參考記數歸0的時候指標就會被釋放。
有了 `shared_ptr` 我們就不必擔心 delete 的責任問題:
```cpp
std::shared_ptr<BigBuffer> getBuffer(int32_t bufferSize) {
return std::make_shared<BigBuffer>(bufferSize);
}
int main() {
auto myBuf = getBuffer(1024); // new(malloc) memory
// use myBuf
return 0;
} // myBuf delete memory here
```
`shared_ptr` 有一個問題是可以會「循環參考」cyclic references也就是 share_ptr A 指向另一個 share_ptr B ,然後 share_ptr B 又指向 share_ptr A這造成參考記數reference count不會減少而永遠無法釋出指標。這個是需要注意的。
但是 `shared_ptr` 還是讓記憶體的管理問題大大減少,應該用 `shared_ptr` 來代替 `new` & `delete`

View File

@@ -15,6 +15,8 @@ draft: false
enableComment: true enableComment: true
--- ---
<!--more-->
## 恢復備份 ## 恢復備份
- `%userprofile%/.config` - `%userprofile%/.config`
- `%userprofile%/.ssh` - `%userprofile%/.ssh`
@@ -24,6 +26,7 @@ enableComment: true
- `%userprofile%/.vimrc` - `%userprofile%/.vimrc`
## 安裝 Chocolatey ## 安裝 Chocolatey
先安裝 [Chocolatey](https://chocolatey.org/) ,根據 [https://chocolatey.org/install](https://chocolatey.org/install) ,用 Administrator 權限打開 Terminal ,輸入以下指令安裝: 先安裝 [Chocolatey](https://chocolatey.org/) ,根據 [https://chocolatey.org/install](https://chocolatey.org/install) ,用 Administrator 權限打開 Terminal ,輸入以下指令安裝:
```powershell ```powershell
@@ -31,7 +34,9 @@ Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManage
``` ```
## 安裝需要的軟體 ## 安裝需要的軟體
接著就可以安裝需要的工具了。 接著就可以安裝需要的工具了。
```shell ```shell
choco install powertoys 7zip vscode hxd sublimetext4 androidstudio intellijidea-community git winmerge freefilesync freedownloadmanager gsudo firacode cascadiacode sourcecodepro delta googlechrome googledrive enpass.install sharex win32diskimager k-litecodecpackmega --yes choco install powertoys 7zip vscode hxd sublimetext4 androidstudio intellijidea-community git winmerge freefilesync freedownloadmanager gsudo firacode cascadiacode sourcecodepro delta googlechrome googledrive enpass.install sharex win32diskimager k-litecodecpackmega --yes
``` ```
@@ -39,6 +44,7 @@ choco install powertoys 7zip vscode hxd sublimetext4 androidstudio intellijidea-
可以在 [https://community.chocolatey.org/packages](https://community.chocolatey.org/packages) 找到其他工具,再加到清單後面即可。 可以在 [https://community.chocolatey.org/packages](https://community.chocolatey.org/packages) 找到其他工具,再加到清單後面即可。
上面的指令安裝了下列的軟體,可以依自己需求增刪: 上面的指令安裝了下列的軟體,可以依自己需求增刪:
- [powertoys](https://community.chocolatey.org/packages/powertoys) - [powertoys](https://community.chocolatey.org/packages/powertoys)
- [7zip](https://community.chocolatey.org/packages/7zip) - [7zip](https://community.chocolatey.org/packages/7zip)
- [vscode](https://community.chocolatey.org/packages/vscode) - [vscode](https://community.chocolatey.org/packages/vscode)
@@ -63,6 +69,7 @@ choco install powertoys 7zip vscode hxd sublimetext4 androidstudio intellijidea-
- [k-litecodecpackmega](https://community.chocolatey.org/packages/k-litecodecpackmega) - [k-litecodecpackmega](https://community.chocolatey.org/packages/k-litecodecpackmega)
## 升級軟體 ## 升級軟體
```shell ```shell
choco upgrade all -y choco upgrade all -y
``` ```

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

View File

@@ -1,47 +0,0 @@
---
slug: 用 oh-my-posh 美化 Git bash
title: 用 oh-my-posh 美化 Git bash
description:
toc: true
authors:
- awin
tags:
- terminal
categories:
- Tool setup
series:
- Windows
date: 2022-06-14T00:00:00
lastmod: 2022-06-14T00:00:00
featuredVideo:
featuredImage:
draft: false
enableComment: true
---
讓 [Windows Terminal](https://apps.microsoft.com/store/detail/windows-terminal/9N0DX20HK701) 中的 Git bash 也可以美美的。
<!--more-->
## 步驟
以下步驟都是在 [Windows Terminal](https://apps.microsoft.com/store/detail/windows-terminal/9N0DX20HK701) 中的 Git bash[^1] 執行。
1. 先下載一個你喜歡的theme: [https://ohmyposh.dev/docs/themes](https://ohmyposh.dev/docs/themes)
2. 下載並安裝字型:[Caskaydia Cove Nerd Font](https://github.com/ryanoasis/nerd-fonts/releases/download/v2.1.0/CascadiaCode.zip?WT.mc_id=-blog-scottha)
3. Install OhMyPosh: `winget install JanDeDobbeleer.OhMyPosh`
4. 建立並修改 `~/.profile`,然後加入
`eval "$(oh-my-posh --init --shell bash --config ~/montys.omp.json)"`
注意最後的 `montys.omp.json` 就是第一步下載的theme這邊要改成你自己的路徑。
5. 修改 Windows Terminal 的 `setting.json`,將字型改為 `CaskaydiaCove NF`
![](images/20220614221618_oh-my-posh_setting.png)
6. 重開 Windows Terminal
[^1]: 在 [Windows Terminal](https://apps.microsoft.com/store/detail/windows-terminal/9N0DX20HK701) 中設定 Git bash 可以參考:[Windows Terminal's 設定 Git Bash 和 SSH @ 傑克! 真是太神奇了! :: 痞客邦 ::](https://magicjackting.pixnet.net/blog/post/225162505-windows-terminal's-%E8%A8%AD%E5%AE%9A-git-bash-%E5%92%8C-ssh)
## 成果
![20220614_221915_WindowsTerminal_1244x262.png](images/20220614_221915_WindowsTerminal_1244x262.png)
## 參考
- [Oh My Posh](https://ohmyposh.dev/)
- [How to make the ultimate Terminal Prompt on Windows 11 - This video is LONG and WORDY and DETAILED - YouTube](https://www.youtube.com/watch?v=VT2L1SXFq9U)
- [My Ultimate PowerShell prompt with Oh My Posh and the Windows Terminal - Scott Hanselman's Blog](https://www.hanselman.com/blog/my-ultimate-powershell-prompt-with-oh-my-posh-and-the-windows-terminal)
- [Windows-Terminal配置OhMyPosh来美化GitBash_偕臧x的博客-CSDN博客](https://blog.csdn.net/qq_33154343/article/details/120661945)

View File

@@ -1,48 +0,0 @@
---
slug: Dokcer Compose 遇到 Python 3.6 不再支援問題
title: Dokcer Compose 遇到 Python 3.6 不再支援問題
description:
toc: true
authors:
- awin
tags: []
categories: []
series: []
date: 2023-05-09T00:00:00
lastmod: 2023-05-09T00:00:00
featuredVideo:
featuredImage:
draft: false
enableComment: true
---
解決 `docker-compose` 警告 Python 3.6 不再支援問題。
<!--more-->
可能已經發生一時間了,但是最近才注意到 XD。
在使用 `docker-compose down` 或是 `docker-compose up`,都會出現下面這個訊息:
```bash
/snap/docker/2746/lib/python3.6/site-packages/paramiko/transport.py:32: CryptographyDeprecationWarning: Python 3.6 is no longer supported by the Python core team. Therefore, support for it is deprecated in cryptography. The next release of cryptography (40.0) will be the last to support Python 3.6.
from cryptography.hazmat.backends import default_backend
```
雖然已經確定使用 Python 3.10,查看 docker-compose 版本也確實發現它還是使用 Python 3.6
```bash
xxxx@xxxx:~/oooo/ooxx$ sudo docker-compose version
/snap/docker/2746/lib/python3.6/site-packages/paramiko/transport.py:32: CryptographyDeprecationWarning: Python 3.6 is no longer supported by the Python core team. Therefore, support for it is deprecated in cryptography. The next release of cryptography (40.0) will be the last to support Python 3.6.
from cryptography.hazmat.backends import default_backend
docker-compose version 1.29.2, build unknown
docker-py version: 5.0.3
CPython version: 3.6.9
```
這是因為 `docker-compose` 這個命令已經過時了,請改用 `docker compose` 就可以了。<br>
要是習慣改不過來不妨就加個alias吧
```bash
alias docker-compose='docker compose'
```

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

View File

@@ -1,62 +0,0 @@
---
slug: Fujifilm X-T5 入手感想
title: Fujifilm X-T5 入手感想
description:
toc: true
authors:
- awin
tags:
- photography
- fujifilm
- x-t5
categories:
- Hobby
series: []
date: 2023-04-08T00:00:00
lastmod: 2023-04-08T00:00:00
featuredVideo:
featuredImage:
draft: false
enableComment: true
---
買了 X-T5 也一陣子了機器功能什麼的是很OK的尤其跟前一台比起來性能、感光度什麼的都是大幅度的進步滿滿的升級感。
只是使用上還是不習慣,這一篇來講一下不習慣的點,還有解決方法。
<!--more-->
雖然 X-T5 的轉盤很漂亮很有型但是要一直轉來轉去也是有點煩人像是你將設定快門之後快門先決要改成A模式光圈先決先得把快門轉回A然後再把光圈轉到你要的位置如果這時候要回到P模式快門轉盤跟光圈環都要調回A才行。也不是不好就是有點煩人。
第二個不習慣的點是我還是習慣用觀景窗來取景要調整轉盤的話變成要將相機放下來轉動轉盤再把相機拿起來取景尤其是ISO轉盤它在左手邊要由本來扶著鏡頭的左手來調整一整個就很不順手。我還是希望可以在取景的時候用右手就可以改變設定不用把相機拿上拿下的。
另外一個問題是X-T5的握把實在太淺了有夠難握這時候就很懷念前一台那厚實的握把可以牢牢握住的那種踏實感。
這邊紀錄一下這幾個問題的解決方法。
## 握把
關於握把,是買[Smallrig 3870](https://www.smallrig.com/SmallRig-Retro-Cage-for-FUJIFILM-X-T5-3870.html),這個兔籠可以加深握把,而且也把快門鈕的位置往前移,但是它往前移的機構並沒有做的很好,必須按連桿中間部份才可以有效的對焦。看下面的影片,一開始按連桿的前面(也就是它原本預計要把快門前移的位置),你會發現按下去之後,連桿沒辦法順利的拉動原本的快門鈕,必須按中間一點的位置才行。
{{< video src="images/IMG_6330.mp4" type="video/mp4" preload="auto" >}}
雖然不完美,但是握把真的舒服太多了,所以這點瑕不掩瑜,是一個可以適應的小問題。
## 滾輪控制
第二個問題是希望可以把光圈、快門、ISO的調整都改為用右手的前後滾輪來控制這樣就可以在取景的時候直接調整了。要達到這目標有幾個地方要調整
1. 光圈環調成 "A"
2. ISO 轉盤調成 "C"
3. EV 轉盤調成 "C"
4. 設定選單,進入「設定」頁面的「按鈕/轉盤設定」將前轉盤的3個功能改為「F」、「EV」、「ISO」
5. 同樣的選單位置將後轉盤改為「S.S」
| | | |
|:-------------------------:|:-------------------------:|:-------------------------:|
| ![](images/IMG_6332.jpg) | ![](images/IMG_6333.jpg) | ![](images/IMG_6334.jpg) |
這樣設定之後後轉盤可以用來控制快門前轉盤可以控制光圈、EV、ISO這3樣。
現在相機會變為「P模式」將快門轉盤轉到 "T" 之後就會變成「S模式」這時候可以用後轉盤來調整快門。
將快門轉盤調回 A將前轉盤「向左轉」這時候會出現藍色的光圈數值這時候就是「A模式」了。
按下前轉盤可以在光圈、EV、ISO之中切換。如果快門轉盤沒有調回 A那麼就是「M模式」總之一切都可以在這2個轉盤中搞定了。
唯一還是需要用到轉盤的就是快門轉盤了不過從A調到T只要2格這不容易弄錯很快就可以熟悉了。
後來我發現X-H2就是我想要的這種操作模式如果這樣的設定還是用不習慣看來只能......🤣。

Binary file not shown.

Before

Width:  |  Height:  |  Size: 484 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 638 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 634 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 592 KiB

View File

@@ -1,25 +0,0 @@
---
slug: 福岡 Nu Gundam
title: 福岡 Nu Gundam
description:
toc: true
authors:
- awin
tags:
- Gunpla
categories:
- Hobby
series:
- Scale Model
date: 2023-02-15T00:00:00
lastmod: 2023-02-15T00:00:00
featuredVideo:
featuredImage:
draft: false
enableComment: true
---
繼台場 RX-78 與 Unicorn 之後,很開心終於收集到了 LaLaport 的 Nu Gundam下一個目標當然就是橫濱的 RX-78 F00 啦!
![](images/DSCF0288_20230215_100150.jpg)
![](images/DSCF0271_20230215_094642.jpg)
![](images/DSCF0272_20230215_094804.jpg)

View File

@@ -1,6 +1,6 @@
#!/bin/bash #!/bin/bash
../../bin/0.100.1_extend/hugo.exe ../../bin/0.100.1_extend/hugo.exe
ssh -t root@192.168.1.30 "rm -rf /var/www/html/*" ssh -t awin@awinpi4 "rm -rf /home/awin/docker/blog/data/*"
scp -r ./public/* root@192.168.1.30:/var/www/html/ scp -r ./public/* awin@awinpi4:/home/awin/docker/blog/data/
ssh -t root@192.168.1.30 "systemctl restart apache2" ssh -t awin@awinpi4 "sudo docker compose -f /home/awin/docker/blog/docker-compose.yml down ; sudo docker compose -f /home/awin/docker/blog/docker-compose.yml up -d"