朝日ネット 開発者ブログ

朝日ネットのエンジニアによるリレーブログ。今、自分が一番気になるテーマで書きます。

Git のサブコマンドに学ぶシェルスクリプトの書き方

はじめに

開発部の tasaki です。

シェルスクリプトはプログラムとプログラムとを繋ぐ存在であり、UNIX や Linux を使う上で最も重要なスクリプト言語であると言えます。 curl, diff, git, rsync, ssh 等の外部コマンドが複数絡むスクリプトや、テキストストリーム処理を多用するスクリプトを書きたい場合はシェルスクリプトとして書くのが最も手軽です。

一方、シェルスクリプトは書き方の自由度が高くコードスタイルについての合意が取りにくい言語であり、移植性の高いものを書くのが難しい言語であります。 大抵の Linux には bash が入っているためそれ向けに書いてしまってもよいのですが、Docker の流行により bash が標準で入っていない Alpine Linux 環境が使われる機会が世間的にも増えているため、少なくともデプロイ先で動くスクリプトは bash に依存しない形で書いておきたいです。

ところで、Git の bisect, filter-branch, stash, submodule, subtree などの一部のサブコマンドはシェルスクリプトとして書かれています。 これはあらゆる環境で安定して動作するシェルスクリプトであると言え、これを参考にすれば移植性の高いシェルスクリプトを書けるのではないでしょうか? 今回は私が Git に含まれるシェルスクリプトを読んで得られた知見を Tips としてまとめていきます。

続きを読む

Bootstrap4エディタのpingendoでpdfのマニュアルをHTML化してみた-後編

watanabeです。前回の記事ではBootstrap4のエディタを用いて、pdfのマニュアルを見た目の印象をあまり変えないようにHTML化しましたが 今回は印刷時のレイアウトを元のマニュアルに近づけるためにどう調整したかを記録します。

また、HTML化してもマニュアルとしての操作性を落とさないようにするためのおすすめTipsも紹介します。

続きを読む

すっきり表組み・見出しを縦に回転

はじめまして、開発部の8lukaです。小ネタですが便利なテクニックのご紹介です。

はじめに:大きな対応表を画面におさめたい

たとえば、商品とその構成品目。たとえば、ロールとその権限。たとえば、飲み会の参加者と日程候補。 こういった対応関係は、表に可視化することができます。

f:id:an8luka:20190225142224p:plain
対応表の例 - 商品とその構成品目(Googleスプレッドシート - Chrome72)

対応関係が整列されて理解しやすい反面、列の数が増えてくるとあっという間に横幅が膨れて、画面におさまらなくなったりレイアウトが崩れたりしてしまいます。

f:id:an8luka:20190225142348p:plain
横幅が広がってしまった対応表の例(Googleスプレッドシート - Chrome72)

見出しを短くして詳細を別の場所に書く手もありますが、見る場所が分散して不親切な表になってしまうかもしれません。

列見出しを縦に回転させる

このようなとき、たとえばExcelやGoogle スプレッドシートでは列見出しを縦に回転させて横幅を圧縮できます。

f:id:an8luka:20190225143136p:plain
縦に回転させる方法(Googleスプレッドシート - Chrome72)
f:id:an8luka:20190225143411p:plain
縦に回転させた結果(Googleスプレッドシート - Chrome72)

横幅を2.7倍、面積比で見ても1.6倍ほど小さくすることができました。

ようやく本題です。同じことをHTMLのtableで実現する簡単な方法はあるのでしょうか?

CSSのtransform

CSSのtransformプロパティを利用すると、要素を簡単に回転できます。これが利用できそうです。手元で試行錯誤してもなかなかうまくいかなかったのですが ブラウザーの対応 の表がまさにこれで実現されていることに気付き、 同様の方法で縦に回転した列見出しを作ることができました。

f:id:an8luka:20190226163624p:plain
CSS transformプロパティによる回転(結果 - Chrome72)

以下、ソースコードです。

<!DOCTYPE html>

