秀丸エディタと VSCode(Visual Studio Code) でどこまでアウトライナーできそうかを調べた

総評

  • アウトライナー的に使いたければ、お好きな方で頑張ってみると良い
  • ただし どちらも 1 ペインのアウトライナーは実現できない

要約

  • どちらも 1 ペインのアウトライナーには遠く及ばない
    • 特に 折りたたまれた行を(折りたたまれた状態を維持したまま)移動させることができない のが痛い
  • VSCode が優れているところ
    • level folding をレベル 7 までサポートしている(秀丸は4)
    • Chords などショートカットキーが柔軟に使える
    • ただのインデントされたテキストなど「特定のファイルタイプでなくても」折りたためる
  • 秀丸エディタが優れているところ
    • 独自単位を設定するのが用意(アウトライン解析を自力でつくる)
    • 前後の単位に移動する操作がある(「見出し」単位になるが)

比較

  • Y キーボードショートカット一発で可能
  • y 一部制約がある
  • - 未サポート
カテゴリ 機能 Hidemaru VSCode 備考
folding 現在行の配下を fold Y Y
folding 現在行の配下を unfold Y Y
folding 現在行の配下を toggle fold Y Y
folding ファイル内のレベル n 以下すべてを fold y Y 秀丸はレベル4まで
folding ファイル内のレベル n 以下すべてを unfold y Y 秀丸はレベル4まで
folding ファイル内のレベル n 以下すべてを toggle fold - -
folding すべて を fold Y Y
folding すべて を unfold Y Y
folding すべて を toggle fold - -
cursor 一つ上/下の単位に移動 Y y VSCodeは ctrl+shift+o による一覧からの移動になる
swap 現在行を配下ごと一つ上/下に移動 Y -
swap 現在行を配下ごと一つ上/下に移動した後、折りたたみが保持される - -
swap 折りたたまれた行をコピペ後、折りたたみが保持される y 秀丸は直接的な操作を用意してない
leveling 現在行を配下ごと一つレベルを上げる/下げる y y unfold 状態で全選択する必要あり
focusing Focus - -
customize 独自単位の作成 Y y VSCodeは拡張機能開発が必要でハードルが非常に高い

その他関連情報

Zoom クライアントでミーティング中に Alt + Left を押すと Zoom ウィンドウが勝手にアクティブになるのを防ぐ

ようやく解決策がわかった。長かった。

AutoHotkey 使ってる場合にたぶん起きます。

事象

Zoom ミーティング中に Alt + Left を押すと、なぜか Zoom ミーティングウィンドウがアクティブになりやがる。

発生原因

以下二つを満たしている場合

  • Zoom クライアントのグローバルショートカットが働いている(これは全員当てはまるはず)
    • 「フォーカスをZoomミーティングコントロールに変更」が、
    • デフォでは Ctrl + Alt + Shift にアサインされてて、
    • これが グローバルショートカット有効 になっている
  • AutoHotkey で Alt + Left に「次のタブ(Ctrl + Shift + Tab)」を充てている

AutoHotkey の設定例はこう。

; next tab/prev tab
!Left::Send {Ctrl down}{Shift down}{Tab}{Ctrl up}{Shift up}

この時、以下のようなからくりで事象が発生する。

  • Alt + Left を押す(ここで Alt が押されてる)
  • AutoHotkey により、Ctrl + Shift + Tab が押される(ここで Ctrl と Shift が押される)
  • 結果として Ctrl + Alt + Shift を押したことになる

回避方法

Zoom クライアントの設定 > キーボードショートカットから、デフォの Ctrl + Alt + Shift を別のアサインにする。

たとえば Ctrl + Alt + Shift + Z にする。

その後、いったん Zoom クライアントを再起動。

おわりに

これで Zoom ミーティング中も Alt + Left が使えるようになった。

私は普段、エディタやブラウザで複数タブを開いてて、Alt + Left によるタブ切り替えを頻繁に行うので、この問題は地味に不便だったのだ。ようやく解決。快適。

p.s. 設定がなぜか保存されずデフォに戻される場合は Zoom クライアントで設定が保存されない(デフォルトに戻される)ことがある件 - stamemo も参照のこと。

Zoom クライアントで設定が保存されない(デフォルトに戻される)ことがある件

僕みたいに「必要な時だけ Zoom クライアントを立ち上げる」使い方をしている場合に遭遇しやすい。

先に結論を言うと、Zoom クライアント起動直後、しばらく待ってから設定画面を開かないとダメ ということだった。

設定が保存されない現象はいつ起きる?

手順で見てみる。以下の ★ 部分に注目してほしい。

  • 1: Zoom クライアントを起動する
  • <ここで Zoom.exe(メインプロセス) が起動してウィンドウが出る>
  • <★ここで設定画面を開いたら設定がデフォに戻る>
  • <しばらくすると>
  • <Zoom.exe --action=preload(設定ロード用のプロセス?) が起動する>
  • 2: 設定画面を開く

