OmniAICreator/Qiita-1.07M huggingface dataset:
RとRStudioのインストール【Rで統計解析 準備編】

# RStudioとは？

RStudioとは、プログラミング言語であるRの統合開発環境です。ここで言う統合開発環境というのは、必要なソフトウェアをまとめて一つの画面上で操作できるようにしたものです。R本体だけでも解析を行うことは十分可能なのですが、RStudioを使うことでよりスムーズに種々のタスクが行えるといったところで、Rで解析を行うならRStudioもインストールすることを私はお勧めします。RStudio導入のメリットは、実際に触れてみることで体感してもらえるかと思います。

![スクリーンショット 2021-07-27 22.54.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/661056/91b2ddbb-8aa1-a7ca-633d-7b8bf59c75c5.png)

# Rのインストール

RStudio上で解析を行うにしても、まずはR本体をインストールする必要があります。Rのインストールは、以下のリンクにあるCRAN（The Comprehensive R Archive Network）のミラーサイト（統計数理研究所）からダウンロードします。CRANとは、R本体やそのパッケージを配布しているサイトで、今後も間接的に利用することがあるかと思います。

https://cran.r-project.org/

まずは自分のPCのOS（WindowsかMacかLinuxか）を選択します。
![スクリーンショット 2021-07-27 22.12.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/661056/1ef48a21-30f2-617b-5595-25818c9e47d3.png)

Windowsの場合、遷移先のページの **install R for the first time** をクリックします。
![スクリーンショット 2021-07-27 22.13.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/661056/f4fc9c9f-b44d-1ae6-64bd-8f046ec540d4.png)

さらに飛んだページで、**Download R (最新版のバージョン) for Windows** をクリックします。するとインストーラーがダウンロードされます。
![スクリーンショット 2021-07-27 22.16.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/661056/5b97dd25-f210-9aa9-9be4-795d5b9c1cbf.png)

Macの場合は、遷移先のページで最新版（Latest release）のインストーラーをクリックします。
![スクリーンショット 2021-07-27 22.13.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/661056/b914c688-6b6b-a93b-2eb7-2e1ec7c4e5ad.png)

Windowsの場合は**R-(versin)-win.exe**、Macの場合は**R-(version).pkg** というインストラーがダウンロードされるので、それをクリックしてインストーラーを起動します。起動したらインストーラーの指示に従ってソフトをダウンロードします。ポップアップが連続して表示されますが、「次へ (N) 」を何回かクリックしていくとインストールが行われます。

# RStudioのインストール

RStudioには、デスクトップ上のアプリケーションの「RStudio Desktop」と、サーバー上での動作を可能にする「RStudio Server」がオープンソースで提供されています。ここでは、前者の「RStudio Desktop」をインストールしていきます。

以下のRStudioのサイトにアクセスします。

https://www.rstudio.com/products/rstudio/

Open Source editionの**DOWNLOAD RSTUDIO DESKTOP** のボタンをクリックします。

![スクリーンショット 2021-07-27 22.47.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/661056/f85d0b7c-f758-2480-cddf-6197ccfedc05.png)

遷移先のページで、もう一回 **RStudio Desktop** をクリックします。

![スクリーンショット 2021-07-27 22.49.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/661056/3193095f-26ba-9366-be15-06d8c8223fb7.png)

すでにRはインストール済みなので、以下の中から自分のOSに合ったバージョンをインストールしてください。

![スクリーンショット 2021-07-27 22.52.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/661056/1dceba59-ce56-98b6-def2-a050db29bae6.png)

クリックするとインストーラーがダウンロードされると思うので、インストーラーをクリックして起動させ、先ほどと同様にインストールを行ってください。

***
以上で、基本的なソフトの準備は完了です。Macの例では、無事にインストールが済むとFinder→「アプリケーション」にRとRtudioがダウンロードされていることが確認できます。
js 3連続以上の改行を2行の改行に変換する

Twitterとかでありますよね。
連続した改行を入力しても、改行幅はマックス２行までに制限されるやつ。
ああいうやつをjsでサッと実装したいときはこれでおk

```js
let newValue = value.replace(/(\r\n){3,}|\r{3,}|\n{3,}/, '\n\n');
```