<html>
<head>
    <meta charset="utf-8" />
    <title>CSS transformプロパティによる回転</title>
    <style>
    table {
        border-collapse: collapse;
        border: solid black 2px;
    }
    td {
        border: solid black 1px;
        padding: 5px;
    }
    tr.header-row td {
        height: 200px;
        vertical-align: bottom;
    }
    .vertical-text {
        display: inline-block;
        transform: rotate(-90deg);
        transform-origin: 10px 10px;
        width: 20px; height: 20px;
        padding: 0;
        white-space: nowrap;
    }
    </style>
</head>
<body>

    <table>
        <tr class="header-row">
            <td></td>
            <td><span class="vertical-text">品目A(モバイルルータA)</span></td>
            <td><span class="vertical-text">品目B(共通ACアダプタ)</span></td>
            <td><span class="vertical-text">品目C(A専用クレードル)</span></td>
            <td><span class="vertical-text">品目D(モバイルルータD)</span></td>
            <td><span class="vertical-text">品目E(D専用クレードル)</span></td>
        </tr>
        <tr> <td>商品1(品目A 単品)</td>
             <td></td> <td></td> <td></td> <td></td> <td></td>
        </tr>
        <tr> <td>商品2(品目A+品目B セット)</td>
             <td></td> <td></td> <td></td> <td></td> <td></td>
        </tr>
        <tr> <td>商品3(品目A+品目C セット)</td>
             <td></td> <td></td> <td></td> <td></td> <td></td>
        </tr>
        <tr> <td>商品4(品目A+品目B+品目C セット)</td>
             <td></td> <td></td> <td></td> <td></td> <td></td>
        </tr>
        <tr> <td>商品5(品目D 単品)</td>
             <td></td> <td></td> <td></td> <td></td> <td></td>
        </tr>
        <tr> <td>商品6(品目D+品目B セット)</td>
             <td></td> <td></td> <td></td> <td></td> <td></td>
        </tr>
        <tr> <td>商品7(品目D+品目E セット)</td>
             <td></td> <td></td> <td></td> <td></td> <td></td>
        </tr>
        <tr> <td>商品8(品目D+品目B+品目E セット)</td>
             <td></td> <td></td> <td></td> <td></td> <td></td>
        </tr>
    </table>
</body>
</html>

幅や高さの数字が埋まっているので、内容がほとんど決まっていてあまり変わらないような場合にはこの方法が便利そうです。