つまり バックグラウンドで密かに立ち上がる「Zoom.exe --action=preload プロセス」が立ち上がるまでは設定画面を開くな ということだ。

待ち時間はどのくらい?

では Zoom.exe --action=preload が立ち上がる時間はどのくらいか。

体感的だし環境次第だろうが 10秒待てば間違いない 感じ。

ウィンドウが出て、全部表示が表示されきって、明らかに「準備完了!」となってから数秒置く……くらいだろうか。

不安なら、下記に従い、何秒くらいで立ち上がるか確認すると良いだろう。

この現象を確かめたい場合

Process Explorer、タスクマネージャなどで Zoom.exe プロセスの存在を見てみると良い。以下のように「名前順で並べる」「コマンドライン列を出す」とわかりやすい。

f:id:stakiran:20191122072601j:plain

Zoom クライアント起動直後は Zoom.exe 一つしかないが、しばらくすると Zoom.exe --action=preload が立ち上がってくる様子が見えるはず。

おわりに

この仕様何なん??

Zoom クライアントでミーティングのチャットログを保存したかったので調べた

やりたいのは「指定したフォルダに保存する」ことと「チャットログを常に自動で保存する」こと。

あと「どんな形式で保存されるか」も確認しておきたい。

前提

  • Zoom Meeting 無料プラン(Basicプラン)
  • Zoom Client バージョン: 4.5.6 (5666.1020)

設定内容

保存場所の変更

  • Zoom クライアント起動してログイン
  • 右上のアバターアイコン > 設定
  • レコーディングしています > 場所 を変更
    • デフォは %userprofile%\Documents\zoom

チャットログを常に保存させる

デフォルトでは手動でいちいち「…」ボタンクリック > チャットの保存、から保存しなきゃいけない。

  • Web 版の Zoom にログインする
    • a) Zoom クライアント > 右上のアバターアイコン > 自分の画像を変更(自分のプロファイル)、から開くのが早いか
    • b) a がダメなら https://zoom.us/profile/ ここからログイン
  • 設定 > ミーティングタブ > ミーティングにて(基本) > チャット自動保存

チャットログの保存のされ方

レコーディング場所に以下フォルダがつくられる。

  • yyyy-mm-dd hh.mm.ss (あなたの名前)の(ミーティング名) (MeetingID)

この中に以下チャットログファイルがつくられる。

  • meeting_saved_chat.txt

meeting_saved_chat.txt のフォーマットはこう。遅い時刻ほど下に append されていく。

HH:MM:SS  開始 (ユーザー名) : (ここに発言内容)
(ここに発言内容 ← 複数行の場合)
……
HH:MM:SS     開始 (ユーザー名) : (ここに発言内容)
(ここに発言内容 ← 複数行の場合)
……
HH:MM:SS     開始 (ユーザー名) : (ここに発言内容)
(ここに発言内容 ← 複数行の場合)
……

Firefox の about:xxxx を一通り眺めてみて、めぼしいものをまとめてみた

Firefox の about:config は有名だが、config 以外にも色々あるらしい。

最近 about:about で「about:xxxx のリンク集」を表示できることを知ったので、めぼしいものがないか探してみた。独断と偏見で使えそうな about:xxxx をリストアップする。

全般

  • 拡張機能によるマウスジェスチャーが効かない(戻るとか)ので、素直に BackSpace で戻る
  • 『クエリー文字列が必要なページはリストから省かれています』らしいです

about:addons

アドオン管理画面。

about:config

設定画面。たぶん一番有名。

about:downloads

ダウンロード履歴。

見慣れたのはポップアップ画面だが、この about:download ではタブ一つ分で広々と表示する。

about:home

ホーム画面に飛ぶ。

about:memory

メモリ操作ダッシュボード的なもの。

個人的には「GC」ボタンはよく使ってる。これ押したら使ってないメモリが一部解放されるので、メモリがシビアな状況下だと常に開いといてこまめに叩く。

about:newtab

新しいタブを開く。

……だけど Ctrl + T で良くない?

about:performance

タブ毎、アドオン毎のメモリ使用量と消費電力を表示。

資源食ってるやつがわかる。

about:preferences

設定画面。

about:privatebrowsing

プライベートブラウジングモードかどうかを表示する画面。

この画面から新たにプライベートブラウジングを始めることもできる。

about:profiles

プロファイルデータの一覧。

特に「今開いてる Firefox はどのプロファイル使ってる?」を知るのに便利。他、データの保存場所とかも表示されてるし、何ならここから名前変更したり削除したりもできる。

つまり firefox.exe -p でプロファイルマネージャ開かなくても大体ここからできるって感じか?

about:robots

