速率即斜率

今天早上騎車的時候想到昨天在看的斜率,然後又想到速率,速率=距離/時間,這公式不就跟斜率是一樣的嗎?
斜率 = (y2-y1)/(x2-x1),假定 y 軸是距離,x軸是時間,以幾何圖形來表示,就很清楚。在愈短的時間裡,經過的距離愈長,表示速度愈快,在圖形上的表示,就是斜率愈陡峭,代表速度愈快。
是說自己把觀念連通的時間也太晚了點,現在才發現。

台哥大Catch上網費率試算

就試算一下,然後作圖。

方案 Catch98 Catch198 Catch398
收費 98 198 398
傳輸量 15 50 150
超過以後費率(元/KB) 0.025 0.015 0.0048
費率 6.533333 3.96 2.653333
Cost if over/MB 25.6 15.36 4.9152


從 Catch 98 升到 Catch 198 時,看起來最划算,因為圖形上的斜率較陡峭,很明顯可以感覺到下降很多,從 6.53 下降到 3.96。

currying

前兩天看Wikipedia上的Currying時,突然頓悟了(可見之前都沒認真)。這個不看英文Wikipedia的說明,還真的是不容易看懂。簡單的說,假設有個 function 是 f( x, y, z ),currying 就是令 f1=f(1),當呼叫 f1( 2, 3 ) 時,就等於是呼叫 f( 1, 2, 3 )。

目前想到可以應用在 c/c# 沒辦法帶預設參數的情況上,像:[c]void func( int x, int y, int z ) { }
void new_func1( int y, int z ) { return func( 1, y, z ); }
void new_func2( int y, int z ) { return func( 2, y, z ); }
[/c]
你可以想像到,這是一項複製、貼上的體力活,用 currying 的話,可以很快創造出新函數:[c]/* 以下為虛擬碼 */
void func( int x, int y, int z ) { }
new_func1 = func(1); /* new_func1 仍是函數 */
new_func2 = func(2); /* new_func2 仍是函數 */
[/c]
在 python 裡,透過 *arg、**kwargs 可以很容易實現,文章可以參考 Currying and Python, a practical example,裏面有點複雜,其實只要看 curry 類別的部份,下面就是直接摘錄出來的實例:[python]class curry:
def __init__(self, fun, *args, **kwargs):
self.fun = fun
self.pending = args[:]
self.kwargs = kwargs.copy()
def __call__(self, *args, **kwargs):
if kwargs and self.kwargs:
kw = self.kwargs.copy()
kw.update(kwargs)
else:
kw = kwargs or self.kwargs
return self.fun(*(self.pending + args), **kw)
def func( a, b, c ):
print( a, b, c )
return (a+b+c)
func1 = curry( func, 1, 100 )
func2 = curry( func, 2 )
print( func1( 200 ), func2( 300, 400 ) )
[/python]
原理就是利用類別的特殊方法 __call__ ,呼叫 func2=curry( func, 2 ) 時,實際上是得到 curry 類別的實體。curry 類別的 __init__ 裡去做參數的判斷跟預存,等到把 func2 當函數執行時,就會執行到 __call__,這裡再去呼叫真正的函數。

Python 2 與 3 之字串與檔案

Python 3 裡,很多常用的 package 名稱都變更了,這個倒還好,在 python 2.x 的文件裡,都已經可以看到說 3 的時候,名稱會是什麼,以及要注意什麼,甚至也有 2to3 的工具來輔助轉換。
最近遇到比較麻煩的是字串與檔案的處理,Python 3 裡的字串都是以 unicode 處理,好處當然是不用轉來轉去了,比較麻煩就是讀取檔案跟寫檔案的時候。我的程式有同時用到 subprocess、urllib/urllib2與一般檔案操作,以下是整理:

  1. 進行 subprocess pipe 操作時,讀出時,都是 bytes
  2. 使用 urllib/urllib2 讀取時,都是 bytes
  3. 使用一般檔案操作,沒特別指定的話,檔案編碼會以你當前的環境編碼來讀取,預定是讀取文字檔。

所以在讀取時,為了後續能用一樣的邏輯來讀取,我統一以 binary 來讀取,避掉 encoding 問題(對於 python 3 在 binary mode時,也能正確分行、tokenize這件事上,真的是深感佩服)。是說剛好之後也不需要做精確的內容判斷,所以也不用硬轉成 string(unicode),在 python3 時,都以 bytes 存在。在 python 2,讀出來就都是一般的 string (無 unicode),不是 bytes。
寫入時,也儘量使用 bytes 去寫入,避免encoding轉來轉去的問題。

