【時短料理ハック】パスタはフライパンで茹でよう

f:id:nurs:20210109141900j:plain:w300

やあ子供たち。パスタ麺を茹でるのはフライパンがお手軽だよ。
理由は

  • フライパンは広く浅く、2次元的な広がりに留まっているので、茹でている間、パスタ麺の束をを意のままに制御し、お湯の中で自在にに躍らせることができる。3次元的に広がってしまったパスタ鍋では、もはやパスタ麺の完全制御は難しく、菜箸をもってしても深いところまでいつまでもかき混ぜる気力が尽きてしまう。
  • パスタ麺をしっかり制御できて、常にお湯の中で躍らせ続けることができるため、パスタ麺が鍋にこびり付くのを防止することができる。
  • 菜箸で麺を躍らせるのは、視覚的にも、手に伝わって来る感覚的にも楽しいため、茹で時間の間、暇をもてあますことはない。
  • パスタ鍋を使う場合よりも、水の量がぐっと少なくて済む。古い集合住宅に住んでいた時は、パスタを茹でる際はいつもミネラルウォーターを使っていたりしたことを思えば、これを節約できることは非常に大きい。キャンプはしないがキャンプ先などでも使えるハックな筈だ。
  • フライパンなので、そのまま食器として食卓に持ってくるのも全然ありだ。さらに菜箸で食べてしまえば、食後の洗い物は鍋と菜箸の二つだけになる。
  • 「パスタ鍋というものがどうしてあるのかというとね」、「たくさんあるお湯の中で麺を躍らせることが大事」だとか、「お湯の中の澱粉濃度が云々、、」とかいう話もあるが、茹で上がり後にパスタ麺表面のぬめりを水で洗い流すので大差ない。

では実際に写真ベースで見ていこう。写真の方がわかりやすいかと思うぞ。

f:id:nurs:20210109141120j:plain:w300
このように長いパスタでもでかいフライパンの中であればすっかり収まってしまう。

f:id:nurs:20210109141211j:plain:w300f:id:nurs:20210109141214j:plain:w300
1分も茹でれば菜箸の言うことは何でも聞くようになる。

f:id:nurs:20210109141220j:plain:w300
このように思いのままに2次元的な広がりの中、自在にパスタ麺を泳がせよう。7分麺とかの場合は途中あくとりが必要になるかも。それは仕方ない。あくとりは一生使えるので買っておこう。

f:id:nurs:20210109141424j:plain:w300
今回は3分パスタなのでこのくらいでいっかと。

f:id:nurs:20210109141551j:plain:w300
水切りをして(一旦、冷水で洗うのもありだ)

f:id:nurs:20210109141328j:plain:w300
さて今回はたまたま台所にあったこちらのお安いソースをかけることにします。

f:id:nurs:20210109141725j:plain:w300f:id:nurs:20210109141753j:plain:w300
フライパンなので2次元的にぐるぐる回しているだけで簡単にあえることができる。

f:id:nurs:20210109141900j:plain:w300
こんな仕上がりに。そしてそのまま食卓に持っていくと。

さて、今日のところはそんなところだよ。チャオ!

Unity+ARKitでハマりました

やあ子供たち。
iPad(第5世代とか6世代とか iOS 13.7など)向けに、
Unity 2020.1.8f1 + ARFoundation 3.15 + ARKit 3.17
を使ってARマーカーに反応してモデルを出すような簡単なアプリを作ろうとしていてとてもハマったことがあってのでメモしておくよ。

「ARKit マーカー」などで検索するだけでたくさん出てくる記事を参考にしながら、ARKitで初めてのアプリを作ろうみたいな手順をやっていくのだが、Unityでエラーなしでビルドして、XCodeでもエラーなしでビルドできて、デバイスにプログラム流し込んで、アプリ実行して、
どきどきしながらカメラをマーカーにかざしてみても何も起きない、ということがありましたよと。

何せ誰もがあちこちで紹介してくれているARFoundation+ARKitを組み合わせて使うその単純な手順が、うまく動かないのだから、もうそれだけで体調が悪くなりそうな事態だ。

