almost 2 years ago

Python

logger

import logging

logging.basicConfig(filename="") 
logging.error('...')

elapsed_time

import time (單位:sec)

start = time.time()
elapsed_time = time.time() - start 

timestamp

import time

time.strftime("%Y-%m-%d %H:%M:%s", time.localtime(time.time()))

wait

import time

time.sleep(<second>)

send GET request

import requests

requests.get(<url>)

JavaScript

  • contain
1. logger
2. timestamp
3. elapsed_time
4. mailer
5. facebook login
/* veck's module for web application */

var log = require('npmlog')
    , fs = require('fs')
    , mailer = require('nodemailer');

log.__proto__.setLogFile = function(path){
    log.stream = fs.createWriteStream(path, {flags: 'a'});  
}

/* timestamp */
log.__proto__.getLogTime = function(){
    var date = new Date();
    var day = date.getFullYear() +'/'+ date.getDate() +'/'+ date.getMonth();
    var time = date.getHours() + ':' + date.getMinutes() + ':' + date.getSeconds() + '.' + date.getMilliseconds();
    return day + ' ' + time;
}
log.__proto__.getLogDate = function(){
    var date = new Date();
    return date.getFullYear() +'/'+ date.getDate() +'/'+ date.getMonth();  
}

module.exports = log;

/*******************************************************/

/* elapsed time */
// Date.now() // return milliseconds (10^-3)

start = Date.now()
elasped = (Date.now - start)/1000

/*******************************************************/

/* mailer */
var transporter = mailer.createTransport({
    service: 'ses',
    host: 'email-smtp.us-west-2.amazonaws.com',
    auth: {
    user: '<username>',
        pass: '<password>'
    }
});
var message = '恭喜您已成功註,請點選以下連結完成註冊認證!';
transporter.sendMail({
    from: 'fbukevin@gmail.com',
  to: confirm.mail.address,
    subject: '註冊認證信',
    text: message
});

/*******************************************************/

/* facebook login */

/*
    TODO: 包成一個 module
 */  

var express = require('express');
var router = express.Router();
var log = require('log_tool');

log.setLogFile('log/auth.js.log');
log.info(log.getLogTime(), 'router index.js logging successfully');
function getRequestIP(req){
  return req.header('x-forwarded-for') || req.connection.remoteAddress;
}

function logging(req){
  log.info(log.getLogTime(), 'Request IP: ' + getRequestIP(req));
}

var passport = require('passport')
  , util = require('util')
  , FacebookStrategy = require('passport-facebook').Strategy
  , logger = require('morgan')
  , session = require('express-session')
  , bodyParser = require("body-parser")
  , cookieParser = require("cookie-parser")
  , methodOverride = require('method-override');

var FACEBOOK_APP_ID = "<FACEBOOK_APP_ID>"
var FACEBOOK_APP_SECRET = "<FACEBOOK_APP_SECRET>";

router.use(session({ secret: 'keyboard cat' }));
router.use(passport.initialize());
router.use(passport.session());

passport.serializeUser(function(user, done) {
  done(null, user);
});

passport.deserializeUser(function(obj, done) {
  done(null, obj);
});

passport.use(new FacebookStrategy({
    clientID: FACEBOOK_APP_ID,
    clientSecret: FACEBOOK_APP_SECRET,
    callbackURL: "http://localhost:3000/auth/facebook/callback",
    profileFields: ['id', 'displayName', 'photos']
  },
  function(accessToken, refreshToken, profile, done) {   
    process.nextTick(function () {
      return done(null, profile);
    });
  }
));
 
over 2 years ago

MySQL 簡單查詢範例

node.js

   var mysql = require('mysql');
   var connection = mysql.createConnection({
     host: '127.0.0.1',
     port: '3306',
     user: 'root',
     password: 'root',
     database: 'nodejs'
   });
  
  connection.connect();
  
  connection.query('SELECT * FROM `test`', function(err, rows, fields){
    if(err) throw err;
    for(var r in rows){
      console.log(rows[r].id);
    }
  });
 
 connection.end();

在 express 的 router 中這樣用:

routers/index.js

