OmniAICreator/Qiita-1.07M huggingface dataset:
「微分や微分方程式をPythonで理解する」を参考にWolframAlphaでやってみたい。

オリジナル

https://qiita.com/maskot1977/items/b4395da5f33f70cd4a09#%E5%B8%B8%E5%BE%AE%E5%88%86%E6%96%B9%E7%A8%8B%E5%BC%8F


#Sympy を使った方法
作業中

#Sympy を使って数学の復習
作業中

#微分
作業中

#常微分方程式

## 2 f'(x) + 5 f(x) = 0 を解く(常微分方程式の分類:一階線形常微分方程式)

https://www.wolframalpha.com/input/?i=2*+y%27+%2B+5+*+y%3D0&lang=ja


y(x) = c_1 e^(-(5 x)/2)


特殊解

https://www.wolframalpha.com/input/?i=2*+y%27+%2B+5+*+y%3D0%2Cy%280%29%3D1&lang=ja

https://www.wolframalpha.com/input/?i=%7B2*+y%27+%2B+5+*+y%3D0%2Cy%280%29%3D1%7D&lang=ja

y(x) = e^(-(5 x)/2)
解のプロットあり

特殊解で x = 2 のとき

https://www.wolframalpha.com/input/?i=2*+y%27+%2B+5+*+y%3D0%2Cy%280%29%3D1%2Cy%282%29&lang=ja

y(2) = 1/e^5
近似値
y(2) = 0.00673795


## f''(x) + f'(x) + 4 f(x) = 0 を解く(常微分方程式の型:自律方程式,スツルム・リウヴィル型方程式)

https://www.wolframalpha.com/input/?i=y%27%27+%2B+y%27+%2B+4+*+y%EF%BC%9D0&lang=ja

y(x) = c_1 e^(-x/2) sin((sqrt(15) x)/2) + c_2 e^(-x/2) cos((sqrt(15) x)/2)



特殊解

https://www.wolframalpha.com/input/?i=y%27%27+%2B+y%27+%2B+4+*+y%EF%BC%9D0%2Cy%280%29%3D1%2Cy%27%280%29%3D1%2Cy%282%29&lang=ja

y(x) = 1/5 e^(-x/2) (sqrt(15) sin((sqrt(15) x)/2) + 5 cos((sqrt(15) x)/2))


特殊解に x = 2 を代入(特定の点における微分方程式の解)

https://www.wolframalpha.com/input/?i=y%27%27+%2B+y%27+%2B+4+*+y%EF%BC%9D0%2Cy%280%29%3D1%2Cy%27%280%29%3D1%2Cy%282%29&lang=ja


y(2) = (sqrt(15) sin(sqrt(15)) + 5 cos(sqrt(15)))/(5 e)



## f'(x) + 0.2 f(x) = 0 を解く, ただし f(0) = 5(常微分方程式の分類:一階線形常微分方程式)

https://www.wolframalpha.com/input/?i=y%27+%2B+0.2+*+y%EF%BC%9D0%2Cy%280%29%3D5&lang=ja

y(x) = 5 e^(-0.2 x)


## f'(x) + f(x)/x - 2 を解く, ただし f(1) = 2(常微分方程式の型:同次方程式,ダランベールの方程式)


https://www.wolframalpha.com/input/?i=y%27+%2B++y%2Fx-2%EF%BC%9D0%2Cy%281%29%3D2&lang=ja


y(x) = x + 1/x



#Scipy.integrate.odeint を使う方法
勉強中

#微分方程式の数値解法
勉強中
イラレコ展覧会2021

# RPA関連のイラレコ・グラレコをまとめてみました！
わたくしのイラレコの変遷などご覧いただきながら、様々な活動内容をご覧ください！
# 2021年01月29日
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/646663/0b71f89a-cae2-cd07-cd9a-4f7fccf40547.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/646663/f4ba5cfd-e2c4-e6fc-dfc9-0997a779772f.png)

# 2021年02月14日
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/646663/06db6df0-58ec-d54c-90fa-6382192a7fe8.png)

# 2021年03月12日
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/646663/5e0194c8-e02d-11a6-0021-0f77c7c594e2.png)

# 2021年03月25日
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/646663/312a5cbf-b1e3-e5a4-8a4c-42a3efb8dcad.png)

# 2021年03月31日
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/646663/7c8aaaa6-967a-1296-66af-a64c7047a7bb.png)

# 2021年04月20日
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/646663/6ff1113a-cc39-d70e-6a1c-a17915da47bf.png)

# 2021年05月21日
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/646663/a36b1446-27ed-14fc-c6e0-6aa0d91eb599.png)

# 2021年07月7日
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/646663/75de51b3-5f5d-8169-0715-9ac11e61a4be.png)

# 2021年07月13日
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/646663/369da1f4-e016-dd23-bac7-db4020120f2a.png)

# 2021年07月26日
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/646663/328a0377-4b5a-6e6f-49b8-1e7ca6c8bdb7.png)

# 2021年07月28日
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/646663/e7eb73d0-62ba-72d9-79d2-cc4f625ea4aa.png)

# 2021年08月27日
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/646663/ce42fc75-8709-bf78-efd8-9a73e6dec5ff.png)

# 2021年08月30日
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/646663/2a918adb-febf-489b-dbe9-7cc0bcc4d0e2.png)

# 2021年08月31日
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/646663/9ff5d301-0f9e-a82a-0a7e-450a024b8775.png)

# 2021年10月08日
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/646663/da18ad79-9f8b-409c-8969-d55a16580d80.png)

# イラレコやグラレコは楽しいぞ！
描きながらだと、なかなか勉強に集中できないので程々にしたいと思いつつ、描くのは楽しいですね✨
皆様もチャレンジしてみてはいかがでしょうか🎨
AirtableをAPIとしてnodeJSを使いJSONデータ化するまで

JSONを吐かせる簡易DB代わりにGoogleSpreadSheetを使っているのですが使っているGAS使ってるシートとそうでないシートとでごちゃごちゃしてきてしまったので無料で使えて代替手段となるものはないのかな〜ということでAirtableを使ってみることに。

（気になってたからってのもある）

## ワークスペースの準備
![スクリーンショット 2021-11-30 16.59.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/651103/8451b4e6-b19e-e468-0bbc-900938404263.png)

初めに、ワークスペースとしてTestテーブルを作成しておきます。シート名も"TestTable"としておきました。

## APIキーの取得
![airtable.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/651103/f357e1a4-5086-c27a-df40-455c1e6967a6.jpeg)

「右上のアイコン > Account」へ飛ぶとAPIキーを生成できるので生成して保存しておきます。

![スクリーンショット 2021-11-30 16.30.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/651103/55d9f2cb-86b8-d959-3556-c7c903336746.png)


### TestテーブルのIDの取得
そして https://airtable.com/api/ へ飛ぶと自分のワークスペース専用ドキュメントができているという素晴らしきユーザー体験

画像の "Test"（あなたの任意のワークスペース） へ飛びます。

![スクリーンショット 2021-11-30 17.03.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/651103/57ddcb56-608e-ac45-2c9c-3cbc0ebd2276.png)

```
https://airtable.com/あなたのテーブルID/api/docs#javascript/ratelimits
```

するURLにテーブルIDがあるので "あなたのテーブルID" を保存しておきます。

## 試しに Name の列のカラムを取得してみる

ディレクトリ構成(node_modulesなどは省く)

```
AirtableTest/
 generated/
 .env
 index.js
 package.json
```

適当に yarn init などしておきディレクトリ準備。

### ライブラリをインストール

```
yarn add -D airtable dotenv
```

scriptsを追加して実行コマンドも設定しておく。

```package.json
省略
  "scripts": {
    "start": "node -r dotenv/config index.js"
  }
省略
```

### 環境変数の設定

```.env
AIRTABLE_API_KEY=あなたのAPIキー
```

### テーブルのName列のカラムを取得する処理

```index.js
const base = require('airtable').base('あなたのテーブルID');
const app = base("TestTable")
const airtableLists = app.select({view: "Grid view"})
airtableLists.firstPage((error, records) => {
  const names = records.map(record =>
    record.get("Name")
  )
  console.log(names);
});
```

## 実行してみる

```
yarn start
```

```
yarn run v1.22.10
$ node -r dotenv/config index.js
[ 'hoge', 'hage', 'fuga', undefined ]
✨  Done in 2.35s.
```

と上のような値が返って来ればOKです。

## JSON化する
ここで取得したデータをJSONデータ化させてみます。

```index.js
const fs = require('fs');
const base = require('airtable').base('あなたのテーブルID');
const app = base("TestTable");
const airtableLists = app.select({view: "Grid view"});

const createJSON = (airtableObj) => {
  const JSONdata = JSON.stringify(airtableObj, null, 2);
  fs.writeFileSync('generated/airtable.json', JSONdata);
}

const getAirtableObj = (airtableLists) => {
  return airtableLists.firstPage((error, records) => {
    const airtableObj = records.map(record => ({ Name: record.get("Name"), Notes: record.get("Notes") }));
    createJSON(airtableObj);
  });
}

getAirtableObj(airtableLists);

```

ここで generated/airtable.json にルート指定して生成します。

```
const createJSON = (airtableObj) => {
  const JSONdata = JSON.stringify(airtableObj, null, 2);
  fs.writeFileSync('generated/airtable.json', JSONdata);
}
```

### 生成されたJSONを確認してみる

空白だったカラムは空になっていますが以下のように取得できていることがわかります。

