たいちょーの雑記

ぼくが3日に一度くらい雑記をかくところ

Goが面白いのでまたcdx作った

cdx

github.com

cdx は僕が一人でメンテしてる cd コマンドのラッパーです。この手のツールでよく使われているのは、enhancdzなどがあります。

github.com

github.com

とくにenhancdは非常に強力なツールで、利用している方も多いと思います。

cdxではCustomSourceという設定項目を用意しました。これを利用することでenhancdの持つような機能はユーザー側が設定として与えることが出来ます。そのかわりcdxは僕が素の状態である程度使えるような機能だけを実装したものになります。

要求環境

  • Go lang (v1.10.2 以上)
    • 実装にはGoを使いました。最近はじめて面白いなと思いました。CLIツールを作るならGoはいい感じですね
  • bash or zsh
    • fishは対応していません
  • fzfやpecoみたいなFuzzy-Finder

インストール

  1. go get するか、GitHubのReleaseページからバイナリをダウンロードしてパスの通ったところに置いてください
$ go get github.com/xztaityozx/go-cdx
  1. お好みのFuzzy-Finderを用意します。個人的には fzfがすきです。 fzy と言うやつもいいらしいですね

github.com

github.com

  1. コンフィグを書いて置きます
$ mkdir -p ~/.config/go-cdx
$ cat << EOF > ~/.config/go-cdx/.go-cdx.json
{
  "HistoryFile": "~/.config/go-cdx/history.json",
  "BookMarkFile":"~/.config/go-cdx/bookmark.json",
  "Command":"pushd",
  "NoOutput":true,
  "Make":false,
  "CustomSource":[],
  "FuzzyFinder":{
    "CommandPath":"選んだFuzzy-Finder",
    "Options":[]
  },
  "BinaryPath":"go-cdxへの絶対パス。go getした場合は消してOK"
}
EOF
$ vim ~/.config/go-cdx/.go-cdx.json # 好きなように設定してください

設定値はGitHubのREADMEに書いてあるのでそちらを見てください

  1. cdx をロードします。
# cdxをロード
$ eval "$(go-cdx --init)"
# シェル起動時に自動でロードするならrcに記述すればOK
$ echo 'eval "$(go-cdx --init)"' >> ~/.zshrc # or ~/.bashrc

使い方

cdx [-A,--action [act]|
     --add|
     -b,--bookmark|
     --config [configFile]|
     --cs-list|
     -c,--custom [name]|
     --help|
     -h,--history|
     --init|
     --make|
     --no-output|
     -p,--popd|
     -v,--version] [PATH]

基本はcdコマンドと同じように使います

$ cdx ~/      # change to home
$ cdx ~/Utils # change to ~/Utils

-A,--action [act]

このオプションでは移動した後にそのディレクトリで実行するコマンドを指定できます

$ cdx ~/Utils --action "ls"
go-cdx
go-cdx.v1.0.13
go-cdx.v1.0.13.tar.gz
...
$ pwd
/home/xztaityozx/Utils

コマンドはbash -cに渡されて実行されることに注意してください

--add

ブックマークにカレントディレクトリを追加します。重複のチェックをしないので注意してください

-b,--bookmark

bookmarkからFuzzy-Finderを使って1つ選択し、cdします。

$ cdx -b
>
  3/3
> [   3] /path/to/hoge
  [   2] /path/to/fuga
  [   1] /path/to/foo

--config [configFile]

デフォルトのコンフィグの代わりになるコンフィグファイルを指定できます。デフォルトは~/.config/go-cdx/.go-cdx.jsonです

--cs-list

後に説明するCustomSourceからのcdの一覧を表示して終了します

-c,--custom [name]

Goでcdxを書き直すにあたって、追加した目玉機能です

cdxは複雑な機能を単体で持ちませんが、代わりにユーザーが機能を自由に追加することが出来ます。これをCustomSourceとよんでいます

CustomSource は、その 名前Fuzzy-Finderに与える入力 のペアで構成されます。

{
    "CustomSource":[
        {
            "Name":"g",
            "Command":"ghq list | xargs -n1 -I@ echo 'echo -e \"$(basename @) $(ghq root)/@\"'|bash|column -t"
        },
    ]
}

この例では、 ghq listで表示されるリポジトリ一覧から1つ選んでcdするgという名前の機能を追加しています

# Fuzzy-Finderに与える入力
$ ghq list | xargs -n1 -I@ echo 'echo -e \"$(basename @) $(ghq root)/@\"'|bash|column -t
"Contest                        /home/xztaityozx/.ghq/github.com/xztaityozx/Contest"
"cdx                            /home/xztaityozx/.ghq/github.com/xztaityozx/cdx"
"dotfiles                       /home/xztaityozx/.ghq/github.com/xztaityozx/dotfiles"
"nandokuka                      /home/xztaityozx/.ghq/github.com/xztaityozx/nandokuka"
"yov                            /home/xztaityozx/.ghq/github.com/xztaityozx/yov"
# cdx のCustomSource gを使ってみる
$ cdx -c g
>
  19/19
