2019年11月28日木曜日

vscode のマクロ定義

いまのところvscode単体ではmacroが使えないようだ。このへんのアンバランスさはなんなんだ。 拡張がいくつも出ていて、とりあえず、これを使ってみている。

まず、標準のsettings.jsonにマクロを定義し、keybindings.jsonでそのマクロを使うようにキーを割り当てるという二段構え。

サンプルを参考に書いたこのマクロは、現在の行を下にコピーして、コメントアウトして、その次の行に行く、というもの

    "macros.list": {
        "commentDown": [
            "editor.action.copyLinesDownAction",
            "editor.action.addCommentLine",
            "cursorLineEnd",
            "cursorRight"
        ]
    }

これをkeybindings.jsonでは

    {
        "key": "ctrl+cmd+/",
        "command": "macros.commentDown"
    }
のようにして参照する。すばらしい。。けど、このくらいデフォルトでついていてほしいなあ。。

2019年10月29日火曜日

docker の中の jupyter

macのdocker内でjupyterを使うときに注意すべきこと

ポートフォワード

コンテナを作るときにポートのフォワードを設定する
docker run -p 8000:8888 --name xxx ubuntu 
とかしておくと、なかの8888で起動したものがそとで8000で使える。

バインドアドレス

jupyter 起動時にデフォルトだと127.0.0.1にバインドに行くが、これをやるとエラーが出る。
  File "/home/xxxx/anaconda3/lib/python3.7/site-packages/tornado/netutil.py", line 174, in bind_sockets
    sock.bind(sockaddr)
OSError: [Errno 99] Cannot assign requested address
これを回避するには --ip をつけて起動する。
jupyter notebook --ip 0.0.0.0
これも面倒なので、config ファイルに書く。
jupyter notebook --generate-config
とやると ~/.jupyter/jupyter_notebook_config.py というファイルができるので、 この中のc.NotebookApp.io を下記のように設定する。
c.NotebookApp.ip = '0.0.0.0'

パスワード

外からつなぐときにトークンをいちいちうつのが面倒なので、 パスワード認証にする。
jupyter notebook password
とやると聞いてくるので、適当に指定する。

2019年10月25日金曜日

karabiner element で'{'で英数モードに切り替える。