謎。誰か教えて下さい。

about:support

トラブルシュート用情報表示。

環境情報表示としても使えそうか。

about:welcome

ようこそ画面。

おわりに

前々からずっと気になっていたが、ようやく一通り調査できた。満足。

AWS CloudFormation で一つのテンプレートから n 個の環境を一気につくる

一つのテンプレートからパラメーターだけ変えて n 個の環境をつくりたい、という場合、手作業で一つずつスタックをつくるのはしんどい。一気につくれる方法があったのでまとめる。

サマリー

作り方

  • 1: ベースとなるテンプレを S3 にアップ
  • 2: AWS::CloudFormation::Stack リソースを定義する
    • Parameter と TemplateURL を与える感じ

つまり AWS::CloudFormation::Stack は「このテンプレにこのパラメーターを与えてスタックつくれ」というリソースになる。仮に n 個分の環境がつくりたいなら、このリソースの定義を n 個分書き並べればいい

所感

  • めちゃくちゃ楽できる
    • 仮に 50 個の SecurityGroup を作る場合
    • 手作業なら 1H はかかる
    • この方法なら数分でつくれる(最初に n 個の定義を並べたテンプレを作る必要はあるが)
  • n 個定義を手作業コピペでつくるのがだるいならプログラミングで頑張る
    • 複数行文字列と書式指定が使える扱える言語が良い
    • 私は Python 使った

スクリプト例

ここではテストとして VPC の中に SecurityGroup をつくるだけのテンプレを用意し、これを使って n 個の SecurityGroup を一気につくろうとしている。各 SecurityGroup は Name タグで区別する。

こんな感じ。

  • a) あらかじめ VPC を一つつくっておく
  • b) ベースとなるテンプレ → SecurityGroup を一つつくるテンプレ
  • c) n 個つくるテンプレ → b) をベースにした定義を n 個並べたテンプレ

c) は以下のようなイメージになる。

Parameters:
  VpcId:
    Description: VPC ID
    Default: vpc-XXXXXXXXXXXXXXXXX
    Type: String
  TemplateURL:
    Description: base template URL.
    Default: https://s3.amazonaws.com/(TEMPLATE-URL)
    Type: String

Resources:
  Stack01:
    Type: AWS::CloudFormation::Stack
    Properties:
      TemplateURL: !Ref TemplateURL
      Parameters:
        VpcId: !Ref VpcId
        NameTagSuffix: "01"

  Stack02:
    Type: AWS::CloudFormation::Stack
    Properties:
      TemplateURL: !Ref TemplateURL
      Parameters:
        VpcId: !Ref VpcId
        NameTagSuffix: "02"

  # ...

用語

ルートスタック

管理コンソール上から作成したスタック。大元のスタック。

上記で言えば c)。

ネストされたスタック

AWS::CloudFormation::Stack でつくられたスタックのこと。

上記で言えば Stack01, Stack02 ……。

運用時の注意点

  • スタック更新時は常にルートスタックから行うようにする
    • 上記で言えば c) のテンプレートを修正してから再アップする

参考

AWS CloudFormation のクロススタック参照(Output Export と Fn::ImportValue)のメリットと設定方法

クロススタック参照というものがよくわからない。普通に Parameters から指定して参照させるだけではダメなの?……というわけで調べてみた。いくつかメリットがあるみたいだ。

メリット

削除保護ができる

スタック B がスタック A に依存している(A がエクスポートしたものを B から参照している)場合、スタック A を管理コンソール上から削除しようとしても削除されない

B ---> A
       ^^
       こっちを先に削除すると……?
       → 「いや B が参照してますよ」と怒ってくれる

管理コンソール上では以下のようなメッセージが出る。

CREATE_COMPLETE Export export-environment-xxxx-vpcid cannot be deleted as it is in use by (スタック B のスタック名)

より詳しく言えば(削除すると普通は DELETE PROGRESS になるところを、それがキャンセルされる、でもそれだけだと見た目わからんから再び)CREATE COMPLETE と表示している……という感じ。

Parameters を介さずに参照できる

スタック A でつくった環境にスタック B でリソースを注入したい(A のサブネットに B で定義したインスタンスをつくる等)場合、A のどのリソースに注入するかは Parameters から指定させるのが普通(たぶん)だと思う。

しかしクロススタック参照を使えば、エクスポートした名前をお互いに使うだけで渡せる。いちいちパラメーターを指定する画面を介さなくて良い。

書き方

参照される側、する側両方のテンプレに修正が必要。

1: 参照される側のリソースを Output Export する

肝心部分は Outputs.XXXX.Export.Name に「エクスポートしたい名前」を指定する ところ。

続く Import では、この名前をそのまま指定することになる。

Outputs:
  VpcId:
    Value: !Ref VPC
    Export:
      Name: "export-environment-xxxx-vpcid"