> Contest                        /home/xztaityozx/.ghq/github.com/xztaityozx/Contest
  cdx                            /home/xztaityozx/.ghq/github.com/xztaityozx/cdx
  dotfiles                       /home/xztaityozx/.ghq/github.com/xztaityozx/dotfiles
  nandokuka                      /home/xztaityozx/.ghq/github.com/xztaityozx/nandokuka
  yov                            /home/xztaityozx/.ghq/github.com/xztaityozx/yov

この機能を使って、Fuzzy-Finderで選択された行のいちばん後ろのカラムが、移動先のパスとして選択されることに注意してください

CustomSourceでオレオレcdxを作ることが出来ます

--help

ヘルプを出力して終了します

-h,--history

履歴をFuzzy-Finderで選択してcdします。ログアウトしても履歴はリセットされません

--init

cdxをロードするときにのみ使います

--make

移動しようとする先が存在しないディレクトリだった場合、作成するか訪ねます。yesと答えた場合のみ、ディレクトリを作成しcdします

--no-output

cdxからの出力を無効化します。Fuzzy-Finderや--action出力は表示されます。

-p,--popd

popdを実行して終了します

-v,--version

バージョン情報を出力して終了します

終わり

cdx をよろしくお願いいたします

ICPC2018国内予選に参加した

参加しました

参加しました

A,Cの2完でした。

イカれたメンバー紹介

  • ぼく(@xztaityozx_001)
    • いつもはC#で参加しているヤツ。AtCoderレートがそろそろ茶色に落ちる
    • 激しい憎悪によって目覚めた伝説のバトルメイド1
  • wheson(@wheson)
    • 実質水色の緑。笑顔が素敵。
    • vimのDockerfileを試して、dotfilesを更新したのに反映されない!って怒ってたけどpushしてなかっただけの悪いやつ
  • eliza0x(@eliza0x)
    • いつもはHaskellで参加してるヤツ。感情がすぐに無になる
    • 激しい憎悪によって目覚めた伝説のバトルメイド2

ICPC2018国内予選0問題「参加」

すっごいあめだったので、ぜんじつ、おうちに、かえれませんでした
ちかくにそぼのいえがあるので、ひなんしました。

あさおきたら、あめがやんでいませんでした。ぬれながらがっこうにいきました。
がっこうについたら、むわっとしていました。さいあくでした

そうこうしていたら、めんばーがしゅうごうしたので、ACしました

準備

正直服とか靴とかびしょびしょでコンディションは最悪。それでもなんとか参加できそうであったので、PCのセットアップ、ホワイトボードや飲み物の用意をしました。この日、僕は家に帰れないことが確定していたため、手持ちの服を温存するために、メイド服を着ました。これは去年の11月にゼミ内の圧力により手に入れた暗黒の力です。面倒なことにこれを着ている間は「メイド長」という別の人格が宿る設定なので、色々手間です。この記事ではこの設定が守られない箇所があります。よろしくおねがいいたします。

これについてもう少しあって、正直ぼくはメイドさんという属性は好きだし、手持ちのメイド服もフリフリしててかわいいんですが、できれば誰も見ていないところでひっそり自分だけで楽しみたいと思っています。

因みにもう一着あるのですが、それはeliza0xが着ていました。

なのでここから先は二人のメイドと男が競プロしてる情景を思い浮かべながら読んでください

開始〜A問題AC

開始と同時に前回の教訓を活かしてALLを3部印刷しました。ステープラーで3部をまとめましたが、途中でステープラーがぶっ壊れて泣きました。

Aを読んでいたwhesonとeliza0xが「やるだけ」と言っていたので、また自明に実装の早いwhesonが実装しました。

ACまで10分ぐらいだったのでいい感じだと思いました。

B,Cを読む

Bをeliza0xとwhesonで考察しました。日本語が難しかったので、読解に時間がかかりましたが「実装激重だけどやるだけ」という感じだったのでeliza0xが実装することに。この間 ぼくはあとの問題のためにテンプレを作り、Cを先に読んでいました。

Bの実装が始まったのでCについてwhesonに説明しました。すると「しゃくとりするだけでは?」みたいな提案を受けたので、「109^ だけど大丈夫か?」と聞きました。なんやかんや話してみましたが、まぁ大丈夫でしょwとなったので愚直なしゃくとりを書く方針になりました。

Bがバグる。Cを通す

Bが激重だったのでバグってしまいました。「バグったら印刷して交代」という作戦を取ることにしていたので、Cをやることに。実装がちゃんと降りてきていたみたいなのでwhesonに任せました。

この辺から暑くてメイド服は半脱ぎ状態でした。

しゃくとり自体はすぐかけたみたいなのでテストケースを回すと、計算が終わらないので最適化オプションをつけると、ビビるぐらい計算がはやくなってみんなでビビりました。サンプルはあっていたので提出しAC

無限

ここからBの実装に無限にやられてしまいました。こんがらがってしまった時点で別の誰かが実装を最初からするほうが良かったのかもしれません。

eliza0xからのヘルプに答えつつ、残りの問題で解けそうなのが無いかwhesonと探しましたがぼくは最大流の波動を感じませんでしたし、DPのwhesonもどうやっておとせるかわからないということでした。

G問題が構文解析だったので構文解析のeliza0xに問題概要を説明すると「めっちゃムズいやつやん」と悲鳴をあげていました。

