OmniAICreator/Qiita-1.07M huggingface dataset:
PythonでExcelファイルを読み込む

## 使用するExcelファイル

以下の内容でtest.xlsファイルを作成します。

Sheet1:
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260307/19ca8934-0992-4655-95e3-a1ec5551735b.png)

Sheet2:
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260307/47e1f7a1-c1df-e639-e4ed-a1a0834c289c.png)

## PythonでExcelを読み込む

以下pandasを使用してExcelファイルを読み込みます。(ExcelFileではxlsxファイルは現時点サポートされません。)
シート名を取得します。

```python
import pandas as pd

xls_data = pd.ExcelFile('test.xls')
print(xls_data.sheet_names)
```

出力：

```text
['Sheet1', 'Sheet2']
```

各シートの内容を読み込みます。インデックスもしくはシート名で対象シートを指定します。

```python
df1 = xls_data.parse(0)
print(df1.head())

df2 = xls_data.parse('Sheet2')
print(df2.head())
```

出力：

```text
   col1    col2    col3
0     1  value1  value1
1     2  value2  value2
2     3  value3  value3
   列1  列2
0   1  値1
1   2  値2
2   3  値3
```

## 読込みオプション

以下のようにオプションを使用しての読込みも可能です。

```python
# 1行目スキップ、カラム名のリネーム
df1 = xls_data.parse(0, skiprows=[0], names=['Index','Value01', 'Value02'])
print(df1.head())

# 1列目指定、1行目スキップ、カラム名のリネーム
df2 = xls_data.parse('Sheet2', usecols=[0], skiprows=[0], names=['インデックス'])
print(df2.head())
```

出力：

```text
   Index Value01 Value02
0      2  value2  value2
1      3  value3  value3
   インデックス
0       2
1       3
```
「03.Scala で解く素因数分解　Scala基礎コース」を参考にWolframAlphaとSymPy Liveでやってみた。

# original link

https://qiita.com/glaciermelt00/items/86a4470d6d914add86dc#実習素因数分解の動作を確認する

＞【実習】素因数分解の動作を確認する

# WolframAlphaで
？？？もっと簡単になる方法を教えて下さい。

https://www.wolframalpha.com/input/?i=24%E3%81%AE%E7%B4%A0%E5%9B%A0%E6%95%B0%E5%88%86%E8%A7%A3%2C32%E3%81%AE%E7%B4%A0%E5%9B%A0%E6%95%B0%E5%88%86%E8%A7%A3%2C56%E3%81%AE%E7%B4%A0%E5%9B%A0%E6%95%B0%E5%88%86%E8%A7%A3%2C90%E3%81%AE%E7%B4%A0%E5%9B%A0%E6%95%B0%E5%88%86%E8%A7%A3%2C510510%E3%81%AE%E7%B4%A0%E5%9B%A0%E6%95%B0%E5%88%86%E8%A7%A3&lang=ja

{2^3×3, 2^5, 2^3×7, 2×3^2×5, 2×3×5×7×11×13×17}


https://www.wolframalpha.com/input/?i=24%E3%81%AE%E5%9B%A0%E6%95%B0%E5%88%86%E8%A7%A3%2C32%E3%81%AE%E5%9B%A0%E6%95%B0%E5%88%86%E8%A7%A3%2C56%E3%81%AE%E5%9B%A0%E6%95%B0%E5%88%86%E8%A7%A3%2C90%E3%81%AE%E5%9B%A0%E6%95%B0%E5%88%86%E8%A7%A3%2C510510%E3%81%AE%E5%9B%A0%E6%95%B0%E5%88%86%E8%A7%A3&lang=ja

{2^3×3, 2^5, 2^3×7, 2×3^2×5, 2×3×5×7×11×13×17}


# WolframAlphaで(調子悪いです)

https://www.wolframalpha.com/input/?i=factoring%2824%29%2Cfactoring%2832%29%2Cfactoring%2856%29%2Cfactoring%2890%29%2Cfactoring%28510510%29&lang=ja

結果
510510 2^5 (2^3×3) (2^3×7) (2×3^2×5)

https://www.wolframalpha.com/input/?i=factoring%28510510%29&lang=ja

結果
2×3×5×7×11×13×17 (異なる素因数7個)


#SymPy Liveで
以下のソースコードを貼り付けて、Evaluateです。

https://live.sympy.org/

```python
from sympy import *
print("#",factorint(24),factorint(32),factorint(56),factorint(90),factorint(510510))
# {2: 3, 3: 1} {2: 5} {2: 3, 7: 1} {2: 1, 3: 2, 5: 1} {2: 1, 3: 1, 5: 1, 7: 1, 11: 1, 13: 1, 17: 1}
# ('#', {2: 3, 3: 1}, {2: 5}, {2: 3, 7: 1}, {2: 1, 3: 2, 5: 1}, {2: 1, 3: 1, 5: 1, 7: 1, 11: 1, 13: 1, 17: 1}
```
AtCoderログ：0036 - ABC 211 A

# 問題

https://atcoder.jp/contests/abc211/tasks/abc211_a

## 問題文
> 収縮期血圧 $A$ と拡張期血圧 $B$ が与えられます。
> 平均血圧 $C$ を求めてください。
> ただし、平均血圧は以下のように定義されるとします。
> ・$C=\frac{A-B}{3}+B$

## 制約
> ・$50 \le B \le A le 300$
> ・入力に含まれる値は全て整数である

# 回答
## 回答1 (AC)
問題文通りに計算すれば良いでしょう。ただし計算結果は小数になることがあるので、コーディングに注意が必要です。今回の場合、単に (a-b)/3 とかくと計算結果は整数になってしまうので、(a-b)/3.0 または (float)(a-b)/3 とかく必要があります。コードは以下のようになりました。

```C++:abc211a-1.cpp
#include <bits/stdc++.h>
using namespace std;
 
int main() {
  int a, b;
  cin >> a >> b;
 
  float c = (float)((a-b)/3+b);
 
  cout << c << endl;
}
```

