2019-11-28

Tcl: Two Fer

Create a sentence of the form "One for X, one for me.".

#!/usr/bin/env tclsh

if {$argc >= 1} {
    set name [lindex $argv 0]
} elseif {$argc == 0} {
    set name "you"
}

puts "One for $name, one for me."

2019-11-17

Tcl: Group the strings to concatenate together

set s "Hello "
set t "Tcl"
set u "!"
puts $s$t$u

也可以先設到某個變數,再印出來:
set s "Hello "
set t "Tcl"
set u "!"
set str $s$t$u

puts $str


感覺還蠻有趣的。

2019-11-13

Twitter feed for news and Tcl

@TclLang - Twitter feed for news about happenings in the Tcl world.


我之前沒注意到,這是 Tclers's wiki 的官方帳號嗎?不是很確定。

2019-10-29

tablelist 6.7

ANNOUNCE: Multi-column listbox and tree widget package Tablelist 6.7


Tablelist 釋出了一個新版 6.7,所以我也更新了自己的 RPM spec 測試。

2019-09-19

RabbitMQ/MQTT

RabbitMQ 是實現進階訊息佇列協議 AMQP (Advanced Message Queuing Protocol) 的中間件軟體, 支援的協議版本為 0.9.1,也有 plugin 可以支援 1.0。

官網上有提供安裝檔案可以使用,如果在 openSUSE 15.1,可以使用下列的指令安裝:
sudo zypper in rabbitmq-server rabbitmq-server-plugins

如果要啟動服務,可以使用下列的指令:
sudo service rabbitmq-server start

如果要重啟服務,可以使用下列的指令:
sudo service rabbitmq-server restart

如果知道服務的狀態,可以使用下列的指令:
sudo service rabbitmq-server status

如果要停止服務,可以使用下列的指令:
sudo service rabbitmq-server stop


RabbitMQ 有支援 MQTT 3.1 的 plugin。下面是啟用的方式(啟用後需要重開 server 才會生效):
sudo rabbitmq-plugins enable rabbitmq_mqtt

設定檔案在 /etc/rabbitmq/rabbitmq.conf,因為只是要測試,所以我把 port 改為 1883,啟用預設的 username/password, 並且關閉允許匿名連線:
## ----------------------------------------------------------------------------
## RabbitMQ MQTT Adapter
##
## See https://github.com/rabbitmq/rabbitmq-mqtt/blob/stable/README.md
## for details
## ----------------------------------------------------------------------------

# =======================================
# MQTT section
# =======================================

## TCP listener settings.
##
mqtt.listeners.tcp.1 = 127.0.0.1:1883
mqtt.listeners.tcp.2 = ::1:1883

## TCP listener options (as per the broker configuration).
##
# mqtt.tcp_listen_options.backlog = 4096
# mqtt.tcp_listen_options.recbuf  = 131072
# mqtt.tcp_listen_options.sndbuf  = 131072
#
# mqtt.tcp_listen_options.keepalive = true
# mqtt.tcp_listen_options.nodelay   = true
#
# mqtt.tcp_listen_options.exit_on_close = true
# mqtt.tcp_listen_options.send_timeout  = 120

## TLS listener settings
## ## See https://rabbitmq.com/mqtt.html and https://rabbitmq.com/ssl.html for details.
#
# mqtt.listeners.ssl.default = 8883
#
# ssl_options.cacertfile = /path/to/tls/ca_certificate_bundle.pem
# ssl_options.certfile   = /path/to/tls/server_certificate.pem
# ssl_options.keyfile    = /path/to/tls/server_key.pem
# ssl_options.verify     = verify_peer
# ssl_options.fail_if_no_peer_cert  = true
#


## Number of Erlang processes that will accept connections for the TCP
## and TLS listeners.
##
# mqtt.num_acceptors.tcp = 10
# mqtt.num_acceptors.ssl = 10

## Whether or not to enable proxy protocol support.
## Once enabled, clients cannot directly connect to the broker
## anymore. They must connect through a load balancer that sends the
## proxy protocol header to the broker at connection time.
## This setting applies only to STOMP clients, other protocols
## like STOMP or AMQP have their own setting to enable proxy protocol.
## See the plugins or broker documentation for more information.
##
# mqtt.proxy_protocol = false

## Set the default user name and password used for anonymous connections (when client
## provides no credentials). Anonymous connections are highly discouraged!
##
mqtt.default_user = guest
mqtt.default_pass = guest

