Toshusai blog

知識の保管庫

C#でString.Formatを用いて文字列を挿入する

int hp = 10;
String str = String.Format("HP:{0}", hp);

Format文字列に{0}, {1}, {2}, ...のように中括弧で0から始まる整数を書くことで第2引数以降のobjectで置換できる。4つ以上の要素は配列で渡すことができる。

int[] hps = {10, 15, 23, 45};
String str = String.Format("HP:{0}, HP:{1}, HP:{2}, HP:{3}", hps);

{0,4}のように記述すると挿入文字列の幅を空白で調整することができる。

int hp = 10;
String str = String.Format("HP:{0, 4}", hp);
// 1234
//>  10
String str = String.Format("HP:{0, 8}", hp);
// 12345678
//>      10

docs.microsoft.com

JavaScriptのfetchでPOSTリクエストをする

const obj = {title: "This is fetch"};
const options ={
    method: "POST",
    headers: {
        'Accept': 'application/json',
        'Content-Type': 'application/json'
    },
    body: JSON.stringfy(obj)
}
fetch("https://example.com", options)
    .then((res)=> res.json())
    .catch(console.error);

参考

developer.mozilla.org

https://developer.mozilla.org/ja/docs/Web/API/WindowOrWorkerGlobalScope/fetch

Unityでテクスチャを動的生成する

公式:https://docs.unity3d.com/ja/2017.4/ScriptReference/Texture2D-ctor.html

幅と高さを指定して空のテクスチャを作成する。

int width = 16;
int height = 16;
Texture2D texture = new Texture2D(width, height);

テクスチャのフォーマット、ミニマップを作成するかどうか、リニアかsRGB色空間かどうかも設定できる。

public Texture2D (int width, int height, TextureFormat format, bool mipmap, bool linear);

Gitでコミットの日時を変更する

1つ前のコミットのcomitter dateとauthor dateを現在の時刻に変更する

GIT_COMMITTER_DATE=\"$(date)\" git commit --amend --no-edit --date \"$(date)\"

特定のコミットを変更する

git rebase <commit-hash>^ -
  1. pickeに変更して保存
  2. amendで更新
git rebase --continue

rebaseを完了する

※当然ながらあとから変えない方が良い

参考

https://codewithhugo.com/change-the-date-of-a-git-commit/

新婚三択アルゴリズムを1行で実装する

はじめに

ご飯にする?お風呂にする?それとも私?という言葉を聞いたことがあるだろうか。この仕事等から帰ってきた旦那さんを出迎えた奥様が提示する三択は一般的には新婚三択と呼ばれているようだ。*1,*2 起源は全員集合の志村けんのコントとするものもあったが、筆者の2分ほどの調査では正しい起源を確認することはできなかった。*3 特に理由はないがプログラミング言語のレベルにモデル化することにした。

実装

ご飯お風呂以外の選択肢を選んだ場合の動作は未定義であることが多いが、今回のケースではご飯お風呂以外をとする。

 const f = (action) => ご飯 == action ? 🍚 : お風呂 == action ? 🛁 : 🤷<200d>♀️

次に、ご飯お風呂以外の選択を例外として処理したい場合を考える(ここでは夫からの呼びであるため、選択肢としての呼び名をと定義する)。

 const f = (action) => ご飯 == action ? 🍚 : お風呂 == action ? 🛁 : action === 君 ? 🤷<200d>♀️ : (()=>{throw `ActionError: Unexpected action '${action}'`})();
 f(ご飯);
 // 🍚
 f(お風呂);
 // 🛁
 f(君);
 // 🤷<200d>♀️
 f(ゲーム);
 // Uncaught ActionError: Unexpected action 'ゲーム'

注意すべき点は、3項演算子中で例外を投げるには、例外を投げる即時関数を呼び出さないといけない(以下のコードを参照)。*4

 false ? 'ok' : throw 'omg'; 
 // Uncaught SyntaxError: Unexpected token 'throw'
 false ? 'ok' : (()=>{throw 'omg'})(); 
 // Uncaught omg

見てわかるように、このケースではやや冗長なコードになる。

おわりに

今回はJavaScriptを用いて実装したが、PythonやGo言語のように3項演算子を持たない言語では1行で書くことは不可能である。また、世の中には3項演算子の良し悪しについての議論が存在する。*5本記事はジョーク記事なのでそういった議論は一切受け付けない。

