Clojureを使ってみる
たまたまClojureを触ってみて、なんだか良さそうだと感じたのでいろいろ書き散らしている。
環境構築が比較的容易で、WEBアプリが作りやすそうなのがよかった。あとScalaほど四角四面ではなく、Groovyほど壊れにくい*1
環境構築
まずこれでMavenと連携させてみる
Leiningen
そしてLeiningenを入れる
Windowsの場合、Msys2上でUNIX用のスクリプトを動かしたほうが早い
> wget https://raw.githubusercontent.com/technomancy/leiningen/stable/bin/lein -O /usr/bin/lein > lein self-install > lein --version Leiningen 2.7.1 on Java 1.8.0_112 Java HotSpot(TM) 64-Bit Server VM
Maven化
プロジェクトを作ってMaven化
$ lein new wiki
project.clj ができるので、そこからpomを作る
$ lein pom
leinが出力するpom.xmlは、全部project.cljが元である。Mavenに慣れているならパズルゲームみたいな感じで設定出来ると思う。
Hello, World!!
ここからHello, Worldまではこのサイトがわかりやすい
core.cljを書き換えて・・・最終的にこうなった
(ns wiki.core (:gen-class main true)) (defn -main "I don't do a whole lot." [& args] (println "Hello, World!"))
Emacs
適当にこんな感じ
;; Clojure (unless (package-installed-p 'clojure-mode) (package-refresh-contents) (package-install 'clojure-mode)) (require 'clojure-mode) (add-to-list 'auto-mode-alist '("\\.clj$" . clojure-mode))
EmacsでモダンClojure開発環境構築 - Qiita
新: Emacs を使うモダンな Clojure 開発環境 - Qiita
cider-modeはmsys2では動かないかもしれない。
コレクション操作
Ruby
見慣れた形、データが先で関数で回す
# listの中身をトレース [1, 2, 3].each do |n| puts n end # mapの中身をトレース { 1 => "a", 2 => "b", 3 => "c" }.each do |k, v| puts "#{k}, #{v}" end
Clojure
Lispなのでデータが後で関数が先
mapについては doseq, reduce-kv 2つの関数を見つけた
; listの中身をトレース (map #(println %) [1 2 3]) (map #(prn %) [1 2 3]) ; mapの中身をトレース (doseq [[k v] {1 "a" 2 "b" 3 "c"}] (prn k v)) (reduce-kv #(println %2 %3) 0 {1 "a" 2 "b" 3 "c"})
マクロとかLispっぽさ、関数型言語っぽい書き方もできたりするのだろうか。
チュートリアルを見ているとClojureは結構実用的に感じた。
Clojure の日本語ガイド — Clojure の日本語ガイド
- 作者: 山田剛史,杉澤武俊,村井潤一郎
- 出版社/メーカー: オーム社
- 発売日: 2017/07/15
- メディア: Kindle版
- この商品を含むブログを見る
*1:偏見…?
x86 汎用命令 - ModR/M の解説
ModR/Mについては前もちょっと記事を書いたけど、まだちょっと中途半端だったのでもう一度まとめます。
nantonaku-shiawase.hatenablog.com
ModR/Mの実際の例
例えば以下のような命令がある、 /r の意図がみなさんわからないのではないでしょうか?
; IMUL r32, imm32 0x69 /r iw
また、次のような命令、 /7 の意図がみなさんわからないのではないでしょうか?
; CMP r/m8, imm8 0x80 /7 ib
ModR/Mの構造
全体の概要についてはこのページをみたほうがよい
また、このページも役立つ
'''/r'''および'''/7'''の意味
解説を Assembly Programming on x86-64 Linux (06) から引用する
この記事で注目している項目を赤字で表現。
記法 | 解説 |
---|---|
/0 - /7 | ModR/M バイト の reg フィールドの 0 から 7 の数字はオペコードの拡張用に使われる。r/m フィールドだけをオペランドに使用する。 |
/r | 命令には ModR/M バイトが続き、レジスタオペランドと r/m オペランドの両方を使う。 |
cb、cw、cd、cp, co, ct | オペコードの後に 1 バイト(cb)、2 バイト(cw)、4 バイト(cd)、6 バイト(cp)、 8 バイト(co)または 10 バイト(ct)が続く。 |
ib, iw, id, io | オペコード、ModM/R バイト、または SIB の後に続く 1 バイト(ib)、2 バイト(iw)、4 バイト(id)または 8 バイト(io)の定数(即値)。 |
+rb, +rw, +rd, +ro | + の左側のオペコードに加算される 0 から 7 までのレジスタコード。 結果として 1 バイトのオペコードとなる。 |
reg(/0 - /7指定の場合)
- regは、/0 - /7を指定された場合はそれをそのまま使う
もちろんこれは10進数表記なので、2進数に直すと以下のようになる。ModR/Mバイトのregフィールドはこれで埋まるわけだ。
/0 - /7 | 2進数表記 |
---|---|
/0 | 000 |
/1 | 001 |
/2 | 010 |
/3 | 011 |
/4 | 100 |
/5 | 101 |
/6 | 110 |
/7 | 111 |
reg(/0 - /7指定の場合)の実例
- 0x80 /7 ib をアセンブル
; 0x80 /7 ib CMP r/m8, imm8 ; 例 CMP CL,18 ; オペコードは0x80で確定 ; --------------------- ; ModR/Mの値は ; [mod] 11 ; [reg] 111 ; [r/m] 001 ; => "11111001" ; => 0xf9 ; --------------------- ; 18は16進数で0x12 ; --------------------- ; よって、以下がアセンブルされると CMP CL,18 ; 以下のバイナリが出力される 0x80, 0xf9, 0x12
reg('''/r'''指定の場合)
- regは、レジスタコードを指定する
つまり、mod2bitに続いて、regとr/mが3bitずつ続くことになる
reg(/r指定の場合)の実例
- '''0x69 /r iw''' をアセンブル
; 0x69 /r iw IMUL r32, imm32 ; 例 IMUL ECX,4608 ; オペコードは0x69で確定 ; --------------------- ; ModR/Mの値は ; [mod] 11 ; [reg] 001 ; [r/m] 001 ; => "11001001" ; => 0xc9 ; --------------------- ; 4608は16進数で0x1200 ; リトルエンディアンのため、 0x00, 0x12と並ぶ ; --------------------- ; よって、以下がアセンブルされると IMUL ECX,4608 ; 以下のバイナリが出力される 0x69, 0xc9, 0x00, 0x12
/r指定の場合のレジスタの細かい指定
さて、実はここまでregとr/mのどちらがどちらのレジスタを指定しているのか気になった人がいるかもしれない。その指摘はめっちゃ正しい。
ここのサイトに答えが書いてある。
The d bit in the opcode determines which operand is the source, and which is the destination:
d=0: MOD R/M <- REG, REG is the source
d=1: REG <- MOD R/M, REG is the destination
"d"bitというのは、1byte(8bit)のデータを先頭から数えて4番目のbitである。*1
つまり、"d"bitが0か1かによってmodとr/mの3bitをそれぞれ入れ替えなければいけない。
C++の疑似コード、std::bitsetを使うとやりやすい
uint8_t op = 0x8e; std::bitset<8> bsl(op); // オペコード if (bsl[3]) { // d=0 or 1 // d=1: REG <- MOD R/M, REG is the destination } else { // d=0: MOD R/M <- REG, REG is the source }
はじめて読む486、ModRMとかに関してはほとんど役に立たず…
- 作者: 蒲地輝尚
- 出版社/メーカー: アスキー
- 発売日: 1994/09
- メディア: 単行本
- 購入: 20人 クリック: 165回
- この商品を含むブログ (84件) を見る
*1:わかるか…!こんな細かい仕様…!
Let's Encryptを手動更新
だいたいここの指示にしたがえばよし
こんなエラーが出た。
Cleaning up challenges Attempting to renew cert from /etc/letsencrypt/renewal/freestylewiki.xyz.conf produced an unexpected error: At least one of the required ports is already taken.. Skipping.
httpdを一回停止させればOK
# systemctl stop httpd
成功時のログ
* Pythonのスクリプトがいろいろやってる(秘密鍵更新+CSR作成+証明書作成(中間証明書も))
[root@freestylewiki letsencrypt]# ./certbot-auto renew --force-renew Saving debug log to /var/log/letsencrypt/letsencrypt.log ------------------------------------------------------------------------------- Processing /etc/letsencrypt/renewal/freestylewiki.xyz.conf ------------------------------------------------------------------------------- Starting new HTTPS connection (1): acme-v01.api.letsencrypt.org Renewing an existing certificate Performing the following challenges: tls-sni-01 challenge for freestylewiki.xyz Waiting for verification... Cleaning up challenges Generating key (2048 bits): /etc/letsencrypt/keys/0001_key-certbot.pem Creating CSR: /etc/letsencrypt/csr/0001_csr-certbot.pem ------------------------------------------------------------------------------- new certificate deployed without reload, fullchain is /etc/letsencrypt/live/freestylewiki.xyz/fullchain.pem ------------------------------------------------------------------------------- Congratulations, all renewals succeeded. The following certs have been renewed: /etc/letsencrypt/live/freestylewiki.xyz/fullchain.pem (success)