Resources:
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      InstanceTenancy: default
      CidrBlock: 10.192.0.0/16

2: 参照する側のリソースから ImportValue する

Export されてる名前をそのまま指定する。

この例では 1 でエクスポートしてる VPC export-environment-xxxx-vpcid を参照したいので、これを Import する。

Resources:
  SecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties: 
      GroupDescription: "Dummy security group to test cross stack."
      SecurityGroupIngress:
      - CidrIp: 0.0.0.0/0
        FromPort: 22
        ToPort: 22
        IpProtocol: tcp
      VpcId: !ImportValue "export-environment-xxxx-vpcid"

参考

AWS CloudFormation で UserData を用いて Linux インスタンスを構築する際の TIPS

テンプレートの例、挙動、TIPS などを雑多にまとめた。

前提

  • Lin インスタンスは RHEL

テンプレート

Resources:
  Instance1:
    Type: AWS::EC2::Instance
    Properties: 
      ……
      UserData: !Base64
        Fn::Sub: |
          #!/bin/bash -xe

          # ★ここに ShellScript を書く

          # 制約
          # - root ユーザーで実行される(sudo 不要)
          # - インタラクティブは受け付けない
          #   X) yum install unzip
          #   O) yes | yum install unzip

          # 変数の書き方
          # - CloudFormation系は ${} で囲む
          #     !Ref Vpc1 → ${Vpc1}
          #     ${AWS::Region}
          # - ShellScript の変数は ${!VarName} のように ! でエスケープ
          #     target_vpc="`cat vpc-id.txt`"
          #     aws ec2 describe-instances --filters "Name=vpc-id,Values=${!target_vpc}" ...

          # デバッグ
          # - 動作ログは以下みたいだが, メタ情報すぎて役に立たない
          #   /var/log/cloud-init.log
          # - UserData に書いたスクリは以下に保存されてる
          #   /var/lib/cloud/instances/(instance-id)/user-data.txt

ドキュメント

挙動

UserData に書いたスクリはいつ実行されるか?

Ans: CREATE COMPLETE から少しタイムラグがある

  • 1: 管理コンソール上で Lin インスタンスが CREATE COMPLETE した
  • 2: Lin インスタンスに SSH ログインできるようになった
  • 3: UserData に書いたスクリが実行された

1, 2, 3 は同時ではなく この順番で実行にタイムラグがある。感覚では 1 の後に 2 が可能になるまで数十秒、2 の後に 3 が実行されるまでに 10 秒。

なので素早く操作してると「あれ?UserData実行されてないんじゃん?」 → 「あ、実行されてた」なんてことになってちょっと焦る。

UserData に書いたスクリが実行失敗したらステータスはどうなる?

Ans: CREATE COMPLETE のまま。

管理コンソール上からは UserData スクリの実行成否は見えない

たぶんだけど、そもそもレイヤーが違う感じ。以下のようになってる?

  • Lin インスタンスが生成されたら CREATE COMPLETE
  • その後で、
  • UserData を走らせる
    • この結果は管理コンソールには出さないよ

UserData 部分を編集して再アップ(スタック更新)したら再実行どうなる?

Ans: されません。

リファレンス AWS::EC2::Instance - AWS CloudFormation によると、

Update requires: Some interruptions

とある。Some interruptions(中断を伴わない更新)とは リソースの使用を中断することなく、またリソースの物理 ID を変更することなく、リソースを更新する もの。一方で、UserData は「新しくインスタンスをつくるときに一度だけ実行される」もの。

よって再実行はされない。

※リソース更新として何が更新されるかはよくわからん。 /var/lib/cloud/instances/(instance-id)/user-data.txt あたりが置き換わったりしてる?

TIPS - 書き方

あらかじめつくっといたスクリを実行させたいのですが?

Ans: どっかにアップしたものをゲットしてくる。

たとえば S3 にアップしておいて、curl で取ってくるとか。

curl "https://(BucketName).s3-(RegionName).amazonaws.com/(UploadedScriptName).sh" -o "(YourFavoriteName).sh"
chmod 775 (YourFavoriteName).sh
./(YourFavoriteName).sh

ただし S3 のアクセス権が面倒か。適切にアクセス権つけて IAM つける必要がある。

私は今回はちょっとしたお試しだったので以下のようにした。

  • スクリプトは全部パブリックにする
  • バケットは……
    • 使うときはパブリックにする
    • 使わないときはパブリックを全部切る

ガバガバなので好ましくはない。たとえば URL がばれたら誰でも見れちゃうし、悪意ある人が DDoS で get を仕掛けたら(たとえば何百万回とダウンロードするとか)課金地獄になってしまうかもしれない。

AWS CLI をセットアップしたいのですが?

Ans: 愚直に。

