記録は作業の証

鉄道とコンピュータ

Vim/NeovimでLisp処理系と対話するためのプラグイン Vlime

導入

リポジトリはこちら github.com

公式マニュアル

公式チュートリアル

Susam Pal 氏によるチュートリアル

設定

デフォルトでは'\'(バックスラッシュ)キーをプレフィクスとするコマンドを使う。 自分はカンマに設定している。

 let g:vlime_leader = ','
" sbclとcclはプラグイン内(vim/autoload/vlime/server.vim)で対応している
" 他の実装はドキュメントを見て少々特別な設定をする必要がある
let g:vlime_cl_impl = 'ccl'

Vlimeのリポジトリに含まれるstart-vlime.lispを手動でLisp処理系にロードしてから使うプラグインである。そのためシェルのエイリアスを設定しておくとよい。

よく使うコマンド

太字は特によく使う。

  • ,rr Lisp実装を起動してSLIMEサーバを開始し、接続する。オムニ補完はSLIMEサーバと繋がっているときに有効。

  • ,cc 手動で起動したSLIMEサーバに接続する。

    • リモートのLisp処理系に繋いでリモートデバッグできる(!)。
  • REPLへ送信(,s)
    • \i インタラクションモードの開始と終了。
    • \st バッファ内のトップレベルにある式で、カーソルの下にあるものを送信する。
    • \se 今カーソルが合っている式を送信する。
    • \sa 今カーソルが合っているアトムを送信する。
      • 変数を参照するときに使う。
    • \l 今のファイルをロードする。
    • \b 関数の入口にブレークポイントを設定する。
  • コンパイル(,o)
  • 定義の削除
    • \uf 関数を削除する。
    • \us シンボルを削除する。
    • \ui 対話的に削除する。
  • マクロ展開
    • \mm MACROEXPANDしてプレビューバッファに出す。
    • \m1 MACROEXPAND-1してプレビューバッファに出す。
    • \ma 全ての入れ子のマクロを展開する。
  • REPLバッファ
    • CTRL-C REPLスレッドを止める
    • \I カーソル下の評価結果をインスペクタで見る。
    • \y 無名バッファに評価結果をヤンクする。
    • \C REPLバッファをクリアする。
    • CTRL-n 表示されている次のオブジェクトに移動?
    • CTRL-p 表示されている前のオブジェクトに移動?
  • デバッガバッファ
    • d カーソルの下のフレームについて、ローカル変数やソースファイル位置などの詳細を表示する。
    • S カーソル下のフレームに関係するコードへジャンプする。
    • T カーソル下のフレームに関係するコードへ新しいタブでジャンプする。
    • a ABORTする。
    • c CONTINUEする。
    • e カーソルの下のフレーム内で式を評価する。
      • 誤りを修正できる?
    • E カーソルの下のフレーム内で式を評価してREPLへ送信する。
    • C コンディションオブジェクトをインスペクタで見る。
    • r カーソル下のフレームを再起動する。
    • s カーソル下のフレームでステップ実行を始める。
    • x ステップオーバー。
    • o ステップアウト。
    • D 逆アセンブル
  • インスペクタ
    • 型やオブジェクトのスロットなどを表示してくれるようだ
    • \IT トップレベルにある中でカーソルの下にあるものをインスペクタで見る
    • \II カーソルの下の式またはアトムを評価してインスペクタで見る
    • \IE カーソルの下の式を評価してインスペクタで見る
    • \IA カーソルの下のアトムを評価してインスペクタで見る
    • \I ビジュアルモードで選択中の領域を評価してインスペクタで見る
    • インスペクタバッファ
      • Space フィールドやボタンを押す
      • CTRL-n 次のフィールドやボタンへ
      • CTRL-p 前のフィールドやボタンへ
      • s カーソルの下のフィールドの値をREPLに送信する。
      • S インスペクタで見ている値をREPLに送信する。
      • p インスペクタで 一つ前に見ていたオブジェクトに移動する。
      • P インスペクタで 一つ次に見るオブジェクトに移動する。
      • R インスペクタバッファを更新する。
    • インプットバッファではiで書いてEscで抜けてEnterキーで確定
  • パッケージ
    • \p 現在のバッファで使うパッケージを指定する
  • クロスリファレンス

Rustで1行に数字が並ぶテキストを読む方法

はじめに

AtCoderなどの競技プログラミングのプラットフォームでは、標準入力として空白と改行で区切られたテキストが与えられることが多い。

N
A_1 A_2 ... A_N

Rustでは入出力の記述が煩雑になりやすいとされているため、有志によってproconioというクレートが開発されている。

docs.rs

もっと単純に事を済ませることができないかと考えたので、ここにコードを記録しておく。

コード

fn read_line() -> String {
    let mut line = String::new();
    std::io::stdin().read_line(&mut line).unwrap();
    line
}

fn scan_line<F>() -> Vec<F>
where
    F: std::str::FromStr,
{
    read_line()
        .trim()
        .split_whitespace()
        .flat_map(|s| s.parse::<F>())
        .collect()
}

データが空白区切りで、それぞれのデータが FromStr が実装されている型としてパースできればよいということにしてみた。

上の例のフォーマットで入力が与えられるとき、以下のようにすれば読み取ることができる。

if let [n] = scan_line()[..] {
    let a_n = scan_line()[..n].to_vec();
    solve(n, a_n);
}

TRPL読書記 1

はじめに

知り合いが「これからはRustを知らないとまずいぞ」というので、重い腰をあげてRustを勉強することにした。

