2016年9月11日 星期日

[js]打造自己的開發環境閱讀心得

前言

因為有點不知道除了 visual studio 之外的開發環境會長怎樣,所以研究了一下以下的文章,稍微了解一下現在的世界長怎樣了。 http://larry850806.github.io/2016/09/04/es7-environment/

我這篇算是心得報告,只有把我不會的地方加一些描述。要了解全部還請記得去原來的地方看。記得一定要感謝原作者 Larry Lu http://larry850806.github.io/about/
https://github.com/Larry850806/nodejs-ES7-template

了解生字

  • babel
    它看來是一個編譯器,把你寫的 javascript 轉成另一種寫法的 javascript。這大概就是目前 javascript 最有趣的地方吧…。 https://babeljs.io/
    類似的有:TypeScript, CoffeeScript

  • gulp
    這個看起來像是 gcc make 的系統,依照你寫的設定標,自動把編譯、複製、散佈等工作做完的系統。是 node.js 的套件之一。
    http://gulpjs.com/ http://abgne.tw/web/gulp/gulp-tuts-install-gulp-js.html

目錄安排

文章中的建議是因為有用了 gulp 做自動處理,所以會把檔案很乖地很分散在各個不同的目錄裡。

package.json
node_modules
gulpfile.js
index.js
src
    index.js
    utils.js
build
    index.js
    utils.js

package.json 與 node_modules 是 node.js 需要的。
gulpfile.js 是 gulp 的設定
最外面的 index.js 是程式執行的起點。但它只是轉一手讓 build/index.js 來執行。為了不要讓人太傷腦筋。
src 裡,原文是放 ES7 的程式,build 是被轉成 ES5 的程式。

註:ES7 與 ES5 是指 ECMA Script 7 與 ECMA Script 5。是 Javasript 目前的正式學名。兩個在語法上有不同,所以必須要分兩個名字來講。目前可以靠程式把新語法轉成舊語法,以利舊瀏覽器/舊環境執行,減少大家開發上轉換的痛苦。這一點也是獨特之處。

開發流程

開發時只動 src 裡的東西,其他的動作靠 gulp 來幫忙。
真正執行的起點是 ./index.js,而它會去執行 build/index.js。

gulp 設定

因為是靠 gulp 來處理轉譯與搬檔案,所以要了解一下它的用法。https://github.com/nimojs/gulp-book

文章內使用的設定是:

// gulpfile.js

var gulp = require('gulp');
var babel = require('gulp-babel');

gulp.task('babelify', function(){
    return gulp.src('src/**/*.js')
        .pipe(babel({
            presets: ['es2015', 'es2016', 'es2017'],
            plugins: [
                [
                    "transform-runtime", {
                        "polyfill": false, 
                        "regenerator": true
                    }
                ]
            ]
        }))
        .pipe(gulp.dest(build))
});

使用方法是在命令列輸入 gulp babelify,gulp 就會把 src 裡所有的 js 用 babel 轉成 ES5 的程式碼,丟到 build 裡去。所需要的模組是:

{
    "babel-plugin-transform-runtime": "^6.12.0",
    "babel-preset-es2015": "^6.13.2",
    "babel-preset-es2016": "^6.11.3",
    "babel-preset-es2017": "^6.14.0",
    "gulp-babel": "^6.1.2"
}

babel 轉譯錯誤的輸出