```airtable.json
[
  {
    "Name": "hoge",
    "Notes": "ほい"
  },
  {
    "Name": "hage",
    "Notes": "はい"
  },
  {
    "Name": "fuga",
    "Notes": "へい"
  },
  {}
]
```
Laravelの.envに#を書いてハマった話

非常につまらないことで半日以上無駄にしたので、愚痴のつもりで書きます。

##要約
.envに設定値を書くときは、""でクォートしておけ！特に記号が含まれる文字列は！

※おそらくPHPとRubyに適用される話だと思います。その他の環境についてはわかりません。

##語り
他社さんにDBを構築してもらって、接続用のIDとパスワードを受け取りました。
今回、このパスワードに # が含まれていました。
DB_PASSWORD=hoge#fuga
という設定を.env に記入して php artisan migrate を実行したところ、エラーが発生。

> SQLSTATE[HY000] [1045] Access denied for user 'USERNAME'@'XXX.XXX.XXX.XXX' (using password: YES) (SQL: ...省略)

おかしいなと思い mysql コマンドで接続を試みたところ、特に問題なし。設定ミスや伝達ミスの線は消えました。
.env の設定値を見直しても問題なし。この時点で何だこりゃ？となるわけです。

試しにconfig/database.php 内にパスワードを書いてみたところ、問題なく php artisan migrate が実行できました。こりゃ .env から読み込むところがおかしいんだろう、おそらく#以降がコメント扱いなっておるんじゃろうと推測しました。
 
で、.env の記述を
DB_PASSWORD="hoge#fuga"
としてやったら .env 側の設定だけで php artisan migrate が動いた、というわけです。

ここまでで半日経ってます。
※まぁ、こればかりやってたわけじゃないですが

##.envってどう処理されてるの？

Laravel は PHP dotenv というライブラリを使って .env を読み込んでいるようです。
https://github.com/vlucas/phpdotenv

このページを見ただけでは、#の扱いがよくわかりません。
サンプルが良くないですよね....

:::note info
別のページでは#の前に空白があればコメントになるという記述も見かけました。
連続する文字列の中の#はコメントとして扱われない、ということですね。
結果的にはこの情報が間違っているわけですが、古い情報なので当時は正しかったのかもしれません。
リンクはしませんが....
:::


PHP dotenv は Ruby dotenv の PHP版という立ち位置のようです。
https://github.com/bkeepers/dotenv

こちらのページには、#を含む文字列はクォートすればいいんだな、と判断できるサンプルが書かれています。
説明はこのように行うように心がけたいものです。


また、Laravel 添付の .env.example にも課題があるのではないかと思います。
設定値を "" でクォートしているものは .env内で定義した設定値を参照している箇所のみなので、
ここから .env に入った人は「設定値はベタ書きでいいんだ」と思うことでしょう。

かく言う自分も他の人が書いた .env を環境に合わせて設定していただけなので、今回のハマりを招いてしまったわけです。これが "" で囲まれているパスワードを置き換えるのであれば、なんの問題もなかったわけです。
※私自身の知識にはなんの増加もないことになりますが、そんなことより早く仕事を終わらせたいときだってありますよね
※そこは今回の自分の仕事の範囲じゃないんじゃよ...

ここから導かれる対策は２つ
・設定値に#を含めないようにせよ
・設定値はとにかく "" でクォートしておけ
前者の対応は論外なので、後者を推奨。

もちろん、何でもかんでもクォートしていると面倒だし、不要なところは省略していいと思うんですが、自分のようにうっかり # を書き込む羽目になってしまったような人のために、fool proof な書き方になっている方が良いですよね、って話です。

お付き合いありがとうございました。
C++からOptunaを呼ぶライブラリを作った

# まとめ
これを書いた。 https://github.com/not522/optuna-cpp

# Python以外の言語でOptunaを使う
OptunaはPythonのライブラリなので、他の言語で使うには

