1
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?

Mind8のランタイムディスパッチャC実装の代替実装をC#で行う(空列を返せないわけではない)

Last updated at Posted at 2024-09-23

はじめに

本記事は日本語プログラミング言語Mind8のC言語で実装されているランタイムディスパッチャをC#で代替実装し、.NETのライブラリ資産を利用しやすくしたいという思惑の元に遂行されている企画の続きです。前回の記事で検証用コンソールの完走版にコードを追加した結果、文字列実体の「空列」で止まっていることが判明しました。

前提条件

Windows11 Pro 22H2
VSCode(Visual Studo Code) 1.86.1
Microsoft Visual C++ 2008 Express Edition
Mind Version 8.0.08 for Windows
C# 12
dotnet-sdk-8.0.204-win-x64

VSCodeの拡張機能

C/C++ for Visual Studio Code 1.18.5 Microsoft
C/C++ Extension Pack 1.3.0 Microsoft
.NET Install Tool 2.0.2 Microsoft
Base language support for C# 2.18.16 Microsoft

C/C++のデバッガはCで実装されているMind8kernelの動作をデバッグ実行で探るために使用します。こちらの記事の環境となります。

カスタマイズConsoleのビルド

Mind開発者の@killyさんよりご提供いただいた情報に従い、下記のようにカスタマイズConsoleのビルド用のフォルダfilelevel群を作成しています。

ビルド用フォルダ構成

現状は下記のようなフォルダ構成となります。filedummyフォルダは起動検証用Consoleのビルド環境です。fileフォルダは正規のソースファイルが格納されたフォルダです。
filedummyの内容はこちらの記事を、filelevel1,2(旧0)の内容はこちらの記事を参照してください。

C:\developments\vscode\mind8>tree
C:.
├─bin
├─file
│  └─obj
├─filedummy <--完走
│  └─obj
├─filelevel0 <--完走
│  └─obj
├─filelevel1 <--完走
│  └─obj
├─filelevel2 <--未完走
│  └─obj
├─filelevel3 <--完走
│  └─obj
├─filelevel4 <--完走
│  └─obj
├─filelevel5 <--未完走
│  └─obj
├─filelevel6 <--未完走
│  └─obj
├─kernel
│  └─.vscode
├─lib
├─libY
└─sample

filelevel5,6フォルダは本記事のバージョンの格納フォルダです。filelevel2のソースコードの一部を追加しています。

お題のMindソースコード

こちらの記事より「コンソール初期化・基本部」の定義部に独自に簡略化した「私のプログラム名と起動パラメータを設定0」を導入しています。

conslevel4(,5,6).src
コンソール初期化・基本部とは  (・  →  ・)
 (しばらくはシステムコールするな)
    終了パラメータを クリアし        ※CCONST.SRC
    エラー文字列初期化し           ※CERROR.SRC
    空白文字列初期化し            ※COUTPUT.SRC
	   エラー出力を本来の出力に切り替え     ※COUTPUT.SRC
       私のプログラム名と起動パラメータを設定0し
	。

各ライブラリ初期化とは     本定義     (・  →  ・)
    コンソール初期化・基本部し           ※本ソース示すること。

この範囲は今回の記事でも同じです。今回は「私のプログラム名と起動パラメータを設定0」の内容を変更しています。

下記は完走しているlevel4の状態です。

conslevel4.src
Mind文字列に変換して次のアドレスを得る0とは 処理単語  .N ※1999.07.04訂正
 (ASCIZアドレス → 文字列、次のASCIZアドレス(または0))
        アドレス1は 変数
        バイト位置は 変数		  ※←32bitに(1999.07.04)

    アドレス1に 入れ
。

私のプログラム名と起動パラメータを設定0とは  (・  → ・)
  	※※※※※※※※※※※※※※※※※※※※※※※※※
	※ ・当モジュール内の$$COLD_FORTHから呼ばれる ※
  	※ ・この中で「私のプログラム名」もセットする ※
  	※※※※※※※※※※※※※※※※※※※※※※※※※
  (私のプログラム名を決定)
	c_mcodeFullFilenameを Mind文字列に変換して次のアドレスを得て0
。

これに対して前回は
level5

