カテゴリー: Development

StringBuilderってどうよ?

StringBuilderの効果ってどうなのか?というところに疑問を持ったので、調べてみることにした。

Javaの文字列結合はStringBuilderでいいのか

結論的には、

・複数ステートメントで
・結合される側の文字列を複数スレッドで共有しない場合は
メモリアロケーションの回数が少ないStringBuilderが一番高速で文字列結合できる

なのだが、どのような処理になっているのでこうなる!というのが書かれていて、非常に参考になった。

スレッドを使ったときは不具合が起きるというのは、以下のページに書いてある。

【Java】+演算子、StringBuilder、StringBufferの違い(実際に測ってみた。)

StringBuilderとStringBufferの使い分けについても書いてあるので、これも参考に。

以下はVB(.NET)のStringBuilderについての記載。

Visual Basic で StringBuilder を使うべき場合とその利点

こちらもJavaと同じような話。(SE2年目でこの記載は凄いなぁ。うちの社員にもこういう人欲しい。)

使い方については、

意外と知られてないStringBuilderに関する初歩的なTips【Java・C#】

なんか、どうでしょう。
インスタンスをコロコロ変えたくないなぁと思っているので、こういうのはありがたい。

が、少し待て!

男(かどうか知らんが)がすなる時間計測といふものを女もしてみむとてするなり・・・

VC#(.NET Framework4.8)でやってみた。
<1> Length=0でクリアする
<2> 新たなインスタンスを作る
<3> Clearを使う(C#はClearメソッドがある)

        static void Main(string[] args) {
            var sw = new System.Diagnostics.Stopwatch();

            // <1>
            for (int j = 0; j < 10; j++) {
                sw.Start();
                StringBuilder sb1 = new StringBuilder("");
                for (int i = 0; i < 999999; i++) {
                    sb1.Length = 0;
                    sb1.Append(i.ToString());
                }
                sw.Stop();
                Console.WriteLine($"1) {sw.ElapsedMilliseconds}ms");
            }

            // <2>
            for (int j=0;j<10;j++) {
                sw.Restart();
                for (int i = 0; i < 999999; i++) {
                    StringBuilder sb2 = new StringBuilder("");
                    sb2.Append(i.ToString());
                }
                sw.Stop();
                Console.WriteLine($"2) {sw.ElapsedMilliseconds}ms");
            }

            // <3>
            StringBuilder sb3 = new StringBuilder("");
            for (int j = 0; j < 10; j++) {
                sw.Restart();
                for (int i = 0; i < 999999; i++) {
                    sb3.Clear();
                    sb3.Append(i.ToString());
                }
                sw.Stop();
                Console.WriteLine($"3) {sw.ElapsedMilliseconds}ms");
            }
        }

結果発表!

<1> Length=0でクリアする <2> 新たなインスタンスを作る <3> Clearを使う
1) 693ms 2) 1440ms 3) 583ms
1) 1303ms 2) 1495ms 3) 503ms
1) 2398ms 2) 1455ms 3) 472ms
1) 3421ms 2) 1401ms 3) 514ms
1) 4656ms 2) 784ms 3) 520ms
1) 5780ms 2) 692ms 3) 500ms
1) 6798ms 2) 580ms 3) 498ms
1) 7786ms 2) 599ms 3) 519ms
1) 8868ms 2) 553ms 3) 485ms
1) 9937ms 2) 643ms 3) 469ms

<1> Length=0でクリアだと、処理速度がどんどん上がっていくので、嫌な感じ。
<2> 新たなインスタンスを作るは、<1>より速くて<3>と同等かもしくは遅いレベル。
<3> Clearを使うのが一番コンスタントに速い。

Javaは試していないので申し訳ないのだが、VC#ならば、用意されているClearメソッドを利用したほうがインスタンスを毎度作るよりは速いということになる。

色々調べてみるものだ、うん。
「無知の知」というのは大事だなぁと思う午後のひと時であった・・・

AccessVBA覚書 Public変数が変わらない

Accessは嫌いです。
理由はわかんないから。

オイオイ・・・

って、そんな理由かい!って思う人もいるのだろうけど、わからないというのは
・想定通り動いてくれない
・Debugしながら動かしたときと、Debugしないで動かしたときで動作が変わる
という2点からだ。

この間VB6のソースを見ていた時も実は同じようなことがあって、
・Debugしながら動かしたときと、Debugしないで動かしたときで動作が変わる
というのは、どうしたらいいのかさっぱりわからないのだ。

