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...';
    }
  });

how to install chinese and japanese fonts for matplotlib and seaborn plots

### Jupyter Notebook Python Code for Displaying CJK Unicode
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>

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 
.....

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

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稱為分群,適用於一門課同時開多個班上課的情況。

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

how to check windows version

查看windows版本兩種方法:

1. 指令ver

    Microsoft Windows [版本 10.0.17134.471]

2. 指令 slmgr.vbs -dlv

    軟體授權服務版本: 10.0.17134.471

    名稱: Windows(R), Professional edition
    描述: Windows(R) Operating System, VOLUME KMSCLIENT channel
    啟用識別碼: x-x-x-x-x
    應用程式識別碼: x-x-x-x-x
    延伸的PID: x-x-x-x-x-1028-17134.0000-1382018
    產品金鑰通路: Volume: GVLK
    安裝識別碼: x
    部分產品金鑰: x
    授權狀態: 已取得授權
    大量授權啟用到期: 255777分鐘(178天)
    剩餘的Windows重設授權狀態計數: 1001
    剩餘的SKU重設授權狀態計數: 1001
    信任時間: 2018/12/13 下午06:42:18
    已設定的啟用類型: All

    最近的啟用資訊:
    金鑰管理服務用戶端資訊
      用戶端電腦識別碼(CMID): x-x-x-x-x
      已登錄的KMS電腦名稱:  x.x.edu.tw:1688
      KMS電腦IP位址: x.x.x.x
      KMS電腦延伸的PID: x-x-x-x-x-1028-9600.0000-2932015
      啟用間隔: 120分鐘
      更新間隔: 10080分鐘
      啟用KMS主機快取

four design examples for the add function as class or instance methods

物件導向程式設計在規劃一個運算方法時,面臨兩種選擇

  1. 運算要定義為類別方法或物件方法
  2. 運算結果要定義為方法回傳值,或覆蓋原物件

這兩者選擇完全取決於設計者。底下以簡單的整數加法運算為例,說明定義為類別方法或物件方法,回傳結果或覆蓋原物件,其製作及使用上的差別。 一般是類別設計者參考下面表格先決定運算要如何使用,再決定如何製作。


回傳結果 覆蓋原物件
類別方法 範例: sum=Integer.add(3, 5) → 回傳 8
特性: 不改變原物件,偏向函數式設計
範例: Integer.addInPlace(obj, 5) → obj 由 3 變成 8
特性: 直接修改物件,副作用明顯
物件方法 範例: sum=obj.add(5) → 回傳新物件值 8,原 obj 仍為 3
特性: 保留原物件,方便鏈式操作
範例: obj.addInPlace(5) → obj 由 3 變成 8
特性: 高效但有副作用,難以追蹤狀態
A.四種加法運算的個別設計範例如下:

(1) 類別方法,回傳結果
 public class WholeNumber
 {
    public int number;

    public WholeNumber(int n)
    {
      this.number = n;
    }

    public String toString()
    {
      return String.format("%d", number);
    }

    public static WholeNumber add(WholeNumber n1, WholeNumber n2)
    {
      WholeNumber n = new WholeNumber(0);
      n.number = n1.number + n2.number;
      return n;
    }

    public static void main(String args[])
    {
      WholeNumber n1 = new WholeNumber(3);
      WholeNumber n2 = new WholeNumber(4);

      // 呼叫加法運算時,須傳入兩個運算元n1,n2,並預期=號接收新結果物件n3
      WholeNumber n3 = WholeNumber.add(n1, n2);

      // n3:7 = n1:3 + n2:4
      System.out.printf("n3:%s = n1:%s + n2:%s\n", n3, n1, n2);
    }
  } 


(2) 類別方法,結果覆蓋原物件
 public class WholeNumber
 {
    public int number;

    public WholeNumber(int n)
    {
      this.number = n;
    }

    public String toString()
    {
      return String.format("%d", number);
    }

    public static void add(WholeNumber n1, WholeNumber n2)
    {
      WholeNumber n = new WholeNumber(0);
      n.number = n1.number + n2.number;
      n1.number = n.number;
    }

    public static void main(String args[])
    {
      WholeNumber n1 = new WholeNumber(3);
      WholeNumber n2 = new WholeNumber(4);
      WholeNumber n1_copy = new WholeNumber(3);

      // 呼叫加法運算時,須傳入兩個運算元n1,n2,並預期n1由結果覆蓋
      WholeNumber.add(n1, n2);<

      // n1:7 = n1:3 + n2:4
      System.out.printf("n1:%s = n1:%s + n2:%s\n", n1, n1_copy, n2);
    }
  } 


(3) 物件方法,回傳結果
 public class WholeNumber
 {
    public int number;

    public WholeNumber(int n)
    {
      this.number = n;
    }

    public String toString()
    {
      return String.format("%d", number);
    }

    public WholeNumber add(WholeNumber n2)
    {
      WholeNumber n = new WholeNumber(0);
      n.number = this.number + n2.number;
      return n;
    }

    public static void main(String args[])
    {
      WholeNumber n1 = new WholeNumber(3);
      WholeNumber n2 = new WholeNumber(4);

      // 呼叫加法運算時,只額外傳入運算元n2,並預期=號接收新結果物件n3
      WholeNumber n3 = n1.add(n2);

      // n3:7 = n1:3 + n2:4
      System.out.printf("n3:%s = n1:%s + n2:%s\n", n3, n1, n2);
    }
 } 