余談ではあるが、新婚三択を言われたいかどうかというアンケートによると53.9%の男性がいいえと答えたそうだ。*6

マイナビウーマン調べ(2015年8月にWebアンケート。有効回答数102件。22歳~39歳の社会人男性)

筆者はそんなことを考えたことはないが、どうかと聞かれたら、ちょっと言われてみたい。

参考

*1

新婚三択 (しんこんさんたく)とは【ピクシブ百科事典】 https://dic.pixiv.net/a/新婚三択

*2

新婚三択とは (シンコンサンタクとは) [単語記事] - ニコニコ大百科 https://dic.nicovideo.jp/a/新婚三択

*3

ご飯にする?お風呂にする? - それとも私?って具体的にどういうことですか?? - Yahoo!知恵袋 https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q14137012839

*4

JavaScript error handling: can I throw an error inside a ternary operator? - Stack Overflow https://stackoverflow.com/questions/9370606/javascript-error-handling-can-i-throw-an-error-inside-a-ternary-operator

*5

三項演算子?:は悪である。 - Qiita

https://qiita.com/raccy/items/0b25b2f106e2a813828b#:~:text=条件演算子(conditional%20operator,項演算子である。

*6

「ごはんにする? お風呂にする? それとも私にする?」って、男性は言われてみたいもの? https://woman.mynavi.jp/article/150901-125/

CloudinaryでOGP画像を自動生成する

Cloudinaryとは

Cloudinaryは画像や映像、メディアを簡単に配信できるストレージサービス。URLを入力するだけや多くのAPIで画像の編集などがすぐに行える。無料枠も存在する。

テキストを表示する

https://cloudinary.com/documentation/image_transformations#using_custom_fonts_for_text_overlays アップロードした画像に対してテキストを表示することができる。 URLで使用すると以下のようなURLになる。

https://res.cloudinary.com/demo/image/upload/w_500/l_text:Verdana_75_bold_underline_letter_spacing_14:Flowers/flowers.jpg

大体以下のような構造になっている。

const baseUrl = \"\";
const font = \"Verdana\";
const fontSize = \"75\";
const fontStyle = \"bold\";
const text = \"Hoge\";
const image = \"sample.jpg\";
const options = \"w_800,c_fit\";
const url = `${baseUrl}/${options}l_text:${font}_${fontSize}_${fontStyle}:${text}/${image}`;

w_XXXは文字の最大の幅がXXXピクセルとなるように設定する。 c_fitは文字が最大の幅に到達したときに折り返す。スペースの内英字だと折り返されずに...となる。

カスタムフォントを使う

カスタムフォントを使おうとしたら若干手間取った。フォントを使えるようにアップロードするには以下のようにいくつかの設定をする必要がある。

Cloudinary::Uploader.upload(\"AlexBrush-Regular.ttf\", 
    resource_type: 'raw', # Custom fonts must be upload as 'raw'
    type: 'authenticated', # Custom fonts must be upload as 'authenticated'
    public_id: 'AlexBrush-Regular.ttf')

この設定はブラウザが適用するには設定画面から設定を作る必要がある。 https://support.cloudinary.com/hc/en-us/community/posts/360048769011-Custom-font

Signing ModeをSignedに、Delivery typeをAuthenticatedに設定する。 画像やビデオ以外のrawに対してこの設定を適用してフォントをブラウザからアップロードすれば使えるようになる。

References

https://catnose99.com/cloudinary-dynamic-ogp-image/

対応ブラウザのみにwebpを配信する

<picture>
  <source type=\"image/webp\" srcset=\"flower.webp\">
  <source type=\"image/jpeg\" srcset=\"flower.jpg\">
  <img src=\"flower.jpg\" alt=\"\">
</picture>

参考

https://insanelab.com/blog/web-development/webp-web-design-vs-jpeg-gif-png/#:~:text=WebP%20vs.,-JPEG&text=JPEG%20is%20a%20no%2Dbrainer,JPEG%20as%20an%20image%20format.

https://blog.ideamans.com/2019/04/safari-121-not-webp.html

nuxt/markdownitでpluginをoption付きで使う

https://github.com/nuxt-community/modules/tree/master/packages/markdownit

公式に載ってなかった

https://www.npmjs.com/search?q=keywords:markdown-it-plugin