バイスであるところのiPadの画面にもエラーも何も出ないので途方にくれて何度もビルド手順をただただ見直した。何度も手順を見直したさ。
、、しかし、原因は手順云々ではなかったのです!
何とありがたいことに、Macとデバイスをつなげた状態でXCodeからアプリを起動すると、XCodeのコンソールでデバイスの状況がわかる、クロスデバッギングのような状態になっているようなのですが、このアプリ実行中のコンソールへの出力内容をよく見てみると下図のようなエラーが出ていました。

f:id:nurs:20201026233026p:plain:w300

エラー文が出れば後はそれをコピペしてググるだけなのでもうこっちのものです。検索結果やいかに。はい、情報あまりない中で、同じような状況のいい質問出してる人がいるのに誰も解決策を出せず迷宮入りしてしまっているこちらのQ&Aみたいなページもありながら、こちらのページの最後の方で人々がWindowsのパスの長さに触れ始めたところ(2019年の8月1日とか同年12月11日とかの書き込み)が目に止まりました。

結論から言うと、WIndowsのファイルパスの文字数制限にやられましたという話だったっぽい。今まではUnityのprojectをデスクトップの中のさらにフォルダ階層3つくらい掘ったところに置いてビルドしていたわけですが、上記のページに書き込みがあるように、Unityのprojectをドライブレター直下の場所に置いてビルドして、それをMacに持っていって、ビルドしてデバイスにプログラム流し込んで、、それだけでした。それだけで、ARマーカー上に指定した3Dモデルが表示されるようになりました。

まこれ、UnityやARKitに限らず、一般的な常識みたいなところに落ち着くのかも知れませんが。あとファイルパスの文字数制限外す裏ワザもあちこちで紹介されてるしね。まそれは今回試してないけど。。(でもその裏ワザ、もうやっちゃうべきなのかも。もう二度とこれで悩まなくてもよくなるように。)

やー、手順の見直しよりもデバッグですよなー何が起きてるのかを教えてくれるわけだから

手順しかすがるものがない状況って、ほんと無力なのでそこで絶望して諦めちゃだめだ!手順がうまくいかない場合は何が問題なのかを探るアプローチも絶対に試すべき!と改めて思った一件でした。
チャオ!

mongodbの練習に区市町村統計表をインポートしてみよう

やあ子供たち。
さあ今日はWindows10な環境にインストールしたmongodbに、ネットからダウンロードしてきた、区市町村統計表のCSVをインポートするの実験だよ。

●食材のダウンロード
では早速やっていきましょう。「東京都 23区 面積 人口」などで検索すると、こちらのページ
がヒットするのでここからCSV形式で区市町村統計表をダウンロードします。すると、ku18rv2310.csv というファイルがダウンロードできますね。区市町村なんだね、おじさんはよく市区町村という言い方を耳にしてきた気がするんですが、どっちでもいいのかな。まそんなことはさておき、以下レシピを実践して行きましょう。

CSVをあえてExcelで開いて上書き保存。
まずダウンロードしてきたCSVを、あえてExcelで開いてですね、上書きしましょう。これをしないとうまくいかないことがあるので、面倒くさがらずにやりましょう。(改行コードが治る感じなのか、ちょっと裏はとってません。一つの事例と思ってください。)

●トップのタイトル行を削除
mongoimportは、トップ1行目はデータ要素ではなく、見出し行として認識してくれるオプションがあるので今回はそれを利用したいと思いますが、見出しの項目名が被っていると怒られるということがあります、で、この一行目の、「区市町村統計表」の後ろにカンマがたくさん続いている行ですね、このカンマがたくさん続くということは、名前のない見出し項目がたくさんあると思われて、このままだと上記理由で怒られてしまいますので、保存しなおしたCSVをメモ帳で開いて、一行目、各列のタイトルが、どれも互いに異なった文字列になるようにしておきます。簡単には、1列目は「a」、2列目は「b」、などとしておけばよいかと思います。(まだメモ帳を閉じてはなりません)