conslevel5.src
Mind文字列に変換して次のアドレスを得る0とは 処理単語  .N ※1999.07.04訂正
 (ASCIZアドレス → 文字列、次のASCIZアドレス(または0))
        アドレス1は 変数
        バイト位置は 変数		  ※←32bitに(1999.07.04)

    アドレス1に 入れ
	アドレス1を バイトロードし ゼロ?
		ならば 空列と 0を 返し
			終り
		つぎに
	空列と 0を 返し
。

Mind文字列に変換0とは 処理単語  .N
 (ASCIZアドレス → 文字列)
    Mind文字列に変換して次のアドレスを得て0  捨てること。

私のプログラム名と起動パラメータを設定0とは  (・  → ・)
  	※※※※※※※※※※※※※※※※※※※※※※※※※
	※ ・当モジュール内の$$COLD_FORTHから呼ばれる ※
  	※ ・この中で「私のプログラム名」もセットする ※
  	※※※※※※※※※※※※※※※※※※※※※※※※※
  (私のプログラム名を決定)
	c_mcodeFullFilenameを Mind文字列に変換0して
	  捨てること
。

level6

conslevel6.src
Mind文字列に変換して次のアドレスを得る0とは 処理単語  .N ※1999.07.04訂正
 (ASCIZアドレス → 文字列、次のASCIZアドレス(または0))
        アドレス1は 変数
        バイト位置は 変数		  ※←32bitに(1999.07.04)

    アドレス1に 入れ
	空列と 0を 返し
。

Mind文字列に変換0とは 処理単語  .N
 (ASCIZアドレス → 文字列)
    Mind文字列に変換して次のアドレスを得て0  捨てること。

私のプログラム名と起動パラメータを設定0とは  (・  → ・)
  	※※※※※※※※※※※※※※※※※※※※※※※※※
	※ ・当モジュール内の$$COLD_FORTHから呼ばれる ※
  	※ ・この中で「私のプログラム名」もセットする ※
  	※※※※※※※※※※※※※※※※※※※※※※※※※
  (私のプログラム名を決定)
	c_mcodeFullFilenameを Mind文字列に変換0して 
	捨てること
。

としていました。両者は完走しませんでした。そこでlevel6で下記のように「空列と」をとってみるとこれは完走することがわかりました。

level6改

conslevel6.src
-	空列と 0を 返し
+ 	0を 返し

ここまでが前回の結果で、「空列」は下記のように「文字列実体」として宣言されているところまでを確認しておりました。

cconvar.src
空列は         文字列実体 長さ 0。

level2の「私のプログラム名と起動パラメータを設定」の完全記述版でも、「文字列実体」が出てきていたような気がして、以前として文字列の扱いは不完全なので、このあたりでこけているっぽいことが判明しました。

そこで前回記事のコメントでMind開発者の@killyさんより、

 空列を

と書くのと

 「」を

と書くのは効果として同じなのですが、前者がデータ領域上の文字列であることに比べ、後者はMコード領域上の文字列という違いがあります。

とのアドバイスをいただきましたので、空列が問題というよりはデータ領域上のポインティングの問題かどうかを切り分けるため、level5,6のコードを下記のように修正して実行してみます。

level6改2

conslevel6.src
-	空列と 0を 返し
+ 	「」を 返し

level5は上記の複数ヶ所を同様に訂正。

本来のお題のMind8のソースファイル

こちらの記事を参照してください。

お題のMind8の中間コード実行リスト

今回は省略しました。

お題のMind8の中間コードのC#代替ディスパッチャ実行リスト

まずlevel5改の結果です。完走しました。

level5改

