0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【第4章】「FFRPGに変換して」の一言で6つのAIに同じRPG IIIを渡したら、6通りの壊れ方をした

0
Posted at

はじめに

チームで「RPG × AI」の検証を行っています。全体は以下の6本立てで、本記事はその ④ にあたります。

# テーマ
① 概要
② 仕様書作成
③ ソース(RPG III)生成
④ FFRPG変換(本記事)
⑤ FFRPG変換(カスタムルール/ILE経由)
⑥ まとめ

本章では同じRPG IIIソースを6つのAIに渡し、「FFRPGに変換して」の一言だけでフリーフォームRPG(FFRPG)に変換を検証しました。

条件は以下の通りです。

  • 与えるのは RPG III のソース1本と、プロンプト「FFRPGに変換して」だけ(DDS、コーディングルール、サンプルは渡さない)
  • 1回のプロンプトで生成させ、再試行・追加指示・対話での修正はしない
  • 生成されたソースは人手で一切直さず、そのままソースメンバーに貼り付けてコンパイルする

結果を先に言うと、6本すべてコンパイルは通りませんでした。 要修正メッセージは最少2件、最多84件。ただし「何件エラーが出たか」と「人が何箇所直せばいいか」は、まったく別の話でした。この記事はその中身の話です。

検証条件

項目 内容
対象プログラム JUCORR(受注入力プログラム/RPG III 固定フォーマット・500行)
参照オブジェクト JUCORD(DSPF・サブファイル)/TOKMEP・HINMEP(マスター)/JHEDRP(受注ヘッダー)/JDETLP(受注明細)
コンパイル環境 IBM i / 5770WDS V7R4M0(IBM ILE RPG)
コマンド CRTBNDRPG PGM(...) SRCFILE(...) GENLVL(10) OPTION(*XREF *GEN *EXPDDS *EXT)
検証ツール Claude / ChatGPT / GitHub Copilot / Bob / Gemini / Gemini Notebook
プロンプト 「FFRPGに変換して」+ RPG III ソース全文
与えた情報 RPG IIIソースのみ(DSPF・PFのDDSは渡していない)
集計方法 コンパイル・リスト末尾「最終の要約」のメッセージ合計と、「メッセージの要約」のMSG ID別件数をそのまま採用

DFTACTGRP はコマンドでは指定していません(省略時の *YES)。Ctl-Opt を書くかどうかも含めて、ツールに任せています。

元ソースはこういう、よくある構造です。

JUCORR.RPG(F仕様書)
     FJUCORD  CF  E                    WORKSTN
     F                                        RRN1  KSFILE JUSFLR
     FTOKMEP  IF  E           K        DISK
     FHINMEP  IF  E           K        DISK
     FJHEDRP  UF  E           K        DISK                      A
     FJDETLP  O   E           K        DISK

サブファイル、外部記述、コンパイル時配列(CTDATA)、SDS、TIME 命令、GOTO/TAG による脱出。移行対象としては標準的なところだと思います。

結果サマリ

順位は「要修正メッセージ数(重大度20以上)」の少ない順です。
今回は GENLVL(10) でコンパイルしているため、重大度10以下のメッセージだけならオブジェクトは作成されます。
実質的に直す必要があるのは重大度20以上です。

順位 ツール 通知(00) 警告(10) エラー(20) 重大(30+) 合計 要修正(20+) 根本原因
1 Claude 21 0 2 0 23 2 1
2 Gemini Notebook 26 0 1 7 34 8 3
3 Gemini 25 0 23 5 53 28 9
4 Copilot 24 0 24 8 56 32 3
5 ChatGPT 24 0 3 61 88 64 10
6 Bob 22 0 10 74 106 84 12

Claude だけが重大度20で止まり、他5ツールは重大度30で停止しています。
最少2件、最多84件で42倍の開きがあります。

見方その1 ── 件数ではなく「原因の数」で見る

4位の Copilot は要修正32件ですが、原因は3箇所です。
そのうち24件は、コンパイル時配列を INZ の値リストに置き換えようとした、この1つの宣言から出ています。

Copilot
// Copilot ── RNF3308 ×20 / RNF0312 ×2 / RNF0633 ×2
dcl-s Err char(78) dim(11) inz(
   '得意先コードを入力してください' :
   '得意先コードが存在しません' :
   ...
   'システムエラーが発生しました');