そして、VBAをDebug.Printを使って変数値を見ながら実行させてみたらば、Public変数に値を入れているのに値が置き換わっていないことが判明。

で、調べてみたらこんな記事があった。

Public宣言された変数の有効期間 [VBA]

なるへそ。
ってかさ、別に参照設定とかPublic変数を変えたとか、致命的なエラーが出たとかなら、リセットされるのはわかりますよ。
でもね、実行中にリセットする必要ありますか?

何のためのPublic変数なんですか!!!!

と。

で、上述の記事でテーブルに入れるのがいいと書いてあったので、結局その通りいたしました。
Excelでこんなこと起きたことはないんですけどね。
でも起きたことがないだけで、起きることがあるんだと思うとExcelのマクロも作れませんな・・・

大丈夫かMicrosoft。

ExcelVBA覚書 CSV読込とSchema.ini

CSVファイルを読み込むときに、ADODBを使って読み込むやり方というのがあって、これには
1,ADODB.Streamを使う
2,ADODB.CommandとADODB.RecordSetのGetStringを使う(SELECT * FROM [{ファイル名}])
という2種類の方法があるというので、サンプルを実行してみたら、
1より2のほうが若干処理が速い。
ただ、2には落とし穴があって、それは
★勝手に型を変えてしまう
★読み込み方によっては正しくすべてのデータが取り込めない
ということだと分かった。

前0がついていようが数値にしよるし、日付は勝手に日付型でシートに出力されてしまうは、設定の仕方によっては思い通りのデータ取込ができなくなってしまう。

ってかさ、こんないい加減なサンプル送ってくんなよ!!
(他のところで実行時エラー起きてるし・・・)

ってなことであったが、どうすれば改善できるのか知らない私。
いろいろやってみて途方に暮れたところでGoogle先生の厄介になってみたら、

Schema.ini使うんです!

みたいな記事発見。で、「ADODB Schema.ini」で検索をかける。
ふむふむ、取り込む列の型とか、文字エンコードとか、このファイルの中で指定してあげればよいのだね!
————-
[{ファイル名}]
ColNameHeader=False
CharacterSet=65001
Format=CSVDelimited
Col1=列1 Text
Col2=列2 Text
Col3=列3 Text
Col4=列4 Text
Col5=列5 Text
—————
{ファイル名}は実際に読み込むファイル名(パスはなしで、ファイル名だけでいい)
ColNameHeader は、ヘッダー有無。(Trueはあり)
Format=CSVDelimited は、CSV形式(カンマ区切り)
CharacterSet=65001 は文字エンコードがUTF-8である。(S-JISなら932)
下に読み取り用のサンプルソースをつけているが、そこでCharacterSetを指定しているので,iniには必要ない。
(どちらかに設定があればOK)
Col1=*** の *** は、列のタイトル、その右のTextが型

【VBA】ADOを使用してテキストファイル(CSV)をDB操作する方法のまとめ

を参照したところ、型は整数はShortやLong、日付はDateと記載されている。
Char型で50文字なら、「Char Width 50」といったように記載されているので、固定長であればこういう記載になるのかと思う。
(試してはいない)

で、このSchema.iniをcsvファイルのあるフォルダパスと同じところに入れておくのだが、

チョイ待ち!!

読み込むcsvファイルが常に同じところに置かれているとは限らんではないか!
ということになった。
そう、読み込むCSVは、ダイアログで選ばせるのだ・・・
となると、csvと同じところにschema.iniを配置させねばファイルの意味がないし、いや、そもそもダイアログで選ぶファイル名もSchema.iniで定義したファイル名と異なっていたら読み込んでくれへんやん!!!

と、また1つ問題が生じてしまった。
ということで、最終的には、

a) 一時保存用のフォルダを作る
b) a)で作ったフォルダにSchema.iniを入れる
c) ダイアログで選択されたCSVファイルを a)で作成したフォルダに固定のファイル名にコピーする
  (固定のファイル名というのが、Schema.iniに定義する{ファイル名}と同じになるように)
d) c)のコピーされたほうのファイルをADODBでSELECTして読み込む
e) 読込が終わったら、c)のコピーされたほうのファイルを削除

として、どの場所にあっても、同じフォーマットで取り込まれるようにしたのだった。
ってなると、ADODB.Streamを使うより時間がかかってしまったので、結局Streamのほうが速い!という結論に至った。