文字コードUTF-8に。
続いて保存です。ファイル>名前を付けて保存で開かれるファイル保存ダイヤログの一番下、右の方にある、文字コードを選べるプルダウンで、UTF-8を選択した上で、保存します。これも上書き保存で大丈夫です。

●mongoDB上にデータベースを作成
テストDBを作成しておきましょう。windowsコマンドラインではなく、mondodbのコマンドラインにて、use testdb とでもしておきましょう。これでtestdbというDBが作成されました。

●mongoimportを使ってインポートを完了!
最後はこの調理し終えたCSVを、mongodbにインポートします。インポートは、mongodb内のコマンドではなくて、mongoimport.exeという、プログラムを使います。Windowsコマンドラインを開いて、mongoimport.exeのあるパスに移動して、以下のようなオプションを指定して、コマンドを実行します。

mongoimport.exe --db testdb --collection tokyo_dist --drop --file C:\Users\XXX\Desktop\local_thing\_excel\ku18rv2310.csv --type csv --headerline

うまくいくと以下のような出力が表示されます。

2020-10-09T11:11:11.337+0900    connected to: mongodb://localhost/
2020-10-09T11:11:11.486+0900    dropping: testdb.tokyo_dist
2020-10-09T11:11:11.530+0900    72 document(s) imported successfully. 0 document(s) failed to import.

●登録状況を確認しよう
はい、これで、testdbという下に、tokyo_dist という名前のコレクションとして、今回の区市町村CSVがインポートできたかと思います。
ちょっと確認してみましょう。

use testdb
db.tokyo_dist.find()

と打って、CSVで見た内容が表示されれば、完璧です。
mongodbのお勉強をする上で、いろいろ試す中で、ちょっと本格的なデータがほしいなというときにですね、このように巷に落ちているCSVファイルを取り込んでみると、便利なこともあるかと思います。
チャオ!

GoogleHomeでアラームに名前をつけたら超便利に使えそうな件

やあ子供たち。
今日はおじさんが最近発見した、GoogleHomeでかんたんに備忘アラームを実現するやり方の自分用メモだよ。(アラームだよ、アラートじゃないよ、東京アラートじゃないよ。東京アラートって何だったんだ。「東京アラート」って笑うわ。何が「東京アラート」だ、赤いライトアップしたかっただけなんじゃないの。)
みんなもGoogleHome、タイマーやアラームを仕掛けて、便利に使っているかと思う。
「オーケーグーグル。明日の10時にアラームをセットして」
という感じにね。

しかし、明日になってみて今日とか昨日しかけたアラームが突然鳴り出すと、あれ、このアラームは、何のアラームだっけ?ということになって、アラームの意味を覚えていればよいが、セットしたのが一日前だったり、何日も前に備忘のためにセットしたアラームだったりすると、何の備忘のためだったっけ?と、忘れてしまうのが人間というものだ。

ところが、例えば
「オーケーグーグル、ホニャララのアラームをセットして」
というと、
そのアラームに名前(タイトル)(この場合は「ホニャララ」)をつけることができる。すると、「はい、アラームの時刻設定は?」という感じで聞いてくるので、そこで、アラームの設定時刻をいつものように普通に告げよう。
(8時とか言うと20時のことかどっちかややこしくなるのでここは確実に午前とか午後とかをつけて時刻を教えよう。19時のように24時間形式の時刻を伝えればより確実だ)

さてこうしておくと何が便利かって、アラームが鳴ったときに、
「オーケーグーグル、何のアラーム?」
と聞くと、「今、鳴っているホニャララのアラームがあります」
と、まあ、日本語はちょっと変(汗)だが、そのアラームのタイトルを教えてくれるというものだ!

これが意味することは、例えば、毎週ゴミ出しのアラームを仕掛けることができて、ゴミ出し時間の例えば30分前に設定しておけば、絶対にゴミ出しするのを忘れないという状況ができあがるというわけさ。