1. Pythonから他の言語を呼び出す
1. Optunaの[command line interface](https://optuna.readthedocs.io/en/v2.10.0/reference/cli.html)を使う

のどちらかが必要です。optuna-cppでは2番目の方法を採用して、C++だけでOptunaを呼び出せるようにしています。

# 使い方
```cpp
#include <iostream>

// optuna.hとnlohmann/json.hppのある環境でコンパイルしてください
#include "optuna.h"

int main() {
  // studyの作成
  optuna::Study study("sqlite:///example.db", "test_study", optuna::MINIMIZE, true);

  // 探索空間の定義
  optuna::SearchSpace search_space;
  search_space.add_categorical<std::string>("c", {"a", "b"});
  search_space.add_float("x", -10, 10);
  search_space.add_int("y", -10, 10);

  // trialを10回行う
  for (int i = 0; i < 10; ++i) {
    optuna::Trial trial = study.ask(search_space);
    std::string c = trial.param<std::string>("c");
    double x = trial.param<double>("x");
    int y = trial.param<int>("y");
    if (c == "a") {
      study.tell(trial, x * x + y * y);
    } else {
      study.tell(trial, x * x + y * y + 1);
    }
  }

  // 最適化履歴の取得
  for (const optuna::FrozenTrial &trial : study.trials()) {
    std::cout << trial.number << " "
              << trial.state << " "
              << trial.param<std::string>("c") << " "
              << trial.param<double>("x") << " "
              << trial.param<int>("y") << " "
              << trial.value << std::endl;
  }

  // best trialの取得
  const optuna::FrozenTrial best_trial = study.best_trial();
  std::cout << best_trial.number << " " << best_trial.value << std::endl;
}
```

# Interface

Optuna CLIで最適化する場合、[ask-and-tell interface](https://optuna.readthedocs.io/en/v2.10.0/tutorial/20_recipes/009_ask_and_tell.html)を使うことになります。また、CLIではdefine-by-run形式は使えず、define-and-run形式になります。
Optuna本来のdefine-and-runの書き方だと少し冗長になるので、SearchSpaceというクラスを作ってadd_float/add_int/add_categoricalという関数で記述できるようにしました。

# サポートできてないこと

1. 多目的最適化
1. デフォルト以外のSampler
1. 枝刈り
1. 分岐のある探索空間

多目的最適化とデフォルト以外のSamplerはCLIには存在するので、ちゃんと実装すれば対応できます。枝刈りや分岐のある探索空間はOptuna CLI側がまだ未対応なので、Optuna内部の実装が必要になります。
「顧客要望にだけ応えても売れる商品は作れないよ」と言われて途方に暮れていた初心者PMの苦闘と閃き

こんにちは。エムスリーという会社でPMを担当させて頂いている岩田と申します。

これは[プロダクトづくりのための挑戦とその成功・失敗談を綴るアドベントカレンダー powered by プロダクト筋トレ](https://qiita.com/advent-calendar/2021/product-kintore-challenge)の12月1日の記事です。今後どんどん面白い記事が毎日更新されるので、ぜひ購読・拡散お願いします。

今回は私が未経験PdMとして2年間奮闘した中で学んできた、顧客要望との向き合い方に関する話を書きます。
この機能が無いと買わないって言っていたから作ったのに...とか、なんで機能に劣る他社製品にウチが負けたのか..といったお悩みをお持ちのプロダクトマネージャーの皆様へ役に立つ情報を発信できればと思います。

# 本題に入る前に
本題へ入る前に、まずはコミュニティとこのカレンダーについてご紹介させてください。

## プロダクト筋トレコミュニティについて
プロダクト筋トレコミュニティでは、**「プロダクトづくりに関する知識を広げ、深め、身につける」**を目的に活動しています。

```
プロダクトを作るために必要な知識は技術だけではなく、事業、ユーザー体験、チームのマネジメント、ドメインの知識などと多岐に渡ります。
そして、そのすべてに長けている人はほとんどいません。​

「何を学べば良いかわからない」状態から「自分のレベルがわかる」状態へ、そして「弱みや強みを強化していく」状態へ。

プロダクトづくりに関する知識や考える力をつけるための思考の筋トレをプロダクト筋トレと呼んでいます。
社外の仲間と勉強、議論をし、よりよいプロダクトをつくる筋肉を伸ばしていきましょう。
```
(公式サイトより抜粋)

https://www.productkintore.org/

## このカレンダーについて
このカレンダーは、コミュニティ内の有志の皆様によるプロダクトづくりのための挑戦とその成功・失敗談が綴られていきます。
ぜひご参照頂ければと思います。

# 本題
1. [「顧客要望通りに作っても売れない」とは言うけれど](#「顧客要望通りに作っても売れない」とは言うけれど)
2. [顧客の事前期待を超えることがイノベーションの第一歩](#顧客の事前期待を上回ることがイノベーションの第一歩)
3. [勝つべくして勝つ。自社の強みを生かして顧客の事前期待を超える](#勝つべくして勝つ。自社の強みを生かして顧客の事前期待を超える)
4. [社内の関係者は最初の顧客。まずは社内の期待を超える](#社内の関係者は最初の顧客。まずは社内の期待を超える)
5. [まとめ](#まとめ)

## 「顧客要望通りに作っても売れない」とは言うけれど
PMであればおそらく100回はヘンリー・フォードの以下の言葉を見聞きするのではないでしょうか。

```
「もし顧客に、彼らの望むものを聞いていたら、彼らは「もっと速い馬が欲しい」と答えていただろう。」
```

とはいえ顧客が想像もしていないような製品を考えることは困難を極めます。
巷の書籍では「イノベーション」の考え方は提供してくれますが、それをすぐに自分の製品に当てはめたところでどうにかなるようなものでもありません。

自分が企画するプロダクトが何かが欠けていることはわかる。わかるが、何が足りないのか。アイデアのキレが足りないと言っても、雲をつかむような話に感じられ、しばらく何も企画が進まない状況が続きました。自分はPMに向いていないんじゃないかと真剣に悩んでいました。

## 顧客の事前期待を超えることがイノベーションの第一歩
その時に上司から紹介された以下の書籍が私に閃きをもたらしてくれました。

https://www.amazon.co.jp/exec/obidos/ASIN/B00B1ND2Z0

この書籍では顧客満足は以下の引き算で計算できるとしています。

```
顧客満足 = 顧客が感じた価値 - 事前期待値
```

確かに言われてみれば、人間の感動というのは予想の裏切りが伴っていると感じます。
大谷翔平選手の素晴らしい活躍や多くの人々を感動させましたが、これは人々の予想を裏切るほどのインパクトだったからこそ、人々が感動したのではないでしょうか。

とはいえ驚きを生み出すために技術的、デザイン的、事業的に破綻していたらお話になりません。そこを破綻しない範囲で、かつ顧客の予想を大きく裏切るようなアイデアを企画し形にすることこそがPMのキモであるとこのとき気づくことができました。

## 勝つべくして勝つ。自社の強みを生かして事前期待を超える
とはいえ、「驚き」というのは誰も想像していなかったからこその驚きです。 それを人為的に作り出せと言われても途方にくれてしまうのではないでしょうか。
しかしPdMとしてはここが踏ん張りところです。なんとかしなくてはいけません。

「驚き」を考えるヒントとして私が好むのはバリュー・プロポジションの考え方です。

![バリュー・プロポジション](https://www.mugendai-web.jp/wp-content/uploads/2017/11/171107_nagai_02.jpg)

この画像は下記から引用させて頂きました。

https://www.mugendai-web.jp/archives/7654

この画像にある「顧客が望んでいて、競合が提供できなくて、自社が提供できる価値」を提供するというのは大きなヒントではないでしょうか。 

創業期のベンチャーであれば、創業者自身の強み、なぜ高いリスクを取って創業に至ったのか、といったストーリーなどが当てはまりそうです。
大企業であれば、社内の様々な資産や他事業とのシナジーなどが当てはまりそうです。
このように、顧客が望む価値と、自社にしか無い提供できない価値がうまく重なる領域を見つけられると、顧客満足度が高まるのではないでしょうか。

## 社内の関係者は最初の顧客。まずは社内の期待を超える
ここまで主に顧客の事前期待を超えるという前提で話を進めてきました。しかしながらプロダクト開発というものはまず社内から始まります。
社内の関係者というのはある意味では最初の顧客とも言えます。
特にプロダクト立ち上げ期において社内からの事前期待を超えることは、その後のプロダクト成功にとって非常に肝要であると考えます。

とはいえMVPとして要件を絞る以上、機能面やユーザー体験で事前期待を超えることはなかなか難しい場合もあると思われます。
そこでオススメなのが、社内の予想と比べて半分以下の期間でリリースまでこぎつけることです。半年以内に欲しいと言われたら3ヶ月、1ヶ月以内と言われたら2週間でリリースしてしまえば、事前期待を超えることができます。

社内のメンバーが疲弊しない範囲内に留める必要はありますが、半分の期間でリリースという方法は最も再現性高く、事前期待を超えることができると考えます。

## まとめ
顧客満足を生み出すためには、顧客が期待もしていないような驚きを提供すべしという考えを私は持っています。驚きを生み出すためには、自社にしか無い強みを活かすこと。社内の関係者は最初の顧客と見做し、彼らの期待も超えるよう意識すること。そのためには半分の期間でリリースまで漕ぎつける方法が最も再現性が高いと考えます。
Rustで簡単にDiscordBotを動かしてみる

## 自己紹介

- 名前：牛島涼介

- 趣味：ゲーム（LOL, Steam, PS4）

- 所属：ユニークビジョン株式会社（半年）

- 半年前に仕事でRustを触り始めました

- 前職ではC言語を書いてました

---
## Discordとは
- 音声のコミュニケーションツール

- 軽くて簡易的に配信ができる代物

- ボットなどのアプリケーションが作りやすいようにアクセストークンが簡単に手に入る

- チャンネルとメッセージの既読情報を追跡する「Read States」をRust言語で実装している<br>
https://discord.com/blog/why-discord-is-switching-from-go-to-rust

---
## 使用するライブラリとアクセストークン
- Rust製のDiscordBot用ライブラリ [cerenity](https://github.com/serenity-rs/serenity) を使用

- Discordのアクセストークンが必要となる

- exampleがあり、Botがすぐ動かせる

アクセストークンを取得

1. [開発者用のページ](https://discordapp.com/developers/applications/)からアプリケーションを作成

2. その後、BOTタブからBOTを作成

3. Oauth2からURL Generatorを選択

4. botにチェックを入れ、URLをコピー

5. コピーしたURLにアクセスし、サーバー選択 + 認証で紐づけ完了

- 詳細は[こちら](https://dot-blog.jp/news/discord-bot-token/)を参照

---
cerenityのpingpongを動かす

```
$ export DISCORD_TOKEN=xxxxxxxxxx
$ git clone https://github.com/serenity-rs/serenity.git
$ cd serenity/examples/e01_basic_ping_bot
$ cargo run
```

実行結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1770714/bb58e32b-e9a3-a838-f1c0-37e7815a8618.png)

--- 
## pingpongBotを変更
```rust:メッセージを返信している個所
    async fn message(&self, ctx: Context, msg: Message) {
        if msg.content == "!ping" {
            // Sending a message can fail, due to a network error, an
            // authentication error, or lack of permissions to post in the
            // channel, so log to stdout when some error happens, with a
            // description of it.
            if let Err(why) = msg.channel_id.say(&ctx.http, "Pong!").await {
                println!("Error sending message: {:?}", why);
            }
        }
    }
```

---
## pingpongBotを変更
```rust:メッセージを追加
    async fn message(&self, ctx: Context, msg: Message) {
        if msg.content == "!ping" {
            // Sending a message can fail, due to a network error, an
            // authentication error, or lack of permissions to post in the
            // channel, so log to stdout when some error happens, with a
            // description of it.
            if let Err(why) = msg.channel_id.say(&ctx.http, "Pong!").await {
                println!("Error sending message: {:?}", why);
            }
        }
        if msg.content == "!hi" {
            // Sending a message can fail, due to a network error, an
            // authentication error, or lack of permissions to post in the
            // channel, so log to stdout when some error happens, with a
            // description of it.
            if let Err(why) = msg.channel_id.say(&ctx.http, "Hi, I'm TestApp!").await {
                println!("Error sending message: {:?}", why);
            }
        }
    }
```

## 実行結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1770714/8d82beb7-e8a3-7510-d70a-ef2f05557e89.png)

---
## まとめ
- DiscordのBotを簡単に動かせる

- exampleから出力する文字列やデータを変更することで、表示も変えられる

- 自由に関数が加えられるので、別のAPIと連携して何かアプリを作ったりもできる

---
## 参考文献
- https://discord.com/blog/why-discord-is-switching-from-go-to-rust

- https://github.com/serenity-rs/serenity/tree/current/examples
【Ruby】メソッドのオーバーライド

##メソッドのオーバーライド

親クラスを継承した子クラスで同じメソッドを定義するとメソッドがオーバーライドされる。


```ruby
class Parent
  def talk
    puts '早く寝なさい'
  end
end

class Child < Parent
  def talk
    puts '眠い'
  end
end

p = Parent.new
p.talk
#=> 早く寝なさい

p = Child.new
p.talk
#=> 眠い
```


##super
オーバーライドされる前のメソッドを呼び出すことができるメソッド。
```super```で親クラスの```talk```メソッドを呼び出している。

```ruby
class Parent
  def talk
    puts '早く寝なさい'
  end
end

class Child < Parent
  def talk
    super
    puts '眠い'
  end
end

p.talk
#=> 早く寝なさい
#=> 眠い
```

##参考

https://docs.ruby-lang.org/ja/latest/doc/spec=2fcall.html
[Drupal] リストのキーからラベルを取得する

## やりたいこと
以下のように選択肢が定義されているリストフィールドで、`0`ではなく`Cat`を取得したい

```
0|Cat
1|Dog
2|Hamster
```

## やりかた

### その1

```php
// リストのキーを取得.
$key = $node->get('FIELD_NAME')->getString();

// ラベルを取得.
$label = $node->get('FIELD_NAME')->getSettings['allowed_values']['KEY'];
```

### その2

```php
// リストのキーを取得.
$key = $node->get('FIELD_NAME')->getString();

// ラベルを取得.
$label = $node->get('FIELD_NAME')
  ->getFieldDefinition()
  ->getFieldStorageDefinition()
  ->getOptionsProvider('value', $node)
  ->getPossibleOptions()['KEY'];
```


### その3
```php
// フィールド定義を取得.
$field_definitions = \Drupal::service('entity_field.manager')
  ->getFieldDefinitions('ENTITY_TYPE', 'BUNDLE')['FIELD_NAME'];

// リストのキーを取得.
$key = $node->get('FIELD_NAME')->getString();

// ラベルを取得.
$label = $field_definition->getSettings['allowed_values']['KEY'];

```

### その4
こんなのも見つけた。（フィールドフォーマッターの設定が「デフォルト」もしくは出力結果がラベルになっている場合のみ使用可）

```php
$label = $node->get('FIELD_NAME')->view()[0]['#markup'];
```
CXL (Compute Express Link) その3 - CXLデバイスの用途


メモリデバイスの不揮発性メモリ制御やホストIFなどを扱うソフト屋です。
仕事でCXL(Compute Express Link)まわりの技術に関わっています。
CXL技術に関連するメモ書きを残していこうと思います。
ホストまわりのこと経験・知識共に乏しいので、詳しい親切な方は教えて下さると幸いです。現在、まずはQEMUで、CXLが接続された環境を立ち上げようとしているので、教えて頂けると非常に有難いです。
また、間違い、アドバイス、その他、ご意見やご要望ありましたらお気軽にどうぞ。

今回からCXLの仕様の詳細を書こうかと思っていたのですが、まだ前置きです。

#1. Type3 CXLデバイスの位置付け
メモリデバイスの話でよく登場するのですが、メモリデバイスは下図のような階層構造で表されます。
![MemoryHierarchy.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2292852/e97b6ef7-946e-94fb-4c7c-6f43826d8c5c.png)
メモリデバイスと便宜的に呼びますが、メモリデバイスは階層の上からCPU Register、CPU Cache、DDR DIMM、CXL Type3 Device、SSD、HDDとなっています。括弧内は、それぞれのメモリデバイスで主に使用されているメモリ媒体を表記してあります。

階層の上の方が、レイテンシが短く、かつメモリ媒体のビット当たりのコストが高い、下の方がレイテンシが長く、かつメモリ媒体のビット当たりのコストが安い、ということを表しています。
帯域に関しては、この階層図では言及をしていません。

Type3 CXLデバイスは、DIMMのメモリとSSDの間に位置するデバイスとして期待されています。PMはPersistent Memoryを表しています。Persistent Memoryとは、Byte addressableは不揮発性メモリです。例えば、SSDで使われているNAND Flash Memoryは、読み書きのアクセス単位が4kB程度のページ単位、消去単位が数MBのブロック単位であるため、PMとは呼ばれません。

PMには、IntelのOptaneの名前で製品化されているPCM(Phase Change Memory)、ReRAM、MRAMなど、新規メモリと呼ばれており、各社で開発が行われています。新規メモリでは、ビット当たりのコストを下げるため、クロスポイント構造が採用されているようです。
メモリの記憶素子の材料開発に加えて、クロスポイント構造に不可欠である、セレクタと呼ばれるスイッチング素子の開発が不可欠となり、メモリのプロセス開発の障壁はかなり高く、各社とも高容量のメモリチップの製品化は難航しているようです。

自分にとってIntelは競争相手にあたるのですが、要約すると製品化まで持っていけたIntel凄いという話です。
話が長くなる上、自分はソフト屋で専門ではないので、これ以上、メモリ自体のテクノロジについて詳しく書くのは止めておきます。

#2. Type3 CXLデバイスの用途
Type3 CXLデバイスは、データセンター等で使われることが想定されています。
Type3 CXLデバイスの用途として、以下の2通りの用途が考えられます。

1. 揮発性メモリ空間の拡張空間  
DDR DIMMの用途の延長線で、CXL Type3 Deviceを使う。
2. 低レイテンシのストレージ空間  
SSDの用途の延長線で、CXL Type3 Deviceを使う。

それぞれの用途でデバイスへの要求が変わってきます。
例えば以下のような違いがあります。

- レイテンシ(Latency)
揮発性メモリ空間の拡張空間としての使い方は、DDR DIMMの延長の使い方なので、メモリのレイテンシがCPUの演算速度への影響が大きいため、使い方②より短いレイテンシであることが要求されます。

- 耐久性(Endurance)
一般的に不揮発性メモリは、データの書き換え回数に関しては、寿命があります。例えば、MLCのNAND Flash Memoryは3000回程度の書き換え回数で寿命になります。
揮発性メモリ空間の拡張空間としての使い方は、DDR DIMMの延長の使い方ということで、データの書き換えが頻繁に起こるため、低レイテンシのストレージ空間としての使い方より高い耐久性が要求されます。

- 保持期間(Retention)
一般的に不揮発性メモリは、データ保持期間についても、上限があります。例えば、MLCのNAND Flash Memoryでデータ保持が保証されているのは5年程度だったかと思います(SSDにデータを書いて放っておくと、消えてしまうことを意味しています)。低レイテンシのストレージ空間としての使い方はSSDの延長の使い方で、データを書いて保持しておくことになり、頻繁にデータの書き換えが行われる揮発性メモリ空間の拡張空間としての使い方よりも、長い保持期間が要求されます。

顧客要求や製品仕様など、具体的な数値を書くと怒られそうなので、ここには書きません。

---
次回こそは、CXLの仕様の詳細について書いていこうと思っています。
Azure Cosmos DB を確実にFreeレベルで使用する方法

# はじめに

Azure CosmosDBを使用するにあたり、確実にFreeレベルで使用する方法を最近知りました。本記事はその方法をまとめたメモです。

# Cosmos DB を Free レベルで使用する方法

最近、Cosmos DBに Cost Management という機能が増えました。
この機能を使って確実に Free レベルでCosmos DBを利用する設定を行います。

前提として、Cosmos DB の Free レベルを使うにはいくつか条件があるので、その条件を満たす必要があります。詳しくは[こちら](https://docs.microsoft.com/ja-jp/azure/cosmos-db/free-tier)。

Free レベルで使うための条件は以下です。

- 1 Azure サブスクリプションあたり、1 Azure Cosmos DB アカウントのみFreeレベルで利用可能
- 合計スループット制限が1000RU/秒になっている
- 概要ページから確認できるFree レベル割引がOpted Inになっている

![2021-11-30_18h46_36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562946/01c2252a-7dfd-b341-5255-6e051edc1e2b.png)

上記確認ができたら、Cost Management の合計スループット制限設定 で「アカウントの合計プロビジョニング スループットを、Free レベルの割引に含まれる量に制限する」にチェックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/562946/1aeb4dcd-c259-cd7d-b384-4c89a0055d9b.png)

こうしておくことで、確実にFree レベルでCosmosDBを利用できます。

# さいごに

使いすぎても勝手に料金を請求されず、止まってくれるので安心して使えそうです。
無料でつかえるのはありがたいですね。
powerapps 駆動モデル　JSの使い方

1.JSフォーマット
var Sdk = window.Sdk || {};
(function () {
  Xrm.Navigation.openAlertDialog("AAA");
  console.log("AAA");
  // Code to run in the form OnLoad event
  this.formOnLoad = function (executionContext) {
    Xrm.Navigation.openAlertDialog("BBB");
    console.log("BBB");
  }
}).call(Sdk);

2.フォームからJSを追加
![configure-events-on-from-handlers.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/368087/9cda3188-cfc5-e28f-4308-e765913639d8.png)

3.Fucntionに、Sdk.formOnloadを記入（Sdkは大文字区別）
VCIでリング的なUIをつくりたい

この記事は[スライドバー的なUIを作りたい](https://qiita.com/sakkinonana/items/f0892a67e9990975f535)の続編となります。

# リングタイプのスライドバーを作りたい
VRではUIを使いたいときに、あまりそういうコンポーネントが用意されているわけでもないので、各人作らないとなりません。特にバーチャルキャストはすべて自分で作らなくてはいけません。
いちいちUIで時間を消費するのもあまり良くないと思いますので、ここで共有したいと思います。

作るのは↓みたいな感じです。

https://twitter.com/sakkinonana/status/1465648997415399426

#モデル
前回はモデリングせずに済みましたが、さすがに今回はモデリングが必要でした。といっても、Blenderでドーナツ（トーラス）を追加するだけでOKです。お好みで適当に細くして形を整えましょう。

unityのヒエラルキー（階層構造）は以下のようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/494837/87527ba1-d3b0-1283-4feb-2b1844dede16.png)

dummyが実際に持つアイテム（実際使う際は透明にしておくといいと思う）、Sphereが操作に連動して動くインジケーター、torusがドーナツ形リングで、レールみたいな役割をします。

前回同様バーチャルキャストではある経路に沿ってだけ動く、みたいな拘束はかけられないため、掴みたいスライドバーのつまみと、実際に掴んでいるものとを別にします。その上でドーナツ上のインジケーターの座標を計算してスクリプトで移動させるという形式を取ります。

#スクリプト
以下スクリプトを貼り付けておきます。前回の流用なので、例によって別オブジェクトの色を回転角度に応じて変えています。

```lua:main.lua

local ctr = vci.assets.GetTransform("Sphere")
local dummy = vci.assets.GetSubItem("dummy")
local torus = vci.assets.GetSubItem("torus")
local lscale=0.5
torus.SetLocalScale(Vector3.one*lscale)

local flggrabdummy = False
local bufdummypos = dummy.GetPosition()
local bufctrpos = ctr.GetPosition()-- ctr.GetPosition()

local nowctrpos = bufctrpos

function update()
    --持っているときはコントローラーをコライダーダミーに追従させ、放したときはダミーをコントローラーの位置に戻す
    if flggrabdummy == false then
        dummy.SetPosition(Vector3.MoveTowards(dummy.GetPosition(),ctr.GetPosition(),1))
    else
        nowctrpos = Vector3.ProjectOnPlane(dummy.GetPosition()-torus.GetPosition(),torus.GetRotation()*Vector3.up).normalized*.6*lscale
        ctr.SetPosition(torus.GetPosition() + nowctrpos)
    end

    -- 色をつける
    local hueangle = Vector3.SignedAngle(nowctrpos,torus.GetRotation()*Vector3.left,torus.GetRotation()*Vector3.up)+180
 
    local starcolor = Color.HSVToRGB(hueangle/360,1,1)
    print(starcolor)
    vci.assets._ALL_SetMaterialColorFromName("blackbody", starcolor)

    vci.assets._ALL_SetText("Temp", string.format("hue %d",hueangle))

end

function onGrab(target)
    if target == "dummy" then
        flggrabdummy = true
        print("grabbing")
        bufdummypos = dummy.GetPosition()
        bufctrpos = ctr.GetPosition()
    end
end

function onUngrab(target)
    if target == "dummy" then
        flggrabdummy = false
        print("ungrabed")
    end
end
```

骨子は前作のスライドバーと同じですが、スライドバーと違って、無限回転するので、角度をとります。
なのでポイントは

```lua
nowctrpos = Vector3.ProjectOnPlane(dummy.GetPosition()-torus.GetPosition(),torus.GetRotation()*Vector3.up).normalized*.6*lscale
```

ここですね。（ここの0.6はドーナツの大きさです）

```lua
local hueangle = Vector3.SignedAngle(nowctrpos,　torus.GetRotation()*Vector3.left,torus.GetRotation()*Vector3.up)+180
```

ここもです。今回は回した角度を求めるのに、

1. トーラス（リング）のある平面に、持っているdummyの位置を投影する
1. 投影された位置と、基準となるベクトルの角度を求める。この時、Angle()ではなくSingnedAngleを使うことで360度求まる
1. SignedAngleは-180度~180度の値をとるので、180を足して正規化する。

ということをやっています。ProjectOnPlaneはこういうのに使えるので、結構便利に使っています。


#おわりに
実際UIを一から作るのは以外に大変ですから、VCI製作者としては他にも使いたいUIはたくさんあると思うので、ぜひ皆さんも作ったら共有していってください。いちいちUIに消耗してるのはもったいないからね。


読んでいただきありがとうございました。
DartでHTTPサーバを立てる

FlutterでOAuthを実装しようとしたときに、OAuthを使おうとしたサービスがredirect_urlにCustom URL Schemeが使えなかった（http://~, https://以外許可されていなかった）ので、
リダイレクト先のHTTPサーバを立ててあげようとしたときのメモ。

```dart
import 'dart:io';

Future<void> main() async {
  final server =
      await HttpServer.bind(InternetAddress.LOOPBACK_IP_V4, 8080, shared: true);
  listenForServerResponse(server);
}

listenForServerResponse(HttpServer server) {
  server.listen((HttpRequest request) async {
    final uri = request.uri;
    request.response
      ..statusCode = 200
      ..headers.set("Content-Type", ContentType.HTML.mimeType);

    final code = uri.queryParameters["code"];
    final error = uri.queryParameters["error"];
    await request.response.close();
    if (code != null) {
      print(code);
    } else if (error != null) {
      print(error);
    }
  });
}
```

エミュレータとかで試してないけど、こんなコードでRedirectされてきたURLのQueryParameterからCodeが取れるはず。

- `InternetAddress.LOOPBACK_IP_V4` は`127.0.0.1`になっているはず
- HttpServer.bindの２つ目の引数でポートを指定する。この場合`8080`
- `shared: true`は他のHttpServerが同じアドレスにBindできるかどうかのフラグ（？）っぽい。別インスタンスのHttpServerを同じポートで複数建てられるってコト？！
    - https://api.flutter.dev/flutter/dart-io/HttpServer/bind.html
    - ワーカーみたいにたくさんServerを立てられるってコトかも？ -> Isolateが一緒だと結局遅くなりそうだけどどうなんだろうか

## 実行サンプル

```powershell
> curl 'http://localhost:8080/?code=12345'


StatusCode        : 200
StatusDescription : OK
Content           :
RawContent        : HTTP/1.1 200 OK
                    x-frame-options: SAMEORIGIN
                    x-xss-protection: 1; mode=block
                    x-content-type-options: nosniff
                    Content-Length: 0
                    Content-Type: text/html


Forms             : {}
Headers           : {[x-frame-options, SAMEORIGIN], [x-xss-protection, 1; mode=block], [x-content-type-options, nosniff], [Content-Length, 0]...}
Images            : {}
InputFields       : {}
Links             : {}
ParsedHtml        : mshtml.HTMLDocumentClass
RawContentLength  : 0
```

```powershell
> dart .\main.dart
12345
```
[Drupal] フィールドのマシン名からフィールドのラベルを取得する

```php
// ノードのarticleコンテンツタイプのfield_testのラベルを取得する.
$field_definitions = \Drupal::service('entity_field.manager')->getFieldDefinitions('node', 'article');
$label = $field_definitions['field_test']->getLabel();
```
【Linux】【zcat】圧縮ファイルの中身を解凍せずに確認する方法

awsのs3環境で作業をしていると、gzファイルなどの圧縮ファイルを扱うことが多いです。
大体はファイルの移動で終わりますが、データが正しいか中身を確認したい時もあります。
ファイルを別ディレクトリにコピーし、解凍後にcatコマンドやviコマンドで確認することもできますが、正直そんな事をしていたら非効率ですので、そんな時に以下コマンドが役に立ちます。

<BLOCKQUOTE><FONT COLOR=red>zcat</FONT></BLOCKQUOTE>

使い方は簡単で、cpコマンドのオプションとして語尾に付けるだけです。

<BLOCKQUOTE>aws s3 cp s3://xxxx/xxxx/test.tsv.gz <FONT COLOR=red>- | zcat</FONT></BLOCKQUOTE>

下記のようにオプションを付け足すことで、レコード件数を確認出来たりもします。

<BLOCKQUOTE>aws s3 cp s3://xxxx/xxxx/test.tsv.gz <FONT COLOR=red>- | zcat | wc -l</FONT></BLOCKQUOTE>

awsではなく普通のLinux環境でしたら、下記のようにして確認可能です。

<BLOCKQUOTE><FONT COLOR=red>zcat</FONT> test.tsv.gz</BLOCKQUOTE>

以上です。
str.containsで複数の式を利用


#概要#
str.containsで「or」といった複数の条件を設定する際には正規表現を利用

#実装#
データフレームの作成

```
import pandas as pd

dict1=dict(date=[20151204,20151204,20151204],prefecture=["東京都","神奈川県","和歌山県"])
list1=pd.DataFrame(data=dict1)
list1
```

| date | prefecture | 
|:-:|:-:|:-:|:-:|
|20151204| 東京都  |True|   
|20151204| 神奈川県| True|   
|20151204| 大阪府|False|  

都道府県から任意の地方に該当するかについてstr.containsの複数の式を利用

```
list1['関東']= list1['prefecture'].str.contains('神奈川県|東京都')
list1
```

| date | prefecture | 関東| 
|:-:|:-:|:-:|:-:|
|20151204| 東京都  |True|   
|20151204| 神奈川県| True|   
|20151204| 大阪府|False|   

正規表現を使わないと以下のようになってしまいます。

```
list1['関東']= list1['prefecture'].str.contains('東京都' or '神奈川県')
list1
```

| date | prefecture | 関東| 
|:-:|:-:|:-:|:-:|
|20151204| 東京都  |True|   
|20151204| 神奈川県| False|   
|20151204| 大阪府|False|
Ubuntuで起動時に自動でShellScriptを実行する方法

# はじめに
UbuntuでShellScriptやプログラムを自動で実行しようとしたとき、たまにハマるというのとそこそこ聞かれるので記事にしようと思いました。
serviceを使用する方法を使うためsystemctlコマンドで止めたり再起動をかけたりできるので私はこのやり方を使ってます。
# 環境
Ubuntu16.04
# 準備
ひとまずこの記事の内容を確認できるようにShellScriptの作成や権限付与の準備を行います。
## ShellScriptの作成
ひとまず、テストでShellScriptを作成します。
場所はユーザー直下にします。
`$ vim test.sh`

```html:~/test.sh
#!/bin/sh
ping localhost > ~/test.log
```
このShellScriptは自身のPCのping応答テキストに残す内容になっています。
## 権限付与
実行権限を付与します。
`$ chmod +x ~/test.sh`

# serviceファイルの作成
自動実行のためのserviceファイルを作成します。
今回はテストでauto_shell.serviceを作ります。
これはroot権限が必要になります。
`$ sudo vim /etc/systemd/system/auto_shell.service`

```html:/etc/systemd/system/auto_shell.service
[Unit]
Description=ping service
After=network.target

[Service]
User=[ユーザー名]
ExecStart=/home/[ユーザー名]/test.sh
Restart=always
type=simple

[Install]
WantedBy=multi-user.target
```
ExecStartに実行ファイルを書くのですが、フルパスで入れないと起動しません。
よくハマっている人を見ます。

# 自動起動の設定
これを忘れてハマりました(1敗)
`$ sudo systemctl enable auto_shell.service`
後は再起動後/home/ユーザー名/test.logが生成されていれば成功です。
自動起動をやめる場合はdisableコマンドでやめれます。
`$ sudo systemctl disable auto_shell.service`

# その他systemctlコマンド
シェルが動いているか確認するときやserviceファイルを更新したときに私が良く使うコマンドを紹介します。

## serviceファイルの更新後に使用するコマンド
これを忘れて頭を悩ませることが多々ありました。(大敗)
`$ sudo systemctl daemon-reload`

## serviceが動いているか確認するときのコマンド
エラー内容やactiveなのかdeadなのかが分かったりします。
`$ sudo systemctl status auto_shell.service`

## serviceが自動起動状態か確認するコマンド
enbaleになっていれば自動起動の状態です。
`$ sudo systemctl is-enable auto_shell.service`

## serviceを再起動するコマンド
これもよく使います。
`$ sudo systemctl restart auto_shell.service`
【RSpec】APIのリクエストテストでgemはあまり使われていないらしい

APIのリクエストテストをやる際、
jsonが期待通りに取れているかをもっとわかりやすく書けないかと思ったときにいくつかgemを発見した。

- [jsonapi-rspec](https://github.com/jsonapi-rb/jsonapi-rspec/)
- [rspec-json_matcher](https://github.com/r7kamura/rspec-json_matcher)

最後のコミットが何年も前だったこと、starの数もあまり多くなかったこと、実際に使ってみて使いづらかったことを踏まえてgemは使わずやることにした。

gemを使ったAPIのリクエストテストの方法をあまり記事で見かけなかったので、みんなそもそもgemを使わないのかなーとも思った。


```spec.rb
...
it '自分の本の情報が昇順に返ること' do
  json = JSON.parse(response.body)
  expect(response.status).to eq 200
  expect(json['books']).to eq([
    {"id"=>book.id, "type"=>"mystery", "date"=>"2021-01-01", "punched_at"=>1609459200},
    {"id"=>book2.id, "type"=>"love", "date"=>"2021-01-05", "punched_at"=>1609804800},
    {"id"=>book1.id, "type"=>"mystery", "date"=>"2021-01-11", "punched_at"=>1610323200}
  ])
end
...
```
React Nativeでreact-native-async-storageを使う

<h1>（１）作成のきっかけ</h1>

<p>普段はソーシャルワーカーとして障がいをお持ちの方の支援をしており、IT技術を使用して事業所の運営や支援に役立つようなことが実現できたらなと思っています。</p>

<p>以前、モバイルアプリを作成してみたいと思い、アップルストアに年間使用料を払って登録したのですが、なかなか時間がなくて💦これはもったいないなと思い、集中して一カ月ほどreact-nativeを勉強して、なんとかストアに登録することができたので、使用したライブラリについてなんかを書いてみようと思います。</p>

<h1>（２）作成したモバイルアプリ</h1>

<p>指定難病についての情報にアクセスするためのモバイルアプリです。11月1日に新たに難病が追加されることもあり、実際に難病の方の支援をすることもあるので、自身の勉強のためにも作成してみました。</p>

<h1>（３）使った技術</h1>

<p>
・react-native<br>
・Expo<br>
・react-navigation<br>
・react-native-maps<br>
・react-native-multi-selectbox<br>
・react-native-async-storage

<p>などなどです、react-nativeやExpoの情報はバージョンによって動く動かないがあるので苦労しました。</p>

<h1>（３）useContext の値を端末にも保存</h1>
<p>タイトルの通り、react-native-async-storageを使用して、useContextでの状態管理の値を端末に保存します</p>
```ts
// ./ModesContext"

import React, { createContext, useState, useEffect } from "react";
import AsyncStorage from "@react-native-async-storage/async-storage";

export const ModesContext = createContext();

export const ModesContextProvider = ({ children }) => {
  const [modes, setModes] = useState("");
  const saveModes = async (value) => {
    try {
      const jsonValue = JSON.stringify(value);
      await AsyncStorage.setItem("@modes-", jsonValue);
    } catch (err) {
      console.log("保存できませんでした", err);
    }
  };

  const loadModes = async () => {
    try {
      const value = await AsyncStorage.getItem("@modes-");
      if (value !== null) {
        setModes(JSON.parse(value));
      }
    } catch (err) {
      console.log("読み込めませんでした", err);
    }
  };

  const change = (mode) => {
    setModes(mode);
  };

  useEffect(() => {
    loadModes();
  }, []);

  useEffect(() => {
    saveModes(modes);
  }, [modes]);

  return (
    <ModesContext.Provider
      value={{
        modes,
        changeModes: change,
      }}
    >
      {children}
    </ModesContext.Provider>
  );
};
```
各画面で使うときは

```ts

// 包んであげてください
import { ModesContextProvider } from "./ModesContext";
<ModesContextProvider>
 <App>
</ModesContextProvider>

// 各画面で使うときは
import React, { useContext } from "react";
import { ModesContext } from "./ModesContext";

//　値を参照する
const { modes } = useContext(ModesContext);

// 値を変化させる
const { changeModes } = useContext(ModesContext);
changeModes((previousState) => !previousState);


```
端末に保存されているので次回起動時も設定が継続されます

<h1>（４）終わりに</h1>

<p>アプリをストアに登録することで達成感がありました、Expoを使うことで簡単にストア登録ができたことは有難かったです。今回は自身の勉強とアプリを登録することを目的としましたが、次回はニーズに合わせたものを作りたいですね。いろいろ考えながら作っている時が一番楽しいですね:relaxed:</p>
Cloud Runで動くflaskアプリをサクッと作る

# 背景
Cloud Runで動く簡易的なFlaskアプリが必要だったので構築した時のメモ。


# 実装
Hello World返すFlaskのDockerイメージを作成する

```py:main.py
from flask import Flask

app = Flask(__name__)

@app.route("/")
def hello_world():
    return "<p>Hello, World!</p>"
```

python3.9 + Flaskのイメージにする。ポートは80。

```Dockerfile:Dockerfile
FROM python:3.9

ENV APP_HOME /app
ENV FLASK_APP main
WORKDIR $APP_HOME
COPY . .

RUN pip install -r requirements.txt

CMD flask run --host=0.0.0.0 --port=80

EXPOSE 80
```

```requirements.txt
#
# These requirements were autogenerated by pipenv
# To regenerate from the project's Pipfile, run:
#
#    pipenv lock --requirements
#

-i https://pypi.org/simple
click==8.0.3; python_version >= '3.6'
flask==2.0.2
itsdangerous==2.0.1; python_version >= '3.6'
jinja2==3.0.3; python_version >= '3.6'
markupsafe==2.0.1; python_version >= '3.6'
werkzeug==2.0.2; python_version >= '3.6'
```
イメージをビルドしてGCPにpushする

```sh
# ビルド
docker build -t flask_server:tag_name . 
# イメージをContainer Registryにpush
docker tag flask_server:tag_name gcr.io/${YOUR_PROJECT}/flask_server:tag_name 
docker push gcr.io/${YOUR_PROJECT}/flask_server:tag_name
```

Cloud Runのコンソールで、pushしたimageを指定してポート80で作成すればおk。

# 参照

https://qiita.com/munaita_/items/139807ba354620867072

https://flask.palletsprojects.com/en/2.0.x/
Laravel8 Dusk操作

#Laravel Dusk

##ナビゲーション
###visit
```
$browser->visit('/hello');
```
>visitメソッドを使用して、アプリケーション内の特定のURIに移動できます。

###visitRoute
```
$browser->visitRoute('hello');
```
>visitRouteメソッドを使用して名前付きルートへ移動できます。

###backおよびforward
```
$browser->back();

$browser->forward();
```
>backおよびforwardメソッドを使用して「戻る」および「進む」をナビゲートできます。

### refresh
```
$browser->refresh();
```
>refreshメソッドを使用してページを更新できます。


---
# 要素操作
## マウス操作
###click
#### click(css)
```index.blade.php
<button class="h-button">送信</button>
```

```tests\Browser\HelloPageTest.php
    public function testExample()
    {
        $this->browse(function (Browser $browser) {
            $browser->visit('/hello')
                    ->click('.h-button');
        });
    }
```

#### click(Duskセレクタ)
```index.blade.php
<button dusk="h-button">送信</button>
```

```tests\Browser\HelloPageTest.php
    public function testExample()
    {
        $this->browse(function (Browser $browser) {
            $browser->visit('/hello')
                    ->click('@h-button');
        });
    }
```
>セレクタを定義するには、HTML要素にdusk属性を追加します。次に、Duskブラウザを操作するときに、セレクタの前に@を付けて、テスト内でアタッチされた要素を操作します。

---

## フォーム操作

### type
```
$browser->visit('/hello')->type('gender', '男');
```
>このメソッドは必要に応じて１引数を取りますが、CSSセレクタをtypeメソッドに渡す必要はないことに注意してください。CSSセレクタが提供されていない場合、Duskは指定したname属性を持つinputまたはtextareaフィールドを検索します。

### clear
```
$browser->clear('gender');
```
>入力値をクリアするには、clearメソッドを使用します。


### リンクのクリック
```
->clickLink($linkText)
```
>リンクをクリックするには、ブラウザインスタンスでclickLinkメソッドを使用します。clickLinkメソッドは、指定した表示テキストを持つリンクをクリックします。


---

## アサート

###assertSee

```
$browser->assertSee($text);
```
> 指定したテキストが、ページ上に存在することを宣言します。



##環境
- Laravel Framework 8.73.2
OSSのコントリビュータになろう!

# 本記事で語る事
- そもそも「コントリビュータ」って何?
- コントリビュータになるメリット
- **初学者の方こそコントリビュートに挑戦して欲しい**、という事
- コントリビュータになる事は難しくない
- コントリビュータになる流れ

# (大前提)OSSとは
知ってらい!という方が多いかと思いますが、あえて...

OSSとは、
オープンソースソフトウェア、の略称です。

Web開発での例に挙げさせて頂くと、
ReactやjQuery等、無償での利用が可能なソフトウェアになります。

昨今、Web開発であればReactやVue.js等を使わないプロジェクトはほとんど無い、ソフトウェアエンジニアにとっては非常に身近な存在であると考えます。

詳細は[こちら](https://ja.wikipedia.org/wiki/%E3%82%AA%E3%83%BC%E3%83%97%E3%83%B3%E3%82%BD%E3%83%BC%E3%82%B9%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2)

# コントリビュートとは
和訳 -> *contribute* : *貢献する*  

OSS開発においては、有志によるOSS開発への貢献を指します。 

貢献、とは様々な形がありますが、

本記事ではバグ改修、機能改善等、**ソフトウェア(OSS)の開発、改善**を貢献として解説させて頂きます。

# ハードルは高い?
高くありません。

OSS、内容によりますが、難易度が高い複雑なバグ改修、機能追加だけが貢献ではありません。

非常に軽微なバグ改修や、README等のドキュメントリソースの誤字脱字修正も立派な貢献です。

# コントリビュートするメリット
## 技術力の向上につながる
自身が興味を抱いているOSSや、普段から使っているOSSであれば、そのOSSに対する習熟がより深まります。
また著名なOSSであれば、**開発に携わっているハイスキルなエンジニアのテクニックをより身近で吸収するチャンスにも恵まれます。**

## 転職活動でアピールポイントになる
Web系企業であれば、応募時点でGithubのアカウントまで確認される、という風潮はもう珍しい物ではありません。

ポートフォリオや個人開発といった自分だけの開発実績もアピールに繋がりますが、OSSへのコントリビュートは更にアピールに繋がりやすいです。

何故ならば、大小含め**OSSへのコントリビュートを果たせる時点で、ある程度のリテラシーが担保されるから**です。

リテラシーとは何ぞや?という点に関してですが、例を挙げると
 - Git(+Github)のリテラシー
 - チーム開発のリテラシー
 - 英語力のリテラシー
   - 大抵のOSSは英語で管理されているため  


 等です。
 
 
以上の理由から、  
特に初学者の方にとって、OSSのコントリビュータに挑戦するという事は、**学びになると同時に転職時へのアピールポイントにも使える、エンジニアとして非常に有用な自己投資となりえます。**


# コントリビュートの流れ
## 前提
 - Githubで管理されているOSS
 - 詳細な手順は各OSSによって異なる
 - 作業環境にはgitのクライアントツールがインストール済


## 手順
1. [Github](https://github.com/login)にログイン
2. コントリビュートしたいOSSのGithubリポジトリにアクセス
3. 対応出来そうなバグ、改善を*Issues*から見つける
4. 「Contributing」**というニュアンスの項目**がどこかにあるので、探し出す(キャプチャは[Next.js](https://github.com/vercel/next.js/))![](https://storage.googleapis.com/zenn-user-upload/1a61725fb717-20211130.png)

4. 記載されている手順に沿って作業を進める


以上です。
上記だけだとイメージしづらいかもしれないので、よくある流れをかいつまんで紹介します。

### よくある流れ
1. 環境構築
      - `git clone`から始まり、その後は必要な各種モジュールを手順に沿ってインストールしていく。
2. 実装
3. テストコード作成
4. テスト実施
     - 実施した結果次第で2、3に戻って実装を直す
5. コミット
6. プルリクエストを作成
     - レビューバックがあれば対応。2～6までの流れを再度行う。
7. 🎉マージ🎉


# 終わり
如何だったでしょうか。

この記事を見て、OSSのコントリビュータ活動を始められる方が一人でも増えれば幸いです。
それでは。
ゲームテスター未経験のプログラマがゲーム自動化スクリプターにジョブチェンジした話

#はじめに
この記事には事実とフィクションを織り交ぜています
あらかじめご了承ください

#プロフィール
とある東北にて生まれすくすくと育ち専門学校でPGを学び現在東京にてプログラマをしています
使用言語
> - JavaScript
> - HTML
> - Java
> - SQL（読めるだけ）
> - Python

好きなゲームは
> - すばらしきこのせかい（最新作よかったよ…）
> - ダンガンロンパシリーズ（個人的にV3の結末好きだよ）
> - プリコネ（毎月2桁順位でクラバトを嗜んでる）
> - 逆転裁判シリーズ（最近は神ゲー逆転検事2を再プレイした）
> - DISSIDIA FINAL FANTASY NT（ROM選）

記事作成当時やってるゲームはGhost of Tsushimaです


#経緯
元々非ゲームのSESでプログラマをしていました
しかしブラック案件をたらいまわしにされ精神がすり減り退職

転職サイトにエントリーし次の仕事は何ににするか悩んでいるときに
知人がゲームのテスターをしていたので話を聞いてみたところ興味が湧き応募してみました
（結果テスターではなく経験を生かしてゲームQA自動化を行うバリバリのプログラマとして働いていますが）

#ゲーム自動化を扱ってみての感想
フレームワークはAirtestを用いていますが、使ってみると直感的でわかりやすいし使いやすい
どういうフレームワーク知りたい方がいましたらググってほしいですが、
元々非ゲームでお仕事していたときも
#####WEBの画面範囲指定して処理できたらいいのになぁ！！！
と思ってたのでAirtestの画面を範囲指定し画像にしその画像を使用して処理するという方法は私の性に合っていました
ゲームテスター未経験で入社しましたが、テストする際に注意してみる箇所はほぼ同じでそこにゲーム、非ゲームの差はありませんでした
まだゲーム自動化が発展途中ということで自分たちで工夫してあれこれ進めていくのも楽しいところではあります
皆さんもぜひ試してはいかがでしょうか。

#注意点
スマホゲームによっては自動化を試みて禁止事項に値しアカBANされるケースもあるかと思いますが、当方は責任を一切負いません。
データの面積按分とその他の按分

# はじめに

技研商事インターナショナルの柿沼です。
Location Tech Advent Calendar 2021 by LBMA Japan 🛰 Advent Calendar 2021の11日目の投稿となります。

位置情報と関連するテーマとしてデータの按分について簡単にですが書いてみました。

# データの按分

「施設への来訪者の居住地データを町丁目単位で入手したがメッシュ単位での分析をしたい！」
このようなケースでデータの按分を検討することになりますが、シンプルな面積按分とその他の按分について比較してみました。

# 面積按分

面積按分とはその名の通り面積に応じてデータを配分する方法です。
![面積按分_01_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2277366/6ecb820b-5e08-372d-bc9d-6fdce983ad18.png)
例えば、上図での青枠の町丁目内に居住する来訪者100人を赤枠の3つのメッシュへ按分する時、町丁目の面積が3つのメッシュへ56％、43％、1％と属しているならば、来訪者100人をそれぞれ56人、43人、1人と配分する、ということになります。

# 面積按分以外

### 実は…

上の例のように面積按分はシンプルですが、実は次の図のように左上のメッシュには川が通っており河川敷で居住者が少ないエリアだったとすると、青枠の町丁目の来訪者を面積の比率に従い56％配分してしまうのはまずそうです。
![面積按分_02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2277366/d387bb64-7f82-3d5f-6c93-7deec8d5712c.png)

### 例えば世帯数按分

面積を用いた按分ではダメということで、今回は世帯数データを使用して按分してみます。
![面積按分_03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2277366/9fe0ab0c-f287-528e-07b6-2e791060a005.png)
例えば3つのメッシュの世帯数が上のような場合、まずは青枠のエリア内はそれぞれ何世帯となるか、面積按分で求めます。
![面積按分_04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2277366/f86bfce5-37b4-1590-b203-12a7129215ed.png)
↑求めました。
あとは最初の面積の代わりに世帯数の比率で青枠内の来訪者数を按分します。
![面積按分_05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2277366/2d47d996-5748-244d-a963-fb87bd515137.png)
最初の例と比べると大きな差がある結果となりました。

今回は「世帯数」をもとに按分した例を挙げていますが、来訪者の傾向に合わせて「20代人口」を採用する、といったケースも考えられるかと思います。
どこまでいっても実データとは一致しないということで、実際の運用ではデータ利用者にとって納得感のあるような按分手法を選択することも考えられます。

# 最後に

町丁目単位の来訪者数データをメッシュ単位に変換する今回の例のように、本来存在しないデータを作成することができる点が按分の大きなメリットです。

一方で、按分に使用できるような面積以外のデータが都合よく見つからなかったり、按分結果の検証も難しかったりと、実際にはいろいろとハードルがあります。
今回は簡単なケースの例示のみとなりましたが、今後このあたりのノウハウについても調べられたらと思っています。
【javascript】例外処理, try

# 例外処理

エラーが発生した時に飛ぶ特別な処理

## tryの基礎構文

```js
try { //try直下の構文に何らかのerrorが発生したらcatch処理へ
    console.log('start') 
    throw new Error('error message');
    console.log('end')
} catch(e){
    console.error(e);
} finally {　//終了処理は必ず通る。
    console.log('bye')
}

```

## case

* 取得したいjsonファイルが空だったらerrorを出力する

```js
async function fetchUsers(){
    const response = await fetch('users.json')
    if(response.ok){ //responseには成功可否を判断するokプロパティが存在する。
        const json = await response.json(); //jsonファイルにアクセス。
        if(!json.length){ //jsonデータが空だったらtrue
            throw new Error('no data found')
        }
    return json;
    }
}


async function init(){
    try {
        const users = await fetchUsers(); //上で作成した関数を実行
        for(const user of users){
        console.log(`私は ${user.name}, ${user.age} 才です。`)
        }
    }catch(e){ //errorが飛んできたらここを処理
        console.error(e);
    } finally {　//終了処理は必ず行う
        console.log('bye')
    }
}

init();

```
Dockerで、検証用サーバーを構築してみた① (Dockerインストール編)

# 初投稿

## [投稿の背景]
日頃、開発業務に携わり着々と業務をこなすと、知識の定着が主な目的でもありますが
学んだ内容を記録していきたいなと思って投稿を開始しました。

## [概要]
タイトルの内容になりますが、
アプリ開発をしていると、
サーバー通信を実装したりすることもあると思いますが
今回は、HTTP通信で、固定のレスポンスデータを返却できたら、
また、その上で自由にデータを書き換えることが出来たら。良き良きと言う事で構築してみました。
**※記事の内容は浅い箇所もあると思いますが、まずは実践して成し遂げる事を目的としています。**

**<メリット>**
・Dockerを少しでも学べる。 (※今回使用)
・短時間で、リクエストからレスポンスを体験できる。
・検証サーバー（基盤）を構築できるので、今後応用できる。

**<記事数>**
①〜⑤

## [作業]

##Dockerのインストール

Dcokerは、仮想環境を構築してアプリケーションを開発できるソフトウェア。
仮想環境を作って、色々できるみたい。
今回は、検証用サーバー構築のため、この子を使用してみたいと思います。

DLサイト：https://hub.docker.com/editions/community/docker-ce-desktop-mac/

[手順]
1, 上記DLサイトにて、ソフトを落してきてインストール！
2, 以下、コマンドででDokcerバージョンが表示されればとりあえずOK！


```ruby:terminal
$ docker -v
```

## [次のページ]
[② Dockerファイル作成編](https://qiita.com/Mar_N/items/da22489496c3003eb80f)


## [参考]
・ https://qiita.com/tomokei5634/items/7b1e7a121d5d7bc12116
【初心者】PostgreSQLのコマンド類すぐ忘れる

# psqlコマンドをすぐ忘れる
postgres12.3環境

## OSのコマンド
#### postgresクライアントで接続

```console
# psql -U postgres -W
Password: 
psql (12.8)
Type "help" for help.

postgres=# 
```

#### DB一覧

```console
# psql -l
```

## クライアントのコマンド
#### DB一覧

```console
postgres=# \l
```

#### DBに接続

```console
postgres=# \c db名
データベース"db名"にユーザ"ユーザ名"として接続しました。
```

```console:同じデータベースで接続ユーザを変える
postgres=# \c - ユーザ名
```

```console:別データベースに別ユーザで接続
postgres=# \c データベース名  ユーザ名
```

#### DB作成

```console
postgres=# createdb --owner オーナー名　db名
```

#### DB削除

```console
postgres=# drop database db名
```

#### スキーマ作成

```console
postgres=# create schema スキーマ名 AUTHORIZATION オーナー名
```

#### スキーマ削除

```console
postgres=# drop schema スキーマ名 CASCADE
```

#### スキーマ一覧

```console
postgres=# \dn
```
#### カレントのスキーマを確認

```console
postgres=# select current_schema();
```

#### カレントのスキーマの切替え

```console
postgres=# set search_path=スキーマ名;
SET
```

#### クライアントのカレントディレクトリを移動する

```console
postgres=# \cd パス
```

#### (カレントのスキーマに)DDLを流し込む

```console
postgres=# \i  sqlファイルのパス
```

#### テーブル一覧

```console
postgres=# \z
```


https://qiita.com/Shitimi_613/items/bcd6a7f4134e6a8f0621
LIFFでWebSpeechAPI(音声認識)が動くのか試してみた

本記事は [NECソリューションイノベータ　Advent Calendar 2021](https://qiita.com/advent-calendar/2021/nec_solution_innovators) の12/1の記事です。

## きっかけ

最近、LIFFを使ったWebアプリを作る機会が多く、カメラを使ったバーコードリーダーを作ったりしたため、マイクアクセスも同様に実装できるのか試したかったのがきっかけです。

## 先に結論

Chrome（Android）やMobile Safari（iOS）では動きましたが、LIFFブラウザではWeb Speech API(音声認識) が動作するところまで確認できませんでした。。
以下、調査した内容をまとめています。

## Web Speech API とは

Web Speech API は、Webアプリケーション(ブラウザ)で音声を使った機能を提供するAPIであり、主に音声認識(Speech Recognition)と音声合成(SpeechSynthesis)いう2つの機能があります。
いくつかのクラウドサービスで音声を認識したりするサービスはありますが、WebSpeechAPIはブラウザ上の機能であるため、サーバー側の用意が不要になる点がメリットです。  [参考](https://developer.mozilla.org/ja/docs/Web/API/Web_Speech_API)

### 音声認識(Speech Recognition)動作デモ

公開されているデモで実際に動作を確認してみましょう。２つのデモのURLを以下に記載します。

- https://browser-recognition.glitch.me/
- https://mdn.github.io/web-speech-api/speech-color-changer/

### ブラウザ対応状況

WebSpeechAPIはブラウザ上の機能と書きましたが、全てのブラウザで対応しているわけではありません。[こちら](https://developer.mozilla.org/ja/docs/Web/API/SpeechRecognition#browser_compatibility)のようにブラウザによって対応状況が異なります。

## LIFF とは

LINE Front-end Framework（LIFF）は、LINEが提供するウェブアプリのプラットフォームです。自分で作ったWebアプリをLINE上で動作させることができ、このプラットフォームで動作するWebアプリを、LIFFアプリと呼びます。  [参考](https://developers.line.biz/ja/docs/liff/overview/)

### LIFFブラウザ

LIFFはWebアプリとして動作しますが、chromeやsafariといったブラウザで動作するわけではありません。デフォルトではLIFFブラウザという、iOSであれば[WKWebview](https://developer.apple.com/documentation/webkit/wkwebview)、Androidであれば[Android Webview](https://developer.android.com/reference/android/webkit/WebView)に準拠した実装になっているようです。また、v2からは機能の制限等はありますが、外部ブラウザで開くことも可能です。[参考](https://developers.line.biz/ja/docs/liff/overview/)

![image](https://developers.line.biz/assets/img/liffBrowser.b6283a4f.png)

### LIFFブラウザで動かしてみた

今回LIFFアプリを作成する手順は省略しますが、上記のデモ等を参考に実装したWebアプリを動作させてみた結果を以下に記載します。
 

|  | Chrome | Safari | Mobile Safari | LINE | 
| ------------ | ------ | ------ | ------------- | ---- | 
| PC(Mac)      | ○     | ×      | -             | -    | 
| iphone       | ×      | -      | ○            | ×    | 
| Android      | ○     | -      | -             | ×    | 


- 端末(行)とブラウザ(列)のマトリクスです
  - 端末のバージョンはMacが11.6、iphoneが14.8.1、Androidが11です。
  - 列に記載しているブラウザの名前は[ua-parser-js](https://github.com/faisalman/ua-parser-js)というライブラリのgetBrowserを使って取得しています。LINEとなっている部分がLIFFブラウザのことです。 
- ×の部分は共通してマイク許可のダイアログが出てこなかったです。
- どの端末でもいずれかのブラウザでは動作しましたが、共通的に動作するブラウザはありませんでした（私の実装自体が悪い可能性は大です） 







## 参考
MDN Web Docs

- https://developer.mozilla.org/ja/docs/Web/API/Web_Speech_API
- https://developer.mozilla.org/ja/docs/Web/API/SpeechRecognition#browser_compatibility

LINE Developers

- https://developers.line.biz/ja/docs/liff/overview/ 
- https://developers.line.biz/ja/docs/liff/development-guidelines/

twilio BLOG

- https://www.twilio.com/blog/speech-recognition-browser-web-speech-api-jp
[JavaScript] sort()の使い方

文字列のソートに```sort()```を使用したので使い方と合わせて数値のソートについてもまとめておく。

# sort()の使い方
この```sort()```は、配列の要素を順番に並び替えてくれるメソッド。このメソッドは、配列の要素を***文字列に変換してから比較***を行い、昇順にソートされる。そのため、文字列を比較する場合は次のように書ける。

```javascript:
array = ["red", "white", "blue", "green", "black"];
array.sort();    // [ 'black', 'blue', 'green', 'red', 'white' ]
```
ここで、ソートされた結果は元の配列（上記だとarray）に上書きされるので、元の配列データは変更されてしまうことに注意が必要である。元の配列のデータを保持しておきたい場合は、あらかじめ配列をコピーしておく必要がある。

###数値の比較の場合
上記のように文字列の比較はそのままメソッドを使用すればよいが、数値を比較する場合は比較関数を指定して記述する。比較関数はアロー関数（ラムダ式）を使って書くこともできる。一次元配列の数値のソートを行う場合は以下のように書ける。

```javascript
// 昇順ソート
array = [130, 90, 30, 7, 50];
array.sort((a,b) => a - b);    // [ 7, 30, 50, 90, 130 ]

// 降順ソート
array = [130, 90, 30, 7, 50];
array.sort((a,b) => b - a);    // [ 130, 90, 50, 30, 7 ]
```