とはいえ、CSVファイルの全データが取得できなかった点も、Schema.ini、Properties(“Extended Properties”)や、GetStringメソッドを見直して何とかとりあえずうまく行くようにはなった。
Officeは2016。

    Dim con As ADODB.Connection
    Dim cmd As ADODB.Command
    Dim rs  As ADODB.Recordset

    Set con = New ADODB.Connection
    With con
        .Provider = "Microsoft.ACE.OLEDB.12.0"
        .Properties("Extended Properties") = "Text;CharacterSet=65001;"    '65001=UTF-8 ,932=SJIS
        .Open {csvファイルのあるフォルダパス}
    End With
    Set cmd = New ADODB.Command
    Set cmd.ActiveConnection = con
    cmd.CommandText = "SELECT * FROM [{CSVファイル名}] "
    Set rs = New ADODB.Recordset
    rs.CursorType = adOpenStatic
    rs.Open cmd
    
    Dim dmp As String
    dmp = rs.GetString(adClipString, , ",", vbCrLf, "")  '行はCRLF, 列はカンマで区分するという設定に
    rs.MoveFirst
    Do Until rs.EOF
        '****** 1行分の処理を記載 ***********  
        rs.MoveNext
    Loop
   
  ’どばっとExcelに貼りつけるなら、Range.CopyFromRecordsetメソッドで 
    ' Activesheet.Cells(1,1).CopyFromRecordset rs            みたいな感じ

   rs.Close
    Set rs = Nothing
    Set cmd = Nothing
    con.Close
    Set con = Nothing

GetString メソッド (ADO)

中途半端なサンプルを送りつけられたせいで悩んだが、かえっていい勉強になったわぃ!
ということにしておこう。

VB.NET覚書 バックグラウンドプロセスからExcelが消えない

VB2019で、ライブラリMicrosoft.Office.Interop.Excelを使ってExcel出力を行っている。
Officeは2019だ。
COMオブジェクトなので、ReleaseComObjectでメモリ解放をしているのだが、

だが、処理が終わってもバックグラウンドプロセスからExcelが消えない・・・

リリースしてまっせ!
と思うのだが、何故か残る。

というので調べた。

・Rangeとか変数定義してるところ、リリースしてる?
 全部リリースするのよ!
・リリースはしてても時差があったりするよ!

んーーーーーー、そっか。でも頑張ってBookもSheetもRangeも処理いれたんだけど。

ということで、最後。ReleaseComObjectをぐるぐる回す。

<参照サイト>
ドリリウム『【Interop.Excel】Excelプロセス絶対殺すコード』

このサイトのWhileでReleaseComObjectを回してリリースさせるようにする!っていうのをやってみた。
とりあえず、残らなくなった気がする・・・
気がする。(ちょっと不安やけど)

Linux覚書 yum update の取り消し

yumのupdateをしたほうがいいよ~、みたいなメッセージが出てたので、updateしたらばWebアプリの調子がおかしくなった。
しまった!、もうイチから入れなおさなあかんかなぁと思っていたが、調べてみるとupdateの巻き戻しができるようなのでやってみた。

sudo yum history

とコマンドを打って、まず履歴をチェック。

履歴がリストで出てくるので、左端にある番号、update日時からキャンセルする番号を確認。
キャンセルする番号が5ならば、

sudo yum history undo 5

とコマンドを打って実行。
途中最終確認でy/nを聞いてくるので、問題がなければyキーを打つ。

処理が正常に済んだらOK。

Webアプリとサーバを再起動させたら、update前のようにWebアプリがちゃんと動くようになった。
めでたしめでたし・・・

Qiita yumでインストールしたパッケージを取り消す

GoogleChrome画面が真っ黒に

なった・・・
真っ黒。何もできない・・・、けど右上をクリックするとちゃんとChromeが閉じる・・・

で、Windowsを再起動してもうまくいかず。
色々調べて、最終的にはショートカットのリンク先にパラメータを渡して解決。

“C:\Program Files (x86)\Google\Chrome\Application\chrome.exe” -disable-gpu

この「-disable-gpu」をつけることでとりあえずはなんとか普通に表示されるようになった。

ORACLE覚書 階層データを引数として渡す

サマリ1
 |– 明細1-1
 |– 明細1-2
サマリ2
 |– 明細2-1

のような、階層のあるデータを引数で渡したいと思って、調べてみたらオブジェクト型なるものを発見。

で、実際にどうやって実装すればいいのか、また調べて実行。

<手順>
1, まずはCREATE TYPEでもって、任意のオブジェクト型を作ってみる。

・明細データの型を作る。(Javaでいうと、データクラスみたいなもの)

