OmniAICreator/Qiita-1.07M huggingface dataset:
datepickerとtimedropperでDateTimeFieldをカスタマイズする

今回のお題
-
以前にModelFormウィジェットをいくつか取り上げた際に、日時を入力できる`SplitDateTimeWidget`を紹介しました。

https://qiita.com/keishi04hrikzira/items/a6e6820740e1e99d05fe

ただ、これをそのまま使うと日時を直接入力する必要があり使い勝手が悪いです（詳しくは上記の記事を参照）。

そこで今回は以下のようにカレンダーと時計から日時を選択できるようにしていきたいと思います。

[![Image from Gyazo](https://i.gyazo.com/8319527ea7c8bc34b0d2bee0dc4178dc.png)](https://gyazo.com/8319527ea7c8bc34b0d2bee0dc4178dc)

[![Image from Gyazo](https://i.gyazo.com/2a293fe181f14d58f3901bd5c5565838.png)](https://gyazo.com/2a293fe181f14d58f3901bd5c5565838)

カレンダーには`datepicker`, 時計には`timedropper`というjQueryプラグインを使います。

datepickerの導入
-

プラグインの読み込み部分および実行部分は以下の通りです。

```html:プラグイン読み込み部分
    <link rel="stylesheet" href="//code.jquery.com/ui/1.13.0/themes/base/jquery-ui.css">
    <script src="https://code.jquery.com/jquery-3.6.0.js"></script>
    <script src="https://code.jquery.com/ui/1.13.0/jquery-ui.js"></script>
```
```html:スクリプト実行部分
    <script>
      $(function(){
        $('#id_datetime_0').datepicker({
          dateFormat: "yy-mm-dd"
        });
      });
    </script>
```

datepickerに関しては公式サイトがあるので、バージョンの問題なども含めて一度そちらをみていただくのが良いかと思います。

https://jqueryui.com/datepicker/

一応スクリプト実行部分について解説しておきます。

```javascript
$('#id_datetime_0')
```
`SplitDateTimeWidget`で生成されたinput要素のうちの日付の入力欄の方を指定しています。

idはdjangoから自動で付与されます。

```javascript
datepicker({
  dateFormat: "yy-mm-dd"
})
```
`datepicker`メソッドで、対象のinput要素（今回であれば`#id_datetime_0`)にカレンダーを付与します。

引数の`dateFormat`はカレンダーで選択した日付をどのようなフォーマットでinput要素に入力するかを指定します（今回は`yy-mm-dd`なので年数は４桁、月と日付は十の位を0詰め）。

djangoのdatetime.dateオブジェクトのデフォルトのフォーマットは(yyyy-mm-dd)なので、datepickerのフォーマットもそれに合わせるかウィジェットの方で引数を追加して対応可能なフォーマットを増やさないとバリデーションエラーになります。

timedropper
-

timedropperの方のコードは以下の通りになります。

こちらは公式サイトらしきものにあまり情報がなかったので個人ブログなどをいくつか参考にさせていただきました。

バージョンなどは最新ではないかもしれないです。

```html:プラグイン読み込み部分
    <link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/timedropper/1.0/timedropper.min.css">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/timedropper/1.0/timedropper.min.js"></script>
```
```html:実行部分
    <script>
      $(function(){
        $("#id_datetime_1").timeDropper({
          format: "H:mm:00"
        })
      })
    </script>
```

```javascript
$('#id_datetime_1')
```
は時刻入力欄に自動付与されるidです。

ここに対して`timeDropperメソッド`で時計を付与しています。

```javascript
format: "H:mm:00"
```
についてですが、`timeDropper`は何時何分までしか指定できず、それを無理矢理djangoが解釈可能な`H:i:s`のフォーマットに変換するためにこのようにしました。

終わりに
-
以上でdatepickerとtimedroperが実装できました。

カレンダーと時計を表示させるだけであればほとんどコピペでも動くレベルですが、フォーマットに気をつけないとバリデーションで弾かれてしまうのでそこに気をつけたいですね。
[Vue] 親子間のライフサイクルフック（created, mounted）の処理順

## はじめに

- 機能実装に伴って、mountedライフサイクルフックに処理を追加した際に、思い通りの挙動をせず解決までにちょっと時間をかけてしまったので自戒の念を込めまとめます。

## やりたかったこと

- 前提として、親のmountedで取得したデータを受け取って要素を表示するコンポーネント
- その要素に対して処理を追加したい

## 結論

- 単純に親子間の処理順の問題でした。（ただの無知でした）
- 親のmountedより子のmountedが先に処理される為、思い通りの挙動にならなかったということです。

## サンプル

#### 親コンポーネント
```Parent.vue
<template>
  <div>
    <span>parent</span>
    <Child />
  </div>
</template>

<script>
import Child from './Child.vue'

export default {
  components: {
    Child,
  },
  mounted() {
    console.log("i am parent.")
  },
}
</script>
```

#### 子コンポーネント
```Child.vue
<template>
  <div>
    <span>child</span>
  </div>
</template>

<script>
export default {
  mounted() {
    console.log("i am child.")
  }
}
</script>
```

#### 結果

![スクリーンショット 2021-11-13 17.10.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46053/efca246f-d5e8-2901-cbcb-5b5883e987c9.png)

## サンプル改

- 孫コンポーネントを追加
- createdライフサイクルフックを追加

#### 親コンポーネント
```Parent.vue
<template>
  <div>
    <span>parent</span>
    <Child />
  </div>
</template>

<script>
import Child from './Child.vue'

export default {
  components: {
    Child,
  },
  created() {
    console.log("[created] i am parent.")
  },
  mounted() {
    console.log("[mounted] i am parent.")
  },
}
</script>

```

#### 子コンポーネント
```Child.vue
<template>
  <div>
    <span>child</span>
    <Grandchild />
  </div>
</template>

<script>
import Grandchild from './Grandchild.vue'

export default {
  components: {
    Grandchild,
  },
  created() {
    console.log("[created] i am child.")
  },
  mounted() {
    console.log("[mounted] i am child.")
  }
}
</script>
```

#### 孫コンポーネント
```Grandchild.vue
<template>
  <div>
    <span>grand child</span>
  </div>
</template>

<script>
export default {
  created() {
    console.log("[created] i am grand child.")
  },
  mounted() {
    console.log("[mounted] i am grand child.")
  }
}
</script>
```

#### 結果

![スクリーンショット 2021-11-13 17.15.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46053/52731359-e4ab-ec47-f071-9a9333e09961.png)

## まとめ

- createdは、親→子の順に処理が行われる
- mountedは、子→親の順に処理が行われる
- めんどくさがらず仕組みを理解しよう！
    - こういうディティールへの理解が大事だなと自戒

## 参考記事
https://medium.com/@brockreece/vue-parent-and-child-lifecycle-hooks-5d6236bd561f
JavaScriptのReact NativeプロジェクトにTypeScriptを導入する

JavaScriptで作ったReact Nativeプロジェクトだけど、やっぱりTypeScript使いたい！
というとき何か方法無いかな？と思っていたら、公式ドキュメントに方法が書いてありました。

[Adding TypeScript to an Existing Project](https://reactnative.dev/docs/typescript#adding-typescript-to-an-existing-project)

公式ドキュメントを読むの大事だな、と改めて思いました。
SPAで<input type=file>要素を使い回す場合はvalueをクリアしましょう

## 先に結論だけ

[input type="file"](https://developer.mozilla.org/ja/docs/Web/HTML/Element/input/file)要素は選択されたファイルの情報を保存します。まったく同じファイルを選択した場合、input要素はchangeおよびinputイベントを発行しません。input要素のvalue属性に`"" 空文字`を設定すると選択状態がクリアされ、input要素は再度イベントを発行します。

## はじめに

この記事は`input type="file"`要素の選択状態とイベント発行について記録、共有するためのものです。

シングルページアプリケーションで、fileタイプのinput要素をファイルオープンコマンドとして利用したところ、イベントが発行されず詰まりました。fileタイプのinput要素について誤解していた点と、解決手順を整理します。

## 問題発生の経緯

ローカルファイルを開き、編集を加えるシングルページアプリケーションを開発します。

ファイルオープンコマンドとしてfileタイプのinput要素を利用します。input要素のchangeイベントをトリガーにしてファイルを開き編集します。

編集状態を破棄してもう一度ファイルを開こうとしたとき、input要素からイベントが発行されないことに気がつきました。この問題は、編集状態を破棄する前と後で同じファイルを開くときのみ発生し、別のファイルを開くときは正常に動作します。

## 問題の分析と解決

この問題は、同一ファイルをinput要素に連続して与えるとイベントが発行されない事が原因です。

### マルチページアプリケーションの場合

マルチページアプリケーションでは、ユーザーはお問い合わせフォームのような一連のinputフォームを入力し、最後にsubmitボタンを押します。JavaScriptはsubmitボタンが押されてから、すべてのフォームの入力値をあつめてサーバーに送信し、送信前ページなど次のページに遷移します。

このページ遷移のタイミングでinput要素はすべて破棄されるため、開発者はフォームの再利用を考える必要がありません。ページの遷移に伴いフォームがクリアされる点を失念したため、この問題が発生しました。

### シングルページアプリケーションの場合

シングルページアプリケーションでは、ユーザーがinput要素に値を入力したらJavaScriptはイベントに応じてそのたびに反応を返します。input要素は、入力値が再び必要になった場合に備えてvalue属性に入力値をため込んでいます。input要素はvalue属性値と同じ値を入力された場合、changeおよびinputイベントを発行しません。

### 解決方法

ため込んだ値をクリアすれば、input要素は再びイベントを発行します。fileタイプのinput要素の場合、value属性に`空文字""`を代入すれば値がクリアされます。

以上、ありがとうございました。

## 参考記事

https://stackoverflow.com/questions/20549241/how-to-reset-input-type-file
SQL Server コンテナーを実行して.NET アプリケーションと接続する

## 参考

- [クイック スタート:Docker を使用して SQL Server コンテナー イメージを実行する](https://docs.microsoft.com/ja-jp/sql/linux/quickstart-install-connect-docker?view=sql-server-ver15&preserve-view=true&pivots=cs1-bash)
- [SQL Server Docker コンテナーをデプロイして接続する](https://docs.microsoft.com/ja-jp/sql/linux/sql-server-linux-docker-container-deployment?view=sql-server-ver15&pivots=cs1-bash)

## 概要

Docker コンテナで立ち上げたSQL Serverを.NET 5.0で作成したアプリケーションに接続します。

## Docker コンテナの作成

Docker Imageを取得

```bash
docker pull mcr.microsoft.com/mssql/server:2019-latest
```

Dockerでコンテナイメージを実行する

```bash
docker run -e ACCEPT_EULA=Y -e SA_PASSWORD=<YourStrong@Passw0rd> \
   -p 1433:1433 --name sql1 -h sql1 \
   -d mcr.microsoft.com/mssql/server:2019-latest
```

コンテナが無事に起動しているかを確認

```bash
>>> docker ps
CONTAINER ID   IMAGE                                        COMMAND                  CREATED          STATUS          PORTS                                       NAMES
0c832fda2fef   mcr.microsoft.com/mssql/server:2019-latest   "/opt/mssql/bin/perm…"   15 seconds ago   Up 11 seconds   0.0.0.0:1433->1433/tcp, :::1433->1433/tcp   sql1
```

起動したSQL ServerへはVS Codeの拡張機能から接続すると便利
参考：[Visual Studio Code 用 SQL Server 拡張機能](https://docs.microsoft.com/ja-jp/sql/tools/visual-studio-code/sql-server-develop-use-vscode?view=sql-server-ver15)

VS Codeの拡張機能でSQL Serverに接続するときの認証情報
server name：```localhost,1433```
db name：```空欄```
認証方法：```SQL Login```
user name：```sa```
password：```<YourStrong@Passw0rd>```

## .NET アプリケーションとの接続

appsetting.jsonにDBとの接続情報を書き加える

```json
{
  "ConnectionStrings": {
    "defaultConnection": "Server=tcp:localhost,1433;Initial Catalog=sample-db;Persist Security Info=False;User ID=sa;Password=P@ssw0rd;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;"
  },
  "Logging": {
      "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
      }
    },
"AllowedHosts": "*"
}
```

以下のドキュメントを参考に.NET Coreアプリからデータベースへの接続をする設定を行う

参考：[EF Core の概要](https://docs.microsoft.com/ja-jp/ef/core/get-started/overview/first-app?tabs=netcore-cli#feedback)
EBSスナップショットストレージでAWSの無料枠を超えそうになった話

# はじめに
AWSから以下のようなメールが来ました。
どうやら、1つ以上のAWS無料枠対象サービスの使用制限の85%を超えたよ、というアラートらしいです。
![aws_mail.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1504894/c89f3f36-f5ca-3cce-7265-4b9591f776cd.png)
85%を超えた「Product」は「EC2」って書いてますね。
11月はEC2さわってないし、10月に動かしてたEC2インスタンスは全て停止していたはずなので、
このメールが来たとき、？？？ってなりました。
メールをよく見ると、
「1GB of Amazon Elastic Block Storage snapshot storage」の無料枠を
あとちょっとで超えるよ、と言われてます。

# 原因
そもそも「Elastic Block Storage（EBS）」とは、
ネットワーク接続型ストレージで、EC2にアタッチして使われますが、EC2とは独立して管理されるものです。
同じブロックストレージのインスタンスストアとは異なります。


では、なぜEC2インスタンスを停止していたのに、アラートメールが来たのでしょうか。
https://aws.amazon.com/jp/premiumsupport/knowledge-center/ebs-charge-stopped-instance/
ここに分かりやすく書いてくれてありますね。
> Amazon EC2 インスタンスで料金が発生するのはそれを起動している間だけですが、**インスタンスに接続されているEBSボリュームの場合、インスタンスを停止したとしても、情報の保持と料金の発生は継続されます。**



# 解決方法
無料枠を超えないようにする方法も上記のサイトに書いてくれてます。
> Amazon EBS の関連料金を停止するには、不要な EBS ボリュームと Amazon EBS スナップショットを削除します。

というわけで、まずは不要なEBSボリュームを削除しましょう。
![ebs_detach.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1504894/e912b398-a1ad-2554-c3a2-00849f0ffee8.png)
と言っても、EC2インスタンスにアタッチされている状態では削除できないので、まずはデタッチします。
そしたら削除できるようになるので、EBSボリュームを削除します。
次に、スナップショットを削除しましょう。
![snapshot_delete.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1504894/bffce28f-9adf-a859-ae44-e66a478458cf.png)
こちらはAMIを先に削除しないと削除できないみたいです。

そもそも使っていないEC2インスタンスなら、ボリュームとスナップショットの削除じゃなくて
EC2インスタンス自体を終了（削除）すれば良さそうですね。。
Goのtime型で過去300分の時間を出力

# 概要
goで過去300分の時間を出力するプログラムです。
goの文字列からtime型への変換で手間取ったため、備忘録ととして残しておきます。



```golang:main.go
package main

import (
	"fmt"
	"strconv"
	"time"
)

func main() {
	t:= time.Now()
	fmt.Println(t)

	for i := 1; i < 300; i++ {

		s:= strconv.Itoa(-i)
		// iを文字列型に変換

		m, _ := time.ParseDuration(s+"m")
		// 文字列型を時間に変換
		
		t2 := t.Add(m-time.Minute)
		// 時間を引く
		fmt.Println(t2)
	}
}
```

#参考元
>https://pkg.go.dev/time#example-Duration.Minutes
webサーバにDBサーバの秘密鍵をscpするのにハマった話

### はじめに
- AWSの紫本P147にて「踏み台サーバーを経由してSSHで接続する」で躓いたので備忘のためにメモ。

### 結論
- 秘密鍵はローカルのホームディレクトリに置かなくてもいい。
- scpコマンドオプションを知っていれば問題ない。

### 手順
#### 1. AWSマネジメントコンソールからWEBサーバのキーペア（以下、`web.pem`）とDBサーバのキーペア（以下、`db.pem`）をローカルの任意のディレクトリ（以下、`hoge/`）ダウンロードする。
#### 2. EC2のWEBサーバのパブリック IPv4 DNSを確認する（以下、`PublicIPv4DNS`）
#### 3. ローカル上で以下のコマンドを叩く。

```shell
$ cd hoge/
$ ls # web.pem と db.pemがあることを確認する
$ scp -i ~/hoge/web.pem ~/hoge/db.pem ec2-user@PublicIPv4DNS:~/
# ~/hoge/web.pem を使ってwebサーバにアクセスし、~/hoge/db.pem を ec2-user@PublicIPv4DNS:~/ にコピーするという意味
```
とすると、

```
db.pem                                                                                           100% 1700    65.4KB/s   00:00  
```

と表示される。これでwebサーバーにdbサーバーの秘密鍵がアップロードは完了。

#### 4. SSHでWEBサーバーに接続する。
#### 5. WEサーバー上で以下のコマンドを叩く。
```shell
[ec2-user@ip-10-0-1-10 ~]ls
db.pem
[ec2-user@ip-10-0-1-10 ~]ssh -i db.pem ec2-user@10.0.2.10
```

### 以上
シェルスクリプトの実験のために作った POSIX 準拠 awk 実装の CSVパーサー (RFC4180対応)

## はじめに

シェルスクリプトでのデータ読込処理の実験のために手軽に出力フォーマットを変更できるやつが欲しかったので CSV パーサーを書きました。一応 POSIX 準拠 の awk で動いて（GNU 拡張は使っていません） RFC 4180 対応のつもり（フィールドの中にカンマや改行やダブルクォートや制御文字が入っていてもちゃんと動くはず）。ただし最低限の動作確認しかしてないので自己責任で。ライセンスは CC0 としますので、コピペして使うなり、加工して自分のコードとして使うなり、ご自由にどうぞ。

## コード

**RFC 4180 との違い**

- 改行コードは CR LF だけでなく LF にも対応しています。
- 行末のカンマを受け付けます（最後に空フィールドが有るとみなされる）。

```awk:csvparser.awk
# CSV の論理的な一行毎に呼び出されるコールバック関数（サンプル）
# row: 行番号（最初の行は1） len: フィールド数 fields: フィールドデータ
function callback(row, len, fields,  col, field) {
    for ( col = 1; col <= len; col++ ) {
        field = fields[col]
        gsub(/\\/, "&&", field)  # \ は \\ にエスケープする
        gsub(/\n/, "\\n", field) # 改行は \n にエスケープする
        print row ":" col " " field
    }
}

BEGIN { row = max_idx = 0 }
{
    idx = 0
    sub(/\r$/, "")
    while ($0 != "") {
        if (match($0, /^(["]([^"]|["]["])*["]|[^,"]*)(,|$)/)) {
            fields[++idx] = ""
        } else if (match($0, /^["]/)) {
            fields[++idx] = substr($0, 2)
            for (;;) {
                if (getline == 0) exit 1
                sub(/\r$/, "")
                if (match($0, /^([^"]|["]["])*["](,|$)/)) break
                gsub(/["]["]/, "\"")
                fields[idx] = fields[idx] "\n" $0
            }
            fields[idx] = fields[idx] "\n"
        } else {
            exit 1
        }
        field = substr($0, RSTART, RLENGTH)
        $0 = substr($0, RSTART + RLENGTH)
        lastcomma = sub(/,$/, "", field) > 0
        gsub(/^["]|["]$/, "", field) && gsub(/["]["]/, "\"", field)
        fields[idx] = fields[idx] field
    }
    if (lastcomma) fields[++idx] = ""
    while (idx < max_idx) delete fields[max_idx--]
    callback(++row, idx, fields)
    max_idx = idx
}
```

使い方

```sh
awk -f csvparser.awk data.csv
```

こういう CSV ファイルが

```csv:data.csv
aaa,bbb,ccc
"d,d,d","e""","""","""e","f\f\f"
"AAA
BBB
CCC
",,D D D,
"
E
E"
```

このように出力されます。（形式 `行番号:列番号 フィールド値`）

```
1:1 aaa
1:2 bbb
1:3 ccc
2:1 d,d,d
2:2 e"
2:3 "
2:4 "e
2:5 f\\f\\f
3:1 AAA\nBBB\nCCC\n
3:2
3:3 D D D
3:4
4:1 \nE\nE
```

出力形式は awk の `callback` 関数で整えているだけなので、必要に応じて変更してください。

## さいごに

余計なことはしてないのでそこそこ速いと思いますが gawk は結構遅いですね。実は正規表現使わずに実装した方が速いんじゃないかって思っています。

さて改行が含まれる CSV データをシェルスクリプトで読み取って処理しようとした時、一体どういうフォーマットを使えば一番効率的（高速）に処理できるんでしょうね。その実験をするのがこのコードを書いた目的です。わざわざ書かないで既存のコードを使えばいいじゃないか？と思うかもしれませんが既存の奴はやけにコードが長かったり出力を加工しづらかったりで目的に合わなかったり、ちゃんと文字列をパースせずに `sed` や `tr` で場当たり的に処理しているようなものは、特定の文字を扱えなかったりダブルクォート周りのバグで信頼性に疑問があったりで、修正するよりも書いたほうが早かったので。まあこのコードもバグがあるかもしれませんが。あと正規表現使って CSV パースしたことなかったのでやってみたかったのと、POSIX コマンドしか使えない環境でも動くようにしたいとか、そういう理由もありました。
path 要素の fill が指定されている SVG は svg 要素の fill を CSS で変えても意味がない

多くの SVG は `svg` 要素と `path` 要素で構成されています。

```html
<svg
  class="heart pink"
  width="32"
  height="32"
  viewBox="0 0 100 100"
  xmlns="http://www.w3.org/2000/svg"
  fill="black"
>
  <path
    d="M 10,30
   A 20,20 0,0,1 50,30
   A 20,20 0,0,1 90,30
   Q 90,60 50,90
   Q 10,60 10,30 z"
  />
</svg>
```

https://developer.mozilla.org/ja/docs/Web/SVG/Element/path

また、上述の SVG は以下の CSS で塗り潰し色を変えることができます。

```css
.pink {
  fill: pink;
}
```

https://developer.mozilla.org/ja/docs/Web/SVG/Tutorial/Fills_and_Strokes

ただし、 `svg` 要素ではなく `path` 要素の `fill` 属性で塗り潰し色が指定されていた場合、先述の CSS では色を変更することができません。
言い換えると、 `path` 要素の `fill` 属性が指定されていた場合、 `svg` 要素の `fill` 属性よりもそちらが優先されます。

```html
<!-- CSS で色をピンクに変更している SVG -->
<svg
  class="heart pink"
  width="32"
  height="32"
  viewBox="0 0 100 100"
  xmlns="http://www.w3.org/2000/svg"
  fill="black"
>
  <path
    d="M 10,30
   A 20,20 0,0,1 50,30
   A 20,20 0,0,1 90,30
   Q 90,60 50,90
   Q 10,60 10,30 z"
  />
</svg>

<!-- CSS で色をピンクに変更しようとしているが、できていない SVG -->
<!-- svg 要素ではなく path 要素に fill="black" を指定している -->
<svg
  class="heart pink"
  width="32"
  height="32"
  viewBox="0 0 100 100"
  xmlns="http://www.w3.org/2000/svg"
>
  <path
    fill="black"
    d="M 10,30
   A 20,20 0,0,1 50,30
   A 20,20 0,0,1 90,30
   Q 90,60 50,90
   Q 10,60 10,30 z"
  />
</svg>
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/138531/a1619db4-80fd-92aa-5ca0-1d61207135e7.png)

上記コードの動作サンプルは↓にあります。

https://cannot-fill-svg.glitch.me/

`path` 要素の `fill` 属性で塗り潰し色が指定されている SVG は、以下の CSS で色が変更できます。
（@nagtkk さんありがとうございます。）

```css
.pink > path {
  fill: pink;
}
```

ちなみに、筆者がこの問題にぶつかった時に開発していたのは Web ではなく React Native プロダクトであったため、上述のようなスタイリングは書けませんでした。（僕が書き方を知らないだけ...？）
なので、 `svg` 要素が `fill` 属性を持つように SVG ファイルの中身を編集して対応しました。

Figma などで画像を SVG 形式でエクスポートすると、 `svg` 要素ではなく `path` 要素の `fill` 属性が指定された状態で出力されることがあるようです。
WordPressのパーミッション設定 決定版

#はじめに
WordPressの構築時、SFTPで`ファイル転送ができない`ことや、`プラグインがインストールできない`などのエラーに遭遇したため、wordPressのパーミッション設定についてまとめます。

#前提条件
- wordpressのサーバーに対して、SFTPでファイル転送することがある。(ログインユーザは`ec2-user`)
- `/var/www/html/`配下にwordpressのディレクトリやファイルが置かれている
- nginxを使用。apacheでも問題なし。

#ファイル転送やプラグインインストール時、パーミッションが原因のエラー

###プラグインやwordpressバージョンをアップデートするときに、`FTP接続情報`を聞かれる
原因は、サーバであるapacheやnginxに対して、ディレクトリやファイル所有者権限が不足しているためです。
![スクリーンショット 2021-11-13 0.09.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/988747/88876f44-908d-6fc1-5ca7-7519f667463f.png)

###プラグインを更新するときに、`ディレクトリを作成できませんでした。`とエラーになる
こちらも同様に原因は、サーバであるapacheやnginxに対して、ディレクトリやファイル所有者権限が不足しているためです。
![スクリーンショット 2021-11-13 0.10.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/988747/7529521a-91cb-5ebb-af23-3eada27e6d7c.png)

###SFTPでファイル転送できない
原因は、転送先のディレクトリや上書きするファイルに対して、書き込み権限が足りていないためです。
![スクリーンショット 2021-11-13 0.21.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/988747/1ae676c2-5d18-4380-1d6c-dd98ac1131e3.png)

#結論

サーバーがnginx、SFTPのログインユーザーをec2-userとして、ファイルを転送する場合、以下のように設定します。

|ファイルやディレクトリ |権限|所有者:グループ|
|---|---|---|
| .htaccess | 606 | nginx:ec2-user|
| wp-config.php| 600 |nginx:ec2-user |
| ディレクトリ| 775 | nginx:ec2-user|
| ファイル| 664 |nginx:ec2-user |

以下のコマンドで所有者とグループ、権限を一括で変更できます。

```
$ sudo chown -R nginx:ec2-user /var/www/html


$ sudo find /var/www/html -type f -exec chmod 664 {} \;
$ sudo find /var/www/html -type d -exec chmod 775 {} \;
↑できない場合は↓
$ sudo find /var/www/html -type f -print | xargs chmod 664
$ sudo find /var/www/html -type d -print | xargs chmod 775
```
-execオプションを入れることで、findで検索した結果を使って別のコマンドを実行できます。
その時に、{}は検索結果とエイリアスとして働きます。

###セキュリティー面に不安の場合
もし、セキュリティーに不安がある場合、ファイル転送作業後は、権限を狭めるとよいと思います。

|ファイルやディレクトリ |権限|所有者:グループ|
|---|---|---|
| ディレクトリ| 705 | nginx:ec2-user|
| ファイル| 604 |nginx:ec2-user |

##パーミッションを修正してもFTP接続情報が聞かれる場合
wp-config.phpに追記します。

```php:wp-config.php
define('FS_METHOD', 'direct');
```
このとき、


```php
if ( !defined('ABSPATH') )
    define('ABSPATH', dirname(__FILE__) . '/');
require_once(ABSPATH . 'wp-settings.php');
```
よりも上に追記する必要があります。

#wordpressのパーミッションに問題ないかの確認方法
wordpress→ツール→サイトヘルスに遷移し、サイトヘルスが`「良好」`だと問題ありません。

![スクリーンショット 2021-11-12 13.33.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/988747/12a4f512-d8dc-1691-b75c-3e3a28adc945.png)


#参考

https://ja.wordpress.org/support/article/changing-file-permissions/

https://www.toumasu-program.net/entry/2019/10/12/105822

https://wp-master.club/about_permission

https://qiita.com/mizu0715/items/c901cc103a21c7eb62c1
採用DXサービスにおけるマルチクラウドアーキテクチャ戦略



X-Tech JAWSというAWSユーザグループの１つの勉強会に招待いただき、マルチクラウド戦略について発表してきました。

https://xtechjaws.doorkeeper.jp/events/127612
>X-Tech JAWSはAWSを利用している異業種企業間との交流の場であり、技術の学習、サービスの情報交換、サービス提携などのやりとりの場として活用される勉強会です。業界間の壁を超えた交流が行われることを期待しています。

<script async class="speakerdeck-embed" data-id="8b95b2990a824a518d3d6b4d4b1e7582" data-ratio="1.77777777777778" src="//speakerdeck.com/assets/embed.js"></script>

## サービス紹介
harutakaでは、エントリー動画と、Web面接サービスを提供しており、それぞれにAI機能を組み込んでいます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/222931/fc35481a-5836-a415-4169-9b0dabf81c08.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/222931/d988ce66-630a-313a-3bc7-46cd4818bd97.png)

アプリケーションやデータ分析はGCPに載っており、動画の保存や加工などにAWSというように使い分けています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/222931/2f132e29-c4b8-a607-9243-af7c737bd480.png)


具体的には各種サービスをパイプラインでつないでいって、動画アップロードから閲覧、解析まで運用しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/222931/4d4b023f-781e-51af-9331-ca2a870da677.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/222931/cc2b011c-7cc9-17e1-fb64-5fa838349240.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/222931/28822a91-e098-7311-9020-b67abb9dd670.png)



以下にもまとめていただきました。

[【開催レポート】X-Tech JAWS 【第14回】 ~新たな時代を創るハイパーカンパニーによるクラウド活用教室~](https://note.com/coosuke/n/nc4c715de86c8?fbclid=IwAR0xfch1o3_-HvAzzbRgjQ31gbvShO869qIiTyFRzG2qmflZKZYZKeer9YA)

https://togetter.com/li/1793702?fbclid=IwAR0pbjMU5ercEuvkzIz8KHapqrQ2qPmRxOD_NZP6JUe4tHxqlobxY1-BsHc

↑11000PVに達していました！

### 終わりに
一つのクラウドベンダに縛られず、柔軟な選択肢をとることが当たり前になってくるので、
さまざまなクラウドの情報をキャッチアップしていきたいものです。
【整理術】ブックマークが煩雑になってきたので整理してみた

#背景
ブックマークの保存が煩雑になってきたので、いつか整理したいと思ってました。
ツールの導入や他のアイデアでもっと良い整理術があるかもしれませんが現状思いついた整理法を記載します。
※他にいいやり方あればそこにシフトするかもしれません！

#自分の環境
OS：macOS(ver11.0.1)
ブラウザ：Chrome（バージョン: 95.0.4638.69（Official Build） （x86_64））
ブックマーク管理ツール導入：なし
※他のブラウザでも応用がきくかわかりません

#整理する上での考え
・可能な限りフォルダの使用は控える
　→階層が深くなるのを阻止
・カテゴリ分けして見つけやすくする
・検索で見つけやすくする

#作業
ここから下記は僕が具体的にやったことを記述していきます。

ブックマーク マネジャーを利用すると整理しやすいです。
ブラウザ右上の「︙」をクリックして下記画像をたどればブックマークマネジャーが開けるかと思います。
![スクリーンショット 2021-11-13 15.55.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1621592/b6c342cd-5b01-0351-c14a-e01bf67be470.png)

##よく利用するリンク
・フォルダに入れない（ブックマークバーに表示）
・リンク名は消しファビコンのみにする
![スクリーンショット 2021-11-13 15.37.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1621592/b3ed2ff6-aec4-d5ae-1be7-4d22ce90b938.png)

##フォルダで整理
| フォルダ名 | 内容 |
| ------------- | ------------- |
| LIFE | 日常生活で使うもの（通販サイト、天気予報など） |
| MAIL |メール関連 |
| SNS |SNS関連 |
| MOVIE |動画関連 |
| TiPS |ITなどの技術投稿サイト |
| FINANCE |金融系関連 |
| JOBS |仕事関連 |
| STUDY |学習・資格関連 |
| TMP | とりあえず格納 |
![スクリーンショット 2021-11-13 15.45.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1621592/a7381b51-5bbb-a109-74f0-fa5bdf31a3d8.png)

##リンク名で整理
・よけいな文字は削除
・可能な限り第二、第三階層のフォルダは作らずリンク名に役割も持たせる
　　→文頭にカテゴリを記載
・名前順に並べるといい感じにまとまる
名前![スクリーンショット 2021-11-13 15.58.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1621592/b7fd22a3-85b9-ac11-62ff-aa3f6b9407f9.png)

補足
名前順に並べ替えるにはブックマークマネジャーの「︙」をクリック
![スクリーンショット 2021-11-13 16.01.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1621592/1e875b1e-b9e3-7c1b-a70f-c72979d50663.png)

名前順をクリック
![スクリーンショット 2021-11-13 16.02.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1621592/13088b49-3649-326e-6a2e-6d4a2cad2e01.png)

ブックマークがごちゃごちゃしてきた方のお役に立てれば幸いです。
PHPの関数でreturnを使って値を返してみましょう！

#関数でreturnを返す
<br>
PHP関数の中でreturnを使って値を戻してみます！

こちらの関数があったとします。
<br>

```php:index.php
<?php
function sum($a, $b, $c) {
  echo $a + $b + $c;
}
sum(2, 3, 4);
```

<br>
ターミナルに以下を入力すると...
<br>

```
~$ php index.php
```
<br>
3つの値が計算されて出力されました！
<br>

```
~ $ php index.php
9~ $
```

<br>
returnで書き換えてみます
<br>

```php:index.php
<?php
function sum($a, $b, $c) {
  return $a + $b + $c;
}
echo sum(2, 3, 4);
```
<br>
もう一度以下のターミナルを実行します！
<br>

```
~$ php index.php
```

<br>
同じ結果になりました！
<br>

```
~ $ php main.php
9~ $ 
```
<br>
では、returnを使うと便利になる方法を見ていきましょう！

何個か値を合算したい時にreturnを使っていきます。
<br>

```php:index.php

<?php
function sum($a, $b, $c) {
  return $a + $b + $c;
}
echo sum(2, 3, 4) + sum(1, 2, 3) . PHP_EOL;

```

<br>
もう一度以下のターミナルを実行すると...
<br>

```
~$ php index.php
```
<br>
2つの計算が合算されました！
<br>

```
~ $ php index.php
15
~ $
```

<br>
return後の関数の中の処理だけ無視されるので注意しましょう　☆
<br>
DockerComposeでCentOS8+Nginxの開発環境を作る

最初に手動でDocker+CentOS8+Nginxの環境を構築し、その後で、同じ環境をDockerComposeで構築します。

# 前提
- Docker Desktop for Macがインストール済

# 環境
- macOS Big Sur
- Docker version 20.10.8
- docker-compose version 1.29.2

# 構築手順
## 手動でDocker+CentOS8+Nginxの環境を構築
#### CentOS８イメージを取得、コンテナを作成してバックグラウンドで起動
```
% docker run -it -d --privileged -p 8080:80 --name="centos8_nginx" centos:centos8 /sbin/init
```
　　
#### CentOS８のコンテナにログイン
```
% docker exec -it centos8_nginx /bin/bash
```
　　
#### CentOS８で初期設定とNginxのインストール、ドキュメントルートの変更
※以降は、ログイン後のCentOS8で作業　
##### 一応、バージョン確認
```
# cat /etc/redhat-release
CentOS Linux release 8.4.2105
```
##### パッケージを最新にする
```
# dnf -y update
 ```
##### ロケールの設定
```
# dnf -y install langpacks-ja && \cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
# LANG="ja_JP.UTF-8"
# LANGUAGE="ja_JP:ja"
# LC_ALL="ja_JP.UTF-8"
```
##### Nginxのインストール
```
# dnf -y install nginx
```
##### which、vimはよく使うのでインストールしておく
```
# dnf -y install which
# dnf -y install vim
```
##### よく使うaliasを設定
```
# echo 'alias ll="ls -l"' >> ~/.bashrc
# . ~/.bashrc
```
##### Nginxのドキュメントルートを`/home/html`に変更
ディレクトリ作成

```
# mkdir /home/html
```

以下のindex.htmlを作成する

```/home/html/index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>test</title>
</head>
<body>
<p>Hello World</p>
</body>
</html>
```

nginx.confのserverブロックのrootディレクティブのパスを`/home/html`に変更する

```/etc/nginx/nginx.conf
server {
    listen       80 default_server;
    listen       [::]:80 default_server;
    server_name  _;
    # root         /usr/share/nginx/html;
    root         /home/html;

```

##### Nginx起動
```
# systemctl start nginx
```

##### 確認
ホストOSのブラウザで`http://localhost:8080/`にアクセスし、index.htmlのページが表示されればOK。

##### コンテナから抜ける
```
# exit
```

##### コンテナ停止
```
% docker stop centos8-nginx
```
　　
手動での構築はここまで。

##### コンテナを削除する場合

```
% docker rm centos8-nginx
```
　　

## docker-composeで同じ環境を構築する
#### ディレクトリ構成
centos8_nginx/
　　　　　　├─ docker-compose.yml
　　　　　　├─ nginx/
　　　　　　│　　└─ Dockerfile
　　　　　　│　　└─ conf
　　　　　　│　　　　　└─ nginx.conf
　　　　　　└─ html/
　　　　　　　　　└─ index.html
#### 各ファイルの内容
`docker-compose.yml`

```
version: '3'
services:
    nginx:
        build:
            context: ./nginx
        ports:
            - 8080:80
        volumes:
            - ./html:/home/html
            - ./nginx/conf/nginx.conf:/etc/nginx/nginx.conf
```


`nginx/Dockerfile`

```
FROM centos:8

RUN dnf -y update
RUN dnf -y install langpacks-ja && cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime

ENV LANG="ja_JP.UTF-8" LANGUAGE="ja_JP:ja" LC_ALL="ja_JP.UTF-8"

RUN dnf -y install nginx
RUN dnf -y install which vim

RUN echo 'alias ll="ls -l"' >> ~/.bashrc

ENTRYPOINT /usr/sbin/nginx -g 'daemon off;' -c /etc/nginx/nginx.conf
```

`nginx/conf/nginx.conf`
手動で作ったCentOS8環境の時の/etc/nginx/nginx.conf をコピーする


`html/index.html`
手動で作ったCentOS8環境の時のhtml/index.htmlをコピーする


#### 起動
```
% docker-compose up -d
```

#### 確認
ホストOSのブラウザで`http://localhost:8080/`にアクセスし、index.htmlのページが表示されればOK。
お疲れ様でした。

この後で使いそうなコマンドも書いておきます。

#### コンテナ一覧表示
```
% docker-compose ps
```
#### コンテナに入る
```
% docker-compose exec nginx bash
```

#### 停止してコンテナとイメージ削除
```
% docker-compose down --rmi all
【JavaScript】部分和を動的計画法で解く


https://qiita.com/drken/items/a5e6fe22863b7992efdb

またまたこの続き．

# 問題
n個の正の整数 a[0],a[1],…,a[n−1]a[0],a[1],…,a[n−1] と正の整数 AA が与えられる。これらの整数から何個かの整数を選んで総和が AA になるようにすることが可能か判定せよ。可能ならば "YES" と出力し、不可能ならば "NO" と出力せよ。

【制約】
・1≤n≤1001≤n≤100
・1≤a[i]≤10001≤a[i]≤1000
・1≤A≤100001≤A≤10000

【数値例】
　n=3n=3
　a=(7,5,3)a=(7,5,3)
　A=10A=10
　答え: YES (7 と 3 を選べばよい)

# 実装
結果がわかりやすいように出力を少しだけオリジナルに整形してます．

```JavaScript:partialSum.js
const generate2DArray = (height, width) => {
    return [...Array(height)].map(() => Array(width).fill(0));
}

const partialSum = (numList, target) => {
    const dp = generate2DArray(numList.length + 1, target + 1); // 0行目・0列目を含む二次元配列を生成

    for (let col = 0; col < numList.length; col++) {
        for (let row = 0; row < target + 1; row++) {
            if (row >= numList[col]) {
                dp[col + 1][row] = Math.max(dp[col][row], dp[col][row - numList[col]] + numList[col])
            } else {
                dp[col + 1][row] = dp[col][row];
            }
        }
    }

    const result = dp[numList.length][target];
    return dp[numList.length][target] === target ? `YES:${result}` : `NO:${result}`;
}

const numList = [4, 6, 8];
console.log(partialSum(numList, 10)) // YES:10
```
Expoプロジェクトの新規作成

#Expoを使ってプロジェクトを新規に作成する

##Expoのインストール
```shell:cmd
> npm install -g expo-cli
```
##nodeのバージョンを確認する
nvsを使ってnodeを使用する場合はnodeのバージョンと一致させる必要がある。

```shell:cmd
>node --version
```
```shell:cmd
>nvs ls
```

##ディレクトリを移動する
```shell:cmd
> cd "任意のフォルダ"
```
##


## expoを初期化する
```shell:cmd
> expo init
```
nvsを使ってnode.jsを導入

#nvsとは？
nvs（Node Version Switcher）とはnode.jsを使用するにあたって複数のバージョンを管理することのできるツールである。こちらをインストールしておくことでバージョンによる競合を防ぐためのバージョン切り替えが容易にできる。
こちらの[Github](https://github.com/jasongin/nvs)からインストールすることが可能である。

##nvsのインストール方法

[Readme](https://github.com/jasongin/nvs/blob/master/README.md)に記載がある通りにインストールすることができる。ここではMacのインストール方法を説明する。※Gitをインストールしてある必要がある。

```shell:cmd
> export NVS_HOME="$HOME/.nvs"
> git clone https://github.com/jasongin/nvs "$NVS_HOME"
> . "$NVS_HOME/nvs.sh" install
```
###確認方法
以下のコマンドで確認することができる。バージョンが出てきたらOK。

```shell:cmd
> nvs --version
1.6.0
```
### node.jsバージョンの追加
v14.15.0をインストールする場合は以下のコマンドで。

``` shell:cmd
> nvs add 14.15.0
```
### node.jsバージョンの切り替え
```shell:cmd
> nvs use 14.15.0
```
Raspberryでsudo apt updateのエラーが出たときの対処法

Raspberryを再構築している時にエラーが出たのでその対処法のまとめ。
エラー内容

```bash
$ sudo apt update
ヒット:1 http://archive.raspberrypi.org/debian bullseye InRelease                                                
ヒット:2 http://raspbian.raspberrypi.org/raspbian bullseye InRelease                                             
パッケージリストを読み込んでいます... エラー!
E: Encountered a section with no Package: header
E: Problem with MergeList /var/lib/apt/lists/raspbian.raspberrypi.org_raspbian_dists_bullseye_main_binary-armhf_Packages
E: パッケージリストまたはステータスファイルを解釈またはオープンすることができません。
```

対処法

```bash
sudo rm /var/lib/apt/lists/* -vf
```
以上

あとは煮るなり焼くなり```sudo apt-get update```するだけ。
Netlifyでデプロイしてみた話

### そもそもNetlifyとはなにか？

Netlifyは静的サイトをホスティングサービスのうちの一つです。ホスティングサービスというのは、外部のサーバーを介して、自分のデータをweb上で公開できるサービスのことです。静的サイトホスティングサービスには、GithubPages、Netlify、Amazon S3、Vercelなどがあります。

ポートフォリオをデプロイする際、これまではGithub Pagesを使ってデプロイしていたが、思い切ってNetlifyを使ってデプロイしてみた話をご紹介します。これからフロントエンドのポートフォリオを作成して自分の作品を一般公開したいと考えている人はぜひご一読ください。

### Netlifyを選んだ理由

- 無料で使える
- ドメイン名をカスタムできる
- Githubと連携していて自動デプロイが可能

GithubPagesも無料で使えますが、ドメイン名に自由度がないのと、自動デプロイ機能がありません。この問題をNetlifyが解決してくれます。

### ドメイン名の設定

ドメイン名をカスタムできるというのは自分の好きな名前のURLで公開できるということであり、以下画像の設定で編集することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/997322/26199323-fc03-3de2-73cc-e850fcf60022.png)


### 自動デプロイ

これまでGithubPagesでデプロイしていたときは、自動デプロイの機能がなかったため、コミットをプッシュする度にローカルでビルドしないといけませんでした。しかし、Netlifyではビルドコマンドを設定できるため、ローカルでビルドしなくてもリモート上で自動的にビルドしてくれます。それによってプッシュ前に毎回ビルドコマンドを叩く手間が省けると同時にビルドし忘れてデプロイできていなかったというミスを未然に防ぐことができるようになりました。

**ビルドの設定**

以下のNetlifyの画像がビルドの設定画面です。設定箇所がいくつかありますが、赤枠の箇所のように設定すればうまくいきます。

+ **Build command**　　　ビルドするyarn(またはnpm)コマンドを入力
+ **publish directory**　 　ビルド後に生成されるビルドの対象となるフォルダを入力
+ **Builds**　　　　　　　 プッシュした時に自動的にビルドが走る設定
+ **Production branch**　 ビルドの対象となるブランチを設定

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/997322/b98685d6-ae18-e01c-4d86-5ab8dd5f4a84.png)

:::note warn
**自動デプロイ設定の際に気をつけるべきこと**
ローカル上のnodeバージョンが少し古い場合、Nelify上のnodeバージョンもそれに合わせる必要があります。
nodeのバージョンはNetlifyのGUIで設定できないため、プロジェクト内で.node-versionsファイルを設置し、その中でnodeバージョンを記載することでNetlify上のnodeバージョンを指定することができます。
:::
以下画像はローカル上とNetlify上のnodeのバージョンが異なってビルドが失敗した時
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/997322/fa5fd831-15bb-c9cc-07be-94bfdc50bd77.png)

### Tips
NetlifyにはGithub上からデプロイの監視ができるステータスバッジという便利機能もあります。以下の画像みたいにGithubのリポジトリ上にnetlifyのデプロイが成功していることを通知するバッジをつけることでnetlifyのデプロイがうまく行っているかをGithub上で確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/997322/618efd32-8edc-b28d-b118-405b1c42498d.png)

Netlify上でStatus badgeを選択すると、ステータスバッジのURLを取得でき、これをREADME上に貼ることで確認することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/997322/39d6de32-c27a-2805-2b92-cee27ce0f92a.png)
acme.shを使って無料でTLS(SSL)証明書を取得する

# 概要

[acme.sh](https://github.com/acmesh-official/acme.sh)を使うとLet's Encryptで簡単に証明書が取得できる。今回はローカル環境で証明書を発行してみる。

# インストール

emailの部分は適宜自分のものに変更する。

```bash
curl https://get.acme.sh | sh -s email=my@example.com
source ~/.zshrc
```

# アカウント発行

```zsh
acme.sh --register-account -m my@example.com
```

# 証明書発行

## ngrokのUIでドメインの設定を行う

ngrokで該当ドメインにきたトラフィックをローカルのマシンにトンネルする設定を作る。左のメニューの[Domains](https://dashboard.ngrok.com/endpoints/domains)から新規ドメインを追加する。

下記のような設定になるようにする。

![Screen Shot 2021-11-13 at 15.18.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7565/6a2a99fa-fb9b-b590-c915-ede4f78fa4fa.png)

## DNSのCNAMEを設定

ngrokで払い出された一時ドメイン(2abdgylzz.cname.jp.ngrok.io)を使っているDNSサーバでレコードを作成してCNAMEに割り当てる。

Route53であれば下記のようになる。

![Screen Shot 2021-11-13 at 15.21.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7565/3f2c24e2-f98f-94fe-0926-12e595b9010d.png)


## ngrokでポートフォワードを行う。

ngrokコマンドが入っていなければ`brew install ngrok`や、`yay ngrok`などとして使っているOSのパッケージマネジャを使ってインストールしておく。

次にngrokのトンネルを開始する。

```bash
ngrok http --region=jp --hostname=ドメイン名 8081
```

## ウェブサーバ

Let's encryptが通信してくるウェブサーバを起動する。

```bash
docker run -it \
	--rm \
	-d \
	-p 8081:80 \
	--name web \
	-v ~/適当なディレクトリ:/usr/share/nginx/html \
	nginx
```

## acme.shで証明書発行

```bash
acme.sh --issue -d ドメイン名 -w ~/適当なディレクトリ
```

`~/.acme.sh/ドメイン名`に証明書が作成される。
数は、取り扱い注意 ～JavaScriptの場合～

# 初めに
JavaScriptで数を扱うとき注意した方がよいなと思うポイントを書いていきたいと思います。
具体的には「小数点の取り扱い注意」「暗黙の型変換で取り扱い注意」の2つとなります。

# 小数点の取り扱い注意
JavaScriptの数値型は「IEEE 754 倍精度浮動小数点数」で64ビットの範囲内でどのように小数点を表現するか？ということを定めた規格です。我々は当たり前のように小数点を考えられますが、コンピュータは`0`か`1`かの情報しか持っておらずしかも限られた64ビットという範囲では正確に小数点を表すことができません。仮に`0.1`と数値に与えた場合でも実際には`0.1000000000000000055511151231257827021181583404541015625`として認識してしまいます。
そのため、小数点の計算をJavaScriptで行うと実際の値と異なる結果になることがあります。確認のために以下のようなコードを書いてみます。

```html:test.html
<html>
  <head></head>
  <body>
    <div id = "print"></div>
    <script type="text/javascript" src="test.js"></script>
  </body>
</html>
```

```javascript:test.js
function print_html(){
  var test1 = 0.1
  var test2 = 0.2
  var test3 = 0.3
  var test = test1 + test2 + test3
  document.getElementById("print").innerHTML = "<p>" + test +"</p>" 
}
print_html()
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/524088/ae59c75a-492a-0e1a-2fe1-6bada7a8094b.png)
答えはなんと`0.6`ではなく`0.6000000000000001`となります。
そのため、JavaScriptで計算を行うときは極力小数点を使わないようにする必要があります。

# 暗黙の型変換で取り扱い注意
JavaScriptでは暗黙の型変換が行われ特に数が関わる時には予想に反する型変換が行われる場合があります。
想定外の型変換が行われる例を紹介します。

## 1 + true は 2となる
先ほどの`test.js`を少し書き換えます。

```javascript:test.js
function print_html(){
  var test1 = 1
  var test2 = true
  var test = test1 + test2
  document.getElementById("print").innerHTML = "<p>" + test +"</p>" 
}
print_html()
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/524088/79fb953f-5c00-d9e0-8fcb-0b5ce48fa62a.png)
この時の出力結果は2となり数値とbooleanが普通に計算できる状態となります。

## 1 + "1" は11となる
先ほどの`test.js`をまたもや少し書き換えます。

```javascript:test.js
function print_html(){
  var test1 = 1
  var test2 = "1"
  var test = test1 + test2
  document.getElementById("print").innerHTML = "<p>" + test +"</p>" 
}
print_html()
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/524088/4fe98024-fc38-aeb1-2317-d574e41341ca.png)
この時の出力は11となり2にはなりません。
直感的に思った結果と実際の結果が違うのではまることもあるかなと思いました。

# おわりに
ある程度経験を積んでいるエンジニアであれば当たり前と思うような内容ではあるかもしれませんが、初心者にしてみればなんでこうなるんだとはまるケースもあるのかなと思いました。
この手のバグは知っているか知らないかで気づくことができるかが変わってくると思いますので、紹介することでこれらの仕組みが起因するバグをより多くの人が防止できればうれしいなと思います。
django ModelFormクラスのwidget属性の使い方

widget属性とは
-
djangoアプリにおいて、`Formクラス`, `ModelFormクラス`のフォーム部品の種類を規定する要素。

djangoフォームではフィールドを設定した時点でフォーム部品の種類が決まる（`CharField`であれば通常は`input type="text"`, `choicesオプション`があれば`select/option`、など）が、このwidget属性を指定することである程度はフォーム部品のコントロールが可能。

SelectDateWidget
-
`DateField`に設定することで、年月日選択のプルダウンを生成できる。

`DateTimeField`にも設定可能だが、その場合であっても年月日欄のみが表示され時刻選択はできなくなる。

```python
class ReservationForm(ModelFrom):
  class Meta:
  # 中略
  widgets = {
      "datetime": widgets.SelectDateWidget
    }
```

【widget設定前】
[![Image from Gyazo](https://i.gyazo.com/ef02b5cdae5e14f7152e8c6e6f5b526f.png)](https://gyazo.com/ef02b5cdae5e14f7152e8c6e6f5b526f)

【設定後】
[![Image from Gyazo](https://i.gyazo.com/e16c8d3036f028c1b67289f480f62324.png)](https://gyazo.com/e16c8d3036f028c1b67289f480f62324)

NumberInput(type="date")
-
HTMLの`input type="date"`と同じ形式のカレンダーを生成する。

`SelectDateWidget`と同じく、`DateTimeField`に対して使うと時刻が設定できなくなる。

```python
class ReservationForm(ModelFrom):
  class Meta:
  # 中略
  widgets = {
    "datetime": NumberInput(attr={
      "type": "date"
    }
  }
```
`NumberInput`に対して`attr`属性を指定しないとただのinput要素になる。

[![Image from Gyazo](https://i.gyazo.com/6047e5ef7038a54468dc5bb96674af47.png)](https://gyazo.com/6047e5ef7038a54468dc5bb96674af47)

SpliteDateTimeWidget
-
日付用と時刻用の二つのinput要素を生成する。

上が日付で下が時刻
[![Image from Gyazo](https://i.gyazo.com/a40d1502f33676edff20902d5ad9069e.png)](https://gyazo.com/a40d1502f33676edff20902d5ad9069e)

このウィジェットを使う場合には、フォームのフィールドを`SpliteDateTimeField`に設定する必要がある。

```python:forms.py
from django.forms import ModelForm, SplitDateTimeField, widgets
class ReservationForm(ModelForm):
  datetime = SpliteDateTimeField(label="予約日時")
  class Meta:
    fields = ["datetime"]
    widgets = {
      "datetime": widgets.SpliteDateTimeField
    }
```

上記の例だと日時を直接入力する必要がある。

`DateField`とは異なり`SelectDateWidgetP`や`NumberInput(type="date")`のような便利なwidgetは用意されていないので、`datepicker`や`timeDropper`などのjqueryプラグインを用いることになる。

https://qiita.com/keishi04hrikzira/items/cb486c6c2147d86d38ec

CheckboxSelectMultiple
-

複数選択可能なチェックボックスを生成する。

```python
from django.forms import ModelForm, CheckBoxSelectMultiple
class TeamForm(ModelForm):
  class Meta:
    fields = ["users"]
    widgets = {
      "users": CheckboxSelectMultiple
    }
```
enebularでarduino-iot-cloudノードを一通りためしてみる

# はじめに
Arduino IoT Cloudノードをenebular上から一通り触ってみて、ざっくりどのような挙動をするのかまとめてみました。

# arduino-iot-cloudノードをインストールする方法について
こちらを参照してください。
https://qiita.com/Inoue_Minoru/private/d03e764ac48e9038bb9a

# やってみたこと
enebular環境のNode-REDに[@arduino/node-red-contrib-arduino-iot-cloud](https://flows.nodered.org/node/@arduino/node-red-contrib-arduino-iot-cloud/in/x6nLBn2zSj93)をインストールし、下記のノードを一通り試してみた。

- propertyノード
- historicノード
- periodicノード
- injectノード

# 試す上での前提条件
- enebularなどのNode-RED環境にて[@arduino/node-red-contrib-arduino-iot-cloud](https://flows.nodered.org/node/@arduino/node-red-contrib-arduino-iot-cloud/in/x6nLBn2zSj93)をインストールしていること。
- **Arduino IoT Cloudにアカウントを持っており、かつEntry以上のプランに入っていること。(APIキー取得済みであること)**
- Device,Thing(Valiable)を既に作成しており、何かしらのセンサデータがマイコンから取得できること。

なお、ノード設定等でPropertyという表記が出てきますが、当記事ではValiable=Propertyとして読み進めて頂いても問題ございません。

## Propertyノード
まず受信ノードではNode-RED側で作成した値をArduino IoT Cloudのプロパティへ設定する場合に使います。逆に送信ノードではArduino IoT Cloud側の値をArduino IoT Cloudからポーリングする際に使います。
また、送信ノードの送信タイミングはValiable設定時のOn ChangeならびにOn Periodicallyの設定に基づきます。

<img width="500" alt="histric" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271381/b9439225-57b2-45d0-acab-54894bf12711.png">

<img width="500" alt="histric" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271381/83dcb7e4-9295-476a-f741-b9377801fcbe.png">

## historicノード
指定したpropertyに関して、指定期間に遡ってデータを取得できるノードです。
センサ値の状態遷移が必要な場合や、データのリアルタイム性を確保したい場合に良いかもしれません。

以下の場合は過去一時間に遡って取得したデータです。

<img width="500" alt="histric" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271381/b4f91254-8956-82b8-757c-b944bfd0b0c7.png">

<img width="500" alt="histric設定" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271381/1f8db435-c2a4-8665-e9af-94e238080fa0.png">

xの値は単位msのUNIX時間(UTC)で、データ取得時間が入っています。また、yの値には指定したPropertyの値が入っています。

## periodicノード
任意の実行期間でPropertyの値をポーリングしてくれます。添付写真では1秒ごとに自動でpropertyの値を取得するようになっています。
部屋の室温管理など、リアルタイム性の薄いデータ取得に向いていそうです。

<img width="500" alt="periodic" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271381/525645b2-36b5-3d3a-b663-2d2405125d5c.png">

<img width="500" alt="periodic設定" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271381/b2f8c68b-1257-fd57-24ca-f246e74a5ae8.png">


## injectノードについて

何かしらのペイロードが入力されたときにセンサ値を出力します。
AlexaのようなVUIからセンサ値を参照するような、特定のイベントのときにデータを取得したい場合に良いと思います。

<img width="500" alt="inject" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271381/17f3375d-0023-98da-849f-2627cbee7c21.png">

<img width="500" alt="inject" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271381/9ac0dbfc-0672-93e2-1c1f-111a956daf39.png">

# まとめ

arduino-iot-cloudノードに関して下記のノードを試した。

- propertyノード
- historicノード
- periodicノード
- injectノード

単にpropertyから値を取得したり、逆に値を設定する場合であればpropertyノードで事は足りそうだけど、historicノードなどの下３つのノードを使えばよりシンプルにフローを構成できるかと思います。

誰かの役に立ってくれれば嬉しいです！
URLのパスに紐づくjsonデータを返すテストサーバー(wsl+docker+FastAPI)

# はじめに
Restの動作確認をするときにとりあえずテストファイルのjsonデータを返してくれるdockerの上に乗ったFastAPIサーバーを作っています
※testdataのフォルダ以下にtest.json があれば `http://***/testdata/test` にリクエストすればtest.jsonのデータが返ってくるような仕組み

# 環境
Windows10 + WSL(Ubuntu 20.04.3 LTS)

```shell
$ cat /etc/os-release
NAME="Ubuntu"
VERSION="20.04.3 LTS (Focal Fossa)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 20.04.3 LTS"
VERSION_ID="20.04"
・・・
```

docker 20.10.10

```
$ docker -v
Docker version 20.10.10, build b485636
```


# フォルダ構成
```
fastapi
 ├ Dockerfile
 └ app
   ├ main.py
   └ testdata
     ├ temp.json
     └ ...
```
※確認時は`/home/user名` にdockerフォルダを作ってその中にfastapiを展開

## 変更
テストサーバーなので、接続フリーな設定を追加しました

## ファイル
書くのが面倒な方は、[こちら](https://github.com/naozo-se/Docker-FastAPI-Test) からダウンロード

```Dockerfile:Dockerfile
# 3.6以降なら大丈夫みたい
FROM python:3.9-slim-buster

# pipのupgrade (Warning出るけど、お気になさらずに...)
RUN pip install -U pip

# fastapiとuvicornのインストール
RUN pip install fastapi uvicorn

# ポートはデフォルトの8000で利用
EXPOSE 8000

# デフォルトのディレクトリ設定
WORKDIR /app

# サーバー起動
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
```

```python:main.py
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
import json
import uvicorn
import os

app = FastAPI()
# テストサーバーなので、アクセスオールフリー
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

jsonExtention = ".json"


@app.api_route("/{path:path}", methods=["GET", "POST"])
async def catch_all(path: str):

    # カレントまでの絶対パス取得
    absPath = os.path.abspath(".")
    jsonFilePath = f"{absPath}{os.sep}{path}"

    # jsonの拡張子付きではない時
    if os.path.splitext(jsonFilePath)[1] != jsonExtention:
        jsonFilePath = f"{jsonFilePath}{jsonExtention}"

    # ファイルが存在するか
    if os.path.exists(jsonFilePath):
        jsn = None
        with open(jsonFilePath, "r", encoding="utf-8") as f:
            jsn = json.load(f)
        return jsn

    # ファイルがない時
    return {"message": "error"}
```


```json:temp.json
{ "test": "テスト" }
```
※こちらはファイル名や内容についてはお好みで

## コンテナ構築シェル

```shell
# dockerファイルのイメージビルド
sudo docker build -t fatestimage .
# コンテナ化(-v appのフォルダ共有、-p 8000ポート使用)
sudo docker run -d --name fatest -v $PWD/app:/app -p 8000:8000 fatestimage
```
※上記フォルダ構成の fastapi 以下で実行


## 動作確認
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/541739/a8b50284-bd79-f0e1-d168-bf111d063fc5.png)

## 運用アドバイス
`\\wsl$` でエクスプローラーからwslにアクセス可能。あとはフォルダとjsonファイルを勝手に作ってアクセス先を増やしたりすればよいかと


# 最後に
なにも設定してないEdgeが、確認画面をペーストするときに便利なことに気づきました
Ray-Tracingに向けた Importance Sampling

こんにちは。以前の記事で球面上で一様な乱数を生成するための方法を紹介しました。Ray-Taracingにおいて、これでは不十分なことが多いのでHemispherical Importance Sampling Monte Carlo Methodを紹介します。こちらの記事と照らし合わせながら導出します。（https://qiita.com/KionIm/items/08589a22c2daa5490f8b）

#目次
[1.Hemispherical Importance Sampling Monte Carlo Method](#1-Hemispherical Importance Sampling Monte Carlo Method)
[2.Cosine-Weighted Hemisphere Sampling](#2-Cosine-Weighted Hemisphere Sampling)
[3.おわりに](#3-おわりに)

#1. Hemispherical Importance Sampling Monte Carlo Method

<img width="500" alt="IMG_0078.jpg" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2277765/37c5af4b-fc53-440a-f58e-7a59fa79ec0e.jpeg">

図にあるように、ある点$x$の色はオブジェクトの色と周囲からの光の影響から成る。しかし、青線で描いた半球に入射する光が$x$の色に対して全て等しい重みで寄与していると考えると、水平線付近からの寄与が不自然に大きくなってしまう。そのため、天頂付近からの寄与が大きくなるように新たなMonte Carlo法を考える。これがHemispherical Importance Sampling Monte Carlo Methodである。

#2. Cosine-Weighted Hemisphere Sampling

半球面上で一様に生成された乱数が全て等しい重みを持っているとは$p(\omega) = 1/2\pi$であるということだ。同じように、天頂に近いほど重みを大きくするには$~p(\omega) \propto \cos \theta $ のような分布の確率密度を与えればよい。

```math
\begin{align}
\int_{\mathcal{H}_2} p(\omega) d\omega 
&= \int^{2\pi}_0 \int^{\frac{\pi}{2}}_0 c~\cos\theta \sin\theta d\theta d\phi \\
&= 2\pi c\int^{\frac{\pi}{2}}_0 \cos\theta \sin\theta d\theta \\
&= \pi c = 1
\end{align}
```
このことと、参考先の(3)を用いると、

```math
c = \frac{1}{\pi}~,~~~p(\omega)=\frac{1}{\pi}\cos \theta~,~~~p(\theta,\phi) = \frac{1}{\pi} \cos \theta \sin\theta
```
となる。次は、確率密度関数を変数ごとに分離します。

```math
p(\theta) = \int^{2\pi}_0 p(\theta, \phi) d\phi = \int^{2\pi}_0 \frac{1}{\pi} \cos\theta \sin \theta d\phi = 2\sin \theta \cos \theta 
```
```math
p(\phi) = p(\phi|\theta) = \frac{p(\theta,\phi)}{p(\theta)} = \frac{1}{2\pi}
```
次は、累積密度関数を計算する手順となるが、経度方向は一様乱数分布なので緯度方向$~p(\theta)~$のみを考える。

```math
P(\theta) = \int^{\theta}_0 p(\theta') d\theta' = \sin^2 \theta 
```
$u = P(\theta)$とすると、

```math
u = \sin^2 \theta~,~~v = \frac{\phi}{2\pi} 
```

一様乱数(0,1)に従う($u,v$)を与えることで、確率密度に従った($\theta,\phi$)が生成される。ここで生成される($\theta,\phi$)は天頂付近にサンプルが集中しており、以下のようにMonte-Carlo法を計算することで、球面上で一様なサンプルを取得するよりも少ないサンプル数で現実に近い結果(irradiance)が得られる。

```math
\left< F^N\right> = \frac{1}{N} \sum^{N-1}_{i=0} \frac{f(\theta,\phi)}{p(\omega)} 
```

#3. おわりに
今回は理論のみの紹介だが、今後は実装についても紹介していきたい。
TypeScriptの基本（初級）

最近流行りのTypeScriptがずっと気になっていたので最初は遊んで実務レベルまで持って行きたい。

## 型について
もし型を指定しない場合は、型推論で勝手に決めてくれる、それをやっていいかは別。

```typescript
// 真偽値
let bool: boolean = true;
// 数値
let num: number = 0;
// 文字
let str: string = "A";
// 配列
let arr: Array<number> = [0, 1, 2];
// 配列で複数の方を使いたい時はパイプで繋いで上げる(=共用型と言う)
var word: (string | number)[] = ['a', 'b', 1];
// tuple
let tuple: [number, string] = [0, "A"];
// any すべてのデータ型OK！
let any1: any = false;
// void 返却値なし
const funcA = (): void => {
  const test = "TEST";
};
// null
let null1: null = null;
// undefined
let undefined1: undefined = undefined;
// object
let obj1: object = {};
// enum型　定数を列挙する型
enum code {
  space = 8,
  tab = 9,
}
console.log(code.space);
// 値を入れない場合は勝手にインデックスがふられる
enum chara {
  bob,
  anri,
  tanaka,
}
console.log(chara.bob) // 0
console.log(chara.anri) // 1

```

## アクセサメソッド
プロパティ名と同じアクセサメソッドは定義できない

```javascript

class Animal {
  private _legs = 4;

  // アクセサメソッド(getter,setter)
  get legs() {
    return this._legs;
  }

  set legs(value: number) {
    this._legs = value; 
  }
}
```

## ジェネリック
クラスの外側からクラス内部の型指定ができる

```typescript

// ジェネリック
class num {
  data: number;
}

class str {
  data: string;
}

// いくつもクラスを作らずにインスタンス化したタイミングで型を決めてあげる
class Stotre<T> {
  data: T;
}

let data = new Stotre<string>();

// 複数指定も可能
class Component<T, U> {
  name: T;
  id: U;
}

```
Git初心者メモ ①


#### このメモは？
以前から気になっていたGitを一からセットアップして、導入方法をメモしていきたいと思います。
「Git何それおいしいの？」レベルの無知に限りなく近い人がまったりとGit使うまでのメモとして、ここに記録していきたいと思います。

#### 目標
PythonやC#のコードをGitLabを使ってバージョン管理する。
※この時点ではGitLabを知らないので上記の日本語が正しいかどうかすらわからない。

---

#### まず、GitLab登録
以下のURLにアクセスしてGitLabに登録。
https://github.com/

サクサクと登録を終えるとクイックスタート。
https://docs.github.com/en/get-started/quickstart/hello-world
マニュアルで「hello-world」リポジトリを作成してこれをコミットしたりマージしたりする。

え、なんか僕の知ってるコミットと違う。。
なんか、コミットして完了ちゃうねん。

マジ、__プル__とか、__マージ__とか何なん？？
（マージはなんとなく分かるけど、プルのせいで巻き添え）

言葉を知るには意味から。

> ●名詞
プル　pull
牽引　tow, pull, drag, hauling
伝手　intermediary, introducer, influence, connection, connexion, pull
引っ張ること　pull
●動詞
引っ張る　pull, drag, draw, stretch
引く　play, draw, pull, subtract, tug
引っぱる　pull, drag, draw, stretch

なるほど、ならプルリクエストって、「これを引っ張って！」って意味か！
私を甲子園に連れてって、的なことなんか！（違う


続く
PythonでExcel操作：特定文字の行数・列数取得

#### Excelシート内の特定文字の行数・列数を取得しよう
- 業務上、Excelシート内の行数や列数が追加・削除されることが割と頻繁にある。
- PythonでExcelを読み込む際にその都度、行数や列数を指定し直さないといけない。

#### 方針
特定の文字を検索取得して、その文字のセル番地、つまり行数・列数を取得する。
・・・もちろん、その特定の文字がシートから抹消されることがあればこれも意味なくなるので、重要な文字をターゲットにしてくださいね！！！

#### 開発環境
　Jupyter lab
　Python3.9.6
　Windows
#### 実施内容
題材として「経産省の統計資料」を抜粋し、Excelに一部を転記。
今回は事例として<font color="red">国内用</font>という文字の行数と列数を取得する例を紹介する。
**「国内用」のセル番地：(M10), (10行,13列)** を取得してくる。
以下、黄色塗りつぶし箇所。

以下イメージ写真
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1980655/04e018c3-9616-fae8-117a-9748b072f98c.png)

```python:特定文字の行数・列数取得
#必要ライブラリのインポート
import openpyxl 
# openpyxlを使ってエクセルファイルを開く
workbook = openpyxl.load_workbook("~~ファイルを指定してください~~")
# シートを取得,シート名はSheet1
ws = workbook["Sheet1"]
# target_valueが一致するセルの座標を検索
# 100行100列の中に探したい文字列があるとして設定
for r in ws.iter_rows(max_row=100, max_col=100):
# 列を一つずつ探索
    for c in r:
    # もしc.valueがtarget_valueと一致したらその行番号を返す
        if c.value == "国内用":
             #セル番地を指定する:M10
            cell_nloc=c.coordinate
             #行数のみcell_nloc[1]を取得に格納
            cell_row_n=openpyxl.utils.cell.coordinate_from_string(cell_nloc)[1]
　　　　　　 #列数のみをcell_nloc[0]取得し、アルファベットから数字にする
            cell_col_m=openpyxl.utils.column_index_from_string(cell_nloc[0])
            
print("セル番地："+ cell_nloc)
print("セル行番号："+ str(cell_row_n))
print("セル列番号："+ str(cell_col_m))
```
---output---
セル番地：M10
セル行番号：10
セル列番号：13

#### 解説
1. cordinateで特定文字のセル番地をM10のようにアルファベット＋数値で取ってくる。
2. openpyxl.utils.cell.coordinate_from_stringでM10をタプル形式で("M", 10)として列と行を別々に取り出せるようにする。
3. openpyxl.utils.column_index_from_stringで列名アルファベット:Mを列番号:13に変換する。