## おまけ
問題文に記述されていた平均血圧の計算法を調べたところ、実際の計算式を利用していたことがわかりました。ここで気になるのは、平均血圧というなのに、(a+b)/2 という計算式ではないところです。これについても調べてみたところ、[最高血圧時の血量は少なく最低血圧時の血量は多いので、それを加味して3で割っている](https://kango-oshigoto.jp/hatenurse/article/1809/)とのことでした。

# 調べたこと
## [AtCoder の解説](https://atcoder.jp/contests/abc211/tasks/abc211_a/editorial) → [公式解説](https://atcoder.jp/contests/abc211/editorial/2285)
回答1と同じ方針でした。

# リンク
## 前後の記事
- 前の記事 → [AtCoderログ：0035 - ABC 087 B](https://qiita.com/RoadLynton/items/338e306e579fb345969d)
- 次の記事 → [AtCoderログ：0037 - ABC 105 B](https://qiita.com/RoadLynton/items/3fba438c4a744b0ced0c)
RFID とは

## 勉強前イメージ

ユニクロとかGUであるイメージ

## 調査

### RFID とは

Radio Frequency Identification の略で、
近距離の無線通信を用いてデータを記録した専用タグを非接触で情報をやり取りする技術です。

### RFIDのメリデメ

- メリット
	- 離れた場所からでも読み取れる
	- 箱の外からでも読める
	- 複数のRFIDタグを一括に読み取れる
- デメリット
	- RFIDタグやリーダーなど、コストが高くなります。
	- 金属の近くに置いたりすると精度が落ち、正しく通信が行われないことがあります。

### RFIDタグとは

RFIDタグとは
ICチップと接続したアンテナで構成されており、
ICタグやRFタグとも呼ばれます。
RFIDタグ・ICタグ・RFタグは大体同義で使用されていることが多いです。(厳密には違うかも....)

### タグの分類

#### バッテリーによる分類

- パッシブタグ

RFIDリーダーをエネルギー源として動作します。
通信距離は短いですが、安価

- アクティブタグ

電池を内蔵したタグで、通信距離は長いですが高価で電源の管理が必要になる

- セミパッシブタグ

パッシブタグとアクティブタグの両方の特徴と持っているタグで、
通常はパッシブタグのように稼働しているが、
リーダーから通信があればアクティブタグのように電池を使用して通信を行います。

#### 周波数による分類

- LF帯
	- 周波数 : 135KHzまで
	- 通信範囲 : 10cmまで
	- ユースケース : スマートキー等

- HF帯
	- 周波数 : 13.56MHz
	- 通信範囲 : 30cmまで
	- ユースケース : 交通系ICカード

- UHF帯
	- 周波数 : 860～960MHz
	- 通信範囲 : 20mまで
	- ユースケース : アパレルのタグ等

- マイクロ波帯
	- 周波数 : 2.45GHz
	- 通信範囲 : 3mまで
	- ユースケース : 旧周波数帯

## 勉強後イメージ

ユニクロとかGUとかのやつはNFCタグかな？
電池が内蔵されているやつもタグって言うのね。
NFCって障害物に強いってどっかに書いてあった。
知らなかったけど、ICOCAとかスマホのカバーとかにつけてる人もいるから強いんだね。

## 参考

- [RFIDとは？｜基本の【き】](https://imagers.co.jp/contents/102/)
- [RFIDとは？その意味や仕組み、特徴などをわかりやすく解説！](https://it-trend.jp/physical_distribution_management/article/83-0018)
- [ICタグ・RFタグの基礎知識](https://rfid.tss21.co.jp/knowledge/whatsrfid/basic_tag.html)
Buttonを押すとSegmentが減る(UISegmentedControl)

# 今回の内容
[Buttonを押すとSegmentが増える(UISegmentedControl)](https://qiita.com/HiroUrata/items/92345fe16e03390224a3)の続きになります。

# 機能説明
* Buttonを押すと、`UISegmentedControl`のSegmentが減る。

# コードと簡単解説

* Segmentを削除するときは、右側から削除していきたいので現在のsegmentCountとsegmentContentsArrayの最大値が同じなら、`.removeSegment(at: segmentCount, animated: true)` で一番右のSegmentを削除します。

* `.segmentContentsArray.remove(at: segmentCount)`の後に`segmentCount -= 1`をすることで、segmentContentsArrayの最大値とsegmentCountを同じにしておかないと、次にSegmentを増やす時に見た目がおかしくなります。

* Segmentを削除するときも、増やす時と同様にframeのwidthを引いています。

```Swift:ViewController
 @IBAction func minusSegment(_ sender: Any) {
        
        if segmentControl.segmentContentsArray[segmentCount] == String(segmentCount){
            
            segmentControl.uiSegmentControl.removeSegment(at: segmentCount, animated: true)
            
            segmentControl.segmentContentsArray.remove(at: segmentCount)
            
            segmentCount -= 1
                        
            segmentControl.uiSegmentControl.frame = CGRect(x: segmentControl.uiSegmentControl.bounds.minX, y: segmentControl.uiSegmentControl.bounds.minY + 100, width: segmentControl.uiSegmentControl.frame.width - 35, height: segmentControl.uiSegmentControl.frame.size.height)
        }
        
    }
```

# 終わり
昨日のUISegmentedControlを増やすだけのアプリに減らす機能を作りました。
ご指摘、ご質問などありましたら、コメントまでお願い致します。
[Ruby]layoutsファイルと７つのアクション

# はじめに
本記事は、本日私が理解できていなかった
「layouts」ファイルの中身について書きました。
今回は、これに何時間もかかりましたので、備忘録として投稿します。

#　layoutsファイルには
具体例

```erb
<!DOCTYPE html>
<html>
  <head>
    省略
  </head>
  <body>
    <header class="header">
      <div class="inner">
        <div class="nav">
          <div class="nav__left">
            <%= link_to image_tag("logo.png", class: :logo), root_path %>
          </div>
          <% if user_signed_in? %>
            <div class="nav__right">
              <%= link_to "ログアウト", destroy_user_session_path, method: delete, class: :nav__logout %>
              <%= link_to "New Proto", root_path, class: :nav__btn %>
            </div>
          <% else %>
            <div class="nav__right">
              <%= link_to "ログイン", new_user_session_path, class: :nav__btn %>
              <%= link_to "新規登録", new_user_registration_path, class: :nav__btn %>
            </div>
          <% end %>
        </div>
      </div>
    </header>
    <%= yield %>
    <footer class="footer">
      <p class="copyright">Copyright © ~~~ All rights reserved.</p>
    </footer>
  </body>
</html>
```

このように、

```html
<html>
  <head></head>
  <body>
    <header></header>
    <footer></footer>
  </body>
</html>
```

という記述になるファイルになります。
つまり、ブラウザ上に表示されるものに直結すると考えても良いと思います。

# 勘違いしていたこと
当時、私は、「新規登録ボタン」から`ユーザー登録`ができるようコードを書いておりましたが、
一向に新規登録画面に遷移することはありませんでした。

理由としては、
createアクションで、`app>views>registrations>new`のファイルにユーザーが情報登録するためのURLをコードに記述しただけだったためです。


```erb
<div class="main">
  <div class="inner">
    <div class="form__wrapper">
      <h2 class="page-heading">ユーザー新規登録</h2>
        <%= form_with model: @user, url: user_registration_path, local: true do |f| %>

        省略
     
    </div>
  </div>
</div>
```


# 原因
完全に理解していたと思われた
`７つのアクションの役割`を正確に理解していなかったことから、
このようなミスに繋がったと考えます。

###改善策
・再度、７つのアクションについての役割を分析する。
・今後もこのようなことが起きないように注意する。
・注意の方法として、７つのアクションそれぞれに関連深いものも確認しておく。

この３つに焦点を当てて、復習します。

# 終わりに
初心者がまず失敗してしまうミスという感じがします。

ここからは理解したことをさらに深く、
知識の肉付けをどんどん実施していきたいと思いました。

以上です。
引き続き頑張ります！
[TypeScript] ReturnTypeで関数の戻り値の型を取得する。

Formikの型を付けたかったのですが、
useFormikの戻り値の型が見当たらなかったので、
関数の戻り値から型をつけるようにしました。

ReturnTypeを使ってこんな感じで取得できます。

```ts
ReturnType<typeof useFormik>
```

公式だと以下のページに記載がありました。

[TypeScript | Utility Types](https://www.typescriptlang.org/docs/handbook/utility-types.html#returntypetype)

Utility Typesには他にも便利そうな型が多いですね。どんどん使っていきたいです。
【AWS】セキュリティグループとネットワークACL

# ネットワークサービス

## アクセス制御

### ◉セキュリティグループとネットワークACL
インバウンド通信とアウトバウンド通信を設定するファイアウォール機能

| 項目 | セキュリティグループ | ネットワークACL |
|:-:|:-:|:-:|
| 適用範囲 | インスタンス単位 | サブネット単位 |
| デフォルトの動作 | インバウンド：全拒否　アウトバウンド：全許可  |  インバウンド：全許可　アウトバウンド：全許可 |
| ルールの評価 | 全てのルールに適用 | ルールの番号順で適用 |
| ステータス | ステートフル | ステートレス |

#### ◎セキュリティグループ
**特徴**

- インバウンド／アウトバウンドの種別／プロトコル／ポート範囲／アクセス元／アクセス先IPなどの**ルールのみ定義する**
- EC2インスタンスに**複数のセキュリティグループの適用が可能**
- セキュリティグループの設定追加／変更は**即時反映**

:::note info
ステートフルな制御
ルールで許可された通信の戻りの通信も自動的に許可される
:::

#### ◎ネットワークACL
**特徴**

- VPC内に構成した**サブネットごとに一つのネットワークACLを設定可能**
- VPC作成時に**デフォルトのネットワークACL**が準備されている
- 新規にネットワークACL（カスタムネットワークACL）を作成できるが、その時の初期設定は**全てのトラフィックを拒否**
- 異なるサブネット間の通信の許可または拒否を明示した制御が可能

:::note info
ステートレスな制御
アウトバウンドとインバウンド通信それぞれに対する通信制御の設定が必要
:::

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

#### 参考
https://milestone-of-se.nesuke.com/sv-advanced/aws/network-acl-and-security-group/

https://docs.aws.amazon.com/ja_jp/vpc/latest/userguide/VPC_Security.html#VPC_Security_Comparison
環境変数の設定方法をVimコマンド無知の状態でもできるようにまとめた

環境変数の設定方法は、すでに多くの方が記事にまとめてくださっているので、今さら私が記事にする必要もないかと思います。
しかし、Vimモードのコマンドをまったく知らなかった私には、「もう少し詳しく解説してくれると助かるな」と思ったので今回まとめることにしました。(まぁ調べれば済む話なのですが…)


おそらくそのように感じる人も多いと思うので、きっとこの記事が役に立つはずです。
**この記事を読むことで、スムーズに環境変数を設定できるようになるでしょう。**

※この記事はMacを想定しています。

##目次
* 環境変数とは
* なぜ環境変数を設定する必要があるのか
* 環境変数の設定方法
* 環境変数の呼び出し
* まとめ

##環境変数とは
> **環境変数とは、パソコンが持っている値を入れておく変数です。**
OSが動いているときに使える変数です。
公開したくないデータを環境変数として定義しておき、プログラムからデータを参照することで必要に応じて利用することが可能となります。
*引用：[「分かりそう」で「分からない」でも「分かった」気になれるIT用語辞典](https://wa3.i-3-i.info/word11027.html)*
*[【Ruby】ENVオブジェクトで環境変数として設定した値を取得する方法](https://style.potepan.com/articles/27698.html)*

##なぜ環境変数を設定する必要があるのか
セキュリティリスクを避けるために環境変数を設定します。
例えば、GitHubなどのオープンソースで開発をしている場合、第三者に知られたくないパスワードなどを公開しないようにできます。
環境変数で設定したデータを、必要なときにプログラムから呼び出すことで、セキュリティリスクを回避しています。

##環境変数の設定方法
Railsを使用している場合、環境変数の設定方法は2つあります。

1. ``.bash_profile``ファイルに記載する方法
2. ``Dotenv-rails``というgemを使う方法

今回は``.bash_profile``ファイルに記載する方法を解説していきます。

###参考``.bash_profile``ファイルとは
``.bash_profile``ファイルとは、**ログインシェルがbashの状態でログインしたときに読み込まれる設定ファイルのことです。**
*引用：[「分かりそう」で「分からない」でも「分かった」気になれるIT用語辞典](https://wa3.i-3-i.info/word13650.html)*

あなたが自分のパソコンにログインした直後のディレクトリ（ホームディレクトリ）にあります。
つまり``.bash_profile``ファイルに記載するとは、**シークレットキーなど外部に漏れてしまうと危険なデータを、自分のパソコンに保存しておくということです。**

###``.bash_profile``に環境変数を設定する手順

1. ``.bash_profile``を開く
1. 環境変数を書く
1. 環境変数を有効にする

それぞれ解説していきます。

###``.bash_profile``を開く
ターミナルで以下のコードを実行してください。

```terminal:ターミナル
vim ~/.bash_profile
```

###環境変数を書く
ターミナルの表示が切り替わったら「i」を押して、編集できるようにしましょう。
編集できるようになったら、以下のように記述しましょう。

```terminal:ターミナル
*
*
*
export KEY='123456789' #=>''の中に値を入れる。
export PAS='*********'
```

編集モードを終了するには``esc``ボタンを押します。
macの場合は左上にあります。

編集したファイルを保存して終了しましょう。
以下のコマンドを実行します。

```terminal:ターミナル
:wq
```

もし上記のコマンドで保存して終了できなかった場合は「！」をつけて上書きします。

```terminal:ターミナル
:wq!
```

これでvimモードから抜けられます。
###環境変数を有効にする
環境変数を設定したら以下のコマンドを入力して設定を有効化します。

```terminal:ターミナル
source ~/.bash_profile
```

これで環境変数の設定が終わりました。
設定した環境変数は以下のコマンドで確認できます。

```terminal:ターミナル
printenv
*
*
*
KEY='123456789'
PAS='*********'
```

###環境変数の呼び出し
下記のように``ENV["環境変数"]``で環境変数を呼び出しできます。

```ruby:key.rb
API_KEY=ENV["KEY"]
API_SECRET=ENV["PAS"]
```

##まとめ
* 環境変数とは、パソコンが持っている値を入れておく変数である。
* 環境変数は、セキュリティリスクを避けるために使用する。
* 設定した環境変数は``ENV["環境変数"]``で呼び出せる。

参考記事
*[[Ruby on Rails]環境変数の設定方法(.bash_profile、Dotenv-rails)
](https://qiita.com/yuichir43705457/items/7cfcae6546876086b849)*
*[[Rails]環境変数って何だろう？作る理由と作り方](https://qiita.com/Yukina_28/items/74cf08a23fbc8f304926)*
個人開発でつくったものをgithubにあげる方法

## 手順
1.githubで新しいリポジトリの作成
※ここで3で使うコマンドが表示されるのでメモる
2.ターミナルでgit initを入力
→ローカルリポジトリの作成を行う
→Initialized empty Git repository in〜みたいなのができたら成功
3.ターミナルでgit remote add origin <githubURL>を入力
→これでリモートリポジトリのプッシュ先を設定できる
(差分を見たいときはgit diffコマンド)
4.ターミナルでgit add .を入力
5.ターミナルでgit commitを入力
6.ターミナルでgit push -u origin masterを入力
→リモートリポジトリ(github)にプッシュできる
Intellij Ideaに必要なPythonパッケージをインストールする

## モジュールがないエラー

Intellij IdeaのうえでExcelを読み込むプログラムを組む際、以下のエラーが出ました。

```text
ModuleNotFoundError: No module named 'xlrd'
```

xlrdモジュールがないというとこで、以下の手順で追加できました。

## Intellij IdeaにPythonパッケージをインストールする

1. tools -> Manage Python Packagesをクリックします。  
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260307/ecdbcd0e-728d-6b53-93b2-63dac865e468.png)
2. +をクリックし、必要なパッケージを検索し、Install Packageをクリックします。
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/260307/7f5815e7-2d9e-6985-8366-053f5c2501f7.png)
ChromeDriverを自動更新するライブラリ

# 概要
SeleniumとChromeを使用してブラウザ操作の自動化をしていると、Chromeのバージョンアップの度にエラーが発生し、ChromeDriverを更新するということがあります。
今回紹介するwebdriver_managerというライブラリを使用すると、自動でChromeDriverの更新を行ってくれるようになります。


# 使用方法

1.ライブラリのインストール

```console:console
pip install webdriver-manager
```

2.コードの変更

```python:python　変更前
from selenium import webdriver
import chromedriver_binary

driver = webdriver.Chrome()
driver.get('https://google.com')
```

```python:python　変更後
from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager
 
driver = webdriver.Chrome(ChromeDriverManager().install())
driver.get('https://google.com')
```

3.実行
通常通り実行するだけです。
実行時にChromeのバージョンとChromeDriverがサポートするバージョンが異なる場合は、Chromeのバージョンに合うChromeDriverを自動的にダウンロードしてから実行されます。
Google Cloudにて開発環境の設定

## 前提
この記事では、Google Compute Engine 仮想マシンをプロビジョニングし、Google Cloud Platform での Node.js を使用したソフトウェア開発用にソフトウェア ライブラリをインストールします。

サラっとした内容なので、そんなに時間はかからないと思います。！

## 全体像
①Google Compute Engine インスタンスをプロビジョニングし、SSH を使用してインスタンスに接続する。

②インスタンスにソフトウェアをインストールする。

③ VM を設定してアプリケーション ソフトウェアを実行する

#### ①Google Compute Engine インスタンスをプロビジョニングし、SSH を使用してインスタンスに接続する。

Cloud Platform Console のナビゲーション メニューで、[Compute Engine] をクリックします。

![スクリーンショット 2021-07-26 20.27.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1740345/e9308e17-a399-6d54-7548-1cbd372110b9.png)


[VM インスタンス] ページで [作成] をクリックします。

![スクリーンショット 2021-07-26 20.31.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1740345/11ef9187-b7d0-dcd9-ba27-47d090341044.png)


[インスタンスの作成] ページで、[名前] に「dev-instance」（任意）と入力し、リージョンに [us-central1]（任意）、ゾーンに [us-central1-a]（任意） を選択します。

Google Cloudでは、リージョンと呼ばれる複数の異なる地理的なロケーションでプロダクトやサービスが提供されます。

各リージョンには複数の異なるゾーンがあります。各ゾーンは電源とインターネット接続が他のゾーンから分離されています。

[ID と API へのアクセス] > [アクセス スコープ] で、[すべての Cloud API に完全アクセス権を許可] を選択します。

![スクリーンショット 2021-07-26 20.32.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1740345/51d14824-3291-a9b0-e7eb-fdfbb09560c0.png)


[ファイアウォール] で、[HTTP トラフィックを許可する] を有効にします。

残りの設定はデフォルトのままにして、[作成] をクリックします。

仮想マシンがプロビジョニングされて起動されるまでに数十秒かかります。

[VM インスタンス] ページの dev-instance の行で、[SSH]をクリックします。

これにより、ブラウザでホストされる SSH セッションが起動されます。

なお、SSH 認証鍵の設定や管理は必要ありません。
結構ここって、Google Cloudの便利な点だよなあと個人的には思います。SSHしやすいといいますか、立ち上がりも早いですよね。
Cloud Shellなんかは、コンソール画面に、CLIが上手く融合されていると言いますか、GUIベースのはずなのに、VScodeのような使い勝手のような、非常に洗練されたデザインだと個人的には思うわけです。（早口）
AWSとかだと、SSMでコンソール上でSSHすることはできますが、画面遷移がGoogle Cloudに比べると多い気がします。
そういう点ではGoogle Cloudは使いやすいですね。

## ②インスタンスにソフトウェアをインストールする。

SSH セッションで Debian パッケージのリストを更新するには、次のコマンドを実行します。

```
$ sudo apt-get update
```

Git をインストールするには、次のコマンドを実行します。

```
$ sudo apt-get install git
```

プロンプトが表示されたら Enter キーを押します。

Node.js の設定スクリプトをダウンロードするには、次のコマンドを実行します。

```
$ curl -sL https://deb.nodesource.com/setup_14.x | sudo -E bash -
```

npm と Node.js をインストールするには、次のコマンドを実行します。

```
$ sudo apt install nodejs
```


## ③ VM を設定してアプリケーションソフトウェアを実行する

クラス リポジトリのクローンを作成するには、次のコマンドを実行します。

```
$ git clone https://github.com/GoogleCloudPlatform/training-data-analyst
```

作業ディレクトリを変更するには、次のコマンドを実行します。

```
$ cd ~/training-data-analyst/courses/developingapps/nodejs/devenv/
```

シンプルなウェブサーバーを実行するには、次のコマンドを実行します。

```
$ sudo node server/app.js
```

Cloud Console の仮想マシン インスタンスのリストに戻り、dev-instance（任意） の外部 IP アドレスをクリックします。

Node.js からの「Hello GCP dev!」 というメッセージが表示されます。

SSH ウィンドウに戻り、Ctrl+C キーを押してアプリケーションを停止します。

Compute Engine 用に Node.js ライブラリをインストールするには、次のコマンドを実行します。

```
# npm install
```

Compute Engine インスタンスを一覧表示するシンプルな Node.js アプリケーションを実行するには、次のコマンドを実行します。

```
$ node list-gce-instances.js
```

マシンに関する詳細な情報がターミナル ウィンドウに表示されます。


```
【参考】
https://cloud.google.com/nodejs/docs/setup
```
Java 11 LTSから Java 17 LTSへ

## これはなんですか
社内では現状みんなの共通言語として Java11 LTS を利用しているが、2021/9 にリリースされる Java17 LTS に乗り移るかどうか判断するため、各種 feature のまとめと、社内での議論のネタを積んでおくものです。

## 誰向け？
同様のことを検討しているお歴々には参考になるかもしれません。
後日コメントで弊社の結論も記載します。

## Java 11 ~ 17
12~16までは @nowokay 様がまとめてくださっているため、そちらを参照します。

### feature/java12
https://qiita.com/nowokay/items/0e860819b6ffb1aca90a
### feature/java13
https://qiita.com/nowokay/items/3e1625a77cb435394547
### feature/java14
https://qiita.com/nowokay/items/ec85d97a7cecaaac8123
### feature/java15
https://qiita.com/nowokay/items/2858699bc1cd89222cd8
### feature/java16
https://qiita.com/nowokay/items/215769cdcb14d6c5412f
### feature/java17
https://www.techgeeknext.com/java/java17-features

1. JEP 415: Context-Specific Deserialization Filters
    1. シリアライズ関連の変更（簡単になるよ的な）
1. JEP 414: Vector API (Second Incubator)
    1. ベクトル計算のAPIが導入されるけど我々あんまり使わないと思う・・
1. JEP 412: Foreign Function & Memory API (Incubator)
    1. 内部制御に関するもの
1. JEP 411: Deprecate the Security Manager for Removal
    1. 消えるｒｙ
1. JEP 410: Remove the Experimental AOT and JIT Compiler
    1. 消える
1. JEP 409: Sealed Classes
    1. https://openjdk.java.net/jeps/409
    1. **これは文法とクラス、インターフェースの制御に関する重要な変更**
1. JEP 407: Remove RMI Activation
    1. 消える
1. JEP 406: Pattern Matching for switch (Preview)
    1. https://openjdk.java.net/jeps/406
    1. 型による分岐が可能に

```
static String formatterPatternSwitch(Object o) {
    return switch (o) {
        case Integer i -> String.format("int %d", i);
        case Long l    -> String.format("long %d", l);
        case Double d  -> String.format("double %f", d);
        case String s  -> String.format("String %s", s);
        default        -> o.toString();
    };
}
```
1. JEP 403: Strongly Encapsulate JDK Internals
    1. セキュリティ関連
1. JEP 398: Deprecate the Applet API for Removal
    1. ええ・・まだいたんすか・・・
1. JEP 391: macOS/AArch64 Port
    1. M1 Macのネイティヴサポート！
1. JEP 382: New macOS Rendering Pipeline
    1. あんまり関係ない
1. JEP 356: Enhanced Pseudo-Random Number Generators
    1. 乱数生成に関するもの。もしかしたらエントロピー枯渇を気にしなくてよくなる？
1. JEP 306: Restore Always-Strict Floating-Point Semantics
    1. 浮動小数点に関する変更　これも普通に使っていればあまり意識しないでよい

## Javaのデメリット
1. メモリ食いすぎる　某正規空母みたいな奴
1. fat jar 化しやすくビルドが長引く
1. jarやjdkのスリム化を行うのが面倒でカスタマイズに知識が必要

## 他のフレームワーク
1. python
    1. いろいろあるみたいだけどよくわからない
1. go
    1. シンプルで速いともっぱらのうわさ
    1. 個人的にはC言語が最初の言語である私にはとっつきやすそう
1. node
    1. 書いてくと複雑化しやすいから大規模開発ではやりたくない
Setting a timer for a long period of time, i.e. multiple minutes がうざい

#無視しちゃおう

```
import { LogBox } from 'react-native';
LogBox.ignoreLogs(['Setting a timer']);

```


```
Setting a timer for a long period of time, i.e. multiple minutes, is a performance and correctness issue on Android as it keeps the timer module awake, and timers can only be called when the app is in the foreground. See https://github.com/facebook/react-native/issues/12981 for more info
```
【ピボットテーブル】日付のグループ化ができない→元データ(日付セル)の空白が原因！

#おきたこと
Excelで家計簿をつけています。

・期間：2021年4~2022年3月
・ピボットテーブルに月ごとの集計が表示されるよう、「グループ化>月」に設定

この状態で問題なく入力していたのですが、
ある日急に、ピボットテーブル上で「更新」をクリックすると
月ごとのグループ化が解除され、↓このように1日ごと表示されるようになってしまいました。

<img width="300" alt="100.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/498057/58c35446-cf31-bf3e-2702-47ce8352c617.png">

試しにピボットテーブルの日付セルの上で右クリックし「グループ化」をクリックしてみましたが
「選択対象をグループ化することはできません」というエラーが出ました。
<img width="300" alt="200.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/498057/4c1d5b2c-c3ba-37c3-6070-e362f89ebb61.png">

#確認

・書式設定は「日付」になっているか？→なっている。
入力用のシートを確認したところ、
「セルの書式設定>分類」の設定は文字列等ではなく、きちんと「日付」になっていました。

・データソースは正しい範囲が選択されているか？→されている。
（「分析>データソースの変更」で確認。）
<img width="500" alt="300.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/498057/d27ed59b-e149-87c1-99df-5129672a36e1.png">

・データソースの日付セルに「空白」のセルが含まれていないか？→含まれている。
原因はこれでした！
データソースのシートはテーブル化してあり、データソースはこのテーブル名を指定するかたちにしていました。
このテーブルの最後の方は、まだ入力がされていない行が何行もありました。
「日付」が空白になっているセルが含まれていると、ピボットテーブルで日付のグループ化はできない、ということがわかりました。

#結論
元データの「日付」セルに空白が含まれていると、ピボットテーブルで日付のグループ化はできない。
空白になっている行はデータソースの範囲から除外せよ。
meta-tagsについて

# Gem meta-tags について

今回SEO対策として何か実装したいと考えて調べてみた所、meta-tagsというGemを知りましたので、実際に使ったので備忘録として記入したいと思います。

#meta-tagsの導入

```routes.rb
Gem 'meta-tags'
```

bundlerでインストール

```ターミナル
bundle exec
```

これで導入完了です

# 各種設定

上記の作業を正常に完了してれば```config/initializers/meta_tags.rb```という感じにファイルが生成されています。
meta-tagsの内容は下記の通りです。

```meta_tags.rb
# Use this setup block to configure all options available in MetaTags.
MetaTags.configure do |config|
  # How many characters should the title meta tag have at most. Default is 70.
  # Set to nil or 0 to remove limits.
  # config.title_limit = 70

  # When true, site title will be truncated instead of title. Default is false.
  # config.truncate_site_title_first = false

  # Maximum length of the page description. Default is 160.
  # Set to nil or 0 to remove limits.
  # config.description_limit = 160

  # Maxumum length of the keywords meta tag. Default is 255.
  # config.keywords_limit = 255

  # Default separator for keywords meta tag (used when an Array passed with
  # the list of keywords). Default is ", ".
  # config.keywords_separator = ', '

  # When true, keywords will be converted to lowercase, otherwise they will
  # appear on the page as is. Default is true.
  # config.keywords_lowercase = true

  # List of additional meta tags that should use "property" attribute instead
  # of "name" attribute in  tags.
  # config.property_tags.push(
  #   'x-hearthstone:deck',
  # )
end
```

こちらの記述は「タイトルでも文字数制限などを設定できますが、デフォルトでも大丈夫らしいので、今回はこのままです。
各種サイトの条件に合わせて設定してください。

metaタグの初期設定をおこなうため、「app/helpers/application_helper.rb」にdefault_meta_tagsメソッドを実装します。

```application_helper.rb
module ApplicationHelper
  def default_meta_tags
    {
      site: 'サイト名',
      title: 'タイトル',
      reverse: true,
      charset: 'utf-8',
      description: 'description',
      keywords: 'キーワード',
      canonical: request.original_url,
      separator: '|',
      icon: [
        { href: image_url('favicon.ico') },
        { href: image_url('icon.jpg'), rel: 'apple-touch-icon', sizes: '180x180', type: 'image/jpg' },
      ],
      og: {
        site_name: 'サイト名', # もしくは site_name: :site
        title: 'タイトル', # もしくは title: :title
        description: 'description', # もしくは description: :description
        type: 'website',
        url: request.original_url,
        image: image_url('ogp.png'),
        locale: 'ja_JP',
      },
      twitter: {
        card: 'summary',
        site: '@ツイッターのアカウント名',
      }
    }
  end
end
```

これまでの作業が終わればあとは、application.html.erbのhead内に```<%= display_meta_tags(default_meta_tags) %>```を記述すればviewに表示できます。
以上です。
REST APIを基本からまとめてみた


## RESTとは
『シンプルなWebシステムの設計思想』のこと。
『REpresentational State Transfer　（リプレゼンテーショナル・ステイト・トランスファー）』の略。
『Representational→具象化された　State→状態の　Transfer→転送』＝『具体的に状態を定義した情報のやり取り』の意味合い。

#### RESTの4つの設計原則
①セッションなどの状態管理を行わない。(やり取りされる情報はそれ自体で完結して解釈することができる)
②情報を操作する命令の体系が予め定義・共有されている。（HTTPのGETやPOSTメソッドなど）
③すべての情報は汎用的な構文で一意に識別される。（URLやURIなど）
④情報の内部に、別の情報や(その情報の別の)状態へのリンクを含めることができる。

## REST APIとは
『RESTful API(REST API)』とは、Webシステムを外部から利用するためのプログラムの呼び出し規約(API)の種類の一つで、
RESTと呼ばれる設計原則に従って策定されたもの。RESTそのものは適用範囲の広い抽象的なモデルだが、
一般的にはRESTの考え方をWeb APIに適用したものをRESTful APIと呼んでいる。

RESTful APIでは、URL/URIですべてのリソースを一意に識別し、セッション管理や状態管理などを行わない(ステートレス)。
同じURLに対する呼び出しには常に同じ結果が返されることが期待される。

また、リソースの操作はHTTPメソッドによって指定(取得ならGETメソッド、書き込みならPOSTメソッド)され、
結果はXMLやHTML、JSONなどで返される。
また、処理結果はHTTPステータスコードで通知するという原則が含まれることもある。


## 参考サイト
[REST APIとは？ざっくりと理解してみる【初心者向け】](https://tech.012grp.co.jp/entry/rest_api_basics)
ffmpegで動画のサイズと拡張子を一括変換

# 概要
pythonのos.system関数から、ffmpegを呼び出して動画のサイズや拡張子を一括で変更するスクリプトです。サイズや拡張子の指定がなければ、オリジナルの情報を引き継ぎます。

注：2021年に書いた記事です。当時は自分用として限定公開にしていましたが、積極的に隠すほどでもないと考え直して公開します。

# 環境

```
% sw_vers
ProductName:    macOS
ProductVersion: 11.4
BuildVersion:   20F71
% python -V
Python 3.8.6
```

# コード

```Python
import os
import random, string

INPUT_DIR = os.path.join("input") #path to input movie directory
OUTPUT_DIR = os.path.join("output") #path to output movie directory

def randomname(n):
   randlst = [random.choice(string.ascii_letters + string.digits) for i in range(n)]
   return ''.join(randlst)
   
def convert(input=None, output=None, width=None, ext=None, skip=True):
  if input is None: input=INPUT_DIR
  if output is None: output=OUTPUT_DIR
  if width is None: width = OUTPUT_WIDTH

  os.makedirs(output, exist_ok=True)

  files = os.listdir(input)
  files = [f for f in files if f.split(".")[-1] in ["mp4","MP4","m4v","MOV","mov"]]
  input_files = [os.path.join(input, f) for f in files]
  if ext:
    output_files = [os.path.join(output, "{}.{}".format(".".join(f.split(".")[:-1]), ext)) for f in files]
  else:
    output_files = [os.path.join(output, f) for f in files]

  for ipt, opt in zip(input_files, output_files):
    if skip and os.path.exists(opt):
      print("{} is skipped".format(ipt))
      continue
    tmpopt = opt
    if os.path.exists(opt):
      tmpopt = "{}{}.{}".format(".".join(opt.split(".")[:-1]), randomname(12), opt.split(".")[-1])
      
    if width:
      cmd = f"ffmpeg -i {ipt} -vf scale={width}:-1 {tmpopt}"
    else:
      cmd = f"ffmpeg -i {ipt} {tmpopt}"
    os.system(cmd)
    if not skip:
      cmd = "mv {} {}".format(tmpopt, opt)
      os.system(cmd)

if __name__=="__main__":
  convert(width=854, ext="mp4")
```

# 参考

[Pythonを使ってランダムな文字列を生成](https://qiita.com/Scstechr/items/c3b2eb291f7c5b81902a)
Jupyter Notebookを一瞬で記事にできて誰でも収益化できるサービス作ってみた

## こちらで紹介しているサービスはMagicodeとして再リリースされました！詳しくは以下の記事をご覧ください。
https://qiita.com/Taiki92777/items/c53c51b3586078e2318c

https://jp.magicode.io
# はじめに
あらゆるサイエンス領域で使われているJupyter Notebookですが、誰でもシェアできるサービスはGithub / Colab・Kaggleしかありませんでした。しかも、Github / Colabはシェアはできるけど、シェアして終わり、Kaggleはコンペありきのノートブックしかない（コンペ参加しなかったら見ないですよね普通）、という状況でした。また、シェアすることで収益化できるというサービスはありませんでした。

そこで、処理・アルゴリズムのTipsから、体系的なサマリー・教材など、あらゆる表現ができるノートブックを一瞬で記事としてシェアできて、誰でも収益化ができるサービスを今回作ってみました。

# 作ったもの：Notebox
ノートブックsということでダジャレみたいですけど、Noteboxというサービスを作りました。
技術スタックはこちらの記事から見れます！

https://zenn.dev/fasdfas/articles/839bfc5160a81e

ここでは簡単な使い方・機能を紹介したいと思います。

## ローカルのノートブックを記事にする
+ボタンを押すと作成画面に移動します。ここにローカルのノートブック(.ipynbで終わるもの)をアップすると、記事が自動で作成されます。タイトルとタグを付けて、右下の公開するボタンを押すとすぐに公開されます。

動画だとこんな感じです。
<iframe width="560" height="315" src="https://www.youtube.com/embed/IWcUbVnQxkw" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

## GitHubのノートブックを記事にする
GitHub連携することで、GitHubにあるノートブックを簡単に記事にできます。現在は公開レポジトリのみ対応しています。

## 収益化する
3種類の収益化があります。
1. **投げ銭**・・・知見の対価として読者が金額を決めてコメントとともに贈れます。
2. **スーパーコメント**・・・投げ銭とほとんど同じですが、コメント欄にYouTubeのスーパーチャットと同じように表示されます。(β版機能です。)
3. **有料記事**・・・記事の設定で有料記事にもできます。無料公開の範囲も簡単に決めることができます。

# 最後に
さまざまなサイエンス領域で自由に知見が共有され、投稿者にとってもオーディエンスにとっても実用的で心地の良い場所にしていけたらと思います。是非使ってみてください！

https://notebox.jp/
Google Apps Script　doGetのテストをする

#Google Apps Script　doGet関数をデバッグしたい。
どうやらdoGet関数のと同じ働きをする関数を自分で作ってデバックするようです。
以下のページを参考に自分用に追記しました。
[参考](https://breezegroup.co.jp/201906/gas-get/)

<b>やりたいこと</b>
Google Apps ScriptのdoGet関数内でURL クエリパラメータのチェックをしたい
いちちちURLを作成するのが面倒
<B>自分のとった方法</b>
doGet関数のと同じ働きをする関数を自分で作ってデバックする


##例：http://〇〇〇?id=123&name=test
##パラメータのidとnameに値が設定されているか確認する

##使い方
###①dobugTest関数にデバックしたいパラメータを配列形式で記入する
###②doget(e)関数内でパラメータのチェックなどをする
###③dobugTest関数の選択後デバッグボタンを押す
※疲れた状態でなんとなくコピペしてデバックを押すと、別の関数がデバックされて、思った結果にならなかった。しかもしばらくその事実に気が付かない（実話）


```:GoogleAppsScript

//この関数の中にクエリパラメータを配列形式で設定する
//idがない場合は下記載の配列からidを消す
//id= のように空の場合のテストをしたい場合id:'' にする
function debugTest(){
  const e = {
    parameter:{
      id:'33',
      name: 'AA'      
    }
  }
  const a = doget(e);
  
}

//下の関数でクエリパラメータを取得して、チェックできます。
function doget(e){
  //パラメータをログに出力してみる。
  console.log(e.parameter['id']);
  console.log(e.parameter['name']);

  //パラメータがある場合変数にはパラメータの値が入る
  //パラメータが無いもしくはあるけれど値が空の場合変数にはfalseが入る
  let id=e.parameter['id'] ? e.parameter['id']:false
  let aa=e.parameter['name'] ? e.parameter['name']:false
  

  if (id===false){
    console.log("パラメータidがないもしくは値が空の場合の処理")    
  }
  if (name===false){
　　　console.log("パラメータnameがないもしくは値が空の場合の処理")
  }

}


```
AIスピーカーYoSiE開発日誌

#AIスピーカーYoSiE開発日誌その一 ～ とりあえず書こう編
##初投稿
今日からこうやって記事を書き始めるけど何を書けばいいのかわからない
今こうやって書いてるけどすごい緊張する。
．
．
うーむ、まぁとりあえずは考えずに書いてみるか、
あんまり長くなく短くもなく難しい...
とりあえず続けてみる
##きょうやったこと

・チームロゴ決め
・ライトニングトーク
・githubでかんばんを作成した
##チームロゴ
こんな感じで高級感を…(私の作品ではない)
…
![twitter_profile_image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1782915/c6e53039-7505-4194-b88e-7190f04115a4.png)
##ライトニングトーク
これに関しては場数を踏むしかない
突っ込まれるのを覚悟しようか
###point
・わからないところは言わない
・とりあえず言いたいことを絞る
・ポジティブなことだけ言う
・相手にも楽しく
##githubでかんばん作成
とりあえずTodoリストにやることを書こう
###早速書いてみよう
とりあえずこんな感じで![スクリーンショット 2021-07-26 200617.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1782915/e5b6951b-ee08-5a33-7d95-11ed3074000c.png)
####あれ？
![スクリーンショット 2021-07-26 200819.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1782915/caa7058e-6878-1419-40cb-88debafb2f8e.png)
こんな感じになってしまった。(汗)

とりあえず聞いてみたら

-------には改行してあげなきゃいけないようだね
###やってみよう
開けてみた![スクリーンショット 2021-07-26 201324.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1782915/00d84e46-e02d-045c-c2b8-fa0178d0c0b4.png)
できたかな？
![スクリーンショット 2021-07-26 201436.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1782915/4cef7c4a-f078-ece2-5897-8ee7c2f81f98.png)
おお！綺麗になったぞ嬉しい
ポートフォリオ作成の配色に困ったときに使えるアプリ

#はじめに

ポートフォリオ作成で配色のセンスがありません。。。
そんな時、youtubeで見つけた良いアプリがあったので紹介させていただきます。


#Coolors

https://coolors.co/

ランダムでベストな配色を決めてもらえるアプリです。

![スクリーンショット 2021-07-26 19.28.20（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1264460/9bb1ad0b-f083-dc1c-81f4-16aea17ad5ca.png)

まずは`Start the generator!`をクリックして始めましょう！

![スクリーンショット 2021-07-26 19.39.54（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1264460/02274793-fd4f-9350-c1b6-4e972b1415e7.png)


このような色がランダムで表示されます。
気に入った配色が出るまでスペースキーで押しましょう！

[![Image from Gyazo](https://i.gyazo.com/e81119cf626d7f2627e097325a34a279.gif)](https://gyazo.com/e81119cf626d7f2627e097325a34a279)

いいなと思った色があったら固定することもできます。
また配色を追加したり削除したりする事ができます。

[![Image from Gyazo](https://i.gyazo.com/7cecc45d5495de1e788f155c6fae5bc0.gif)](https://gyazo.com/7cecc45d5495de1e788f155c6fae5bc0)

自分の中で入れたい色を最初から入れる事もできますし、人気の配色など表示することができます。


#参考

https://photoshopvip.net/127898
Pythonスクレイピングにおけるパスの書き方

<h2>初めに</h2>
現在学習でスプレイピングを学習しているのですが、抽出したデータをcsvなどで保存する際にわざわざ絶対パスで書くことによる障害が起きるのではないかと思った。

そしてそのコードを他の人が使用する際にローカルのパスでは動かないのでコードを変更する必要があった。

自分の学習のメモだと思ってみてください。

<h2>問題点</h2>
とあるサイトのページからデータを取得したい。
その際にサイトの情報をHTMLファイルで保存を行う。その際に以下のコードでは問題が起きる。


```ruby:sc.py
p = f"/Users/ユーザー名/Python-Scraping/html/{driver.title}.html"
    with open(p,"w") as f:
        f.write(html)
```

途中は端折っていますが、要するにPython-Scrapingフォルダの下に別々にsc.pyファイル、htmlフォルダが同じ階層に存在しています。

この場合に異なるフォルダ形式や異なるユーザー名ではコードが動かなくなるのが現在の問題点です。

<h2>解決策</h2>
まず初めにライブラリをインポートします。

```ruby:sc2.py
import os
```

この後で続きのコードを記入していきます。

```ruby:sc2.py
#現在のファイルの位置のパスを表示することができる。
print(os.path.abspath(__file__))
#上のファイルが格納されているフルパスを得ることができる
print(os.path.dirname(os.path.abspath(__file__)))

```

実際にターミナルで実行が可能であるか確認してみてください。パスが確認できると思います。

```ruby:ターミナル
/Users/ユーザー名/Python-Scraping/lesson.py
/Users/ユーザー名/Python-Scraping
```
このように出力されます。

---


```ruby:sc2.py
dir = os.path.dirname(os.path.abspath(__file__))

os.path.join(dir,"html","index.html")
```

先ほどの二つ目のコードを変数dirに格納します。そして同じ階層にあるhtmlフォルダ内のindex.htmlファイルとして作成を行うことができます。

実際に作成が行われるかの確認を行うために出力を行なってみてください。

```ruby:sc2.py
print(os.path.join(dir,"html","index.html"))
```

```ruby:ターミナル
/Users/ユーザー名/Python-Scraping/html/index.html
```
このように出力されていれば成功です。

---

あとは最初に記述したコードを書き換えるだけです。

```ruby:sc.py
dir_name = os.path.dirname(os.path.abspath(__file__))
#p = f"/Users/ユーザー名/Python-Scraping/html/{driver.title}.html"
p = os.path.join(dir_name,"html",f"{driver.title}.html")
    with open(p,"w") as f:
        f.write(html)
```

<h2>まとめ</h2>
このように一見なんともないコードも他者との連携が取りにくい場合があります。
一文変えることによって、ユーザーに囚われることなくフォルダの中にファイルを格納することが可能となりました。
Laravelのクエリビルダで使われる比較演算子について

Laravelのクエリビルダで下記のようなコードを見つけた。

```
->where('team_id', '<>', $team_id)
```

あまり見慣れなかった比較演算子だったので再度調べた所、

```
「 a <> b 」 　は  「　a と b は等しくない　」
```
という意味らしい。

つまり、下記は「team_idと$team_idが等しくないもの」という条件指定となる。

```
->where('team_id', '<>', $team_id)
```

「<、<=」などは条件分岐で馴染みがあるが、
SQL独自の比較演算子なのか「<>、a <=> b」などは知らなかったので今後のために覚えておく。

参考記事はこちら↓

https://www.dbonline.jp/mysql/ini/index7.html
ドメイン駆動設計入門で学んだこと #2

# はじめに

本記事は以下の書籍を読んで学んだことをまとめることを目的としています。
[前回](https://qiita.com/minoura_a/items/986fd79985eb814cbf00)の続きです。
[ドメイン駆動設計入門 ボトムアップでわかる! ドメイン駆動設計の基本 | 成瀬 允宣 |本 | 通販 | Amazon](https://www.amazon.co.jp/%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E9%A7%86%E5%8B%95%E8%A8%AD%E8%A8%88%E5%85%A5%E9%96%80-%E3%83%9C%E3%83%88%E3%83%A0%E3%82%A2%E3%83%83%E3%83%97%E3%81%A7%E3%82%8F%E3%81%8B%E3%82%8B-%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E9%A7%86%E5%8B%95%E8%A8%AD%E8%A8%88%E3%81%AE%E5%9F%BA%E6%9C%AC-%E6%88%90%E7%80%AC-%E5%85%81%E5%AE%A3/dp/479815072X/ref=sr_1_1?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=325IZJW8OL7R9&dchild=1&keywords=%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3%E9%A7%86%E5%8B%95%E8%A8%AD%E8%A8%88&qid=1593219430&sprefix=%E3%83%89%E3%83%A1%E3%82%A4%E3%83%B3,aps,244&sr=8-1)

# DDDで出てくる概念

DDDで出てくる概念を整理します。

## エンティティ

エンティティの性質は以下です。

- 可変
- 同じ属性でも区別
- 同一性による区別

[前回](https://qiita.com/minoura_a/items/986fd79985eb814cbf00)値オブジェクトの説明で
>stringでは表せない文字数制限や入力できる文字種の制限など、そのシステム固有のルールを表現をしたい、かつ値の性質を適用したいときに使われます。値の性質とは以下が挙げられます。
- 不変
- 交換可能
- 等価性による比較

と説明しました。エンティティは値オブジェクトを逆の性質も持つといえます。
エンティティの性質が少しわかりにくいと思ったので、値オブジェクトとの違いを意識してもう少し説明します。

- 可変
  - 値オブジェクトと異なり、Changeメソッドなどで属性を変更させることができます。代入による変更はしなません。
- 同じ属性でも区別
  - 値オブジェクトは等価性による比較が行われ、同じ属性であれば区別されませんでしたが、エンティティは同じ属性でも区別されます。例えばNameプロパティを持つオブジェクトがあったとして、同じ値が入ったインスタンスがあったときに、値オブジェクトであれば、同じものとみなされますが、エンティティの場合は別物になります。
- 同一性による区別
  - 同じ属性で見分けがつかないと困るので、エンティティ同士を区別するために識別子による比較をします。インスタンスの属性を変更したとしても識別子という同一性によって、変更前と同じものであると認識されます。

### 値オブジェクトとエンティティのどちらを使えばよいか

何を値オブジェクトにして、何をエンティティにするかは非常に難しいと思います。
その一つの解決策として、ライフサイクルが紹介されていました。
例えば「ユーザー」というオブジェクトの場合、アプリケーションの会員登録で作成されたり、退会して削除されたり、とライフサイクルが存在するため、エンティティになります。
「名前」というオブジェクトの場合、ユーザーの属性として値の性質を持つオブジェクトとして利用されることが考えられます。アプリケーションの中でライフサイクルとして表現することは無意味であるため、値オブジェクトになります。
可変なのか不変なのかで判断できそうです。
ただし、同じ概念を持っていたとしても、システムによって値オブジェクトとなるのか、エンティティとなるのかは変わります。そのため、構築したいシステムによってしっかり考える必要があると思いました。

### ドメインオブジェクトのメリット

値オブジェクト、エンティティという二つのドメインオブジェクトについて学びました。
なぜこのような概念が必要かというと、[前回](https://qiita.com/minoura_a/items/986fd79985eb814cbf00)と同じような話になるのですが、オブジェクトの意味や仕様がコードを読むだけでわかるドキュメント性を高めるため、仕様の変更を局所化しロジックの散在を防ぐためです。
上記のメリットから、なるべくドメインオブジェクト自身が自分のことを色々語るように、自分のことは自分でやるように設計するのが良いと私は理解しています。

## ドメインサービス

値オブジェクトやエンティティといったドメインオブジェクトに記述するには不自然な振る舞いはドメインサービスに記述します。
不自然な振る舞いとは、複数のドメインオブジェクトに跨って処理されるようなときに多く見られるそうです。
確かに、自分自身のことを自分でやることは普通のことですが、ほかのオブジェクトを全て確認するなど、そのドメインオブジェクトが本当にやるべき責務なのかは一度考えた方がよさそうに思いました。

実装上の注意

- ドメインオブジェクトと異なり、ドメインサービスには自身の振る舞いを変更するような状態をもたない
- むやみにドメインサービスに振る舞いを書かない。ドメインオブジェクトに書くべき振る舞いが、サービスに漏れて、自分自身で何もしなくなってしまうと、ドメインモデル貧血症となる
- 迷ったらドメインオブジェクトに振る舞いを書くべき

### ドメインモデル貧血症がなぜいけないのか？

ドメインオブジェクトのメリットである「オブジェクトの意味や仕様がコードを読むだけでわかるドキュメント性を高めるため、仕様の変更を局所化しロジックの散在を防ぐため」がなくなってしまうからです。
自分自身で何もできないオブジェクトを見ても、どんなルールがあるかわからないし、ルールを守るためのロジックも散在してしまいます。

# さいごに
ここまでお読みいただき、ありがとうございました。
長くなるので、#3に続きます。
Laravelは複数のwhereを配列で一括指定できる

Laravelのクエリビルダでwhereで複数条件指定する際は

```
->where('id', $id)->where('name', $name)
```
とするのもアリだが、複数指定は下記ように配列で指定するほうが可読性が上がる。

```
->where([
  ['id', '=', $id],
  ['name', '=', $name],
])
```



【おまけ】Eloquentとクエリビルダの違いの再確認

下記記事がわかりやすかった。

https://biz.addisteria.com/query_builder/
【Angular11】Cannot find namespace 'NodeJS'. にハマった話

# 環境
- Angular CLI: 11.0.4
- Node: 10.13.0
- TypeScript: 2.9.2

## やろうとしてたこと

```setInterval``` を使ったタイマを作成し、タイマーを止めるために返り値の```NodeJS.Timeout``` 型のプロパティで保持しようとしていました。ただ、この型宣言で、「NodeJSっていう名前空間が見つからんよ！」って怒られちゃいました。

```sample.component.ts

private timer: NodeJS.Timeout; // Cannot find namespace 'NodeJS'.

public setTimer() {
    this.timer = setInterval(()=>{});
}
```


## ハマったこと

修正方法を日本語・英語の両方で調べると、結構ヒットします。ただ、そのほとんどが```tsconfig.json``` を修正する記事ばかりで、知識のない私が意味も理解せずに、その通りに修正しても直りませんでした。


# 解決策

```src/tsconfig.app.json``` がある場合は、そちらの```compilerOptions``` の```types``` に```node``` を追加で解決できました。

```src/tsconfig.app.json
{
  "extends": "./tsconfig.json",
  "compileOnSave": false,
  "compilerOptions": {
    "baseUrl": "./",
    "types": [
      "node"   // 追加
    ],
  },
}
```

```@types/node``` をインストールしていなければ、下記コマンドでインストールします。

```bat
npm install --save-dev @types/node
```

## 何が違ったのか

よくよく自分のプロジェクト構成をみると、継承した```tsconfig.app.json``` がありました。いくら```tsconfig.json``` を修正しても、そちらで上書きされてしまっていたようです。

なお、調べたサイトをちゃんと見返すと```tsconfig.app.json```って書いてありました。。。先入観で記事を見てはダメですね。。。



### 参考

- [styled-componentsの「Cannot find namespace 'NodeJS'.」 - Qiita](https://qiita.com/camcam_lemon/items/6cfbdf649d7858c48c07#typesnode%E3%82%92%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB-1)
- [Cannot find namespace 'NodeJS' - Stack Overflow](https://stackoverflow.com/questions/58223909/cannot-find-namespace-nodejs/62759265)
[vuejs]buttonのtypeを忘れていた。[html]

# はじめに
最近タスクが落ち着いてきてそれなりの頻度で書くことができています。（当社比）

# くるしめられた！
とあるページで、取得してきた画像を削除するページがありましたとさ・・・

```vue:button.vue
<template>
    <div v-for="(image, index) in images" :key="index">
        <img :src="image.file_path" />
        <button @click="onDeleteImage(image.id)"></button>
    </div>
</template>
<script>
    export default {
        data () {
            return {
                images: [],
            }
        },
        methods: {
            async onDeleteImage(id) {
                if (!confirm('削除してもよろしいですか？')) {
                    return
                }
                try {
                    const resp = await axios.delete('/api/image/'+id)
                    if (resp.data.result) {
                        alert('削除しました。')
                        this.getItems()
                    } else {
                        // error message
                    }
                } catch (error) {
                    console.error(error);
                }
            }
        }
    }
</script>

```

imagesは画面読み込み時(getItems)で取得されている想定です。
delete前
![スクリーンショット 0003-07-26 午後6.59.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206053/761c66e1-f24a-de05-26cc-3e0a070cc95f.png)

delete後
![スクリーンショット 0003-07-26 午後6.59.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206053/e6a67840-d615-c957-e785-a455f68be9c4.png)

削除後、alertのみで遷移の命令とか出してないな・・・って思ったんだけど、、、

# 初歩的なミス・・・

```
<button type="button" ~~~
```

だった・・・
どうやらbuttonタグは typeがないと初期でsubmitになるらしく、
buttonにもtype="button"と指定してあげないと画面遷移？が入るみたいでした。

#まとめ
buttonなんだから初期でbuttonにしろと思ったのは僕だけではないはず。
Active Storageの導入

#Active Storageとは？
ファイルアップロード機能を簡単に実装できるGemです。


ActiveStorageを導入しただけではファイルをアップロードできるようになるだけです。

保存した画像を画像を加工してから（サイズや色など）表示できるようにするには以下の画像加工ツールとgemが必要になります。

## ImageMagick 
コマンドラインから画像に処理を加えることができるツールです。
処理としては、画像の作成やサイズ変更、保存形式の変更などがあります。

ImageMagickはGemではなく、ソフトウェアです。
そのため、Homebrewからインストールします。

GemではないImageMagickをRubyやRailsで扱うには、MiniMagickというGemが必要となります。

## MiniMagick
ImageMagickの機能をRubyで扱えるようにしてくれるGemです。
RailsでImageMagickを扱うために必要となります。

MiniMagickによって、ImageMagickの機能がRailsで使用できるようになりますが、画像サイズの変更には、もう1つImageProcessingというGemを追加する必要があります。

## ImageProcessing
MiniMagickでは提供できない、画像サイズを調整する機能を提供するGemです。

たくさんのツールとGemを紹介しましたが、それぞれの関係性は把握しておきましょう。
それでは、これらのツールとGemを導入します。

## 導入手順
まずはImageMagickを**　Homebrew　**からインストールします。

ターミナル

    % brew install imagemagick


次にMiniMagickとImageProcessingをインストールします。

gemfile

    　　　# gemfileの一番下に記述する
    % gem 'mini_magick'
    % gem 'image_processing', '~> 1.2'
　　　　
続いて、ターミナルにて`bundle install`します。

ターミナル

    % bundle install

gemを新しくインストールしたらローカルサーバーを再起動しましょう。

ターミナル

    % rails s
    
    # サーバー開いている場合は一度「 control + c 」で閉じてから再起動するように


以上でActive Storageを使用する為に必要なツールのインストールは完了です。


続いて、Active Storageをアプリケーション内で使用する準備を行います。

ターミナル

    % rails active_storage:install

`rails active_storage:install`コマンドを実行すると、Active Storageに関連したマイグレーションが作成されます。続けてマイグレートしましょう。

ターミナル

    % rails db:migrate

Sequel Proを確認し、**active_storage_attachments**と**active_storage_blobs**の二つのテーブルが追加されていれば成功です。

これで、Active Storageと画像加工ツールの導入は完了です。
ffmpegとpythonで動画のサイズを一括変換

# 概要
pythonのos.system関数から、ffmpegを呼び出して動画のサイズ（幅）を一括で変更するスクリプトです。雑にいろんな動画の容量を軽くしたいときなどに使います。

注：2021年に書いた記事です。当時は自分用として限定公開にしていましたが、積極的に隠すほどでもないと考え直して公開します。

# 環境

```
% sw_vers
ProductName:    macOS
ProductVersion: 11.4
BuildVersion:   20F71
% python -V
Python 3.8.6
```

# コード

```Python
import os
INPUT_DIR = os.path.join("input") #path to input movie directory
OUTPUT_DIR = os.path.join("output") #path to output movie directory
OUTPUT_WIDTH = 640#16:9の場合1280, 854, 640あたりから選ぶ

def resize(INPUT=None, OUTPUT=None, WIDTH=None, skip=True):
  if INPUT is None: INPUT = INPUT_DIR
  if OUTPUT is None: OUTPUT = OUTPUT_DIR
  if WIDTH is None: WIDTH = OUTPUT_WIDTH

  os.makedirs(OUTPUT, exist_ok=True)

  files = os.listdir(INPUT)
  files = [f for f in files if f.split(".")[-1] in ["mp4","MP4","m4v","MOV","mov"]]
  input_files = [os.path.join(INPUT, f) for f in files]
  output_files = [os.path.join(OUTPUT, f) for f in files]

  for ipt, opt in zip(input_files, output_files):
    if skip and os.path.exists(opt):
      print("{} is skipped".format(ipt))
      continue
    cmd = f"ffmpeg -i {ipt} -vf scale={WIDTH}:-1 {opt}"
    os.system(cmd)

if __name__=="__main__":
  resize()
```
PostgreSQLのインストール~DBの作成

# 背景

データベースについて、理解不足だったため備忘録を兼ねてインストール~DBの作成について執筆。
コマンドはターミナル上で実行します。

Mac OSを使用しています。

## brewのインストール

brewとは、パッケージ管理システムの一つです。

```
インストールされている場合は以下の結果が出力されます。

which brew 
=>/usr/local/bin/brew

```

されていなかったら以下を実行しましょう。

```
$ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"
```


## DBのインストール(PostgreSQL)


```:インストール
brew install postgresql
```
*brew install <パッケージ名>でインストールできます。逆にアンイストールしたい場合はbrew remove <パッケージ名>でできます。


```:バージョン確認
postgres --version
=>postgres (PostgreSQL) 13.3
```


```:DB起動
brew services start postgresql
```

```:psqlへログイン
psql postgres
psql (13.3)
Type "help" for help.

postgres=#
```
上記のコマンドで、postgreSQLへログインできます。
`potgres=#`の状態になればpsqlの設定が可能です。


```:SUPERUSERの作成
postgres=# create user <ロール名> SUPERUSER;
CREATE ROLE
```
CREATE ROLEと表示されればSUPERUSER状態のロールが作成されています。

```DB作成
postgres=# create database <DB名> owner=postgres;
CREATE DATABASE
```
CREATE DATABASEと表示されればDBが作成されています。

```:DB停止
brew services stop postgresql
```

```:ログアウト
postgres=# \q
```
\ は 「option + ¥」です。

```:DB削除
消したいDB以外のデータベースにログイン状態で

postgres=# DROP DATABASE <消したいDB名>;
```

ちなみにログインしていなくても削除できます。

```:ターミナル
$ dropdb <db名>
```
性能負荷テストにおけるリトルの法則

## 最初に

システム開発において、特に大規模なリクエスト量が見込まれるアプリケーションを作成する際には、実際のリクエスト量を模擬した性能負荷テストも実施する。
過去に参加してきた性能負荷テストにおいて、目標値に関して、勘違いをして議論をしている場合があるため、この記事を書いてみた。

## スループット(TPS)と並行数

よく性能負荷テストを議論するときに、スループット(TPS)と並行数を混同して議論をしていることがある。
ここではそれぞれの言葉の定義を再度書く。

- スループット(TPS)

単位時間辺りに処理できるトランザクション数。
通常単位時間には秒を用いることが多いため、秒あたりのトランザクション数としてTPS(Transaction Per Secend)とも表現される。

スループットの値が大きいことは、多くのトランザクションが処理できていることを意味する。

- 並行数

ある時点に置いて、どれだけのトランザクションが処理されているか。
こちらは単位としては、トランザクション数である。

並行数が大きいことは、ある時間において、多くの処理が同時にできていることを意味する。

ややこしくしている原因は、スループットも並行数も大きい値は多くの処理ができていることを示す概念であることである。

実例で説明しましょう。

1つめのケースは1秒ごとに2つのリクエストが送信され、それぞれのリクエストは1秒で終了するケース。
このケースではどの時点でも並行数は2で、スループットは1秒あたり2トランザクションである。

![case1.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13808/2be7c74a-e7b3-bf5b-74a4-9f102240d1b7.png)

2つめのケースは2秒ごとに2つのリクエストが送信され、それぞれのリクエストは2秒で終了するケース。
このケースでもどの時点でも並行数は2であるが、スループットは2秒あたり2トランザクションで、1秒あたりで換算すると1トランザクションである。

![case2.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13808/0d5f0903-7296-33c4-5f91-2b61629fb0d2.png)

さて、この2つはともに並行数は2であるが、スループットには差がついた。この差の要因は、応答時間であることは一目瞭然だと思う。

まとめると以下である。並行数は変わらないが、スループットが伸びると、応答時間が少なくなっている。

|ケース |並行数|スループット(TPS)|応答時間(秒)|
|-------|-------|-------|-------|
|ケース1 |2|2|1|
|ケース2 |2|1|2|

賢明な方は気がつくと思うが、これらの数値には関係性がある。

## リトルの法則

リトルの法則とは[Wikipediaによれば](https://ja.wikipedia.org/wiki/%E3%83%AA%E3%83%88%E3%83%AB%E3%81%AE%E6%B3%95%E5%89%87)、待ち行列理論で以下の数式で表される。

```math
L = \lambda W
```

ここで、$L = 顧客数$、$\lambda = 到着数$、$W=顧客が費やす時間$ である。
この数式は待ち行列理論の意味合いで表される。そのため、一見無関係に思えるが、性能負荷テストの場合は以下の数式で表すことができる。

```math
並行数 = スループット \times 応答時間
```

先ほどのケース1/ケース2にあてはめると、下記のとおりである。

- ケース1

```math
2_{並行} = 2_{tps} \times 1_{秒}
```

- ケース2

```math
2_{並行} = 1_{tps} \times 2_{秒}
```

この2つのケースだと、簡単すぎるので、少し複雑な例を考えてみる。

![case3.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13808/56de9b54-e5ec-2dcc-8715-fa1d917c9da5.png)

この例では4並行で稼働していることはすぐに分かる。そのため、スループットと平均応答時間の乗算が4になるはずであるが、それを検証してみる。

まず、スループットは1行目8トランザクション、2行目4トランザクション、3行目2トランザクション、4行目1トランザクションの合計13トランザクションが8秒の間に到着している。つまり、$\frac{8 + 4 + 2 + 1}{8} = 15/8 = 1.875_{tps}$である。

平均応答時間は以下のとおり。(添字のtranはトランザクションの意味)

```math
\frac{1_{秒} \times 8_{tran} + 2_{秒} \times 4_{tran} + 4_{秒} \times 2_{tran} +  8_{秒} \times 1_{tran} }{15_{tran}} = \frac{32_{秒Tran}}{15_{Tran}}=2.133 秒
```

これらを掛け合わすと以下のとおり4(並行)となる。

```math
1.875_{tps} \times 2.133_{秒} \fallingdotseq 4.00_{並行}
```

これは分数で計算すると、より正確である。

```math
\frac{15}{8}_{tps} \times \frac{32}{15}_{秒} = 4_{並行}
```

## 改めてスループット/並行数/応答時間

リトルの法則をもう一度見直しみよう。

```math
並行数 = スループット \times 応答時間
```

この数式を見る限り、並行数を上げるには、スループットを上げるか、応答時間を上げるかで達成できる。
スループットを上げることで並行数が上がることは理解がしやすいと思うが、同一スループットで応答時間が上がることで並行数が上がることもイメージを持っておくことが重要である。

スループットを中心とした式は以下の通り。

```math
スループット =  \frac{並行数}{応答時間}
```

スループットを上げるには、並行数を上げるか、応答時間を **下げるか** で達成できる。これはいずれも直感どおりではないかと思う。

応答時間を中心とした式は以下の通り。

```math
応答時間 =  \frac{並行数}{スループット}
```

応答時間を **下げる** には並行数を下げるか、スループットを上げることで達成できる。応答時間を並行数やスループットと関係してイメージできることが重要である。

## まとめ

並行数/スループット/応答時間はそれぞれリトルの法則に基づき理解をすると、性能負荷検証において、より正確で深い理解ができるようになるので、是非使ってみてください。
iOS15 LocationButton

#エラー発生
* iOS15から導入された「LocationButton」普通に書くと
[Error Domain=kCLErrorDomain Code=1 "(null)] 
が出る
結局、「requestLocationAuth()」とPlistへのお約束が必要だった（XCode13にはデフォルトないけど）
確認するには「stopLocation()」で一回update Locationを止めて確認する

```swift:LocationButton
class LocationButtonViewModel: NSObject, ObservableObject, CLLocationManagerDelegate {
//その他省略
    func requestLocation() {
        locationManager.requestLocation()
    }
    func stopLocation() {
        locationManager.stopUpdatingLocation()
    }

     func requestLocationAuth(man: CLLocationManager) {

        locationManager.requestAlwaysAuthorization()
        locationManager.desiredAccuracy = kCLLocationAccuracyReduced

        switch man.authorizationStatus {
        case .authorizedAlways:
            locationStatus = "authorized always"
            checkLocationAccuracyAllowed()
        case .authorizedWhenInUse:
            locationStatus = "authorized when in use"
            checkLocationAccuracyAllowed()
        case .notDetermined:
            locationStatus = "not determined"
        case .restricted:
            locationStatus = "restricted"
        case .denied:
            locationStatus = "denied"
        default:
            locationStatus = "other"
        }
        
    }
}
struct ContentView: View {
    @ObservedObject var model = LocationButtonViewModel()
        
        var body: some View {
 
        LocationButton(.currentLocation) {
            locationVM.requestLocation()
        }

```