ただ、この機能、ちょっと難があって、例えば「水やり」のアラームをセット、と何度言っても「やり」のアラームをセットしましたとか言うし、あとは、例に出したばかりだけど、「ゴミ出し」のアラームをセットと何度頑張ってみても、はい、「ゴミ」のアラームをセットしましたとしかならない。なんだろう。簡単な単語しか受け付けないのだろうか。ちょっとだけおバカさんなのかしらね?「リンゴ」だとか「ゴミ収集車」だったら、正しくタイトルを登録できた。何かとても簡単な単語、名詞、みたいな言葉しかタイトルにできないのかも知れない。

タイトルがちゃんと設定できたか確認する方法としては、時刻を設定直後に、~のアラームを設定しましたというので、そこでダメだと分かれば、「オーケーグーグル、~のアラームを取り消し」といって、すぐさま取り消し、別のもっと簡単な単語のタイトルを試してみればいい。

まそうやって、何日か前、あるいは毎週の定期的なタスク、あるいは特定の日時にすべき大事な準備など、すべてこのタイトルつきアラームにしてしまって、アラームが鳴って驚いたときに「オーケーグーグル、何のアラーム?」と聞けば、それが何のアラームだったかを教えてくれるというわけだ。

人間何かを忘れている時って、文字通り「忘れて」いるのだから、ちょうどそのタイミングで実際に「言って」もらわないと、もしくは「気づかせて」もらわないとだめな場合ってよくあるので、音声で突然しらせてくれるこの機能はとても重宝すると思うのだが、いかがだろうか。
ただし、同じGoogleHomeのショッピングリスト機能みたいに、アラームのタイトルにも、もっとふつうに長い文章を入れられればよいの思うのだけど。
以上、チャオ!

c++ StrtokNeoを作ったよ。

やあ子供たち。おじさんは古い人間なので、文字列をトークンに分解しようと思った時、どうしてもC言語のstrtokを使いたくなってしまうわけだが、strtokの仕様上、区切り文字が連続できた場合は丸ごと読み飛ばしてしまうということがあり、これがためにCSVを読み込む処理を簡単に書くことができないという何とも不器用な現実があった。(CSVでは空のカラムがあった場合、カンマが連続することがあるからね)。昨今でC++で文字列のトークン分解というと、決まってstringstreamとgetlineを使うのがお決まりとなっているが、例えば10万行、100万行のCSVファイルを、できるだけ、何事もなかったかのような時間で処理したいというケースではやはりそういう手段はとりたくないというケースがあるわけなんだね。
とはいえ、strtokはあまりに不器用だ。ならば大した処理ではないし、作ってしまおうというわけで、StrtokNeoを紹介するぞ。ソースは以下のようだよ。
(VisualStudio 2017, 2019、そして、codepadで、動作を確認済み。codepadの場合はnullptrをNULLにしたり、使用例コードmainの中の各種ラムダを関数化する必要あり。)

//
//  strtok_neo.hpp by @nursmaul
//      [https://nurs.hatenablog.com/entry/2020/07/08/024652]
//
#define  _CRT_SECURE_NO_WARNINGS
#include <iostream>


class StrtokNeo
{
public:
    // aa,,bb,,,0,,
    StrtokNeo(char* line, const char* dlmtrs)
    {
        _q = nullptr;
        _p = line;
        _dlmtrs = new char[strlen(dlmtrs)+1];
        strcpy(_dlmtrs, dlmtrs);
        _tmp='\0';
    }
    ~StrtokNeo(void)
    {
        delete [] _dlmtrs;
    }
    const char* get_token()
    {
        if (_q != nullptr) {
            *_q = _tmp;
        }
        if (_p == nullptr) {
            return nullptr;
        }
        _q = _p;
        const char* result = _p;
        while (!0)
        {
            if (*_q == '\0')
                break;
            bool thats_it = false;
            for( const char* ich = _dlmtrs; *ich!='\0'; ++ich)
            {
                if (*_q == *ich) {
                    thats_it = true;
                    break;
                }
            }
            if (thats_it)
                break;
            ++_q;
        }// while
        if (*_q != '\0')
            _p = _q + 1;
        else
            _p = nullptr;
        _tmp = *_q;
        *_q = '\0';
        return result;
    }
    char* _p;
    char* _dlmtrs;
    char _tmp;
    char* _q;
};

