OmniAICreator/Qiita-1.07M huggingface dataset:
Databricksにて現在のノートブックのワークスペースURLを取得する方法

## 概要
`dbutils.notebook.entry_point.getDbutils().notebook().getContext()`によりノートブックのセッション情報が取得でき、`browserHostName`の値が現在実行しているノートブックのワークスペースURLであるようです。

```python
import json
notebook_info = json.loads(dbutils.notebook.entry_point.getDbutils().notebook().getContext().toJson())

notebook_info
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/7fbf1445-ffdf-4931-82e9-8f55339ed7a9.png)

ただし、Jobsとして実行する場合に、取得できなことに注意してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/f343ecbb-512e-8550-31b3-6b8adaac7e9f.png)


## 現在のノートブックのURLを取得する方法
### 1. 下記のコードを実行

```python
import json
browserHostName = json.loads(dbutils.notebook.entry_point
                                      .getDbutils()
                                      .notebook()
                                      .getContext()
                                  .toJson()
                                 )['tags']['browserHostName']

# プロトコルを追加
db_url = f"https://{browserHostName}" # DatabricksのURL 

print(db_url)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/58fe3e9a-2df9-0ac0-25e9-97cc094536fd.png)
react-admin: TextFieldで改行が表示されるようにする方法

react-adminには、テキストを表示するコンポーネントに`TextField`があります。この投稿では、`TextField`で表示するテキストに改行が入っていた場合、その改行を画面でも表示されるようにする方法を紹介します。

## TextFieldで表示したテキストは改行が有効にならない

react-adminのTextFieldコンポーネントは複数行の表示を想定した作りになっていません。例えば、次のような改行入りテキストがあったとき、

```
line1
line2
line3
```

TextFieldコンポーネントで描画すると、

```
line1 line2 line3
```

のようになってしまいます。

## 改行テキストを描画する方法

TextFieldコンポーネントでは解決できないので、シンプルなカスタムコンポーネントを作ります。

改行を描画する中心的なテクニックとしては、CSSの`white-space: pre-line`をテキストに適用する方法が手軽なので採用します。

カスタムコンポーネントのコードは次のようになります:

```multilineTextField.tsx
import { FC } from "react";
import { TextField, TextFieldProps } from "react-admin";
import { makeStyles } from "@material-ui/core/styles";

const useStyles = makeStyles({
  textContent: {
    whiteSpace: "pre-line",
  },
});

const MultilineTextField: FC<TextFieldProps> = (props) => {
  const classes = useStyles();
  return <TextField className={classes.textContent} {...props} />;
};

MultilineTextField.defaultProps = TextField.defaultProps;

export default MultilineTextField;
```

この`MultilineTextField`の使い方は、`TextField`と同じです。

```tsx
<MultilineTextField source="note" />
```
AWS(S3)に画像を保存できない

s3に画像を保存する処理を書いたのですが、以下のエラーがでてしまい画像を投稿する事ができません。
バケット内のファイルを

```
$list = Storage::disk('s3')->files('');
dd($list);
```

で確認することはできます。
putができません。

![スクリーンショット 2021-07-18 15.05.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/826735/af008389-38ac-eb6f-ef4d-ef4f7ad97fc9.png)


![スクリーンショット 2021-07-18 11.16.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/826735/b18b4521-4a55-9c2d-df86-615ec064e901.png)


試したこと
.envファイルの設定の見直し、○は正しい値を設定している

```php
AWS_ACCESS_KEY_ID=○○○○○○○○○○
AWS_SECRET_ACCESS_KEY=○○○○○○○○○○○○
AWS_DEFAULT_REGION=ap-northeast-1
AWS_BUCKET=○○○○○○○○○○○
AWS_USE_PATH_STYLE_ENDPOINT=false
```

・アクセス許可設定
アクセス許可を正しく設定されていないと保存できないと言う意見が散見されるので以下を試すもだめ

![スクリーンショット 2021-07-18 11.18.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/826735/c611f659-d379-d0cb-13d1-35fecc3c7c7c.png)


viewファイル

```php
<div class="table-text">
      <form action="{{route('upload')}}" method="post" enctype="multipart/form-data">
      {{ csrf_field() }}
          <input type="file" name="file">
          <button type="submit">保存</button>
     </form>
</div>

```

コントローラ

```php

public function upload(Request $request)
 {
    $file = $request->file('file');
    $path = Storage::disk('s3')->put('/', $file, 'public');
    ~以下略~
 }
```

参考にした記事
https://qiita.com/tiwu_dev/items/ecb115a92ebfebf6a92f


何か考えられる原因や解決法があればご教授いただければと思います。
LaTeX for Mac プリアンサンブル