AWS_REGION="ap-northeast-1"
curl "https://bootstrap.pypa.io/get-pip.py" -o "get-pip.py"
python get-pip.py
pip install awscli
aws configure set region ${AWS_REGION}

自身が所属する VPC の ID など AWS リソース情報がほしいのですが?

Ans: AWS CLI の describes 系コマンドで頑張る。

たとえば以下は「指定タグがついた VPC」の ID を表示する。

$ aws ec2 describe-vpcs --filters "Name=tag-key,Values=${TagKeyForMyParentVpc}" --query "Vpcs[].VpcId[]"
[
    "vpc-XXXXXXXXXXXXXXXXX"
]

上記をもう少し詳しく言うと、TagKeyForMyParentVpc タグのついた VPC 情報 response を引っ張ってきて、その response.vpcs.0.VpcId を見ている。クエリは --query "Vpcs[].VpcId でも良いかも?

ちなみに上記は jq でパースすれば楽に取り出せる。

$ aws ec2 describe-vpcs --filters "Name=tag-key,Values=${TagKeyForMyParentVpc}" --query "Vpcs[].VpcId[]" | jq -r .[0]
vpc-XXXXXXXXXXXXXXXXX

参考: describe-vpcs — AWS CLI 1.16.281 Command Reference

JSON をパースしたいのですが?

Ans: jq を使う。RHEL ではパッケージがないので自力でバイナリを get してきて配置する。

yes | yum install wget
wget -O jq https://github.com/stedolan/jq/releases/download/jq-1.6/jq-linux64
chmod 775 ./jq
cp jq /usr/bin

参考: How to install jq on RHEL6.5 - Server Fault

TIPS - UserData を素早く試行するには?

まず ShellScript 部分はインスタンス上で一通り動作確認まで持っていく。問題はその後、UserData に書き写してから動作成功に持っていくところだろう。

やり方1: 全部入りテンプレ

愚直に行くと「インスタンス」と「インスタンスに必要な VPC やら IAM やら」を全部つくるテンプレに UserData を書いてスタック作成することになる。仮に 全部入りテンプレ と呼ぼう。

全部入りテンプレは言うまでもなく時間がかかる。最小構成でも VPC x1、Subnet x1~2、RouteTable x1~2、InternetGateway x1、NAT x1、SecurityGroup x1、Instance x1 くらいはつくると思う。この規模だと スタック作成に 5 分、削除にも 5 分くらいかかる感触。つまり一度の試行で 10 分くらいかかる。

なのでもう少し楽をする。

やり方3: 注入テンプレ

注入テンプレ と名付けた方法を使う。といっても、単純で、

  • 1: 「インスタンスに必要な環境をつくるテンプレ A 」で環境をつくる
  • 2: 「A の環境にインスタンスをつくるテンプレ B」でインスタンスをつくる
  • 試行するときは B だけをスタック作成&削除する

こうする。これなら全部入り(A+B)とは違い、インスタンス(B)だけが作成&削除の対象になる。作成に 1 分、削除に 1 分くらいで済む

※IAM もつくっちゃうと 2 分くらいなるけど……

ちなみにインスタンス作成時には「サブネットの ID」が必要なので、以下のようにすると良いか。

  • テンプレ A の Output で、サブネットの ID を表示する
  • テンプレ B には「テンプレ A のサブネット ID」を受け付けるパラメーターを設置する

おわりに

サーバー設定の自動化として UserData を使う方法についてまとめた。AWS リソースと比べるとトライアルアンドエラーしづらいが、このレイヤーも自動化したいなら頑張るしかない。少しずつ頑張っていくとしよう。

他にも AWS::CloudFormation::Init などの手段があるみたいなので追々試したい。

Clibor のウィンドウをアクティブにするだけでインクリメンタルサーチできるようにする

デフォルトだと Tab キーを押さないとインクリメンタルサーチモードにならないので、押さなくても済むようにする。

AutoHotkey を使う。

(2019/11/22 追記) スリープ入れても上手く動作しないことがある。どうも(Tab キーが転送されたりされなかったりして)不安定。微妙なので物好きな方だけ試してください。

AutoHotkey スクリプト

;Clibor
#IfWinActive ahk_class TFrm_Clibor
Sleep 300
Send {Tab}
#IfWinActive

解説

上記は「Clibor ウィンドウがアクティブになったら Tab キーを転送する」設定になる。

Sleep 300 は「0.3秒待つ」の意味。Clibor はウィンドウアクティブ直後に Tab キーを受け付けないことがある ので、少しだけ待たないと上手くいかない(ことがある)。ここではとりあえず「0.3秒くらい待てば大体大丈夫だろう」としている。実際、私の環境ではほぼ問題なく動く。

うまく動作しないなら、この値を増やしてみると良いかも。

Markdown to PDF が簡単にできるらしい md-to-pdf を試した