SqNo mcode mc(dec) mpoint dtp.point  dtp+0   dtp+1 rtp.point  rtp+0  rtp+1
   1 8019  32793    114   1024        0        0   1024        0        0
   2 002F     47    102   1024        0        0   1023      114        0
   3 0012     18   8094   1024        0        0   1023      114        0
   4 0036     54   8096   1024        0        0   1023      114        0
   5 0080    128   8102   1024        0        0   1023      114        0
   6 0036     54   8104   1024        0        0   1023      114        0
   7 0070    112   8110   1024        0        0   1023      114        0
   8 803A  32826   8112   1024        0        0   1023      114        0
   9 002F     47    238   1024        0        0   1022     8112      114
  10 80E9  33001   8090   1024        0        0   1022     8112      114
  11 0036     54   8072   1024        0        0   1021     8090     8112
  12 0071    113   8078   1024        0        0   1021     8090     8112
  13 8046  32838   8080   1024        0        0   1021     8090     8112
  14 8045  32837    326   1024        0        0   1020     8080     8090
  15 0012     18    314   1024        0        0   1019      326     8080
  16 0036     54    316   1024        0        0   1019      326     8080
  17 0074    116    322   1024        0        0   1019      326     8080
  18 0020     32    324   1024        0        0   1019      326     8080
  19 0020     32    328   1024        0        0   1020     8080     8090
  20 80A3  32931   8082   1024        0        0   1021     8090     8112
  21 0036     54   3884   1024        0        0   1020     8082     8090
  22 0012     18   3890   1024        0        0   1020     8082     8090
  23 016E    366   3892   1024        0        0   1020     8082     8090
  24 0020     32   3898   1024        0        0   1020     8082     8090
  25 808F  32911   8084   1024        0        0   1021     8090     8112
  26 0097    151   3626   1024        0        0   1020     8084     8090
  27 0065    101   3628   1022        0        2   1020     8084     8090
  28 0020     32   3634   1024        0        0   1020     8084     8090
  29 80E8  33000   8086   1024        0        0   1021     8090     8112
  30 0261    609   8064   1024        0        0   1020     8086     8090
  31 80E7  32999   8066   1022        0 2151879280   1020     8086     8090
  32 80E6  32998   8058   1022        0 2151879280   1019     8066     8086
  33 001A     26   8026   1022        0 2151879280   1018     8058     8066
  34 006B    107   8028   1022        0 2151879280   1016        0        0
  35 0055     85   8032   1024        0        0   1016 2151879280        0
  36 008F    143   8036   1022        0 2151879280   1016 2151879280        0
  37 00ED    237   8038   1022        0 2151879280   1016 2151879280        0
  38 00A5    165   8050   1024        0        0   1016 2151879280        0
  39 0095    149   8054   1022        0     8052   1016 2151879280        0
  40 0022     34   8056   1020        0        0   1016 2151879280        0
  41 0122    290   8060   1020        0        0   1019     8066     8086
  42 0020     32   8062   1022        0     8052   1019     8066     8086
  43 0122    290   8068   1022        0     8052   1020     8086     8090
  44 0020     32   8070   1024        0        0   1020     8086     8090
  45 0020     32   8088   1024        0        0   1021     8090     8112
  46 0020     32   8092   1024        0        0   1022     8112      114
  47 00A5    165   8114   1024        0        0   1023      114        0
  48 803C  32828   8138   1022       20     8116   1023      114        0
  49 002F     47    246   1022       20     8116   1022     8138      114
  50 001A     26   5802   1022       20     8116   1022     8138      114
  51 006E    110   5804   1022       20     8116   1020     8086     8090
  52 0015     21   5808   1024        0        0   1020       20     8090
  53 00ED    237   5810   1022        0        1   1020       20     8090
  54 0022     34   5830   1024        0        0   1020       20     8090
  55 00A5    165   8140   1024        0        0   1023      114        0
  56 00C1    193   8158   1022       14     8142   1023      114        0
$$COLD_FORTH
  57 0020     32   8160   1024        0        0   1023      114        0
  58 80F4  33012    116   1024        0        0   1024        0        0
  59 00A5    165   8610   1024        0        0   1023      116        0
  60 8083  32899   8628   1022       14     8612   1023      116        0
  61 0012     18   3510   1022       14     8612   1022     8628      116
  62 004E     78   3512   1022       14     8612   1022     8628      116
  63 00EC    236   3518   1020        0        0   1022     8628      116
  64 0096    150   3524   1022       14     8612   1022     8628      116
  65 026D    621   3526   1020        0        1   1022     8628      116
Hello by mind8
  66 0020     32   3528   1024        0        0   1022     8628      116
  67 0020     32   8630   1024        0        0   1023      116        0
  68 801A  32794    118   1024        0        0   1024        0        0
  69 002F     47    106   1024        0        0   1023      118        0
  70 00A5    165   8188   1024        0        0   1023      118        0
  71 00C1    193   8202   1022       10     8190   1023      118        0