儲存空間即將不足(續)

  1. 想用 statfs 去看 /data 到底是剩多少可用,結果要自己弄 jni,一整個懶惰,就…
  2. SL4A的python應該可以用吧,查了 python 文件,得知要用 os.statvfs,但是 SL4A 的 os.statvfs 被閹割掉… 囧
  3. 查 threshold,這個應該是可以的,只是要把 Settings.Secure.SYS_STORAGE_THRESHOLD_PERCENTAGE 改成 “sys_storage_threshold_percentage”,這個沒真的下去寫程式驗證。
  4. 用 terminal+busybox df 去查 /data 的,total bytes 是 162529280,心一橫,就拿這數字設到 debug.freemem (sudo setprop debug.freemem 162529280),真的,那個討厭的”儲存空間即將不足”的通知就消失了。

以上。但是要裝比較大的app的時候,還是沒辦法裝,可惡!!

儲存空間即將不足

都上 SD Card,加裝 Link2SD 了,才裝幾個程式,Android 手機就開始唉唉叫,左上角老是出現”儲存空間即將不足”的訊息,真的是太令人生氣。本來不想挖程式出來看的,唉~
Android 程式的文字多半是存在 xml 檔案,也就是 resource 檔,關鍵是在於對應所使用的變數名稱。在 mydroid 目錄下先用 source build/envsetup.sh ,再用 resgrep ‘儲存空間即將不足’ 來找,出現這段文字的檔案有兩個,不過很明顯,變數名稱應該是 low_internal_storage_view_title。
再用 jgrep 去找:jgrep low_internal_storage_view_title ,排除掉 R.java 之後,可以看到一個不一樣的:frameworks/base/services/ajva/com/android/server/DeviceStorageMonitorService.java
看來關鍵就在這檔案裡了。從裏面可以看到在 sendNotification 裡,會把 low_internal_storage_view_title 當作訊息丟出去,於是上方的通知欄就有了’儲存空間即將不足的訊息’。那麼是在那邊去 sendNotification 的呢? 是同個檔案裡的 checkMemory()。
checkMemory() 裡的檢查邏輯很簡單,先 getMemThreshold(),再用 mFreeMem 去做判斷,如果比取到的 threshold 值要小,mLowMemFlag 還沒設為true,就先試著清理 cache,再不行,就 sendNotification。
getMemThreshold() 是怎麼取 threshold 的呢?是從 Content Resolver 裡找 “sys_storage_threshold_percentage” 來的,如果沒取到,則以 10 為預設值,然後乘上 mTotalMemory。
好,上面有幾個關鍵的變數:mTotalMemory、mFreeMem,這兩個變數又是怎麼來的?checkMemory() 裡在檢查 mFreeMem 之前,有先呼叫 restatDataDir(),這個函數會呼叫到底層的 C 函數 – statfs 來取得 /data 的資訊,statfs 回傳一個結構體,主要會使用到裏面的 f_bavail、f_bsize、f_blocks。mFreeMem = f_bavail * f_bsize; mTotalMemory = f_blocks * f_bsize。
從上面的資訊看來,如果要避免不足的問題,要不就是增加 /data 的可用空間,要不就是降低 threshold 的值。但原始碼裡透露了另外一個密技,restatDataDir() 裡,在使用 statfs 取得資訊以後,接著去取 System properties 裡的 debug.freemem,如果有取到,就拿這個當作 mFreeMem 的值來用。看來是可以利用的喔~搭配 setprop 可以設置 debug.freemem ,不過需要 root 嗎? 待驗證。

語言治療(5)