## Enable anonymous connections. If this is set to false, clients MUST provide
## credentials in order to connect. See also the mqtt.default_user/mqtt.default_pass
## keys. Anonymous connections are highly discouraged!
##
mqtt.allow_anonymous = false

## If you have multiple vhosts, specify the one to which the
## adapter connects.
##
mqtt.vhost = /

## Specify the exchange to which messages from MQTT clients are published.
##
mqtt.exchange = amq.topic

## Specify TTL (time to live) to control the lifetime of non-clean sessions.
##
mqtt.subscription_ttl = 1800000

## Set the prefetch count (governing the maximum number of unacknowledged
## messages that will be delivered).
##
mqtt.prefetch = 10

下面是使用 tcl.mqttc 測試 Subscribe 與 Publish 功能的測試程式:
package require Thread
package require mqttc
catch {console show}

set ::gThread [thread::create {thread::wait} ]
set result 0

proc subscribe { } {
    thread::send -async $::gThread {
        package require mqttc

        mqttc client "tcp://localhost:1883" "USERTest1" 1 -cleansession 1 \
                     -username guest -password guest
        client subscribe  "MQTT Examples" 1
        while 1 {
            if {[catch {set result [client  receive]}]} {
                puts "Receive error!!!"
                break
            }
            if {[llength $result] > 0} {
                puts "[lindex $result 0] - [lindex $result 1]"
                if {![string compare -nocase [lindex $result 1] "Exit"]} {
                    break
                }
            }
        }
        client unsubscribe  "MQTT Examples"
        client close
    } ::result
}

subscribe
puts "started test..."

after 250

mqttc client "tcp://localhost:1883" "USERTest2" 1 -timeout 1000 \
             -username guest -password guest
client publishMessage "MQTT Examples" "Hello MQTT!" 1 0
client publishMessage "MQTT Examples" "Exit" 1 0
client close

vwait ::result

2019-09-10

tcl.mqttc v0.6

因為 paho.mqtt.c 有一個新的版本 1.3.1,所以我做了 tcl.mqttc 相關的更新,同時將版本設成 v0.6。

不過我只有測試 tcp 部份,使用 ActiveMQ 測試 MQTT 3.1,以及使用 EMQX 測試 MQTT 3.1 以及 5 的部份。

我忘記是不是有在這個部落格貼過了,下面是 MQTT 3.1 測試 Subscribe 與 Publish 功能的測試程式:
package require Thread
package require mqttc
catch {console show}

set ::gThread [thread::create {thread::wait} ]
set result 0

proc subscribe { } {
    thread::send -async $::gThread {
        package require mqttc

        mqttc client "tcp://localhost:1883" "USERTest1" 1 -cleansession 1
        client subscribe  "MQTT Examples" 1
        while 1 {
            if {[catch {set result [client  receive]}]} {
                puts "Receive error!!!"
                break
            }
            if {[llength $result] > 0} {
                puts "[lindex $result 0] - [lindex $result 1]"
                if {![string compare -nocase [lindex $result 1] "Exit"]} {
                    break
                }
            }
        }
        client unsubscribe  "MQTT Examples"
        client close
    } ::result
}

subscribe
puts "started test..."

after 250

mqttc client "tcp://localhost:1883" "USERTest2" 1 -timeout 1000
client publishMessage "MQTT Examples" "Hello MQTT!" 1 0
client publishMessage "MQTT Examples" "Exit" 1 0
client close

vwait ::result

2019-08-19

casstcl 2.13.2

我發現有新的版本,所以更新了我自己的 openSUSE RPM spec

casstcl  需要 cassandra cpp driver,我也有寫一個 openSUSE RPM spec,在安裝 casstcl 前需要先安裝 cassandra cpp driver。

2019-08-05

MAWT (Movie Automation With Tcl) 0.2.0

MAWT - Movie Automation With Tcl 已經在 2019/06/20 釋出了 0.2.0。

0.2.0 更新的資訊:
Improved video generation functionality.


所以我也更新了我自己的 openSUSE 套件

2019-06-08

Tclsh and Here document

Here document

之前我只有在 bash 使用過,今天突然間想試看看 tclsh。我發現…… 對,可以使用同樣的手法。下面就是一個測試的例子:
tclsh - << "EOF"
puts "HELLO World"
EOF

再來是另外一個簡單的測試:
tclsh - << "EOF"
puts [expr 99 + 1]
EOF

這樣就可以在命令列執行簡單的 tclsh 命令。

2019-06-02

Functional Programming

