2019年12月15日 星期日

json format for ChineseQA-with-BERT

正常解問答題時,常以1文章1問題1答案為單位進行,但準備資料集時為省空間,常依實際1文章多問題多答案格式來存放案例。 故在利用底層BERT(雙向變形器編碼表現法)微調模型及預測問答時,須將1文章多問題多答案資料,還原成1文章1問題1答案格式, 才能進行微調及預測。

百度ChineseQA-with-BERT套件可基於BERT預訓練模型作問答題微調。 其run_dureader.py可接受的訓練檔json格式,可用來存放1文章1問題1答案內容,或1文章多問題多答案內容。

其中,訓練案例的各欄位路徑如下:

․問題編號: data/paragraphs/qas/id
․文章: data/paragraphs/context
․問題: data/paragraphs/qas/question
․答案: data/paragraphs/qas/answers/text

以下舉例說明此格式用來存放1文章1問題1答案的json格式長相。
{
    "data": [
        {
            "paragraphs": [
                {
                    "context": "文章",
                    "qas": [
                        {
                            "answers": [
                                {
                                    "answer_start": 答案起點下標,
                                    "text": "答案"
                                }
                            ],
                            "is_impossible": false,
                            "id": 問題編號,
                            "question": "問題"
                        }
                    ]
                }
            ],
            "title": "N.A."
        }
   ]
}

2019年10月16日 星期三

memo for installing pycharm on ubuntu with snap-confine problem

  發覺Ubuntu 16.04/18.04下,
  若使用snap安裝pycharm
    snap install pycharm-community --classic
  老在執行時出現如下安全性問題 
    Snap-confine has elevated permissions and is not confined but should be
  
  這時,可改用如下1或2方法重新安裝 pycharm 解決執行不起來問題。
  1. umake安裝pycharm法
    sudo add-apt-repository ppa:ubuntu-desktop/ubuntu-make
    sudo apt-get update
    sudo apt-get install ubuntu-make
    --
    umake ide pycharm
  其中,安裝路徑預設在~/.local/share/umake/...
  可以搬到全域路徑供大家共用:
   cd /usr/local/share
   sudo cp -pr ~/.local/share/umake .
   sudo ln -s /usr/local/share/umake/bin/jetbrains-pycharm-ce /usr/bin/pycharm
  這時就可用pycharm啟動ide整合開發環境
  
  2. 直接下載tar.gz安裝pycharm法
    https://www.jetbrains.com/pycharm/download/#section=linux

    cd /usr/local/share
    sudo tar zxvf pycharm-2019.2.3.tar.gz 
    sudo ln -s /usr/local/share/pycharm-2019.2.3/bin/pycharm.sh /usr/bin/pycharm
  這時就可用pycharm啟動ide整合開發環境

2019年10月12日 星期六

memo for streaming google drive on ubuntu file system

若想在Ubuntu檔案系統掛載串流版Google硬碟,可考慮安裝google-drive-ocamlfuse。
串流版好處是不佔實體硬碟空間,有須要才從雲端抓取資料到快取區。
其安裝指令如下,須管理者權限:
 $ sudo add-apt-repository ppa:alessandro-strada/ppa
 $ sudo apt install google-drive-ocamlfuse

安裝好之後,可供一般用戶以用戶模式掛載到家目錄,方便存取。
以下掛載指令只要執行一次即可,會啟動瀏覽器作身份確認:
  $ mkdir ~/google-drive
  $ google-drive-ocamlfuse ~/google-drive

若想卸載,可用以下指令
  $ fusermount -u ~/google-drive

症狀A: 發現執行 google-drive-ocamlfuse,沒有跳出瀏覽器驗證身份。
解法A: 清空快取狀態,指令是 google-drive-ocamlfuse -cc
       或顯示掛載除錯訊息,指令是 google-drive-ocamlfuse -debug ~/google-drive
      

症狀B: 發現 google-drive-ocamlfuse 不釋放刪除檔案之快取內容,吃光個人硬碟配額。
       用 quotarepquota -avus 指令看得到配額用光,而 du -s ~/ 指令卻看不到被誰吃光,
       但用 lsof | grep pid 指令則可以看到上千個 50MB 快取塊仍未釋放。
解法: 重新啟動google-drive-ocamlfuse,作法是
1.查詢google-drive-ocamlfuse行程pid,指令為 ps ux | grep google-drive-ocamlfuse
2.刪除google-drive-ocamlfuse行程,釋放已刪除快取,指令為 kill -9 pid
3.重新啟動google-drive-ocamlfuse,指令為 google-drive-ocamlfuse ~/google-drive