router.get('/', function(req, res){
    connection.query('SELECT * FROM `test`', function(err, rows, fields){
    res.render('index', {title: rows[0].id});
  });
});
 
over 2 years ago

本文是要介紹如何使用 Pythonrequest 模組來呼叫 Google Finance API 並解析取得的股價內容。

有關 requests 模組的介紹,請參考:http://docs.python-requests.org/en/latest/user/quickstart/

首先當然就是要安裝 request 模組啦!

pip install requests

然後就可以開始寫程式了

>>> import requests
>>> r = requests.get("https://finance.google.com/finance/info", params = {"client":"ig", "q":"TPE:2330"})

這段是以 HTTP GET 方法呼叫 Google Finance 的 API,可以得到不同國家區域證券交易所提供的即時股價資訊,requests 物件的 get 方法可以給予兩個參數,第一個參數是資源的 URI,第二個參數是相關設定,項目很多種,這裡我們用來設定 GET 傳輸所夾帶的資料,有 client (通常設定 "ig") 和 q (query string 的意思,格式為 <證券交易所代碼>:<股票代碼>),本例整個發送的資源敘述會變成:

https://finance.google.com/finance/info?client=ig&q=TPE:2330

如果成功取得回應資源,我們可以用 r.text 來查看回應內容本文,用 print() 可以印的比較漂亮點(人類可讀):

>>> print(r.text)         #pretty output

// [
{
"id": "674465"
,"t" : "2330"
,"e" : "TPE"
,"l" : "138.00"
,"l_fix" : "138.00"
,"l_cur" : "NT$138.00"
,"s": "0"
,"ltt":"1:30PM GMT+8"
,"lt" : "Oct 28, 1:30PM GMT+8"
,"lt_dts" : "2015-10-28T13:30:02Z"
,"c" : "-1.00"
,"c_fix" : "-1.00"
,"cp" : "-0.72"
,"cp_fix" : "-0.72"
,"ccol" : "chr"
,"pcls_fix" : "139"
}
]

Parse Response String

假如回傳的資料內容確定是 JSON 格式內容,你可以用 r.json() 來 parse 出內容,但是注意回傳的內容,雖然長得很像 JSON 的格式,但是在整個字串最前面多了兩個 '/',這導致這個物件並不是 JSON 物件,呼叫 r.json() 會出錯誤,因此我們需要先處理掉這兩個反斜線。

由於 JSON 的字串物件無法直接替換掉字串指定索引的內容,所以我採用複製子字串的方式來取得不帶有反斜線的其他內容:

>>> s = r.text[4:]         #copy from "["

>>> import json
>>> o = json.loads(s)
>>> o[0]['l']
u'138.00'
>>> import decimal
>>> d = decimal.Decimal(o[0]['l'])
Decimal('138.00')
>>> int(d)
138
>>> float(d)
138.0

補充一下,requests.get() 帶的第二個參數,用 paramsdata 是不同的項目喔,如果用 data,會得到 Bad request

 
over 2 years ago

PyMongo 簡單查詢

>>> import pymongo
>>> from pymongo import MongoClient
>>> client = MongoClient('localhost', 27017)
>>> db = client['express-wait']
>>> collection = db.waits
>>> collection.find_one()
{u'content': u'http://benchmarkjs.com/', u'_id': ObjectId('5629de95d488910889000001'), u'__v': 0}

reference: https://api.mongodb.org/python/current/tutorial.html

mongojs 簡單查詢

var mongojs = require('mongojs');
var db = mongojs('mongodb://dbuser:dbpass@host:post/db', ["waits"]);

db.waits.find(function(err, docs){
  console.log(docs);  
});

refence: http://mafintosh.github.io/mongojs/

Ruby Mongo 簡單查詢

irb(main):004:0> require "mongo"
irb(main):005:0> Mongo::Client.new(['127.0.0.1:27017'], :database => 'express-wait')
irb(main):006:0> client = Mongo::Client.new(['127.0.0.1:27017'], :database => 'express-wait')
irb(main):009:0> client[:waits].find().each do |document|
irb(main):010:1*  p document
irb(main):011:1> end
{"_id"=>BSON::ObjectId('5629de95d488910889000001'), "content"=>"http://benchmarkjs.com/", "__v"=>0}