(4) 物件方法,結果覆蓋原物件
 public class WholeNumber
 {
    public int number;

    public WholeNumber(int n)
    {
      this.number = n;
    }

    public String toString()
    {
      return String.format("%d", number);
    }

    public void add(WholeNumber n2)
    {
      WholeNumber n = new WholeNumber(0);
      n.number = this.number + n2.number;
      this.number = n.number;
    }

    public static void main(String args[])
    {
      WholeNumber n1 = new WholeNumber(3);
      WholeNumber n2 = new WholeNumber(4);
      WholeNumber n1_copy = new WholeNumber(3);

      // 呼叫加法運算時,只額外傳入運算元n2,並預期n1由結果覆蓋
      n1.add(n2);

      // n1:7 = n1:3 + n2:4
      System.out.printf("n1:%s = n1:%s + n2:%s\n", n1, n1_copy, n2);
    }
 }


B.四種加法運算的整合設計範例如下,將四種寫法合併成一支類別,方便比較四種用法的不同:


 class WholeNumber
 {
    public int number;

    // 建構子
    public WholeNumber(int n)
    {
      this.number = n;
    }
    
    // 拷貝建構子
    public WholeNumber(WholeNumber n)
    {
      this.number = n.number;
    }

    // 列印方法
    public String toString()
    {
      return String.format("%d", number);
    }

    // 類別方法,結果由新物件回傳
    public static WholeNumber classAddReturn(WholeNumber n1, WholeNumber n2)
    {
      WholeNumber n = new WholeNumber(0);
      n.number = n1.number + n2.number;
      return n;
    }

    // 類別方法,結果覆蓋n1物件
    public static void classAddOverwrite(WholeNumber n1, WholeNumber n2)
    {
      WholeNumber n = new WholeNumber(0);
      n.number = n1.number + n2.number;
      n1.number = n.number;
    }

    // 物件方法,結果由新物件回傳
    public WholeNumber instanceAddReturn(WholeNumber n2)
    {
      WholeNumber n = new WholeNumber(0);
      n.number = this.number + n2.number;
      return n;
    }

    // 物件方法,結果覆蓋本物件
    public void instanceAddOverwrite(WholeNumber n2)
    {
      WholeNumber n = new WholeNumber(0);
      n.number = this.number + n2.number;
      this.number = n.number;
    }

    // 測試四種加法的主程式
    public static void main(String args[])
    {
      WholeNumber n1,n2,n3,n4,n1_copy;
      
      n1 = new WholeNumber(3);
      n2 = new WholeNumber(4);
      
      // 呼叫加法運算時,須傳入兩個運算元n1,n2,並預期=號接收新結果物件n3
      n3 = WholeNumber.classAddReturn(n1, n2);
      
      // n3:7 = n1:3 + n2:4
      System.out.printf("n3:%s = n1:%s + n2:%s\n", n3, n1, n2);


      n1_copy = new WholeNumber(n1);
      // 呼叫加法運算時,須傳入兩個運算元n1_copy,n2,並預期n1_copy由結果覆蓋
      WholeNumber.classAddOverwrite(n1_copy, n2);
      
      // n1:7 = n1:3 + n2:4
      System.out.printf("n1:%s = n1:%s + n2:%s\n", n1_copy, n1, n2);


      // 呼叫加法運算時,只額外傳入運算元n2,並預期=號接收新結果物件n4
      n4 = n1.instanceAddReturn(n2);

      // n4:7 = n1:3 + n2:4
      System.out.printf("n4:%s = n1:%s + n2:%s\n", n4, n1, n2);


      n1_copy = new WholeNumber(n1);
      // 呼叫加法運算時,只額外傳入運算元n2,並預期本物件n1_copy由結果覆蓋
      n1_copy.instanceAddOverwrite(n2);

      // n1:7 = n1:3 + n2:4
      System.out.printf("n1:%s = n1:%s + n2:%s\n", n1_copy, n1, n2);
    }
 } 

Virtual Machine Spec for Google Colab Environment

Google Colab提供最多12小時連線的Jupyter Notebook開發環境,其2018年底層的虛擬機實測規格如下:

CPU: Intel(R) Xeon(R) TwinCore @ 2.20GHz x 2

Memory: 13GB

Drive: 347GB

GPU: Tesla K80 with 4992 cores at 556MHz + 11GB Memory

OS: Ubuntu 18.04.1 LTS

Time Limit: 12 hours

規格實測的python指令如下:

# https://stackoverflow.com/questions/48750199/google-colaboratory-misleading-information-about-its-gpu-only-5-ram-available
# memory footprint support libraries/code
!ln -sf /opt/bin/nvidia-smi /usr/bin/nvidia-smi
!pip install gputil
!pip install psutil
!pip install humanize
import psutil
import humanize
import os
import GPUtil as GPU
GPUs = GPU.getGPUs()
# XXX: only one GPU on Colab and isn? guaranteed
gpu = GPUs[0]
def printm():
 process = psutil.Process(os.getpid())
 print("Gen RAM Free: " + humanize.naturalsize( psutil.virtual_memory().available ), " | Proc size: " + humanize.naturalsize( process.memory_info().rss))
 print("GPU RAM Free: {0:.0f}MB | Used: {1:.0f}MB | Util {2:3.0f}% | Total {3:.0f}MB".format(gpu.memoryFree, gpu.memoryUsed, gpu.memoryUtil*100, gpu.memoryTotal))
printm()

!df
!cat /etc/issue
!nvidia-smi
!nvidia-smi -L

!cat /proc/cpuinfo
!cat /proc/meminfo

Disable UDP to solve frequent RDP disconnection

解決 RDP 遠端桌面經常斷線問題:「關閉 UDP 傳輸」 在使用 Windows 內建的 遠端桌面(RDP, Remote Desktop Protocol) 連線時,你是否也常遇到連線突然卡死、畫面凍結,或是頻繁跳出「連線已中...

總網頁瀏覽量