參考
1. Rendeck (2018) Google Drive on Ubuntu 18.04 Bionic Beaver Linux
2. GitHub: Disk space not freed up from cache #512
3. EPH 的程式日記 [Linux] 使用 lsof, lslocks, fuser 指令列出目前鎖定中的 file locks
4. 想知道硬碟用量及哪些目錄、檔案最耗空間的指令如下: 
     > quota       # 看個人配額使用情形
     > du -s ~/*    # 看個人第一層家目錄空間用量
     > tree -s --sort=size ~  # 逐層列舉家目錄以下各檔案大小,由大到小排序
                              # 若無tree指令,可請管理員用 sudo apt-get install tree指令安裝

2019年8月21日 星期三

memo for installing docker-ce on ubuntu 18.04

Quick Memo for Installing docker-ce on Ubuntu 18.04

# prepare utilities
> sudo apt-get update
> sudo apt-get install apt-transport-https ca-certificates curl software-properties-common

# add key and repository
#    curl -f fail silently
#    curl -s silent mode
#    curl -S show error
#    curl -L allow redirect
> curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
> sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu bionic stable"

# install docker-ce
> sudo apt-get install docker-ce

# check docker status
> sudo service docker status
> sudo systemctl status docker

# grant docker permission to specific user 'foobar'
> sudo setfacl -m user:foobar:rw /var/run/docker.sock
> sudo setfacl -x user:foobar /var/run/docker.sock
> getfacl /var/run/docker.sock
getfacl: 從絕對路徑名尾部去除“/”字符
# file: var/run/docker.sock
# owner: root
# group: docker
user::rw-
user:foobar:rw-
group::rw-
mask::rw-
other::---
> docker image list

# disable and unload AppArmor for container removal
> sudo aa-status
> sudo systemctl disable apparmor.service --now
> sudo service apparmor teardown
> sudo aa-status


Reference:
1.如何在Ubuntu 18.04上安裝與更新Docker
2.How to use Docker without sudo on Ubuntu
3.Play With Docker provides an Alpine Linux 3.10 environment with docker and git ready for use
     CPU: Intel(R) Xeon(R) CPU E5-2673 v4 @ 2.30GHz with 8 cores
     Memory: 32GB
     Drive: 64GB with 16GB used
     Limit: Use of up to 5 nodes for up to 4 hours per session

2019年8月20日 星期二

what are the four addresses of an NAT table?

為了達到內部私有網路和外部公開網路有所區隔又可適當互通的防火牆功能,
NAT網路住址轉換技術用到如下4個住址組成的表格作比對及替換:

inside global address 內部主機全域端住址(IGA)
inside local address 內部主機本地端住址(ILA)
outside local address 外部主機本地端住址(OLA)
outside global address 外部主機全域端住址(OGA)

其中,IGA及ILA為內部網路主機於全域端及本地端網路的代表住址,
     OLA及OGA為外部網路主機於全域端及本地端網路的代表住址;
     ILA/OLA為連線封包在本地端網路傳送時的內部/外部網路主機住址,
     IGA/OGA為連線封包在全域端網路傳送時的內部/外部網路主機住址。
即講主機住址時用內部/外部區分主機所在位置,講封包傳送時用本地端/全域端網路區分傳送所在位置,
又住址轉換只發生在內部主機的全域端住址(IGA)及內部主機的本地端住址(ILA)兩者之間。

NAT遇連線封包由內網流向外網,將取封包的來源住址及去處住址,
  比對NAT表格記錄的【內部主機的本地端住址(ILA),外部主機的本地端住址(OLA)】兩欄位,
  若記錄比對成功,將封包的來源住址私有IP替換成NAT表格記錄的【內部主機的全域端住址(IGA)】公開IP。
  若記錄比對不到,建立新記錄如下
      內部主機的全域端住址(IGA) = NAT公開IP
      內部主機的本地端住址(ILA) = 封包來源住址
      外部主機的本地端住址(OLA) = 封包去處住址
      外部主機的全域端住址(OGA) = 封包去處住址

NAT遇連線封包由外網流向內網,將取封包的來源住址及去處住址,
  比對NAT表格記錄的【外部主機的全域端住址(OGA),內部主機的全域端住址(IGA)】兩欄位,
  若記錄比對成功,將封包的去處住址公開IP替換成NAT表格記錄的【內部主機的本地端住址(ILA)】私有IP。
  若記錄比對不到,封包丟棄。

2019年7月31日 星期三

aws my billing dashboard

使用AWS雲端服務由於綁信用卡,且無法訂刷卡上限,所以使用任何服務,最好隨時注意用量,以控制預算。由於用量不一定能立即統計,有可能延遲6小時反應,所以記得測試完,隔一陣子要回頭看一下用量。看用量最簡單方法就是點選【帳號名/我的帳單儀表板(My Billing Dashboard)】,進入帳單與成本管理設定頁面(Billing and Cost Management Dashboard),觀察消費摘要(Spend Summary)的月初至今總金額,及月初至今服務的消費(Month-to-Date Spend by Service)細目。AWS文件提供典型的帳單與成本管理設定頁面供參考,全沒使用的0用量頁面則如下:


2019年7月28日 星期日

iam login v.s. root login for aws

AWS分成IAM及root兩種登入模式,常常讓初學者摸不著頭緒。
A. root登入模式由以下入口進入,

   https://console.aws.amazon.com/console/home

須要經過3個畫面,分別輸入郵箱,安全檢查碼,及密碼三欄位,如下


郵箱欄位


安全檢查碼欄位


密碼欄位
B. IAM登入模式須要單畫面,輸入ID,IAM,密碼三欄位,如下
註:root及 IAM 兩種登入模式可彼此切換 A. root登入模式可按 Sign in to a different account 切換到 IAM 登入模式。 B. IAM 登入模式也可按 Sign-in using root account credentials 切換到root登入模式。 又一個root帳號可以建立很多個IAM帳號,供不同權限登入之用。

2019年7月27日 星期六

how to give an IAM user full access except account and payment methods information

依最小權限的安全原則,AWS服務允許設定IAM群組/使用者,只賦予特定任務所須權限,以完成基本任務要求。
可是,IAM群組/使用者在使用服務時又常常須要隨時觀察服務使用量,以避免帳單超額。
理由是AWS帳號須綁信用卡,且無法設定付款上限,所以觀察服務用量,避免浪費才是省錢王道。

照理說AWS應該將觀察使用金額列為基本功能,偏偏AWS為了避免帳單等敏感資料遭非帳號擁有者看到,
將帳單和成本管理(Billing and Cost Management)的許可(Permission)分為如下幾類:
   aws-portal:ViewBilling
   aws-portal:ModifyBilling
   aws-portal:ViewAccount
   aws-portal:ModifyAccount
   aws-portal:ViewPaymentMethods 
   aws-portal:ModifyPaymentMethods
   aws-portal:ViewUsage
   -
   budgets:ViewBudget
   budgets:ModifyBudget
   -
   cur:DescribeReportDefinitions
   cur:PutReportDefinitions
   cur:DeleteReportDefinition
同時預設所有IAM群組/使用者不能取用上述帳單和成本管理服務,簡稱Billing服務。
這樣除了帳號擁有者自己看得到,其他受委託任務的IAM群組/使用者將無從直接觀察服務使用量,
只能間接等設定的預算超額收到通知才知道用量太多,容易造成帳單意外超額。

所以,假設帳號擁有者希望IAM群組/使用者擁有管理者權限,但不能看帳戶,付款方法等敏感資料,
則建議帳號擁有者可作如下組態設定。

1.Console/My Account: 啟動IAM存取選項,使其有機會取用Billing服務

2.Console/IAM: 為IAM群組/用戶套用如下政策,可用Billing服務,但拒絕其中敏感的帳戶及付款方法服務 受管政策: 連接政策,例如: 預設的管理者權限AdministratorAccess,包含Billing服務, 如下 { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "*", "Resource": "*" } ] } 內嵌政策: 建立群組政策,例如: 建立自行命名的 policygen-deny_view_account_paymentmethods-201907271730 如下 { "Version": "2012-10-17", "Statement": [ { "Sid": "Stmt1564219794000", "Effect": "Deny", "Action": [ "aws-portal:ViewAccount", "aws-portal:ModifyAccount", "aws-portal:ModifyBilling", "aws-portal:ViewPaymentMethods", "aws-portal:ModifyPaymentMethods" ], "Resource": [ "*" ] } ] }
註1: 上述作法雖方便管理者在敏感資料獲保護下,以適當權限委託IAM群組/使用者, 使其得以一邊看帳單用量,一邊完成任務,避免帳單超額, 但是在看帳單用量部份,目前AWS無法細分那些服務用量能給誰看, 也就是說其他IAM群組/使用者的用量也會一併看到,這是其缺點。 註2: 針對公司或學校,若只想開一個AWS帳戶給一個專案使用,則上述作法很適合參考。 因為同一個專案用戶本來就知道會用到那些服務,無須保密。 又給其管理者權限也無妨,因為專案本來就可能作各種服務測試,無從事先設限。 只要設定一個有限預算金額,設定預算達到多少用量就自動寄發通知(Alert)間接提醒, 再搭配專案用戶隨時可直接查看有時間延遲的使用量,應可有效防止意外的帳單超額情形。 註3: AWS針對學生及教育工作者有提供AWS Educate帳號,可獲得定量的免費學習配額。 若不綁信用卡,可建立免費配額較低的AWS Educate Starter帳號,用完為止。 但無法使用某些特定或局部的AWS服務,詳AWS Educate Starter帳號提供的服務清單。 Cf: Billing and Cost Management 許可參考

2019年7月21日 星期日

wmts/wms maps of taiwan from sinica/nlsc

隨著地圖應用的普及化,開放地理空間協會(OGC, Open Geospatial Consortium)及
開源地理空間基金會(OSGeo, Open Source Geospatial Foundation)相繼製訂很多公開地圖存取標準,例如:
 
  OGC-1999-網路地圖服務 (WMS, Web Map Service) 
  OGC-2004-網路圖徵服務(WFS, Web Feature Service) 
  0SGeo-2006-圖磚服務 (TMS, Tile Map Service) 
  OGC-2010-網路圖磚服務 (WMTS, Web Map Tile Service) 

台灣地區目前提供免費地圖服務的主要有如下兩機構,2019.7.截止地圖列表如後。
可利用JOSMQGIS免費地圖軟體純觀看,及利用OpenLayersLeaflet免費JavaScript套件內嵌於網頁呈現。

A.國土測繪中心提供的台灣WMS地圖清單: (共計46種地圖)
  http://wms.nlsc.gov.tw/wms?SERVICE=WMS&REQUEST=GetCapabilities
           - 6種
           縣市界 (CITY)
           鄉鎮區界 (TOWN)
           村里界 (Village)
           段籍圖 (LANDSECT)
           地政事務所轄區圖 (LandOffice)
           各級學校範圍圖 (SCHOOL)
           - 2種
           1/5000基本地形圖 (B5000)
           1/5000圖幅框 (MB5000)
           - 9種
           坡向圖 (MOI_ASPECT)
           等高線圖(2003-2005) (MOI_CONTOUR)
           等高線圖(2010-2015) (MOI_CONTOUR_2)
           陰影圖 (MOI_HILLSHADE)
           渲染圖 (MOI_SHADERMAP)
           坡度圖-30%坡(2003-2005) (MOI_SLOPEP_GT30)
           坡度圖-30%坡(2010-2015) (MOI_SLOPEP_GT30_2)
           坡度圖-7級(2003-2005) (MOI_SLOPEP_LV7)
           坡度圖-7級(2010-2015) (MOI_SLOPEP_LV7_2)
           - 10種
           國土利用調查成果圖 (LUIMAP)
           國土利用調查-1類農業 (LUIMAP01)
           國土利用調查-2類森林 (LUIMAP02)
           國土利用調查-3類交通 (LUIMAP03)
           國土利用調查-4類水利 (LUIMAP04)
           國土利用調查-5類建築 (LUIMAP05)
           國土利用調查-6類公共 (LUIMAP06)
           國土利用調查-7類遊憩 (LUIMAP07)
           國土利用調查-8類礦鹽 (LUIMAP08)
           國土利用調查-9類其他 (LUIMAP09)
           - 2種
           正射影像圖(通用) (PHOTO2)
           正射影像(混合) (PHOTO_MIX)
           - 17 種
           臺灣通用電子地圖 (EMAP)
           臺灣通用電子地圖(灰階) (EMAP01)
           臺灣通用電子地圖透明 (EMAP2)
           臺灣通用電子地圖(套疊等高線) (EMAP5)
           臺灣通用電子地圖(套疊等高線)opendata, 最大比例尺一萬八千分之一 (EMAP5_OPENDATA)
           臺灣通用電子地圖(不含等高線) (EMAP6)
           臺灣通用電子地圖(不含等高線)opendata, 最大比例尺一萬八千分之一 (EMAP6_OPENDATA)
           taiwane-map(transparent) (EMAP7)
           taiwane-map(en) (EMAP8)
           臺灣通用電子地圖(無鐵公路) (EMAP9)
           臺灣通用電子地圖透明(無門牌) (EMAP12)
           臺灣通用電子地圖(無門牌) (EMAP15)
           臺灣通用電子地圖(不含等高線及門牌) (EMAP16)
           臺灣通用電子地圖(高dpi字) (EMAP96)
           taiwan e-map(new) (EMAP97)
           臺灣通用電子地圖(新) (EMAP98)
           臺灣通用電子地圖(無文字) (EMAPX99)

B.中研院提供的台灣WMTS地圖清單: (共計48種地圖)
  http://gis.sinica.edu.tw/tileserver/wmts
           1897-日治臺灣假製二十萬分一圖-1:200,000 (JM200K_1897)
           1899-日治臺灣全圖-1:400,000 (JM400K_1899)
           1901-日治行政區-廳(1900年代) (Admin_1901a)
           1901-日治行政區-堡里(1900年代) (Admin_1901b)
           1901-日治行政區-街庄(1900年代) (Admin_1901c)
           1904-日治臺灣堡圖(明治版)-1:20,000 (JM20K_1904)
           1905-日治臺灣圖-1:100,000 (JM100K_1905)
           1914-日治官有林野圖(臺東廳) (Map_LSB1_Taitung)
           1914-日治官有林野圖(花蓮港廳) (Map_LSB1_Hualien)
           1916-日治蕃地地形圖-1:50,000 (JM50K_1916)
           1920-日治地形圖(總督府土木局)-1:50,000 (JM50K_1920)
           1921-日治地形圖-1:25,000 (JM25K_1921)
           1921-日治臺灣堡圖(大正版)-1:20,000 (JM20K_1921)
           1924-日治地形圖(陸地測量部)-1:50,000 (JM50K_1924)
           1924-日治地形圖(陸地測量部)-1:50,000 (JM50K_1924_new)
           1930-日治行政區-州廳(1930年代) (Admin_1930a)
           1930-日治行政區-郡市(1930年代) (Admin_1930b)
           1930-日治行政區-街庄(1930年代) (Admin_1930c)
           1932-二十萬分一帝國圖(臺灣部分) (JM200K_1932)
           1934-日治臺灣全圖(第三版)-1:300,000 (JM300K_1934)
           1936-五十萬分一輿地圖(臺灣部分)-1:500,000 (JM500K_1936)
           1939-日治臺灣全圖(第五版)-1:300,000 (JM300K_1939)
           1942-日治二萬五千分之一地形圖(昭和修正版) (JM25K_1942)
           1944-日治地形圖(航照修正版)-1:25,000 (JM25K_1944)
           1944-美軍地形圖-1:50,000 (AM50K_1944)
           1945-美軍繪製臺灣城市地圖 (AMCityPlan_1945)
           1945-美軍航照影像(1945/6/17攝) (Taipei_aerialphoto_1945)
           1956-臺灣土地利用及林型圖 (1956_Landuse)
           1956-臺灣地形圖-1:50,000 (TM50K_1956)
           1966-臺灣省水利工程、水文站及基準點位置圖 (TM50K_1966)
           1987-臺灣地形圖-1:100,000 (TM100K_1987)
           1989-臺灣經建1版地形圖-1:25,000 (TM25K_1989)
           1990-臺灣經建1版地形圖-1:50,000 (TM50K_1990)
           1993-臺灣經建2版地形圖-1:25,000 (TM25K_1993)
           1996-臺灣經建2版地形圖-1:50,000 (TM50K_1996)
           2001-臺灣經建3版地形圖-1:25,000 (TM25K_2001)
           2003-臺灣經建3版地形圖-1:50,000 (TM50K_2003)
           2003-臺灣經建4版地形圖-1:25,000 (TM25K_2003)

2019年7月16日 星期二

forward to and send as setup for gmail

Gmail信箱可以換發信者身份,將寄出的信件當成從公司信箱發出,方便對方回信也回覆到公司信箱。
另外,也可以一律將收到的信件轉寄到另一信箱,通常是容量較大的信箱,例如Google Apps機構信箱。
在修改發信來源及轉信去處時,為避免濫用,常須驗證兩者信箱是否為同一人所擁有。
故須利用寄驗證信方式作身份驗證。比較特別的是驗證信寄出時,是委託第3方程式從Gmail發信伺服器送出,
因此,要填入的為Gmail帳號及從Google申請得到的第3方應用程式密碼。

以下簡單摘要Gmail信箱修改發信來源及轉信去處的方法:

A.修改Gmail發信來源:  設定以某信箱身份發信
    Gmail/設定/帳戶和匯入:
      以這個地址寄送郵件:(使用 Gmail 從您的其他電子郵件地址傳送郵件)
        xalias <xxx@gmail.com> [設為預設值] [修改資訊]     (此為驗證過候選信箱1)
        yalias <yyy@gmail.com> [設為預設值] [修改資訊]     (此為驗證過候選信箱2)
        zalias <zzz@gmail.com> [預設] [修改資訊] [刪除]    (此為目前使用的發信身份信箱)
        郵件遞送伺服器:smtp.gmail.com
        採用 [TLS] 的加密連線 (通訊埠 587)
        [新增另一個電子郵件地址]
        回覆郵件時:
          來自和郵件傳送地址相同位置的回覆
         o永遠從預設的地址回覆 (目前是 zzz@gmail.com)
          (注意:您可以在回覆的同時變更電子郵件地址 [瞭解詳情])

B.修改Gmail轉信去處:  設定信件一律轉寄某信箱
    Gmail/設定/轉寄和 POP/IMAP:
      轉寄:  [瞭解詳情]
          停用轉寄
         o轉寄外來郵件副本給 [zzz@gmail.com] 並且 [刪除Gmail的副本]
         [新增轉寄地址]
         提示:您也可以建立[篩選器],只轉寄部分郵件。
         --
         [儲存變更] [取消]

註1: 在發信新增電子郵件地址及修改資訊時,有兩種驗證法
         收到驗證信,點選連結確認
         收到驗證信,回填驗證碼
     兩種皆須從smtp.gmail.com,通過Gmail帳密,寄驗證信到新增電子郵件地址
     其中,填寫的密碼不是原始Gmail密碼,而是允許第3方存取Gmail帳號之應用程式臨時密碼,詳註2。

     其操作過程如下:
     1.新增您其他的電子郵件地址:
         輸入您其他電子郵件地址的資訊。
         (您所傳送的郵件上會顯示您的姓名和電子郵件地址)
           名稱: alias (填寫發信者別名)
   電子郵件地址: abc@xxx.yyy.zzz (填寫發信者信箱)
               V視為別名。[瞭解詳情]
               [指定不同的回覆至地址](選用)

     2.新增您其他的電子郵件地址:
         透過SMTP伺服器傳送郵件
         -
         將您的郵件設為透過 xxx.yyy.zzz SMTP 伺服器傳送 [瞭解詳情]
         SMTP 伺服器: smtp.gmail.com 通訊埠: 587    (維持預設Gmail發信SMTP伺服器)
          使用者名稱: uuu   (填寫gmail帳號名稱,不含@gmail.com)
                密碼: vvv  (填寫允許第3方存取gmail帳號之應用程式臨時密碼,取得法參考註2)
              o採用[TLS]的加密連線(建議使用)
               採用[SSL]的加密連線
              [取消] [上一步] [新增帳戶]

     3.驗證信寄出成功訊息  
         確認驗證並加入您的電子郵件地址
         恭喜!系統已找到該伺服器並驗證您的憑證,完成最後一個步驟即可開始使用!
         附有確認碼的電子郵件已傳送至 abc@xxx.yyy.zzz。 [重新傳送電子郵件]
         如要新增電子郵件地址,請任選以下其中一種方法:
         按一下確認電子郵件中的連結  或  輸入並驗證確認碼。

     4.驗證信寄出失敗訊息
         驗證失敗,請檢查您的使用者名稱/密碼。
         [伺服器回應:534-5.7.9 Application-specific password required. Learn more at 534 5.7.9 
         https://support.google.com/accounts/answer/185833 h30sm162349uad.6 - gsmtp code(534) ]
         申請應用程式密碼網址: https://security.google.com/settings/security/apppasswords?pli=1

註2: 如何取得允許第3方存取gmail帳號之應用程式臨時密碼
        進入Google帳號/安全性/登入Google: 應用程式密碼
        身份驗證後,即可取得應用程式密碼vvv。

註3: 寄發驗證信時,除了使用預設的Gmail發信SMTP伺服器,填入Gmail應用程式密碼之外,
     也可使用公司機構的發信SMTP伺服器,這時填入的帳密即為公司機構帳密,可省去Gmail取應用程式密碼的困擾。
     但是因為限定採用TLS及SSL連線,如果發信SMTP伺服器不支援此兩類加密連線,只好回復使用Gmail發信SMTP伺服器。

how to run windows sandbox

Steps for running Windows Sandbox for Testing Purposes 

A.check windows version
   Search Bar: CMD
     Microsoft Windows [Version 10.0.18362.239]

B.check bios setup
   Reboot
   Press Del

   Asus UEFI BIOS Utility - Advanced Mode

   Boot \ CSM (Compatibility Support Module)
   Launch CSM:   Enabled
   Boot Device:  UEFI and Legacy OpROM
   Boot from Network Devices: Ignore
   Boot from Storage Devices: Both, Legacy OpROM First

   -----

   Advanced \ CPU Configuration
   ...
   Hyper-threading: Enabled
   ...
   Intel Virtualization Technology: Enabled
   ...

   -----
   Save and Reset

C.check windows features
   Search Bar: Turn Windows features on or off
      Windows Sandbox      V

D.reboot
   Search Bar: Windows Sandbox

E.check NAT networking
   Search Bar: CMD

  C:\Users\WDAGUtilityAccount> ipconfig /all

  Windows IP Configuration

   Host Name . . . . . . . . . . . . : 60347f14-fb9f-4411-b680-c4514197c248
   Primary Dns Suffix  . . . . . . . :
   Node Type . . . . . . . . . . . . : Mixed
   IP Routing Enabled. . . . . . . . : No
   WINS Proxy Enabled. . . . . . . . : No
   DNS Suffix Search List. . . . . . : mshome.net

  Ethernet adapter 乙太網路:

   Connection-specific DNS Suffix  . : mshome.net
   Description . . . . . . . . . . . : Microsoft Hyper-V Network Adapter
   Physical Address. . . . . . . . . : C8-27-CC-C2-37-5A
   DHCP Enabled. . . . . . . . . . . : Yes
   Autoconfiguration Enabled . . . . : Yes
   Link-local IPv6 Address . . . . . : fe80::8cd6:5a39:ffd6:d73a%6(Preferred)
   IPv4 Address. . . . . . . . . . . : 192.168.142.78(Preferred)
   Subnet Mask . . . . . . . . . . . : 255.255.255.240
   Lease Obtained. . . . . . . . . . : Tuesday, July 16, 2019 1:15:55 PM
   Lease Expires . . . . . . . . . . : Wednesday, July 17, 2019 3:37:37 PM
   Default Gateway . . . . . . . . . : 192.168.142.65
   DHCP Server . . . . . . . . . . . : 192.168.142.65
   DHCPv6 IAID . . . . . . . . . . . : 113780684
   DHCPv6 Client DUID. . . . . . . . : 00-01-00-01-24-BF-15-E3-C8-27-CC-C2-37-5A
   DNS Servers . . . . . . . . . . . : 192.168.142.65
   NetBIOS over Tcpip. . . . . . . . : Enabled

2019年6月5日 星期三

jquery getJSON and ajax functions for calling JSON-based web services

網頁端利用jquery提供的高階javascript方法getJSON或ajax取用其他網頁服務的寫法,資料傳收過程皆採用json格式:

  $.getJSON( "http://host:port/path",
      {bookID:"1309088",format:"json"})
    .done(function( data ) {
      var output = "";
      for(var i in data.items){
         output ="<li>" + data.items[i].value + "," + data.items[i].id + "," + data.items[i].name + "</li>\n";
         $('#result').append(output);
      }
    })
    .fail(function() {
       window.alert("fail");
    });
  //--
  $.ajax({
      url: 'http://host:port/path',   //存取Json的網址
      type: 'post',
      cache:false,
      dataType: 'json', // format expected from server
      contentType: 'application/json; charset=utf-8', // format sent to server
      data: JSON.stringify({bookID:"1309088}),
    success: function (data) {
      html = '<table>';
      i=1;
      $.each(data, function () {
          html +=  '<tr><td>' + data[i]['model'] + '</td>'
                   ' + data[i]['epoch'] + '</td></tr>\n';
         i++;
      });
      html += '</table>';

      document.getElementById("list_model").innerHTML = html;
    },
    error: function (xhr, ajaxOptions, thrownError) {
      document.getElementById("result").innerHTML =
        'internal error(' + xhr.status + ',' + thrownError + '), try again...';
    }
  });

2019年5月28日 星期二

install chinese and japanese fonts for matplotlib and seaborn plots

import matplotlib
from matplotlib.font_manager import FontProperties

### 下載日中字型檔
### install japanese font
!apt-get -y install fonts-ipafont-gothic
font_jp = FontProperties(fname=r'/usr/share/fonts/opentype/ipafont-gothic/ipagp.ttf',size=20)
print(font_jp.get_family())
print(font_jp.get_name())

### install chinese font
!apt-get -y install fonts-moe-standard-kai 
font_tw = FontProperties(fname=r'/usr/share/fonts/truetype/moe/MoeStandardKai.ttf',size=20)
print(font_tw.get_family())
print(font_tw.get_name())

### install chinese,japanese,korean font
#!apt-get install fonts-noto-cjk  ## .ttc
#font_cjk = FontProperties(fname=r'/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc',size=20)
#print(font_cjk.get_family())
#print(font_cjk.get_name())

!apt-get install ttf-unifont
font_uni = FontProperties(fname=r'/usr/share/fonts/truetype/unifont/unifont.ttf',size=20)
print(font_uni.get_family())
print(font_uni.get_name())

### 設定畫圖啟用 sans-serif 系列字型
!grep font.family /usr/local/lib/python3.6/dist-packages/matplotlib/mpl-data/matplotlibrc
!sed -i "s/#font.family/font.family/" /usr/local/lib/python3.6/dist-packages/matplotlib/mpl-data/matplotlibrc
!grep font.family /usr/local/lib/python3.6/dist-packages/matplotlib/mpl-data/matplotlibrc

### 設定屬於 sans-serif 系列字型包含日中字型
!grep font.sans-serif /usr/local/lib/python3.6/dist-packages/matplotlib/mpl-data/matplotlibrc
!sed -i "s/#font.sans-serif.*DejaVu Sans/font.sans-serif     : IPAPGothic, TW-MOE-Std-Kai, Unifont, DejaVu Sans/" /usr/local/lib/python3.6/dist-packages/matplotlib/mpl-data/matplotlibrc
#!sed -i "s/font.sans-serif.*DejaVu Sans/font.sans-serif     : IPAPGothic, TW-MOE-Std-Kai, Unifont, DejaVu Sans/" /usr/local/lib/python3.6/dist-packages/matplotlib/mpl-data/matplotlibrc
!grep font.sans-serif /usr/local/lib/python3.6/dist-packages/matplotlib/mpl-data/matplotlibrc

### 連結日中字型檔到畫圖字型目錄
!ln -s /usr/share/fonts/opentype/ipafont-gothic/ipagp.ttf /usr/local/lib/python3.6/dist-packages/matplotlib/mpl-data/fonts/ttf/
!ln -s /usr/share/fonts/truetype/moe/MoeStandardKai.ttf /usr/local/lib/python3.6/dist-packages/matplotlib/mpl-data/fonts/ttf/
#!ln -s /usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc /usr/local/lib/python3.6/dist-packages/matplotlib/mpl-data/fonts/ttf/
!ln -s /usr/share/fonts/truetype/unifont/unifont.ttf /usr/local/lib/python3.6/dist-packages/matplotlib/mpl-data/fonts/ttf/
!ls /usr/local/lib/python3.6/dist-packages/matplotlib/mpl-data/fonts/ttf/[Miu]*

### 重建畫圖字型快取,納入日中字型檔
matplotlib.font_manager._rebuild()
flist = matplotlib.font_manager.get_fontconfig_fonts()
names = [matplotlib.font_manager.FontProperties(fname=fname).get_name() for fname in flist]
print(names)

### 確認sans-serif系列清單有日中字型
print(matplotlib.rcParams['font.sans-serif'])  ## 確認sans-serif系列清單是否有日中字型
if 'IPAPGothic' not in matplotlib.rcParams['font.sans-serif']:
  matplotlib.rcParams['font.sans-serif'] = ['IPAPGothic', 'TW-MOE-Std-Kai', 'Unifont'] + matplotlib.rcParams['font.sans-serif']
print(matplotlib.rcParams['font.sans-serif'])

### 測試畫圖字型顯示
#!!!!! 若X軸標示字型有誤,表示引擎快取仍未更新,請【重新啟動並運行所有單元格】
import matplotlib.pyplot as plt

testString = u"喜欢 海灘 散步 걷기 好き"   ## 簡中,繁中,日文,韓文,日文
plt.title(testString, fontproperties=font_uni)
plt.xlabel(testString)   # 利用sans-serif第一個字型顯示
plt.ylabel(testString, fontproperties=font_tw)
plt.show()
import seaborn as sns
emotion_counter = [('愉快', 200), ('高興', 180), ('開心', 160), ('歡喜', 140), ('生氣', 130), ('憤怒', 120), ('悲傷', 110), ('難過', 100), ('哀愁', 90), ('傷感', 80)]
sns.set_color_codes("pastel")
sns.barplot(x=[k for k, _ in emotion_counter], y=[v for _, v in emotion_counter])
參考: 解決Python 3 Matplotlib與Seaborn視覺化套件中文顯示問題 link

flask-based web interface deployment for pytorch chatbot

### folder structure and flask setup
> ls 
data/  pytorch_chatbot/  save/  templates/  web.py

> ls templates/
template.html

> conda install Flask

> python web.py
 * Serving Flask app "web" (lazy loading)
 * Environment: production
   WARNING: Do not use the development server in a production environment.
   Use a production WSGI server instead.
 * Debug mode: off
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)


<html>
<title>template.html</title>
<body>
<pre>
Test page for pytorch chatbot on seq2seq dataset
<form action='translate' method='post'>
model: <input type='text' name='model' value='{{param["model"]}}' />
epoch: <input type='text' name='epoch' value='{{param["epoch"]}}' />
topn: <input type='text' name='topn' value='{{param["topn"]}}' />
query: <input type='text' name='query' value='{{param["query"]}}'/>
<input type='submit' value='translate' />
</form>
{{param['result']}}
</pre>
</body>
</html>



##########################
# web.py
#    > python web.py
#########################
from flask import Flask, request, render_template

import torch
import random
import pytorch_chatbot.main as pcm
import pytorch_chatbot.evaluate as pce
from pytorch_chatbot.train import indexesFromSentence
from pytorch_chatbot.load import loadPrepareData
from pytorch_chatbot.model import nn, EncoderRNN, LuongAttnDecoderRNN

import subprocess
import json

def predictLoad(corpus, modelFile, n_layers=1, hidden_size=512):
  print('corpus={}\nmodelFile={}'.format(corpus,modelFile))

  torch.set_grad_enabled(False)
  voc, pairs = loadPrepareData(corpus)
  embedding = nn.Embedding(voc.n_words, hidden_size)
  encoder = EncoderRNN(voc.n_words, hidden_size, embedding, n_layers)
  attn_model = 'dot'
  decoder = LuongAttnDecoderRNN(attn_model, embedding, hidden_size, voc.n_words, n_layers)

  checkpoint = torch.load(modelFile)
  encoder.load_state_dict(checkpoint['en'])
  decoder.load_state_dict(checkpoint['de'])

  # train mode set to false, effect only on dropout, batchNorm
  encoder.train(False)
  decoder.train(False)

  #try:
  encoder = encoder.to(device)
  decoder = decoder.to(device)
  #except:
  #  print('cannot get encoder/decoder')
  
  return encoder, decoder, voc

def predict(encoder, decoder, voc, question, top):
  result_list = []

  if(top==1):
    beam_size = 1
    output_words, _ = pce.evaluate(encoder, decoder, voc, question, beam_size)
    answer = ' '.join(output_words)
    answer = answer.replace('<EOS>','')
    result_list.append(answer)
    #print(output_words)
  else:
    beam_size = top
    output_words_list = pce.evaluate(encoder, decoder, voc, question, beam_size)
    count = 0;
    for output_words, score in output_words_list:
      count = count + 1
      if(count <= top):
        output_sentence = ' '.join(output_words)
        output_sentence = output_sentence.replace('<EOS>','')
        result_list.append(output_sentence)
        #print(" {:.3f} < {}".format(score, output_sentence))
  
  return result_list

def filter(voc, question):
  words = question.split()
  result = []
  for w in words:
    if(w in voc.word2index):
      result.append(w) 
  return ' '.join(result)

# -------------------------------
def sentence_test(voc,en,de,top,sentence):
    source = sentence.rstrip()
    seg_source = source
    fil_source = filter(voc, seg_source)
    target = predict(en, de, voc, fil_source, top)
    result = "\nsource: '%s'\nfilter: '%s'\n" % (seg_source,fil_source)
    
    for answer in target:
      result = result + "\t'%s'\n" % (answer)
    
    result = result + '\n'
    return result

def sentence_test_model(seg_corpus_name, iteration, top, sentence):
  n_layers = 1
  hidden_size = 512

  modelFile = home_path + 'save/model/' + seg_corpus_name + '/1-1_512/' + str(iteration) + '_backup_bidir_model.tar'

  en, de, voc = predictLoad(seg_corpus_name, modelFile, n_layers, hidden_size)

  return sentence_test(voc,en,de,top,sentence)

def file_test(voc,en,de,top,test_file_name):
  with open(test_file_name,"r") as f:
    jp_data = f.readlines()

  for i,source in enumerate(jp_data):
    source = source.rstrip()
    seg_source = source
    fil_source = filter(voc, seg_source)
    target = predict(en, de, voc, fil_source, top)
    print("%d:\nsource: '%s'\nfilter: '%s'" % (i+1,seg_source,fil_source))
    
    for answer in target:
      print("\t'%s'" % (answer))

def file_test_model(seg_corpus_name, iteration, top, test_file_name):
  n_layers = 1
  hidden_size = 512

  modelFile = home_path + 'save/model/' + seg_corpus_name + '/1-1_512/' + str(iteration) + '_backup_bidir_model.tar'

  en, de, voc = predictLoad(seg_corpus_name, modelFile, n_layers, hidden_size)

  file_test(voc,en,de,top,test_file_name)
  
def print_voc(voc):
  print('tw+jp voc size=%d' % (len(voc.word2index)))
  print(voc.index2word)

def list_models(seg_corpus_name=''):
  if seg_corpus_name=='':
    modelPath = home_path + 'save/model/'
  else:
    modelPath = home_path + 'save/model/' + seg_corpus_name + '/1-1_512'

  out_bytes = subprocess.check_output(['ls','-l',modelPath],
                                    stderr=subprocess.STDOUT)
  out_text = out_bytes.decode('utf-8')
  return out_text

def load_source(seg_corpus_name):
  path = home_path + 'data/' + seg_corpus_name + '.txt'
  
  with open(path) as inp:
    data = inp.readlines()

  print(len(data), len(data[0::2]), len(data[1::2]))

  data = { 'source': data[0::2], 'target': data[1::2] }
  return data

# --------------------------
app = Flask(__name__)

param0 = { 'model': 'translation2019_train_83k',
          'epoch':  6000,
          'topn' : 10,
          'query' : 'what time is it?',
          'result' : 'result area'
        }

@app.route('/')
def forms():
  return render_template('translate.html', param=param0)

@app.route('/translate/<model>/<int:epoch>/<int:topn>', methods=['GET', 'POST'])
def translate_long(model,epoch,topn):
  if request.method == 'POST':
    query = request.values['query']
  elif request.method == 'GET':
    query = request.args.get('query')

  return translate(model,epoch,topn,query)


@app.route('/translate', methods=['GET', 'POST'])
def translate_short():
  if request.method == 'POST':
    query = request.values['query']
    model = request.values['model']
    epoch = request.values['epoch']
    topn = request.values['topn']
  elif request.method == 'GET':
    query = request.args.get('query')
    model = request.args.get('model')
    epoch = request.args.get('epoch')
    topn = request.args.get('topn')

  return translate(model,epoch,topn,query)

def translate(model,epoch,topn,query):
  epoch = int(epoch)
  topn = int(topn)

  try:
    target = sentence_test_model(model,epoch,topn,query)
  except:
    target = 'internal error, retry a again'

  result = 'query="{}"\nresult="{}"\n'.format(query,target)
  
  param2 = { 'model': model,
          'epoch':  epoch,
          'topn' : topn,
          'query' : query,
          'result' : result
        }
  return render_template('translate.html', param=param2)

@app.route('/list/<model>')
def list_model(model):
  mlist = list_models(model)
  return '<pre>{}</pre>'.format(mlist)

@app.route('/list/')
def list():
  mlist = list_models()
  return '<pre>{}</pre>'.format(mlist)

#######################################

USE_CUDA = torch.cuda.is_available()
device = torch.device("cuda" if USE_CUDA else "cpu")
home_path = './'

if __name__ == '__main__':
  app.run(host='0.0.0.0',port=8080)


註: 本程式使用 GitHub JavaScript code prettifier 工具標示顏色。其方法如下:
   1.參考 [Blogger] 如何在 Blogger 顯示程式碼 - Google Code Prettify
     於【Blogger 版面配置 HTML/JavaScript小工具】安裝如下套件
       <script src="https://cdn.jsdelivr.net/gh/google/code-prettify@master/loader/run_prettify.js"></script>
   2.文章編輯再以HTML模式為程式包上如下標籤。
       <code class="prettyprint lang-html linenums"> ... </code>
       <code class="prettyprint lang-python linenums"> ... </code>

2019年5月17日 星期五

memo for quota setup on Ubuntu/Linux

Ubuntu 設定帳號的硬碟配額方法

############# 一次性安裝及設定指令 =======================
# 安裝 quota 配額套件

$ sudo apt install quota

# 修改檔案系統表 fstab,針對套用配額的掛載點,加上usrquota, grpquota

$ sudo vi /etc/fstab
UUID=xxxx /home ext4 defaults,usrquota,grpquota 0 2

$ sudo mount -o remount /home

$ grep /home /etc/mtab
/dev/sdb1 /home ext4 rw,relatime,quota,usrquota,grpquota,data-ordered 0 0


# 產生權限設定檔
$ sudo quotacheck -cug /home
$ sudo quotacheck -ugvmca
$ ls /home

# 啟用配額管制
$ sudo quotaon -a
$ sudo quotaon -ap

# 修改配額超用免責期,預設為資料區塊數及索引區塊數皆享有7日超過免責期
$ sudo edquota -t
Grace period before enforcing soft limits for users:
Time units may be: days, hours, minutes, or seconds
  Filesystem    Block grace period   Inode grace period
  /dev/sdxy       7days                7days

############ 經常性檢視及設定用戶配額指令 ###################
# 修改user1用戶的資料/索引區塊的軟/硬配額
#   資料區塊用於存放檔案內容,blocks顯示目前資料區塊用量
#   索引區塊用於存放目錄內容,inodes顯示目前索引區塊用量
#   軟(soft)配額可以超過,但超過將進入寬限期
#   硬(hard)配額不可超過
#   寬限期(grace)預設7天,超過後硬碟無法新增檔案,直到刪除用量,降到軟配額以下
$ sudo edquota -u user1
Disk quotas for user user1 (uid xxx):
  Filesystem   blocks  soft hard inodes soft hard 
  /dev/sdxy    yyyy      0     0  zzzz    0     0

# 將user1用戶的配額設定套用到user2,user3
$ sudo edquota -p user1 user2 user3

# 列出user1,user2用戶的配額設定
$ sudo quota user1 user2 ...

# 列出所有用戶的配額設定
$ sudo repquota -avus
*** report for user quotas on device /dev/sdxy
Block grace time: 7days: Inode grace time: 7days

                 Space limits          File limits
User       used  soft  hard grace   used soft hard grace
--------------------------------------------------------
root  --  1088k   0k   0k            188  0  0 
.....

2019年5月8日 星期三

environment setup for running pytorch chatbot

PyTorch框架有很多深度學習範例,例如Chatbot聊天機器人展示。
以下記錄如何在Ubuntu環境,已安裝anaconda套件管理工具下,
建置適合PyTorch Chatbot執行的環境。

=== 設定顯示 conda環境,只要設定一次即可,以後登入會自動顯示
user@gpu:~/jupyter$ /usr/local/anaconda3/bin/conda init bash
user@gpu:~/jupyter$ source ~/.bashrc

=== 以後登入會自動顯示如下提示符號
(base) user@gpu:~/jupyter$
    conda create --name chatbot python=3.6 # 建立chatbot環境,執行一次即可
    conda activate chatbot # 進入chatbot環境

(chatbot) user@gpu:~/jupyter$
    -- 以下只要設定一次即可
    conda list # 列出目前環境安裝套件
    --
    conda install jupyter pytorch tensorflow-gpu torchvision tqdm [-c pytorch] # 安裝套件
    --
    jupyter notebook --generate-config # 產生jupyter notebook設定檔
    vi ~/.jupyter/jupyter_notebook_config.py # 修改設定檔
     c.NotebookApp.port = xxxx   # 選擇埠號xxxx
     c.NotebookApp.ip = '*'      # 允許外部連入
    jupyter notebook password       # 設定密碼

    -- 以上只要設定一次即可,以後只要進入chatbot環境,如下啟動jupyter notebook即可
    jupyter notebook                # 啟動jupyter notebook
    [Ctrl-C]
    --
    /usr/bin/lsof -i [:xxxx]  # 查看那個行程佔用那個埠號,或特定xxxx埠號
    /usr/bin/nvidia-smi   # 查看那個行程佔用GPU及其記憶體
    /usr/bin/top   # 查看那個行程佔用CPU及記憶體
    /usr/bin/kill -9 yyy  # 砍掉pid=yyy的行程
    --
    conda deactivate  # 離開chatbot,回到base環境

(base) user@gpu:~/jupyter$

註1: 使用上的注意事項
1. /usr/bin/xfce4-terminal 為命令列終端機,位於選單【應用程式/系統/Xfce終端機】
2. /snap/bin/pycharm-community 為PyCharm IDE,位於選單【應用程式/開發/PyCharm Community Edition】
3. /home/user/.conda/envs/chatbot/pkgs/ 為實際每個人利用conda安裝個人套件後的套件位置
4. /home/user/.conda/envs/chatbot/bin/ 為實際每個人利用conda安裝個人套件後的執行檔位置,例如jupyter指令
5. C:\Users\user\AppData\Local\conda\conda\envs\chatbot 為Windows上chatbot環境位置


註2: 假設 Ubuntu 18.04.1 LTS Kernel 4.15.0-47-generic #50-Ubuntu SMP 已裝好如下套件:
1. /usr/local/cuda <- cuda_10.0.130_410.48_linux.run
2. /usr/lib/x86_64-linux-gnu/libcudnn.so.7 <- libcudnn7_7.5.0.56-1+cuda10.0_amd64.deb
3. /usr/local/anaconda3/bin/conda <- Anaconda3-2019.03-Linux-x86_64.sh
4. /snap/bin/pycharm-community <- pycharm-community-2019.1.1.tar.gz

2019年3月8日 星期五

moodle administration memo

Moodle平台操作備忘錄

1.批次新增學生方法 (add new users)
  【首頁>網站管理>用戶>帳戶>批次建立用戶】
    上傳如下欄位檔案
      username, password, firstname, lastname, email

2.設定分組名單方法 (add users into groups)
  【系統管理/課程管理/用戶/分組:】
     為每一組【新增/移除 使用者】

3.利用.csv檔匯入分組名單方法 (import users into groups)
  A.依如下雙欄位格式準備.csv檔,第一筆為欄位名,分組名只能寫英文。
     username, group
     學號1, team01
     學號2, team01
     .....
     學號n, team02

  B.【系統管理/課程管理/用戶/匯入學生名單:】
    檔案位置:選擇一檔案
    CSV分隔符號: ,
    編碼: UTF-8
    Role to assign: 學生
    First column contains: Id number
    Create group(s) if needed: 是
    Create grouping(s) if needed:  ** (新分組是否獨立為新分群)
    Send me a mail report: 否
    點選【加入課程】
    ---
    username xxx already enroled and added to Moodle's group team yy
    .....
    0 enroled
    zz group(s) created : team01, team02, ...
    tt grouping(s) created :

註: moodle平台的group稱為分組,適用於一個班級內的小組活動。
    grouping稱為分群,適用於一門課同時開多個班上課的情況。

2019年1月21日 星期一

what are single/dual homed/multi-homed network topologies?

在討論廣域網路如何將客戶端(client)連向伺服端(server),或輻輳(spoke)連向軸心(hub)的連線拓樸時,
常根據源頭(source or home)個數,及線路(link)個數,將連線拓樸依其可靠度/成本分成四類如下:

1.single homed = single-link single-source 單線路單源頭拓樸
2.dual homed = dual-link single-source 雙線路單源頭拓樸
3.single multi-homed = single-link multiple-source 單線路多源頭拓樸
4.dual multi-homed = dual-link multiple-source 雙線路多源頭拓樸

單線路單源頭(single homed)拓樸的成本最低,但是可靠度最差。
雙線路多源頭(dual multi-homed)拓樸的可靠度最佳,但是成本最高。

四類連線拓樸的各種實例可參考如下網頁介紹:
  https://datapacket.com/blog/multihomed-network-vs-single-homed-network