実行終り
  72 801B  32795   8204   1024        0        0   1023      118        0
  73 002F     47    110   1024        0        0   1022     8204      118
  74 00A5    165   8162   1024        0        0   1022     8204      118
  75 00C1    193   8184   1022       18     8164   1022     8204      118
実行終り時の処理
  76 0020     32   8186   1024        0        0   1022     8204      118
  77 0012     18   8206   1024        0        0   1023      118        0
  78 004E     78   8208   1024        0        0   1023      118        0
  79 0014     20   8214   1022        0        0   1023      118        0
例外がスローされました: 'Mind8Kernel.Dispatcher.ExitModule' (mind8dispatch.dll の中)
プログラム '[13396] mind8dispatch.dll' がコード 0 (0x0) で終了しました。

続いてlevel6改2の結果です。こちらも完走しました。
level6改2

SqNo mcode mc(dec) mpoint dtp.point  dtp+0   dtp+1 rtp.point  rtp+0  rtp+1
   1 8019  32793    114   1024        0        0   1024        0        0
   2 002F     47    102   1024        0        0   1023      114        0
   3 0012     18   8078   1024        0        0   1023      114        0
   4 0036     54   8080   1024        0        0   1023      114        0
   5 0080    128   8086   1024        0        0   1023      114        0
   6 0036     54   8088   1024        0        0   1023      114        0
   7 0070    112   8094   1024        0        0   1023      114        0
   8 803A  32826   8096   1024        0        0   1023      114        0
   9 002F     47    238   1024        0        0   1022     8096      114
  10 80E9  33001   8074   1024        0        0   1022     8096      114
  11 0012     18   8054   1024        0        0   1021     8074     8096
  12 0036     54   8056   1024        0        0   1021     8074     8096
  13 0071    113   8062   1024        0        0   1021     8074     8096
  14 8046  32838   8064   1024        0        0   1021     8074     8096
  15 8045  32837    326   1024        0        0   1020     8064     8074
  16 0012     18    314   1024        0        0   1019      326     8064
  17 0036     54    316   1024        0        0   1019      326     8064
  18 0074    116    322   1024        0        0   1019      326     8064
  19 0020     32    324   1024        0        0   1019      326     8064
  20 0020     32    328   1024        0        0   1020     8064     8074
  21 80A3  32931   8066   1024        0        0   1021     8074     8096
  22 0036     54   3884   1024        0        0   1020     8066     8074
  23 0012     18   3890   1024        0        0   1020     8066     8074
  24 016E    366   3892   1024        0        0   1020     8066     8074
  25 0020     32   3898   1024        0        0   1020     8066     8074
  26 808F  32911   8068   1024        0        0   1021     8074     8096
  27 0097    151   3626   1024        0        0   1020     8068     8074
  28 0065    101   3628   1022        0        2   1020     8068     8074
  29 0020     32   3634   1024        0        0   1020     8068     8074
  30 80E8  33000   8070   1024        0        0   1021     8074     8096
  31 0261    609   8046   1024        0        0   1020     8070     8074
  32 80E7  32999   8048   1022        0 4224635920   1020     8070     8074
  33 80E6  32998   8040   1022        0 4224635920   1019     8048     8070
  34 001A     26   8026   1022        0 4224635920   1018     8040     8048
  35 006B    107   8028   1022        0 4224635920   1016        0        0
  36 00A5    165   8032   1024        0        0   1016 4224635920        0
  37 0095    149   8036   1022        0     8034   1016 4224635920        0
  38 0022     34   8038   1020        0        0   1016 4224635920        0
  39 0122    290   8042   1020        0        0   1019     8048     8070
  40 0020     32   8044   1022        0     8034   1019     8048     8070
  41 0122    290   8050   1022        0     8034   1020     8070     8074
  42 0020     32   8052   1024        0        0   1020     8070     8074
  43 0020     32   8072   1024        0        0   1021     8074     8096
  44 0020     32   8076   1024        0        0   1022     8096      114
  45 00A5    165   8098   1024        0        0   1023      114        0
  46 803C  32828   8122   1022       20     8100   1023      114        0
  47 002F     47    246   1022       20     8100   1022     8122      114
  48 001A     26   5802   1022       20     8100   1022     8122      114
  49 006E    110   5804   1022       20     8100   1020     8070     8074
  50 0015     21   5808   1024        0        0   1020       20     8074
  51 00ED    237   5810   1022        0        1   1020       20     8074
  52 0022     34   5830   1024        0        0   1020       20     8074
  53 00A5    165   8124   1024        0        0   1023      114        0
  54 00C1    193   8142   1022       14     8126   1023      114        0