使い方は以下のようだ。

int main(void)
{
    auto StrtokNeoHelper = [](char* ss)
    {
        // 検索対象文字列と、デリミタ文字列とを指定
        StrtokNeo sn(ss, ",+=\"");
        // あとはget_token()を順次呼び出して各トークンを取得。(NULLがかえれば終了)
        while (const char* p = sn.get_token())
            std::cout << "-->" << p << "<--" << std::endl;
        std::cout << std::endl;
    };

    //トークン切り出し結果の出力
    char aa[] = "aaa,+=,COOH+AAA=OH,bb,,do you really think so?\"I doubt that\"";
    auto tak = [](const char* s)
    {
        std::cout << "// "<< s << std::endl;
    };
    tak("解析対象文字列");
    std::cout << aa << std::endl << std::endl;
    tak("StrtokNeo 出力");
    StrtokNeoHelper(aa);
    tak("使用後の対象文字列もインタクトに保持");
    std::cout << aa << std::endl;
    getchar();
    return 0;
}

とっても簡単だね。
これの出力結果は以下のようだよ。

// 解析対象文字列
aaa,+=,COOH+AAA=OH,bb,,do you really think so?"I doubt that"

// StrtokNeo 出力
-->aaa<--
--><--
--><--
--><--
-->COOH<--
-->AAA<--
-->OH<--
-->bb<--
--><--
-->do you really think so?<--
-->I doubt that<--
--><--

// 使用後の対象文字列もインタクトに保持
aaa,+=,COOH+AAA=OH,bb,,do you really think so?"I doubt that"

ま最低限のフィロソフィーだけ述べておくと、

  • StrtokNeoは、strtok同様、デリミタ文字を複数指定することが可能である。
  • StrtokNeoは、strtokのように、絶対内部で変な状態値を持ってんだろみたいな謎な実装ではない。関数ではなく素直にクラスとして実装しており、スレッド安全である。
  • StrtokNeoでは、strtokのように入力の文字列を破壊(デリミタを\0で置換し、もとの文字列を\0の穴だらけにする)したりすることはない。(ただし、非constな文字列を要求する点は変わらない。)
  • StrtokNeoは、strtokとは違い、デリミタが連続していてもそのデリミタ間に「空文字」の存在を明示的にパースして返す。このため植木算を「地で行く」動作仕様となっており、入力文字列を(デリミタの数+1)個のトークンに素直に分解するので、CSVファイル中の空カラムで、カンマが連続して出現するケースなどを高速にパースするのにも最適。
  • StrtokNeoは、iostreamヘッダにしか依存していない。stringすら使っていないため、多くの開発環境でかつ超高速処理が必要なシーンでも迷わず安心して導入することができそうな予感。
  • StrtokNeoのような当たり前に使いやすくて便利なものがC++でこんなに簡単に作れてしまうだのに、ただのC言語から進化して、クラスが定義可能になったC++になったタイミングで何故用意されていないのか、なぜstrtokの壁にぶち当たっただけで、みんなstringstreamやgetlineに流れたり、「C++は難しい」状況を放置してきてしまったのか、そういう不器用さがC#pythonなどに昨今プログラミング言語としての座を明け渡すことになった理由の、あれではないのかと。もっと便利な仕様の関数体系を作ればよかっただけなのではないかと、今までそうしてこなかったんだったらこれからどんどんやればいいじゃんと。。。って止まらなくなりそうなので

今回はこの辺で。
チャオ!

vs2019 community edition をインストールしてみたよ

やあ子供たちご無沙汰したな。今回おじさんはVS2019のCommunityEditionを個人的に導入してみたのでそのメモだよ。

●インストールフォルダの構成は2017とさして変わらないのでわかりやすい。
もうね、この記事は3年前の記事「vs2017 community edition をインストールしてみたよ」の自分用焼き直しであって、vs2019は、このときの知見があるので、以下とても簡単だったねという話。もう以下のパスなんかも、2017を2019と書き換えるだけでよかったねと。