まずはTRPLから読んでみることにし、とりあえず第三章まで読んだので練習問題の自分の解答をここに掲載してみる。

書いたコード

温度を華氏と摂氏で変換する。

fn main() {
    let celsius = 33;
    let fahrenheit = (celsius as f64) * 1.8 + 32.0;
    println!("{}℃ → {}℉", celsius, fahrenheit);

    let fahrenheit = 88.0;
    let celsius = (fahrenheit - 32.) / 1.8;
    println!("{}℉ → {}℃", fahrenheit, celsius);
}

フィボナッチ数列のn番目を生成する。

fn main() {
    for n in 0..10 {
        println!("fib({}) is: {}", n, fib(n));
    }
}

fn fib(n: u32) -> u64 {
    if n == 0 {
        return 0;
    }
    if n == 1 {
        return 1;
    }
    let mut now: u64 = 0;
    let mut next: u64 = 1;

    for _ in 2..(n + 1) {
        let temp = now + next;
        now = next;
        next = temp;
    }

    next
}

クリスマスキャロルの定番、"The Twelve Days of Christmas"の歌詞を、 曲の反復性を利用して出力する。

fn main() {
    for n in 1..13 {
        print_on_the_nth_day_of_christmas(n);
        print_presents(n);
        print_partridge(n);
        println!("")
    }
}

fn print_on_the_nth_day_of_christmas(n: u8) {
    let d = [
        "zero", "first", "second", "third", "fourth", "fifth", "sixth", "seventh", "eighth",
        "ninth", "tenth", "eleventh", "twelfth",
    ];

    println!(
        "On the {} day of Christmas my true love sent to me",
        d[n as usize]
    );
}

fn print_presents(n: u8) {
    let presents = [
        "dummy zero",
        "dummy one",
        "two turtle doves,",
        "three French hens,",
        "four calling birds,",
        "five golden rings.",
        "six geese a-laying,",
        "seven swans a-swimming,",
        "eight maids a-milking,",
        "nine ladies dancing,",
        "ten lords a-leaping,",
        "eleven pipers piping,",
        "twelve drummers drumming,",
    ];

    for i in (2..(n as usize + 1)).rev() {
        println!("{}", presents[i]);
    }
}

fn print_partridge(n: u8) {
    if n >= 2 {
        print!("and ");
    }
    println!("a Partridge in a Pear Tree.");
}

picoCTF Write-up ARMssembly 0

問題文

https://play.picoctf.org/practice/challenge/160

What integer does this program print with arguments 4134207980 and 950176538? File: chall.S Flag format: picoCTF{XXXXXXXX} -> (hex, lowercase, no 0x, and 32 bits. ex. 5614267 would be picoCTF{0055aabb})

考えたこと

AArch64のアセンブリプログラムを読み、実行結果が何であるかを問うもの。

最初は、アルゴリズムを理解する必要があると考え律儀に読んでいた。

そうしているうちに、ふと、実行環境を用意して実行すればいいだけなのではないかと気がついた。

解答

AArch64のGCCQEMUを用意して実行する。

$ aarch64-linux-gnu-gcc chall.S
$ qemu-aarch64-static -L /usr/aarch64-linux-gnu/ ./a.out 4134207980 950176538

picoCTF Write-up keygenme-py

問題文

https://play.picoctf.org/practice/challenge/121

keygenme-trial.py

考えたこと

Pythonスクリプトを読み解くことで解くようだ。読み解くことで次のことがわかる。

  • フラグに関連する文字列が格納された変数群がある。
    • key_part_static1_trial
    • key_part_dynamic1_trial
    • key_part_static2_trial
    • key_full_template_trial
  • check_key という関数という関数があり、ユーザが入力した文字列 user_keybUsername_trial をSHA256でハッシュ化したものと比較している。
  • decrypt_full_version という関数で、暗号化された文字列 full_versionuser_key を使って復号している。
  • 復号できたコードを実行し、「フルバージョン」に移行する。

bUsername_trialFREEMAN という文字列である。復号鍵は、 FREEMAN をSHA256でハッシュ値を計算し、その16進数表現での一部の文字を取りだして並べかえたもののようだ。

解答

Racketで計算してみる。

gist1a3f6e96013dd25b4b3c5175f3206c0c

picoCTF Write-up caesar

問題文

https://play.picoctf.org/practice/challenge/64

Decrypt this message.

考えたこと

ヒントにはシーザー暗号のことが書かれていたので、これで復号すればよさそう。

問題は鍵がわからないことである。アルファベットだけで26通り試す必要がある。

CyberChefで頑張ってもよいが、プログラムで解いてみることにした。

解答

Racketで無駄に細かく実装してしまった。

gist78f1bc506514bd2cdeea83ce8c67827d

picoCTF Write-up Easy1

問題文

The one time pad can be cryptographically secure, but not when you know the key. Can you solve this? We've given you the encrypted flag, key, and a table to help UFJKXQZQUNB with the key of SOLVECRYPTO. Can you use this table to solve it?.

考えたこと

table.txt というファイルがあり、アルファベットの表のようなものがある。 どこかで見覚えがあったので、次の本で調べてみると、どうやらウィジュネル暗号というものらしい。

鍵の文字の列を見て、次に平文の文字の行を見て、交差するところの文字が暗号文の文字になるらしい。

解答

表を生成して、手作業でやるのと同じ要領をプログラムとして実装してみた。

gista314157a89293838cb7e584d9148e7a9