配列を INZ で要素ごとに初期化する構文は RPG にありません。
1行ずつ「キーワード名が正しくない」と怒られ続けた結果が20件です。
人が直すのは、この宣言を ctdata に戻して末尾に **CTDATA ERR を置くだけ。
原因の数で見ると Copilot は2位の Gemini Notebook と同じ3箇所です。

逆に3位の Gemini は要修正28件に対して原因が9箇所。件数は Copilot より少ないのに、直す場所は3倍あります。

ツール 要修正件数 根本原因 1原因あたり 最大の原因
Claude 2 1 2.0 %DEC の時刻書式 *HMS0(2件)
Gemini Notebook 8 3 2.7 サブルーチン内の dcl-s(5件)
Gemini 28 9 3.1 dcl-proc なのに DFTACTGRP(*NO) なし(10件)
Copilot 32 3 10.7 配列の INZ 値リスト(24件)
ChatGPT 64 10 6.4 存在しない IndDS を LIKEDS 参照(22件)
Bob 84 12 7.0 作業変数7個の宣言漏れ(57件)

エラー件数だけで順位づけすると、修正工数を読み違えます。

見方その2 ── 6ツールが同じ罠にかかっている

ツールが違っても踏む地雷はだいたい同じでした。
複数のツールが踏んだものを、影響の大きい順に見ていきます。

パターン1:フリーフォームに存在しない命令をそのまま書く(TIME / GOTO / TAG)

今回いちばん意外だったところです。TIME、GOTO、TAG はフリーフォームには存在しない命令ですが、ChatGPT と Bob の2ツールがそのまま書きました。

ChatGPT
// ChatGPT ── RNF7030(TIME / GOTO / VTOKX / VMCHK が未定義)+ RNF5347 ×9
   time W@DAT;
   ...
   if D@TOKC = *blanks;
      ERRMSG = ERR(1);
      *in01 = *on;
      ERRFLG = '1';
      goto VTOKX;
   endif;
   ...
VTOKX:
endsr;