ライブラリをインストールすればnuxt.config.jsmarkdownit.useにpluginを適用できる。

{
  modules: [
    '@nuxtjs/markdownit'
  ],

  // [optional] markdownit options
  // See https://github.com/markdown-it/markdown-it
  markdownit: {
    preset: 'default',
    linkify: true,
    breaks: true,
    use: [
      'markdown-it-div',
      'markdown-it-attrs'
    ]
  }
}

ここでmarkdown-it-anchorをオプション付きで使いたい。 useに配列で['plugin-name', options]にするとオプション付きでプラグインを使える。

  markdownit: {
    preset: 'default',
    linkify: true,
    breaks: true,
    use: [
      'markdown-it-prism',
      [
        'markdown-it-anchor',
        {
          level: 6,
          permalink: true,
          permalinkSymbol: '¶',
          permalinkBefore: true
        }
      ]
    ],
  },

References

https://stackoverflow.com/questions/60436593/how-to-use-markdown-it-plugins-options-in-nuxt-js

DockerでHeadless Chrome(puppeteer)を使う

DockerでHeadless Chrome(puppeteer)を使う

About

ブラウザ操作にはjsのライブラリpuppeteerを使う GitHub: https://github.com/puppeteer/puppeteer

Docker Image

日本語フォントに対応したHeadless Chrome Dockerコンテナ

FROM mhart/alpine-node:12

ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true

RUN apk update && apk add --no-cache nmap && \\
    echo @edge http://nl.alpinelinux.org/alpine/edge/community >> /etc/apk/repositories && \\
    echo @edge http://nl.alpinelinux.org/alpine/edge/main >> /etc/apk/repositories && \\
    apk update && \\
    apk add --no-cache \\
      chromium \\
      harfbuzz \\
      ttf-freefont \\
      nss

# 日本語フォントをインストールする
RUN mkdir /noto

ADD https://noto-website.storage.googleapis.com/pkgs/NotoSansCJKjp-hinted.zip /noto 

WORKDIR /noto

RUN unzip NotoSansCJKjp-hinted.zip && \\
    mkdir -p /usr/share/fonts/noto && \\
    cp *.otf /usr/share/fonts/noto && \\
    chmod 644 -R /usr/share/fonts/noto/ && \\
    fc-cache -fv

WORKDIR /
RUN rm -rf /noto

Chromeのバージョンが違うと動かないことがある 上記のDockerfileだと72が入るのでpuppeteerのバージョンを合わせてインストールする。

npm install puppeteer-core@chrome-72

TypeScriptで使うなら

npm install -D @types/pupeteer

executablePathを指定してあげる。Macとかのホストマシンで動かす場合はなくても大丈夫。 --no-sandboxを指定しないとルート権限で動かせない。

const browser = await puppeteer.launch({
    executablePath: \"/usr/bin/chromium-browser\",
    args: ['--no-sandbox'],
    defaultViewport: {
        width: 1920,
        height: 1090
    },
});

APIはここ https://github.com/puppeteer/puppeteer/blob/master/docs/api.md

スクリーンショットを取る