このあとPCのグラフィックドライバがぶっ飛んだり、雨が強くなったり、暑すぎてメイド服をやめたりといろいろありましたが、結局Bを通すことができませんでした。

まとめ

模擬では良い結果を出せただけに、今回の2完は少し悔しいものとなりました。ぼくとwhesonは今年が最後のICPCでしたが、eliza0xはまだ参加できるので、来年の活躍を楽しみにしつつ消えることとします。

第36回シェル芸勉強会@限界キャンパスサテライトを開催した

この限界のはてに、まだ救いがあると思っている

お前が生まれたこの世界は、お前を救ってくれるとまだ信じている

なんかこんな感じのことをメタルギアで聞いた気がする。

震源+大雨=限界

弊キャンパスは直近の地震震源の真上ぐらいにあったところです。ここにこの間の大雨を合わせるとまさに限界!という感じです

大阪サテライトがこの雨の影響で中止となってしまったため、家に変えることも出来ないぼくはこの限界キャンパスで勝手にサテライトを開催することにしました。

あーたのしい

午前の部

鳥海さんによる文字コードの講義が始まりました。難読化クラスタとしては何かネタが転がっているかもしれないとワクワクしていました。

まずはlocaleiconvのような文字コードなどに関わってきそうなコマンドについてでした。
ずっと「ja_JP.utf8ってなんやねん冗長やなオイ」って思ってたんですが、どういう意味なのか解ることが出来てよかったです。