CREATE TYPE DTL_TYPE AS OBJECT (
   DTL_ID   VARCHAR2(5)
   DTL_NAME VARCHAR2(10)
);

・次に作った明細(DTL_TYPE)のテーブルを型にする。(JavaでいうとList<明細>みたいなもの)

CREATE TYPE DTLTAB_TYPE AS TABLE OF DTL_TYPE;

・明細が済んだら次はサマリも同じように型を作る。

CREATE TYPE SUM_TYPE AS OBJECT (
  SUM_ID   VARCHAR2(5)
 ,SUM_NAME VARCHAR2(20)
 ,DTL      DTLTAB_TYPE
);
CREATE TYPE SUMTAB_TYPE AS TABLE OF SUM_TYPE;

2, 試しに作ったオブジェクト型を引数に、関数を作ってみる

---------------------------------------
-- 明細データをカンマ区切りで取得
---------------------------------------
CREATE OR REPLACE FUNCTION OTAMESHI_FUNC(
  PARAM IN SUMTAB_TYPE 
) 
RETURN VARCHAR
IS
  TEMP    VARCHAR(1000);
BEGIN
  -- サマリをぐるぐる回す
  DECLARE
  CURSOR CURSUM IS SELECT SUM_ID, SUM_NAME, DTL FROM TABLE(CAST(PARAM AS SUMTAB_TYPE));
  CURSUM_ROW CURSUM%ROWTYPE;
  BEGIN
    OPEN CURSUM;
    LOOP
      FETCH CURSUM INTO CURSUM_ROW;
      EXIT WHEN CURSUM%NOTFOUND;

      TEMP := TEMP || ',<<' || CUR_ROW2.SUM_ID || ':' || CUR_ROW2.SUM_ID || '>>';
      
      -- 明細をぐるぐる回す
      DECLARE
      CURSOR CUR IS SELECT DTL_ID, DTL_NAME  FROM TABLE(CAST(CURSUM_ROW.DTL AS DTLTAB_TYPE));
      CUR_ROW CUR%ROWTYPE;
      BEGIN
        OPEN CUR;
        LOOP
          FETCH CUR INTO CUR_ROW;
          EXIT WHEN CUR%NOTFOUND;

          TEMP := TEMP || ',' || CUR.DTL_ID || ':' || CUR.DTL_ID;

        END LOOP;
      END;


    END LOOP;
  END;

  -- TEMPに入れたデータを返す
  RETURN TEMP;
EXCEPTION
  WHEN OTHERS THEN
    RETURN 'エラーです.';
END;

3, 作った関数を呼び出してみる

SELECT
  OTAMESHI_FUNC(
      SUMTAB_TYPE(
        SUM_TYPE('01'
               , 'まさか'
               , DTLTAB_TYPE(
                             DTL_TYPE('A1','やさか')
                            ) 
               )
       ,SUM_TYPE('02'
               , 'どうか'
               , DTLTAB_TYPE(
                             DTL_TYPE('D1','ぎんか')
                            ,DTL_TYPE('B1','きんか')
                            ) 
               )
     )
  )
FROM DUAL

できるのは解ったのだが、う~ん、どうなんだろう。

Alexa覚書 Display表示

Displayを使ってみたくなってスキルを改修して申請したのだが、審査でNGになってしまった。

う~ん、Display表示の要素を足しただけなのになぁ・・・と思っていたら、ただ足しただけではダメっぽかった。
すいません、リファレンス読んでません。

Alexa Skills Kit Displayインターフェースのリファレンス

Qiita『Alexa ディスプレイ端末対応時にセッションをクローズする時の注意点』

審査でNGになってわかったのは、

・スキルの継続・終了とセッションの維持・破棄を明示的に合わせておくこと。
・セッションを維持させる場合は、維持させることがわかるような発話をすること。 (例えば、「ほかにないですか?」とか「もう一度教えて」とか)

で、何とか審査はパス。
お手数おかけしました。

コマンドプロンプト覚書 ゴミ箱を空に

HDDの容量を圧迫しているごみ箱の中身を削除したいのに、なんだかGUIでやると全然動作しない・・・
空にしますか?とも聞いてこない・・・

で、何とかならないのかと思ったら、コマンドプロンプト上でコマンドを打てばよいとのこと。

Cドライブのごみ箱なので、

rd /s c:\$Recycle.Bin

でやってみた。
でけた。

PowerShell覚書 ファイル操作いろいろ

最近、VBSよりPowerShellのほうをよく使うようになった。
イケてないところは多々あるものの、デバッグもしやすいので便利だ。