Functional Programming (Tcler's Wiki)


Tcl 是個很奇妙的語言,就如同下面說的:

As with many things, Tcl is rather unique in this area. Commands themselves can not be passed as arguments to other commands, but their names can, which provides something very similar to first-class functions. Additionally, apply can be used to interpret a value as a function and evaluate it, providing the equivalent of lambda functions.


Tcl 的表達方式與波蘭表示法 (Polish notation) 一樣,和 Lisp 的 S-expression 的精神十分相像,特點是操作符置於操作數的前面(就是如果是一連串資料所組合成的述句,Tcl 述句的第一個是一個 command,後面是 command 要處理的資料)。

Tcl 也跟 Lisp 一樣,並不是純粹的 Functional Language,而是支援多重典範的語言。

2019-05-24

Tcl: 奇數和偶數

#!/usr/bin/env tclsh

puts -nonewline "Please input a number: "
flush stdout
gets stdin var
 
if { [ regexp {^[0-9]+$} $var ] == 0} {
    puts "It is not a number!!!"
    exit
}

if { [expr $var % 2] == 0} {
    puts "It is even!!!"
} else {
    puts "It is odd!!!"
}

也是一個很簡單的練習,只是使用正規表示式判斷是否為數字。

2019-05-21

Tcl:九九乘法表

這只是一個簡單的 Tcl 練習。

所以第一個是 for loop 的版本。
#!/usr/bin/env tclsh

for {set nx 0} {$nx < 10} {incr nx} {
    for {set ny 0} {$ny < 10} {incr ny} {
        puts "[format "%d x %d = %2d" $nx $ny [expr $nx  * $ny]]"
    }
} 

第二個版本是我在寫同樣的東西(也是九九乘法表),因為 Erlang 沒有 for 和 while 迴圈,所以我先建立一個 list,然後再使用 Erlang 提供的 lists:foreach 印出結果。我用同樣的精神寫 Tcl 九九乘法表的第二個版本(同時測試 mathop)。
#!/usr/bin/env tclsh

set x [list 1 2 3 4 5 6 7 8 9]
set y [list 1 2 3 4 5 6 7 8 9]

foreach nx $x {
    foreach ny $y {
        set z [::tcl::mathop::* $nx $ny]
        puts "[format "%d x %d = %2d" $nx $ny $z]"
    }
}

最後是遞迴的版本:
#!/usr/bin/env tclsh

namespace path {::tcl::mathop ::tcl::mathfunc}

proc mul {x y} {
    puts [format "%d x %d = %2d" $x $y [* $x $y]]
    if {$y < 9} {
        mul $x [+ $y 1]
    } else {
        if {$x < 9} {
            mul [+ $x 1] 1
        } else {
            return
        }
    }
}

mul 1 1

2019-05-13

Next Scripting Framework 2.3.0

ANNOUNCE: Next Scripting Framework 2.3.0 is available


NSF 釋出了 2.3.0,所以我更新了我自己的 openSUSE RPM spec, 這可以比較方便進行測試。我在下載的時候 SourceForge 似乎出現問題,所以無法順利下載,我把下載檔案的地址切到 NSF 在 Github 的 mirror

2019-05-09

Update tklib spec

tklib-spec


因為 tablelist 釋出了新版 v6.5,為了反應 tklib 最近的變化,所以更新了我自己的 openSUSE RPM spec,更新到目前的 code base。

2019-04-16

使用 QEMU 執行 openSUSE/AARCH64 image

因為 tclBlend 我接到一個 issue,在 AARCH64 下編譯失敗,所以需要一個 AARCH64 模擬器來除錯。


首先要安裝 QEMU-ARM:
sudo zypper install qemu-arm

要下載一個 openSUSE AARCH64 image 來進行測試(我使用 unxz 解壓縮)。
wget https://download.opensuse.org/ports/aarch64/factory/images/openSUSE-Tumbleweed-ARM-JeOS-efi.aarch64-Current.raw.xz
unxz openSUSE-Tumbleweed-ARM-JeOS-efi.aarch64-Current.raw.xz

如果使用 efi image,需要有 Unified EFI BIOS 模擬器正確的載入 boot loader 才行(不然無法正確執行)。我從 Linaro 下載一個來使用。
wget https://releases.linaro.org/components/kernel/uefi-linaro/16.02/release/qemu64/QEMU_EFI.img.gz
gzip -d QEMU_EFI.img.gz 

然後就可以這樣執行:
qemu-system-aarch64 -m 2048 -cpu cortex-a57 -smp 2 -M virt -bios QEMU_EFI.img -serial stdio -device virtio-net-device,netdev=hostnet0,id=net0,mac=52:54:00:09:a4:37 -netdev user,id=hostnet0  -drive if=none,format=raw,file=openSUSE-Tumbleweed-ARM-JeOS-efi.aarch64-Current.raw,id=hd0  -device virtio-blk-device,drive=hd0

(使用者帳號為 root,密碼為 linux)

參考文章:
openSUSE:AArch64
Documentation/Platforms/ARM
Linux on AArch64 ARM 64-bit Architecture
Building ARM Servers With UEFI And ACPI


就 ARM 來說,有二種描述 hardware scheme 的方式,一種是 UEFI/ACPI,一種是 Device Tree。Linux kernel 可以編譯為二種都支援。文件中有提到:

ACPI support in drivers and subsystems for ARMv8 should never be mutually exclusive with DT support at compile time.

At boot time the kernel will only use one description method depending on parameters passed from the boot loader (including kernel bootargs).

Regardless of whether DT or ACPI is used, the kernel must always be capableof booting with either scheme (in kernels with both schemes enabled at compile time).

2019-04-10

Difference between 2 dates in XQuery

package require xqilla

xqilla db
set exprs [db prepare {days-from-duration(xs:dateTime('2019-06-14T00:00:00') - current-dateTime())}]
set result [$exprs execute]
set diff 0

while {[$result next]} {
    set diff [$result string_value]
}

puts "The answer is $diff."

$result close
$exprs close
db close

使用 XQuery 的日期函式計算出二個日期間的差距,這裡使用 XQilla 測試。

Difference between 2 dates in SQLite3

package require tdbc::sqlite3

tdbc::sqlite3::connection create db :memory:
set statement [db prepare {SELECT CAST ((JulianDay('2019-06-14') - JulianDay('now')) as Integer) as d}]    

set diff 0
$statement foreach row {
    if {[catch {set diff [dict get $row d]}]} {
        set diff 0
    }
}

puts "The answer is $diff."

$statement close
db close

使用 SQLite3 的日期函式計算出二個日期間的差距,這裡使用 tdbc::sqlite3 測試。

2019-03-04

tkimg 1.4.9

tkImg


tkImg 釋出了一個新的版本,1.4.9。


下面是節錄的說明:

This file contains a collection of format handlers for the Tk photo image type, and a new image type, pixmaps. It can be used in combination with Tcl/Tk 8.3 or later but 8.6 or newer are highly recommended.

Included in this distribution are the most recent versions (as of March 2019) of the libz, libpng, libjpeg, and libtiff libraries. These are not required, unless you need support for the PNG, JPEG, or TIFF format. Note that you have to build these libraries to support the named formats, even if your system already has shared libraries for these formats. This is because the libraries here are built such that they can be loaded as packages by the Tcl/Tk core, making the handling of the various dependencies much easier. An earlier version, 1.2.4, used a modified copy of Tcl's functions for loading of shared libraries to load the support libraries at runtime. These have been abandoned in favor of the new approach.

2019-02-14

Update tcl-cmark

tcl-cmark


tcl-cmark 最近更新,修正了 cmark-gfm 最近幾個版本的不相容修改結果 tcl-cmark 會編譯失敗的問題。我自己的 RPM spec 也跟著更新,移掉我自己之前的修正,使用 tcl-cmark 更新的部份就可以了。

2019-02-11

Update tclreadline

tclreadline


tclreadline 釋出了一個新的版本,所以我也更新了我自己的 RPM spec

2019-01-23

otpcl

otpcl - Open Telecom Platform Command Language a.k.a. Tcl-Flavored Erlang


這是一個很有趣的案子,在 Erlang VM 寫一個類似 Tcl 的語言,但是目前只是在極早期開發的階段,看起來是有一些東西可以用但是離真的能實際使用仍然有一大段的距離。

Erlang 最近幾年似乎聲勢有掉下來的情況(我是指本來就有點小眾的情況變成真的小眾,然而 WhatsApp 又再次證明 Erlang 在網路程式上真的有其優越之處),但是分散式系統或者是 concurrent solution (也就是 Actor model) 方面仍然是眾多解決方案「致敬」的對象。

2019-01-01

promise 1.1.0

ANNOUNCE: promise 1.1.0 released
tcl-promise-spec


Promises are concurrency primitives that let you write asynchronous code in a sequential style. This Tcl based implementation is mostly modeled on the Javascript/ECMAScript 7 standard. 

因為作者釋出新版,所以我也更新了我自己的 openSUSE RPM spec.