轉眼就第五次上課了,這次上課前發生了請假風波。因為趕著出門,大公子以為是要去學校,所以就情緒激動地叫不要,於是我打電話給醫院老師,跟她請假。結果下了樓,大公子才又說是要去醫院,這下尷尬了,我趕上樓,再打一次電話給老師,說今天還是會去。
今天是爸爸載大公子、媽、二公子跟我一起去的,爸跟媽要去耕莘醫院買醫療用品,二公子就順便一起去,而大公子跟我則到慈濟醫院。到了醫院,大公子喊說餓了,也是該餓的時候了,在家時叫他吃早餐,他死活都不要。就帶他到樓下全家買了蛋酥麵包跟養樂多給他吃,他很快就吃掉半個蛋酥麵包,然後喝完養樂多。
這次上課一開始,老師先問他為什麼心情不好,因為我是以他心情不好的理由跟老師請假的。他沒說,老師就先拿出3個拼圖給他拼,邊拼圖的時候,邊請他講拼圖內的圖案,然後藉機會也問他說,綠色的水果有哪些,橘色的水果有哪些。綠色的水果他只講了芭樂,老師提醒他還有哈密瓜,可惜我們家真的很少吃哈密瓜,西瓜還比較常吃,橘色的水果只講了橘子。
接著拿出三張左右對照的圖片,就左邊是不好的行為,右邊是好的行為,然後教他講跟請他講,有些部份,大公子已經講的不錯了。講到後面時,老師請他跟她講一樣的,大公子總是接著老師的話說,例如:老師說,”好寶寶要”,大公子就直接接話,而不是跟著念”好寶寶要”。老師花了一點時間,才讓他明白要跟著念。等講完這三張圖片,又再拼了3個拼圖。最後老師再請他說為什麼心情不好,大公子才說,”早上不來老師這裡啊”,所以才生氣,老師因此多給了他一張貼紙。
這次講完,老師有跟我說,大公子從評估到現在進步很多,也比一般需要語言治療的孩子要來的好,像是ㄉㄨㄟ,大公子隔週還會記得,一般的孩子則是會忘記。我是說,可能因為從年初到現在,大公子好像正處在爆發期,所以感覺上很快,也跟評估時的情況不一樣。然後有提到回家跟他複習時,他會說”不要說”。老師說,接著會調整課程內容,只是她下週請假一週。
附帶一提,晚上在看綠15路線圖時 (大公子很愛看地圖、路線圖),我發現他已經有在認字了,像”七張”,他就已經可以直接看著念出來,不需要問我。

WIFI優先於3G?

蠻怕浪費錢的,所以還去挖code驗證了一下。NetworkStateTracker 用 NetworkUtils.setDefaultRoute() 設置routing。
在ConnectiveService裡有定義優先權,但這邊的陣列值其實是在 framework/base/core/res/res/values/config.xml 中的 networkAttributes:

Type radio priority
wifi 1 1 1
mobile 0 0 0
mobile_mms 2 0 2
mobile_supl 3 0 2
mobile_hipri 5 0 3

所以再依照程式裡的邏輯,應該是WIFI為優先… (好吧,我承認我沒認真去看懂程式邏輯,所以說”應該”…)

語言治療(4)

這次一開始,老師就拿了上次”雨傘”故事的圖卡,一張張的內容再帶過一次,然後請大公子來排出順序,邊排邊說。等到故事圖卡排列完,接著拿出一本大書,裏面有許多小小的方形磁鐵,上面貼著各種東西,像是葡萄、獅子、長頸鹿、外套…等等,總共5個大類。由於時間的關係,這次只做3個大類:水果、動物、衣服。老師一樣先帶過一次,確定大公子都知道了,然後把這些小方形磁鐵弄亂,請大公子分類。
在整個過程裡,除了教導大公子講故事以外,也針對大公子某些字的發音跟慣用詞做矯正,例如:”葡萄”的”葡”、”對”、”甜”、”嘟嘟”應該是”火車”…等等。
最後老師說他7/19要請假,那天就暫停一次。
從去醫院評估之後到現在,已經快四個月了,我個人是覺得大公子在這段期間進步很多,希望在年底前就可以不用再去上語言治療課程。

語言治療(3)

第三次上課。基本上每次上課就只有半個小時,但為了這半小時,不管是大人、小孩都需要請半天假。第一次上課時,是大人請半天,大公子請整天,第二次之後,就是都請半天了。
這周是把上週的故事「雨傘」講完,除了講後半本的部份,也讓大公子重頭再講一次。邊講故事邊糾正大公子的某些發音,例如:「對」,大公子常念成「貴」,老師教他先念「ㄉㄨ」,再念「ㄟ」,合起來就是「ㄉㄨㄟˋ」。最後和大公子玩記憶卡片的遊戲 ,把兩兩一張的卡片共五組,洗牌後蓋起來,一人一次翻兩張牌,翻到一樣的牌就拿起來,算得分一次;翻到不一樣的牌就要再蓋回去,看誰拿到的牌組多。