.NET 的 擴充方法 (C#/VB.NET)
https://docs.microsoft.com/zh-tw/dotnet/visual-basic/programming-guide/language-features/procedures/extension-methods
https://docs.microsoft.com/zh-tw/dotnet/csharp/programming-guide/classes-and-structs/extension-methods
不用繼承,也不用改變原始程式的情況下,替類別新增新的方法。
## VB .NET
要 Imports System.Runtime.CompilerServices 。
要在 Module 宣告。若要給 dll 外部使用,Module 要宣告 Public。
要擴充的方法上面要加上 <Extension()>,該方法或函式的第一個參數就是要擴充的型別。
可擴充的型別有:
類別 (參考類型)
結構 (實值類型)
介面
委派
ByRef 和 ByVal 引數
泛型方法的參數
陣列
## C#
要定義在 static 物件中的 static 方法。
方法的第一個參數要加上 this 型別。
擴充方法是定義成靜態方法,但透過執行個體方法語法呼叫。
2018年12月25日 星期二
2018年12月24日 星期一
[心得]幾種 系統內溝通 的方式
幾種 系統內溝通 的方式
用 ros 的名詞:topic, service, actionlib
1. topic 方式,有兩個習慣模式
eventbus: event listen/event raise
topic: publish/subscribe
兩者極為相似,也常常被當成一樣的東西。依我的定義,其中不同的地方是:
topic 在系統中,幾乎只有單程,沒有去與回的對應。接收方不需要與發送方互動時使用。也可不理會重覆傳送的問題。
eventbus 在系統中,有可能會存在著事件去與回的處理,每次事件會在乎重覆傳送的判定問題。
但因為這兩種也都可以用簡單程式方式解決掉彼此的差異,所以視為一樣也沒有什麼問題。
2. service 方式
也就是 http 採用的模式,也就是 request/response。必定由 client 發起 request,由 server 送回 response。
3. actionlib 方式
由 client 設定 goal,server 定期或定時回報 progress ,當最後結束的時候回傳 result 的模式。在進行的過程中,還可以 cancel 中斷執行以及查看 status。
這種模式也可由前兩種組合, request/response + event 來做到。流程稍有不同。
client 送出 request,server 回應 response 是否執行,然後由 server 發送 event 來通知 client 進度與結果。
用 ros 的名詞:topic, service, actionlib
1. topic 方式,有兩個習慣模式
eventbus: event listen/event raise
topic: publish/subscribe
兩者極為相似,也常常被當成一樣的東西。依我的定義,其中不同的地方是:
topic 在系統中,幾乎只有單程,沒有去與回的對應。接收方不需要與發送方互動時使用。也可不理會重覆傳送的問題。
eventbus 在系統中,有可能會存在著事件去與回的處理,每次事件會在乎重覆傳送的判定問題。
但因為這兩種也都可以用簡單程式方式解決掉彼此的差異,所以視為一樣也沒有什麼問題。
2. service 方式
也就是 http 採用的模式,也就是 request/response。必定由 client 發起 request,由 server 送回 response。
3. actionlib 方式
由 client 設定 goal,server 定期或定時回報 progress ,當最後結束的時候回傳 result 的模式。在進行的過程中,還可以 cancel 中斷執行以及查看 status。
這種模式也可由前兩種組合, request/response + event 來做到。流程稍有不同。
client 送出 request,server 回應 response 是否執行,然後由 server 發送 event 來通知 client 進度與結果。
2018年10月5日 星期五
[點網核] win2003, win7 與 .net core 不是很熟的樣子
.net core 搞半天,win2003 不認得它……
win7 也跟它不熟……
如果是抱怨 hostfxr.dll 無法載入,那就安裝以下更新
https://www.microsoft.com/en-us/download/details.aspx?id=26764
KB2533623
win7 也跟它不熟……
如果是抱怨 hostfxr.dll 無法載入,那就安裝以下更新
https://www.microsoft.com/en-us/download/details.aspx?id=26764
KB2533623
2018年9月25日 星期二
[點網][超速譯]VS2017 的中斷點
https://blogs.msdn.microsoft.com/visualstudio/2018/09/13/how-can-i-pause-my-code-in-visual-studio-breakpoints-faq/
Visual Studio 是我用過最好用的 IDE,沒有之一。
中斷點這件事也是我看過不少碼農不甚使用的事。正好有官方提出一些小技巧給大家知道。
快速摘譯重點,成為超速譯的一篇。
設立 breakpoint
(1)左點左邊界 或是 按F9
(2)按F5
管理 breakpoint
(1)breakpoint window
(2) Debug -> Window -> Breakpoints
Conditional Breakpoint
(1)設定 breakpoint
(2)鼠標飄到 breakpoint 上,按下齒輪圖示
(3)選擇 Conditions,然後設定條件
(4)條件輸入完畢,關閉設定窗
Iteration breakpoint
(1)設定 breakpoint
(2)鼠標飄到 breakpoint 上,按下齒輪圖示
(3)選擇 Conditions,然後設定條件為 Hit Count
Function breakpoint
(1) Debug -> New Breakpoint -> Break at Function
Value change breakpoint
* C++, data breakpoints
* Watch Window or the Breakpoints Window 右點 變數 選擇 Break when value changes
* managed code, 針對某個 instance 的屬性偵測改變
(1)在 break mode,右點物件選擇 Make Object ID
(2)在欲偵測的屬性 setter 加入一個 conditional breakpoint 條件是 this == $1
(3)按F5,會停在 setter
(4)在 Call Stack 雙點前一個 frame 可以看到改變屬性的 code 是哪一行
exception breakpoint
在 Exception Settings 窗,設定哪些 exception 要停下來
call stack breakpoint
(1)Debug -> Windows -> Call Statck
(2)右點 calling function,選擇 Breakpoint -> Insert Breakpoint
disassembly breakpoint
(1)打開 disassembly window, Debug -> Windows -> Disassembly
(2)左點左邊界或按F9
Visual Studio 是我用過最好用的 IDE,沒有之一。
中斷點這件事也是我看過不少碼農不甚使用的事。正好有官方提出一些小技巧給大家知道。
快速摘譯重點,成為超速譯的一篇。
設立 breakpoint
(1)左點左邊界 或是 按F9
(2)按F5
管理 breakpoint
(1)breakpoint window
(2) Debug -> Window -> Breakpoints
Conditional Breakpoint
(1)設定 breakpoint
(2)鼠標飄到 breakpoint 上,按下齒輪圖示
(3)選擇 Conditions,然後設定條件
(4)條件輸入完畢,關閉設定窗
Iteration breakpoint
(1)設定 breakpoint
(2)鼠標飄到 breakpoint 上,按下齒輪圖示
(3)選擇 Conditions,然後設定條件為 Hit Count
Function breakpoint
(1) Debug -> New Breakpoint -> Break at Function
Value change breakpoint
* C++, data breakpoints
* Watch Window or the Breakpoints Window 右點 變數 選擇 Break when value changes
* managed code, 針對某個 instance 的屬性偵測改變
(1)在 break mode,右點物件選擇 Make Object ID
(2)在欲偵測的屬性 setter 加入一個 conditional breakpoint 條件是 this == $1
(3)按F5,會停在 setter
(4)在 Call Stack 雙點前一個 frame 可以看到改變屬性的 code 是哪一行
exception breakpoint
在 Exception Settings 窗,設定哪些 exception 要停下來
call stack breakpoint
(1)Debug -> Windows -> Call Statck
(2)右點 calling function,選擇 Breakpoint -> Insert Breakpoint
disassembly breakpoint
(1)打開 disassembly window, Debug -> Windows -> Disassembly
(2)左點左邊界或按F9
2018年9月13日 星期四
[python] WARNING:tornado.general:Invalid multipart/form-data
用 flask 自帶的 server,有時就是會發出 500 之後就無法動作,要重開一次。
想說試試用 tornado 來裝 flask。結果就發現一個 warning。
於是再找一下定義 https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition
## 同場加映
header 裡的的資料若是超過 ISO-8859-1 還是有救。
剛好在 Content-Disposition 定義找到
https://tools.ietf.org/html/rfc5987
ex: foo: bar; title*=UTF-8''%c2%a3%20and%20%e2%82%ac%20rates
## tornado 原始碼部份
想說試試用 tornado 來裝 flask。結果就發現一個 warning。
WARNING:tornado.general:Invalid multipart/form-data查了一下,找到 tornado 原始碼 http://www.tornadoweb.org/en/stable/_modules/tornado/httputil.html,發現應該是 Content-Disposition 只要不是 form-data 就叫。
於是再找一下定義 https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition
> Only the value form-data, as well as the optional directive name and filename, can be used in the HTTP context.attachment 只能用在非 http 的情況。好吧,應該是要改成 form-data 才合規定。就改吧
## 同場加映
header 裡的的資料若是超過 ISO-8859-1 還是有救。
剛好在 Content-Disposition 定義找到
https://tools.ietf.org/html/rfc5987
ex: foo: bar; title*=UTF-8''%c2%a3%20and%20%e2%82%ac%20rates
## tornado 原始碼部份
def parse_multipart_form_data(boundary, data, arguments, files):"""Parses a ``multipart/form-data`` body.The ``boundary`` and ``data`` parameters are both byte strings.The dictionaries given in the arguments and files parameterswill be updated with the contents of the body... versionchanged:: 5.1Now recognizes non-ASCII filenames in RFC 2231/5987(``filename*=``) format."""# The standard allows for the boundary to be quoted in the header,# although it's rare (it happens at least for google app engine# xmpp). I think we're also supposed to handle backslash-escapes# here but I'll save that until we see a client that uses them# in the wild.if boundary.startswith(b'"') and boundary.endswith(b'"'):boundary = boundary[1:-1]final_boundary_index = data.rfind(b"--" + boundary + b"--")if final_boundary_index == -1:gen_log.warning("Invalid multipart/form-data: no final boundary")returnparts = data[:final_boundary_index].split(b"--" + boundary + b"\r\n")for part in parts:if not part:continueeoh = part.find(b"\r\n\r\n")if eoh == -1:gen_log.warning("multipart/form-data missing headers")continueheaders = HTTPHeaders.parse(part[:eoh].decode("utf-8"))disp_header = headers.get("Content-Disposition", "")disposition, disp_params = _parse_header(disp_header)if disposition != "form-data" or not part.endswith(b"\r\n"):gen_log.warning("Invalid multipart/form-data")continuevalue = part[eoh + 4:-2]if not disp_params.get("name"):gen_log.warning("multipart/form-data value missing name")continuename = disp_params["name"]if disp_params.get("filename"):ctype = headers.get("Content-Type", "application/unknown")files.setdefault(name, []).append(HTTPFile( # type: ignorefilename=disp_params["filename"], body=value,content_type=ctype))else:arguments.setdefault(name, []).append(value)
2018年9月12日 星期三
[點網] process.MainWindowHandle == 0
## 原因
為了拿到 process 的 MainWindowHandle 作隱藏/顯示。
但是在隱藏之後,process 的 MainWindowHandle 會等於 0
## 使用 AttachConsole GetConsoleWindow FreeConsole
其中一個方法是針對 console app 的作法是接到 console,拿到其 consolewindow 要到 ID,再離開。
使用 AttachConsole GetConsoleWindow FreeConsole
宣告需要:
```
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool AttachConsole(uint dwProcessId);
[DllImport("kernel32.dll")]
static extern IntPtr GetConsoleWindow();
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
static extern bool FreeConsole();
int GetSmsdMainWindowHandle(int procID)
Int32 tryHandle = 0;
try
{
AttachConsole((uint)procID);
tryHandle = GetConsoleWindow().ToInt32();
FreeConsole();
}
catch (Exception)
{
//pass
}
finally
{
FreeConsole();
}
return tryHandle;
}
```
使用方法:
```
int smsdMainWindowHandle = GetSmsdMainWindowHandle(xProc.Id);
```
## 使用 EnumChildWindows GetWindowThreadProcessId
另一個方法是列舉所有 子window 再拿到其 window thread 的 process ID。
使用 EnumChildWindows GetWindowThreadProcessId
宣告需要:
```
private struct SearchData
{
// You can put any vars in here...
public int currentTaskID;
public IntPtr currenthWnd;
}
private delegate bool EnumWindowsProc(IntPtr hWnd, ref SearchData data);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool EnumChildWindows(IntPtr hwndParent, EnumWindowsProc lpEnumFunc, ref SearchData data);
[DllImport("user32.dll")]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out int ProcessId);
bool EnumProc(IntPtr hWnd, ref SearchData data)
{
int lProcID;
GetWindowThreadProcessId(hWnd,out lProcID);
if (lProcID == data.currentTaskID)
{
data.currenthWnd = hWnd;
}
return true;
}
```
使用方法:
```
SearchData n = new SearchData();
n.currentTaskID = xProc.Id;
EnumChildWindows(IntPtr.Zero,new EnumWindowsProc(EnumProc),ref n);
int smsdMainWindowHandle = (int)n.currenthWnd;
```
這個方法的 VB Code 由 Cyrus 提供:
```
Dim currenthWnd = 0
Public Function fEnumWindowsCallback(ByVal hWnd As Integer, ByVal lpData As Integer) As Integer
fEnumWindowsCallback = 1
Dim lProcID As Integer
Call GetWindowThreadProcessId(hWnd, lProcID)
If lProcID = currentTaskID Then
currenthWnd = hWnd
End If
End Function
Call EnumChildWindows(0&, AddressOf fEnumWindowsCallback, 0&)
If currenthWnd <> 0 Then
If goSECSInterface.GEMObject.HideSMSD = True Then
ShowWindow(currenthWnd, SW_HIDE)
Else
ShowWindow(currenthWnd, SW_NORMAL)
End If
End If
```
## 參考:
- * https://stackoverflow.com/questions/8949652/do-windows-api-enumwindows-and-enumchildwindows-functions-behave-differently-in
2018年9月11日 星期二
[pi-nas]raspberry pi glusterfs 換硬碟
在樹莓派上裝 gluster,硬碟壞了要換掉。查了幾種方式要來試試。但是想先試個最無腦的方法,就是 umount 舊硬碟,mount 新硬碟,看看有沒有比較方便。以下就是過程。
步驟 1
停止 gluster daemon
`sudo systemctl stop glusterfs-server`
這個只能讓 umount /mnt/gv0 成功,umount /data/brick1 還是不行
glusterfsd 還是佔著,查詢誰在用檔案或掛載 `fuser -m -u /data/brick1`。
用 `sudo /etc/init.d/glusterfs-server stop` https://gluster.readthedocs.io/en/latest/Administrator%20Guide/Start%20Stop%20Daemon/ 也不行
最後只好使用 `kill -9 PID` 處理掉,比較溫和應該用 `kill -15 PID`
umount /data/brick1 成功
步驟 2
拔掉舊的硬碟,插入新的硬碟,格式化
`sudo mkfs.xfs -i size=512 /dev/sda1`
修改 fstab `PARTUUID=c121432b-52f5-4bb2-a260-0d38992df858 /data/brick1 xfs defaults 1 2` 其中 PARTUUID 用 `blkid /dev/sda1` 查詢
`sudo mount -a`
`sudo mkdir /data/brick1/gv0`
到這,試試重開。
步驟 3
檢查 heal 狀況 `sudo gluster volume heal gv0 info`
看來直換是沒有,還需要下些指令。glusterfsd 3.9.0 有 reset-brick 看起來很好用,但!
我的 glusterfsd 是 3.8.8-1 沒有支援 reset-brick。
自身 replace `sudo gluster volume replace-brick gv0 pi315:/data/brick1/gv0 pi315:/data/brick1/gv0 commit force` 也不行。
所以一定要換個新名字,所以改成 gv0_1:
`sudo gluster volume replace-brick gv0 pi315:/data/brick1/gv0 pi315:/data/brick1/gv0_1 commit force`
這個時候,pi315 的 glusterfsd 才起得來
然後,heal 就自動開始了。
查看 heal 狀態 `sudo gluster volume heal gv0 info`
到這其實就結束了,但是如果很在意那個 gv0_1 的話,我在 heal 結束之後又執行了一次 `replace-brick` 只是把 gv0_1 又換成 gv0。要考慮硬碟空間要足夠兩倍大。看硬碟閃,還是從 pi314 那裡拿資料。
參考:
## 有故意使用 setfattr 強迫 heal
https://serverfault.com/questions/710220/how-do-you-add-a-replacement-hdd-to-a-glusterfs-volume
https://lists.gluster.org/pipermail/gluster-users/2014-August/018515.html
https://docs.gluster.org/en/v3/Administrator%20Guide/Managing%20Volumes/#replace-brick
## 只使用 sudo gluster volume replace-brick 舊brick 新brick
https://sysadmins.co.za/replace-faulty-bricks-in-glusterfs/
## 使用 reset-brick
https://docs.gluster.org/en/latest/release-notes/3.9.0/
步驟 1
停止 gluster daemon
`sudo systemctl stop glusterfs-server`
這個只能讓 umount /mnt/gv0 成功,umount /data/brick1 還是不行
glusterfsd 還是佔著,查詢誰在用檔案或掛載 `fuser -m -u /data/brick1`。
用 `sudo /etc/init.d/glusterfs-server stop` https://gluster.readthedocs.io/en/latest/Administrator%20Guide/Start%20Stop%20Daemon/ 也不行
最後只好使用 `kill -9 PID` 處理掉,比較溫和應該用 `kill -15 PID`
umount /data/brick1 成功
步驟 2
拔掉舊的硬碟,插入新的硬碟,格式化
`sudo mkfs.xfs -i size=512 /dev/sda1`
修改 fstab `PARTUUID=c121432b-52f5-4bb2-a260-0d38992df858 /data/brick1 xfs defaults 1 2` 其中 PARTUUID 用 `blkid /dev/sda1` 查詢
`sudo mount -a`
`sudo mkdir /data/brick1/gv0`
到這,試試重開。
步驟 3
檢查 heal 狀況 `sudo gluster volume heal gv0 info`
```
pi@pi315:~ $ sudo gluster volume heal gv0 info
Brick pi314:/data/brick1/gv0
Status: Connected
Number of entries: 0
Brick pi315:/data/brick1/gv0
Status: Transport endpoint is not connected
Number of entries: -
```
看來直換是沒有,還需要下些指令。glusterfsd 3.9.0 有 reset-brick 看起來很好用,但!
我的 glusterfsd 是 3.8.8-1 沒有支援 reset-brick。
自身 replace `sudo gluster volume replace-brick gv0 pi315:/data/brick1/gv0 pi315:/data/brick1/gv0 commit force` 也不行。
所以一定要換個新名字,所以改成 gv0_1:
`sudo gluster volume replace-brick gv0 pi315:/data/brick1/gv0 pi315:/data/brick1/gv0_1 commit force`
這個時候,pi315 的 glusterfsd 才起得來
```
pi@pi314:~ $ sudo gluster volume status
Status of volume: gv0
Gluster process TCP Port RDMA Port Online Pid
------------------------------------------------------------------------------
Brick pi314:/data/brick1/gv0 49153 0 Y 1492
Brick pi315:/data/brick1/gv0_1 49153 0 Y 1846
Self-heal Daemon on localhost N/A N/A Y 26710
Self-heal Daemon on pi315 N/A N/A Y 1851
Task Status of Volume gv0
------------------------------------------------------------------------------
There are no active volume tasks
```
然後,heal 就自動開始了。
查看 heal 狀態 `sudo gluster volume heal gv0 info`
到這其實就結束了,但是如果很在意那個 gv0_1 的話,我在 heal 結束之後又執行了一次 `replace-brick` 只是把 gv0_1 又換成 gv0。要考慮硬碟空間要足夠兩倍大。看硬碟閃,還是從 pi314 那裡拿資料。
參考:
## 有故意使用 setfattr 強迫 heal
https://serverfault.com/questions/710220/how-do-you-add-a-replacement-hdd-to-a-glusterfs-volume
https://lists.gluster.org/pipermail/gluster-users/2014-August/018515.html
https://docs.gluster.org/en/v3/Administrator%20Guide/Managing%20Volumes/#replace-brick
## 只使用 sudo gluster volume replace-brick 舊brick 新brick
https://sysadmins.co.za/replace-faulty-bricks-in-glusterfs/
## 使用 reset-brick
https://docs.gluster.org/en/latest/release-notes/3.9.0/
2018年8月29日 星期三
[pi-nas] raspbain 樹莓派 wlan0 失效,自動重啟
wlan0 失效,自動重啟,這個網路上有找到一些解法,但是有些太舊方法已經失效。於是這次重做一次,再記錄下來。
總體的概念是,使用 bash script,每隔一段時間測試網路狀況,如果有問題就重啟。
完整 bash script 如下:
```
總體的概念是,使用 bash script,每隔一段時間測試網路狀況,如果有問題就重啟。
- 測試的方法是用 curl 向 google 與 yahoo 要網頁,有回應就算成功。
- 重啟的動作,ifup/ifdown,ifconfig wlan0 up/down 或是 dhcpcd restart 都無用。ifup/ifdown 在 raspbian 有問題,找不到 wlan0,而後兩個失敗的原因是 route default gateway 的設定會失蹤。解決方法直覺的是使用 `sudo route add default gw 192.168.1.1`,另一個則是在 dhcpcd restart 之前做 `sudo ip addr flush dev wlan0`,而我選擇後者。
- 每隔一段時間執行的動作是使用 cron,在 raspbian 這個版本用的是 anacron,直接在 /etc/crontab 加入設定即可。它自己就會檢查與執行,不用重啟 cron deamon。
完整 bash script 如下:
```
```#!/bin/bash urls=("http://www.google.com" "http://tw.yahoo.com") http_code_accept=("200" "301" "302" "404") count=${#urls[@]} connected=0 echo "now start to check net is on or not" echo "bash file in /home/pi/net_restart.sh" #check net is connected or not for ((i=0;i<$count;i++)) do url=${urls[$i]} result=$(curl -o /dev/null -s -m 10 -w "%{http_code}" "$url") for flag in ${http_code_accept[@]} do #echo $flag $result $url if [ $flag = $result ]; then connected=$(expr $connected + 1) echo "accept" $url $connected fi done done if [ $connected -eq 0 ]; then echo "network not good" echo "going to restart network" ip addr flush dev wlan0 systemctl restart dhcpcd fi
2018年8月9日 星期四
[點網]現在 visual studio 正在轉型中
最近研究 roslyn 發現幾個點。
- 2013 還是使用 native 的 csc.exe vbc.exe。而 2015 2017 開始,使用 roslyn 做為 compiler。
- vs extension 的規格開始改變,名字叫做 .net standard,所以 NuGet 有的東西的打包沒有跟上的話,在 2015 之後就會裝不進舊的 vs。當然也會有舊的東西裝不進新的 vs。像是 .Net Compiler Platform SDK 如果用 extension (NuGet or VSIX)裝的話,會被 vs2017 關掉。要從 Visual Studio Installer 的 Individual components 頁籤安裝才行。現在是混亂期,從 2015 到現在已經三年了吧。
- 現在除了 library 打包換規格之外,現在也因為推出 .Net Core 的關係,framework 也是混亂期,library 有新舊兩種的 portable 格式,給 framework 用的與 core 用的也是要慎選。
2013 與 2017 的間隙很大,應該是沒辦法直跳,2015 應該要保留著用來轉換專案用。
就跟 2005 一樣,用來轉換 2003 與 2008 的專案。
現在如果要專案升級最好還是等等。
相關連結:
https://www.facebook.com/groups/DotNetUserGroupTaiwan/permalink/1945828905710218/
現在如果要專案升級最好還是等等。
相關連結:
https://www.facebook.com/groups/DotNetUserGroupTaiwan/permalink/1945828905710218/
[點網]實際的四捨四入
文章連結:https://www.facebook.com/groups/DotNetUserGroupTaiwan/permalink/1945395752420200/
一定要筆記
一定要筆記
今天在使用某個成績系統時候遇到四捨五入結果與Excel的ROUND()比對有誤差的問題與負責的工程師一起測了一下之後發現造成此問題的原因是因為 .net 中 Math.Round() 函數的行為於是來與各位分享一下大家先猜猜下面四捨五入到小數第二位的輸出結果Math.Round(18.265, 2);Math.Round(18.265, 2, MidpointRounding.AwayFromZero);Math.Round(18.275, 2);Math.Round(18.275, 2, MidpointRounding.AwayFromZero);Math.Round(18.275M, 2);Math.Round(18.275M, 2, MidpointRounding.AwayFromZero);================================..答案分別是Math.Round(18.265, 2) = 18.26Math.Round(18.265, 2, AFZ) = 18.27Math.Round(18.275, 2) = 18.27Math.Round(18.275, 2, AFZ) = 18.27Math.Round(18.275M, 2) = 18.28Math.Round(18.275M, 2, AFZ) = 18.28而造成此原因是因Math.Round() 在遇到5的時候預設是使用 MidpointRounding.ToEven 作為捨去或進位的依據也就是會round到該位最近的偶數假設我需要四捨五入到小數第二位在遇到18.265的時候因為6是偶數,所以會做捨去如果18.265使用了MidpointRounding.AwayFromZero就會不管奇偶去做四捨五入得到與Excel的ROUND()相同的18.27但又有一個問題18.275出來為何都是18.27?這是因為在四捨五入過程中遇到了精度丟失造成了非預期的四捨五入行為改為decimal之後就正常了【結論】處理小數四捨五入的邏輯時#務必使用decimal型別#確認四捨五入邏輯#明確指定MidpointRounding模式才會得到精確的結果【補充】留言中有人有提到.net預設的 ToEven也就是 Banker's rounding兩種四捨五入設計給不同的用途開發前務必確認四捨五入的邏輯
2018年8月5日 星期日
[pi-nas] pi 增加 SmartMonTools
Smart Mon Tools 是用來看硬碟上 S.M.A.R.T 的資訊,
可以提前知道硬碟是不是快壞了。
對於 NAS 來說是必要的。
但因為樹莓派原先不是用來當 NAS 的,所以沒有預載這個程式。
因此要手動安裝。
因為很久沒有去動它,所以有可能會遇到站台不見的情況而遇到 unable to fetch some archives 的情況。此時,先執行 sudo apt-get update 再試。
這樣就可以看到該硬碟所有資訊。
以下的是正常的硬碟
可以提前知道硬碟是不是快壞了。
對於 NAS 來說是必要的。
但因為樹莓派原先不是用來當 NAS 的,所以沒有預載這個程式。
因此要手動安裝。
sudo apt-get smartmontools
因為很久沒有去動它,所以有可能會遇到站台不見的情況而遇到 unable to fetch some archives 的情況。此時,先執行 sudo apt-get update 再試。
sudo smartctl --all /dev/sda
這樣就可以看到該硬碟所有資訊。
以下的是正常的硬碟
=== START OF READ SMART DATA SECTION ===如果看到以下的文字,就應該要考慮換硬碟了。
SMART overall-health self-assessment test result: PASSED
=== START OF READ SMART DATA SECTION ===接下來找時間來換硬碟,會記錄 gluster 換硬碟的流程,免得又忘記了。
SMART overall-health self-assessment test result: FAILED!
Drive failure expected in less than 24 hours. SAVE ALL DATA.
See vendor-specific Attribute list for failed Attributes.
2018年8月1日 星期三
[git]用工具的還是人
一則臉書貼文,有關 git 之前大家怎麼版控的。
https://www.facebook.com/groups/git.tw/permalink/1817171478331512/
樓主留言問到:「想請教一下各位前輩
知道在沒有git 或 svn之類的軟體出現之前
是怎麼協同開發的...
剛剛跟公司的高層主管(不會寫程式)聊天
他說我們公司DevOps很奇怪
為什麼都沒辦法協同開發
說到協同開發每個人都一臉大便
我跟他說很多點公司的現況
1.git當備份工具 commit都沒有意義 更別說開分支之類的
2.大家都是直接連到伺服器去改程式
3.沒有人來負責merge程式
之類的
就被他反嗆
他們1X年前沒用這些東西
大家也都是連到同一台伺服器去做
照樣都可以協同開發
系統也更新了好幾代
為什麼現在不行...
所以想了解一下早期1X年以前
git svn這些東西出現以前
是怎麼協同開發的」
結果有滿多留言不是在回答「git svn這些東西出現以前
是怎麼協同開發的」,而是在講主管有問題。
如果是你,應該怎麼回答這問題呢?
也許樓主是來討拍的,而講主管有問題的才是正確解答。
但我還是留言以前經歷過的協同開發怎麼做的:「Code review, 專人merge 。之後有rational, source safe, cvs,就有辦法一個人改的時侯check out鎖檔不讓別人改,改完check in。」
當然,有些人講得沒錯,現在的程式複雜度比較高,沒有工具就很難處理好。
可以說,因為現在工具的存在,才會出現現在程式的高複雜度。
但反過來說也對,因為有高複雜度的程式的需求,才會造成現在工具的誕生。
但是,重要的還是,不會用工具的人還是會搞得一團糟。
人的概念、程式複雜度、工具支援度,三個東西是程度相合的。其中一個跟不上,就必定出問題,就必定要調整。
最後,我只能留以下留言給事主:
「如果你推不動其他資深同事,那就跟老闆說清楚。
你講的123點,不論用什麼工具都是必須要人們去做好的。
工具再好,人亂用,還是一塌糊塗。
用工具卡死、強迫一定要做到123點,每個 commit 要送老闆簽核、只有某些人才有辦法 merge 進版…等都有辦法做到,以前的幾個 source control software 都做得到。但是如此做會面對更多人性的挑戰,因為那是用伺服器就開始卡權限的,一個人不在位子上,就有可能整個公司不用改程式,一定更多人會抱怨。
工具會進步,就代表舊的方式需要捨棄一些東西來換取另一些東西。git 就是捨棄嚴格卡控,換來靈活合併與分支。如果同事們沒有相對應的概念,就容易弄得更亂。
這時候你們要想想該選擇哪種合作模式才是適合你們這群人,看是要改模式還是換工具或是換公司。」
以上幾點感想。
https://www.facebook.com/groups/git.tw/permalink/1817171478331512/
樓主留言問到:「想請教一下各位前輩
知道在沒有git 或 svn之類的軟體出現之前
是怎麼協同開發的...
剛剛跟公司的高層主管(不會寫程式)聊天
他說我們公司DevOps很奇怪
為什麼都沒辦法協同開發
說到協同開發每個人都一臉大便
我跟他說很多點公司的現況
1.git當備份工具 commit都沒有意義 更別說開分支之類的
2.大家都是直接連到伺服器去改程式
3.沒有人來負責merge程式
之類的
就被他反嗆
他們1X年前沒用這些東西
大家也都是連到同一台伺服器去做
照樣都可以協同開發
系統也更新了好幾代
為什麼現在不行...
所以想了解一下早期1X年以前
git svn這些東西出現以前
是怎麼協同開發的」
結果有滿多留言不是在回答「git svn這些東西出現以前
是怎麼協同開發的」,而是在講主管有問題。
如果是你,應該怎麼回答這問題呢?
也許樓主是來討拍的,而講主管有問題的才是正確解答。
但我還是留言以前經歷過的協同開發怎麼做的:「Code review, 專人merge 。之後有rational, source safe, cvs,就有辦法一個人改的時侯check out鎖檔不讓別人改,改完check in。」
當然,有些人講得沒錯,現在的程式複雜度比較高,沒有工具就很難處理好。
可以說,因為現在工具的存在,才會出現現在程式的高複雜度。
但反過來說也對,因為有高複雜度的程式的需求,才會造成現在工具的誕生。
但是,重要的還是,不會用工具的人還是會搞得一團糟。
人的概念、程式複雜度、工具支援度,三個東西是程度相合的。其中一個跟不上,就必定出問題,就必定要調整。
最後,我只能留以下留言給事主:
「如果你推不動其他資深同事,那就跟老闆說清楚。
你講的123點,不論用什麼工具都是必須要人們去做好的。
工具再好,人亂用,還是一塌糊塗。
用工具卡死、強迫一定要做到123點,每個 commit 要送老闆簽核、只有某些人才有辦法 merge 進版…等都有辦法做到,以前的幾個 source control software 都做得到。但是如此做會面對更多人性的挑戰,因為那是用伺服器就開始卡權限的,一個人不在位子上,就有可能整個公司不用改程式,一定更多人會抱怨。
工具會進步,就代表舊的方式需要捨棄一些東西來換取另一些東西。git 就是捨棄嚴格卡控,換來靈活合併與分支。如果同事們沒有相對應的概念,就容易弄得更亂。
這時候你們要想想該選擇哪種合作模式才是適合你們這群人,看是要改模式還是換工具或是換公司。」
以上幾點感想。
2018年5月8日 星期二
[googleIO] 2018 年 Google IO 講題分類統計
2018 Google IO 已經開始,從講題分類統計,看今年 Google 的重點方向。
今年的分類跟去年差不多,統計如下:
AR & VR: 13
Accessibility: 8
Ads: 8
Android & Play: 122
Assistant: 24
Cloud: 33
Design: 28
Firebase: 26
Flutter: 11
Identity: 13
IoT: 18
Keynote: 13
Location & Map: 6
Machine Learning & AI: 26
MISC: 38
Nest: 1
OpenSource: 2
Payment: 6
Web: 53
今年很強調 Android,Web。
去年的重點統計:
Firebase 場數有 24 場
Mobile Web 場數有 20 場
Cloud 為 12,Android 為 11。
今年的分類跟去年差不多,統計如下:
AR & VR: 13
Accessibility: 8
Ads: 8
Android & Play: 122
Assistant: 24
Cloud: 33
Design: 28
Firebase: 26
Flutter: 11
Identity: 13
IoT: 18
Keynote: 13
Location & Map: 6
Machine Learning & AI: 26
MISC: 38
Nest: 1
OpenSource: 2
Payment: 6
Web: 53
今年很強調 Android,Web。
去年的重點統計:
Firebase 場數有 24 場
Mobile Web 場數有 20 場
Cloud 為 12,Android 為 11。
2018年4月3日 星期二
[git]form hg to git (windows)
目前主要趨勢底定是 git。得要先把 hg 的專案轉到 git 來。
我在 windows 有裝 tortoisehg,所以作法如下:
(1) 在 tortoisehg 的 global settings 裡,把 extension hggit 打開。
(2) 在 bitbucket 開一個 git repo。假設路徑為 https://bitbucket.org/username/hg-projectname-git
(3) 在原來的 hg 的目錄下,執行以下命令,產生 git 的頭:
打完收工
注意事項:
(1) tortoiseplink 已經失效,所以 hg push git+ssh 這個指令會失敗。我找不到辦法換成 ssh.exe,所以就用 https 的方式。
(2) hg push 的路徑不要用 https://username@bitbucket.org 這種,hg 會產生 getaddrinfo 錯誤。
主要參考文章三篇:
http://arr.gr/blog/2011/10/bitbucket-converting-hg-repositories-to-git/
https://mcmblog.azurewebsites.net/using-tortoisehg-with-git/
https://stackoverflow.com/questions/9272233/hg-clone-using-mercurial-throws-getaddrinfo-failed-error-windows-7
我在 windows 有裝 tortoisehg,所以作法如下:
(1) 在 tortoisehg 的 global settings 裡,把 extension hggit 打開。
(2) 在 bitbucket 開一個 git repo。假設路徑為 https://bitbucket.org/username/hg-projectname-git
(3) 在原來的 hg 的目錄下,執行以下命令,產生 git 的頭:
hg bookmark -r default master(4) 在原來的 hg 的目錄下,執行以下命令,把歷史推上去:
hg push git+https://bitbucket.org/username/hg-projectname-git(5) 用 git clone 新路徑。之後就用這個新的 git clone 目錄工作。
打完收工
注意事項:
(1) tortoiseplink 已經失效,所以 hg push git+ssh 這個指令會失敗。我找不到辦法換成 ssh.exe,所以就用 https 的方式。
(2) hg push 的路徑不要用 https://username@bitbucket.org 這種,hg 會產生 getaddrinfo 錯誤。
主要參考文章三篇:
http://arr.gr/blog/2011/10/bitbucket-converting-hg-repositories-to-git/
https://mcmblog.azurewebsites.net/using-tortoisehg-with-git/
https://stackoverflow.com/questions/9272233/hg-clone-using-mercurial-throws-getaddrinfo-failed-error-windows-7
訂閱:
文章 (Atom)