確かに楽だ。コマンド一発で hoge.md を hoge.pdf にできる。日本語もバッチリ。以前紹介した Prince よりもラクチン。

前提

  • Windows 10

インストール

npm install で一発。ただ依存ライブラリ(chromium)が 100MB 超なので貧弱回線だと辛いかも。

$ npm install -g md-to-pdf

使い方

Markdown 置いてるディレクトリに移動して md-to-pdf を実行するだけ。

今回は readme.md を置いたディレクトリで試す。

こんな感じで生成された。

$ md-to-pdf
  √ generating PDF from readme.md

$ dir /b
...
readme.md
readme.pdf

PDF の出来

OK:

  • 日本語の記述(文字化けとかしてないこと)
  • 画像
  • 外部リンク
  • コードハイライト
    • .py は文字列リテラルとキーワードが最低限
    • .bat はハイライトされず

NG

  • ローカルファイルを指す相対リンク
    • http://localhost:XXXXX/(Filename).(Ext) ← こんなリンクになった
    • ポート番号はたぶん空いてるのが使われる?

所感

自宅で文章を印刷したい場合に使えそう。

プリンタ持ってない勢の私はコンビニ利用なのだが、コンビニ機は Markdown に対応してない(PDF や Word のみ)。でも md-to-pdf を使えば Markdown から一発で PDF つくれる

このツールにありがちな「日本語が文字化けして話にならない」もなさそうだし。

※ちなみに以前は結構苦労した → テキストファイルをコンビニで印刷するために markdown to pdf する - stamemo

トラブルシュート

Q: なんかファイアウォールの許可ダイアログが出たんだけど?

Ans: どう対処したか覚えてないけど、もしブロックされてたら解除したら良いかも。

この辺うろ覚え。たぶんダイアログをそのまま閉じたら「node.exe は全部ブロック!」的な設定になっちゃう。それで md-to-pdf も実行が終わらなくなる可能性がある。

もしそうなら以下対応を。

  • 1: firewall.cpl を実行する
  • 2: 詳細設定リンクから「セキュリティが強化された Windows Defender ファイアウォール」を開く
  • 3: 受信の規則から「Node.js: Server-side JavaScript」の設定を探す
  • 4: 3 がブロックになってたら無効にしておく
    • 私の場合 TCP と UDP で計二項目あった

Q: 生成時間に結構時間かかるくない?

Ans: かかるかも。

node.js はただでさえ遅いし、なんか通信も走らせてるみたいなので。

今回の例、3000 文字、10 リンク、3 画像くらいの readme.md ファイル一つだが 10 秒はかかってる。

Q: 細かいレイアウトや整形はできない?

Ans: できそうだが試してない。

詳しくは以下を。

秀丸エディタで現在開いてるファイルを一時保存&あとで復旧するマクロ

普段秀丸エディタで多数のファイル(タブ)を開いているが、作業によってこれら「開いているファイルたち(セット)」がごっそりと変わる。一般的に作業 A のセットと作業 B のセットは大きく異なると思う。これらを簡単に切り替えられるようにしたい。

方法は色々ありそうだが、とりあえず 現在のセットを一時保存しておいて、後で呼び出す という簡単なケースを考え、形にしてみた。

使い方

  • 1: 下記マクロを導入する
  • 2: 下記マクロを実行する

実行するとメニューが表示される。Save で保存、Load で読込。Edit this はプログラミング用。

なお Save 時は「そのマクロファイルがあるフォルダ」に desktop.hmdesk が生成される。これは秀丸エディタの仕組みで、「デスクトップ保存」機能で保存した時の実体。Load 時はこれを読み込んでいる。

マクロスクリプト

menu_desktop.mac

// (2019/11/06 18:58:54 追記) directory → currentmacrodirectory に修正しました。
// directory だと「今秀丸エディタで開いてるファイル」のパスに保存されちゃう……
$hmdesk_path = currentmacrodirectory+ "\\desktop.hmdesk";

$items[0] = "Save";
$items[1] = "Load";
$items[2] = "Edit this";
mousemenuarray $items, 3;
if(result==0){
    endmacro;
}
#selected_idx = result-1;
if(#selected_idx==0){
    savedesktop $hmdesk_path;
    endmacro;
}
if(#selected_idx==1){
    restoredesktop $hmdesk_path;
    endmacro;
}
$path = hidemarudir+"\\hidemaru.exe " + currentmacrofilename;
run $path;
endmacro;

解説

実践的な秀丸マクロ講座……というと言い過ぎだが、ちょっと詳しく書いてみる。

ファイル名やファイルパスなど

  • 使うファイルは desktop.hmdesk
    • directory ← このマクロファイルがあるフォルダパス
  • 手軽にいじれるよう、Edit this を選ぶと「このマクロファイル自身を秀丸エディタで開く」ようにしてある
    • hidemarudir+"\\hidemaru.exe ← 秀丸エディタのフルパス
    • currentmacrofilename ← このマクロファイルのフルパス