ASCIIDOCで、文字置き換えを多用していたら、 { で英数モードに自動的に切り替わってほしくなった。 Karabiner Elementで入力モードに依存したキーコード発生ができるということなので、やってみた。

設定方法

~/.config/karabiner/assets/complex_modifications 以下に設定したJSONファイルを置くと、それがcomplex modifications のなかに出てくるようになる。 このJSONファイルの、trailing comma の扱いが妙にシビアで
["a","b",] 
みたいな物があると、パースに失敗するらしくリストに出てこない。logにもでないので、理由がわかるまでに時間を浪費した。

設定ファイル

こんな感じ。日本語入力モードだったら、cmd-spaceでモードを切り替えてから'{'を入力する。 とりあえず快適。
{
  "title": "for vscode asciidoc",
  "rules": [
    {
      "description": "turn off IME with rbrace",
      "manipulators": [
        {
          "type": "basic",
          "from": {
            "key_code": "open_bracket",
            "modifiers": {
              "mandatory": [
                "left_shift"
              ]
            }
          },
          "to": [
            {
              "key_code": "spacebar",
              "modifiers": [
                "command"
              ]
            },
            {
              "key_code": "open_bracket",
              "modifiers": [
                "shift"
              ]
            }
          ],
          "conditions": [
            {
              "type": "input_source_if",
              "input_sources": [
                {
                  "language": "ja"
                }
              ]
            }
          ]
        }
      ]
    }
  ]
}

2019年10月14日月曜日

Python traitlet

JupyterのWidget に使われている Traitletについてしらべてみた。 ここにある。 要するに、比較的高機能なプロパティをクラスインスタンスに与えるためのパッケージ。高機能というのは
  • 型を制約。別の型の値を代入するとエラーになる。
  • デフォルト値を動的に計算可能にする。
  • 代入時に強制型変換をおこなったり、バリデーションチェックをおこなったりする。
  • 値が変更された際にcallback関数を呼び出す。
  • コンフィギュレーションファイルから値を読み込む。
どうも最後のことがやりたくて作ったんじゃないかという気がする。 使い方のサンプルはこんな感じ。
from traitlets import HasTraits, Integer, observe

class TraitletsExample(HasTraits):
    num = Integer(5, help="a number").tag(config=True)

    @observe('num')
    def _num_changed(self, change):
        print("{name} changed from {old} to {new}".format(**change))
widgetではobserveをあとから呼び出しているが、通常はこうやって関数を登録するようだ。 便利そうだが、おそそうでもある。

jupyter widgetsでコールバック

Jupyter のWidgetはポーリングすれば値がとりだせる。今どきのGUIだと常時更新し続けるのが常らしいので、それだけでもこまらないようなのだけど、それだとあまりにバカっぽい。コールバックができる仕掛けを調べてみた。 ここに書いてある。
slider = widgets.IntSlider()
slider.observe(lambda change: print(change), names='value')

display(slider)
のようにobserveでコールバック関数を登録すればいい。 スライドをいじると下のようなイベントがたくさん飛んでくるのが見える。
{'name': 'value', 'old': 0, 'new': 1, 'owner': IntSlider(value=1), 'type': 'change'}
observenames引数がよくわからないが、これを指定しないと _property_lockというnameのチェンジイベントもたくさん飛んでくるようになる。
{'name': '_property_lock', 'old': {'value': 1}, 'new': {}, 'owner': IntSlider(value=1), 'type': 'change'}
なのでつけておいたほうがいいのだろう。 ドキュメントによるとIPython traitlets というものがイベント周りをなんとかしているようなのだけど、どこをみたら書いてあるんだろう。。ここにあった。。

2019年10月13日日曜日

vscode でターミナルとエディタ間のトグル

vscode ではターミナルが統合されていて便利なのだけど、そことの行き来にマウスを使うのが面倒。ぐぐってみたら こんな記事を発見。すばらしい。 キーボードショートカットとして下のように登録するとCtrl-`で行き来できる。便利だ。
// Toggle between terminal and editor focus
{ "key": "ctrl+`", "command": "workbench.action.terminal.focus"},
{ "key": "ctrl+`", "command": "workbench.action.focusActiveEditorGroup", "when": "terminalFocus"}

2019年6月1日土曜日

macbook で特定のディスプレイで4K出力できなくなった

なにかきっかけがあったのかどうかはわからないのだけど、macbook pro から、職場で愛用しているシャープの4Kテレビに出力できなくなった。 1080p のディスプレイとして認識されてしまい、それ以上の解像度に設定することができない。
  • もう一台のmacbookからは、問題のTVに4K出力できる。
  • 問題のmacbookから別の4Kテレビには出力できる。
  • Display menu のようなツールをつかっても同じ ということで、なにがおこっているのかさっぱりわからない。テレビの型番としては正しく認識できているので、 想像するに、
  • TVから送られてくる情報がなにか腐っている
  • TVから送られてくる情報をどこかでキャッシュしていて、それが腐っている のどちらかのような感じ。

    SMCリセットとPRAMリセットも当然試してみたが、無駄。 ということで諦めかけたのだけど、40インチの1080ディスプレイというのは壮烈に使いにくくて、悲しすぎるので もう少し頑張ってみた。

    いろいろ調べてみたところ こんな記事を見つけた

  • EDID という規格がある。 これはVESAが決めているもので、ディスプレイが受け付けることのできる解像度などを コンピュータ側に送信する規格らしい。
  • Mac OSには
    /System/Library/Displays/Contents/Resources/Overrides
    というディレクトリ があり、ここにEDIDのファイルを適切においておくと、ディスプレイから送ってくる情報をオーバライドできる。 ということがわかった。 とはいえ、ただしいEDIDファイルの作り方もわからないし、ファイル名(ディスプレイの名乗り上の型式名)もわからない。 ということで、先の記事からリンクされているrubyのスクリプトを使ってみた。このスクリプトは色空間のおかしなディスプレイの 色空間を強制的にRGBに戻したEDIDファイルを作ってくれるものなのだけど、その際に接続されているディスプレイの 型番をちゃんと調べてくれる。 もう一つ面倒なのはEDIDファイルのディレクトリは、システムインテグレーションの対象なので普通にはsudo をしても いじることができない。なので、まずシステムインテグレーションを切る必要がある。
    • まずリカバリーモードに入り、システムインテグレーションを切る
      • Command-R を押しながら起動
      • Utility から端末を開く
      • csrutil disable とタイプ
    • 次にrubyのスクリプトを実行するとファイルができる。これであるべきファイル名がわかる。 DisplayVendorID-4d10/DisplayProductID-1100。
    • 同じベンダとのところに別のディスプレイのファイルが置いてあったので、これを複製して、ファイル名を変更
    • リカバリーモードからシステムインテグレーションを復活
    これでなんとか、ちゃんと繋がるようになった。おそらく本当の正解は、ちゃんと動作している別のmacbookのほうで、 EDIDファイルをみつけて、コピーする方法だろうと思うが。。 まあ、とりあえずまた使えるようになってよかった。。
  • 2019年5月17日金曜日

    X11 connection uses different authentication protocol

    ssh -X でログインしてXを手元に飛ばそうとしたら、どうにもうまくいかない。認証周りの問題らしいのだけど、全然わからない。 いろいろ試しているうちに、ssh に -vvvをつけたらリッチなデバッグ情報がでて、一気に解決した。
    X11 connection uses different authentication protocol
    
    これでググったところ、サーバ側に.ssh/rc があると、xauthがサーバ側で動かない、というのが 問題だったらしい。。うーんなるほどわからん。

    教訓はデバッグレベルは最高にするといい、ということだな。-v とかケチケチしてはいけない。

    2019年5月11日土曜日

    itertools product

    複数のリストの直積集合(cartesian product)を作りたい場合がある。 例えば複数の項目に対してそれぞれ選択肢がいくつかある場合に、それらを虱潰しに探索したい、というケース。 個の要な場合Pythonではitertools の product を使う。簡単。 うーん簡単。自分で実装しちゃったよ。結構面倒だったのに。
    In [5]: for a, b, c in itertools.product([1,2,3], ['a', 'b', 'c'], ['x', 'y', 'z']):
       ...:     print(a, b,c)
    1 a x
    1 a y
    1 a z
    1 b x
    1 b y
    1 b z
    1 c x
    1 c y
    1 c z
    2 a x
    2 a y
    2 a z
    2 b x
    2 b y
    2 b z
    2 c x
    2 c y
    2 c z
    3 a x
    3 a y
    3 a z
    3 b x
    3 b y
    3 b z
    3 c x
    3 c y
    3 c z
    
    

    2019年5月10日金曜日

    Python のClosure

    Python では入れ子になった関数では外側の変数が見えるのだけど、そのままだと更新はできない。でもPython3ではnonlocalとして宣言することで更新可能になる。
    >>> def genCounter():
    ...     c = 0
    ...     def inc():
    ...         nonlocal c
    ...         c += 1
    ...         return c
    ...     return inc
    ... 
    >>> c = genCounter()
    >>> c
    <function genCounter.<locals>.inc at 0x10fa58598>
    >>> c()
    1
    >>> c()
    2
    
    面倒くさい。。

    2019年4月22日月曜日

    docker exec ctrl-p 二度押し問題

    dockerでlinuxのテスト環境を作成したのだけど、どうもshellのctrl-pの動作がおかしい。 ぐぐってみたら おなじことに ハマっているひとを見つけた。
    問題は、ctrl-pがデタッチのキーシーケンスのプリフィックスだかららしい。なので、 .docker/config.json に、
      "Detachkeys": "ctrl-[,q"
    
    を追加すると解決。すばらしい。

    2019年4月14日日曜日

    vscodeでtabをctrl-Iで入力する

    vscodeでなぜかctrl-I がtabにならないので。 keybindings.jsonに記述。しかし、なんでUIでできないの??別にいいけど。
    [
        {
            "key": "ctrl-I",
            "command": "tab",
            "when": "editorTextFocus && !editorReadonly && !editorTabMovesFocus"
        },
    ]
    

    vscodeで line space調整

    vscodeではfontサイズは設定のUIで変えられるが、行間が調整できない。 Settingsを開いて右上の"{}"アイコンをクリックするとJSONで直接編集できるようになる。
    "editor.lineHeight": 15,
    
    を追記すれば良い。 便利。

    Siera以降でkeyrepeatをより小さく

    Mac OS Siera以降で標準UIよりもキーリピートを小さくする。以前はKarabinerでできていたのだけど、できなくなったとのこと。 こちら より。
    defaults write -g InitialKeyRepeat -int 10 # normal minimum is 15 (225 ms)
    defaults write -g KeyRepeat -int 1 # normal minimum is 2 (30 ms)
    
    要再起動。面倒。。

    2019年3月20日水曜日

    pycairo で テキスト画像作成

    CairoというライブラリのPython バインドでテキストの画像を作る。 サンプルが少なくてわかりにくかった。。 テキストの描画時のサイズをScaledFontを用いてextentsとしてうけとり、 それを使って位置決めしている。
    > python test.py TEXT FONTSIZE
    
    のように使う。
    import cairo
    import sys
    
    WIDTH, HEIGHT = 256, 64
    text = sys.argv[1]
    fontsize = int(sys.argv[2])
    
    surface = cairo.ImageSurface(cairo.FORMAT_RGB24, WIDTH, HEIGHT)
    ctx = cairo.Context(surface)
    
    ctx.set_source_rgb(1, 1, 1)  # White
    ctx.rectangle(0, 0, WIDTH, HEIGHT) # clear background
    ctx.fill()
    
    ctx.set_source_rgb(0,0,0) # Black 
    ctx.set_font_size(fontsize)
    
    sf = ctx.get_scaled_font()
    extents = sf.text_extents(text)
    ctx.move_to(WIDTH / 2 - extents.width /2, HEIGHT /2 + extents.height / 2)
    ctx.show_text(text)
    
    surface.write_to_png("example.png")
    

    2019年3月1日金曜日

    django のテンプレートだけ使う

    文献リストのHTML生成を以前からdjangoのテンプレートだけ使ってでやっていたのだけど、 Python2 系から 3系にあげて、djangoのバージョンを上げたら動かなくなってしまったので、 再調査して実現。こういうのを技術的負債というのだろう。

    普通djangoはWebフレームワークとして初期化されるのだけど、 テンプレートエンジンだけ使おうとすると、本来通るべき初期化の部分を通らないので、 いろいろ自前でやらなければならない、ということ。

    基本的には、

    • 設定ファイルをpythonコードとして書き
    • それを環境変数 DJANGO_SETTING_MODULE に指定してpythonを起動
    すればいい。

    設定ファイルはこんな感じ。SECRET_KEYは適当に設定しないと文句を言われる。。

    import django
    SECRET_KEY = '01234567890123456789012345678901234567890123456789'
    django.setup()
    
    DEBUG = True
    
    TEMPLATES = [
        {
            'BACKEND': 'django.template.backends.django.DjangoTemplates',
            'APP_DIRS': True,
        },
    ]