ファイル操作のアレコレをこの投稿にいろいろ書き足していこうと思う。
(アレコレって、漢字だと「彼是」って書くのね。知らんかった。)

【ファイル検索】
例えば、「Cドライブ」直下のファイルを漁りたいときはこんな感じ。
Get-ChildItemの戻り値を「 」(半角スペース)でSplitしてやれば、ファイル名のリストを取得できる。

$dir = "C:\";
$files = Get-ChildItem $dir;
$files_arr = $files -split " ";

【フォルダ検索】
「W」で始まる「Cドライブ」直下のディレクトリを漁りたいときはこんな感じ。
Get-ChildItemの戻り値を「 」(半角スペース)でSplitしてやれば、ディレクトリ名のリストを取得できる。
Where-Object で、「$_.PSIsContainer」を指定すればディレクトリだけを取得できる。

$dir = "C:\";
$subdir = Get-ChildItem $dir | Where-Object { $_.PSIsContainer } | Select-String "^W";
$sub_arr = $subdir -split " ";

【フォルダ・ファイル有無確認】
指定フォルダ、ファイルがあるかどうかは「Test-Path」を使う。

if (Test-Path ($dir)) {
   # あるとき
} else {
   # ないとき
}

【フォルダ作成】
フォルダ作成は「New-Item」で、パスを指定して、「-ItemType Directory」のオプションをつける。
「-Force」はすでにフォルダがあるときは、エラーにならないようにするときにつける。

New-Item $dir -ItemType Directory -Force;

【ファイルコピー】
ファイルコピーは「Copy-Item」で、コピー元のパスを指定して、「-Destination」でコピー先を指定する。
「-Force」はすでにコピー先にファイルがあっても、エラーにならないようにするときにつける。

Copy-Item $src_path -Destination $goto_path -Force;

【ファイル移動】
ファイル移動はコピーしてから削除するのがいい。
「Remove-Item」の「-Recurse」は削除対象がフォルダであれば、中のファイルを削除してからフォルダも消してくれる。
「-Force」をつければ、隠しファイルとかも消してくれるそう。

Copy-Item $src_path -Destination $goto_path -Force;
Remove-Item -Path $src_path -Recurse -Force;

【ライブラリ利用】
ライブラリは、パスを指定して読み込んでやらないと使えない。こんな感じ。

[string]$dll       = "C:\....\.....dll";
[void][reflection.assembly]::LoadFrom($dll);

PostgreSQL覚書 RETURNIG *

UPDATE、INSERT、DELETE文の最後に「RETURNING *」を加えてやると、「更新件数が返ってくる」というのをネット上で見たのだが、厳密にはどうやらそうではないらしいのでメモっておく。

INSERT .... RETURNING *

と書くとINSERTしたデータ行がすべて返ってくるのであって、件数が返ってくるわけではないのだ。
結局、

INSERT .... RETURNING {キー項目}

みたいに書いて、返ってきたデータの行数から更新件数を導きだす必要があるのだ。
だから、Javaなんかだと、SQL文を実行後のResultSetのgetRowメソッドを使う。
例)

int kensu = rs.getRow();

みたいに、返ってきたデータの行数を取得してやるのだ。

中途半端な日本語を書かれると、こういう勘違いをしてしまう。

JavaScript覚書 JSONパース

仕事でJSONデータをバリバリ使うことになった。
けど、階層が多いからちゃんとデータ設定できているのか気になって、解析しようとJavaScriptで組むことにした。
(本当はExcelのマクロでセルにペタッと出力させたかったのだが)

<body>
    <textarea id="src"></textarea><br>
    <button onclick="javascript:return parseData();">解析</button><br>
    <pre id="res"></pre>
    
    <script>
        var doc = "";
        var indent = "&nbsp;&nbsp;";
        
        // 解析
        function parseData() {
            var srcObj = document.getElementById("src");
            var resObj = document.getElementById("res");
            doc = "";
            resObj.innerHTML = doc;
            
            var json = JSON.parse(srcObj.value);
            convJson(json, "");
            resObj.innerHTML = doc;
        }
        
        // 解析処理本体
        // obj : JSONデータ, caps : 階層表示インデント
        function convJson(obj, caps) {
            if (typeof(obj) == "object") {
                for (var i in obj) {
                    if (typeof(obj[i]) == "object") {
                        doc += caps + "[" + i + "]<br>";
                        convJson(obj[i], caps + indent);   // 下の階層を解析
                    } else {
                        doc += caps + i + " : " + obj[i] + "<br>";
                    }
                }
            } else {
                        doc += caps + i + " : " + obj[i] + "<br>";
            }
        }
    </script>