たとえば c:\data\hidemaru\macro\menu_desktop.mac だとしたらこうなる。

  • diretoryc:\data\hidemaru\macro
  • currentmacrofilenamec:\data\hidemaru\macro\menu_desktop.mac

慣れないとわかりづらいが「どの環境の秀丸エディタ」でも汎用的に動くようなマクロにしたいなら、こういう書き方を心がける必要がある。

メニュー系

  • mousemenuarray でメニューをつくってる
    • menuarray ← キャレット位置にメニューを表示
    • mousemenuarray ← マウスカーソル位置にメニューを表示
    • 今回は(私の好みで)ツールバーからの起動を前提としているので mousemenuarray にしている

メニュー UI は「この中から選んだ項目を実行するよ」という手軽さがあるので、習得すると便利。

書き方は煩雑だが、

  • 0番目から n-1 番目までの項目をつくって、
  • menuarray で n 個分つくるよと指定して、

で、あとは

  • 「どの項目が選択されたら」の条件分岐を result の値で見ている

という感じ。

デスクトップ保存系

  • savedesktop で、指定ファイル名で「現在開いてる状態を保存」
  • restoredesktop で、指定ファイルを読み込んで復元

Slack ワークフロービルダーで匿名フォームを実現する

従来 Slack で匿名フォームを実現するには Google スプレッドシートだの Bot だの必要だったが、ワークフロービルダーを使えばこれ単体で実現できるっぽい。

実現可否

Ans: 可能

アクションメニューを用いて、以下のステップからなるワークフローをつくれば可能。

  • 1: 「フォームを作成」ステップ
    • 提出された回答をチャンネルまたは DM で他のメンバーに送信する、は チェックしない
  • 2: 「メッセージを送信」ステップ
    • メッセージのテキストを変数「送信元: XXXX」をする
    • これで 1 の内容をそのまま送信できる

1 の「フォームを作成」ステップでチェックを入れると出所(~~さんが送信しました)が出てしまうが、上記のように 「メッセージを送信」ステップをはさむ と出ない。

匿名性の担保について

Ans: 誰かが 名前が表示されるようにワークフローをこっそり修正したら 匿名性は崩れる

ワークフローを修正できるのはコラボレーターのみ。

  • デフォはワークフロー作成者のみ
  • ワークスペースの管理者 or オーナーは 自分自身をコラボレーターにできる
    • ただしこれを行うと全員に通知が行くらしい

参考: ワークフロービルダーのアクセスと権限を管理する - Slack

匿名性に関する疑問

Q: HTML にこっそり送信者名が埋め込まれてたりしない?

Ans: F12 ツールで覗いてみたが見当たらなかったので、たぶん大丈夫。

Q: ワークフロービルダーに実行履歴的なの記録されてない?

Ans: されてないと思う。当該画面は見当たらないし、Slack の API を見ても 2019/10/29 現時点ではそのような機構はない(というかワークフロー絡みのメソッドさえない)。

Q: ワークフロー作成者本人がこっそり修正したことはわかる?

Ans: ビルダー画面にて「~~時間前に~~が編集」という形で 直近の修正日時 だけはわかる

その他疑問

Q: ワークフロービルダーが使えません

Ans: フリープランには非対応。あと 権限が付与されてなければスタンダード以上でもつくれない

Q: 動作確認したいんだけど、どうすればいい?

Ans: ワークフローを試す用のパブリックチャンネルをつくって、そこで。

ワークフローは パブリックチャンネルに対してしか 設置できないので、何らかのパブリックチャンネルをつくる必要がある。

まとめ

  • 匿名フォームは実現できる
  • でも性悪説に従うなら万全ではない
    • 設置者本人 or オーナー・管理者がこっそり「匿名が壊れるような修正」をするかもしれない
  • 修正をしたら一応形跡は残る
    • 編集の形跡はビルダーの「~~時間前に~~が編集」でわかる
    • オーナー/管理者の介入時は全員に通知が走るようになっている

Amazon S3 でパブリックアクセスできるスクリプトを公開する

AWS CloudFormation で環境構築を自動化しているのだが、EC2 インスタンス内の設定を自動化するには CloudFormation では無理。自動化用スクリプトをつくっといて、これをインスタンスから実行させる必要がある。

※UserData はデバッグしづらいのでいったん除く。

今回は「Amazon S3 にスクリをアップ」して、これを「インスタンスから curl などでゲット」というやり方を試してみた。まともに S3 を使ったのはじめてなので、S3 についてまとめておく。

データ構造

「バケット」という入れ物の中に「ファイル」と「フォルダ」を入れる感じ。

※ファイルは AWS では「オブジェクト」と呼ばれる。