●次に、VS160COMNTOOLS環境変数どこいったという話。
devenv.exe呼び出すのに便利なVSxxxCOMNTOOLS環境変数
vs2015のときは、VS140COMNTOOLS,
vs2017のときは、VS150COMNTOOLS、
vs2019のときは、VS160COMNTOOLS、というわけだ。
call "C:\Program Files (x86)\Microsoft Visual Studio"\2019\Community\Common7\Tools\vsdevcmd\core\vsdevcmd_start.bat
これを実行すれば、VS160COMNTOOLS 環境変数がしっかり定義された状態で、以降の行に書いた処理も実行されるという感じでした。。
肝心のdevenv.exe自体は、
C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\IDE
の下にあるので、ま上記環境変数以下の構成的には、これに関しては従来通りのようだ。(なお、上記パスの、「Community」となっているあたりのフォルダ構成はエディションによって変わってくるのだと思う。)

なので、devenv.exeのBATファイルからの起動方法は、vs2019の場合は以下のようになるよ。(わかりにくいかも知れんが2行だよ。)

call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\Tools\vsdevcmd\core\vsdevcmd_start"
"%VS160COMNTOOLS:tools=ide%\devenv.exe" .\minerva.sln

おわかりか。つまり、devenv.exeの場所はべた書きしたくないわけです。なので、VS160COMNTOOLS環境変数を設定すべく、1行目で、vsdevcmd_startを呼んで、2行目では、同環境変数の、toolsという文字列を、ideに置換しているというわけさ。
チャオ!

Excelの列番号を列名に返還するPythonスクリプト

やあ子供たち。
Excelでは列を指定する際にアルファベットが使われてるよな。
Aから始まって、B,C、、Zまで来たら、
次はAA、AB、AC、という具合になって、AZまできたら
次はBA、BB、BC、、という
具合にね。
さてさて、OpenPyXL などを使っていて、「1」から始まる列番号を、
このアルファベット名にしたい場合があるよな。
そこで今日はそんな関数を作ったので以下メモだよ。

num2alpha = lambda c: chr(c+64)
def num2alphaXL(c):
    j = c//26
    yo = c%26
    if(c<=26):
        return num2alpha(c)
    else:
        if( yo==0 ):
            return num2alpha(j-1)+'Z'
        else:
            return num2alpha(j)+num2alpha(yo)

はい。なんて汚いロジックなんだろうね。でも動けばいいのさ。
だって誰もこんなロジック美しく書くことに時間かけてらんないだろ?
おじさん何か間違ったこと言ってるかな?うだろ?いんだよこれで。
さてさて、これを以下のようなテストプログラムから呼んでみよう。

#"""
for i in range(1,60):
    print( str(i) + "  :" +num2alphaXL(i))
"""
#"""

結果は以下のようになるよ

1  :A
2  :B
3  :C
4  :D
5  :E
6  :F
7  :G
8  :H
9  :I
10  :J
11  :K
12  :L
13  :M
14  :N
15  :O
16  :P
17  :Q
18  :R
19  :S
20  :T
21  :U
22  :V
23  :W
24  :X
25  :Y
26  :Z
27  :AA
28  :AB
29  :AC
30  :AD
31  :AE
32  :AF
33  :AG
34  :AH
35  :AI
36  :AJ
37  :AK
38  :AL
39  :AM
40  :AN
41  :AO
42  :AP
43  :AQ
44  :AR
45  :AS
46  :AT
47  :AU
48  :AV
49  :AW
50  :AX
51  :AY
52  :AZ
53  :BA
54  :BB

ただ、お気づきかも知れないが、ZZまでしか対応してないのだと思う。

698  :ZV
699  :ZW
700  :ZX
701  :ZY
702  :ZZ
703  :[A
704  :[B
705  :[C

ほらね。(注意せよ!)
でもいいんだ。おじさんは700列まであるExcelには縁も興味もないので。
チャオ!