そのあと基数変換の話題ではbash$((2#bbbb))というパターンで変換できると知り驚きました。これすごい便利

いよいよ文字コードっぽいところに来た時、続きは次回ですとなっりました。えっ次回も参加するしか無い

昼休憩

昼休憩の間に限界サテライトからLTの配信が出来ないかどうか試していました。手伝ってくれた方々ありがとうございました。

限界サテライト側の機材不足で、音声がクリアに拾えないという問題があったため、結局配信は無しということになりました。悔しい・・・

昼飯を食ったあとは完全に体力の限界という感じでした。でも家に帰る手段も無いのでこのまま午後も見ることにしました。あとこれは秘密ですが、気づいたらメイド服を着ていました。

午後の部

とっても楽しい問題の始まりです。今回は時間内に解けた問題が全然ありませんでした。チクショー

因みに問題と解答はここです

問1

welcome.txtというファイルに仕込まれたバイナリを解析して、AAを見つける問題。いきなりヘビー過ぎて泣いた。とりあえずxxdしてみると不思議な模様があったので目を細めて見てみると0x00が紛れていたので、sedしてみました

するとめちゃめちゃなAAが出てきたので、適当にターミナルの横幅を動かしてみると70ぐらいだと解りました

cat welcome.txt | sed 's/\x00/@/g' | fold -70

因みに幅が70だったのは、toiletコマンドの出力の幅が70だったからだそうです。なるほどな〜〜〜〜

問2

フォーマットがめちゃくちゃなファイル名を揃える問題。こういうのはよくありそうだし、できると最高かもしれないですね

これはゴリゴリやればいいなとおもったので、ゴリゴリ。

ls -1|nkf -Z|sed 's/[0-9]/& /g;s/[aA-Z]/ & /g'|sed -r 's/^([0-9]).*([aA-Z])[^組]/\1年\U\2組/g'|sed 's/組組/組/g'|paste <(ls -1) - | xargs -n2 echo "mv" | bash

まずsedで年次と組を分離し、その後またsedしました。ちょっと冗長ですねこれ

因みに、ぼくは全角英数と半角英数が混ざっていると死にます。

問3

2018年の日付のうち2,3,5,7が4つ含まれる日付を列挙する問題。 例えば2018/07/23と言った感じ。
4つあるかどうかgreptrで削ったあとawklengthを見ればいいなと思っていたんですが、日付の列挙がうまく出来なかった・・・

時間内には解けなかったんですが、dateutils.dseqというコマンドがあるよということだったのでそれを使って解いてみました。

dateutils.dseq 2018-01-01 2018-12-31|sed -E 's/[^2357]//g'| paste - <(dateutils.dseq 2018-01-01 2018-12-31)|awk 'length($1)==4{print $2}'

pasteを使えるようになってから、よく使うようになりました。とっても便利ですよねこのコマンド

問4

tanzakuファイルをcatすると・・・

$ cat tanzaku
┏ ーー-┷-ーー┓
┃       ┃
┃       ┃
┃       ┃
┃       ┃
┃       ┃
┃       ┃
┃       ┃
┗ーーーーーー┛

このように表示されるのでこの中に俳句を入れる問題。ゴリゴリでいけそう

字余りするところは全角スペースで埋めてtetayoko。そのあとはsedの後方参照をつかってそれーという感じ。見た目ほど難しくなかった

問5

cowsayコマンドの出力を右向きにする。ただし文章はひっくり返しちゃダメ。
見た瞬間うっとなるのは響け!ユーフォニアム問題に似たものを感じる。

これは最初にrevしたあとsedで行を選択して末尾にスペースを埋め込んでいく戦法を考えました。でもあんまりよくないし何よりもめんどくさいので脳を休めてた。

問6

seq 20のうち素数である番号を○で囲む問題。

1
②
③
468
9
101214
15
161820

こういう感じですね。午前でやったことを活かして行こうと思い。まず②のxxdを見る。ASCIIコードを見つけて、それを基準に差分を足していけばいいのでは?と思ったのでゴリゴリしてみる

seq 20|factor|awk 'NF==2{print $2}'|xargs -I@ echo "echo \$((0xe291a1+@-2))"|bash|bc <(echo "obase=16") |tr '[A-F]' '[a-f]'|sed 's/$/0a/g'|xxd -p -r|paste <(seq 20|factor|awk 'NF==2{print $2}') -|awk '{print "s/^"$1"$/"$2"/g"}'|sed -f- <(seq 20)

前回のシェル芸勉強会で覚えた-f-も使えたので良かった。ちょっと冗長なので、他のシェル芸人さんみたいにスマートなやり方も鍛えていきたい

問7

textというファイルには見えない文字が含まれているらしい。どこにどんなのがあるか調査する問題。

調査するというのが難しかったので、とりあえずどんなのがありそうなのかbatで見る。すると・・・

丸見えになったのでコレで良いのではとなってしまった。この辺でもう脳が死んでたのでこんな解答しか出来なかった・・・

問8

最後はルビをふる問題。シェル芸人からの挑戦状を読んでいたので、sedで送り仮名を削りつつ、ルビのペアを作るのは出来てたけど上につける時のスペースの入れ方がわからなくてダメだった。

column -tでいいよということだったので覚えていきたい。

LTしたかったやつ

都合でいつものパワポテーマで作れなかったんですが。また難読化でLTする予定でした。今回は日夜手で難読化しているシェル芸人さんたちのために難読化コンバータを作りました。Go製です。ぜひ使ってみてください

因みにぼくは使ったことないです

まとめ

シェル芸勉強会はやはりサテライトでみんなで集まってやるのがたのしいですね。一人でサテライト開いても寂しいだけでした。問題が激しかったので寂しがっている暇はありませんでしたが。次回も参加したいなーとおもっています

今回もとても楽しかったです!ありがとうございました!!!

ICPC2018国内模擬に参加しました

参加した

参加しました

ABCEの4完でした。

イカれたメンバー紹介

  • ぼく(@xztaityozx_001)
    • いつもはC#で参加しているヤツ。ICPCには無いので実力が2割しか出せない
    • バグ産みマスター
  • wheson(@wheson)
    • 実質水色の緑。紅茶が好きらしい
    • vimのDockerfile試しておいてって頼んだのにスルーした悪いヤツ
  • eliza0x(@eliza0x)
    • いつもはHaskellで参加してるヤツ。C++に翻弄されるのが好き
    • 構文解析は任せろって言ってた

敬称略します

準備

僕の研究室を会場にすることになったので、PCのセットアップをした。僕以外の二人がUS配列を使う人たちだったので、Fcitxの設定を色々した。
エディターはvimで良いだろうとなったので、設定ファイルをかき集めてシンボリックリンクを貼り直すようなスクリプトでも作っておくか〜と思ったけど、Dockerでいいじゃんとなったのでそっちを用意した。

どのターミナルが誰のvimかわからんみたいになったので、ノード名を変えるとかしたほうが良さそう

直前にプリンターが死んだけど気合で直した。えらい

開始〜A問題ACまで

とりあえず全部印刷して、A,B,Cをざっくり見た。whesonが「Aはやるだけですね」と言ったので自明に実装が早いwhesonにまかせてB,Cをeliza0xと読むことにした。

Cを読んでいたらBNFが見えたので、eliza0xに投げた。ワクワクして「やるだけですね」と言ってた。
Bを読んでいたeliza0xが条件を式にしてくれていたので、ほぼ読んでないけど書けそうになった。

そうこうしているうちにwhesonがAを通した。ここまででだいたい15分だった。

D,Eの考察とCの実装

eliza0xが先にC行けそうなのでやりたいとすごいやる気だったので譲った。その間Dをwhesonと眺めることにした。

各桁にはコレだけ目的の数があるよね〜〜って式を立ててたんですが、ホワイトボードで列挙して数え上げたときと誤差がでて死亡。任意の2つの数字の組み合わせで、小さい順に並べると二進数っぽい増え方するよね〜って言ったりしていたけど、ダメそうだったのでEを先に見ることに。このときeliza0xは半分ぐらいCが出来ていたっぽい

これは失敗だが、3部問題を印刷しなかったので、全員が一度に問題を見れなかった。なので先にwhesonにEを読んでもらった。

whesonが「グラフですね」というのでイヤだなーと思っていたが、条件を聞くと二部グラフの波動を感じたので言った。whesonも少し考えた後、目を大きく見開いてそうですねといっていたので、ほぼ考察終了。このときの彼の顔がまさにピンときたみたいな顔だったので忘れられない。

「ホンマに二部グラフなんか」と思ったので条件を再度精査して、ホワイトボードに書き起こす。そしたら二部グラフ丸出しだったので、そうっぽいということになった。

ライブラリの所有者で実装が完全に頭で出来ていたwhesonがEを書くと言っていたので、僕はBを脳内コーディングして、Cを待つことに。

B,C,Eをバグらせる

この辺は目まぐるしく入れ替わったので、よく覚えていない。

たしか、パーサーはうまく動いているけどどこかが変らしく、eliza0xがCをつまらせていたので一旦、実装の軽いBをやることに。脳内コーディングとeliza0xとのペアプロでそれなりの速度でコードがかけたがやはりどこかがおかしく、プリントアウトしてwhesonと交代した。

ライブラリの写経をしている間に、eliza0xとCの問題文をもう一度よく読み、ほしい答えを読み取る。すると、実装が降ってきたみたいなので交代。この時whesonもどこかをバグらせていたみたいなのでプリントアウトして交代。ここでだいたい2時間経過ぐらい。

怒涛のAC

完全に降りてきていたみたいなのでさっとCをeliza0xが通す。Bも関数の1つがintを返さないと行けないのにboolを返してたという大ポカを修正してちょこっといじれば通ったので、whesonに交代。

Eのバグは写経ミスらしかったので、コーナーケースとかの処理をして、サンプルが通ったのがだいたい終了5分前ぐらい。この間ずっと田中ヒメの過呼吸みたいなやつの真似をしていたんだけど、whesonは気づいてくれなかったし、eliza0xは落ち着いてと言っていたので、やるタイミングを完全に間違えた。

Eを無事ACし、やったぜー!となっていた時は終了2分前だった。

終了後

終了後、弊学から参加していた人々が集まった。みんな口々に感想を言ったり、ここでバグらせたなどを言ったりしていた。あとでランキング?みたいなのを見るとselectedになっていたので素直に嬉しかった。

次は予選本番ですね!!!!!!!!同じ調子でできれば予選突破も夢じゃなさそうなので頑張っていきたい。

今回はコーディング環境周りや、手順、役割配分などで課題も見え、単に座るだけをせずに済んだのでとても良い模擬だった。ちなみに同日のARCは参加TLEしたので、問題すら見ていない・・・・・・(参加したかった)

超・記号オンリー難読化シェル芸の材料について

時代と共にUsageも変わる・・・!

そんなお話

シェル芸botくんにmtコマンドが入った

LANG=Cにもしていただいたみたいなので超・記号オンリー難読化ができる

www.slideshare.net

とっても嬉しい。ありがとうございます。

試してみる

喜び勇んで試しにmtコマンドのUsageを見ようと思ったのでやってみたんですが

思ってた出力と違います。ちなみに期待していたのは以下

$ LANG=C mt --usage
Usage: mt [-?V] [-f DEVICE] [--file=DEVICE] [--rsh-command=COMMAND] [--help]
            [--usage] [--version] operation [count]

なんだこれーと思ったのでとりあえずmtコマンドのバージョンを見てみると

$ mt --version
mt (GNU cpio) 2.12
...

え〜〜〜全然違うなるほど〜。どうやらaptでインストールできるmtは少し古いみたいですね

$ apt search mt-st 
ソート中... 完了
全文検索... 完了  
mt-st/bionic 1.3-1 amd64
  Linux SCSI tape driver aware magnetic tape control (aka mt)

やっぱりバージョンによってmtのUsageが違うんですねー。時代を感じる

GNU CPIOのサイトで公開されているChangeLogを眺めてみると、何回かmtのUsageを変更したゼみたいなことが書いてあります(英語わからん)

GNU CPIO

具体的にどのリリースからUsageが違うのか、配布されてるソースをビルドしてみたりしたんですがわからなかったです(もうちょっと調査するかも)

マナ の色が違う

しかしこのマナではスライドそのままでは 世界樹 を作ることができません。こうした色の違いを 属性 ということにしました

属性 が違うなら混ぜるか変換すればいいので 命の泉マナ から作れる別のコマンドを探し、世界樹 へつなげます

今回選んだのは tset コマンドです。適当に/usr/bin/bin以下から探して目についたのと、響きがなんか可愛かったので選びました。

tset

tsetは変なオプションをつけるとUsageを出力して終了します

$ tset -@
tset: invalid option -- '@'
Usage: tset [options] [terminal]

Options:
  -c          set control characters
  -e ch       erase character
  -I          no initialization strings
  -i ch       interrupt character
  -k ch       kill character
  -m mapping  map identifier to type
  -Q          do not output control key settings
  -q          display term only, do no changes
  -r          display term on stderr
  -s          output TERM set command
  -V          print curses-version
  -w          set window-size

If neither -c/-w are given, both are assumed.

割とたくさん文字が出ますね。mt始動をやめてtset始動に切り替えても行けるかもしれません

ともかく、tsetmtマナ世界樹 が作れそうです

やったね

一応難読化の解説も書いておきます

# mtのUsage
___=$(mt 2>&1)
# tset
____=$(${___:8:1}${___:1:1}${___:4:1}${___:8:1} -@ 2>&1)

# ls --help
echo ${____:10:1}${____:1:1} -${___:28:2}${____:2:1}${____:10:1}${____:15:1}

なんの解説なの?これ

LANG=C問題

この難読化では文字を変数に格納して展開することを繰り返して難読化します。なのでマナや世界樹を作るmt,ls --helpと言ったコマンドの出力は重要です。

今回のバージョンの違いというのもありますが、特に影響するのは言語設定です。翻訳の程度では全く難読化が成り立たなくなることもあります。

じゃあLANG=Cを必須にして難読化の先頭につければいいじゃん?という御仁もいらっしゃることかと思いますが、頑張ってアルファベットを消したのに復活させるのは悔しいのでダメです

なのでこれらの出力の中でもLANGの値に依存しない部分を切り取ったりすることが肝要です。これは実は発案のkanataさんが 命の泉 を作るときにもやっています。僕はコレをやっていなかったので実は超・記号オンリー難読化はできてないと言えます。

現に日本語設定だとmtのUsageは日本語訳され、以下のように出力されます

$ mt
使用法: mt [OPTION...] 操作 []
Try 'mt --help' or 'mt --usage' for more information.

かなり違うのが解ると思います。使える文字種も減っています。

解決していく

しかし、よく見てみれば 世界樹 を得るだけであれば Try...の行さえあれば大丈夫であることがわかります。

なのでkanataさんのやったようにいらない部分を削っていきます。

$ __=$(mt 2>&1)
$ echo $__
使用法: mt [OPTION...] 操作 []
Try 'mt --help' or 'mt --usage' for more information.
$ echo ${__##*]} 

Try 'mt --help' or 'mt --usage' for more information.

いい感じですね。空行が気になりますが、必要な部分だけ記号のみで取り出せそうです。

同様にls --helpの出力も必要な部分だけ取り出すようにしていきます。

$ LANG=C /bin/ls --help|grep -o .|sort -u|grep "[A-Za-z]"|xargs
A B C D E F G H I K L M N O P Q R S T U W X Y Z a b c d e f g h i j k l m n o p q r s t u v w x y z
$ /bin/ls --help|grep -o .|sort -u|grep "[A-Za-z]"|xargs
A B C D E F G H I K L M N O P Q R S T U W X Y Z a b c d e f g h i j k l m n o p q r s t u v w x y z

ん?あれ?一緒なの?日本語にしても得られる文字種は一緒に見えます。これならLANG=Cしなくても良さそうです。少なくとも日本語環境では

しかしホンマかいなと思って発表時に得られなかった文字を探してみました。そしたらjだけが新たに現れていました。しかも両方

なんかおかしいな〜とおもって確認したら

$ type ls
ls is an alias for exa

あ〜〜〜exaに変えてたんだった

github.com

実際jが増えたからと言ってどうせJ,Vが足りないのでブレース展開をするので何でも良いんじゃないかと考える方もいるかと思いますが、世界樹内での文字の位置が変わるため、割と死活問題です・・・

まとめ

今回はmtが作るマナについて少し調査しました。その結果

  • 古いmtと最近のmtじゃUsageが違う(この違いを属性の違いとした)
  • aptで探すと出てくるのは古いほう。
  • 古いUsageだとそのままじゃ世界樹にならない
  • tsetのマナから足りない部品を集める。ただしmtは既に使わなくてもいいレベルで文字が豊富

さらにLANG=Cが必須かもしれない問題についても少し取り組みました

  • やはり環境に依存しない部分だけで難読化するのがよさそう
  • mtの場合は必要な部分だけ切り取ってやればOK
  • つまりLANG=Cはなくても良い
  • ただしツールは合わせること(/bin/ls を指定するとか)

難読化シェル芸。とっても楽しいですね。色んな所で話題になっているようで、これで興味を持ってもらえていたら難読化シェル芸クラスタとしてはとっても嬉しいです。ありがとうございます。

これからもヤベー難読化が見つかることを楽しみにしています。

GoでGoogle Spreadsheetにデータを書き込みたい

面倒なことは機械にやらせよう

こんな記事は死ぬほどあるけど他に書くこともない

動機

研究でめっちゃデータ取ってる。もともとデータの集計も手作業でやる系だったんだけど、この部分はシェルスクリプトとかで自動化してMarkdownの表を生成するまではやってた。しかし報告するときにMarkdownの表は見づらいみたいなことをBOSSと同期に言われたので集めてるデータをGoogle Spreadsheetで管理しようと思った。
今見たらこのMarkdownの表、自分でみてもわかりにくい

要件

書き込みたいデータ

double
int
int
int
int
int
int
int
int
int

先頭が少数、その後に9つの整数が縦に続く。これを書き込みたい。
いろんなパラメータを書く欄があるのでカラムはEから始まる。行は4から。Zまで書き込んだあとはEへ戻って下の行へ移動する。

できれば次の行への移動とかも自動でやってほしい。

使う言語

最近GoをはじめたのでGoでやってみようと思った。SpreadSheetはAPIを公開してて、Go向けにもライブラリがあったのでこれでいいやみたいな

developers.google.comhttps://developers.google.com/sheets/api/quickstart/go

作ってみる

ためす

まずは試す。

qiita.com

この解説を一通りやってみると大体の感覚が解る。ちなみにAPIを試すだけならAPIのリファレンスの各ページからも試せる。API試せるのめっちゃありがたい

リファレンスだと自動入力が効いてるのでRequestのbodyとかの書き方をチェックするのにも使えて最高

メソッドを選ぶ

developers.google.comhttps://developers.google.com/sheets/api/reference/rest/v4/spreadsheets.values/batchUpdate

今回はspreadsheets.values.batchUpdateを選んだUpdateをまとめてできるらしい。今の所1回につき1セットのデータしか書き込まないけど、そのうち拡張するかもしれないのでこっちにしておいた。

bodyをみていると、dataっていうところがあった。data便利な単語だと思う。
それで、data にはValueRange型を好きな数書くといいみたい。ValueRange型についてはリファレンスとか解説記事を見るとわかやすい

qiita.com
developers.google.comhttps://developers.google.com/sheets/api/reference/rest/v4/spreadsheets.values#ValueRange

今回最低限書き込みに必要な情報だけまとめるとこうなった

{
    "valueInputOption": "USER_ENTERED",
    "spreadsheetId": "xxxxxxxxxxxxxxxxxxxxxxxxxx",
    "responses": [
        {
          "range":"E4:E13",
          "majorDimension":"COLUMNS",
          "values":[
                double,
                int,
                int,
                int,
                int,
                int,
                int,
                int,
                int,
                int,
         ],
     },
 ],
}

これをライブラリを使って投げてやればいいだけですね

実装してみる

とりあえずリファレンスのQuickStartをコピペ。かいてあるとおりにやったらAPIにアクセスできるようになった。便利な世の中やでホンマ

ここからはgoを雰囲気でかいているところが散見するのでマサカリが有ったらブンブン投げてほしいところ

変更したところはgetClientを少し変えたぐらい

func getClient(ctx context.Context,credentialFile string) *http.Client {
    b, err := ioutil.ReadFile(credentialFile)
    if err != nil {
        log.Fatalf("Unable to read client secret file: %v", err)
    }

    config, err := google.ConfigFromJSON(b, "https://www.googleapis.com/auth/spreadsheets")
    if err != nil {
        log.Fatalf("Unable to parse client secret file to config: %v", err)
    }
    tokFile := "token.json"
    tok, err := tokenFromFile(tokFile)
    if err != nil {
        tok = getTokenFromWeb(config)
        saveToken(tokFile, tok)
    }
    return config.Client(ctx, tok)
}

contextを受け取れるようにしただけw

次にmain部分をかいていく

func main() {
    spreadsheetId := ""
    ctx := context.Background()
    client := getClient(ctx,"client_secret.json")

    sheetService, err := sheets.New(client)
    if err != nil{
        log.Fatal(err)
    }


    data := []*sheets.ValueRange{
        {
            Range: "E4:E13"
            Values: [][]interface{}{
                0.123,
                1,
                2,
                3,
                4,
                5,
                6,
                7,
                8,
                9,
            },
            MajorDimension: "COLUMNS",
        },
    }

    reqest := &sheets.BatchUpdateValuesRequest{
        ValueInputOption: "USER_ENTERED",
        Data: data,
    }

    res, err := sheetService.Spreadsheets.Values.BatchUpdate(spreadsheetId,reqest).Context(ctx).Do()
    if err != nil{
        log.Fatal(err)
    }
 

    fmt.Printf("%#v\n",res)
}

typescriptをかいてたときも思ったけど。こうやってソースの途中にJSONみたいな記述ができるってのはすごく良いと思う。どう良いかっていうのは説明できない

とりあえずこのままgo runすれば

0.123
1
2
3
4
5
6
7
8
9

みたいなデータがかけるようになったうれしい

もっと自動化する

書き込めて嬉しいけどこれだと書き込みたいデータが変わるごとにソースを更新しないといけない。しかも手作業
ぼくは人間なので手作業をN回すれば絶対1度はミスを犯すのでここも自動にしたいわけです

とりあえずbodyをJSONから読み込めるようにします。

type Body struct {
  Start  int            `json:"Start"`
  End    int            `json:"End"`
  Column string         `json:"Column"`
  Data   []interface{}  `json:"Data"`
}

これはencoding/json パッケージを使えば下みたいなJSONファイルと簡単にやり取りできます

{
  "Start":4,
  "End":13,
  "Column":"E",
  "Data":[
    1,2,3,4,4,5,6,7,8,9
  ]
}

goはこういうところが良い感じですね。すき

リクエストを送るときは書き込みたいデータが既にまとまっているとして、終了時にはリセットしておきます。書き込みたいデータはシェルスクリプトからjqを使って書き込むことにします
つまり

書き込みたいとき

{
  "Start":4,
  "End":13,
  "Column":"E",
  "Data":[
    1,2,3,4,4,5,6,7,8,9
  ]
}

終わるとき。Dataにはjqでデータを書き込むことにします

{
  "Start":4,
  "End":13,
  "Column":"F",
  "Data":[]
}

こうしたいので下みたいに書いてみたよ

func writeNext(b *Body) {
    cur := b.Column
    var next string
    st := b.Start
    ed := b.End

    if cur == "Z" {
        next = "E"
        st = ed + 2
        ed = st + 9
    } else {
        next = string([]byte(cur)[0]+1)
    }
    wd := Body{
        Column: next,
        Data: []interface{}{},
        Start: st,
        End: ed,
    }
    path := "next.json"
    jb, err := json.Marshal(wd)
    if err != nil{
        log.Fatal(err)
    }
    ioutil.WriteFile(path,jb,0644)
}

読み込み側はこうだな

func readNextJson() *Body{
    path := "next.json"
    b, err := ioutil.ReadFile(path)
    if err != nil {
        log.Fatal(err)
    }
    var readData Body
    if err := json.Unmarshal(b,&readData); err != nil{
        log.Fatal(err)
    }
    return &readData
}

こうやって修正したmainがこういう感じになった

func main() {
    spreadsheetId := "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
    ctx := context.Background()
    client := getClient(ctx,"client_secret.json")

    sheetService, err := sheets.New(client)
    if err != nil{
        log.Fatal(err)
    }

    rj := readNextJson()

    data := []*sheets.ValueRange{
        {
            Range: fmt.Sprintf("%s%d:%s%d",rj.Column,rj.Start,rj.Column,rj.End),
            Values: [][]interface{}{
                rj.Data,
            },
            MajorDimension: "COLUMNS",
        },
    }

    reqest := &sheets.BatchUpdateValuesRequest{
        ValueInputOption: "USER_ENTERED",
        Data: data,
    }

    res, err := sheetService.Spreadsheets.Values.BatchUpdate(spreadsheetId,reqest).Context(ctx).Do()
    if err != nil{
        log.Fatal(err)
    }
 

    fmt.Printf("%#v\n",res)

    writeNext(rj)
}

あとは好きなタイミングでこれをgo runすればいいですね。はー楽になった

終わり

Vim向けのGoプラグインが優秀なこともあって、Goはなかなか楽に書けるな〜と思いました。そのうちデータの集計とかもGoにまとめたいですね

Surface3にUbuntu Budgie 17.10をインストールする

windowsしんどいっす

ってsurface3が言ってた

surface3にUbuntu Budgie 17.10をインストールする

2年ほど前に中古でsurface3を買いました。価格は5万円ぐらいだったと思います。
買った時にはすでに尿液晶で、白いUIだと尿まみれでした

最近、強いノートPCを支給され、winマシンは要らなくなったのでsurfaceUbuntuマシンにしようと思っていろいろ迷走したのでその備忘録です
先に行っておくと、なんでうごいてるのかわからないという内容の記事ですので注意です。

SurfaceLinux

www.reddit.com

超有益な情報が集まっているredditがありました。名前も超そのままだ・・・

ざっくりやったこと

  1. Ubuntu 17.10を普通にインストール。しばらく使っていたらWi-Fiが死んだので終了
  2. Ubuntu MATE 17.10をインストール。こんどはSurfaceLinuxのGUIDEに沿ってやってみるも不安定なWi-Fi
  3. Ubuntu Budgie 17.10をインストール。後述のppaで追加できるカスタムカーネルを試そうとしたら16.04までだった。GUIDEを試して再起動すると画面がつかなくなった
  4. LiveUSBつくるのがダルかったのでUbuntu Budgie 17.10をもう一度インストール。GUIDEはすっ飛ばした。なぜか安定しているのでここで終わり

採用したやつ

OSはUbuntu Budgie 17.10を使いました。

ubuntubudgie.org

PlankTilixがデフォでインストールされているとか、何もしなくても黒UIなところとかシンプルで綺麗とかもあるんですが、コイツでしかちゃんと動いてないっていうのもあります。

これの前にUbuntu,Ubuntu MATEを試したんですがダメでした。僕はどちらも17.10をインストールしたんですが、redditにある解決策やGUIDEを試してもうまく動きませんでした。

Budgie 17.10だとインストールした瞬間から安定して動作していました。というわけでそれについてです

LiveUSBを作る

Ubuntu Budgie 17.10のLiveUSBを作ります。作り方は解説記事がたくさんあるのでそちらに任せます。

ubuntubudgie.org

インストールする

LiveUSBからUbuntu Budgieを起動するにはSecureBootをOFFにする必要があります。
BIOSを出すときは、WindowsでShiftキーを押しながら再起動ボタンを押せば楽にいけて便利です

Ubuntu Budgieが起動したらインストールします。今回はWindowsとお別れするのでディスクを削除してインストールしました。
Ubuntuのアップデートを同時にインストールしましたし、MP3とかも一緒にやりました

インストールしたあと

IBus

なんかIBusが死んでいます。このへんのツールにこだわりはないので動きそうなFcitxに乗り換えます。

kledgeb.blogspot.jp

Ubuntu Budgieじゃないとき

やはり普通のPCではないのでいろいろ普通に問題が山積みです。例えばWi-Fiが突然死したり、画面がすごい勢いで明滅します。

www.reddit.com

16.04をインストールする場合は上のリンク先が非常に役に立ちます。ppaを追加してインストールできるkernalが超いい感じらしいです(試せてない)

サスペンドできない

これは解決策がGUIDEに書いてあります。試してないので試したら追記します

バッテリー情報が取得できない

できないです。SurfaceLinux内でも話題に上がっていることの一つでした。どうやらカーネルのバグらしく・・・
106231 – Call-By-Reference-Constant - battery and power adapter not working, MSHW0011 driver needed, even in windows - Surface 3

パッチはできてるみたいで、PRもmergeされたぜ!みたいなこと書いててカーネル4.13に入るかもな!やったー!カスタムカーネル無しで動くわね!って感じだったけど結局revertされたらしい。

ここで配布されているパッチ当てればなおるのかな?英語もパソコンもなんもわからん