URL

https://(バケット名).s3-(リージョン).amazonaws.com/(パス)

つくる

バケットをつくる

  • バケット名はグローバルで一意
  • デフォでは index.html の補完は効かない
    • static website hosting を有効する必要アリ

ファイルを入れる

管理コンソールの「アップロード」から。D&D アップロードもできて便利。

  • アクセス権
    • パブリックにしたいなら「このオブジェクトにパブリック読み取りアクセス権限を付与する」を選択
    • 別にここで選択しなくても良い(あとで変更できる 下記参照)
  • ストレージクラス
    • スタンダードでいい
    • 他の選択肢は「安くなるけどアクセス遅い」系で普段使い用ではない

URL は各ファイルページの概要タブに表示される。

フォルダをつくる

管理コンソールの「フォルダの作成」ボタンから。

パブリックアクセスを実現するためのアクセス権

パブリックアクセスを実現するための付け方。

  • バケット
    • アクセス権限 > ブロックパブリックアクセス
    • パブリックアクセスをすべてブロック以下を 全部オフ
  • ファイル
    • アクセス権限 > パブリックアクセス
    • Everyone の「オブジェクトの読み取り」を はい

つまりバケットのフル解放とファイル単位の読み取りオンが必要。

アップしたスクリプトを EC2 から使う

NAT や Internet Gateway などでインターネットを見に行ける Linux の EC2 インスタンスがあるとしたら。

たとえば curl で、こんな感じで使える。

$ curl "https://(BucketName).s3-(RegionName).amazonaws.com/(Filename.Ext)" -o "Filename.Ext"
$ chmod 775 Filename.Ext
$ ./Filename.Ext

既にアップロードしたファイルの CRUD

削除したい

→ 管理コンソールから当該ファイルを選択して、概要 > アクション > 削除

内容を変更したい

→ 同名で再度アップロードすれば良い。

別名にリネームしたい

→ リネーム前ファイルを削除し、リネーム後ファイルをアップロード。

アクセス時の挙動

URL にアクセスした時の挙動。ここでは Firefox を使用。

バケットが見つからない場合:

  • XML で返される
    • NoSuchBucket
    • The specified bucket does not exist

バケットは存在するが、ファイルが存在しない or アクセス許可が無い場合:

  • XML で返される
    • AccessDenied

バケットが存在し、ファイルも存在して、アクセス許可がある場合:

  • 当該ファイルが RAW リンクで返される

運用時の懸念など

Q: 料金はどのくらい?

Ans: 詳しく調べてない

ただ個人やチームの評価・省力化目的で「自動化用スクリをアップしといて、EC2 から curl でダウンロードして使う」程度なら誤差の範囲内。

料金が何百円何千年と牙をむく規模は、ウェブサイト運用や MB 単位のデータを月何千何万リクエストするとか、そういうレベルみたい?

Q: DDoS が怖いのでガードしたいんですが?

DDoS で GET リクエスト大量に食らえばエグい料金請求されるんじゃないかという懸念。

Ans: 二通りあると思われる。

1つ目は CloudFront を使う方法。利用者側の利用の仕方を S3 URL 直アクセスではなく、CloudFront 経由にさせる。設定は煩雑そうなので割愛する(よく調べてないし)が、どうも S3 に対する細かい制御がしたいなら「CloudFront というラッパー?入り口?を立ててそっちで色々やれ」という感じみたい。

2つ目は運用回避だが、使ってない時は「バケットのパブリックアクセスをオフにする」こと。バケット自体をオフにしちゃえば、その中のファイルは全部アクセスできなくなる。いちいちオフにするのは面倒だが、EC2 インスタンスも使ってない時は電源オフにするし、そういうものなのかな。

Q: 特定 EC2 インスタンスからのみアクセス可能にするには?

Ans: S3のバケットポリシーを使うっぽい

詳しくは S3のバケットポリシーでハマったので、S3へのアクセスを許可するPrincipalの設定を整理する | Developers.IO を。

どうも「AWS アカウント ID」と「IAM ユーザー」の二つが必要みたい。この二つがあれば、バケットに以下バケットポリシーを設定することで、

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::(アカウントID):user/(IAM ユーザー名)"
            },
            "Action": "s3:ListBucket",
            "Resource": "arn:aws:s3:::${S3_BUCKET_NAME}"
        }
    ]
}

指定アクション(ここでは ListBucket)を許可できる。なんか Principal の書き方がハマりどころみたい?

おわりに

簡単に試してみたが、使いやすくて良い感じ。かなり大雑把なので間違い等あったらぜひ教えて下さい!

今回は画面ベースだったが、省力化したいなら AWS CLI や REST API が使えるだろう。

実運用については、細かいアクセス管理とお金の面をもっとちゃんと調べて考える必要がありそうか。追々。