reference: https://docs.mongodb.org/ecosystem/tutorial/ruby-driver-tutorial/

 
over 2 years ago

這是一個簡單易用的 Node.js 寄信模組,因為太容易使用,本文只是一個使用紀錄,官網的範例已足以滿足大家~

nodemailer

安裝套件

npm install nodemailer

寫程式

var nodemailer = require('nodemailer');

// 這個模組是透過 STMP 協定來做信件傳輸,所以需要設定代理伺服器

var transporter = nodemailer.createTransport({     // 建立 sender 物件: transporter

    service: 'Gmail',
    auth: {
        user: 'fbukevin@gmail.com',
        pass: '*******'
    }
});

// 設定 mail 選項

var mailOptions = {
    from: 'fbukevin@plsm.nccu.edu.tw',
    to: 'fbukevin@gmail.com', // 若有多個收件者,請在 ''  中用 ',' 點隔開

    subject: 'Test nodemailer',
    text: 'hello world',
    html: '<b>What does this option use?</b>' // 我一開始不知道這個是做什麼的

};

// 傳送

transporter.sendMail(mailOptions, function(error, info){
    if(error){
        console.log(error);
    }else{
        console.log('Message sent: ' + info.response);
    }
});

傳送成功的回傳訊息

fbukevin@plsm:~/test/nodemailer$ node test.js
Message sent: 250 2.0.0 OK 1441955541 sl7sm343448pbc.54 - gsmtp
 
almost 3 years ago

我現在有個需求,要讀取目錄下所有的檔案列表,然後拷貝檔名的部分就好,不要副檔名
可以直接這樣:f = readdir(),如此會回傳一個 Array{Union(ASCIIString,UTF8String),1}
接著我們可以存取陣列來取的特定檔案名稱:

julia> println(f[1])
julia> f[1]
"likea玉儿躁郁症病患.csv"

注意! index 從 1 開始喔! 這是承襲 Matlab 和 R 的,應該是比較符合科學家邏輯吧!從0開始是電腦的角度
這裡有一篇關於 Julia 從 1 開始的討論:
https://groups.google.com/forum/?hl=en#!topic/julia-dev/tNN72FnYbYQ

為了實現我的主題,我先拷貝到一個字串中,並且我試著去存取指定的幾個中文字元

julia> s = f[1]       # => "likea玉儿躁郁症病患.csv"

julia> println(s[6])   # => 玉

julia> println(s[7])   # => error

Ooop!當你試圖存取 s[7] (看起來應當是 )時,會出現以下錯誤:

ERROR: ArgumentError: invalid UTF-8 character index
 in next at ./utf8.jl:80
 in getindex at string.jl:62

根據官網文件的說明:

UTF-8 is a variable-width encoding, meaning that not all characters are encoded in the same number of 
bytes. In UTF-8, ASCII characters — i.e. those with code points less than 0x80 (128) — are encoded as 
they are in ASCII, using a single byte, while code points 0x80 and above are encoded using multiple 
bytes — up to four per character. This means that not every byte index into a UTF-8 string is necessarily
a valid index for a character.

簡單來說,是因為 UTF-8 的每個字符編碼長度不同造成的,也就是說 雖然同樣都是 UTF-8,但是兩者的編碼長度不同, 可能只占用 byte 6,但 可能占用 byte 7-9 (假設),換句話說,length(s) 在 Julia 中是你所能看到的『字串長度』,但是實際上字串的『編碼總長(記憶體空間)』是 endof(s) 的值,以下馬上來實驗看看:

julia> println("length of s is " , length(s))
julia> length of s is 16
julia> println("end index of s is ", endof(s))
julia> end index of s is 30

解決辦法:我們可以透過 nextind(str, i) 這個函數來取得下一個合法的字串索引,下面我們用 for 迴圈來查看 s 這個字串所有 [1] 之後的合法索引

julia> for i = 1:endof(s)
           println(nextind(s, i))
       end
2     
3 
4 
5 
6 
9 
12 
15 
18 
21 
24 
27 
28 
29 
30 
31 # (刪除重複後) 