参考 [013：正規表現を使い、連続した改行コード・改行文字を取り除く](https://www.system-ido.com/risouken/index.php?page=tech&num=13)
無限ループや IndexError: list index out of range になる

**変数の値を変えて同じ動作を複数回行うなら関数を定義!**
## 期待した動作と計画
for で「リストX(固定)とリストY(可変)の[0]を比較し、一致した場合はリストYの[0]を削除する。リストXが終わるか、リストYが空になれば終了する」という動作を作成。
カウンタと while で for の動作を2回行う。リストYは変化するので、 while の前でリスト1をリストYに代入し、 while の1回目のみリスト2をリストYに代入する。
## 発生した事象
何度も無限ループや IndexError: list index out of range に陥った
## 原因
while の中の for で while や if を複数書き、break/ continue の行先が想定外のところになっていることに気付けなかった。
リストXが終わるまでにリストYが空にならなかった場合、 while でリストXの2周目が始まってしまった。
「同じ動作を複数回行うなら for/ while でループ」だと思い込んでいた。
## 対策
こまめに print して期待通りの動作か確認する。
変数をの値を変えて同じ動作を複数回行うなら関数を定義する。

### 期待した動作ができた例
```rb
sk = list(input())
a = list(input())
b = list(input())

def compare(x):
    for s in sk:
        if s == x[0]:
            del(x[0])
            if x == []:
                break
            
compare(a)
compare(b)
```
パッケージ管理とHomebrewについて

##パッケージ管理について

###パッケージとは何か？
→直訳すると一括してまとまっているものを指す。
その名の通り、
何かの処理を実行するためのファイルや
その処理などを設定するためのソースコードが記述されたファイル、ライブラリなどを１つにまとめているもののことを言います。

例えばkaminariというパッケージは
次のページ、最後のページなどのページ機能を与えてくれたりする

####もっと分かりやすく言うと
誰かが公開してくれているファイル、ライブラリなどが１つのファイルにまとまっている便利なツールのこと
→イメージ的にはマクド○ルドのビック○ックセットやケン○ッキーのお正月バーレルのようなものだったり遊○王のストラクチャーデッキ（すでにカードが入っているデッキ）みたいな感じ。

####ライブラリとは
ある特定の機能を持ったコンピュータプログラムを他のプログラムから呼び出して利用できるようにした後、複数集めて一つのファイルに収納したもののこと。
→これは直訳通り図書館をイメージするとわかりやすかったです。(たくさんの本が置いてある感じ)

###パッケージ管理システムとは?
その名の通り、パッケージの管理をしてくれる**システム**のこと。
しかしそれだけではなくパッケージの導入も行なってくれるのである！

パッケージ管理システムがあることで、
パッケージのインストール
(ハードウェアやソフトウェアをコンピュータのシステムに導入し、使えるように設定すること)や
アンインストール(使えるようにしたものを解消すること)
の作業を行なってくれる！

###整合性という利便性
パッケージ管理システムを使うことで管理内のパッケージやライブラリがお互いに関わりあった関係(依存関係)になる
→整合性（物事に矛盾が生じておらず、整っている性質）をとることができる
→整ってた方がアップデートとかにも対応しやすくて楽
→そんな楽が管理システムには存在する。

###具体的な便利機能
整合性により管理されたもののバージョンのインストール・アンインストールだけでなくアップグレードなども行なってくれたり、依存関係からアンインストールした際に関連するファイルも端末から削除してくれたりするのでデータの容量を減らせたりする
→関連するものをまとめてくれるので楽に処理できちゃう
→整合性の利便性

###様々なパッケージ管理システム
パッケージ管理ツールには様々なものが存在しますのでそれらを上げていきたいと思います。

・rubyのパッケージとしてのgem（gemを管理数るためのbundlerというツールも存在する）
・Node.jsのnpm 
・PythonのPipenv
・これから紹介するmacのパッケージ管理ツールHomebrew

##Homebrewについて
パッケージ管理システムの１つにHomebrewがある

OSによってパッケージを管理するツール（手法）が異なる。
→OS上の動作環境ごとに管理するツールを変化させる必要がある！
（例）Windows→Chocolatey
RH系のLinux→yum, dnf

そして**macOS**ではパッケージ管理ツールとして**Homebrew**が使用される
→つまりWindowsでは動作しない。

このHomebrewによってmacで様々なパッケージのインストールを行える！
→MacのPCで最初に自分好みの環境構築を行う際の第一歩としてターミナルに
homebrewをインストールする必要がある

ちなみに私はHomebrewの公式サイトとQiitaの記事を活用しながらインストールを行いました。
詳しくはこちら。

https://brew.sh/index_ja


https://qiita.com/zaburo/items/29fe23c1ceb6056109fd



またHomebrewを使用して実際にMac OSの環境構築をしたものがこちらになります。

https://qiita.com/ryutake459/items/1181f01960daef420b57
Firebase Authenticationはトークン認証を利用している話

先日、Firebaseを利用して、`Vue.js`で作ったSPA（Single Page Application）に認証機能を爆速で実装したことがあった。（[ソースコードはここ](https://github.com/shiiyan/home-life-logger/commit/7f0c0959afc121d699bd70d477a1f0d551acee09)）（[動くアプリはここ](https://shiiyan.github.io/home-life-logger/)）

Firebaseが提供する公式の[JavaScript用SDK](https://firebase.google.cn/docs/auth/web/facebook-login?hl=ja)を使うことで1時間と100行以内の実装で認証機能を作ることができた。

本記事では、Firebase SDKの裏を探り、Firebase Authenticationの仕組みを理解し、実装した感想を述べる。


## Firebase Authenticationのトークン認証仕組み

Firebase Authenticationはステートレスのトークン認証を採用している。ステートレスというのは今どのユーザーがログイン中なのかという状態をFirebaseバックエンド側が管理していないこと。

認証成功した後、Firebase Authenticationはトークンを発行し、それをブラウザーのIndexedDBに保存している。

IndexedDBについては、LocalStorageの上位版だと理解している。LocalStorageでは`Key=Value`ペアのように文字列しか保存できないのに対し、IndexedDBではJSONオブジェクトなども容易に扱える。


IndexedDBに保存されたデータを実際に見せると

![スクリーンショット 2021-08-20 22.05.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/481207/befc8113-c5c4-2a55-a919-e9102e0f2a18.png)

`stsTokenManager`の属性に`accessToken`と`refreshToken`があるのがわかる。ここの`accessToken`は内部の名前で正式の名前はFirebase ID Tokenと言われている。（https://stackoverflow.com/questions/50192454/firebase-acces-and-id-tokens）

Firebase ID TokenはFirebase Authenticationのバックエンドによって、認証プロバイダーが提供するユーザー名、パスワードなどの認証情報と控えに発行したもので、有効期間が短く、デフォルトでは一時間となっている。期限切れとなったら、Refresh Tokenを使って、新しいID Tokenを発行できる。

ID TokenはJWT（JSON Web Token）仕様である。https://jwt.io/ でトークンをデコードすると、

![スクリーンショット 2021-08-20 22.32.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/481207/e7fb0410-1da9-a4c9-5da3-441bf9abe530.png)

ペイロードにUid、ユーザー名や認証プロバイダーの情報があるのがわかる。


## トークン認証についての感想

トークン認証のステートレスの性質はFirebase中のサービスまたは複数のバックエンドサービスの間にユーザー情報を共有するのに大変役立つことを実感した。

Firebaseの例を挙げると、Firestore（Firebaseが提供するNoSQLのデータストア）に特定のデータは作成者である本人しか読み取りができないというルールを実装した場合に、読み取りリクエストの送信者の身分を確認することが必要となる。

Firebase Authenticationで認証機能を実装した場合、読み取りリクエストのヘッダーにID Tokenを含めるだけで、データストア側はトークンをバリデートし、送信ユーザーを特定することができる。

また、上記と同じ感じで、Firebase Admin SDKを利用して自作サーバーなどでもログインユーザーを特定することが容易に実装できる。（[詳細は公式ドキュメント](https://firebase.google.com/docs/auth/admin/verify-id-tokens#node.js)）

## 参考

https://firebase.google.com/docs/auth/admin/manage-sessions

https://firebase.google.com/docs/auth/admin/verify-id-tokens
Next.jsでWebアプリを作った

![スクリーンショット_2021-10-08_12-19-58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/417037/24379bdf-a0c6-1eae-dca7-24a0fd7c7f0e.png)
はてなブックマークの人気のエントリの取得と、ローカルストレージへの保存を行うWebアプリを作った。
[HateB! Reader](https://hateb-reader.vercel.app/)
[コード](https://github.com/meu29/nextjs-practice)

以下Next.jsについての備忘録。

##静的レンダリング
アプリのビルド時にレンダリングを行うこと。
表示する値を更新するにはビルドをし直す必要がある。
ブログといった全てのアクセス者に同じコンテンツを提供するWebアプリに向いている。

##getStaticProps
静的レンダリングのためにAPIなどを用いて値を取得するメソッド。

```index.tsx
import { NextPage, GetStaticProps } from "next";

const IndexPage: NextPage<{message: string}> = ({ message }) => { /* (省略) */ }

export const getStaticProps: GetStaticProps = async () => {

    return {
        props: {
            message: "ようこそ"
        }
    }

}
```
データ取得はサーバーで行うため、ブラウザからはアクセスできないCORS未対応のAPIにもアクセスできる。

##getStaticPaths
静的レンダリング + 動的ルーティングを行うためのメソッド。
下記の例ではhttp://hogehoge.com/post/001 か http://hogehoge.com/post/002 にアクセスが来た際に返すページを作成している。

```pages/post/[post_id].tsx
import { NextPage, GetStaticPaths, GetStaticProps } from "next";
import { ParsedUrlQuery } from "querystring";

type Post = {}

const PostPage: NextPage<{post: Post}> = ({ post }) => { /* (省略) */ }

export const getStaticPaths: GetStaticPaths = async () => {

    return {
        paths: [{params: {post_id: "001"}}, {params: {post_id: "002"}}]]
        fallback: false
    }

}

export const getStaticProps: GetStaticProps = async ({ params }) => {

    return {
        props: {
             /* ユーザーが定義したメソッド */
             post: getPost((params as ParsedUrlQuery).post_id as string)
        }
    }

}

```

これらのメソッドはアプリのビルド時に実行される。またpagesディレクトリに存在するコンポーネントでしか使用できない。

##API Route
今回は使わなかったが、Next.jsはAPIを作ることもできる。
以下の例は https://hogehoge.com/api/book?book_id=001 にリクエストを受けた時の処理である。

```pages/api/book/index.ts
import { NextApiRequest, NextApiResponse } from "next";

export default async (req: NextApiRequest, res: NextApiResponse) => {
    /* リクエストメソッド */
    console.log(req.method)
    /* クエリ 001 */
    console.log(req.query.book_id);
    /* postリクエストなどでリクエストボディを受け取る場合 */
    /* console.log(req.body.xx) */
    /* ここでローカルDBからデータを取ってくることもできる */
    return res.status(200).json({books: []});
}

```
https://hogehoge.com/api/book/new にしたい場合は同じディレクトリにnew.tsを作れば良い。
【Swift】テキストフィールドの入力を数字のみ可能にする方法

結論から書くとこちら。

        //Outlet接続する
        @IBOutlet weak var textField: UITextField!

        //textFieldのキーボードタイプを数字のみに変更する
        textField.keyboardType = UIKeyboardType.numberPad

　
これでビルドするとテキストフィールドが数字のみ入力可能となります。
既にUITextFieldをOutlet接続しているという方はこちら。


    //textFieldのキーボードタイプを数字のみに変更する
    textField.keyboardType = UIKeyboardType.numberPad
　

またほとんどの方がtextField.keyboardTypeの所のtextFieldの部分の名前が違うと思うのでこちらを参考に修正してください。
　

例えば年齢のtextFieldを作成していた場合はこうなります。

        //Outlet接続する　　　　　　　　　　　　↓ここを修正
        @IBOutlet weak var ageTextField: UITextField!

        //textFieldのキーボードタイプを数字のみに変更する
       　　　 ↓ここを修正
        ageTextField.keyboardType = UIKeyboardType.numberPad

　

またOutlet接続がうまくいってないので表示されないといった場合はこちらの記事を参考にしてください。

https://capibara1969.com/1253/#toc8
Flutter Expected to find '}'.dart(expected_token)を解決した１例

#謎のエラーExpected to find '}'.
なんだこれは？？？

```dart
import 'package:firebase_auth/firebase_auth.dart';
import 'package:cloud_firestore/cloud_firestore.dart';

// 省略

User get user => _user;

// 省略
Future<void> signInAnonymously() async {
  await _auth.signInAnonymously().then((UserCredential userCredential) => {
         _user = userCredential.user; // ここでエラー！！！
            FirebaseFirestore.instance
                .collection('users')
                .doc(_user.uid) // 匿名ログインした時にuidをFirestoreに保存したい
                .set({'uid': _user.uid,})
          });
 }
```

Firebaseで匿名ログインした時に`uid`をFirestoreに保存したいので、上記のようなコードで試してみようとしたが、、、

なんかエラーが発生しました。。。

#`=>`が不要なようです。。

```dart
 await _auth.signInAnonymously().then((UserCredential userCredential) {
        _user = userCredential.user;
        FirebaseFirestore.instance
            .collection('users')
            .doc(_user.uid)
            .set({'uid': _user.uid, });
      });
```




#参考
returns void（つまり何も返さない）だと`=>`は付けない、という認識でいいのかな？？:sweat_smile:

```dart
Map foo() => {'key': 'value'}; // returns Map
void bar() { print('just executes set of instructions'); } // returns void
```

https://stackoverflow.com/questions/62830817/flutter-expected-to-find-in-if-else-condition
思考を整理する方法

何かを考えなくちゃいかない時に、うまく考えがまとまらない時の対処法を共有したいと思います。

思考がうまくまとまらない場合の多くの原因は考えなくちゃいけないことが渋滞していることです。
それを解決するためにはタイトルの通り、思考を整理する必要があります。

数ある思考の整理の方法の一つを紹介できればと思います。


#思考を可視化する

思考を整理する上で大切なのは思考と情報を可視化することです

頭の中がモヤモヤしている原因の多くは「頭の中だけで考えてしまい、何について悩んでいるか分からなくなってしまう」という状況から引き起こされるものだからです。

つまり、悩んでいる原因を目に見える形にする「可視化」をしていないため、頭の中でぐるぐると考え、悩んでしまうと言えます。

そのため、メモやノートにモヤモヤしていることを書き出して、「可視化」することが重要になります。

#思考を分類する

思考と情報が可視化出来ているのに整理が出来ない人は、「分類」を行えていないかもしれません。
 
モヤモヤを書き出しただけでは、思考と情報の「整理」が出来たとは言えません。
きちんと整理するためには、思考と情報を「プライベート」や「仕事」に分け、さらにそこから細分化する必要があります。
 
こうした作業を思考の分類と言います。
 
分類を行うことで、自分がどこで何に悩んでいるのかをハッキリさせることができ、思考と情報を「整理」できるようになります。

#解決策を考える
思考を整理する時には、何かの問題についての解決策を考える必要があるケースも存在します。
 
例えば、「仕事があまりうまくいかない」という悩みを書き出し、その悩みを「仕事」に分類したとします。
 
この分類で終わりにしてしまっては、一時的に頭の中をすっきりさせるだけで、問題に対する根本的な解決にはなりません。
 
そこで、「仕事で思うような成果が出ない」という悩みに対する「解決策」を考える必要性があります。
 
このように、問題の解決策にまで目を向けることで、思考を整理することができるようになります。
SageMaker Studio で他人の App を削除させない

# 概要

前回「[特定の IAM ユーザにだけ SageMaker Studio のユーザを使えるようにする](https://qiita.com/harusamet/items/f09a1d471f1d394269aa)」からの続きで SageMaker Studio を使う IAM ユーザの権限についてです。

AmazonSageMakerFullAccess 権限があると SageMaker Studio の他のユーザの App を消すことができます。App は Jupyter ノートブックの Docker image のようなものなので、再度ノートブックを起動すれば App は戻ってきますが、途中の実行結果などメモリにあった情報は消えてしまいます。App が多すぎて消したい場合に、誤って他人の App を消してしまわないよう、DeleteApp を自ユーザの App に対してのみ実行できるようにします。

削除画面（deleteと入力して Deleteボタンポチーであっさり消えます）
![Amazon_SageMaker_-__Private_Browsing_2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/279199/fad8c069-be00-8f00-7cee-6e062d45bd9e.jpeg)


# DeletApp で削除する App をどのように指定するのか確認

SageMaker の以下の Doc をみると DeleteApp で指定できる内容が記載されています。

https://docs.aws.amazon.com/ja_jp/service-authorization/latest/reference/list_amazonsagemaker.html

**Amazon SageMaker で定義されるアクション**の表から `DeleteApp` を探します。App*というのを指定できるみたいですね。このリンクをクリックすると同ページの App の説明に飛べます。

![Amazon_SageMaker_のアクション、リソース、および条件キー_-_サービス認証リファレンス.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/279199/a1d1a13e-b843-6170-0a72-2f5dfbdaa362.jpeg)

飛んだ先はこちらですね。このように App の ARN を指定して削除するようです。

![Amazon_SageMaker_のアクション、リソース、および条件キー_-_サービス認証リファレンス.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/279199/9084b3ac-ad01-65dd-4a2d-19e0a288568a.jpeg)

今回だと特定のStudio のユーザ（前回の記事では restricted-user)のみを消すようにしますので、東京リージョン、アカウントID 123456789012、ドメインが d-XXXXXXxxxxxx, ユーザープロファイルが restricted-user なら以下のようになります。ワイルドカードを入れて、`restricted-user`以下のAppを指定します。

```
arn:aws:sagemaker:ap-northeast-1:123456789012:app/d-XXXXXXxxxxxx/restricted-user/*
```

# IAMユーザにポリシーを追加

前回「[特定の IAM ユーザにだけ SageMaker Studio のユーザを使えるようにする](https://qiita.com/harusamet/items/f09a1d471f1d394269aa)」と同様に IAM ユーザの画面からインラインポリシーを追加します。追加するのは `restricted-user`以外のAppに対する DeleteApp を Deny するポリシーです。表現はややこしいですがポリシーは以下のとおりです。上記に従って、リージョンなどはいれてくださいね。

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Deny",
            "Action": "sagemaker:DeleteApp",
            "NotResource": "arn:aws:sagemaker:(region):(account_id):app/(domain_id)/(user_mame)/*"
        }
    ]
}

```

こんな感じで追加しましょう。

![スクリーンショット 2021-08-20 21.53.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/279199/26aaf40e-4360-3cc3-59e3-53933229824d.png)


# 試してみましょう

他のユーザの App を消してみようと思います。
![スクリーンショット 2021-08-20 22.12.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/279199/b175cf79-5f19-9e4f-109e-e43234ef1863.png)

delete を押すと権限でエラーが出ました。DeleteApp が許可されていないことがわかりましたね。

![Amazon_SageMaker_-__Private_Browsing_del.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/279199/f0cf38f2-1110-8441-fa49-79489fa2da35.jpeg)

# さいごに
コンソールでアクセスさせる場合には、AmazonSageMakerFullAccess にしておいて、他人のユーザを使わせないのと、他人のAppを消させないようにしておけばいいかなと思います。ドメインの削除、ユーザの新規作成・削除はAmazonSageMakerFullAccessではできないので、指定したユーザのみを使用するだけにできると思います。
PostgreSQL メモ

PostgreSQLを起動。

```
$ brew services start postgresql
```

起動出来たか確認。

```
$ brew services list
```

postgres(databaseの名前)に入る

```
$ psql postgres
```

postgres(userの名前)を作成

```
postgres=#　create user postgres SUPERUSER;
```

sampleって名前のdatabase作成

```
postgres=#　create database sample owner=postgres;
```

作ったら、`exit`で一度抜けてpostgres(ユーザ名)でsample(DB名)に入りなおす。

```
psql sample -U postgres
```

PostgreSQLを停止。

```
brew services stop postgresql
```
do...endと{}について

# do...endと{}について
JavaやC言語などは繰り返し処理の場合、for文を使うことが多いと思いますが、
Rubyの繰り返し処理は、eachメソッドを使うことが多いです。

## do...endの場合
配列の要素を加算する処理
eachメソッドで配列の要素を順番に取り出す作業を行い、その要素の処理はdoからendまでのブロックに記述します。


```Ruby:do...end
numbers = [1, 2, 3, 4]
sum = 0
numbers.each do |n|
  sum += n
end
sum #=> 10
```

上記の場合、配列の中から要素1，2，3，4を順番に取り出して、sum += nで各要素を加算する。


##{}の場合
do...end以外に{}でもブロックを作ること出来ます。

```Ruby:{}
numbers = [1, 2, 3, 4]
sum = 0
numbers.each do { |n| sum += n }
sum #=>　10
```

##まとめ
do...endと{}の使い分けは明確に決まっているわけではありません。
ただ、下記のように使い分けられるケースが多いです。
<br>

**・改行を含む長いブロックを書く場合は、do...end**
**・1行でコンパクトに書きたいときは、{}**
<br>
<br>
####参考文献
プロを目指す人のためのRuby入門・・・伊藤淳一[著]
【初心者向け】Laravelの命名規則

#はじめに
プログラミング始めたての頃は（自分もそうですが）、メソッドやテーブル名などを記述するとき、頭文字が大文字なのか、単語はアンダースコアでつなぐのかなどと迷ってしまいますよね。
適当に分けているのではなく、ちゃんと命名規則があるので、それにしたがって記述していくことになります。

#記述方法について
###①アッパーキャメルケース
単語の先頭の文字はすべて大文字で記述する。
例）ShoppingCart
###②ローワーキャメルケース
先頭は小文字だが、続きの単語の先頭は大文字で記述する。
例）shoppingCart
###③スネークケース
単語と単語をアンダースコアでつなぐ。
例）shopping_cart
###④ケバブケース
単語と単語をハイフンでつなぐ。
例）shopping-cart

#Laravelでの使用方法について
| 種類 | 記述方法 | 単数 | 複数 |
|:----------:|:-----------:|:------------:|:------------:|
| モデル       | アッパーキャメル        | 〇         | ×         |
| コントローラー     | アッパーキャメル      | 〇       | 〇         |
| シーダー       | アッパーキャメル        | ー         | ー         |
| メソッド         | ローワーキャメル          | ×           | 〇         |
| bladeテンプレート       | スネーク       | ー       | ー         |
| 変数    | スネーク     | ー         | ー         |
| テーブル    | スネーク     | 〇         | ×         |
| マイグレーションファイル    | スネーク     | ー      | ー         |

#おわりに
学習を重ねてたくさんコードを書くと、覚えようとせずとも自然に記述方法が分かるようになると思うので、早くその領域にたどり着けるようコーディングしまくりましょう。
ffmpegで動画ファイルから音声ファイルを抽出する方法


ffmpeg便利ですよね。ただ毎度使い方を忘れるので備忘録として残します。

ffmpeg導入されていない方は、macの場合brewで一発で入ります。

```
brew install ffmpeg
```

## 入力の動画ファイルの情報を確認

```
$ ffmpeg -i input.mp4

ffmpeg version 4.4 Copyright (c) 2000-2021 the FFmpeg developers
  built with Apple clang version 12.0.5 (clang-1205.0.22.9)
  configuration: --prefix=/usr/local/Cellar/ffmpeg/4.4_2 --enable-shared --enable-pthreads --enable-version3 --cc=clang --host-cflags= --host-ldflags= --enable-ffplay --enable-gnutls --enable-gpl --enable-libaom --enable-libbluray --enable-libdav1d --enable-libmp3lame --enable-libopus --enable-librav1e --enable-librubberband --enable-libsnappy --enable-libsrt --enable-libtesseract --enable-libtheora --enable-libvidstab --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxml2 --enable-libxvid --enable-lzma --enable-libfontconfig --enable-libfreetype --enable-frei0r --enable-libass --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-libspeex --enable-libsoxr --enable-libzmq --enable-libzimg --disable-libjack --disable-indev=jack --enable-avresample --enable-videotoolbox
  libavutil      56. 70.100 / 56. 70.100
  libavcodec     58.134.100 / 58.134.100
  libavformat    58. 76.100 / 58. 76.100
  libavdevice    58. 13.100 / 58. 13.100
  libavfilter     7.110.100 /  7.110.100
  libavresample   4.  0.  0 /  4.  0.  0
  libswscale      5.  9.100 /  5.  9.100
  libswresample   3.  9.100 /  3.  9.100
  libpostproc    55.  9.100 / 55.  9.100
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'input.mp4':
  Metadata:
    major_brand     : mp42
    minor_version   : 1
    compatible_brands: isommp41mp42
    creation_time   : 2021-07-08T07:51:40.000000Z
  Duration: 00:00:25.91, start: 0.000000, bitrate: 2099 kb/s
  Stream #0:0(und): Video: h264 (Constrained Baseline) (avc1 / 0x31637661), yuv420p, 1920x1080, 1964 kb/s, 29.97 fps, 30 tbr, 90k tbn, 60 tbc (default)
    Metadata:
      creation_time   : 2021-07-08T07:51:40.000000Z
      handler_name    : Core Media Video
      vendor_id       : [0][0][0][0]
      encoder         : h.264
  Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, mono, fltp, 43 kb/s (default)
    Metadata:
      creation_time   : 2021-07-08T07:51:40.000000Z
      handler_name    : Core Media Audio
      vendor_id       : [0][0][0][0]
```

ここから `Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, mono, fltp, 43 kb/s (default)` というaudioの部分に着目すると下記の情報が得られます。

- `48000 Hz`: サンプリング周波数が48 kHz
- `mono`: モノラル
- `fltp`: 内部フォーマットが Single-precision floating point（単精度浮動小数点 32bit）
- `43 kb/s`: ビットレート（音声ビットレート＝サンプリングレート×ビット深度）

## いざ動画ファイルから音声ファイルを抽出

```
ffmpeg -i input.mp4 -ac 1 -ar 48000 output.wav
```

- `-ac 1`: 入力音声がモノラルだったので、チャンネル数は1を指定。当たり前かもですがステレオの時は代わりに2を指定します。
- `-ar 48000`: 入力音声のサンプリング周波数が48kHzだったのでそのまま指定。

以上です。簡単ですね！ 困ったら `ffmpeg -h` でオプション確認してみてください！
特定キーワードを集計する_その１

指定範囲から集計した値を出す
====

今回は指定範囲のセルからキーワードになる文字列が
いくつあるかを集計することができるCOUNTIFの関数を紹介します。

見本として〇×判定した回答結果に見立てたデータを用意しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1879772/f81fe85f-ca8d-dc54-c506-11f583322d8d.png)


Excel関数
------
関数で集計する場合の書き方

```ecl
=COUNTIF(範囲,対象キーワード)

入力例
=COUNTIF(B:B,"〇")

```

B列全体からセルの中身が"〇"であるセルを集計してくれます。
同じように今度は×を集計したい場合は、
"検索キーワード"を"×"にすれば
回答結果の集計がすぐに終わります。

集計結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1879772/b5efb61b-5abb-cd5c-315d-c0d49572c259.png)


では次のような果物の一覧から
"リンゴ"がいくつあるかを集計してみましょう。
ただしリストには"青リンゴ"と"赤リンゴ"も同じく集計対象とします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1879772/9ef316e3-5112-ed0e-894a-4e9d6d6c0ee7.png)


この場合、上記で紹介した関数をそのまま使用しても
"青リンゴ"と"赤リンゴ"は集計対象に含まれません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1879772/ca436386-1e32-9332-39a7-99ed766c63d8.png)


解決策としては"検索キーワード"にワイルドカードを使います。

今回はリンゴの前にどのような文字があっても"リンゴ"が含まれれば良いのですが、
見本なので、前後にワイルドカードを付けて、"リンゴ"が含まれていれば
集計対象とする。という形で紹介します。

```ecl
入力例
=COUNTIF(B:B,"*" & "リンゴ" & "*")

```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1879772/3c72a1c9-80ac-1dd9-54f9-2b000e857513.png)


このようにワイルドカードを前後に付けたりする事で、
単純なキーワードのみではなく、幅広く集計する事が可能です。

COUNTIF関数は色々なところで使えて便利ですが、
関数を入れたままフィルターをかけなおしたりすると
関数計算を再度実行されます。

意外に処理が重い事が多いので、
数値化して問題なければ、値貼り付けして
普通の数字にしてしまう事をオススメします。




ExcelVBA
------

VBAで抽出する場合の書き方

```vb
結果 = WorksheetFunction.CountIf(範囲,対象キーワード)
```

書き方としては"WorksheetFunction"を含めれば
同じ使い方が可能です。
"WorksheetFunction"はとっても便利ですｗ

では実際のコード例ですが、今回は指定の範囲を2行目から最終行までとし、
最終行の値もマクロ内で取得して変数に入れるようにします。

```vb
Sub 集計()

    'セルのB列全部の"〇"を集計して、E2に出力する
    Cells(2, 5) = WorksheetFunction.CountIf(Range("B:B"), "〇")

    '確認用のメッセージボックス
    MsgBox Cells(2, 5)

End Sub
```
新しく出てきた"Range"ですが、
エクセルの関数で使ったりするココからココまでだよって意味です。
今回は例としてB列全体を指定しましたが、
変数の値を使って入れたい場合の入力例も後述で紹介します。

実行結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1879772/7bb3ef14-b08f-b045-20a6-112de250b0dc.png)

最終行をプログラムを使って取得して変数として入力し、
"範囲"に反映させるやり方を一例として紹介します。

```vb
Sub 集計()

    '変数名"x"をVariant方式で指定します
    Dim x As Variant
    
    '変数"x"にB列の最終行を調べる、B列なので2です
    x = Cells(Rows.Count, 2).End(xlUp).Row

    'セルのB2からB列の最終行までの"〇"を集計して、E2に出力する
    Cells(2, 5) = WorksheetFunction.CountIf(Range(Cells(2, 2), Cells(x, 2)), "〇")

    '確認用のメッセージボックス
    MsgBox "B列の最終行は" & x & "行目"

End Sub

```
変数"x"にB列の最終行が何行目か確認して、
"範囲"にあたるRangeのココまでだよの所に変数"x"を指定します。
参考画像では最終的に"x"の変数は21になっています。


実行結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1879772/b108a0f2-0085-be4d-22e7-e312a9e35799.png)

メッセージボックスの内容を最終行を求めた結果を出力するように修正して実行させました。
前述した通り、変数"x"は21になっている事がわかります。

最終行を取得する動きですが、
詳しい説明は次回説明します。（これだけで長くなります）
基本情報技術者試験0820

本日の積み上げ結果
基本情報技術者試験勉強
平成22年春過去問
平成22年秋過去問
間違えた問題の復習
AWSの本を読む

リスク移転　保険に加入するなどで他者と損失の負担を分担すること。

ニューメリックチェック　数値として扱う必要のあるデータに，数値として扱えない文字のようなものが含まれていないかどうかをチェックする。

Ajax  JavaScriptの非同期通信の機能を使うことによって，動的なユーザインタフェースを画面遷移を伴わずに実現する技術。

システムインテグレータ　情報システムの企画，構築，運用などの業務を一括して請け負う。

デイジーチェーン接続　IEEE1394接続コネクタが2口ある工業用カメラを数珠つなぎにし，一端をPCに接続する。

組込みシステムの特許におけるライセンスに関する記述　新開発した組込み製品のハードウェア部分だけが，他社の特許に抵触している場合，その部分のライセンスを得ないと権利侵害になる。

EUC 利用者自身が，表計算ソフトや簡易データベースなどを活用し，業務を遂行することである。

サプライチェーンマネジメント　購買，生産，販売及び物流を結ぶ一連の業務を，企業間で全体最適の視点から見直し，納期短縮や在庫削減を図る。

セル生産方式　部品の組立てから完成検査までの全工程を，1人又は数人で作業する。

経営者が社内のシステム監査人の外観上の独立性を担保とするために講じる措置　システム監査人の所属部署を経営者の直轄とする。

3次元グラフィック処理におけるクリッピング　画像表示域にウィンドウを定義し，ウィンドウ内の見える部分だけを取り出す処理である。

スラッシング　仮想記憶方式では，割り当てられる実記憶の容量が小さいとページアウト，ページインが頻発し，処理能力が低下することがある。

けた落ち　値がほぼ等しい浮動小数点同士の減算において，有効けた数が大幅に減ってしまうことである。

リスク識別　複数の専門家から得られた匿名の見解を要約して，再配布することを何度か繰り返して収束される。

社内ベンチャ組織　プロジェクトを準独立的な事業として遂行し，その成果に対して全面的な責任を負う起業者としての権限と責任を与えられる組織構造。

CRC方式　送信側では，ビット列をある生成多項式で割った余りをそのビット列に付加して送信し，受信側では，受信したビット列が同じ生成多項式で割り切れるか否かで誤りの発生を判断する誤り検査方式。

ヒストグラム　収集したデータを幾つかの区間に分類し，各区間に属するデータの個数を棒グラフとして描き，ばらつきをとらえる。

フラッシュメモリ　データの書き換え時には，あらかじめ前のデータを消去してから書き込みを行う。
【Java】【Ruby】配列内の偶数を数える

　とても簡単ですが、RubyとJavaで、配列内の偶数を数えるプログラムを作りました。「配列を引数として渡すにはどうしたら良いのだろう」という疑問からひとまず作ったものです。

## Ruby

```ruby
def count_evens(nums)
  count = 0
  nums.each do |num|
    if num.even?
      count += 1
    end     
  end
  puts count
end

count_evens([2, 1, 7, 8, 2, 3, 4])
count_evens([2, 2, 6, 5, 0]) 
count_evens([1, 3, 11, 5])
```

## Java

- メソッドを定義したクラス

```java
package example;

public class CountNums {
	void countEvens(int[] nums) {
		int count = 0;
		for(int num : nums) {
			if (num % 2 == 0) {
				count++;
			}
		}
		System.out.println(count);
	}

}
```

- メソッドを呼び出すクラス

```java
package example;

public class UseCountEvens {
	public static void main(String[] args) {
		CountNums n = new CountNums();
		int[] nums1 = {2, 1, 7, 8, 2, 3, 4};
		int[] nums2 = {2, 2, 6, 5, 0};
		int[] nums3 = {1, 3, 11, 5};
		
		n.countEvens(nums1);
		n.countEvens(nums2);
		n.countEvens(nums3);
	}

}
```

　以上です。
<br>
本番環境でCSSだけが反映されていない

##はじめに
DockerとCircleCIを用いた本番環境で、修正を加えてデプロイすると、CSSだけが反映されていないことに気づきました。

CSS全く機能していないのではなく、修正した箇所が反映されていないという事象です。
完全な解決ではないですが、とりあえず反映させることはできましたので残しておきます。

##解決策

まず疑ったのは、キャッシュが残っているのではないかと思いました。
スーパーリロードとシークレットウィンドウで本番環境を試しましたが、効果なし。

また、HTMLの変更点は反映されているため、コンパイルが怪しいと思いました。
（dockerとcircleciを導入する際にかなりてこずったところでもあったので、特に怪しいと感じました。）

取り急ぎ解決策としては

ターミナルからデプロイしているEC2へ行き、自分のアプリに移動して一度precompileしたものをを削除します。

```terminal
$ docker-compose run web bundle exec rails assets:clobber RAILS_ENV=production
```

そしてprecompileをします。

```terminal
$ docker-compose run web bundle exec rails assets:precompile RAILS_ENV=production
```

あとは下記のコマンドです。
実際はCircleCIに組み込んでいるので、gitにpushするだけで下記のものたちは自動で実行されていますが。

```
sudo git pull origin master

docker image prune -f

docker-compose down

docker-compose build

docker-compose up -d'
```

これで私の場合は解決しました。
原因としてはprecompileがうまくいっていないことだと思います。

参考: https://qiita.com/nakamasato/items/00ae23b7fdf0c69b57c5
【SwiftUI】Color.clear / opacity(0)のビューのジェスチャーが反応しない問題

#課題
ビューやパスに対して Color.clear や opacity(0) を設定した場合
タッチジェスチャーなどが反応しなくなります。

```swift
Rectangle()
    .fill(Color.clear) // or .fill(Color.red.opacity(0))
    .frame(width: 100, height: 100)
    .onTapGesture {
        print("On tap") // 呼ばれない
    }
```

#解決法
### 「.contentShape(Rectangle())」 を追加

```swift
Rectangle()
    .fill(Color.clear) // or .fill(Color.red.opacity(0))
    .frame(width: 100, height: 100)
    .contentShape(Rectangle())
    .onTapGesture {
        print("On tap") // 呼ばれる
    }
```

###VStack / HStack / ZStack に関しても同様

```swift
ZStack{}
    .frame(width: 100, height: 100)
    .contentShape(Rectangle())
    .onTapGesture {
        print("On tap") // 呼ばれる
    }
```
光造形3Dプリンタのよくある失敗と対策一覧

最近光造形3Dプリンタを買ったのですが、数多くの失敗とそれと同じだけの克服がありました。
後続のためにここへ概要を書いておきます。

## サポート周りの破断

![IMG_2753.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30316/4b148934-37c6-38e7-f73d-5dffeffe57fe.jpeg)

概ねサポート周りが弱い。サポートの根本・太さ・先を強化したりラフトを強化することで解決できそう。
僕の場合はラフト追加で解決。

## サポートからモデルが脱落

![IMG_2769.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30316/43ba638a-fbe4-e980-7f69-293d805773d7.jpeg)

サポートが弱い。サポートの根本・太さ・先を強化したりラフトを強化することで解決。
僕の場合は総合的にサポートの太さを強化して解決。

## ラフトしか印刷されない

![IMG_2772.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30316/d1416193-1d98-181b-1690-653e5ee42435.jpeg)


いわゆるラフトシルエット([customer\_v2](https://support.formlabs.com/s/article/Raft-Silhouette?language=ja))。
リンク先に書かれている通り以下の対策がある。

1. レジンのフィルタリング
1. Z軸公正
1. LCDディスプレイ
1. フィルムをアルコールタオルで拭く

うちではすべてやった結果成功するようになったのでどれが問題だったのかは不明。

## 立方体の頂点などが欠ける

![IMG_2789.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30316/e1a9d788-52d7-45d6-6189-6f1cf5f9e447.jpeg)

本来きちんとエッジが出るはずの角が印刷されない。削れてしまう。

まず、そもそも角が印刷範囲から外れていた場合があった。chituboxは印刷範囲から物体がはみ出ている警告があったがlycheeはそれがなかったため気づかなかった。この場合は物体の印刷位置を調整して解決。
もう1つのケースでは印刷範囲には問題がなかったため、頂点へサポートをつけることで解決した。

## 印刷後、固まりきっていないレジン部分が残ってしまった

![IMG_2820.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30316/596b69fb-54f6-11e8-16c2-9bd40a57190c.jpeg)

写真の布の造形のエッジの部分。洗浄が足りず固まりきらなかったレジンが残ったまま二次硬化してしまった。

対策として、超音波洗浄機と非常に柔らかいハケ(elegooレジンに毎回1つついてくるやつ)で丁寧にレジンを落とした。

## できたもののの面が付箋のように剥がれる

![IMG_2810.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30316/afb0cf84-3e4b-7d46-71eb-4825827c95ad.jpeg)

原因は造形物の面がレジンの水面と水平に近いため。光造形3Dプリンタはレジン水面と水平方向に0.0x mmの面を積み重ねて立体造形物を作る。そのため造形物の面がレジンの水面と水平に近いとサポート材があっても印刷面が動いてしまい画像のように付箋上に剥がれてしまう。
対策として面をレジン水面と水平ではなく、常に20度以上の確度をつけるようにすることで解決した。

## 印刷物が反ってしまう

![IMG_2844.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30316/64299199-5a1d-c69f-9312-958fd625d1c6.jpeg)

図のように板状のものを印刷した際、本来直線であるはずの面が反って丸まってしまう。

[SK本舗ユーザーのリレーコラム＃05「3Dプリンターで水洗いレジンを使用した際の反り対策と模型制作を考える」（今井誠）](https://skhonpo.com/blogs/blog/usercolumn05)に書かれた角度をほぼ立てにする方法で解決できた。

## サポートを外した場所が凹んでしまう

サポートを外したときに造形物側がえぐれてしまい、ヤスリをかけてもサポート痕が消えない。

対策は<a href="https://www.chitubox.com/en/article/support/indepth/technology/23">Contact Shape Comparison of Support Structures in SLA/DLP/LCD 3D printing</a>で説明されているcontact shapeのsphere化がよい。これによってえぐれることがなくなり、ヤスリがけをするとキレイにサポート痕が消える(プラモデルでランナーからパーツを切り離すとき、ランナーとパーツのコンタクトポイントより少し手間をニッパーで切ってその後ヤスリなどで整えるのと同じテクニック)
ブラウザのよくわからない挙動


#どんな挙動？

*tr*,*th*,*td*が消滅してしまう

#状況

テンプレートとして用意したタグの中から

*tr*,*th*,*td*タグがすっぽり消滅してしまう

##例

ソース

```html
<table>
 <tbody>
 </tbody>
</table>

<div id="template">
 <tr>
  <th>日付</th>
  <td><a href="http://map.html">場所</a></td>
  <td>
   <p>注意事項</p>
  </td>
 </tr>
</div>
```

ブラウザ上

```html
<div id="template">
  <a href="htpp://map.html">場所</a>
  <p>注意事項</p>
</div>
```

なぜか*tr*,*th*,*td*が無くなっている

#解決策

1. id templateのタグを*div*ではなく*table*にする

```html
<table id="template">
 <tr>
  <th>日付</th>
  <td><a href="http://map.html">場所</a></td>
  <td>
   <p>注意事項</p>
  </td>
 </tr>
</table>
```

これで意図通りに動いてくれました。

#あとがき

頻繁にとは言わないけれど、それなりに使う状況ありそうなものだけれど、この挙動についての記事を探してみたけれど見当たらず
みんな躓かないのかな～？
こんなことで３時間も潰してしまったので３年ぶりに吐き出してみました。
３年前とあまり書いているレベルが変わっていないような＾＾；
それでもまあ開発は順調に進んでいます。

初めはjQuery.clone()不具合のような記事を書きましたが
@nishimura さんにご指摘いただきブラウザの挙動によるものとわかり全体的に修正を入れてあります。

@nishimura さん
ありがとうございました！
AI分野で必須の知識：誤差逆伝播法(バックプロパゲーション)の基礎について学習

今回の記事では、誤差逆伝播法(バックプロパゲーション)について、Udemyの講座にて学習した内容を要約する。なお、本記事に掲載しているコードは、すべて下記URLに掲載しているUdemy講座から抜粋している
 - 事前にUdemy講座の講師から許可を頂いています。

Udemy講座URL
[みんなのAI講座 ゼロからPythonで学ぶ人工知能と機械学習 【2021年最新版】](https://www.udemy.com/course/learning-ai/)

#目次

[1.誤差逆伝播法(バックプロパゲーション)の概要](#1-誤差逆伝播法(バックプロパゲーション)の概要)
[2.出力層の学習](#2-出力層の学習)
[3.中間層の学習](#3-中間層の学習)
[4.学習部分の実装コード](#4-学習部分の実装コード)

#1-誤差逆伝播法(バックプロパゲーション)の概要

 - 順伝播：入力→出力　分類で使用
 - 逆伝播：出力→入力　学習で使用
    - 誤差逆伝播法(バックプロパゲーション)
        - 出力と正解の誤差を小さくするように重みとバイアスを更新
 - 誤差逆伝播法は出力から入力に向けて学習が進むため、
初めに出力層から説明すると理解が深まる
 - 本記事ではニューロン数が入力層2、中間層3、出力層1で実装する


#2-出力層の学習

 - δ_0 = (出力 - 正解) × 活性化関数の微分系
 - 重みの修正量 =  - 学習係数 × δ_0 × 入力
 - バイアスの修正量 = - 学習係数 × δ_0 

#3-中間層の学習

※中間層部分の説明は文章表現では限界がありますが、ご了承ください。

 - 中間層が一つの場合
    - δ_m = δ_0 × 出力層にかける重み × 活性化関数の微分系
    - 重みの修正量 = - 学習係数 × δ_m × 入力
    - バイアスの修正量 = - 学習係数 × δ_m
 - 中間層が二つの場合
    - δ_m1(中間層1) = δ_m2(中間層2) ×　出力にかける重み　×　活性化関数の微分系
    - 中間層1の重みの修正量 =  - 学習係数 × δ_m2　× 入力
    - 中間層1のバイアスの修正量 = - 学習係数 × δ_m2
 - δを、入力に近い層に順番に渡していくイメージ

#4-学習部分の実装コード

 - train部分のコードを下記の通り示す
    - 各層のニューロン数
        - 入力層 : 2
        - 中間層 : 3
        - 出力層 : 1
    - 活性化関数としてシグモイド関数を使用する
        - 通常は中間層ではシグモイド関数ではなく、ReLu関数を用いる
            - 勾配消失問題が発生するため
        - シグモイド関数の説明は[別の記事](https://qiita.com/YuSAS/items/b78d9e5069731bd73980)に記載

```Python
   def train(self, correct):
      # 学習係数
      k = 0.3

      # 出力層の出力
      output_o = self.output_layer[0].output
      # 中間層の出力
      output_m0 = self.middle_layer[0].output
      output_m1 = self.middle_layer[1].output
      output_m2 = self.middle_layer[2].output

      # δ_0 = (出力 - 正解)×活性化関数の微分系(今回はシグモイド関数を使用)
      delta_o = (output_o - correct) * output_o * (1.0 - output_o)
      # δ_m = δ_0 × 出力層にかける重み × 活性化関数の微分系
      delta_m0 = self.w_mo[0][0] * output_m0 * (1.0 - output_m0)
      delta_m1 = self.w_mo[0][1] * output_m1 * (1.0 - output_m1)
      delta_m2 = self.w_mo[0][2] * output_m2 * (1.0 - output_m2)
      
      # 出力層の重みの修正量 =  - 学習係数 × δ_0 × 入力
      self.w_mo[0][0] -= k * delta_o * output_m0
      self.w_mo[0][1] -= k * delta_o * output_m1
      self.w_mo[0][2] -= k * delta_o * output_m2
      # 出力層のバイアスの修正量 = - 学習係数 × δ_0
      self.b_o[0] -= k * delta_o

      # 中間層の重みの修正量 = - 学習係数 × δ_m × 入力
      self.w_im[0][0] -= k * delta_m0 * self.input_layer[0]
      self.w_im[0][1] -= k * delta_m0 * self.input_layer[1]
      self.w_im[1][0] -= k * delta_m1 * self.input_layer[0]
      self.w_im[1][1] -= k * delta_m1 * self.input_layer[1]
      self.w_im[2][0] -= k * delta_m2 * self.input_layer[0]
      self.w_im[2][1] -= k * delta_m2 * self.input_layer[1]
      # 中間層のバイアスの修正量 = - 学習係数 × δ_m
      self.b_m[0] -= k * delta_o
      self.b_m[1] -= k * delta_o
      self.b_m[2] -= k * delta_o

```

#参考文献

[みんなのAI講座 ゼロからPythonで学ぶ人工知能と機械学習 【2021年最新版】](https://www.udemy.com/course/learning-ai/)
競プロのデータ入力

# 1行に文字列1つ

入力

```
abcdef ghijklmn
```

空白やカンマで区切られていようとなんだろうと，とにかく1つの文字列として読み込む。

``` Julia
a = readline() # "abcdef ghijklmn"
```

# 1行に整数1つ

入力

```
12345
```

数字以外があったら何が起こるかわからないが，競プロではそんな意地悪入力はないものとして。

```Julia
a = parse(Int, readline()) # 12345
```

# 1行に実数1つ

入力

```
123.45
```

``` Julia
a = parse(Float64, readline()) # 123.45
```

# 1行に複数の文字列

入力

```
a bc def ghi
```

## 個別の変数に読み込み

変数の個数と入力値の個数は同じであると。

```Julia
a, b, c, d = split(readline()) # a = "a", b = "bc", c = "def", d = "ghi"
```

## 一次元配列（ベクトル， Python でいうリスト）に読み込み

``` Julia
l = split(readline()) # l = ["a", "bc", "def", "ghi"]
```

# 1行に複数の整数

入力

```
1 23 456 7890
```

## 個別の変数に読み込み

変数の個数と、入力値の個数は同じであると。

``` Julia
a, b, c, d = parse.(Int, split(readline())) # a = 1, b = 23, c = 456, d = 7890
```

## 一次元配列（ベクトル， Python でいうリスト）に読み込み

``` Julia
l = parse.(Int, split(readline())) # l = [1, 23, 456, 7890]
```

# n行入力，1行に1個の整数

入力

```
3
1
2
3
```

最初の行は n
それ以降の n 行に 1 つずつの整数

``` Julia
n = parse(Int, readline()) # 3
a = [parse(Int, readline()) for i in 1:n] # a = [1, 2, 3]
```

# nxm 行列　1行にm個の整数をn行分

入力

```
3 4
1 2 3 4
5 6 7 8
9 10 11 12
```

最初の行に n, m
それ以降の n 行は，各行当たり m 個の整数

``` Julia
n, m = parse.(Int, split(readline()))
a = zeros(n, m)
for i = 1:n
    a[i, :] = parse.(Int, split(readline()))
end
#= a
3×4 Matrix{Int64}:
 1   2   3   4
 5   6   7   8
 9  10  11  12
=#
```

# 長さ n の x, y, z のベクトルを 一行に x[i], y[i], z[i] の 3 個の整数を n 行で入力

入力

```
3
1 2 3
4 5 6
7 8 9
```

最初の行に長さ n
それ以降 n 行に x[i], y[i], z[i] の 3 個の整数

``` Julia
n = parse(Int, readline())
x = zeros(Int, n)
y = similar(x)
z = similar(x)
for i in 1:n
    x[i], y[i], z[i] = parse.(Int, split(readline()))
end
x # [1, 4, 7]
y # [2, 5, 8]
z # [3, 6, 9]
```
【Linux】よく使うLinuxコマンド

これだけは使い慣れたいコマンド。自分のための覚え書き。

```
$ pwd　　　　　　　　　　　　　今いるディレクトリの表示（print working directory）
$ ls　　　　　　　　　　　　　　　フォルダの内容をリスト形式で表示する
$ ls -a　　　　　　　　　システムファイル表示
$ cd　　　　　　　　　　　　　　　ディレクトリ（フォルダ）移動
$ mkdir　　　　　　　　　フォルダを作成する
$ touch　　　　　　　　　ファイルを作成する
$ cat　　　　　　　　　　　　　ファイルの内容を表示する
$ rm       ファイルを削除する
$ rm -r    フォルダを削除する
$ mv 　　　　    ファイルやフォルダを指定した場所へ移動させる
$ sudo　　　　　　　　　　コマンドライン上から他のユーザ権限でコマンドを実行する
```
自宅用のサーバーを自作する（構成編）


家にCPUが転がっていたので、~~(PCオタクは家にパーツが転がっていがち）~~それを使ってサーバー的なものを作ってみたいという話。
#どのような機能を実装するか

- __ファイルサーバー__
    - 半年に一回ぐらいOSを入れなおすので、必要なものを自動でバックアップするようにしたい。
    - これがメインの要素になるかも。
    - sambaを使用？
    - RAID等はまだ考えない。（HDDが足りない...）
- __データ収集用サーバー？__
    - センサ情報を集めて、それによりオドメトリを推定する技術に興味があるので、それ用のデータを保管しておくサーバー？
    - 正直これはいらないかも。

- __Wake on Lanを使って起動する__
    - ずっとつけっぱなしだとさすがに電気代なんかが気になるので、使う時だけ起動できるようにしたい。

~~正直PCが組みたいだけ~~

# なぜCPUが転がっていたのか
ちょっと前、WSL上でCUDAを動かそうと思っていろいろいじっていたら、__BIOSが壊れた。__
それで__二度とBIOSに入れなくなってしまい__、マザーボードを買い替えることになった。
その時地元のパソコン工房に行ったのだが、マザーボードとCPUを一緒に買うと割引されるキャンペーンがあったため、ヤケクソで安いCPUも一緒に買っておいた。
![hFYZPwS2T0GW2rdtoNdYgA.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1852474/1635d737-f8da-83c5-299f-4c6e7d5e9769.jpeg "実質CPU３０００円ちょっと　安い！")
...とあるように実質3000円ちょっとでCPUを入手できたという話。~~（そうでも言ってないとやってられない出費大杉）~~

# パーツリスト
【CPU】__Intel Core i3 10100__    ```¥13,178```（パソコン工房）
　　・内臓グラフィックのあるCPUで安いのを選んだ。セレロンなんかはちょっと...。

【CPUクーラー】__付属のリテールクーラー__
　　・さすがにこのCPUぐらいなら冷やしきれると信じて。

【メモリ】__CFD販売　DDR4-2666 8GB×1枚　Panram D4U2666PS-8GC19__　```¥4,236```　（Amazon）
　　・Amazonのセールで安かったので。
　　・16GBもいらないだろうという読み。

【マザーボード】__ASUS PRIME B460M-A__ `¥9,278`　（Amazon）
　　・値段とケースを小さめのにしたかったのでMicro ATXを採用。
　　・最低限の機能があるB460チップセットを選んだ。（RAIDなんかも確かできたはずなので。）

【電源】__玄人志向 STANDARDシリーズ 80 PLUS GOLD認証 750W　玄人志向 STANDARDシリーズ 80 PLUS GOLD認証 750W__  `¥7,450`　（Amazon）
　　・こちらもAmazonのセールで安かったので。
　　・サーバー用途となると変換効率を馬鹿にできないので、GOLD認証をとっているものにした。

【SSD】 __シリコンパワー SSD 128GB 3D TLC NAND M.2 2280 SP128GBP34A60M28__  ``¥2,999``　（Amazon）
　　・こちらもAmazonのセールで安かったので。
　　・Wake on Lanを使ってちょこちょこ起動するのなら、ある程度早さの出るSSDのほうがいいかと考えた。
　　・いろいろソフトを入れるわけでもないので、128GBで足りると思われる。

【HDD】__Western Digital 3.5インチ内蔵HDD 2TB 7200rpm WD Blue WD20EZBX__  `¥6,556`（TSUKUMO）
　　・容量が少ない気がするが、もしも何かあったらあとから増設すればいいやの考えで。
　　・サーバーやNAS用途のWS Redも考えたが、少し高いのと、ずっと通電させるわけでもないので定番のBlueにした。
　　・容量の代わりに7200rpmのものにして、少しでもアクセス速度を上げようと考えた。

【ケース】__Antec P5__  ``¥6,174``　（TSUKUMO）
　　・Micro ATXのケースでコンパクトなやつを選択。
　　・HDDなんかも十分搭載できそうだったので。

【合計金額】``¥49,871``
...何とか5万以内に収まっているけど、これメーカー製でよくない？

組むのが楽しいのですよ自作PCは...

#ソフトウェアとか
- **OS**  
    - 最初は`CentOS`を使おうと思っていたけど、なんか開発終了とか言われているので`Ubuntu Server`を使おうかと検討中。
    - 今までデスクトップ環境で使ってきたのもUbuntuだったので、慣れているものを。
- **ファイルサーバー**
    - sambaを使おうか考えている。
    - フリーで使えて、情報も多いので。
- **Wake On Lan**
    - 正直、組んでみないことにはわからない。

#次回
組み立てて、サーバーとして最低限使えるようにしたい。
CityGMLをQGISで読み込むグラフィカルモデラー

※投稿したのは少し前のことですが、FOSS4Gのアドベントカレンダー枠が空いていたので１枠として参加します。

> 最新LTRの3.22.xでは，CityGML読み込み時のXY座標が反転する現象は解消しています。
> 3.22以上のバージョンを使っている場合はご注意ください。

## はじめに

以下の記事で，PLATEAUのCityGMLを読み込めることがわかったのですが，X/Y座標が逆だったり，逆じゃなかったり，2021年8月時点では，CityGMLをQGISで読み込むときにひと手間がかかりそうなのでなので，グラフィカルモデラーでなんちゃってCityGMLローダーを作りました。

https://qiita.com/Yfuruchin/items/aa3a847db26c7f378d6e


### 動作確認環境

- QGIS 3.20.0
- Windows


## Conditional branch（条件分け）

今回なぜわざわざグラフィカルモデラーを使ったかというと，グラフィカルモデラーの中に
[Conditional branch（条件分け）](https://docs.qgis.org/testing/en/docs/user_manual/processing_algs/qgis/modelertools.html#qgiscondition)というアルゴリズムがあることに気づいたからです。これを使いこなすことができれば，様々な場面で活躍してくれることは容易に想像できます。

幸いなことに，条件分けの使い方を[解説してくれている記事](https://courses.spatialthoughts.com/advanced-qgis.html#conditional-branching)に出会えました。今回はこの記事に従ってCityGMLを読み込むときに，X/Y座標を入れ替えるのか否かを切り分けることにしています。

具体的な動作は，[ここ](https://gist.github.com/kohakurei/09b17d8fc6f07406c40f9b4873e0a09c)のmodelファイルを，開いて確認してもらうこととして，以下からはざっくりと全体像と，条件分けを設定している絵を紹介します。


### グラフィカルモデラーの全体像
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59288/89369198-42e8-3b98-8d8f-2a9d7cfeefe8.png)

※ Conditional branchは一番上に書いてある「条件分け」の部分です
※ CityGMLを読み込むときに，X/Y座標を入れ替えるか・否かの2択なので，bool値の入力（図では，Flip X/Y Coordinates）を用意して，Conditional branchの中に条件を追加します。

### Conditional branchの条件設定
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59288/aa3655b0-2f79-eaaa-3116-f3a816dfd05e.png)

条件分けの中に，条件を追加します。上図の通り，bool値がTrueの場合の条件と，Falseの場合の条件を追加します。「@ XY」というのが，グラフィカルモデラーに登録されている，bool値の入力名です。

### Conditional branchの条件と各処理を紐づける

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59288/6fc43ec1-0d7b-fac0-ff94-db3c1e5d80ef.png)

各アルゴリズムの設定フォームを開くと，一番下に「Dependencies」というのがあります。右側の「･･･」を選択すると，以下の画面が表示されて，先ほど作成した条件分けの条件が表示されているので，何もせずに読み込む場合は「NOT ＠XY」を条件とした方，XY座標を入れ替えてから読み込む場合は「＠XY」を条件とした方の条件にチェックを付けます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59288/68a26320-0d50-b80e-ba33-cadb99cd0114.png)

※ 上図は，何もせずに読む込む場合

## いざ！！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59288/dd6e40aa-0300-be4a-9413-c2be809de5ed.png)

作成したモデルを立ち上げると，上図のように入力レイヤを指定するフォームと，チェックボックスが１つ現れます。あとは見た目通りです。

### Flip X/Y Coordinateにチェックをつけるとこうなる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59288/8f8dba54-7489-fbe6-527c-0de2a3139e58.png)


### Flip X/Y Coordinateにチェックをつけないとこうなる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59288/d0c6a0e2-b8da-5ba9-6a5f-8142db0917f8.png)


なお，作成したグラフィカルモデラーのmodelファイルは，以下の場所で公開しています。
（利用は自己責任で）

https://gist.github.com/kohakurei/09b17d8fc6f07406c40f9b4873e0a09c
tensorflow-gpu Geforce 3060ti インストール

# tensorflow-gpuをインストールする方法

### 経緯
gpuなしのディープラーニングは、時間がかかりすぎる。（タスクにもよるけど、）
あと実行中は、当たり前だけど、そのパソコンでyoutube、netflixは、見れない。
パソコン1台しか持っていない自分は、パソコンなし生活になってしまった、、、  

念願のgpu搭載pcを買って、tensorflow-gpuでやろうとおもったんだが、tensorflow-gpuインストールできてもgpuを認識しなくて、すっげー困ったのでこの記事を書きました。（忘備録兼）  

###大切なこと
バージョンは、厳密に合わせたほうが無難。
最新版をインストールすると互換性がわるくなるし、ドキュメントが少ないので、gpuを認識できなかった。
これで沼にはまりました。
王道が一番でした。

###環境
OS: Windows 10
GPU: NVIDIA Geforce 3060ti
python: 3.7.5 (3.7~3.8が可能)


###インストール手順
#####・ディスプレイドライバのインストールまたは、更新  
<href>https://www.nvidia.com/Download/index.aspx
#####・visual studio (MSVC 2019)　インストール  
<href>https://visualstudio.microsoft.com/ja/thank-you-downloading-visual-studio/?sku=Community&rel=16
#####・ Cuda tool kit インストール  
厳密にバージョンをあわせてインストール
[tensorflow-gpu対応表](https://www.tensorflow.org/install/source_windows#gpu)

<href>https://developer.nvidia.com/cuda-toolkit-archive
#####・ cuDNN インストール  
<href>https://developer.nvidia.com/rdp/cudnn-archive
 
cuDNNでインストールした、cudaフォルダーは、toolsフォルダー作っていれた。
（なぞに、tensorflow公式はそうしていたので、）
#####・　PATH追加  
ユーザー環境設定に書く。

```
C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.0\bin
C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.0\extras\CUPTI\lib64
C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.0\include
C:\tools\cuda\bin
``` 

#####・ tensorflow-gpu インストール
```
pip install tensorflow-gpu==インストールしたいバージョン
```

#####・ gpu動作確認

```
from tensorflow.python.client import device_lib　　

print(device_lib.list_local_devices())

>>> device_type: "GPU"　　　があればOK！！
```

###沼にはまった僕を助けていただいた人たち（参考）
<href>https://webbigdata.jp/study/post-9499

<href>https://www.kkaneko.jp/tools/win/tensorflow2.html


***

公式

<href>https://www.tensorflow.org/install/gpu
インターネットとWebの違いって？

#はじめに#
　最近よく「ネットで叩かれる」とか、「ネットで買い物した」といった言葉を耳にしますが、ネット（正確にはインターネット）とWebとは別物なので、この使い方は実は誤りです。まあ今となってはWebを指してネットと呼ぶことがあまりに一般化しているので諸説ありますが。
　
　今回はそもそもインターネットとは何なのか、Webとの違いは？といった内容で書いていきます。

※誤り等ありましたらご指摘いただけますと幸いです。


#インターネットとは#
>インターネットとは、インターネット・プロトコル・スイートを使用し、複数のコンピュータネットワークを相互接続した、地球規模の情報通信網のことである。省略してネットとも呼ばれる。

↑（Wikipediaより引用）

　つまりインターネットとは、**世界中のコンピュータなどの情報機器を接続するネットワークそのもの**のことで、ものすごく大きな情報通信網になります。また、これらは共通の通信手段（プロトコル）でつながっています。
　
　インターネットの起源は諸説あるっぽいですが、1967年、米国で研究が開始されたパケット通信のネットワークであるARPAnet (Advanced Research Projects Agency NETwork）というものだそうです。年齢にすると54歳ですから、人間の歴史からすると生まれて間もない赤ちゃんですね。
　しかしインターネットはそこから急速に世界中で拡大し、今や我々の生活にはなくてはならないインフラの一つになっています。


#Webとは#
Webとは、正確にはWWW（World Wide Web）ですが、下記のような意味で用いられます。

>World Wide Web（ワールド・ワイド・ウェブ、略名：WWW）とは、インターネット上で提供されているハイパーテキストシステムである。Web、ウェブ、W3（ダブリュー スリー）[1]とも呼ばれる。

↑(Wikipediaより引用）

　俗にいうWebとはインターネット上で用いられる情報（画像や文書など）を結びつけ、我々が情報を得られるようにしたもののことを言います。もう少し具体的に言うと、インターネット上でHTML文書を取得し、情報を得られるシステムのことです。

　例えば、Qiitaや2chなど我々がよく言う「ネット」というのはWebのことを指していることが多いです。


#まとめ#

　インターネットとは、世界中のコンピュータが相互に通信して作られた情報網そのもの、Webがそのインターネット上で動いている情報提供システムのことでした。

　よく似ている言葉と思われがちですが、このように考えると違いが分かってくるのではないでしょうか。
Textboxのカーソル位置の論理行を取得する

#カーソル位置は何行目か？
カーソル位置の行を処理したいことってありますよね？
自分は、テキストから行単位で音声合成するアプリケーションを作るときに、「カーソル行のテキストを読み上げ」という機能を付けたくてこういう処理を実装したことがあります。

#カーソル位置の取得
カーソル位置の取得は

```csharp
System.Windows.Forms.TextBox.SelectionStart
```
で得られます(厳密には選択位置の先頭。選択されていないときはカーソル位置になります)
そして、

```csharp
System.Windows.Forms.TextBox.GetLineFromCharIndex(Int32)
```

で指定の文字位置の先頭からの行数を得られます。

ところが、この```System.Windows.Forms.TextBox.GetLineFromCharIndex(Int32)```は論理行ではなく画面上の表示行を返します。これはこれで意味があるのかもしれませんが、論理行を得る関数はありません。

そこで、発想を変えます。

#Linqでサクッと解決
C#といえば、Linqですので、Linqでサクッと解決しちゃいましょう。
カーソル位置の行数というのは、カーソル位置までのテキストの中の改行コードの数と同じです。
そこで、こんなコードを書きます。

```csharp:GetLogicalLine.cs
        private int GetLogicalLine(TextBox textBox1)
        {
            var posStart = textBox1.SelectionStart;
            var lineStart = textBox1.Text.Take(posStart).Count(p => p == '\n');
            return lineStart;
        }
```
こうすれば論理行を容易に取得することができます。String.Substringとかでとってはいけません。この関数はわざわざStringオブジェクトを生成してしまいます。StringはIEnumerableインターフェースを持っていて、Enumerable<Char>として利用できます。文字の抜き出しはTakeでできますし、その後のカウントも含めてその場でカウントします。
PHP 標準入力を取得する

# 目的

- 標準入力を取得する方法をメモ的に残す

# 方法

#### 標準入力が数値の場合

- 下記のように記載することで標準入力を取得する事ができる。

    ```php
    fscanf(STDIN, "%d", $input_int);
    ```

- 標準入力の値が変数`$input_int`に格納される。

#### 標準入力が文字列の場合

- 下記のように記載することで標準入力を取得する事ができる。

    ```php
    fscanf(STDIN, "%s", $input_str);
    ```

- 標準入力の値が編集`$input_str`に格納される。

#### 半角スペースで区切られた複数の標準入力を配列として受け取る

- 下記の様に記載することで半角スペースで区切られた複数の標準入力を配列として受け取ることができる。

    ```php
    $input = trim(fgets(STDIN));
    $input_array = explode(' ', $input);
    ```

- 半角スペースで区切られた複数の標準入力の値が配列`$input_array`に格納される。

# 自分向けのメモ

- 「半角スペースで区切られた複数の標準入力を配列として受け取る」に関してどうしてそのような挙動をするのかを更に調べる。
local_notifications オリジナルの通知音の保存場所


[local_notifications](https://pub.dev/packages/flutter_local_notifications)で、通知音をオリジナルの音源に差し替えました。
その方法についてメモです。

###環境
* macOS Catalina 10.15.7
* Flutter 2.2.2
* flutter_local_notifications ^8.1.1

##Android
flutterのフォルダで以下の場所にファイルを置きます。
android/app/src/main/res/raw/sound.mp3

####Androidでサポートされているメディア形式
https://developer.android.com/guide/topics/media/media-formats.html

##iOS
* XcodeでRunner.xcodeprojを開き、左のツリーを右クリックしNew Groupe を「Resouces」という名前で作成
* Xcode上のResoucesにサウンドファイルをドラッグ＆ドロップ
* オプションのダイアログで「Create folder refernces」「Runner」にチェック

####iOSでサポートされているメディア形式
https://developer.apple.com/documentation/usernotifications/unnotificationsound?language=objc

###local_notificationsに関わるソースはこんな感じ

	Future<void> _scheduleNotification(
	      int id, String title, String body, DateTime time) async {
	    var scheduleNotificationDateTime = time;
	
	    final timeZone = TimeZone();
	    String timeZoneName = await timeZone.getTimeZoneName();
	    final location = await timeZone.getLocation(timeZoneName);
	    scheduleNotificationDateTime =
	        tz.TZDateTime.from(scheduleNotificationDateTime, location);
	
	    var androidChannelSpecifics = AndroidNotificationDetails(
	      id.toString(),
	      title,
	      body,
	      icon: 'app_icon',
	      sound: RawResourceAndroidNotificationSound('sound'),//←Android用に保存した拡張子抜きのファイル名
	      enableLights: true,
	      color: const Color.fromARGB(255, 255, 0, 0),
	      ledColor: const Color.fromARGB(255, 255, 0, 0),
	      ledOnMs: 1000,
	      ledOffMs: 500,
	      importance: Importance.max,
	      priority: Priority.high,
	      playSound: true,
	      timeoutAfter: 10000,
	      styleInformation: DefaultStyleInformation(true, true),
	    );
	
	    var iosChannelSpecifics = IOSNotificationDetails(
	      presentSound: true,
	      presentBadge: true,
	      presentAlert: true,
	      sound: 'sound.caf',//←Xcodeにドロップしたファイル名
	    );
	
	    var platformChannelSpecifics = NotificationDetails(
	      android: androidChannelSpecifics,
	      iOS: iosChannelSpecifics,
	    );
	
	    await flutterLocalNotificationsPlugin.zonedSchedule(
	      id,
	      title,
	      body,
	      scheduleNotificationDateTime,
	      platformChannelSpecifics,
	      payload: 'payload 001',
	      androidAllowWhileIdle: true,
	      uiLocalNotificationDateInterpretation:
	          UILocalNotificationDateInterpretation.wallClockTime,
	    );
	  }
	  

####参考
https://youtu.be/X3tAGnGc_t0