scrapbox.io
ユーザースクリプト機能で以下のCSSを読み込ませると……
.page-wrapper{ width:100%; position: absolute; left: 0px; } .col-page-side{ position: absolute; right: 0px; }
嬉しい!!!!
scrapbox.io
ユーザースクリプト機能で以下のCSSを読み込ませると……
.page-wrapper{ width:100%; position: absolute; left: 0px; } .col-page-side{ position: absolute; right: 0px; }
嬉しい!!!!
シリアル接続でコマンドを実行する際は cu
コマンドや screen
コマンドなどでシリアルコンソールに接続して対話的にコマンドを実行することになると思うんですが,しかし「一定周期ごとにシリアルでコマンドを実行して結果を取得したい」みたいなときに対話モードだとだるいわけです.
というわけで expect
の出番です.以下のように expect
コマンドを利用すると非対話的にシリアルにコマンドを流し込むことができます. expect
コマンドについてはこちらを参照されたい:
expect(1) - Linux man page
expect -c " spawn cu -l ${TTY} -s 9600 send \"AT+CGREG=2\\n\" expect \"OK\" send \"AT+CGREG?\\n\" expect \"+CGREG:\" exit 0 "
これは
にあるLACとCIDを取得するATコマンドの例ですが,こうしてやることで非対話的にATコマンドを流し込むことができます.
while : do RESULT="$(expect -c " spawn cu -l ${TTY} -s 9600 send \"AT+CGREG=2\\n\" expect \"OK\" send \"AT+CGREG?\\n\" expect \"+CGREG:\" exit 0 " | grep '^+CGREG:')" PCRE_LAC_CID_PATTERN='"(.+?)",\s*"(.+?)"' LAC="$(echo "$RESULT" | perl -ale "/${PCRE_LAC_CID_PATTERN}/; print \$1")" CID="$(echo "$RESULT" | perl -ale "/${PCRE_LAC_CID_PATTERN}/; print \$2")" echo "{\"LAC\":$LAC, \"CID\":$CID}" sleep 60 done
例えばこうしてやると1分ごとにcell locationが取れて便利.expect
コマンド最高!!!! (しかし難しい)
全く知らなかったのだけれど,C11の新機能として_Generic
という組み込み関数が提供されていた.
Generic selection - cppreference.com
というのをこのブログを見て気づいたんですが,
#include <stdio.h> int main() { char* x = "foo"; printf("Type of x is: %s\n", _Generic(x, char*: "string", int: "int")); return 0; }
これは完全に動くコード (最初よく文章を読んでなくて,大方擬似コードだろうと侮っていたら本当に動いて驚いた).
だいたい分かると思うんですが,上記のコードは char*
の引数が_Generic
に渡されるとstring
という文字列を出力し,int
の引数が与えられるとint
という文字列が出力されるという挙動をします.
しかしこれが「リッチなgenericsか」というとそうではなくて,_Generic
の引数に延々と型とそれに対応するvalueを書いていかなければならないので,どちらかと言うとType Assertionに近いイメージ.JavaのgenericsやC++のTemplateのようにコンパイル時に良い感じに自動解決してくれるような類のものではない.惜しいですね.とはいえ便利ではある.
問題としてはC11なんてモダンなものを使う環境ってあるの……? という部分であるが……
Code sampleとしては以下がわかりやすかった: http://www.robertgamble.net/2012/01/c11-generic-selections.html
CircleCI上でgradleでテストを走らせていると,プロセスが突然死してテストがコケるという事態に見舞われていました.
運が悪いと10連続でfailしたりするなどかなり厳しい状況だったのでCircleCI Supportに泣きついたところ,
JVM_OPTS
を尊重しない_JAVA_OPTIONS
環境変数は優先するので,制限をかけたいときはこれを使うと良いという術を教えてもらったので,それに従ったところテストが完全に安定しました.
diffとしてはたったのこれだけ!
@@ -7,7 +7,7 @@ working_directory: ~/repo environment: - JVM_OPTS: "-Xms2048m -Xmx2048m" + _JAVA_OPTIONS: "-Xms2048m -Xmx2048m" TERM: dumb steps:
事象としてはgradleは JVM_OPTS
を尊重しないため,JVM_OPTS
にいくらヒープ容量の制限を書いてもそれが反映されず,結果的にgradleがメモリを無尽蔵のバカ食いして死んでしまったということのようです.
_JAVA_OPTIONS
はJVMに直接的にパラメータを食わせることができるので,それを用いるとgradleにもヒープ容量の制限を強く課すことができるようです.
本件についてはCircleCIのこのブログが詳しくて良いです: How to Handle Java OOM Errors - CircleCI
しかし効く環境変数と効かない環境変数があるのはなかなか難しいですね……
今時builderライブラリも無いだろという感じですが,書いたのです.
Motivationにも書いているのですが,普通に作ったJavaのbuilderは不完全なインスタンスを作成できる可能性を孕んでいます.注意深くコードを書けば問題ないかもしれませんが,えてして我々 (主語が大きい) はミスを犯しがちです.そしてNPEがやってきて……我々はしぬ.
というわけで今回作ったのがarnoldです.
端的にいうと「必要なすべての要素を取りこぼさないbuilder」であり,「そのジェネレータ (annotation processor)」でもあります.Basic usageにあるように,
import net.moznion.arnold.annotation.ArnoldBuilder; import net.moznion.arnold.annotation.Required; @ArnoldBuilder public class Example { @Required private String foo; @Required private int bar; @Required private double buz; }
というようにclassに @ArnoldBuilder
を付与することでinstantiate対象のclassであることを示し,builderでbuildしたいフィールドについては @Required
を付与することで必要なフィールドであることを示すことができます.そしてプロジェクトをビルド *1 するとAnnotation Processorが走り,builder classが自動生成されます.
自動生成されたbuilderはこのように使うことができます.
Example example = new ExampleBuilder().foo("foo") .bar(42) .buz(2.71828) .build();
このBuilderは分解して書いてみると
ExampleBuilder exampleBuilder = new ExampleBuilder(); ExampleBuilder1 exampleBuilder1 = exampleBuilder.foo("foo"); ExampleBuilder2 exampleBuilder2 = exampleBuilder1.bar(42); ExampleBuilder3 exampleBuilder3 = exampleBuilder2.buz(2.71828); Example example = exampleBuilder3.build();
というふうになっており,つまり
ExampleBuilder
は foo
を受け取って ExampleBuilder1
を返すsetterを提供するExampleBuilder1
は bar
を受け取って ExampleBuilder2
を返すsetterを提供するExampleBuilder2
は buz
を受け取って ExampleBuilder3
を返すsetterを提供するExampleBuilder2
は build()
を提供するというようなコードをAnnotation Processorが一式生成するという挙動となっています.なかなか富豪的ですね.
このように,1つのbuilder (もはやbuilderではない気もしますが) が高々1つの要素を受け取り次のbuilderを返却し,終端のbuilderが build()
して所望のclassのインスタンスをinstanciateする,という仕組みにすることで
build()
を提供し,ようやくbuild対象のインスタンスをinstantiate出来るようになるという安全な挙動を実現しています.
今後の課題としてはprivate classのinstantiateができないというものがあり,これはなんとかしたい *2.
それはそうと今回Javaのコード生成には square/javapoet を使ってみたんですが,使いやすく,なおかつパワフルで良いですね.
現場からは以上です.ぜひご利用下さい.
行ってきて,そして喋りました.
スライドは以下にあります.
Perlコードに別の言語のコードを埋め込んで動かしてしまう技術であるところのInlineモジュールの話です.今回のYAPCのテーマは「万国津梁」とのことだったので「じゃあPerlと他の言語をつなげるInlineモジュールの話でもすればよかろう」と短絡的に題材を選択してしまったわけですが,そのままではなかなか「引っ掛かり」が無い話になってしまったため (出オチみたいな感じになった),色々風呂敷を広げてみました.それはそうとしてnumpyマジで速いですね.それだけ覚えて帰って下さい.
「グルー言語」の部分については碌々調べずにスライドのあるようなことを喋ったわけですが,恐らくこのような点はあるのだろうなと思っています.
かつて言語側で頑張らなければならなかったコンポーネント間の「糊付け」の責務が,HTTPやTCPのような「プロトコル」のレイヤに寄ってきている,あるいは別の見方をするとprotobuf等のIDLやJSONなどのデータ交換のための表現が発達したことによって「言語」のレイヤから更にメタな「表現」のレイヤにコンポーネントを協調させる責務が寄ってきた (寄ってきたというよりも,「表現」がその責務を負えるだけの進化を遂げたと言う方が適切かもしれません) というのがあるのかなと思います.これはいずれか片方にだけ寄っているという意味ではなく,複合的な要因によるものでしょう.もちろんスライドにも書きましたがLLVMのようなコードを変換するような潮流も,パラダイムを変えていった一因だと考えています.
とは言え「グルー言語」というエッセンスが無価値なものになったかと言うとそうではなく,むしろ選択肢が広がったという見方をするのが自然だと思っているところです.
懇親会ではid:nkgt_chkonkさんが,「例えばプリで計算した結果とかをどこかストレージに入れておいて,それをアプリ側で引いてくるっていうシチュエーションでは,ストレージもグルーのひとつだよね」とおっしゃっていて,たしかにそのとおりだなあと思いました.グルーはあまねく遍在している.これ,僕が言ったことになりませんかね?
それはさておき,今回のYAPCも興味深い話がたくさんあり,特に新屋さんのトークとid:akiymさんのトークは大変おもしろく聞かせて頂きました.
新屋さんのトークは平易な言葉を用いて構文解析における曖昧性の解説をされていて大変勉強になりました.4年前に知りたかった…… *1.語り口としてもちゃんと笑わせてくる部分を作って確実に聴衆を引き込んでいくさまは流石ですね.
id:akiymさんのトークはperlの新しくて便利なモジュール紹介100連発という感じで,常に新しい情報を追うというそのアンテナの高さと,積極的にそれを取り込んでいく姿勢には学ぶべきものが多いと思いました.ところで懇親会で酔っ払ってて訊けなかったんですけど,おもにどこで情報集めてるんですか?
というわけで,今回のYAPCはそんな感じでした.運営の皆さん,お疲れ様でした.
次回は東京に戻ってくるということで楽しみですね!
*1:色々なことが当時あった
向かうべき道は色々考えられるが,実際に試してみたのは以下.
1. node_modulesをzipに含めてアップロードする
2. browserifyを使って1つのjsファイルにバンドルする
ローカルでnpm install
(or yarn install
) してこさえたnode_modulesディレクトリをzipにアーカイブしてそれをLambdaにアップロードするという方法.
zipファイルを作るのは地味に面倒に思えますが,Apexを使うとかなり楽にzipファイルの作成とアップロードができます.しかし得てしてzipファイルの容量が大きくなりがちなのでS3経由でデプロイするなどの方法を採る必要があるかもしれません.
また,ネイティブ拡張を利用しているライブラリが含まれている場合だとLambdaの実行環境 (アーキテクチャ) と同一の環境上で npm insall
してnode_modulesを作る必要があるでしょう.
可能な限りnode_modulesの容量を小さくするために npm/yarn install --production
でdevDependenciesを外すというのも良い考えです.
ようこそ地獄へ.
node_modulesをアップロードする方法は容量が大きく,スマートではない……おれはもっと格好良い,小洒落た方法でやりたいんだ……ということでbrowserifyを使って1つのjsファイルに依存をバンドルし,それをアップロードするという方法が思いつくでしょう.
とりあえずLambdaで動くbundled jsを構築するには以下のようにコマンドを実行してやる必要があります.
$ browserify --node --standalone 'your-app-name' index.js -o bundle.js
--node
と --standalone 'your-app-name'
を指定して実行すると,運が良ければ動くjsが生成されます.運が悪いと動かない.動かない時はどうするか? おそらくおとなしく諦めたほうが良いでしょう……人生は短い…… (不毛すぎる)
もちろんネイティブ拡張を利用しているライブラリが含まれている場合だと動かないので,そういうときはnode_modulesをzipにバンドルする手法を採用する必要があります.
あるいはbrowserifyの代わりにwebpackを使うという方法も考えられる.僕はやっていません.