Hoho! 出現啦!
剛剛 s[6] 是合法的,所以我們印得出 ,可以看到下一個合法的索引是 9 不是 7
馬上印印看:println(s[9])

YA~!
接下來我們可以用 for i = i:endof(s)for c in s 來進行字串拷貝了~

 
almost 3 years ago

最近在調查比較想學習的資料處理語言
我的需求是要開源如 R、簡潔如 Python
剛好我在非資訊領域做科學分析的朋友說 Matlab 很容易寫(他以建構矩陣為例子)
找來找去,大概就是 Julia

http://julialang.org/

這個語言野心極大,標榜結合了像 Python/Matlab/R 的易用和彈性,又兼具 Fortran 或是 C 的執行速度,能無縫銜接現有的 C/Fortran/python/R 所累積的龐大函式庫,又可以支援平行運算,並具有處理資料表格(data frame)的能力。

這麼剛好符合我要的需求 XD

它的創作者是一群用 Matlab 出身的 MIT guys,很有感啊!

Julia REPL 執行畫面

不過資料還很少,中文也是

以下是一些我覺得蠻喜歡的特性

變數預設採用 Unicode

這讓我想到了易語言周蟒...

新舊定義 function 的方式

  1. traditional
    julia> function f(x,y)
       x + y, x-y
       end
    f (generic function with 1 method)
    julia> f(2,4)
    (6,-2)
    
  2. Functional
    julia> ∑(x,y) = x + y
    ∑ (generic function with 1 method)
    julia> ∑(2,3)
    5
    ( ∑ in OS X is “option + w")
    

有三種使用 function 的方式

  1. genaral
    julia> f(2,3)

  2. apply()
    julia> apply(f, 2, 3)

  3. special operator syntax for certain function name
    (waiting)

function 回傳多個值的方法

hkl31 大的 iThome 2014 鐵人邦幫忙系列文章:
Julia(1) - Why Julia?
Julia (2) -- 2048遊戲的架構,Julia的安裝和暖身
Julia (3) -- 2048遊戲實作開始
Julia(4) - 2048遊戲核心完成!
Julia (5) -- Julia的標準輸出
Julia (6) -- Julia的標準輸入,2048主程式迴圈
(其餘文章請參考作者 iThome 活動列表)

Julia for Matlab User 系列文章:
http://sveme.org/julia-for-matlab-users-i.html
http://sveme.org/julia-for-matlab-users-ii.html
http://sveme.org/julia-for-matlab-users-iii.html

Reference:
http://juliatw.readthedocs.org/zh_TW/latest/
Learn Julia in Y minutes

 
about 3 years ago

mocha, chai 和 sinon,我覺得最難的是 sinon 了,因為 mocha 只是驅動,chai 是 assert ,你給他結果值就好,sinon 考慮的是物件的『行為』,最麻煩的就是如果呼叫一個函數或建立一個物件,結果會有副作用(開檔、寫檔、修改資料庫、傳送網路資料等),又不是像 try...catch... 會幫你 rollback 的話,你就得自己來處理,因此本篇想測試 sinon 的物件是否提供 rollback 或類似的測試方法。

複習一下概念:

  • spy 是 監視,所以還是會 invoke function
  • stub 是 隔離,不 invoke function,把 function 替換成 stub 物件或自定義物件函式
  • mock 是直接模擬物件或函式,包含 spy 和 stub 的所有功能,而且還可以最後來驗證物件是否照預期執行

這樣看來主要嘗試就是 spy 和 stub 物件了,mock 物件繼承上述兩者的能力,就不需去嘗試

我們拿 node.js 的 fs.openSync(); 來做例子,它的功能是同步的建立一個檔案

var sinon = require('sinon');
var assert =require('assert');
var fs = require('fs');

/**
 * test if fs.openSync() will rollback(create then delete file after test)
 * automatically with the two main kind of objects in Sinon.
 */

//Spy

describe('Spy', function(){
    it('should call open with w mode to create file', function(){
       var spy = sinon.spy(fs, "openSync");
       spy.withArgs('index.html', 'w');   // register arguments

       fs.openSync('index.html', 'w');  // call

       assert(spy.withArgs('index.html').calledOnce);
       spy.restore();
    });
});

//Stub

describe('Stub', function(){
    it('should call open with w mode to create file', function(){
        var stub = sinon.stub(fs, "openSync");
        stub.withArgs('index2.html', 'w');
        stub("index2.html", "w");
        stub.restore();
    });
});

本來還在想,如果兩者都不會 rollback,就要自己在 mocha 的 afterAll 去 remove file 了,但這樣的話 write 怎半?真的寫了怎麼再去 afterAll 做 rollback?尤其當我嘗試了 spy 並證實,很遺憾的,spy 還是會產生檔案,不會 rollback,所以不太適合寫建立和寫入的操作 ...

接著邊思考邊期待,stub 好像是把指定的 funtion 替換成 stub 物件,也可以自己定義要替換成的 funtion,做到相依斬斷
也許...

緊張緊張,這麼重要的功能的測試的結果就要來了的啦!

Yes! stub 就沒有真的建立檔案了!
不過我認為並不是 stub 有去自動做 rollback 的動作,而是因為 stub 的功能就是要隔離相依性,亦即讓不同功能 (module, method, function) 之間戶不影響測試,因此,這個結果只是 stub 沒有去呼叫真正的那個 function 罷了!

 
about 3 years ago

繼 node.js 後,我也想讓 Python 的程式碼可以不需要輸入 "python" 就可以執行,找到大部分的作法,這是在 UNIX/Linux 和 Mac 上的說明

  1. 寫個簡單的 exe.py
    #!/usr/bin/env python
    
    if name == "main":
    print("Execute Python without typing \"python\")
    
  2. 在終端機輸入 chmod +x exe.py 修改權限
  3. 答啦!
     ~/Desktop -->./exe.py 
    Execute Python without typing "python"
    

甚至也不用打 "./" 了!

如果想連附檔名都不要,有篇教學說可以把檔名改成 exe,也就是拿掉附檔名,而系統會自己知道要用程式碼第一行指定的那個直譯器來執行這個檔案 ~/Desktop -->exe

當然,你也可以把 exe 加入 PATH 中,這樣就可以到處都直接執行它了~

有個問題是,Python 利用 pip 來管理和發佈套件,在 node.js 那邊我們用 npm install -g 就可以安裝成 global command,不需要另外設定權限,那如果今天需要設定權限,那給人安裝後,是不是應該寫 shell script 來設定呢?

還沒研究有沒有人用 pip 來安裝成 command tool,pip 好像主要是拿來安裝 Python module package,如果用 shell script 來設定路徑好像就不是 pip 的用途了

原文參考:http://sebug.net/paper/python/ch03s05.html

 
about 3 years ago
  1. 建立 package.json

    {
    "name": "filesearch",
    "description": "just that",
    "version": "0.1.0",
    "main": "lib/filesearch",   
      "preferGlobal": "true",
      "bin": {
             "filesearch" : "lib/filesearch.js"     // tell node where to execute 
     }
    }
    

    如果你有多個執行檔,bin 這裡可以多放幾個,名稱即指令,值為檔案路徑

  2. 建立 lib/ 和 lib/filesearhc.js

  3. filesearhc.js

    #!/usr/bin/env node            // 直譯器位置(建議不要用 #!/usr/bin/node)
    console.log('execute without type "node" and make it global');
    
  4. install our package locally

    ~/Desktop/exenode/lib -->npm link
    /Users/veck/.nvm/v0.10.35/bin/filesearch -> /Users/veck/.nvm/v0.10.35/lib/node_modules/filesearch/lib/filesearch.js
    /Users/veck/.nvm/v0.10.35/lib/node_modules/filesearch -> /Users/veck/Desktop/exenode
    ~/Desktop/exenode/lib -->
    
  5. cd to the other directory and type "filesearch" without node

    ~/Desktop -->filesearch 
    execute without type "node" and make it global
    
  6. to remove installation

    npm unlink -g <package-name>     // 因為我們用 link 會安裝成 global 的指令,因此要用 -g 
    

如果用 npm 發佈了,只要用 npm install -g <package> 就可以安裝成 global command。

參考原文:http://javascriptplayground.com/blog/2012/08/writing-a-command-line-node-tool/