$$COLD_FORTH
  55 0020     32   8144   1024        0        0   1023      114        0
  56 80F4  33012    116   1024        0        0   1024        0        0
  57 00A5    165   8594   1024        0        0   1023      116        0
  58 8083  32899   8612   1022       14     8596   1023      116        0
  59 0012     18   3510   1022       14     8596   1022     8612      116
  60 004E     78   3512   1022       14     8596   1022     8612      116
  61 00EC    236   3518   1020        0        0   1022     8612      116
  62 0096    150   3524   1022       14     8596   1022     8612      116
  63 026D    621   3526   1020        0        1   1022     8612      116
Hello by mind8
  64 0020     32   3528   1024        0        0   1022     8612      116
  65 0020     32   8614   1024        0        0   1023      116        0
  66 801A  32794    118   1024        0        0   1024        0        0
  67 002F     47    106   1024        0        0   1023      118        0
  68 00A5    165   8172   1024        0        0   1023      118        0
  69 00C1    193   8186   1022       10     8174   1023      118        0
実行終り
  70 801B  32795   8188   1024        0        0   1023      118        0
  71 002F     47    110   1024        0        0   1022     8188      118
  72 00A5    165   8146   1024        0        0   1022     8188      118
  73 00C1    193   8168   1022       18     8148   1022     8188      118
実行終り時の処理
  74 0020     32   8170   1024        0        0   1022     8188      118
  75 0012     18   8190   1024        0        0   1023      118        0
  76 004E     78   8192   1024        0        0   1023      118        0
  77 0014     20   8198   1022        0        0   1023      118        0
例外がスローされました: 'Mind8Kernel.Dispatcher.ExitModule' (mind8dispatch.dll の中)
プログラム '[13292] mind8dispatch.dll' がコード 0 (0x0) で終了しました。

とりあえず「空列と」を書いた場合の文字列実体の扱いに問題がありそうであることがわかりました。

つづく

この記事を書いている途中では文字列実体のアドレッシングがどのようにまずいのかは未確認ですが、引き続き調査を行って参ります。次回解決編に乞うご期待?

補足

level6(改、改2でないやつ)のC#代替ディスパッチャ実行リストとCディスパッチャ実行リストを、停止する直前あたりで比較してみました。

level6 C#代替ディスパッチャ実行リスト

SqNo mcode mc(dec) mpoint dtp.point  dtp+0   dtp+1 rtp.point  rtp+0  rtp+1
   1 8019  32793    114   1024        0        0   1024        0        0
   
  31 80E7  32999   8050   1022        0 2322422464   1020     8070     8074
  32 80E6  32998   8042   1022        0 2322422464   1019     8050     8070
  33 001A     26   8026   1022        0 2322422464   1018     8042     8050
  34 006B    107   8028   1022        0 2322422464   1016        0        0
  35 0052     82   8032   1024        0        0   1016 2322422464        0
  36 0A74   2676   8034   1024        0        0   1016 2322422464        0
例外がスローされました: 'System.IndexOutOfRangeException' (mind8dispatch.dll の中)

level6 Cディスパッチャ実行リスト

SqNo mcode mc(dec) mpoint dtp.point  dtp+0   dtp+1 rtp.point  rtp+0  rtp+1
   1 8019  32793    114   1024 1869567068  6058860   1024        0        0
   
  31 80E7  32999   8050   1022        0  4646640   1020 13987390 13987394
  32 80E6  32998   8042   1022        0  4646640   1019 13987370 13987390
  33 001A     26   8026   1022        0  4646640   1018 13987362 13987370
  34 006B    107   8028   1022        0  4646640   1016        0        0
  35 0052     82   8032   1024 1869567068  6058860   1016  4646640        0
  36 0095    149   8038   1022        0 13991628   1016  4646640        0