若是在 babel 轉譯的時候有錯誤,要把錯誤寫出來,需要在 .pipe(babel({…}) 後面加上 on error 的處理函式

.on('error', function(err){
    console.log(err.stack);
    this.emit('end');
})

debug 用的 source map

在轉譯之後,有 exception 發生時,會 dump 出來的是已轉譯的程式碼(也就是 build/index.js),但是那個我們人類很難看,所以可借用所謂的 source map 來讓錯誤對應到 src/index.js 我們比較好修正。(本來設計也只能在 src 那裡動程式碼。)所以在 on(‘error’, … )的後面加上:

.pipe(sourcemaps.write({
            includeContent: false,
            sourceRoot: 'src'
}))  

要讓 node 知道要採用 source map 來對應錯誤行號與內容,要在執行的 index.js 加上:

require('source-map-support').install();

要做到如此,source map 需要兩個模組:

{
    "gulp-sourcemaps": "^1.6.0",
    "source-map-support": "^0.4.2"
}

程式碼變動自動轉譯

這個功能原作者是用 gulp 來監視檔案有無變動,有的話就自動轉譯。要在 gulpfile.js 加上一段:

gulp.task('watch', function(){
    return gulp.watch(['src/**/*.js'], ['babelify']);
});

gulp.task('default', ['babelify', 'watch']);

最後

還可以多看一篇 http://larry850806.github.io/2016/07/25/react-optimization/ 這裡大概就可以知道為什麼 python 會有 mutable、immutable 的東西跑出來。

2016年9月6日 星期二

[python]改用 requests

源起

最近發現一些程式都不正常結束。查看了一下,有幾個是 http 已經不提供了,被導去 https,所以讓 urllib 的呼叫失敗。目前來看,可以用 requests 來解決這問題。

過程

在安裝 requests 之後,的確程式碼少了一些。只是有個警告一直出現:

InsecurePlatformWarning: A true SSLContext object is not available.

雖然還是正常執行,只是 console 視窗一直被洗很討厭。有人說換到 python 2.7.9 就可以或是 pip install requests[security] ,我換到 2.7.12 也 pip install requests[security] 但只是換了一個訊息,但是還是洗畫面。

InsecureRequestWarning: Unverified HTTPS request is being made.

結局

首先參考 https://urllib3.readthedocs.io/en/latest/security.html

正規解法應該參考 https://urllib3.readthedocs.io/en/latest/user-guide.html#ssl 來解決問題。

但是我使用裡面偷懶的做法,在程式一開始加入

import requests.packages.urllib3

requests.packages.urllib3.disable_warnings()

2016年8月8日 星期一

[mqtt]在 XP 上安裝 mosquitto

[mqtt]在 XP 上安裝 mosquitto

在 XP 上安裝 mosquitto,與在 windows 7 以上不一樣。

在 XP 上,需要使用標有 cygwin 的安裝檔。如果直接使用標注 win32 的安裝檔來裝,在執行時會出現 mosquitto.exe 不是正確的 win32 應用程式的錯誤。
下載 mosquitto-1.4.9-install-cygwin.exe 之後,安裝。一樣的,需要依說明下載 Win32OpenSSL_Light-1_0_2h.exe 與 pthreads-w32-2-9-1-release.zip 然後把需要的 dll 放到 mosquitto.exe 旁邊。
再來則必須要安裝 cygwin,到 cygwin 官網下載 setup-x86.exe,然後執行。只需要安裝基本 (base) 就好了,我們只要是複製幾個檔案。安裝好之後,就點 mosquitto.exe,它會告知少什麼 dll,然後就去 cygwin 安裝的地方 copy 過來。我記得是以下幾個:
* cygcrypto-1.0.0.dll
* cyggcc_s-1.dll
* cygssl-1.0.0.dll
* cygwin1.dll
* cygz.dll
這樣,mosquitto.exe 就正常可用。如果希望它變成一個服務,那最簡單是再執行一次安裝檔,選擇服務選項。如此就會在開機的時候自動啟動。
但是,這個安裝檔裡的 mosquitto_pub.exe 與 mosquitto_sub.exe 仍出現不是正確的 win32 應用程式的錯誤。我想也許是打包錯了,報了 issue 結果負責人說他沒有 XP,所以要我們自己 compile 試試。其實在他回覆之前,我就下載舊的安裝檔來試,裝在另一個目錄,中間有很多不同的錯誤,像是找不到 entry point 的、getTickCount64 不在 KERNEL32.DLL 的。最後終於在 mosquitto-1.2-install-cygwin.exe 找到一個說缺 msvcr100.dll 的。
msvcr100.dll 我找到有兩個,一個在 C:\windows\system32,一個則在 anaconda\Library\bin 裡面。結果是後面這個放到 mosquitto_sub/pub 旁邊才成功。但是 mosquitto-1.2-install-cygwin.exe 裡面的 mosquitto.exe 會出現 無法找到程序輸入點 inet_ntop (在動態連結函式庫 WS2_32.dll) 的錯誤。所以就安裝兩版來解決問題吧 XD
目前只有用到最簡單的連結,其他功能沒有用到(例如 ssl、帳號密碼),所以不知道是不是全功能完整無蟲。可以確定的是 服務正常、pub/sub 正常。私用應該沒問題。

[超譯]Node.js 加 MQTT 入門

https://blog.risingstack.com/getting-started-with-nodejs-and-mqtt/

Node.js 加 MQTT 入門

這篇貼文由 Charlie Key 提供,他是 Structure 的 CEO 與 Co-Founder。Structure 是一個 IoT 的平台,讓你能輕鬆建立相連的經驗與解決方案。Charlie 已經用 Node.js 於工作幾年,現在用它來為 IoT 的世界充能。
Javascript 的世界持續地開發新彊界,像 Node.js 的技術可讓伺服端快速擴展,而現在達到 IoT 的世界。Node.js 現在可在許多嵌入式裝置內,像是 Intel Edison。與嵌入式裝置的溝通一向都可行的,但使用 Node.js 與 MQTT 這類協定讓溝通前所未有的簡單。
在這貼文,我們會看一下如何利用兩個技術(Node.js 與 MQTT)來傳送訊息,建立一個簡易的車庫開門應用程式。這只是此類通訊的其中的一個可能的應用。
MQTT 本身是個非常簡單的 publish / subscribe (出版/訂閱)協定。它讓你在一個主題上送訊息(你可以想像那些是頻道),經由一個中央管理的 message broker。整個協定故意非常輕量。這會讓它能輕易地在嵌入式裝置上執行。幾乎所有的微處理器都有函式庫可用讓它能收送 MQTT 的訊息。以下可以看到 MQTT 溝通的基本概念。
這裡一張架構圖
現在,想像一下我們要打造一個遠端控制的車庫開門系統,使用 MQTT。第一件事我們需要計畫車庫門與遠端遙控器要傳送什麼訊息。為了要讓這範例簡單,我們只打算能夠開門與關門就好。真實的架構圖會長成這樣:
又一張架構圖
門會有幾個狀態,已開、已關、開門中、關門中。真的門也許會有其他狀態,如 暫停。但我們今天暫不考慮。
我們的應用程式會分開兩個檔案,一個是給車庫用另一個給控制器用。我會在每個程式的上頭標名檔名。首先,我們會需要用 npm 安裝 mqtt 函式庫,然後設定我們要用的 broker。現在有很多開放的 broker 可用於測試,我會使用 broker.hivemq.com。再次強調,這只是測試用,不要在正式產品還用這個。以下是兩個檔案一開始都要的程式碼:
// contoller.js and garage.js
const mqtt = require('mqtt')  
const client = mqtt.connect('mqtt://broker.hivemq.com') 
接下來,我們要加一些程式碼來連上 broker。一定連上,我們會建立一個主題(頻道),這在車庫門連上時的溝通用的。在門這邊,是 publish(出版)訊息到這個主題,而控制器這邊則是subscribe(訂閱)。同樣,在這個時間點,我們會加一個區域變數,追蹤車庫門現在的狀態。你會發現我們的主題加了前綴 “garage/”,這是為了組織目的的簡化,你也可以隨自己喜歡來命名。
// garage.js
const mqtt = require('mqtt')  
const client = mqtt.connect('mqtt://broker.hivemq.com')

/**
* The state of the garage, defaults to closed
* Possible states : closed, opening, open, closing
*/

var state = 'closed'

client.on('connect', () => {  
  // Inform controllers that garage is connected
  client.publish('garage/connected', 'true')
})
在控制器端,我們不只是要訂閱這主題,我們也需要加上訊息接聽者,對訊息出版時採取動作。一但訊息收到,我們會使用一個變數,檢查變數的值且追蹤是否門還連在系統上。
// controller.js
const mqtt = require('mqtt')  
const client = mqtt.connect('mqtt://broker.hivemq.com')

var garageState = ''  
var connected = false

client.on('connect', () => {  
  client.subscribe('garage/connected')
})

client.on('message', (topic, message) => {  
  if(topic === 'garage/connected') {
    connected = (message.toString() === 'true');
  }
})
目前為止,門與控制器只知道,門是否連在系統上,我們還不能採取什麼動作。為了要讓控憲器知道門發生什麼事,我們再加上一個函式,送出現在門的狀態,函式長這樣:
// added to end of garage.js
function sendStateUpdate () {  
  console.log('sending state %s', state)
  client.publish('garage/state', state)
}
要使用這個函式,我們會加在車庫連上的呼叫裡:
// updated garage.js connect
client.on('connect', () => {  
  // Inform controllers that garage is connected
  client.publish('garage/connected', 'true')
  sendStateUpdate()
})
現在車庫門可以更新,告訴每個人它現在的狀態。現在控制器需要更新自己的門狀態的變數。然而在這個時間點,先更新訊息處理函式,對應不同的主題呼叫不同的函式。這會增加一點程式的結構性。整個更新完如下:
// updated controller.js
const mqtt = require('mqtt')  
const client = mqtt.connect('mqtt://broker.hivemq.com')

var garageState = ''  
var connected = false

client.on('connect', () => {  
  client.subscribe('garage/connected')
  client.subscribe('garage/state')
})

client.on('message', (topic, message) => {  
  switch (topic) {
    case 'garage/connected':
      return handleGarageConnected(message)
    case 'garage/state':
      return handleGarageState(message)
  }
  console.log('No handler for topic %s', topic)
})

function handleGarageConnected (message) {  
  console.log('garage connected status %s', message)
  connected = (message.toString() === 'true')
}

function handleGarageState (message) {  
  garageState = message
  console.log('garage state update to %s', message)
}
在這裡,我們的控制器可以跟上車庫門的狀態與連線狀態。現在可以加一些功能來控制我們的門。第一件事是讓車庫開始接聽一些訊息,告訴它開或關。
// updated garage.js connect call
client.on('connect', () => {  
  client.subscribe('garage/open')
  client.subscribe('garage/close')

  // Inform controllers that garage is connected
  client.publish('garage/connected', 'true')
  sendStateUpdate()
})
我們現在需要在車庫門這裡加個訊息接聽者:
// added to garage.js
client.on('message', (topic, message) => {  
  console.log('received message %s %s', topic, message)
})
在控制器這裡,我們也會加上傳送開門或關門訊息的能力。這有兩個簡單的函式。在一個真實的應用程式中,這會由外部輸入來呼叫(像是 web 應用程式,手機 app…等)。在這個範例中,我們會用個計時器來呼叫,只是測試這個系統而已。新增的程式碼如下:
// added to controller.js
function openGarageDoor () {  
  // can only open door if we're connected to mqtt and door isn't already open
  if (connected && garageState !== 'open') {
    // Ask the door to open
    client.publish('garage/open', 'true')
  }
}

function closeGarageDoor () {  
  // can only close door if we're connected to mqtt and door isn't already closed
  if (connected && garageState !== 'closed') {
    // Ask the door to close
    client.publish('garage/close', 'true')
  }
}

//--- For Demo Purposes Only ----//

// simulate opening garage door
setTimeout(() => {  
  console.log('open door')
  openGarageDoor()
}, 5000)

// simulate closing garage door
setTimeout(() => {  
  console.log('close door')
  closeGarageDoor()
}, 20000)
以上的程式碼包含開與關的功能。它們確認車庫已經連上系統而且不在已要求的狀態中。我們的控制器最後版本的程式碼如下:
// controller.js
const mqtt = require('mqtt')  
const client = mqtt.connect('mqtt://broker.hivemq.com')

var garageState = ''  
var connected = false

client.on('connect', () => {  
  client.subscribe('garage/connected')
  client.subscribe('garage/state')
})

client.on('message', (topic, message) => {  
  switch (topic) {
    case 'garage/connected':
      return handleGarageConnected(message)
    case 'garage/state':
      return handleGarageState(message)
  }
  console.log('No handler for topic %s', topic)
})

function handleGarageConnected (message) {  
  console.log('garage connected status %s', message)
  connected = (message.toString() === 'true')
}

function handleGarageState (message) {  
  garageState = message
  console.log('garage state update to %s', message)
}

function openGarageDoor () {  
  // can only open door if we're connected to mqtt and door isn't already open
  if (connected && garageState !== 'open') {
    // Ask the door to open
    client.publish('garage/open', 'true')
  }
}

function closeGarageDoor () {  
  // can only close door if we're connected to mqtt and door isn't already closed
  if (connected && garageState !== 'closed') {
    // Ask the door to close
    client.publish('garage/close', 'true')
  }
}

// --- For Demo Purposes Only ----//

// simulate opening garage door
setTimeout(() => {  
  console.log('open door')
  openGarageDoor()
}, 5000)

// simulate closing garage door
setTimeout(() => {  
  console.log('close door')
  closeGarageDoor()
}, 20000)
現在,車庫門必須對應這些訊息做反應。再一次,我們使用 switch 引導不同的主題。一但訊息被收到,門會試著處理它且確認它能到那狀態才動作。然後它會進入轉移狀態(開門中、關門中),送出更新訊息,最後到達持續狀態(已開、已關)。為了測試的目的,最後一個部份是用計時器來完成。在真實情況中,系統應該等待硬體訊號通知它已完成。
// updated garage.js message handler
client.on('message', (topic, message) => {  
  console.log('received message %s %s', topic, message)
  switch (topic) {
    case 'garage/open':
      return handleOpenRequest(message)
    case 'garage/close':
      return handleCloseRequest(message)
  }
})
開門與關門的處理函式可以加到檔案的最後。
// added to garage.js
function handleOpenRequest (message) {  
  if (state !== 'open' && state !== 'opening') {
    console.log('opening garage door')
    state = 'opening'
    sendStateUpdate()

    // simulate door open after 5 seconds (would be listening to hardware)
    setTimeout(() => {
      state = 'open'
      sendStateUpdate()
    }, 5000)
  }
}

function handleCloseRequest (message) {  
  if (state !== 'closed' && state !== 'closing') {
    state = 'closing'
    sendStateUpdate()

    // simulate door closed after 5 seconds (would be listening to hardware)
    setTimeout(() => {
      state = 'closed'
      sendStateUpdate()
    }, 5000)
  }
}
有了這些函式,我們現在有個完整功能的車庫系統。為了測試你可以開啟控制器程式然後再開車庫門程式。控制器會在開啟後 5 秒送開門指令,20 秒送關門指令。
最後我要建議的事是讓我們的車庫門更新自己的連線狀態,當我們的程式因為任何原因被關掉的時候。這個離開的乾淨程式碼是依照 stackoverflow answer 建議,然後改用 mqtt 訊息傳送。這可在放在車庫檔案的最後。所有的東西組合起來就得到最後的車庫檔案。
// garage.js
const mqtt = require('mqtt')  
const client = mqtt.connect('mqtt://broker.hivemq.com')

/**
 * The state of the garage, defaults to closed
 * Possible states : closed, opening, open, closing
 */
var state = 'closed'

client.on('connect', () => {  
  client.subscribe('garage/open')
  client.subscribe('garage/close')

  // Inform controllers that garage is connected
  client.publish('garage/connected', 'true')
  sendStateUpdate()
})

client.on('message', (topic, message) => {  
  console.log('received message %s %s', topic, message)
  switch (topic) {
    case 'garage/open':
      return handleOpenRequest(message)
    case 'garage/close':
      return handleCloseRequest(message)
  }
})

function sendStateUpdate () {  
  console.log('sending state %s', state)
  client.publish('garage/state', state)
}

function handleOpenRequest (message) {  
  if (state !== 'open' && state !== 'opening') {
    console.log('opening garage door')
    state = 'opening'
    sendStateUpdate()

    // simulate door open after 5 seconds (would be listening to hardware)
    setTimeout(() => {
      state = 'open'
      sendStateUpdate()
    }, 5000)
  }
}

function handleCloseRequest (message) {  
  if (state !== 'closed' && state !== 'closing') {
    state = 'closing'
    sendStateUpdate()

    // simulate door closed after 5 seconds (would be listening to hardware)
    setTimeout(() => {
      state = 'closed'
      sendStateUpdate()
    }, 5000)
  }
}

/**
 * Want to notify controller that garage is disconnected before shutting down
 */
function handleAppExit (options, err) {  
  if (err) {
    console.log(err.stack)
  }

  if (options.cleanup) {
    client.publish('garage/connected', 'false')
  }

  if (options.exit) {
    process.exit()
  }
}

/**
 * Handle the different ways an application can shutdown
 */
process.on('exit', handleAppExit.bind(null, {  
  cleanup: true
}))
process.on('SIGINT', handleAppExit.bind(null, {  
  exit: true
}))
process.on('uncaughtException', handleAppExit.bind(null, {  
  exit: true
}))
這了那些,我們完成了我們的車庫門控制器。我希望你能挑戰下一級。一些修改與一個 Intel Edison 會讓你建立一個完整的遠端車庫開門系統。此範例完整的原始碼也會放在 Github。
這只是一個開始。還有一些 MQTT 的新選項與能力,包含使用 SSL、使用者/密碼 認證來增加安全性。
如果你喜歡這篇貼文且想知道 Node.js 能到什麼程度,這有個超讚會議會來到:Node Community Convention。將會有許多偉大的演講,主題包含 IoT、系統放大……等等。

作者
Gabor Nagy
在 Marketing 是個全端。在 web 開發正在從零到英雄的路上。

2016年7月28日 星期四

[超譯] 核心版控演義

linux 核心的版本控制管理系統,曾經有經歷過一段動盪,linus 自己曾經在郵件列表裡回過一段文章,提出自己的看法。郵件標題是 「Kernel SCM saga..」
原文連結:
http://lkml.iu.edu/hypermail/linux/kernel/0504.0/1540.html

好,有很多人已經發現(有些人已經知道好幾個星期),我們正努力解決這一兩個月與 BK [譯註:BitKeeper] 之間的衝突。但,我們沒有成功,所以,核心組正在尋找替代方案。
(顯然這訊息會到 slashdot,所以應該 每個人都知道 )
我選了 BK 就讓能衝突消失的期待,似乎沒有成功 ( “你沒看見這幾G又幾G 的火熖嗎?”)。所以,在某種意義上是無法避免的。但我確信我曾希望能有合理的開源替代能選擇,為此,我們將必須忙和一陣子。
題外話,別怪 BitMover,就算這是一個常見的反應。Larry 真的是想把事情做好,但事情到了我不想要的地步,想要把兩塊湊在一起需要的膠水越多越好。
我們已經使用 BK 三年了,事實上,現在最大的問題是有許多人用過最好的工具之後,變得非常挑剔。包含我自己,我們都因為 BitKeeper 的幫助,在 merging 我的 tree,或把他們的 tree 傳給我的時候變得比較輕鬆。
當然,也許更大多數的人只是把 BK 當成更好(也更快)的「匿名 CVS」的客端。眼前的問題是我花了許多時間試圖找到最好的協作方案。
注意,BitKeeper 不是消失了。只是現在最真切的事情是,我決定不再使用 BK,主要因為我需要找到替代,而不是「讓東西持續正常」。我決定硬著頭皮,看看沒有 BK 的生活會是怎樣。到目前為止,是個黑白的世界。
不要過度解釋,我會用個星期閉關,(想做是 linus 只是去放假的正常事件),我也正在找人負責維護 BK tree,至少是能夠傳給我(單獨)補丁,我會自己 想辦法 merge。
所謂「單獨補丁 individual patches」是個關鍵字。題外話,BK 一個做得很好的事,許多人就算沒用 BK 也喜歡的,就是它對於改變的視圖很棒。這個不會消失。
事實上,BK 讓我們做事的方法有了根本的改變。像是 changeset 的視圖、讓我能相信子維護者能做更大的事、不用按順序上補丁…等。所以三年的 BK 使用不是浪費。我相信這會讓我們用更好的方式做事。我會尋找讓這些事情繼續的方法。
所以,我只是要說,我個人與 BK 相處愉快,與 Larry 也是。合作沒有成功讓核心開發有了巨大的困難。一個暫時性的問題,要產出在 BK 允許的範圍內使用的工具,這一點我們會繼續努力。
讓火開始燒吧。
Linus
PS. 不要再跟我說 subversion。如果你一定要,去研究 “monotone”,那看來是最可行的。但不要再煩開發者讓他們無法把事情做完。他們已經要煩惱我的問題了。

[閒聊]超簡單回答 - 什麼是 github?

github 是一個程式碼代管網站,它讓你可以放程式碼供大家下載。由於它使用 git 版本控制程式,所以名字 github 裡面有個 git。

git 是由 linus 開發出來的(第一版)。是為了因應分散式開發的特性而另外開發的。在他開發的時候,同時間也有其他的分散式開的版本控制系統已經出現,BitKeeper,或是 Mercurial。Mercurial 開發時間只有晚 git 一些些而已。但是 linus 覺得都不合他的意,所以就自幹一套,然後把 linux kernel 的版本控制系統換成了 git。

另外一提,Mercurial,俗稱 hg,這一套版本控制系統是用 python 寫的,Mozilla 與 python 都將程式碼轉移到 hg 的系統之中。

我想,如果有人問我要選哪一個?因為現在使用 git 的人多,也許學用 git 會比較好。至於我自己個人,已經用了 hg,現在還不想隨便換。

參考:
https://zh.wikipedia.org/wiki/Git
https://git-scm.com/book/zh-tw/v1/%E9%96%8B%E5%A7%8B-%E9%97%9C%E6%96%BC%E7%89%88%E6%9C%AC%E6%8E%A7%E5%88%B6
http://lkml.iu.edu/hypermail/linux/kernel/0504.0/1540.html

2016年7月27日 星期三

[閒聊] arduino 也算是個語言?

IEEE 2016 程式排行榜 裡把 arduino 算是一個語言,引起一些討論。
我個人是可以理解為什麼會列為另一種語言。
也許它被認為”足夠”降低開發門檻成功給一般人使用,而且其生態系也大到一個程度。它的前處理,著實也做了很多事,從使用者的角度,根本看不到 C/C++ 要的 ..h, .c or .cpp。在簡化的程度上,已經讓只會寫 arduino 的人,一定不會用 C/C++ 的環境寫程式。
IEEE 官網也很多人質疑,說 arduino 不過是個開發環境,應該要算在 C 上面。但是就如同 C 與 C++ 一樣會有論戰,為什麼 C 要跟 C++ 算一起?或反過來說,C 與 C++ 要算一種語言嗎?如果算一種語言,為什麼要寫 C/C++ 而不乾脆說 C? 如果算兩種語言,但是算人頭的時候又要一起算呢?
曾經在閱讀 cython 的時候,看到他們寫的 「The Cython language is a superset of the Python language that additionally supports calling C functions and declaring C types on variables and class attributes.」他們做的事情,就是讓使用者可以用一般的 python 寫程式,也可以用 cython 新增加的語法指定與 c 合作的宣告與功能。他們也是先經過自己的「前處理器」,把程式轉換過。他們自稱是 cython language。而且還是 superset 。我曾經想了很久。後來又看到 TypeScript,CoffeeScript。如果這些努力可以說是新增了一個新語言,那麼,arduino 被稱做一個語言,我是可以理解的。
我自己的臉書備份