Bob も同じで、TIME W@DAT; と goto VMCHK; / VMCHK: をそのまま残しています(#VTOK の GOTO だけは return に置き換えました)。

コンパイラーは time W@DAT; を「TIME という名前の変数を書いた式」と解釈するので、RNF7030(名前が定義されていない)と RNF5347(EVAL に代入演算子がない)がセットで出ます。
ChatGPT はさらに VTOKX: の直後の endsr; が巻き込まれてサブルーチンの対応が崩れ、後続の14行が「ENDSR の後の命令」として RNF5005 になりました。

残りの4ツールは、それぞれ違うやり方で置き換えています。

置き換えた4ツールの書き方
// Claude / Gemini Notebook / Copilot ── LEAVESR で脱出、TIME は %date/%time で組み立て
  if D@TOKC = *blanks;
    ERRMSG = ERR(1);
    *in01 = *on;
    ERRFLG = '1';
    leavesr;
  endif;

// Gemini(dcl-proc 化)── RETURN で脱出
//   ※ Bob も #VTOK は RETURN にしたが、#VMEI の GOTO VMCHK はそのまま残した
    return;

// Claude / Copilot / Gemini ── #VMEI の GOTO VMCHK は条件を1つの IF にまとめて除去
      if S@HNCD = *blanks and S@TNKA = 0 and S@SRYO = 0;
         iter;
      endif;

ちなみに、サブルーチン内の脱出に LEAVE を使ったツールは今回ゼロでした(LEAVE はループ内でしか使えません)。

パターン2:dcl-proc にしたのに DFTACTGRP(*NO) を書かない

Gemini と Bob はサブルーチンをすべてプロシージャー(dcl-proc)に変換しました。
構造化としては一段上の変換ですが、プロシージャーを使うには Ctl-Opt DFTACTGRP(*NO) が必要です。
2ツールとも Ctl-Opt 自体を書いていないため、プロシージャー10個すべてが RNF1520(重大度20) になりました。

+ ctl-opt dftactgrp(*no) actgrp(*caller);   // ← この1行がない

  dcl-proc #MAIN;                            // Gemini / Bob ── RNF1520 ×10
    ...
  end-proc;

1行足せば10件消えるので工数は軽いのですが、dcl-proc を選んだ以上は必ず付くものなので、ここは知識の抜けです。
begsr を維持した4ツールにはこの問題がありません(Copilot と ChatGPT は begsr のまま dftactgrp(*no) を書き、Claude は明示的に dftactgrp(*yes) を書いており、どちらも正しい)。

パターン3:C仕様書で定義された作業変数を宣言しない

RPG III のC仕様書は、結果フィールドに桁数を書けばその場で変数を定義できます。

JUCORR.RPG(C仕様書)
     C                     MOVEL'SCR1   ' W@SCRF  6
     C                     MOVE '0'       ERRFLG  1
     C                     Z-ADD0         MXRRN1  30

FFRPGにはこの仕組みがないので、dcl-s で宣言し直す必要があります。Bob は7個、Copilot は1個 を落としました。

ツール 宣言し忘れた変数 派生件数
Bob W@SCRF ERRFLG MXRRN1 INPCNT GYONO NEWBNG S 57
Copilot MXRRN1 7

Bob の宣言漏れ7個は、それだけで要修正84件のうち57件を占めます。
W@SCRF は画面遷移の判定に、ERRFLG はエラー判定に使われるので、参照箇所が多く、1個の宣言漏れが15〜20件に膨らみました。

DDSを渡していないので、ツールには「どれが画面項目でどれが作業変数か」を確定する材料がありません。
C仕様書の桁数指定(W@SCRF 6)を読めば区別できるのですが、そこを読んだツールと読まなかったツールで差が出ました。
Claude は作業変数12個をすべて dcl-s で宣言し、DDS項目は1つも宣言していません。

パターン4:DDSで定義済みの項目を、違う桁数で再宣言する

逆に「宣言しすぎ」の罠です。
元ソースの配列が ERR 1 11 78 なので、それを受ける ERRMSG も78桁だろう、と推測したツールが3つありました。
DDS側の ERRMSG は 75A です。

ERRMSG の再宣言
// Gemini Notebook / Gemini / ChatGPT ── RNF6033 ×2(2つのレコード様式でそれぞれ)
dcl-s ERRMSG char(78);

// ChatGPT はさらに
dcl-s RRN1 packed(5:0);     // DDS は ZONE(4,0) → RNF6033 + RNF7408

正しくは、DDSで定義済みの項目は宣言しません。
Claude・Copilot・Bob はDDS項目を1つも宣言せず、この罠を避けています(Bob は作業変数まで宣言しなかったのでパターン3に落ちましたが)。

RRN1 については、Gemini Notebook が packed(4:0) で宣言してエラーなし、ChatGPT が packed(5:0) でエラー、Claude・Copilot・Bob が宣言なしでエラーなし、でした。
宣言する場合はDDSと同じ桁数(4,0)に合わせる必要があります。

パターン5:%FOUND / %EOF の引数にレコード様式名を書く

  chain S JUSFLR;
- if %found(JUSFLR);          // Gemini ── JUSFLR はレコード様式名 → RNF0394
+ if %found(JUCORD);          // 引数はファイル名

  readp JHEDRR;
- if %eof(JHEDRR);            // ChatGPT ── JHEDRR もレコード様式名 → RNF0391
+ if %eof(JHEDRP);

CHAIN や READP の演算項目2にはレコード様式名を書くので、その流れで %FOUND にも様式名を書いてしまう、というミスです。
Gemini は %found(JUSFLR) を3箇所、ChatGPT は %eof(JHEDRR) を1箇所。Claude・Gemini Notebook・Copilot はファイル名で正しく書いています。

パターン6:F仕様書の「A」を見落として、WRITE できないファイルにする

元ソースの受注ヘッダーは更新ファイルに追加(A)を付けた UF ... A です。

JUCORR.RPG(F仕様書)
     FJHEDRP  UF  E           K        DISK                      A
- dcl-f JHEDRP usage(*update) keyed;              // Copilot / ChatGPT ── RNF5197(WRITE できない)
- dcl-f JHEDRP KEYED DISK USAGE(*UPDATE:*ADD);    // Gemini ── *ADD は存在しない → RNF2370 + RNF5197
+ dcl-f JHEDRP disk keyed usage(*update:*output);

F仕様書の右端に1文字だけ置かれた A は、固定フォーマットに慣れていないと見落とします。
Copilot・ChatGPT・Geminiの3ツールが落としました。

パターン7:コンパイル時配列(CTDATA)の扱い

E 仕様書の配列と末尾の ** ERR データを、そのまま ctdata で受けたのは Claude・Gemini・Gemini Notebook の3ツール。残り3ツールはそれぞれ別の方法を選び、全部失敗しました。

ChatGPT
// ChatGPT ── 配列は宣言だけにして、サブルーチンの後ろで代入
/free
ERR(1)  = '得意先コードを入力してください';
...
/end-free

**FREE ソースに /free は書けません(RNF0735)。
さらにこの代入はサブルーチン定義の後ろにあるため、14行すべてが「ENDSR の後の命令」として RNF5005 になります。

Copilot は見方その1で触れた INZ の値リスト(24件)。そして Bob は——

Bob
// Bob ── コンパイルは通る
dcl-s ERR   char(78) dim(11);
...
// ** ERR
// E001 得意先コードを入力してください

配列データをコメントアウトしました。
エラーにはなりませんが、実行時のメッセージは全部ブランクです。これは次の節の話です。

そのほか、1ツールだけが踏んだもの

  • Claude:要修正2件はどちらも同じ1行です。
    W@DAT = %dec(%time():*hms0) * 100000000 + %dec(%date():*usa); — %DEC で時刻を数値にするとき、書式に区切り文字の指定(*HMS0 の 0)は付けられません(RNF7514「区切り記号'0'を数値項目で使用することはできない」)。
    %dec(%time():*hms) と書き換えれば通ります。固定フォーマット時代の *HMS0 の癖がそのまま出た形です。
    #INZ と #TROKU の2箇所にあるので2件。これ以外の重大度20以上はゼロでした。
  • ChatGPT:dcl-ds Indicators likeds(IndDS); と書き、存在しない IndDS を参照した上にサブフィールドまで定義(LIKEDS とサブフィールドは併用不可)。
    標識名など12個が未定義になり RNF7030 ×12、サブフィールド9行が実行文と誤認されて RNF5347 ×9。
    誰も指示していないのに、INDDS を使おうとしたのは ChatGPT だけでした。
  • Gemini:dcl-f TOKMEP KEYED DISK(装置キーワードは先頭に置く → RNF2368 ×4)、zipped(4:0)(zoned の誤記)、overlay(W@DAT:9)(DS名に対する OVERLAY は POS を使う)、#PGM char(10) *PROC(型と *PROC の併用不可)、dcl-pi *n char(8); end-pi; を1行に書いて END-PI 未検出。
    細かい文法ミスが5種類。
  • Gemini Notebook:dcl-ds PgmStatus sds;(正しくは psds)と、サブルーチンの途中に dcl-s curr_date date; を置いた(宣言は演算の前にまとめる)の2つ。

見方その3 ── コンパイルが通っても残る誤り

エラーを直してコンパイルが通ったとしても、正しいプログラムが正しく動くかは分かりません。

  • Bob:CTDATA をコメントアウトしたので、ERR / MSG の中身が全部ブランク。
    画面にエラーメッセージが一切出ません。
    さらに CHAIN の結果を元ソースのまま *IN83 / *IN90 で判定していますが、フリーフォームの CHAIN は結果標識を設定しないので、どちらも一度も *ON になりません。
    品目コードが存在しなくてもエラーになりません。
  • ChatGPT:chain D@TOKC TOKMER; *in90 = %error; — (E) 拡張なしの %ERROR は常に *OFF です。
    しかも「レコードなし」はエラーではないので、(E) を付けても検知できません。
    Bob と同じく、存在しない得意先・品目を通してしまいます。
  • Gemini / Gemini Notebook:for RRN1 = 1 to 5; でサブファイルを作ったので、ループを抜けた時点で RRN1 = 6 です。
    MXRRN1 = RRN1 - 1; と補正して行数は合わせましたが、RRN1 自体は6のまま。
    RRN1 は DSPF の SFLRCDNBR なので、5件しかないサブファイルに6件目を指示することになり、EXFMT で実行時エラーになる可能性が高いです。
  • Gemini:金額オーバーフローの閾値を 9999999999(10桁)から 99999999999(11桁)に書き換えています。
    WKNGA は11桁なので、この判定は永遠に真になりません。
    また、W@DAT = %char(%date():*ISO0) + %char(%time():*HMS0) — 日付が先、時刻が後。
    元の TIME 14桁は時刻が先(hhmmss + 日付8桁)なので、9〜14桁目を切り出す WDATE には日付ではなく ddhhmm のような値が入ります。

レビューかテストでしか見つかりません。「コンパイルが通った」は移行完了ではない、という当たり前のことを実感しました。

なお TIME 14桁の変換を、元の形(時刻が先)で再現しようとしたのは Claude と Gemini Notebook の2ツールでした。

Claude
// Claude ── hhmmss × 10^8 + mmddyyyy の14桁数値(*hms0 の '0' が %DEC では不可 → RNF7514)
W@DAT = %dec(%time():*hms0) * 100000000 + %dec(%date():*usa);

// Gemini Notebook ── hhmmss + '00' + yymmdd の14桁文字列
W@DAT = %char(%time(): *hms0) + '00' + %char(%date(): *ymd0);

TIME 14桁の日付部分の並びはジョブの日付形式(DATFMT)に従うので、Claude は *MDY 系、Gemini Notebook は *YMD 系を想定したことになります。
どちらが「正しい」かは環境次第で、ここまで再現できていれば人が確認して直せる範囲です。
ChatGPT と Bob は TIME をそのまま残し(パターン1)、Gemini は日付を先にしてしまい、Copilot は WDATE を8桁の yyyymmdd に持ち替えました。

見方その4 ── 元バグを「直してくれる」ツール

元ソースには既知のバグが含まれていました。

  • 数量が0以下のときのメッセージを ERRMSG ではなく ERRFLG に MOVE している(MOVE ERR,8 ERRFLG)
  • 数量必須のメッセージに販売単価用の文言を流用している(MOVE ERR,6)

1つ目は、6ツール中5ツールが黙って ERRMSG への代入に直しました。
1桁の ERRFLG に78桁のメッセージを入れる意味がないので、ツールとしては「明らかな誤記」と判断したのだと思います。
2つ目の ERR,6 は Copilot と Gemini Notebook が ERR(8) に直し、残り4ツールはそのまま。

元の挙動を両方とも残したのは Claude だけでした。

Claude
      // 数量範囲チェック(> 0) ※原資産どおり ERRFLG へ設定
      if S@SRYO <= *zero;
        evalr ERRFLG = ERR(8);
        ERRFLG = '1';
        leave;
      endif;

evalr(右寄せ代入)を使っているのは、RPG III の MOVE が右詰めで転記する挙動に合わせるためで、ERRMSG = ERR(n) の代入もすべて evalr になっています。
78桁の配列要素を75桁の ERRMSG に MOVE すると左3桁が切れる、という元ソースの癖まで再現している格好です。

逆に、直したことを明記したのは Gemini Notebook だけです。

Gemini Notebook
        // 数量必須チェック (元コードのバグを修正:ERR,6 から ERR,8 へ)
        if S@SRYO = 0;
          ERRMSG = ERR(8);
        ...
        // 数量範囲チェック(> 0)(元コードのバグを修正:ERRFLGへの誤代入をERRMSGへ、およびERR,8からERR,9へ)

親切に見えますが、レガシー移行の一次変換では厄介です。元の挙動を1対1で移すことが最優先で、バグを黙って直されると、変換後の差異が「AIの改善」なのか「変換ミス」なのか切り分けられなくなります。

残り4ツールのように黙って直すのがいちばん困り、Gemini Notebook のように「直したならコメントに書く」が最低ライン、Claude のように「残してコメントで指摘する」が一次変換としては理想です。
本来は「直すな、疑わしい箇所はコメントで指摘だけしろ」と指示すべきところです。

生成ソースの品質

ツール 総行数 コメント行 構造化 標識 CTDATA GOTO の扱い 受注番号の編集
Claude 473 155 begsr × 10 *INxx 直接 維持 leavesr / 条件統合 %editc 'X'
Gemini Notebook 514 196 begsr × 10 *INxx 直接 維持 leavesr / 条件統合 %editc 'X'
Gemini 460 161 dcl-proc × 10 *INxx 直接 維持 return / 条件統合 %editc 'X'
Copilot 414 107 begsr × 10(名前を英語化) *INxx 直接 INZ リスト(エラー) leavesr / 条件統合 %editc 'X'
ChatGPT 608 258 begsr × 10 INDDS(破綻) 代入文(エラー) goto のまま %subst でゼロ埋め
Bob 529 227 dcl-proc × 10 *INxx 直接 コメントアウト(空) goto のまま %editc 'X'

元RPG IIIは500行。行数はどのツールも大差ありません。差が出たのは「フリーフォームに何が無いかを知っているか」「F仕様書・C仕様書の桁位置の情報を読めているか」の2点で、ロジックの組み替え方の巧拙ではありませんでした。

各ツールの得意・不得意

ツール 良かった点 弱かった点
Claude 要修正2件・原因1箇所。作業変数の宣言とDDS項目の切り分けが正確。元バグを残してコメントで指摘。evalr で MOVE の右詰めまで再現 %DEC の時刻書式(*HMS0)を誤った。TIME の日付部分は *MDY 前提
Gemini Notebook 要修正8件・原因3箇所。TIME の再現が元に近い。元バグの修正をコメントで明記 sds の誤記、サブルーチン内の宣言。RRN1 の6件目問題
Gemini dcl-proc + ローカル変数で最も構造化。条件のまとめ方が綺麗 細かい文法ミスが多い(キーワード順、zipped、*PROC、OVERLAY)。閾値・TIME の順序を黙って変更
Copilot 原因3箇所。DDS項目の再宣言ゼロ。leavesr・%found の使い方が正確 配列の INZ リスト。MXRRN1 の宣言漏れ。日本語コメントの大半を削除
ChatGPT コメント量は最多 頼んでいない INDDS を作って破綻。TIME GOTO 残存。/free。%error で存在チェック不能
Bob dcl-proc 化。%editc 'X' 作業変数7個の宣言漏れ。TIME GOTO 残存。CTDATA をコメントアウトしてメッセージが空

この検証から言えること

  1. エラー件数だけで順位をつけない。
    Copilot は32件でも原因は3箇所、Gemini は28件で原因9箇所。
    実際の修正工数は件数に比例しません。
  2. 「フリーフォームに存在しない命令」を知っているかが最初の分岐点。
    TIME GOTO TAG をそのまま書いたツールが6つ中2つ。
    ここを外すと、サブルーチン1つが丸ごと未定義エラーの山になります。
  3. DDS(DSPF・PF)をプロンプトに含める。
    作業変数の宣言漏れ(パターン3)と DDS 項目の再宣言(パターン4)は、どちらも「どれが画面項目か分からない」ことから来ています。
    DDS を渡せば原理的に両方消えます。
  4. FFRPG特有の落とし穴は、ルールとして明文化して渡す。
    次の7点で、今回の要修正メッセージの9割以上が消えます。
    • TIME / GOTO / TAG は使わない
    • dcl-proc を使うなら ctl-opt dftactgrp(*no)
    • C仕様書で桁数を付けた作業変数は dcl-s で宣言する
    • DDS定義済みの項目は宣言しない
    • %FOUND / %EOF の引数はファイル名
    • F仕様書の A は usage(*update:*output)
    • 配列は ctdata のまま、**CTDATA を末尾に残す
  5. 元バグの扱いを明示的に指示する。
    6ツール中5ツールが黙って直しました。
    「バグを含めて挙動を1対1で移し、疑わしい箇所はコメントで指摘するだけにする」と書くのが有効です。
  6. 全面採用ではなく、人によるレビュー併用が前提。
    コンパイルが通っても、結果標識なしの CHAIN、SFLRCDNBR の範囲外、空の配列、TIME の日付形式のような、実行時に判明する誤りは残ります。

おわりに

「FFRPGに変換して」の一言では、どのツールもコンパイルは通りませんでした。
ただし裏を返せば、Claude は原因1箇所・要修正2件、Gemini Notebook と Copilot も原因3箇所まで来ています。
ここに4の「明文化したルール」 を足す、もしくはRPGLE(ILE)に1度変換して仕様書形式の変換と記述形式の変換を分けるとどうなるか、というのが次の記事のテーマです。

次回⑤では、カスタムルールを与えた場合と、ILEへの変換を経由した場合を検証します。


当記事の著作権はIBMに帰属します。詳細はこちらを参照ください。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?