await page = browser.newPage();
page.goto(\"https://example.com\");
await page.screenshot({ path: \"example.png\" });

ボタンを押して遷移を待つ

await Promise.all([
    page.tap(\"button\"),
    page.waitForNavigation({ waitUntil: \"networkidle2\" })
]);

ファイルをアップロードして待つ

const fileInputHandle= await page.$(\"input\");
await fileInputHandle.uploadFile(\"example.png\");
// アップロード後に変化するDOMを指定するとアップロード完了を待てる
await page.waitForSelector(\"#uploaded\");

複数のDOMに対して処理を行う

var texts: Array<string> = await page.$$eval(\"li\", (elements) => elements.map(el => el.innerHTML));

Cookieを再利用する

保存

var cookies = await page.cookies();
writeFileSync(\"cookies.json\", JSON.stringify(cookies));

セット

var cookies: Cookie[] = JSON.parse(readFileSync(\"cookies.json\").toString());
await page.setCookie(...cookies);

参考

https://github.com/mhart/alpine-node https://help.apify.com/en/articles/1640711-how-to-log-in-to-a-website-using-puppeteer https://stackoverflow.com/questions/46948489/puppeteer-wait-page-load-after-form-submit https://qiita.com/go_sagawa/items/85f97deab7ccfdce53ea https://qiita.com/dd511805/items/dfe03c5486bf1421875a https://blog.logrocket.com/how-to-set-up-a-headless-chrome-node-js-server-in-docker/ https://hub.docker.com/r/justinribeiro/chrome-headless/ https://developers.google.com/web/updates/2017/04/headless-chrome

【Godot】MenuButtonの使い方

Windowsのアプリの左上にあるようなメニューを作るためのノード

PopupMenuをラップしているのだが、エディタからではアイテムを設定できない。 get_popup()からPopupMenuを取得して設定する必要がある。

var pop_up = event_menu_button.get_popup()
pop_up.connect("id_pressed", self, "action")
pop_up.add_item("Open", 0);

参考

godotengine.org

docs.godotengine.org

Golang Opencv4 Install for Windows

公式

こっち見たほうが確実 Windows :: GoCV - Golang Computer Vision Using OpenCV 4

はじめに

Golangのインストール、GitBashのインストールは省略、環境はWindows10、GitBash

GoCVのインストール

go get -u -d gocv.io/x/gocv

MinGw-W64のインストール

Cのコンパイラ

https://sourceforge.net/projects/mingw-w64/?source=typ_redirect.

(versionは7.3.0、architectureはx86_64にする)

MinGwにパスを通す。

C:\Program Files\mingw-w64\x86_64-7.3.0-posix-seh-rt_v5-rev2\mingw64\bin

設定のやり方

コントロールパネル ->システムとセキュリティ ->システム ->システムの詳細設定 ->詳細設定 ->環境変数 ->変数Pathを編集する。

CMakeのインストール

クロスプラットフォームのビルドツール

https://cmake.org/download/

CMakeにもパスを通す

C:\Program Files\CMake\bin

OpenCVのインストールをする

cd ~/src/gocv.io/x/gocv
win_build_opencv.cmd

結構時間がかかる。

最後に以下にパスを通す(忘れずに)

C:\opencv\build\install\x64\mingw\bin

以下が動けばインストール完了

go run ~/src/gocv.io/x/gocv/cmd/version/main.go
gocv version: 0.19.0
opencv lib version: 4.0.1

CordovaでAndroidエミュレーターにビルドしたい

WindowsでCordovaでAndroidビルドする

Cordovaの準備

Cordovaをインストールする

npm install -g cordova

アプリを作る

cordova create hello com.example.hello HelloWorld

Androidを追加する

cordova platform add android

ビルドできるか確認する

cordova requirements

成功すれば下のような感じ

Requirements check results for android:
Java JDK: installed 1.8.0
Android SDK: installed true
Android target: installed android-27,android-26
Gradle: installed C:\Program Files\Android\Android Studio\gradle\gradle-4.4\bin\gradle

JDKのエラー

SDKはここから
http://www.oracle.com/technetwork/java/javase/downloads/index.html
でも8じゃないと多分こんなエラーが出る。

CordovaError: Requirements check failed for JDK 1.8 or greater

最新(今は10)をアンインストールしてこっちから8をダウンロードする
http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html

Android SDK, Android targetのエラー

Android Studioが必要
Android Studio->File->Settings->System Settings->Android SDKからインストールする

Gradleのエラー

Macで試したときに起きたエラー

Gradle: not installed 
Could not find an installed version of Gradle either in Android Studio,
or on your system to install the gradle wrapper. Please include gradle 
in your path, or install Android Studio

普通にbrewでインストールすれば良いっぽい

brew install gradle

エミュレーター起動

これで起動すれば良いけど。

cordova emulate android

このエラーがでてダメだった。

TypeError: Cannot read property 'semver' of null

調べたら以下のサイトがヒットした。

エラーが出る箇所無くても起動はするのでコメントアウトすれば一応動く。 問題があるかはいまいち分かりませんでした。

Macだとこんなエラーが出て一応エミュは起動するけど動かない。というより重いのか?

Running an x86 based Android Virtual Device (AVD) is 10x faster. We strongly recommend creating a new AVD.

エミュレーターを選択すれば良さそうだけど、Windowsでは動いたので、それはまたいつか。WindowsではAndroid Studioで作ったエミュレーターが自動で選択されている。

ビルドして実行

これで実行できるはず。

cordova build android
cordova run android