</body>

Visual Studio 2015 インストーラ他

なんだかもう仕事がいやになりました。
色んなことが進みません。

サーバと接続できないし、Visual Studioもインストールできないし・・・

なんで、最新バージョンしかださず、古いバージョンも簡単に表示してくれないんだ!
必要なんだよ!!!

と、怒っていたが、すんなり行くときはいくもので。
とりあえず2015バージョンのダウンロードページを見つけたので貼っておく。

https://my.visualstudio.com/Downloads?q=visual%20studio%202015&wt.mc_id=o~msft~vscom~older-downloads

結局ダウンロードするには、Microsoftのアカウントが必要・・・

PowerShell覚書 指定IPアドレス+ポート番号で接続確認

Windowsのコマンドプロンプトでpingをたたけば、そのIPアドレスと通信できるかがわかるが、ポート番号まで見てくれはしない。
IPアドレスとポート番号で通信できるか確認するときは、Powershellを使うらしい。

test-netconnection {IPアドレス} -port {ポート番号};

例)

test-netconnection 1.2.3.4 -port 5432;

で、実行すると以下のようなメッセージが返ってくる。

OKの時

ComputerName : 1.2.3.4
RemoteAddress : 1.2.3.4
RemotePort : 8080
InterfaceAlias : Wi-Fi
SourceAddress : 172.22.128.11
TcpTestSucceeded : True ←つながりました!

NGの時

警告: TCP connect to (1.2.3.4 : 3306) failed
警告: Ping to 1.2.3.4 failed with status: TimedOut

ComputerName : 1.2.3.4
RemoteAddress : 1.2.3.4
RemotePort : 3306
InterfaceAlias : Wi-Fi
SourceAddress : *.*.*.*(こっちのアドレス)
PingSucceeded : False  ←ダメでした
PingReplyDetails (RTT) : 0 ms
TcpTestSucceeded : False  ←ダメでした

Windows覚書 タスクスケジュール一覧の取得コマンド

基本

schtasks /query

CSV形式でファイル出力(/Vで詳細まで出力させる)

schtasks /query /V /FO CSV > d:\schtasklist1.csv

CSV形式でファイル出力(/Vで詳細まで出力させる,/NHで列タイトル非表示)

schtasks /query /V /NH /FO CSV > d:\schtasklist2.csv

こう見ると、タスクスケジューラにはいっぱいタスクが登録されているのだなぁ・・・と思った。

Docker覚書 VMWareが使えない・・・のときの対処

VMWare Workstationを起動して、仮想環境を立ち上げようとしたらエラーが出た。

あぁー、Dockerを入れた所為だなぁ・・・
というので、Dockerをアンインストールしようかと思ったが、一旦Dockerを使えなくしてしまう方法を探し、以下の手順でVMWareを無事起動できるようにした。

  1. タスクバーの検索アイコンをクリックして「ローカルグループポリシーの編集」と入れて、ローカルグループポリシーにアクセス
  2. コンピューターの構成>管理用テンプレート>システム>Device Guardを選択し、「仮想化ベースのセキュリティを有効にする」の設定を無効にする。
  3. 次はコントロールパネル>プログラム>Windowsの機能の有効化または無効化をクリック。
  4. Hyper-Vのチェックを外す(下層もすべて外す)
  5. 適用ボタンをクリックすると、再起動するかどうか聞かれるが、ここでは再起動しない。
  6. コマンドプロンプトを念のため管理者権限で開いて、以下のコマンドを打つ。
    (Xドライブを作成するので、Xドライブががないことが前提。もしXドライブがすでにある場合は、「X:」の箇所を別のドライブに変更して実行。)

    mountvol X: /s
    copy %WINDIR%\System32\SecConfig.efi X:\EFI\Microsoft\Boot\SecConfig.efi /Y
    bcdedit /create {0cb3b571-2f2e-4343-a879-d86a476d7215} /d “DebugTool” /application osloader
    bcdedit /set {0cb3b571-2f2e-4343-a879-d86a476d7215} path “\EFI\Microsoft\Boot\SecConfig.efi”
    bcdedit /set {bootmgr} bootsequence {0cb3b571-2f2e-4343-a879-d86a476d7215}
    bcdedit /set {0cb3b571-2f2e-4343-a879-d86a476d7215} loadoptions DISABLE-LSA-ISO,DISABLE-VBS
    bcdedit /set {0cb3b571-2f2e-4343-a879-d86a476d7215} device partition=X:
    mountvol X: /d
    

    PCによっては、以下のコマンドを打つ。

    bcdedit /set hypervisorlaunchtype off  
    

    参考URL「あさまのブログ VMWare仮想マシン起動時に「Device/Credential Guard には互換性がありません。」のエラー解決」

  7. そしてようやくPC再起動。
    (再起動後はDockerは使えなくなる。)