回転を実現しているのは tarnsform: rotate(-90deg); だけなのですが、少々調整が必要になります。特に、以下2点が重要です:

  • white-space: nowrap; で折り返しを禁止します。 これがないと「折り返された状態のテキスト」を回転させることになってしまい、望む表示が得られません。
  • 回転後の内容が十分入る大きさのボックスを、外側の要素で確保します。(この場合は tdheight: 200px;

レンダリング結果とともにまとめると、次のとおりです:

CSS Chrome72でのレンダリング結果
transform: rotate による回転前 transform: rotate による回転後
- - f:id:an8luka:20190311152651p:plain f:id:an8luka:20190311152338p:plain
f:id:an8luka:20190311155415p:plain f:id:an8luka:20190311155516p:plain
f:id:an8luka:20190311154007p:plain f:id:an8luka:20190311154051p:plain

インラインSVG

2019年現在、IE11を含む主要ブラウザはSVG画像の表示に対応しています。しかも、HTMLの中に直接ソースを記述できます。こちらも便利な予感がするので実験してみましょう。

f:id:an8luka:20190314235112p:plain
SVGによるテキストの回転 - Chrome72

テキストの回転はできましたが、以下のソースでもわかるとおり width height viewBoxと延べ6個の数値をそれぞれのsvg要素に指定する必要があります。これではCSSより扱いやすいとは言い難いです。

<!DOCTYPE html>

<html>
<head>
    <meta charset="utf-8" />
    <title>SVGによるテキストの回転</title>
    <style>
    table {
        border-collapse: collapse;
        border: solid black 2px;
    }
    td {
        border: solid black 1px;
        padding: 5px;
    }
    tr.header-row td {
        vertical-align: bottom;
    }
    </style>

</head>
<body>

    <table>
        <tr class="header-row">
            <td>
                <svg width="20" height="200" viewBox="-18 -200 20 200">
                    <text transform="rotate(-90)">回転したテキストを</text>
                </svg>
            </td>
            <td>
                <svg width="20" height="200" viewBox="-18 -200 20 200">
                    <text transform="rotate(-90)">SVGで描いてみたよ</text>
                </svg>
            </td>
        </tr>
    </table>

</body>
</html>

JavaScriptにサイズを設定させる

内容のテキストに合った数値をJavaScriptに計算してもらいましょう。

まずは、SVG要素を生成する関数を定義します。ファイル名は何でもよいですが、ここでは verticaltextsvg.js とします。

// このプログラムは CC0 のもとパブリックドメインです:
// https://creativecommons.org/publicdomain/zero/1.0/legalcode.ja
var createVerticalTextSvg = function() {

    // この関数が呼ばれたscript要素
    var script_e = document.scripts[document.scripts.length - 1];
    // その data-text 属性を拾う
    // 普通に引数で渡してもよいけれど、属性から拾う方がXSS対策の悩みを減らせる
    var content_t = script_e.getAttribute("data-text");

    // SVGの要素を生成して
    var text_e = document.createElementNS("http://www.w3.org/2000/svg", "text");
    text_e.textContent = content_t;
    var svg_e = document.createElementNS("http://www.w3.org/2000/svg", "svg");
    svg_e.appendChild(text_e);

    // そのバウンディングボックスを取りたいのだが、まずは
    // これを済ませないと getBBox が有効な値を返さない
    script_e.parentNode.insertBefore(svg_e, script_e);
    // SVGさえできてしまえば script 要素はどこからも使われないので消しておく
    script_e.parentNode.removeChild(script_e);

    // 回転行列を定義して text要素に適用する
    // rotate 指定でもよいけれど、この後の再利用の都合で行列になっている方が便利
    var rot_m = [ 0, -1, 1, 0, 0, 0 ];
    text_e.setAttribute("transform", "matrix(" + rot_m.join(",") + ")");

    // 満を持してバウンディングボックスを取得する
    // ただし、これは transform 適用前の値
    var bb = text_e.getBBox();

    // なのでバウンディングボックスの4頂点を自力で回転させる
    var rot_vs = [
        [ bb.x,            bb.y             ],
        [ bb.x + bb.width, bb.y             ],
        [ bb.x + bb.width, bb.y + bb.height ],
        [ bb.x,            bb.y + bb.height ]
    ].map(function(v) {
        return [
            rot_m[0]*v[0] + rot_m[2]*v[1] + rot_m[4],
            rot_m[1]*v[0] + rot_m[3]*v[1] + rot_m[5] ];
    });

    // 新しいバウンディングボックスを
    // svg の width height viewBox に設定する
    var rot_xs = rot_vs.map( function(v) { return v[0]; } );
    var rot_ys = rot_vs.map( function(v) { return v[1]; } );

    var rot_min_x = Math.min.apply(null, rot_xs);
    var rot_max_x = Math.max.apply(null, rot_xs);
    var rot_min_y = Math.min.apply(null, rot_ys);
    var rot_max_y = Math.max.apply(null, rot_ys);

    var rot_w = rot_max_x - rot_min_x;
    var rot_h = rot_max_y - rot_min_y;

    svg_e.setAttribute("width", rot_w);
    svg_e.setAttribute("height", rot_h);
    svg_e.setAttribute("viewBox", [
        rot_min_x, rot_min_y,
        rot_w, rot_h ].join(","));

    return svg_e;
};

ポイントが2つあります。

あとは呼び出すだけです。定義部でちょっと頑張った分、呼び出しは簡単です。

<!DOCTYPE html>

<html>
<head>
    <meta charset="utf-8" />
    <title>JS + SVGによるテキストの回転</title>
    <style>
    table {
        border-collapse: collapse;
        border: solid black 2px;
    }
    td {
        border: solid black 1px;
        padding: 5px;
    }
    tr.header-row td {
        vertical-align: bottom;
    }
    </style>
    <script src="verticaltextsvg.js"></script>
</head>
<body>

    <table>
        <tr class="header-row">
            <td></td>
            <td><script data-text="品目A(モバイルルータA)">createVerticalTextSvg()</script></td>
            <td><script data-text="品目B(共通ACアダプタ)">createVerticalTextSvg()</script></td>
            <td><script data-text="品目C(A専用クレードル)">createVerticalTextSvg()</script></td>
            <td><script data-text="品目D(モバイルルータD)">createVerticalTextSvg()</script></td>
            <td><script data-text="品目E(D専用クレードル)">createVerticalTextSvg()</script></td>
        </tr>
        <tr> <td>商品1(品目A 単品)</td>
             <td></td> <td></td> <td></td> <td></td> <td></td>
        </tr>
        <tr> <td>商品2(品目A+品目B セット)</td>
             <td></td> <td></td> <td></td> <td></td> <td></td>
        </tr>
        <tr> <td>商品3(品目A+品目C セット)</td>
             <td></td> <td></td> <td></td> <td></td> <td></td>
        </tr>
        <tr> <td>商品4(品目A+品目B+品目C セット)</td>
             <td></td> <td></td> <td></td> <td></td> <td></td>
        </tr>
        <tr> <td>商品5(品目D 単品)</td>
             <td></td> <td></td> <td></td> <td></td> <td></td>
        </tr>
        <tr> <td>商品6(品目D+品目B セット)</td>
             <td></td> <td></td> <td></td> <td></td> <td></td>
        </tr>
        <tr> <td>商品7(品目D+品目E セット)</td>
             <td></td> <td></td> <td></td> <td></td> <td></td>
        </tr>
        <tr> <td>商品8(品目D+品目B+品目E セット)</td>
             <td></td> <td></td> <td></td> <td></td> <td></td>
        </tr>
    </table>
</body>
</html>

ブラウザで見ると、中身のテキストに合わせてぴったりの表になっているのがわかります。

f:id:an8luka:20190304123442p:plain
JS + SVGによるテキストの回転 - Chrome72

おわりに

以上、表の見出しを縦に回転させて横幅を抑える方法のご紹介でした。 実はこの記事にも使われていますので、よかったら探してみてくださいね。

採用情報

朝日ネットでは新卒採用・キャリア採用を行っております。

OpenAPI Specification 3.0 チートシート

はじめに

こんにちは。朝日ネットでWebアプリケーションの開発を行っている tommy です。

OpenAPI Specification は RESTful な API を記述するための仕様です1。2015年に Open API Initiative が発足し、それまで Swagger という名前で進められていたプロジェクトを引き継ぎました。 現在では実質上の世界標準といえます。

今回は、この OpenAPI を書いている時に、コピペして使える、逆引きの小さなサンプル集が欲しいと思ったので、書いていこうと思います2


  1. カタカナで オープンAPI というと、日本だと一般に公開されたAPIという意味にもなるので注意。

  2. Swagger 2.0 から OpenAPI 3.0 になったことで仕様がだいぶすっきりした上に、公式のドキュメント がわかりやすいため調べながら書くのもそれほど大変なわけではないです。

続きを読む

脆弱性スキャナ Vuls の紹介と実運用時の工夫

はじめに

開発部の tasaki です。

皆さんはソフトウェアの脆弱性の検知をどのように行っていますか? NVD や JVN、Linux ディストリビューションの公式 Web サイトで脆弱性情報を逐一確認し、現在マシンにインストールされているパッケージと照らし合わせる……、というのは非常に骨の折れる作業です。 更にサーバが複数台あり、ディストリビューションもインストールされているパッケージもまちまち、という状況ではとても人の手でできたものではありません。

このような時に役に立つのがオープンソース (GPLv3) の脆弱性検知ツールである Vuls です 1 。 今回は Vuls の基本的な使い方を紹介し、加えて弊社で実際に運用してみて得た知見について書いていきます。


  1. 商用版の FutureVuls も提供されています。

続きを読む