mcode 0052の実行結果が異なっていることがわかります。006Bでデータスタックの状態が異なっているように見えるのは初期状態の違い(C#は先頭値、Cは末尾アドレスが初期値)のようでした。

C#代替実装のmcode 0052を確認してみますと、関数定義だけで中身は実装されていませんでした。他のスタックマクロは何とか解釈できたと思って実装してあるのですが、0052だけマージンの解釈に戸惑い保留としていたようです。

CsFunctionsCompword.cs
        /*---------------------  変数の直接読み出し  ----------------------*/
        private void ZzReadBvar(){
                /* Mコード=0x004C */
            // UCHAR  *varAddr;
            // varAddr = DataBase + FETCH_MCODE_LONG;
            // PUSH_L( *varAddr );
            // PUSH_F( 0 );
            ap.ResetDataIndex(mp.FetchMcodeInt());
            dtp.PushUl(ap.GetUb());
            dtp.PushUl(0);      
        }
        private void ZzReadWvar(){
                /* Mコード=0x004D */
            // USHORT *varAddr;
            // varAddr = (USHORT *)(DataBase + FETCH_MCODE_LONG);
            // PUSH_L( *varAddr );
            // PUSH_F( 0 );
            ap.ResetDataIndex(mp.FetchMcodeInt());
            dtp.PushUl(ap.GetUs());
            dtp.PushUl(0);       
        }
        private void ZzReadDvar(){
                /* Mコード=0x004E */
            // LONG   *varAddr;
            // varAddr = (LONG *)(DataBase + FETCH_MCODE_LONG);
            // PUSH_L( *varAddr );
            // PUSH_F( 0 );
            ap.ResetDataIndex(mp.FetchMcodeInt());
            dtp.PushUl(ap.GetUl());
            dtp.PushUl(0);
        }
        private void ZzReadLvar(){
                /* Mコード=0x004F */
            // ULONG   *varAddr;
            // varAddr = (LONG *)(DataBase + FETCH_MCODE_LONG);
            // PUSH_L( varAddr[0] );                   /* push low  double */
            // PUSH_L( varAddr[1] );                   /* push high double */
            ap.ResetDataIndex(mp.FetchMcodeInt());
            dtp.PushUl(ap.GetUl());
            dtp.PushUl(ap.GetUl());
        }
        private void ZzReadQvar(){
                /* Mコード=0x0050 */
            // ULONG   *varAddr;
            // varAddr = (LONG *)(DataBase + FETCH_MCODE_LONG);
            // PUSH_L( varAddr[1] );                   /* push high double */
            // PUSH_L( varAddr[0] );                   /* push low  double */
            ap.ResetDataIndex(mp.FetchMcodeInt());
            uint var=ap.GetUl();
            dtp.PushUl(ap.GetUl());
            dtp.PushUl(var);
        }
        private void ZzReadSvar(){
                /* Mコード=0x0051 */
            // ULONG  *varAddr;
            // varAddr = (ULONG *)(DataBase + FETCH_MCODE_LONG);
            // PUSH_A( varAddr[1] );                   /* push address */
            // PUSH_C( varAddr[0] );                   /* push length  */
            ap.ResetDataIndex(mp.FetchMcodeInt());
            uint length=ap.GetUl();
            dtp.PushUl(ap.GetUl());
            dtp.PushUl(length);
        }
        private void ZzReadJvar(){
                /* Mコード=0x0052 */
            // ULONG  *varAddr;
            // ULONG   length;
            // ULONG   margin;
            // varAddr = (ULONG *)(DataBase + FETCH_MCODE_LONG);
            // length = *varAddr++;
            // margin = *varAddr++;
            // PUSH_A( (UCHAR *)varAddr + margin );    /* push address */
            // PUSH_C( length );                       /* push length  */
        }
        /*---------------------  局所変数の直接読み出し  ---------------*/

これは(関数枠だけで中身なし)実行時に例外をスローしないのでちょっと危険な状態ですね。保留にしたときもそのように思っていましたが、いま思えばだいぶ長丁場になっているのでこの状態にある関数がどれかとか忘れてしまっていたようです。
関数枠だけあって中身無しの場合は未定義例外などアプリケーション例外をスローしておくとよさそうです。

また、記述済のコードも妥当性は未確認なので、今後書き直される可能性が大きくあります。

1
0
2

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
1
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?