で・・・

これでVMWare Workstationが動くか!と思ったら動かなかった・・・

しょうがないので、VMWare Workstationを再インストール。で、うまくVMWareの仮想環境が起動できた。
ん~、PC再起動でうまくいくって書いてあったんだけど、なんか変なことやらかしたかな。
まぁ、でも取りあえずはVMWareがうまく動いたので一安心。
で、最終的にはDockerをアンインストールしようと思うのだが、なにかうまい手はないか、と思っていたら、VMWare上のLinuxにDockerをいれるという手順を紹介している人がいて、「あぁ、なるほどな」などと感心してしまった。
また時間があったら試す予定。
まだDocker環境上へのDeployを試してない。これが肝心なのに。

Docker覚書 Win10にインストールの巻

そろそろDockerぐらい使えないと!と思って、仕事が暇な今こそ!とチャレンジ。
で、WordpressとMySQLの環境を作って繋げてやろうと意気込んで開始して、後述する手順でうまくいった。

ただ、後から分かったが、同じ環境でVMWare Workstationも使っているので、Dockerを動かしている間はVMWare側は動かせない・・・
しまった!!!
と思いつつ、とりあえずはDockerインストールと環境立ち上げの手順だけの備忘録を投稿。

Windows10でDocker上にWordPressを立ち上げる

  1. Docker CE → Desktop Docker for Windows インストール
  2. Desktop Dockerを起動、Setting
    • スタートメニュー等よりDesktop Dockerを起動
    • タスクバーにDockerアイコンが表示されたらアイコンを右クリックしてSettingをクリック
    • DaemonのExperimentalにチェックしApply
    • NetworkのDNS ServerはFixed:を選択して「8.8.8.8」を設定
    • ResetでRestart Docker…をクリック
  3. コマンドプロンプトを起動
  4. Imageの取込コマンド実行(次のrunコマンド実行でimageがなかったら自動的に取り込むのでここは省略できる。)
    • docker pull mysql:5.7.25
    • docker pull wordpress:latest
    • docker images で取り込めたかどうか確認
  5. コンテナー作成・起動
    • docker run --name test-mysql -e MYSQL_ROOT_PASSWORD=password -d -p 3307:3306 mysql:5.7.25
    • docker run --name test-wordpress --link test-mysql:mysql -d -p 8081:80 wordpress
      • それぞれ、ポート番号は他と被らない番号にしておきます。
    • docker container ls -a  で作成できたかどうか確認
  6. localhost:8081に接続して確認
    • WordPressの初期設定画面が表示されたら、うまく動作していることになる。

うまくいかないパターン

  • DB接続できない
    • MySQLのバージョンがWordpressと噛み合ってないのが原因

他のDockerコマンド

  • docker exec -it {コンテナ名} /bin/bash
    • Linux上でコマンド操作可能に
    • cat wp-config.php で定義ファイル内の確認
  • docker stop {コンテナ名}  コンテナ停止
  • docker start {コンテナ名}  コンテナ開始
  • docker rm {コンテナ名}  コンテナ削除
  • docker rmi {イメージ名}  イメージ削除

他のLinuxコマンド

  • apt update
  • apt install -y vim (WordPressサーバ上で、VIMを利用する場合)
  • apt install -y procps (MySQLサーバ上でMySQLが動作しているか確認で利用)
  • ps aux (プロセス状態確認)
  • mysql -u root -p (MySQL接続)
  • exit (Linuxから抜ける)

Node.js覚書 外部ファイルの変数定義を参照する

Map変数の設定するデータの量が多すぎて、別のファイルに移せないかなぁと思って調べた。

呼出元

変数

var exp = require('./mapxxx.js');
var mapX = exp.data;

呼出先

ここでは、mapxxx.jsとして保存。
変数定義後、exports.ホゲホゲ = 定義した変数 としておけば、呼出元で使えるようになる。

var maps = new Map([
    ['D01', 'DDDDDD'],
    ['E02', 'EEEE'],
    ........
]);