[目次へ戻る](https://qiita.com/okirakuna_danna/items/5cc04d44ed12480fab31)

## プリアンサンブル

### 標準
本文のフォント指定など適切なパッケージを読み込む。


```
\usepackage[sc]{mathpazo}           % 本文、数式　Palatino
\usepackage[scaled]{helvet}         % サンセリフ　Helvetica
\usepackage{textcomp, mathcomp}     % 追加フォント
\usepackage[T1]{fontenc}            % 8ビットエンコード-標準-
\renewcommand{\ttdefault}{lmtt}     % 等幅フォントをlmttに再定義
\usepackage{otf}                    % 8ビットエンコード-標準-
```

### その他

```
\usepackage{url}                    % URL
\usepackage{color}                  % 色
\usepackage{amsmath,amssymb}        % 数式
\usepackage{graphicx}               % 色
```

## スタイルシート
[情報処理学会](http://www.ipsj.or.jp/journal/submit/style.html)
[共立出版向け](http://www.keibundou.co.jp/latex.html)
株式会社 啓文堂さま


[目次へ戻る](https://qiita.com/okirakuna_danna/items/5cc04d44ed12480fab31)
REST WebサービスとJSONパーサー

#はじめに
Automation 360でJSONパーサーを使うとき、ちょっとハマったのでメモ。

##操作例としてやった事
- Automation 360のREST Webサービスを使いAutomation 360のコントロールルームに接続。
- コントロールルームからの応答をJSONで受け取る
- 受け取ったJSONをAutomation 360の「JSONParser」で解析して一部を表示させる。

##おことわり
Automation 360 Community Edition build9637で試しました。
(community.cloudです。community2.cloud-2にはありません）
 
製品版に「JSONParser」が入ってくるときには異なるかもしれません。

#手順
（１）RESTでコントロールルームに接続

- コントロールルームに接続 を使用
- URIに「https://community2.cloud-2.automationanywhere.digital/v1/authentication」
- 認証モード：認証なし
- ヘッダーで以下を指定
![header.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/632535/c8cee2a8-7ad5-1896-097c-30722cee778e.jpeg)
※本当は資格情報を使うべきですが、話がそれるので直接入力。

- 変数に出力を代入で適当な辞書変数に格納（変数RestResponseとします）

（２）レスポンスを確認
うまく接続できたかどうか\$RestResponse{Body}\$を確認します。

（３）「JSONParser: JSON to Dictionary」でJSONを辞書変数に。
![paeser.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/632535/40519786-dc36-fd23-6bf7-9a1efe0f794e.jpeg)

- 仮に変数JsonDictとします。サブタイプを「任意」に指定すること（１つ目のハマり点）。

（４）変数JsonDictを表示してみる。
今回のRESTの戻りは以下のようになっています。

```
{
 "token":"eyJhb(認証トークンの文字列)HIqh9w",
 "user":{"id":999999,"username":"ログイン用のID","domain":null,
        "version":32,"principalId":7777777,"deleted":false,
         "roles":[{"name":"AAE_Bot Insight Expert", .....
```
続けてサービスを受けるためのtokenの取り出しは簡単。
辞書のキーをtokenにして、\$JsonDict{token}\$ でOK。

userの中のusernameを取る所が２つ目のハマり点。

結論としてうまくいったのは以下。

- ディクショナリの代入で、\$JsonDict{user}\$を新たな辞書変数（仮にuserDict）に入れる。
- \$userDict{username}\$で、取り出しOK。
- idのように数値型を取るときには、\$userDict{id}.Number:toString\$

BotStoreにあるJSONParserのReadmeを見て、
キーをuser.usernameとしたのがハマりの元（これではダメでした）。
BotStoreのJSONParserはメソッドの数が少し違うし、
Community Editionに入ったJSONParserとはちょっと違う？

#さいごに
複雑なJSONなら「JSON Object Manager」を使った方が良いかもしれません。
詳しくは以下に。
https://qiita.com/etoootak/items/6c508d2bfa6b1f1ac735
「JSON Object Manager」はネストが深い所でも一発で取れて便利だけど
戻りが全て文字列になるので、用途によって使い分けかな。

# おまけ
あ、JSON Paser, JSON Object Manager は
community.cloud.automationanywhere.digital にはデフォルトで入っているけど
community2.cloud-2.automationanywhere.digital には無いじゃないか。

[2022/04/21追記]
Automation360 v24で、「Json」パッケージが追加されました。
使い方は、ここで書いたBotStoreの「JSON Paser」「JSON Object Manager」とまた異なります。
「Json」パッケージは、現在のところJsonの読み出しだけで、Jsonテキストを作る用途で今使えるのは「Json Paser」パッケージの「Disctionary to JSON」アクションだけかな。
【講義10.php_rdb実践_複数テーブル操作】マスターテーブルについて

#本記事について
今後の開発の参考になればと思い、マスターテーブルについて、講義内容や職場での実体験をまとめたもの。

##マスターテーブルについて
 マスターテーブルとは、システムの運用上変更が頻繁にない基本的な情報が格納されたテーブル。
例えば、商品の情報が格納されたデータベースであれば「商品情報」「商品カテゴリ情報」がマスタテーブルになる。
 「商品マスタ」「商品カテゴリマスタ」などと呼ばれる。
 マスタは「m_」や「mst_」などの名前から始める、というルールでテーブル名がつけられる。
 (テーブル名の例: mst_product,m_product)

##マスターテーブルの活用例
 カラムの中で同じ値が繰り返し入る場合は、マスターテーブルを利用する。
 ここでは顧客情報のテーブルに、関連するデータ（性別マスタ、職業マスタ）を紐付ける。
 以下のような、3つのテーブルをINNER JOINを使用して結合する。
 性別ID、職業IDにそれぞれ相対する名称を紐付ける。


①t_customer(顧客情報テーブル)

| id | custmer_name | gender_id | jod_id | prefectures | municipality |　address |
|:-|:-|:-|:-|:-|:-|:-|
| 1 | 田中 | 1 | 2 | 東京都 | 港区 | 西麻布1丁目1番1号XXビル |


②m_gender(性別マスタ)

| id | gender_name |
|:-|:-|
| 1 | 女性 |
| 2 | 男性 |
| ３ | その他 |


②m_job(職業マスタ)

| id | job_name |
|:-|:-|
| 1 | 会社員 |
| 2 | 経営者・会社役員 |
| 3 | 学生 |
| 4 | フリーター |
| ５ | その他 |

##sql文
　t_customer、m_gender、m_jobを内部結合。
　m_genderのgender_name、m_jobのjob_nameを表示する。

```言語:sql
SELECT * FROM t_customer 
INNER JOIN m_job　ON t_customer.job_id = m_job.id 
INNER JOIN m_gender　ON t_customer.gender_id = m_gender.id
```

##結果
 t_customer（顧客情報テーブル）にgender_name（性別名称）、jod_name（職業名称）が表示される。

| id | custmer_name | gender_id | gender_name | jod_id | jod_name | prefectures | municipality |　address |
|:-|:-|:-|:-|:-|:-|:-|:-|:-|
| 1 | 田中 | 1 | 女性 | 2 | 経営者・会社役員 | 東京都 | 港区 | 西麻布1丁目1番1号XXビル |

以上。
LaTeX for Mac 目次

# LaTeXコマンド
## 目次
[ドキュメントスタイル](https://qiita.com/okirakuna_danna/items/39cee3b5eee1f589ff17)
[文字サイズと書体](https://qiita.com/okirakuna_danna/items/c3f7e299b963b83616a6)
[文字の左寄せ・センタリング・右寄せ](https://qiita.com/okirakuna_danna/items/a5cf622f8e3ae9b4de2f)
[箇条書き](https://qiita.com/okirakuna_danna/items/8eb314cd54e8b41ad2c6)
[表の基本](https://qiita.com/okirakuna_danna/items/218815566f8d46fc4d30)

[プリアンサンブル](https://qiita.com/okirakuna_danna/items/dbe253e8c76a37a2fae5)
[左寄せ・センタリング・右寄せ](https://qiita.com/okirakuna_danna/items/a5cf622f8e3ae9b4de2f)
[図の挿入](https://qiita.com/okirakuna_danna/items/53f2fae203080538a139)
[タイトル](URL)
[タイトル](URL)

[タイトル](URL)
[タイトル](URL)
[タイトル](URL)
[タイトル](URL)
[タイトル](URL)
AtCoderログ：0022 - ABC 210 A

# 問題：[ABC 210 A - Cabbages](https://atcoder.jp/contests/abc210/tasks/abc210_a)

## 問題文
> 高橋君はキャベツ屋さんにやってきました。
> キャベツ屋さんでは、 キャベツを $1$ 個 $X$ 円で買うことができます。
> ただし、キャベツを $A$ 個よりも多く買う場合、$A+1$ 個目以降に買うキャベツについては $1$ 個 $Y$ 円で買うことができます。（ここで、$Y<X$ が保証されます。）
> 高橋君がキャベツを $N$ 個買うために必要な金額を出力してください。

## 制約
> ・$1 \le N \le 10^5$
> ・$1 \le A \le 10^5$
> ・$1 \le Y < X \le 100$
> ・入力はすべて整数

# 回答1 (AC)

問題の内容を正しく理解できればそれほど難しくないでしょう。購入するキャベツの個数 n が閾値の a より大きいかどうかを判断し、それぞれの場合の価格を計算していくことになります。n が a より大きい場合、最初の a 個の単価は x 円、残りの n-a 個の単価は y 円になることに注意が必要です。コードは以下のようになりました。私が[提出したコード](https://atcoder.jp/contests/abc210/submissions/24281564)も同じ方針でした。

```C++:abc210a-1.cpp
#include <bits/stdc++.h>
using namespace std;
 
int main() {
  int n, a, x, y;
  cin >> n >> a >> x >> y;
 
  if ( n<a ) {
    cout << x*n << endl;
  } else {
    cout << x*a+y*(n-a) << endl;
  }
}
```

# 回答2 (AC)
キャベツの購入個数 n を横軸、合計金額 Cost を縦軸にしてグラフを描くと以下のようになります。購入個数が a 個以内ならば、グラフは Cost=x*n という(原点を通る)直線になります(左側の太い実線)。購入個数が a 個を越えた場合、グラフは  Cost=x*a+y*(n-a) という直線(右側の太い実線)になります。それぞれのグラフを延長すると点線部が現れるので、キャベツの購入個数 n に依らず、合計金額は常に x*n と x*a+y*(n-a) の少ない方になっていることがわかります。この考察を用いると、if 文による場合分けが不要となり、以下のようなシンプルなコードになります。

![abc210a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1589302/86adb9fa-e236-7976-60d0-632df835afb9.png)

```C++:abc210a-2.cpp
#include <bits/stdc++.h>
using namespace std;
 
int main() {
  int n, a, x, y;
  cin >> n >> a >> x >> y;
 
  cout << min( x*n, x*a+y*(n-a) ) << endl;
}
```

# 調べたこと
## [AtCoder の解説](https://atcoder.jp/contests/abc210/tasks/abc210_a/editorial) → [公式解説](https://atcoder.jp/contests/abc210/editorial/2293)
回答1と同じ方針でした。なお、n=a の場合はどちらの式を用いても合計金額は同じになりますので、if 文の n<=a は n<a でも問題ありません。

# リンク
- 前の記事 → [AtCoderログ：0021 - ABC 210 に参加しました](https://qiita.com/RoadLynton/items/40418cb138f03b3c0bc7)
- 次の記事 → [AtCoderログ：0023 - ABC 210 B](https://qiita.com/RoadLynton/items/57065aa329a3119808ac)
[WEB]ブラウザバックの戻るボタンでキャッシュからの読み込みを無効（リロード）にする。

```html:test.html
<html>
    <head>
        ...
        <script>
            window.onpageshow = function (e) {
                if ((e.persisted || window.performance) && window.performance.navigation.type == 2) {
                    window.location.reload();
                }
            };
        </script>
    </head>
    <body>
    ...
    </body>
</html>
```
coc.nvimでDocker上のLanguageServerにアクセス出来た話

# coc.nvimでDocker上のLanguageServerにアクセス出来た話
[前回の話](https://qiita.com/Sepi110902/items/1591d144a23b6713a998)の続きです．
前回Docker上のLanguageServerにアクセスすることが出来ない問題点がわかりました．
問題点がわかったことで解決策も見えてきたわけですが，早速試してみたいと思います

## やったこと
やったことは簡単です
とはいえWindowsは現状WSLに頼る必要がありますが...
はじめに設定を載せます(あくまでサンプルです)

```json:coc-settings.json
{
  "languageserver": {
    "elixirLS": {
      "command": "docker",
      "args": ["run", "--rm", "-i", "-v", "/mnt/x/ex_test:/mnt/x/ex_test", "dockeredlsp/elixir-ls:1.12.2-23.3.4"],
      "filetypes": ["elixir", "eelixir"]
    }
  }
}
```

この設定はWSL上で/mnt/x/ex_test内にあるElixirのファイルを補完した際の設定です
Dockerに-vオプションを用いて同一のディレクトリ階層を作成することで補完が可能となります
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/204702/b3ce1842-58ee-3c46-5796-a759ca10820a.png)
補完や
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/204702/c4433262-9c4a-b086-a21a-2295ae91d32b.png)
関数定義を見ることが出来ます
これで取り敢えずDocker上のLanguageServerを用いて保管できることがわかりました．
現状の問題点としてはプロジェクトごとに`coc-settings.json`を書き換える必要があることです
この問題を解決するにはcoc.nvimの設定方法を見直して，場合によっては何かプラグインを作成することを考えたほうがいいかもしれません...
Docker+neovimの環境への探求はまだまだ続く...
macの$PATH

##$PATHのディレクトリ
```zsh
echo $PATH | tr ':' '\n'
```
とすると、

```
/usr/local/bin
/usr/bin
/bin
/usr/sbin
/sbin
```

となる。(人によっては、他にも出て来ますが、上記の5つは必ず入っています)
binはbinary fileの略です。
フォルダの役割は、

| /usr |  システムの起動時には必要がないファイルを配置する。<br>OSのアップグレードで中身が変わらないことが保証されている。|
| :-: | -- |
| /bin <br>/sbin | 起動時やメンテナンス時に必須のコマンド類を格納。コマンドを削除してはいけない。<br>OSアップグレードで上書きされるので、コマンドを追加するのも厳禁。<br>/sbinは一般ユーザーは関与しないものが、/binには一般ユーザーが関与するものが入っている|

|/usr/bin|/usrと/binの考えから、「システムの起動時には必要がなく、一般ユーザが関与するコマンド」の置き場になります。コマンドを追加すべきではない|
|:-:|--|
|/usr/sbin|システムの起動時には必要がなく、一般ユーザが関与しないコマンドの置き場|

|/usr/local| システム管理者がインストールする各種ファイルを保存するディレクトリ
|:-:|--|
|/usr/local/bin|自作のコマンドを入れるのが良い。linuxによっては、空のことも多いようです。|

また、brewなど、パッケージ管理プログラムについては

|opt|付加的なアプリケーションのインストール先に使われる。<br>パッケージ名のサブディレクトリを作り，その下に個々のアプリケーションのプログラムをインストールする。<br>バイナリの実行ファイルのみを格納すること。<br>環境設定ファイルは/etc/opt/パッケージ名，動的に変化するファイルは/var/opt/パッケージ名に入れる。|
|:-:|--|

こちらに入れるべき、とする流儀もあります。（/usr/local/binには自作コマンドのみを入れるのを遵守するということです）。
この流儀を守るなら、homebrewのインストール先は/opt/homebrewになります。

## 参考
[ディレクトリの役割](https://www.itmedia.co.jp/help/howto/linux/0007master/14/02.html)
[Homebrewのインストール先を変更する](https://qiita.com/usamik26/items/601f5612bd3f8a21cc41)
AtCoderログ：0021 - ABC 210 に参加しました

この記事は 2021年07月17日(土)21:00-22:40 に開催された [ABC 210](https://atcoder.jp/contests/abc210) に参加した記録です。

#  結果
- 得点：600 (=100+200+300)
- 時間：68:54 (= 58:54 + 05:00 × 2)
- 順位：4195 / 8876
- パフォーマンス：618
- レーティング：86 → 154 (+68) Highest更新！
- 段級位：12級 → 10級

![2021-07-18_abc210.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1589302/3988781d-7740-6128-347a-d1e9d1826065.png)

# 詳細
|問題|得点|時間|提出コード|復習|
|:--:|:--:|:--:|:--:|:--:|
|[ABC 210 A](https://atcoder.jp/contests/abc210/tasks/abc210_a)|100|03:42|[○](https://atcoder.jp/contests/abc210/submissions/24281564)|[AtCoderログ：0022](https://qiita.com/RoadLynton/items/5730d21e57a52cf7ca3c)|
|[ABC 210 B](https://atcoder.jp/contests/abc210/tasks/abc210_b)|200|10:42|[○](https://atcoder.jp/contests/abc210/submissions/24292499)|[AtCoderログ：0023](https://qiita.com/RoadLynton/items/57065aa329a3119808ac)|
|[ABC 210 C](https://atcoder.jp/contests/abc210/tasks/abc210_c)|300|58:54 (2)|[○](https://atcoder.jp/contests/abc210/submissions/24315657)|[AtCoderログ：0024](https://qiita.com/RoadLynton/items/2afcfb40b491f276bd2d)|
|[ABC 210 D](https://atcoder.jp/contests/abc210/tasks/abc210_d)|400|(2)|---|---|
|[ABC 210 E](https://atcoder.jp/contests/abc210/tasks/abc210_e)|500|---|---|---|
|[ABC 210 F](https://atcoder.jp/contests/abc210/tasks/abc210_f)|600|---|---|---|

# 感想
- A, B, C を完答、D に挑戦している間に時間切れとなりました。前回と一緒ですね。
- A、B は素直に回問して正解。
- C は C++ の map 関連の関数の仕様を調べながらだったため、時間がかかってしまいました。
- D は素朴なアルゴリズムを書いて TLE となったため、改良しているうちにタイムアップ。
- レーティングが順調に伸びたのは良かったです。実力から考えてこんなもんなんでしょう。

# リンク
- 前の記事 → [AtCoderログ：0020 - ABC 068 B](https://qiita.com/RoadLynton/items/45aa08d858c4903231dd)
- 次の記事 → [AtCoderログ：0022 - ABC 210 A](https://qiita.com/RoadLynton/items/5730d21e57a52cf7ca3c)
RX65NでAzureRTOSを使ってみる

# Renesas製 32bit MCU RX65NでAzureRTOSを使ってみる

#本記事でわかること
+ RX65Nを使ったAzureの開発の開始方法・環境の入手場所 

(補足）最新の情報はルネサスWEBのココを見るとよい。
[ルネサスWEBクラウド情報](https://www.renesas.com/us/ja/products/microcontrollers-microprocessors/rx-32-bit-performance-efficiency-mcus/cloud-solution)

#開発環境を入手しよう

###開発ボードの入手

まず開発ボードであるRX65N Cloud Kitを入手します。
3000円～5000円で買える。
 **[ココから：RX65N Cloud Kit購入](https://www.renesas.com/us/ja/buy-sample/check-inventory/result?show_price=1&partno=RTK5RX65N0S00000BE&exact=1)**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/233064/9c17e9c2-0636-965b-f600-9c28b094d3d3.png)

###開発環境のインストール

IDEはe2 studioをダウンロードする。
なお、RXファミリを選択して、GCCコンパイラをインストールする。

[e2 studio ダウンロード](https://www.renesas.com/us/ja/software-tool/e-studio#download)


###Azure RTOSのサンプルコードを入手

実際にAzureRTOSのサンプルコードを入手する。
サンプルコードは、AzureRTOSのサンプルとAzureRTOSのPlug and Playのサンプルコードの2種類ある。
まずAzureに接続することを考えるとPlug and Playが簡単なので、今回はPlug and Playで紹介する。

[RX65N Azure RTOS Plug and Playサンプルコードの入手](https://github.com/azure-rtos/samples/tree/PublicPreview/PnP)

Plag and Playのサンプルコードは3種類あるが、GCCコンパイラを使うので一番したの赤枠をダウンロードする。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/233064/d9486f34-2069-a5af-a971-688de053c8a1.png)

これで準備は完了

# あとは先ほどダウンロードしたZipのReadmeどおりに設定するだけ
 ※Azureの設定はWEBで検索する
[Rails]よく使うバリデーションまとめ

バリデーション機能は、空で保存してほしくないときや、文字数は１０文字以内にしてほしいときなどに、チェックする機能として動きます。

たとえば、インスタグラムのような画像投稿サイトで、画像がないのは望ましくないので、画像は空白では保存できないようにします。
Twiiterのようなテキスト型の投稿サイトなら文字数は140字以内に設定します。

このようにバリデーション機能は、開発者の思うようなアプリ運営を行っていく上で非常に重要な機能です。

Railsではバリデーションをかんたんに実装できるので、今回はよく使うバリデーションの例を実装していきます。

#開発環境

> ruby 2.6.3
> Rails 5.2.6

#発動タイミング

バリデーションは、オブジェクトがデータベースに保存される前に発動して、データが正しいかどうかを確認します。

発動するメソッドは以下です

- create
- create!
- save
- save!
- update
- update!

#基本形

バリデーションはモデルでカラムを対象に書いていきます。
なのでカラムごとに自由に条件を設定できます。

```rb:model
validates :カラム名, 条件
```

#空白

####空でないこと

```rb:model
validates :body, presence: true
```

#一意性（ユニーク）

####他とかぶっていないか、オンリーワンであるか

```rb:model
validates :name, uniqueness: true
```

#長さ

####1文字以上

```rb:model
validates :tweet,  length: { minimum: 1 }
```

####140文字以下

```rb:moedl
validates :tweet, length: { maximum: 140 }
```

####1文字以上140文字以下

```rb:moedl
validates :tweet, length: { in: 1..140 }
```

####8文字のみ

```rb:model
validates :password, length: { is: 8 }
```

#数値

####整数のみ

```rb:model
validates :age, numericality: { only_integer: true }
```

#条件付きバリデーション

####どちらか一方のみ
大喜利のお題などで、文字か写真で一言のような画像のどちらかの場合のみ保存されるようにします。

```rb:model
validate :required_either_image_or_content

private

# image.contentのどちらかの値があればtrue
# image.contentどちらも入力されている場合や入力されていない場合は false
def required_either_image_or_content
  return if image.present? ^ content.present?
  errors.add(:base, '画像または文字のどちらか一方で投稿可能です')
end
```

####◯○の場合のみ

支払方法の選択でカードを選択した場合のみに、バリデーションを有効にしたい場合に使います。

```rb:model
validates :card_number, presence: true, if: :paid_with_card?

def paid_with_card?
  payment_type == "card"
end
```

#複数条件にする場合

今まで１つずつ紹介してきましたが、同じカラムに複数の条件を指定したい場合、コードをまとめることができます。

```rb:model
validates :name, presence: true, uniqueness: true, length: { maximum: 13 }
```

この場合`presence: true`を指定しているので、必然的に1文字以上になります。

#まとめ

今回はよく使うバリデーションとして

>- 空白
>- 一意性（ユニーク）
>- 長さ
>- 数値
>- どちらか一方のみ
>- ◯○の場合のみ

を紹介しました。

まだまだバリデーションはたくさんありますので、Railsガイドなどで調べてみてください。
pip listのWARNINGを消す


# 状況
pip listの照会をすると以下の<font color="Red">**WARNING**</font>が十数件表示された。

```python
hogehogeiMac ~ % pip list
WARNING: Ignoring invalid distribution -yping-extensions (/Users/hogehoge/.pyenv/versions/3.7.7/lib/python3.7/site-packages)
```
警告：(/Users/hogehoge/.pyenv/versions/3.7.7/lib/python3.7/site-packages)にある-yping-extensionsと言うdirectoryは"無効なため配布を無視します”(Google翻訳）という意味らしい。
※ちなみに"hogehoge"は私の名前を隠しています。

# 原因
netで色々調べると、「要らないDirectoryが残っていて、邪魔をしている」らしい。
ちなみに、 ターミナルで　/Users/hogehoge/.pyenv/versions/3.7.7/lib/python3.7/site-packages　に移動して隠しファイルを見てみると

```python
hogehogeiMac site-packages % ls -a
./						pip-21.1.3.dist-info/
../						pkg_resources/
Flask-1.1.2.dist-info/			python_dateutil-2.8.1.dist-info/
Jinja2-2.11.3.dist-info/			qrcode/
MarkupSafe-2.0.1.dist-info/		qrcode-6.1.dist-info/
〜〜省略〜〜（頭に~-が着いているのがおかしい？）
~-nja2-2.11.3.dist-info/			~-portlib_metadata-1.7.0.dist-info/
~-pp-3.1.0.dist-info/				~yping_extensions-3.7.4.3.dist-info/
```
頭に' **~-** 'が着いたdirectoryがイッパイあった。これは右側に　' / 'があるのでdirctoryだがこれに移動しようとしても**not found**となった。
# 対処
・terminalからだと難しそうなので、敢えてFinderからの操作にする。

![IMG_7056.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/634708/4c4900a1-d762-4133-77e0-f9a11a4db003.jpeg)

・Finderを開き、隠しファイルが見える状態（ ショートカット：**Command + Shift + .(ドット)**）にしてから　site-packages　まで移動する。
・念の為デスクトップにfolderを作成してから、「WARNING」で表示される'**頭に~-が着いている**'Directoryを、そのfolderにコピーしておく。（もし消して問題が改善されない場合元に戻すため）
・その上で、それらの'**頭に~-が着いている**'Directoryをsite-packagesから削除した。
# 結果
hogehogeiMac site-packages % ls -a　から先程のdirectoryは消えていた。
hogehogeiMac ~ % pip listの表示も正常になった。（よかった！！）

私は、この方法で正常に戻りましたが、飽くまで自己責任の下でお願いします。
【Kubernetes】deploymentオブジェクトを作ってみる　no.2

![名称未設定のデザイン (12).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011305/07cc2fce-5e12-c8e4-9274-dae0905af9e4.png)


こんにちは。まゆみです。

Kubernetesについての記事をシリーズで書いています

今回の記事では、KubernetesのDeployment objectを作る過程をまとめてみました。


#Deploymentオブジェクトを作る
KubernetesのDeploymentオブジェクトを以下のプロセスで作ってみます

>①Docker Image をbuild する(ローカルで)
②Clusterが実行中か確かめる
③"kubectl create deployment "でdeploymentオブジェクトを作る
④docker hubにイメージをpush する
⑤再度deploymentオブジェクトを作ってみる


##①Docker Imageをbuild する

```
docker build -t <好きなイメージ名> .
```

KubernetesはDockerの代わりになるものではなく、Dockerと共に働くものです。

KubernetesにはImageをbuildすることはできません。

<font color="Red">ローカルでImageをbuildしておきましょう</font>

Kubernetesがすることは、Containerをrunするところからです。


##②Clusterが実行中が確かめる

```
minikube status
```
でminikubeのステータスを確かめましょう

下のスクショのように表示されれば、OKです。

![2021-07-18_7-39-12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011305/33361c05-6eb7-7528-a9da-aabced4432df.png)


もし、Clusterが実行中ではない場合、

```
minikube start --drive=<driver名>
```
でminikubeを起動してください。


##③kubectlでdeploymentオブジェクトを作る

```
kubectl create --help
```

とコマンドを打つと、どんなオブジェクトが作れるのか表示する事ができます

![2021-07-18_7-42-18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011305/c653e14f-0b43-ec5a-8498-4436bbe9675c.png)

今回は『deployment』オブジェクトを作ってみましょう

オブジェクトの作り方は、[Kubernetesドキュメント](https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands)を参考にどうぞ


![2021-07-18_7-47-22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011305/78ffcd70-0447-e65d-a941-d9b9cd1f5987.png)

上のドキュメントを参考に、とりあえず<font color="Red">ローカルにあるImageを利用して</font>、deploymentオブジェクトを作ってみました。

![2021-07-18_7-51-59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011305/09d907ba-6542-f564-754b-50f9ea22c2b7.png)

また、

```
kubectl get deployments
```
でClusterのなかにいくつのdeploymentがあるのか表示させることができるのですが、『0/1』と表示されていて、Ready状態のdeploymentが無い事が確認できます

```
kubectl get pods
```
上記のコマンドでpodがいくつ実行されているのか表示させてみると、

<font color="Red">『ImagePullBackOff』と表示されます。</font>

###ImagePullBackOffの原因は？

『ImagePullBackOff』と表示される原因の答えは[stackoverflow](https://stackoverflow.com/questions/37302776/what-is-the-meaning-of-imagepullbackoff-status-on-a-kubernetes-pod)に書かれていました。

![2021-07-18_8-47-39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011305/a5e4b6fa-3b6e-310f-6ff2-528a1abf4cfb.png)
引用元：stackoverflow

##④ローカルでbuildしたImageをdocker hubにpush する

では最初にローカルでbuildしたImageをdocker hub にpush しましょう

Docker hubに新しいRepositoryを作った後

```
docker tag <ローカルにあるImage> <Docker hubのRepository名>
```

```
docker push <Docker hubのRepository名>
```

##⑤Docker hubにあるイメージを指定して、再度deploymentオブジェクトを作る

```
kubectl create deployment <名前> --image=<docker hubにあるImage>
```

そしてその後

```
minikube dashboard
```
とコマンドを打つと、ダッシュボードを開くことができます


![2021-07-18_9-33-06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1011305/d6c16ef5-ea36-3240-43e8-dae98e7248e1.png)
Supabase: カラムの権限を調べるSQL

Supabaseで

- どのテーブルのどのカラムに
- 誰が
- `INSERT`や`SELECT`, `UPDATE`できるか

を調べるSQLです。

## カラムレベルでの権限を調べるSQL

カラムレベルの権限は`information_schema`の`column_privileges`ビューを開くと簡単にわかります。Supabaseでは、`public`スキーマでの`anon`ロールと`authenticated`ロールの権限がアプリケーションが気にすべき権限なので、その2つに絞って見ると分かりやすいです。

```sql
select grantee, table_name, column_name, privilege_type
from information_schema.column_privileges
where table_schema = 'public'
  and grantee in ('anon', 'authenticated')
order by grantee, table_name, privilege_type, column_name;
```

## 実行結果の例

![CleanShot 2021-07-18 at 09.27.25@2x.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/889/e6fd8017-71fa-329d-ea1a-708947fcd2ab.png)

- `grantee`が権限付与されたロール名です。Supabaseでは`anon`や`authenticated`になります。
- `table_name`はどのテーブルかを指します。
- `column_name`はどのカラムかを指します。
- `privilege_type`はそのカラムに対して`SELECT`や`INSERT`、`UPDATE`ができるかを指します。

ここの結果に出てこないということは、その権限が無いということです。
動的に FPS を変更する方法


# はじめに

### 何をやりたいか

OpenCVでFPSを制御できない時に、FPSが一律でFPSを操作するのではなく、FPSが高い時だけFPSを下げる方法をご紹介します。
今回は、FPSが15以上の時、待機時間を発生させようと思います。

一律でFPSを下げる方法については、以下のリンクを参考にしてみてください。

#### 関連リンク
関連リンクを下記に載せておくので、必要であれば参考にしてください。。

* OpenCVでFPSを制御できない時に無理矢理FPSを下げる方法
    * https://qiita.com/syukan3/items/7373fcb471650f50621f



# ソースコード

```python
import cv2
import time

framecount = 0
time1 = 0
time2 = 0

cap = cv2.VideoCapture(0)

while cap.isOpened():
    ret, frame = cap.read()

    t1 = time.perf_counter()

    framecount += 1

    # FPS が　15　以上の時、待機時間を発生させる
    if time2 != 0 and framecount / time2 >= 15:
        time.sleep(0.03333)

    if framecount >= 15:
        detect_fps = framecount / time2
        framecount = 0
        time1 = 0
        time2 = 0

    t2 = time.perf_counter()
    elapsedTime = t2 - t1
    time1 += 1 / elapsedTime
    time2 += elapsedTime
```

---
### 会社紹介

**株式会社 Mosaica**  
最先端テクノロジーで社会課題を解決し、持続可能な未来を創造する IT カンパニー。
AI ソリューション、クラウド統合、DX 推進、経営コンサルティングなど包括的なサービスでビジネス変革を支援しています。  

詳しくは [公式サイト](https://mosaica.co.jp/) までお気軽にご相談ください。
公式サイト： https://mosaica.co.jp/
WWDC 2021の機械学習、XR関係のトークまとめ

Appleの開発者向け動画のまとめ

## 前口上
2021年のApple Worldwide Developers Conference (WWDC)はオンライン形式で行われました。例年通り開発者向けの動画がオンデマンドで上がっていたので機械学習、XR関係のトークを観ていきます。

## 機械学習
### Create image processing apps powered by Apple Silicon
https://developer.apple.com/videos/play/wwdc2021/10153/

M1 Macはユニファイドメモリアーキテクチャーを持ちシステムメモリーにNeural Engine、GPUがメモリーインターフェイスを通して直接アクセス。CPUからGPUへデータを渡す際にVRAMへの転送部分をスキップできる

---

NVIDIAのGPUもGPUメモリーで価格差がありますね。システムメモリーさえ十分にあればいいのならユニファイドメモリアーキテクチャーも一つの側面では悪くないのかもしれない。

### Tune your Core ML models
https://developer.apple.com/videos/play/wwdc2021/10038/

Core MLのモデルの形式の解説

物体検出にMLMultiArrayが使える。

MLPackageはMetadataがJSON、InterfaceとArchitectureがProtobuf, 学習パラメータがバイナリ。Xcodeでメタデータが編集できる。新たにカスタムオペレーション相当のMLProgram、cpu/gpu実行の選択ができるようになった。

---

変換前後のモデルの出力をビジュアルで比較できるのはいいですね

## Classify hand poses and actions with Create ML
https://developer.apple.com/videos/play/wwdc2021/10039/

Create MLの使い方のチュートリアル。手の位置を認識して指や手のひらから魔法を出す。

動画をフォルダの中に入れて手の動きの分類

---

movファイルのまま訓練してくれるのすごいですね

### Build dynamic iOS apps with the Create ML framework
https://developer.apple.com/videos/play/wwdc2021/10037/

Create MLをiOSで動かす。iOSで機械学習の推論でなく訓練。

プライバシー面でのアドバンテージがある。

---

古いMacと比べるとチップの面でiPhoneが勝っている点はありそう

### Detect people, faces, and poses using Vision
https://developer.apple.com/videos/play/wwdc2021/10040/

Face DetectionでMaskが考慮可能に、ヨー、ロールに追加でピッチが取得可能に

Human Detectionは上半身のみも可能。Person Segmentationは動画にも適用可能で詳細度の段階を選択可能

---

VTuber系のツールが自然になりそう


### Discover built-in sound classification in SoundAnalysis
https://developer.apple.com/videos/play/wwdc2021/10036/

ビルトインの音声分類機。300種類ある。Windowの長さやコンフィデンスの閾値をカスタマイズ可能。

---

YOLO 9000の音声版といった趣

### Explore ShazamKit
https://developer.apple.com/videos/play/wwdc2021/10044/

Shazamのカタログだけでなく独自のカタログに対してもマッチできる。

---

曲のどこでマッチしたかのmatchOffsetも取れるんですね




## XR
### Explore ARKit 5
https://developer.apple.com/videos/play/wwdc2021/10073/

GPSサポートのデバイスでロケーションアンカーがアメリカの一部、ロンドンで使える。

App Clip Codeのアンカーとしての使い方。アンカーからの相対位置でAR表示。

iPad Proで超広角カメラが使える。モーションキャプチャーも使える。

---

App Clip CodeはARマーカーとしても使えるんですね。

### Immerse your app in spatial audio
https://developer.apple.com/videos/play/wwdc2021/10265/

3D音響に関するトーク。AVAudioSessionを使う。
iOS15ではWebkit Media Source Extensionsも対応

---

Apple Glassの準備といった感じですね。
VRヘッドセットではマイクや音声出力ついていることが多いですが、音声部分はAirPods Proに切り分けてGlassのハードウェア価格を下げたいのでしょうか。

### Create 3D workflows with USD
https://developer.apple.com/videos/play/wwdc2021/10077/

3Dパイプラインの規格Universal Scene Descriptionの解説。
gltf, fbx比で複雑なシーンやコラボレーションに対応しているのが.usd。
そのコレクションが.usdz

### Create 3D models with Object Capture
https://developer.apple.com/videos/play/wwdc2021/10076/

画像から3Dデータを作るObject Captureの紹介。

RealityKitでセッションをセットアップ後、プレビューをリクエストしてモデルを処理。

### AR Quick Look, meet Object Capture
https://developer.apple.com/videos/play/wwdc2021/10078/

ReducedとMediumの設定を見直し、二つの写真は70%以上オーバーラップするようにすると綺麗に3Dデータができる。


## 所感
以前[ARヘッドセットを組み立てた](https://ja.algonote.com/entry/project-north-star-2)際も思いましたが真にARを実現させるためには現実の認識が必要で機械学習が不可欠のように感じます。

3D音響や画像からの3Dデータ生成、機械学習の自動訓練、ビルトインの画像や音声認識の拡充などARグラスを成立させるための要素技術の土台を固めている印象です。
Before starting UiPath:代入ってなんだ

## 皆もすなるQiitaといふものを、儂もしてみむとてするなり。

と言う訳で、こん＊＊は！はなっち！です。

★★★この記事はUiPathブログ発信チャレンジ2021サマー、7/18の記事です。★★★

今回は、ちょっとしたシリーズです。UiPathを使うに当たって、UiPathの機能ではなく、コンピュータ言語を使う上での基礎知識を展開していこうと思います。

#代入ってなんだ

中１数学ですと
　　文字の代わりに数字を入れる
と説明されています

    ┌───────────
    │そう「代入」とは、「文字の代わりに数字を入れる」ことなんだ。
    │例えば
    │　　X + 2
    │という式に、X = 1を「代入」すると、
    │　　　X + 2
    │　　= 1 + 2
    │　　= 3
    │になるよ
    └───────────
        参考元：https://www.try-it.jp/chapters-395/sections-396/lessons-433/

コンピュータの世界ですと、
　　　　プログラミングにおいて変数の値を設定（ないし変更）すること（assignment）
と説明されています。

参考元：https://ja.wikipedia.org/wiki/%E4%BB%A3%E5%85%A5

例えば
　　　　X = 0        変数Xの値を設定（初期化）
　　　　X = X + 1    変数Xの値に1を加算したものを変数Xに設定（変数Xを変更）
　　　　X = Y + 2    変数Yの値に2を加算したものを変数Xに設定（変数Yの値は変わらない）
のように。

UiPathでは、「代入」アクティビティを使います。
        左側には、設定されるあるいは変更される変数を記述します。
        右側には、設定するあるいは変更させる式、変数を記述します。

##おわりに
いかがでした？

代入は、変数を使う上での基本の「キ」ですので、しっかり理解しておきましょう！

是非UiPathでのロボ開発の一助になればと思っています。

ありがとうございました！
【Ruby】配列の要素の合計を出す

大きさによって値段の違うフルーツがあったと仮定する。

```ruby
fruits_price = [["apple", [200, 250, 220]], ["orange", [100, 120, 80]], ["melon", [1200, 1500]]]
```

（出力）
appleの合計金額は670円です
orangeの合計金額は300円です
melonの合計金額は2700円です


```ruby
fruits_price = [["apple", [200, 250, 220]], ["orange", [100, 120, 80]], ["melon", [1200, 1500]]]

fruits_price.each do |name, prices|
  puts "#{name}の合計金額は#{prices.sum}円です"
end
```
gitlabのフォルダ名について

大文字、小文字で識別ができないようである。
python で同階層のフォルダからライブラリをimportする際、大文字と小文字で区別をしていたのだが、
ハマってしまった。
これからは、ソースコードに関わるフォルダ名は小文字で統一する
しゃくとり法ではqueueを使おう委員会（Ruby編）

# はじめに
@hibit さんの記事、[しゃくとり法ではqueueを使おう委員会（C++編）](https://qiita.com/hibit/items/5b7e16e739cb68b84520) の二番煎じです。

# [ABC 032 C - 列](https://atcoder.jp/contests/abc032/tasks/abc032_c)
```ruby
n, k = gets.split.map(&:to_i)
s = n.times.map{ gets.to_i }
if s.include?(0)
  puts n
  exit
end
t = 1
max = 0
q = []
s.each do |x|
  q << x
  t *= x
  while t > k && q.size > 0
    t /= q.shift
  end
  max = q.size if max < q.size
end
puts max
```
しゃくとり法で`queue`を使用しますと、ソースコードが`2/3`になります。
短ければ短いほど、早解きやバグり難さで有利となります。

```ruby
q = []
q << x  #　入れる
q.shift #　出す
```
入れて出すだけで、煩わしい添え字の処理が不要になります。
# [ABC 038 C - 単調増加](https://atcoder.jp/contests/abc038/tasks/abc038_c)
```ruby
gets
a = gets.split.map(&:to_i)
q = []
q << a.shift
cnt = 1
a.each do |x|
  if q[-1] < x
    q << x
    cnt += q.size
  else
    q.clear
    q << x
    cnt += 1
  end
end
puts cnt
```
```ruby
q = []
q << x
q.clear
```
この問題では、`shift`の代わりに`clear`を用いて、それまでのデータを一気に消去しています。
# [ARC 022 B - 細長いお菓子](https://atcoder.jp/contests/arc022/tasks/arc022_2)
```ruby
n = gets.to_i
a = gets.split.map(&:to_i)
q = []
h = Hash.new(0)
max = 0
a.each do |x|
  q << x
  h[x] += 1
  while h[x] > 1
    h[q.shift] -= 1
  end
  max = q.size if max < q.size
end
puts max
```
```ruby
  while h[x] > 1
    h[q.shift] -= 1
  end
```
この問題では、`queue`と`hash`を組み合わせて使用してます。
# まとめ
+ ABC 032 C を解いた
+ ABC 038 C を解いた
+ ARC 022 B を解いた
+ hibit さんありがとう
初学者による復習[エラーを解決しよう]

さて今回も復習も兼ねてアウトプットをしていこうと思う。

今回復習をしていて遭遇したエラーがこちら。

```
Invalid route name, already in use: 'root'
```

簡単に説明するとrootが2つ使われていて遷移する際、どっちに遷移して良いか
分からないよ！とエラーが出ているようだ。

修正する前の記述がこちら。

```ruby
Rails.application.routes.draw do
  devise_for :users
  root to: "rooms#index"
  get 'messages/index'
  root to: "messages#index"
  resources :users, only: [:edit, :update]
  resources :rooms, only: [:new, :create]
end
```

確かにroot toで指定しているパスが２つありそりゃどっちやねんってエラーで怒られるわけだ。

なので遷移させたい方だけ残して

```ruby
Rails.application.routes.draw do
  devise_for :users
  root to: "rooms#index"
  get 'messages/index'
  resources :users, only: [:edit, :update]
  resources :rooms, only: [:new, :create]
end
```

これでエラーが無事解決し指定したページに遷移できるようになった！
女性エンジニアコミュニティCode Polaris勉強会 #06 - 1周年記念 を覗いたので、その感想

## Code Polarisとは

https://chomado.com/announce/code-polaris/

女性エンジニアコミュニティ。各種リンクは以下Wikiに色々。

https://github.com/code-polaris/community/wiki

https://code-polaris.connpass.com/
> アプリケーション開発を学びたい人を支援するコミュニティです。
> 昨今のIT業界の男女比において、女性が安心して学べる場が少ないと感じています。

で、これが昨日のMeetupの内容です。以下その感想等など。

https://code-polaris.connpass.com/event/216797/

## 感想

https://twitter.com/e99h2121/status/1416295899270049792?s=20

https://twitter.com/e99h2121/status/1416292401107259398?s=20

https://twitter.com/1115_lilium/status/1416294768066260996?s=20

色々共感。

https://twitter.com/iorin_love_ML/status/1416313355308920833?s=20

学生目線のお話は企業にいる側も（採用担当者も）読んだら良いと思う。

https://twitter.com/s_yo_ko/status/1416312308465160196?s=20

これは後で触ってみたい。

オンライン開催は当然としても各種meetupって平日の夜開催が多めで調整が必要なのだが、土曜の午後という時間帯は育児勢にも優しい。私は土壇場で、おぉ！いま開催している！と気付いて参加した。言いつつ途中もチビ4歳が絡んできてあしらいながらの「ラジオ状態」だったのだが、雰囲気はとてもゆるゆるで居心地のよさは素敵だった。

ということで男性も女性も各種各位に興味を持っていただけたらと思い以上、簡単な感想文でした。お楽しみいただければさいわいです。
Linux: HOSTNAMEコマンドでのホスト名取得が好まれない理由、及びホスト名の変更方法について

現場で言われたことについてメモ。

###### 実施環境：

```Linux:Linux
[root@testhost ~]# uname -a
Linux testhost 4.18.0-147.8.1.el8_1.x86_64 #1 SMP Thu Apr 9 13:49:54 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux
[root@testhost ~]# echo $SHELL
/bin/bash
```

Linuxサーバでホスト名を取得したい場合、unameコマンドとhostnameコマンドの2つの選択肢があります。
(一応、ファイル/etc/hostnameの中身を確認するという方法もあります。このファイルについては後述。)

```Linux:Linux
[root@testhost ~]# uname -n
testhost
[root@testhost ~]# hostname
testhost
[root@testhost ~]# cat /etc/hostname
testhost
```

ただ、ホスト名を取得するためにhostnameコマンドを使用することはあまり好まれません。
理由は簡単で、hostnameコマンドはホスト名の変更もできてしまうためです。
うっかりhostnameコマンドの後に何らかの文字列が入ってしまった場合、確認メッセージも何もなくホスト名が変更されてしまい、場合によっては大きな問題を引き起こす可能性があります。
unameコマンドではホスト名の変更はできないため、安全を考えるならこちらを使用したほうが無難です。
(なお、下記の実行例でファイル/etc/hostnameの中身は変わっていません。これについても後述。)

```Linux:Linux
[root@testhost ~]# hostname testhost2
[root@testhost ~]# uname -n
testhost2
[root@testhost ~]# hostname
testhost2
[root@testhost ~]# cat /etc/hostname
testhost
```

ちなみに、hostnameコマンドでのホスト名の変更は一時的なものです。
サーバを再起動すれば元に戻ってしまいます。
永続的にホスト名を変更したい場合は、ファイル/etc/hostnameを書き換えます。
上記の通りhostnameコマンドでのホスト名の変更はファイル/etc/hostnameには反映されませんので、ファイル自体を直接書き換える必要があります。
書き換えた後、サーバを再起動することで変更が反映されます。

```Linux:Linux(再起動前)
[root@testhost ~]# echo testhost2 > /etc/hostname
[root@testhost ~]# uname -n
testhost
[root@testhost ~]# hostname
testhost
[root@testhost ~]# cat /etc/hostname
testhost2
```

```Linux:Linux(再起動後)
[root@testhost2 ~]# uname -n
testhost2
[root@testhost2 ~]# hostname
testhost2
[root@testhost2 ~]# cat /etc/hostname
testhost2
```
2021/07/16開催 Connpassイベントランキング

# 申込数TOP5

|順位|イベント名|グループ|申込数|定員|
|:---:|:---|:---|:---:|:---:|
|:one:|[Cloud Native Database Meetup #1](https://cndata.connpass.com/event/215876/)|[Cloud Native Data Community](https://cndata.connpass.com/)|943|1001|
|:two:|[事前質問求む！経産省DX室ゼロトラスト報告書の解説。その前にゼロトラストおさらいするよ](https://animereview.connpass.com/event/217288/)|[ロードバランスすだちくん](https://animereview.connpass.com/)|587||
|:three:|[Tech Lead Night vol.0 - 各社のテックリードが、気になるテーマを徹底討論！ -](https://legalforce.connpass.com/event/217400/)|[LegalForce](https://legalforce.connpass.com/)|390||
|:four:|[tc39_study](https://web-study.connpass.com/event/213676/)|[web-study](https://web-study.connpass.com/)|174|65791|
|:five:|[Salesforce好きあつまれ！！夏のオールスター感謝祭](https://umekitaforce.connpass.com/event/214970/)|[Umekita Force](https://umekitaforce.connpass.com/)|145|155|
【備忘録】Build-tool 31.0.0 is missing DXの対処方法（Cordova）

## 追記（2022.03.18）
多くの方の閲覧ありがとうございます。
本エラーはv30.0.3に落とさなくともdx.bat、dx.jarをv30.0.3でコピーして、
それ以上のバージョンに張り付ければ動作するとのことです。

合わせて参考にしてください。

https://stackoverflow.com/questions/68387270/android-studio-error-installed-build-tools-revision-31-0-0-is-corrupted

## 環境
OS : Windows 10
Cordova Ver : v10.0.0
Java Ver : v1.8.0_291
Android SDK : 30, 29（Android 11, 10）
Android Emulator : v30.7.5
Android SDK Platform-Tools : v31.0.2
Android SDK Build-Tools : ~~v31.0.0~~ → v30.0.3

## やりたかったこと
```
cordova emulate android
```
をして、エミュレータでアプリを起動したかった。

## 出たエラー
```
C:\Users\kr-tukimi\pixie\Pixie>cordova emulate android
Checking Java JDK and Android SDK versions
ANDROID_SDK_ROOT=D:\SDK (recommended setting)
ANDROID_HOME=undefined (DEPRECATED)
Using Android SDK: D:\SDK
Subproject Path: CordovaLib
Subproject Path: app
Starting a Gradle Daemon, 1 incompatible Daemon could not be reused, use --status for details
Build-tool 31.0.0 is missing DX at D:\SDK\build-tools\31.0.0\dx.bat
File C:\Users\kr-tukimi\.android\repositories.cfg could not be loaded.
Build-tool 31.0.0 is missing DX at D:\SDK\build-tools\31.0.0\dx.bat
```

## やったこと

- Java（JDK、JRE）の再インストール　→　ビルド失敗
- Cordovaのプロジェクトの作り直し　→　ビルド失敗
- Android SDK Platform-Toolsの再インストール　→　ビルド失敗

## 成功方法

Android StudioのSDK Build-Toolsのバージョンダウン（31.0.0 → 30.0.3）
（どうやら、dx.batが31.0.0でなくなったらしい。）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/461549/5c6c9103-8d1a-3a94-2010-ac0709f083f7.png)

（2021/11/13 追記：右下のShow Package Detailsをクリックするのをお忘れなく）

## 最後に
ここで躓いて正直キレそうだったので、参考になったら幸いです。
間違っていたりしたら、コメントで教えてください...
（実はこれが初めてのQiitaの記事だったりするので...）
非情報系大学生の応用情報技術者（AP）試験 勉強法

初Qiitaです。
2020秋試験で応用情報技術者試験に合格したので、
勉強法をメモしておこうと思います。

マークダウン、初めてでリンクなど上手くできるかわかりませんが、頑張ります！
###目次
0.私について
1.動機
2.午前対策
3.午後対策
4.結果

##0.私について
受験当時、理系大学3年生でした。
理系といっても情報系ではなく、大まかなくくりでは、生物系です。

大学の講義では、基礎的なPCスキルとしてオフィス、
Perl、C言語、FORTRANを少しだけ触りました。

大学１年生でITパスポート、大学２年生で基本情報技術者試験に合格しており、
その流れで応用情報技術者試験に申し込みました。

##1.動機
・講義の中で、教員が情報系資格の取得を勧めていたこと。
・大学から、資格奨励賞として5000円分のQUOカードが貰えること。
この二点が決め手となり、
大学１年生でITパスポート、大学２年生で基本情報技術者試験に挑戦しました。

折角独学で情報系の勉強を頑張ったので、もうワンランク上の応用情報技術者試験を受験してみよう！と思い立ったのが申し込みのきっかけとなりました。
（ちなみに、応用情報技術者試験は資格奨励賞の対象ではありませんでした^^）
##2.午前対策
まず、知識のインプットのために、参考書をひと通り読みました。
[<img src="https://img.ips.co.jp/ij/19/1119101080/1119101080-520x.jpg"width="30%" height="30%">](https://book.impress.co.jp/books/1119101080)
参考書は、PDF版がダウンロードできるものを使用していたので、
Amaz⚪︎nの安いタブレットでお風呂で読むことが多かったです。

その後は、アウトプットとして[過去問道場](https://www.ap-siken.com/apkakomon.php)をやりました。
直近２回分の過去問からは出題されない傾向があるようなので、
一年前のものから５回分程度、満点が取れるまでやりました。
##3.午後対策
[<img src="https://www.itec.co.jp/store/upload/save_image/10131006_5f84fda26da8a.png">](https://www.itec.co.jp/store/products/detail.php?product_id=3756)
これが最もメジャーな午後の参考書だと思います。
まず、直近の過去問を全問といて、得意な分野と苦手な分野を見極めました。
それ以降は、セキュリティを重点的に、練習していきました。

過去問道場でも午後試験の問題を解くことができるのですが、文章が長いので、紙媒体の方が見やすいかと思います。
私はがっつり勉強するときは本で、移動時やお風呂では復習として過去問道場で勉強しました。
過去問道場を使う際は、書き込み機能や計算機機能をうまく使うと時間短縮になると思います。

ネットワークが苦手だったので、[『マスタリングTCP/IP 入門編』](https://www.ohmsha.co.jp/book/9784274224478/)を購入し、読みましたが、本番ではネットワークは選択しませんでした。。。

午前は３週間、午後は１週間ほど毎日5時間以上勉強しました。
##4.結果
午前77.50点
午後67.00点
午後はギリギリですが、合格していました。

1.情報セキュリティ、2.経営戦略、4.システムアーキテクチャ、10.サービスマネジメント、11.システム監査を選択しました。

---

正攻法すぎる勉強法で、特に参考にはならないと思いますが、
Qiitaに何か投稿してみたいなと思い立ち、書きました。

2年間は午前1試験の免除があるので、その間に情報処理安全確保支援士の試験にも挑戦してみたいと思っています。
ShaderForgeで作られたシェーダーをUnityWebGLで動作させる

# 概要

ShaderForge 自体は今ではあまり使われていなそうではあるが、Asset Store 等に入っている Shader で利用されていることが偶にある。しかし、ShaderForge 製のシェーダーは WebGL ビルドを行うと正常に動作しないため、これを WebGL でも利用可能にする方法をメモしておく。

Unity バージョンは Unity 2021.1.4f1 で確認済み。

# 解決策

こちらの記事に解決策が記載されていた。
[Shader Forge on webgl - Unity Forum](https://forum.unity.com/threads/shader-forge-on-webgl.502187/)

対応としては Shader コード内にある `#pragma only_renderers` から始まる行を削除するだけで良い。

# 解説

[Unity 公式ドキュメント](https://docs.unity3d.com/ja/2018.4/Manual/SL-ShaderPrograms.html)によると、`only_renderers` の機能は下記の通り。

> `#pragma only_renderers space separated names` - 指定のレンダラー用にのみシェーダーをコンパイルします。デフォルトではすべてのレンダラー用にシェーダーがコンパイルされます。詳細は後述の Renderers を参照してください。

Renderers の項目を見てみると、下記のように記載されていた。

> Unity はいくつかのレンダリング API (例えば Direct3D 11 と OpenGL) をサポートしており、デフォルトではすべてのシェーダープログラムは、サポートされているすべてのレンダラーにコンパイルされます。#pragma only_renderers または #pragma exclude_renderers ディレクティブを使用してどのレンダラーをコンパイルするかを指定できます。これは、一部のプラットフォームでは使用不可であることが分かっているシェーダー言語の機能を、明示的に使用する場合に最も役立ちます。

つまり、WebGL のレンダラー用にシェーダーがコンパイルされていなかった模様。
`only_renderers` の行を削除して WebGL で ShaderForge の機能を動作させても期待通りの挙動をすることが確認できた。(もしかすると、一部の機能は動作しないのかもしれない)

# まとめ

シェーダーは難しいが、学べば学ぶほど 3D の世界に対する理解が深まって楽しい。
これからもシェーダーに対しての知見を深めていければと思う。
Let's Encryptを用いてlightsailをssl化する

#目次的なの
* 書こうと思った理由
* 発行までの下準備
* 発行
* 更新

#書こうと思った理由
毎回複数サイトを見るのが面倒だからまとめちまおうと

#発行までの下準備
##Let’s Encrypt(LEGO) インストール
以下のコマンドにて/tmpにLet’s Encrypt(LEGO) をインストール

```
# cd /tmp
# curl -Ls https://api.github.com/repos/xenolf/lego/releases/latest | grep browser_download_url | grep linux_amd64 | cut -d '"' -f 4 | wget -i -
```

##解凍

```
# tar xf lego_{バージョン}.tar.gz
```

##作業用ディレクトリの追加、移動
```
# sudo mkdir -p /opt/bitnami/letsencrypt
# sudo mv lego /opt/bitnami/letsencrypt/lego
```

#発行
##bitnamiサービスの停止
```
# sudo /opt/bitnami/ctlscript.sh stop
```

##証明書の発行
```
sudo /opt/bitnami/letsencrypt/lego --tls --email="{your@email.com}" --domains="{domain}" --path="/opt/bitnami/letsencrypt" run
```

##証明書 ファイル、暗号鍵ファイル 差替え
aws Lightsail LAMP7のインスタンス環境だと、デフォルトで証明書ファイル(server.crt)、暗号鍵ファイル(server.key)が配置されています。

これらを作成済みのファイルに差し替える必要があります。

まず、既存のファイルをバックアップします。
※crtファイル、keyファイルが存在しないとbinamiサービスは正常に起動できなくなるので、失敗に備えてバックアップします。

```
# sudo mv /opt/bitnami/apache2/conf/bitnami/certs/server.crt /opt/bitnami/apache2/conf/bitnami/certs/server.crt.old
# sudo mv /opt/bitnami/apache2/conf/bitnami/certs/server.key /opt/bitnami/apache2/conf/bitnami/certs/server.key.old
```

バックアップ後に反映させるため移動

```
# sudo cp /opt/bitnami/letsencrypt/certificates/{domain}.crt /opt/bitnami/apache2/conf/bitnami/certs/server.crt
# sudo cp /opt/bitnami/letsencrypt/certificates/{domain}.key /opt/bitnami/apache2/conf/bitnami/certs/server.key
```

##停止していたbitnamiサービスの起動
```
# sudo /opt/bitnami/ctlscript.sh start
```
ここまで実行すると設定した{domain}がhttpsアクセスできると思います

#更新
このままではいずれ有効期限が切れてしまうため更新用ファイルを作成する

``` 
# sudo vi /opt/bitnami/letsencrypt/renew-certificate.sh
```

中身

```renew-certificate.sh

#!/bin/bash

sudo /opt/bitnami/ctlscript.sh stop
sudo /opt/bitnami/letsencrypt/lego --tls --email="{your@email.com}" --domains="{domain}" --path="/opt/bitnami/letsencrypt" renew
sudo /opt/bitnami/ctlscript.sh start
```

##アクセス権限の書き換え
```
# sudo chmod +x /etc/lego/renew-certificate.sh
```

##cronの設定
``` 
# sudo crontab -e
```
```
# 毎月0時更新
0 0 1 * * sh /opt/bitnami/letsencrypt/renew-certificate.sh
```

#参考
https://qiita.com/yshishido/items/67c57b9faafbda07da81
https://syslog.life/2020/10/18/aws-lightsail-%E8%A8%BC%E6%98%8E%E6%9B%B8-%E4%BD%9C%E6%88%90-%E8%A8%AD%E5%AE%9A-tls-ssl-lets-encrypt/#%E3%83%BBLets_EncryptLEGO_%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB
pythonのformatで分割して代入/別々に代入/段階的に代入

#やりたいこと

pythonの文字列処理でformatというのがあります。
例えば、

```python:test1.py
format_str = "My name is {name}. I am from {place}. Nice to meet you."

what_to_say = format_str.format(name="Bob", place="Beppu")
print(what_to_say)
```

```text:実行結果
My name is Bob. I am from Beppu. Nice to meet you.
```

となります。

ただ、以下のようにするとエラーが出ます。

```python:test2.py
format_str = "My name is {name}. I am from {place}. Nice to meet you."
what_to_say = format_str.format(name="Alice")
what_to_say = what_to_say.format(place="Tsugaru")
print(what_to_say)
```

```text:実行結果
Traceback (most recent call last):
  File "●●.py", line ●, in <module>
    what_to_say = format_str.format(name="Alice")
KeyError: 'place'
```

formatでplaceが指定されていない！と怒られてしまいました。
どうやらstr.format()を使うときは、formatで定義されている変数をすべて一気に入れないとエラーになるようです。

ではこのエラーを回避して、formatの文章に分割して代入/別々に代入/段階的に代入したいときにどうすればいいか、という話になると思います。
そもそも、一気に代入するのが普通なので、こういうケースはほとんどないのですが、以前記事にした、
[Twitter Botで長い文章をツイート可能ギリギリの長さに調節する](https://qiita.com/eg_i_eg/items/179e49918b230caf4bd6)
といったケースでは、書き出し以外の文章を代入して、その後書き出しを代入する、という手順をとる場合は、段階的に代入がしたいです。
(もちろん他の手順をとればいいだけの話ですが、今回はこの方法ですすめるとします)

# 解決策
もっと他にいい方法はあるんじゃないかともいましたが、以下の方法でいけました。

```python:test3.py
format_str = "My name is {name}. I am from {place}. Nice to meet you."
what_to_say = format_str.format(name="Alice", place="{place}")
what_to_say = what_to_say.format(place="Tsugaru")
print(what_to_say)
```

```text:実行結果
My name is Alice. I am from Tsugaru. Nice to meet you.
```
voidでない関数は値を返す必要がある

まあ、当たり前のことですが…

```cpp
#include <stdio.h>
#include <stdlib.h>
__attribute__((noinline)) int func(int n){
for(volatile int i=0;i<n;i++)puts("hello world");
fflush(stdout);
getenv("PATH");
}
int main(){
func(3);
}
```

これをgccに食わせると、`no return statement in function returning non-void`警告が発生します。
この警告に関して、返値を呼び出し側で使わなければ動作に影響はないと思っている人は多いと思います(私もその一人でした)。
しかし実際には、以下のようになります[^1][^2]。

|処理系|func呼び出し結果|
|:--|:--|
|gcc|返値不定|
|g++-6以下|0が返る|
|g++-7|返値不定|
|g++-8以上|**segmentation fault**|
|clang|返値不定|
|clang++|**segmentation fault**|
|icc|返値不定|
|icpc|返値不定|
|icx|返値不定|
|icpx|返値不定|
|msvc|(値を返さないのはそもそも警告ではなくコンパイルエラー)|

g++-8以上およびclang++[^3]では **スタックポインタを復元するアセンブリもretアセンブリも出力されませんでした。** segvまっしぐらです[^4]。
今まで気づかなかったのが不思議です。。

[^1]: https://gcc.godbolt.org/ で確認しました。すごく便利なサイトですね。
[^2]: 最適化ありの場合です。
[^3]: CとしてコンパイルしたときとC++としてコンパイルしたときの挙動が違う…。
[^4]: しかもこれ系はgdbで正しいスタックトレースが取得できなくなるので極めてたちが悪い。
Svelte Nativeを触ってみた

# 目的
Svelte Nativeを使って、カメラを使って写真を撮ってそれを表示するやつをやってみる。

# 環境 
今回はandroidを使ってやった。
android11
node: v16.3.0
npm:  v7.15.1
# プロジェクトの用意
公式ホームページにもある通り、テンプレートからsvelte nativeのプロジェクトを作成する。

```
npm install -g nativescript
npx degit halfnelson/svelte-native-template my-camera-app
cd my-mobile-app
```
その後以下のコマンドを実行すると、正常に動作した場合QRコードのようなものが表示されるはず。

``` 
npm install
ns preview
```

こんなの
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329475/cb55bea5-4795-d1de-cbcb-bcfcc43532f7.png)

## アプリのプレビュー
以下二つのアプリをダウンロードする。
Native Script Playgroundでコンソールに表示されたQRコードを読み込むと、NativeScript Previewのほうにアプリのプレビューが表示される。

https://play.google.com/store/apps/details?id=org.nativescript.play

https://play.google.com/store/apps/details?id=org.nativescript.preview　

こんなのが出たら成功
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329475/bfbaea3f-3b47-a597-01fc-e7164cc3a391.png)

# カメラで写真を撮れるようにする。
以下のコマンドを実行してカメラプラグインを追加する。

```
tns plugin add nativescript-camera
```

そしてプロジェクトの`app/App.svelte`を以下のコードに書き換える。

```ts
<script lang="typescript">
  import * as camera from "nativescript-camera";
  let image;
  const onButtonTap = () => {
    camera
      .takePicture()
      .then(function (imageAsset) {
        console.log(imageAsset);
        image = imageAsset._android;
      })
      .catch(function (err) {
        console.log("Error -> " + err.message);
      });
  };
</script>

<page>
  <stackLayout >
    <button text="Button" on:tap={onButtonTap} />
    <image src={image} />
  </stackLayout>
</page>
```
# 結果
見づらいけど上のほうにボタンがあって、それを押すと、カメラが起動。
写真を撮るとアプリに表示されるアプリが出来上がる。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329475/b93ada68-bfbe-6de6-754d-e47ed75657d6.png)

＊ 写真を撮ってからOKボタンが表示されるまでラグがあるので注意
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329475/c95ed0ed-7e4a-789d-edfb-4f3fea6e07e0.png)

# 結論
すごいね
Rails APIモード　Docker-Compose

```
$ cd

$ mkdir sample_app

$ cd sample_app
```

以下ファイルを用意
Dockerfile
docker-compose.yml
Gemfile
Gemfile.lock
environment.rb


以下コマンドを実行

```
$ docker-compose run web rails new . --force --database=mysql --skip-bundle --api --webpacker
```

以下のコマンドを順に打ちます。

```
$ docker-compose build

$ docker-compose run web yarn install --check-files

$ docker-compose run web rake db:create

$ docker-compose up
```

以下の

```
http://localhost:3000/　
```
にアクセスします。
TypeScript 非nullアサーション演算子を使う

# 記事の趣旨
TypeScriptには、値がnullでないことを示すための、非nullアサーション演算子(Non-Null Assertion Operator) `!` という構文があります。
これが、便利ですがあまり知られていないような気がしたので（自分も最近知りました）、使用例や `?` との違いをまとめました。

# 使用例
## 前提
例として、あるinput要素が存在することが保証されていて、その要素にフォーカスしたい場合を考えます。
この時以下のように書くと型エラーが発生します。

```ts
document.getElementById('input').focus() // エラー: オブジェクトは 'null' である可能性があります。
```

これは、 `document.getElementById` の戻り値が `HTMLElement | null` となるためです。

## オプショナルチェイニングの注意点

要素が存在する（nullでない）ことが保証されている場合、それをコンパイラに伝える必要がありますが、その時以下のようにオプショナルチェイニング `?` を使いたくなるかもしれません（エディタによってはそのように補完してくれます）。

```ts
document.getElementById('input')?.focus()
```

こうすると一旦エラーは解消されますが、万が一改修ミスによってinput要素のidが変わった場合、コンパイルエラーも実行時エラーも発生せず、フォーカスの動作が行われないという発見しづらいバグを生む可能性があります。

**→ 型エラーを防ぐ目的で、安易に `?` を使わないように注意が必要。**

## 非nullアサーション演算子
上記の問題を防ぐ方法として、以下のように非nullアサーション演算子 `!` を使う方法があります。

```ts
document.getElementById('input')!.focus()
```

`!` は、オペランドが非nullかつ非undefinedであることをassertするものです。これは、以下のように明示的にassertすることを省略した書き方とも言えます。

```ts
(document.getElementById('input') as HTMLElement).focus()
```

このように書くことで、input要素が取得できなくなった場合は、 `Cannot read property 'focus' of null` という実行時エラーが発生するため、バグに気付きやすくなります。

ちなみに、`!` は、後ろにメソッド等が続く必要がある訳ではありません。（ `?` の場合は必須）

```ts
const inputElement = document.getElementById('input')!
```

# 不適切に利用しない
あくまで上記の例は、要素が存在していることが保証されている場合の使用例です。

eslintの `typescript-eslint/recommended` のpluginで、 `no-non-null-assertion` というルールが設定されていることからも分かるように、不適切な箇所に使用しないように注意する必要があります。
https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/docs/rules/no-non-null-assertion.md

# 参考
TypeScript Deep Dive
https://typescript-jp.gitbook.io/deep-dive/intro/strictnullchecks