exports.data = maps;

最後の「exports.***」を忘れて、「うまくいかないぃ~」と思っていたが、こんなにあっさりできるとは。

AWS覚書 Lambda関数を作る(2)~コード編集

SDKを入れたZipをアップロードすると、index.jsがないぜ!とエラーが出るので、ファイルツリーの表示欄を右クリックして、New Fileを選択。
できたファイルの名前をindex.jsに変更して、この中に処理を書いていく。
同じ要領で、package.jsonファイルも作っておく。
このとき、node_modulesフォルダとindex.js、package.jsonは同じフォルダ内に配置する。(違う場所に作ってもD&Dでファイル移動できる。)

index.jsサンプル

LaunchRequestHandlerは、呼出名のみ言われたときの処理。
*******IntentHandlerは、*******Intentに引っかかったときの処理。(*******は任意で。)
その他、HelpやErrorのIntentHandlerは処理部分をLaunchRequestHandlerと同じように記載していく。
今回は、DBアクセスなどがないので、軽量SDK「ask-sdk-core」を利用する。

const Alexa = require('ask-sdk-core');

// --------------------------------------------------------------------
const LaunchRequestHandler = {
  canHandle(handlerInput) {
    return handlerInput.requestEnvelope.request.type === 'LaunchRequest';
  },
  handle(handlerInput) {
    return handlerInput.responseBuilder
                       .speak('返答内容')
                       .reprompt('質問内容')
                       .getResponse();
  }
};

// customize intent ***************************
const *******IntentHandler = {
  canHandle(handlerInput) {
    return handlerInput.requestEnvelope.request.type === 'IntentRequest'
      && handlerInput.requestEnvelope.request.intent.name === '*******Intent';
  },
  handle(handlerInput) {
    
    var intent = handlerInput.requestEnvelope.request.intent;
    var dat = intent && intent.slots && intent.slots..*****. && intent.slots.*****.value;
    
    return handlerInput.responseBuilder.speak(speechText)
                                       .withSimpleCard('タイトル', '返答内容')
                                       .getResponse();
  },
};
// customize intent ***************************

const HelpIntentHandler = {
  canHandle(handlerInput) {
    return handlerInput.requestEnvelope.request.type === 'IntentRequest'
      && handlerInput.requestEnvelope.request.intent.name === 'AMAZON.HelpIntent';
  },
  handle(handlerInput) {
      ・・・・(省略)・・・・
  },
};

const CancelAndStopIntentHandler = {
  canHandle(handlerInput) {
    return handlerInput.requestEnvelope.request.type === 'IntentRequest'
      && (handlerInput.requestEnvelope.request.intent.name === 'AMAZON.CancelIntent'
        || handlerInput.requestEnvelope.request.intent.name === 'AMAZON.StopIntent');
  },
  handle(handlerInput) {
      ・・・・(省略)・・・・
  },
};

const SessionEndedRequestHandler = {
  canHandle(handlerInput) {
    return handlerInput.requestEnvelope.request.type === 'SessionEndedRequest';
  },
  handle(handlerInput) {
      ・・・・(省略)・・・・
  },
};

const ErrorHandler = {
  canHandle() {
    return true;
  },
  handle(handlerInput, error) {
      ・・・・(省略)・・・・
  },
};

// --------------------------------------------------------------------
let skill;
exports.handler = async function (event, context) {
    if (!skill) {
      skill = Alexa.SkillBuilders.custom()
                                          .addRequestHandlers( LaunchRequestHandler,
                                                               *******IntentHandler,
                                                               HelpIntentHandler,
                                                               CancelAndStopIntentHandler,
                                                               SessionEndedRequestHandler
                                          )
                                          .addErrorHandlers(ErrorHandler)
                                          .create();
    }

    const response = await skill.invoke(event, context);
    return response;
};

package.jsonサンプル

nameはLambda関数の名前でOK。versionは関数のバージョン。dependenciesに利用するSDKを設定。

{
  "name": "****",
  "version": "1.0.0",
  "private": true,
  "dependencies": {
    "ask-sdk-core": "^2.7.0"
  }
}

処理を記述後、Alexaからの呼出で想定通りの返答がなされていればOK。
もし、うまくいかないときは、Alexa Developer コンソールのテスト画面に表示される「スキルI/O」の「JSON入力」に出力されるJSONをコピーして、Lambda関数のテストイベントの設定に貼り付けてテストしてみる。
すると、結果のログにエラー内容が出力されるので、そのエラー内容で処理の記載を変更してやればよい。