OmniAICreator/Qiita-1.07M huggingface dataset:
Vue.jsの構築方法の7ステップ

この記事では、Vue.jsを用いたフロントエンドの開発環境を構築する方法を7手順で紹介します。

## 前提
- Windows環境です
- 自身の開発環境を構築する際のメモも含みます（プロジェクト名やルートパスは読み替えてください）

## 手順1（Node.jsのインストール）
以下のサイトからインストーラーをダウンロードし、インストール。
URL：https://nodejs.org/ja/download/

- LTS版のご自身のOSのbit数に合わせたものをダウンロードして使いましょう。
- インストーラーは初期設定でOK
- 詳しく知りたい方は↓↓こちらの記事を参照のこと

https://qiita.com/echolimitless/items/83f8658cf855de04b9ce

## 手順2（プロジェクトフォルダを作る）
プロジェクト名（今回はknowlepo）のフォルダを作る。
↓こんな感じのフォルダを作ります。
※GitHubにリポジトリを作ったので「.git」「README.md」がありますが無視してOK。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2627014/385e8484-de90-99b6-2557-b6ae882db74f.png)

## 手順3（vue/cliをインストール）
※すでにインストール済みの場合はこの手順は不要。
フロントエンドフォルダで```npm i -g @vue/cli```コマンドを実行
警告（deprecated=非推奨）が出ていますが、無視して進めましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2627014/61bfa18f-cdca-93af-b52c-485281b12da9.png)

## 手順4（vueプロジェクトを作成）
vueプロジェクトを作成するコマンド```vue create knowlepo```を実行
vueの2と3を選択する画面が出るので基本は3を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2627014/b0a45ed2-b1d8-04f6-49aa-b7a3ffb4ae76.png)

インストールが終わるとこんな感じになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2627014/0710ca96-39e6-ea11-97ad-b948ab006111.png)


## 手順5（フォルダのリネーム）
フォルダを見ると以下のようにvue.jsの基本ファイルができあがる。
ただし、「knowlepo/knowlepo」となってしまうので下の階層の「knowlepo」を「frontend」にリネームする。
※リネームするのは、今後トップフォルダに「backend」フォルダを作るためです。
**こうならない方法をご存知の方がいたら教えてください。**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2627014/a1a046d0-2a49-bba2-afed-b7f92efa023a.png)


## 手順6（vueサーバーのテスト起動）
リネームした「frontend」フォルダに移動し```npm run serve```でテスト起動
↓こうなればOK
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2627014/7d9081fc-28b6-e91e-7fd6-b840a65b0e3b.png)

## 手順7（ブラウザからアクセス）
```http://localhost:8080/```にアクセスし↓が出ればOK
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2627014/8274f1cc-6037-d507-8f85-2743a4483eab.png)


いかがでしたでしょうか。
vue.jsがあっという間に起動できましたか？
うまく動かなかったなどありましたらコメント欄にコメントをお願いします。

## 次回
次回の記事では、vue.jsのサンプル画面を変える方法を紹介します。
スプレッドシートで和暦を西暦に変換するApps Script

和暦を西暦に変換する関数です。例えば、昭和5年11月18日を文字列「S5.11.18」と記述しているときに、「1930年11月18日」に相当するDate型に変換します。

Google Sheets（Googleスプレッドシート）で、拡張機能からApps Scriptを開き、以下の関数を記述します。

```javascript
function getYear_(nengo, japaneseYear) {
  const startYears = {
    M: 1868, // 明治1年 1868年
    T: 1912, // 大正1年 1912年
    S: 1926, // 昭和1年 1926年
    H: 1989, // 平成1年 1989年
    R: 2019, // 令和1年 2019年
  }
  return startYears[nengo] - 1 + Number(japaneseYear);
}

function SEIREKI(value) {
  const [japaneseYear, month, date] = value.split('.');
  const m = japaneseYear.match(/(M|T|S|H|R)(\d+)/);
  const year = getYear_(m[1], m[2]);
  return new Date(year, Number(month) - 1, Number(date));
}
```

スプレッドシートのセルA1に和暦を記述しているなら、セルB1に```=SEIREKI(A1)```と記述すれば、西暦を得られます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6760/7a500b0d-660e-950b-ce2b-2cb5d61cb719.png)

ちなみに、生年月日から年齢を計算するには、```=DATEDIF(B1,TODAY(),"Y")```です。
エラーの場合に空白にしたいなら、```=IFERROR(DATEDIF(B1,TODAY(),"Y"))```です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/6760/2feefbf0-d3ef-3580-e020-61a5b5e01651.png)
デプロイ後に画像がstoreできなくなった。[エラー : 413 Request Entity Too Large]

## 概要
[413 Request Entity Too Large]エラーが出たので、備忘録として記録。

## 構成
|構成|利用機能|
|--|--|
物理サーバー|AWS
仮想サーバー|EC2
webサーバー|Nginx

## 不具合内容
Laravelをデプロイ後に画像がstoreできなくなった。
ローカル環境では、問題なかったのでサーバー設定の問題だと判断しました。

詳しく確認すると、1M以上の画像がアップロードできない模様。

## エラー原因

- Nginxのリクエストボティサイズの設定項目は「client_max_body_size」であり、デフォルト値は「1m（1MB）」で1M以上のアップロードできない。

- phpのデフォルト設定で2m(2MB)以上のアップロードできない。

## 解決法

- Nginxとphpの設定を変更


**nginx編集**
etc/nginx/nginx.confを編集する。
10mbまでの画像を扱えるよう
「client_max_body_size」を「10m」で設定

```diff_php:etc/nginx/nginx.conf
server {
  listen 80;
  server_name example.com;
  root /var/www/html/example;
  index index.php index.html;
+  client_max_body_size 10m;
}
```

nginxの編集で「413 Request Entity Too Large」のエラーは解消しました。
しかし、まだ2M以上の画像がアップロードできませんでした。

<hr>

**php編集**
etc/php.iniの編集
```zsh:ターミナル
 # 一応、バックアップ保存
% sudo cp php.ini php.ini.default
 # vimで編集
% sudo vim etc/php.ini
```
10mbまでの画像を扱えるよう
「upload_max_filesize」を「10M」に変更

postデータ上限もuploadの10mに合わせておく。
「post_max_size」を「10M」に変更

```diff_php:etc/php.ini
- post_max_size = 8M
+ post_max_size = 10M

- upload_max_filesize = 2M
+ upload_max_filesize = 10M
```
<hr>

変更を反映させるため、サービスの再起動
```zsh:ターミナル
% sudo systemctl restart nginx.service
% sudo systemctl restart php-fpm.service
```

解決しました！

## 参考
[チェックは３ヵ所！ 413 Request Entity Too Largeが表示された時の対処法](https://blog.capilano-fw.com/?p=256#author_profile)
[[PHP] ファイルアップロードの上限サイズを変更する際にさわるディレクティブまとめ](http://bashalog.c-brains.jp/12/02/02-105952.php)
【M1 mac】 An error occurred while installing mysql2 (0.5.3), and Bundler cannot continue. 

### M1 macでmysql 0.5.3がインストールできない

データベースをMySQLでrails newをしたところ、下記のエラーに遭遇。
```
$rails new myapp --webpack=react --database=mysql -T

....省略
An error occurred while installing pg (1.3.5), and Bundler cannot
continue.
Make sure that `gem install pg -v '1.3.5' --source 'https://rubygems.org/'`
succeeds before bundling.

In Gemfile:
...省略
```

[こちら](https://zenn.dev/kosuke_ito/articles/0d508035bcd570)の記事のおかげで無事にインストールできました！！


```
$ brew install openssl
$ echo 'export PATH="/opt/homebrew/opt/openssl@1.1/bin:$PATH"' >> ~/.zshrc
$ source ~/.zshrc
$ bundle config --local build.mysql2 "--with-ldflags=-L/opt/homebrew/opt/openssl@1.1/lib"
$ export LIBRARY_PATH=$LIBRARY_PATH:/opt/homebrew/Cellar/zstd/1.5.2/lib:/opt/homebrew/Cellar/openssl@1.1/1.1.1m/lib/
```
Flaskメモアプリをデプロイする(2022.4.9)

<h1>背景</h1>
職場でFlaskを使う必要が出てきました。その本には「物体検知アプリ&機械学習APIの作り方」と書いており、折角なので軽くFlaskに触れながら深層学習アプリの作り方を学びたいと思いました。

<h1>目的</h1>
Flaskアプリをデプロイします。Flaskに慣れるためにDjangoでやった時の様にメモアプリのデプロイから始めます。

<h1>結果</h1>

[【保存版】30分でFlask入門！Webアプリの作り方をPythonエンジニアが解説](https://tech-diary.net/flask-introduction/)を参考に以下の様にアプリをデプロイ出来ました。著者の「はたやす」さんにお礼を申し上げつつ、本記事を書かせて頂いています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2496939/b630004c-641c-3c5d-87b9-d0f54287c931.png)

<h1>方法</h1>

1. 簡単なメモアプリを作る
1. デプロイする

まずは[【保存版】30分でFlask入門！Webアプリの作り方をPythonエンジニアが解説](https://tech-diary.net/flask-introduction/)を参考にメモアプリを作成します。その後、若干の修正を加えつつ、Herokuにデプロイしました。デプロイに関しては私の過去の投稿にあります「[GitHubとHerokuを連携してDjangoアプリをデプロイする（2022.3.15）](https://qiita.com/tan0ry0shiny/items/149179d3d6a3f6c5aa73)」「[「.env」を使ってGitHubで安全なアプリ管理をする（2022.4.2）](https://qiita.com/tan0ry0shiny/items/f692d9f5ba6d85810030)」を参考にしました。
 
<h1>修正</h1>

1.Bootstrapの記述
はたやすさんの記事の通りでは有効にならなかったので、base.htmlの該当箇所を次の様に変えました。有効になると結果にあったような画面になります。
```base.html
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-+0n0xVW2eSR5OomGNYDnhzAbDsOXxcvSN1TPprVMTNDbiYZCxYbOOl7+AMvyTG2x" crossorigin="anonymous">
```
2.「.env」の追加
flaskアプリの実行方法にはflaskコマンドを使う方法と「python app.py」の様に実行ファイルを直接動かす方法があるようです。今回は、「[Python FlaskによるWebアプリ開発入門 物体検知アプリ&機械学習APIの作り方](https://www.shoeisha.co.jp/book/detail/9784798175164)」に沿って、「flask run」で実行できるようにします。「.env」は以下の様になります。
```.env
FLASK_APP=app.py
FLASK_ENV=development
```
今回はセキュリティーについては考えていませんが、今後、このファイルに重要な情報を入れるようになるかもしれません。

<h1>感想</h1>
今回は、深層学習を用いたアプリを作る為の準備としてFlaskでメモアプリを作りました。Djangoアプリを作成した際、GitHub経由でHerokuにデプロイしたり、「.env」を使って環境変数を作ったりしていたのが上手く活用できたので作業しながら楽しくもありました。

<h1>課題</h1>

「[Python FlaskによるWebアプリ開発入門 物体検知アプリ&機械学習APIの作り方](https://www.shoeisha.co.jp/book/detail/9784798175164)」を読み進めて、深層学習アプリを作成できるようにしたいと考えています。

<h1>参考</h1>

1. はたやす(2022.4)、 [【保存版】30分でFlask入門！Webアプリの作り方をPythonエンジニアが解説](https://tech-diary.net/flask-introduction/)、テックダイアリー
1. Ryo Tanohata(2022.4)、[GitHubとHerokuを連携してDjangoアプリをデプロイする（2022.3.15）](https://qiita.com/tan0ry0shiny/items/149179d3d6a3f6c5aa73)、Qiita
1. Ryo Tanohata(2022.4)、[「.env」を使ってGitHubで安全なアプリ管理をする（2022.4.2）](https://qiita.com/tan0ry0shiny/items/f692d9f5ba6d85810030)、Qiita
1. 佐藤ら(2022.1.24)、[Python FlaskによるWebアプリ開発入門 物体検知アプリ&機械学習APIの作り方](https://www.shoeisha.co.jp/book/detail/9784798175164)、翔泳社
Git接続時のプロキシ設定について

初投稿です。
社内ネットワークからGitへ接続しようとした際に大分手こずったので、備忘録として投稿します。
なお実務経験1年未満の本物初心者なので間違っている箇所は指摘していただけるとありがたいです。

# 発端

弊社ではオンプレミス版GitLabとクラウド版GitLabが利用されています。
自分は元々オンプレミス版を利用したプロジェクトに参加しており、クラウド版を利用した新規プロジェクトへ参加する際に問題が発生しました。
社内プロキシの関係で、クローンが行えなかったのです。
その後、プロキシの設定を行き当たりばったりでいじっていいたら、接続できていたはずのオンプレ版にも接続できなくなってしまいました。

# 試したこと
## 1. git configコマンドを用いてプロキシ設定を記述
コマンドプロンプト上で以下のコードを実行しました。
```
$ git config --global http.proxy http://<ユーザ名>:<パスワード>@<プロキシサーバのアドレス>:<プロキシサーバのポート番号>
$ git config --global https.proxy http://<ユーザ名>:<パスワード>@<プロキシサーバのアドレス>:<プロキシサーバのポート番号>
```
httpsの場合もURLはhttpであることに注意。
これにより、/gitconfigファイルへプロキシの情報が記述され、プロキシサーバ経由でのGit接続が可能になります。
※自分の場合、/gitconfigファイルへ記述されずこの設定が足を引っ張ったので注意点の項目で後述します。

## 2. ユーザー環境変数、システム環境変数へHTTPS_PROXYを追加
```
$ set http.proxy = http://<ユーザ名>:<パスワード>@<プロキシサーバのアドレス>:<プロキシサーバのポート番号>
$ set https.proxy = http://<ユーザ名>:<パスワード>@<プロキシサーバのアドレス>:<プロキシサーバのポート番号>
```
これはあまり意味がなかったので、最終的に削除しました。
Git Bash上ではsetではなくexportコマンドなので注意。

## 3. 資格情報マネージャーを開きWindows資格情報の中からGitLabの資格情報を削除する
Gitの認証で設定したユーザー名とパスワードはWindowsの資格情報に保存されます。
初回の接続時にユーザー名とパスワードの入力を求められます。合っていれば問題ないのですが、間違った情報を入力しても資格情報として記録されてしまいます。
Windowsの検索画面で「資格情報マネージャー」を検索し、Windows資格情報の中から接続に失敗したGitの情報を削除しましょう。
その語、再度接続する際に、ユーザー名とパスワードの入力を求められるので、正しいものを入力しましょう。

# 注意点
1. 「git configコマンドを用いてプロキシ設定を記述」にて、「/gitconfigファイルへプロキシの情報が記述され、プロキシサーバ経由でのGit接続が可能になります。」と書きましたが、自分の場合は、gitconfigファイルへ記述されませんでした。そのため、自分はgitconfigファイルへ直接http, httpsの設定を書き込みました。
この場合は、コマンドプロンプト上で変更したgitconfigファイルと直接変更したgitconfigファイルは違うので、それぞれで修正する必要があります。
# おまけ
```
$ GIT_CURL_VERBOSE=1
```
上記のコマンドのあと、git clone などのGitコマンドを実行すると、Gitコマンドのデバッグが行えます。
GitHub Actionsでのリリース自動化にはaction-gh-releaseが便利だったという話

備忘録

## 使ったやつ
[actioin-gh-release](https://github.com/softprops/action-gh-release)

## やりたいこと
- 特定のブランチからmainへのPRがマージされると勝手にリリースされる。
    - リリースタイミングは自分で制御したい。
    - `release`ブランチを作って、そのブランチに変更がマージされた時にリリースジョブが実行されるやり方もあるが、自分は全ての変更をmainに集約させたかったので。
- 勝手にタグを打ってくれる。
- タグ名とリリースタイトルは自分で指定できる。
- 前回のタグとの差分をリリースノートに書いてくれる（Auto-generate release notesと同じことができる）。
- メンテされている。
    - こういった記事でちょくちょく見かける[create-release](https://github.com/actions/create-release)はアーカイブになっているので対象外。
- 成果物をアップロードできる。

## スクリプト
``` create-release.yml
name: create-release

on:
  pull_request:
    types:
      - closed

jobs:
  create-release:
    name: Create release
    runs-on: ubuntu-latest
    if: contains(github.head_ref, 'release')
    steps:
      - uses: actions/checkout@v3
        with:
          fetch-depth: 0
      - name: Set up JDK
        uses: actions/setup-java@v2
        with:
          java-version: 8
          distribution: 'temurin'
          cache: 'maven'
      - name: Build
        run: sh mvnw clean package
      - name: Release
        uses: softprops/action-gh-release@v1
        with:
          name: ${{ github.event.pull_request.body }}
          tag_name: ${{ github.event.pull_request.title }}
          generate_release_notes: true
          files: target/hoge.jar
```

## 解説

### 発火タイミング
```yaml
on:
  pull_request:
    types:
      - closed
```
PRが閉じたタイミングで発火する。
ちなみに、PRの向き先のブランチの指定はここでできるが、どのブランチからのPRかの指定はできなさそう。

### 発火するブランチの指定

```yaml
jobs:
  create-release:
    name: Create release
    runs-on: ubuntu-latest
    if: contains(github.head_ref, 'release')
```

jobに`if`で発火条件を指定できる。
今回はブランチ名に`release`が含まれている場合に発火するように指定した。

### action-gh-releaseのオプション
```yaml
      - name: Release
        uses: softprops/action-gh-release@v1
        with:
          name: ${{ github.event.pull_request.body }}
          tag_name: ${{ github.event.pull_request.title }}
          generate_release_notes: true
          files: target/hoge.jar
```
- `name`: リリースタイトル。今回はPRのbodyを流用した。
- `tag_name`: 作成するタグの名前。今回はPRのタイトルを利用した。PRのタイトルをタグ名にすると、PR一覧を見た時にどれがリリース用のPRかが一目で分かるかなぁと考えたので。
- `generate_release_notes`: Auto-generate release notesをやるかどうか。
- files: アップロードしたいファイル群。改行区切りで複数していできるらしい。

その他は[actioin-gh-release](https://github.com/softprops/action-gh-release)のREADME参照。

## 使い方
1. ローカルで`release/ver`でブランチを切る
1. リリース用のファイル変更を行う（READMEの更新や、mavenプロジェクトだと`revision`プロパティの更新）
1. タイトルを「作成したいタグ名」、内容を「そのリリースでの主な変更点」にして、PRを作成する。
1. テストジョブなどが通過を確認してマージする。
1. 勝手にリリースされてる。

## 参考文献
- https://zenn.dev/ryo_kawamata/articles/github-actions-specific-branch
- https://zenn.dev/itizawa/articles/b832c4e2a33661
新卒未経験が7月までにAWS Professional資格二冠する話


# はじめに
　二冠と言いましても、2022/3月に既にAWS-SAP取得済みであるため、7月までにAWS-DOPを取得することでAWS Professional資格の二冠を達成することになります。この二冠をする過程をみなさんに見ていただけばと思い、企画として記事を連載していきます。
本日、2022/4/9より、学習を始めます。
## 保有資格
応用情報技術者
AWS-SAA
AWS-SAP

## 取得を志す理由
　開発に関しても関心を持っているためです。AWS-SAPを取得後に、AWSの開発に挑戦しましたが、自分自身の開発ペース・開発の質の両面に対して不満を抱いたからです。設計に関してはSAP取得を通してベストプラクティスを学びました。しかし、開発に関してはベストプラクティスを知らずに闇雲に突っ走っているだけでした。これでは、いいプロダクトは開発できませんし、効率もよくないと考えDOPの学習を通して開発面も学んでいければいいなと思ってます。
　もう一つの理由は、今後の業務に役立つと考えたからです。AWS-SAPトップダウンの視点だとしたら、AWS-DOPはボトムアップの視点であると考えています。具体的に、この両面の視点がいかにして役立つかは、新卒の僕には想像できません。しかし、確実に役立つという事実は容易に想像できます。

# 今後の当企画のコンテンツ
この企画のコンテンツとしては、主に二つ考えています。
一つ目は「○○をやってみた」というコンテンツです。これ、この○○は主に自分が参考書や問題集だけでは完全に理解できなかった分野をハンズオンとして実践した過程をこちらに残しておきます。
二つ目は、合格体験記です。合格後にいかにして合格したかを出来るだけ具体的に、かつ簡潔にこちらに残させていただきます。

# 現在の自信
正直、AWS-SAP取得後であるためそれほどDOPの取得は難しいものではないと考えています。学習時間の確保・体調管理が上手くいけば６月までには取得できるような気もしています。

# 今後の学習計画
最初の三日；下位資格であるAWS-DVAの参考書を７割ほど理解
その後：・問題集の周回
	・Blackbelt
	・公式ドキュメント
	・ハンズオン

以上のような非常な大雑把な、感じで約２から３か月ほどかけて学習していきます。

# 開発未経験がクラウドを企業に導入するプロジェクトごっこをしてみたについて
現在同時進行中である「開発未経験がクラウドを企業に導入するプロジェクトごっこをしてみた」は一旦、ＤＯＰ取得のため休止させていただきます。例外として、上記のプロジェクトごっことＤＯＰの学習の両方を達成できるものに関しては、記事を書かせていただく場合があります。
Qiitaの記事が無断転載されたので対処した

# はじめに

Googleでキーワード検索していたら、どこかで見たような記事を見つけた

むかし自分がQiitaに掲載した記事と同じ文章だった（しかも全文・・・[おまけ](#おまけ)に画像あり）

いわゆる**無断転載**だったので、Qiitaガイドラインに則って申請～削除まで至った経緯を記す

# 自分の記事が無断転載されたかも？という場合は

Google先生に**権利侵害の通知**を行います

https://help.qiita.com/ja/articles/about-unauthorized-reproduction

自分の連絡先と、元記事URLと、削除してもらいたいURLを記載します

最後に「ロボットでありませんか？」と聞かれますが、チェックするだけでした
（難しいパズルなどは不要でした）

3分くらいで手続きは終わります

:::note warn
虚偽の申請をすると、損害賠償責任などが課せられる可能性があります！！
:::

# 削除リクエストしたときの様子

スマホの画面を引き伸ばしているので、鮮明なキャプチャーではありませんが・・・

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272511/7e865eb8-faab-aa51-4ccf-523078c5cfae.png)

**保留中のURL**に1件追加されています

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272511/32b451d5-a67d-43af-0630-a3060ba85a96.png)

# 「情報が足りないよ」とメールがきた

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272511/f707d80d-873a-4c15-2033-b3fba18a555d.png)

（返信マークがついているけど、なにも送信ボックスに残ってなかった）

## ダッシュボードを確認する

**拒否されたURL**が1件になっている

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272511/73e347b1-3753-90c2-286c-e739d3794bad.png)

詳細をみると、「情報が不足しています」とのこと

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272511/3653aea8-56cf-b668-982f-dad5c56d5966.png)

# 転載先のURLをみてみたら・・・

**削除されてました**😅

> 著者からリクエストがあったんで、この記事の公開はやめます。元のアドレスにアクセスしてね！

的なことが書かれている

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272511/4dede6dc-c2ee-7e10-fcaf-6d2700c666e7.png)

# おわりに

申請は拒否されたものの、なんらかの力が働いて転載先から記事が消されました

めでたしめでたし

# おまけ

削除される前のようすがGoogleキャッシュに残っていた

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272511/61c3845a-ed2c-fc48-aa7a-8e85a299b39d.png)
Flutter で画像が取得できなかったときにデフォルトの画像を表示する

FlutterでImageウィジットを使って画像を表示するときに、asset に存在しない画像があった場合にデフォルトの画像を表示する方法


[Check if asset exist in flutter](https://stackoverflow.com/questions/52908923/check-if-asset-exist-in-flutter)

```
Image.asset(
  'assets/sample.jpeg',
  errorBuilder: (BuildContext context, Object exception, StackTrace? stackTrace) {
    return Image.asset('assets/default.jpeg');
  },
),
```
SRE本を読んで出てきた用語(備忘録)

# はじめに
ざっくりになりますが、GoogleのSRE本を読んで学んだ用語について記事を書いていきたいと思います。
完璧な内容ではないので、そこはご了承頂ければと思います。
※詳しい内容や書籍のレビューに関しては、ブログで再度記事を書きます。

# SRE本とは？
オライリーが出版している**SRE サイトリライアビリティエンジニアリング**という本になります。
値段が5000円程になります。

https://onl.la/pNSNiVV

:::note warn
電子書籍での取り扱いはなさそうです。
紙書籍のみとなります。(電子版を強く所望しております。)
:::

# SREの用語
SRE本で出てくる用語についてざっくばらんにご紹介していければと思います。

## SLA/SLO/SLI

|  用語  |  内容  |
| ---- | ---- |
|  SLA(サービス品質保証)  |  「Service Level Agreement」の略になります。<br>サービスを提供する事業者がサービスの契約者に対し、サービス内容を保証するための契約になります。  |
|  SLO(サービスレベル目標)  |  「Service Level Objective」の略になります。<br>事業者が定義・合意したSLAを履行するために、サーバーやネットワーク、ストレージなどの各領域の稼働率、性能、可用性、セキュリティ、サポートといった項目ごとに、パフォーマンスの目標値を表したものになります。<br>(SLIの目標値になります。)  |
|  SLI(サービスレベル指標)  |  「Service Level Indicators」の略になります。<br>サービスの動作を直接測定したものになります。|

ざっくり自分の言葉でまとめると以下だと思っています。

|  用語  |  内容  |
| ---- | ---- |
|  SLA(サービス品質保証)  |  サービス提供側と契約者で締結するサービスレベルの値  |
|  SLO(サービスレベル目標)  | サービス提供側で目標にするサービスレベルの値<br>※契約者とのサービスレベルの締結で定めた値ではない |
|  SLI(サービスレベル指標)  | 実際のサービスレベルの測定値 |

## トイル
トイルとは、以下の特徴を持っている作業になります。

- 手作業
- 繰り返される
- 自動化が可能
- 戦術的、長期的な価値がない
- サービスの成長に比例して増加する

実際にSREエンジニアをやっている方と話をしたことがありますが、主に**手作業**のことを指していると思います。

## カスケード障害
システムの一部に障害が発生した場合、その障害がシステムの他の部分にも拡大していく障害になります。

例えると、**ドミノ**のような感じで一部が崩れると他の部分も崩れるような感じの障害になります。

![dominoes-g3e40476f7_1280.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636476/52afe9b4-890a-6a2b-2cc1-62cbccc5c8bd.jpeg)

# オンコール
システム障害があった場合に、いつでも対応できるように待機することを指していると思います。
エスカレーションや通知を受けて対応することが**オンコール対応**であると思っています。

![SRE.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636476/f6b1505a-23da-6f1b-2743-b52bdb53bd81.png)



# さいごに
SIerで働いていると馴染みのある言葉は**SLA**くらいなのかなと思います。
しかし、今後SREとして働く場合に抑えた方が良い用語ばかりなので、コツコツ勉強していければと思います。

# 参考
[SLA、SLO、SLI の比較: 相違点は何か?](https://www.atlassian.com/ja/incident-management/kpis/sla-vs-slo-vs-sli)
[SRE の基本（2021 年版）: SLI、SLA、SLO の比較](https://cloud.google.com/blog/ja/products/devops-sre/sre-fundamentals-sli-vs-slo-vs-sla)
[オンコールエンジニアのための準備](https://pagerduty.digitalstacks.net/blog/prep-on-call-engineer/)
[SRE の原則に沿ったトイルの洗い出しとトラッキング](https://cloud.google.com/blog/ja/products/gcp/identifying-and-tracking-toil-using-sre-principles)
??(null結合演算子)ハテナハテナで条件分岐[JavaScript]

```javascript
const foo = value ?? null;
```
こんな感じで条件分岐を行うことができます。
上記の場合の処理を言葉で書くと、

*valueが存在する場合はvalueを返し、fooに代入する。*
*valueがnullまたはundefinedの場合はnullを返し、fooに代入する。*

こんな感じですね。

```javascript
const foo = value ? value : null;
```
この式の短い版みたいなイメージで使ってます。
ただしvalueがnullかundefinedの場合でないと右側の値へ分岐を行ってくれないので、
**true/falseで処理を分岐させたい場合には使えません。**
Go言語 エラーハンドリング

## エラーハンドリング
Goにおけるエラーハンドリングは、関数の多値返しにて実現する。
関数は処理結果とエラー値を返し、エラー値を確認することにより異常処理の場合を見分ける。
正常処理の場合は、エラー値はnil(Null)である。
異常が起こった場合は、エラー値の中にエラー情報が格納されている。

## Code
```Go
// 割り算を行う関数
func calcDiv(molec int, denomi int) (result int, err error) {
	result = molec / denomi
	return result, err
}

func main() {

	// 正常に計算される割り算
	result1, err := calcDiv(128, 4)
	if err != nil { // 正常処理の場合は、errに値が格納されない
		log.Fatal(err)
	}
	fmt.Printf("Answer : %d \n", result1)

	// エラーが発生する0による割り算
	result2, err := calcDiv(128, 0)
	if err != nil { // 異常の場合は、errに値が格納されている
		log.Fatal(err)
	}
	fmt.Printf("Answer : %d \n", result2)
}
```

## Output Sample
~ $ go build main.go  
~ $ ./main  
Answer : 32  
panic: runtime error: integer divide by zero  
  
goroutine 1 [running]:  
main.calcDiv(...)  
&nbsp;&nbsp;/Users/main.go:10  
main.main()  
&nbsp;&nbsp;/Users/main.go:26 +0x6b 

## GitHub
https://github.com/GL-Kageyama/Go_ErrorHandling
【React塾】React練習問題【カウントアップ・ダウンボタンの実装】

# React練習問題
Q1. カウントアップ・ダウンボタンを作成してください。
![スクリーンショット 2022-04-09 11.57.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326114/9544568a-e5d7-cb94-aaba-da4b69598c63.png)


## 問題の取り組み方

1.Github右上部にあるForkをクリックして、以下のリポジトリをフォーク
https://github.com/SatakeYusuke19920527/react-juku.git
![スクリーンショット 2022-04-02 20.46.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326114/ec733350-37d0-fcb1-37f4-2da9b40254e1.png)


2.git clone
Codeと書いてあるボタンをクリックしてURLをコピー
![スクリーンショット 2022-04-02 20.47.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326114/1f9637ed-3302-6380-abcf-cbcabec2d580.png)

3.git cloneでローカル環境へコードを持ってくる

```
git clone https://github.com/SatakeYusuke19920527/react-juku.git
```
branchは自分の名前 + 問題番号としてください
```
git checkout -b yujiroq2
```

4.src/questions/Q2.tsxに実装してください

![スクリーンショット 2022-04-09 11.58.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/326114/285296a3-8adb-50f2-82c4-6efa14c2fc55.png)


5.実装できたらレビュアーに [SatakeYusuke19920527] を入れてプルリクエストを作成してください

6.レビューして合否を判定します！プルリクエストに合否を書くね。

## みんなのコードを見れることを楽しみにしてます！


https://proaca.tech/
AngularFire - NullInjectorErrorの対処法


AngularFire を操作する中で、少しハマった部分があったので、備忘録として残しておきます。

# 事象
AngularFire の AngularFireDatabase モジュールを利用して、Realtime Database に接続しようとした際に以下のエラーが発生しました。
No provider for InjectionToken とのことなので、providers に AngularFireDatabase をセットすればいいようだがイマイチうまくいかず。。

```
ERROR NullInjectorError: R3InjectorError(AppModule)[AngularFireDatabase -> InjectionToken angularfire2.app.options -> InjectionToken angularfire2.app.options -> InjectionToken angularfire2.app.options]: 
  NullInjectorError: No provider for InjectionToken angularfire2.app.options!
```

# 環境
ng version での出力結果。
@angular/fire の7系が関連している模様。

```
@angular-devkit/architect       0.1302.6
@angular-devkit/build-angular   13.2.6
@angular-devkit/core            13.2.6
@angular-devkit/schematics      13.2.6
@angular/cli                    13.2.6
@angular/fire                   7.3.0
@schematics/angular             13.2.6
rxjs                            7.5.5
```

# 対処策
providersがセットされていないとのエラーでしたが、その中の書き方を少し工夫しないとダメでした。

```app.module.ts
import { NgModule } from "@angular/core";
import { FormsModule } from "@angular/forms";
import { BrowserModule } from "@angular/platform-browser";

import { AppComponent } from "./app.component";
import { CommentDatePipe } from "./pipes/comment-date.pipe";
import { initializeApp, provideFirebaseApp } from "@angular/fire/app";
import { environment } from "../environments/environment";
import { provideAuth, getAuth } from "@angular/fire/auth";
import { provideDatabase, getDatabase } from "@angular/fire/database";
import { FIREBASE_OPTIONS } from "@angular/fire/compat";

@NgModule({
  declarations: [AppComponent, CommentDatePipe],
  imports: [
    BrowserModule,
    FormsModule,
    provideFirebaseApp(() => initializeApp(environment.firebase)),
    provideAuth(() => getAuth()),
    provideDatabase(() => getDatabase()),
  ],
  providers: [{ provide: FIREBASE_OPTIONS, useValue: environment.firebase }],
  bootstrap: [AppComponent],
})
export class AppModule {}

```
AWS Lambdaの関数URL（Function URLs）のユースケースを真面目に考える

AWS Lambdaに新機能 **Function URLs** が追加されました。

https://aws.amazon.com/jp/about-aws/whats-new/2022/04/aws-lambda-function-urls-built-in-https-endpoints/

https://aws.amazon.com/jp/blogs/aws/announcing-aws-lambda-function-urls-built-in-https-endpoints-for-single-function-microservices/

簡単にいうとAPI Gatewayなしに、HTTPSでのリクエストを受け付けられるようになるものです。

**API Gatewayなしで簡単になったよ！わーい！！** ではなく、今までできなかった何ができるようになったのかを真面目に考えてみました。

# Function URLsの認証

Function URLの認証は`IAM認証あり`と`認証なし`（パブリックアクセス）の二通りがあります。

IAM認証が使える環境であれば、以前から**CLI**や**SDK**を使ってLambdaを直接呼び出すことができました。

```console:AWSCLI
aws lambda invoke \
  --function-name <value> \
  <outfile>
```

https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/invoke.html

また、**cURL**でもバージョン7.75.0から`--aws-sigv4 `というオプションが追加されており、IAM認証の情報があればCLIやSDKがなくてもhttpsアクセスでLambdaを呼び出すことができます。

```console
curl \
 -XPOST \
 "https://lambda.ap-northeast-1.amazonaws.com/2015-03-31/functions/<function-name>/invocations" \
 -H "Content-Type: application/json" \
 -d '{ "key": "value" }'   \
 --aws-sigv4 "aws:amz:ap-northeast-1:lambda"   \
 --user "${AWS_ACCESS_KEY_ID}:${AWS_SECRET_ACCESS_KEY}"
```

https://curl.se/docs/manpage.html#--aws-sigv4

https://gist.github.com/mryhryki/28fcd54e8a8cdffb78462d171ce48b27

IAM認証が使える環境であればFunction URLsの登場以前からできることは変わらないということになります。
そのため、Function URLsの存在意義は **「API Gatewayなし」「認証なし」でLambdaを呼び出せるところ** だと思います。

# API Gatewayの仕様制限の回避

API Gatewayの最大の制限は**30秒でタイムアウト**だと思います。
これを回避するためにはSQSを介して非同期化するなどの対策が必要でした。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/41574/aa8028d7-8535-ff7b-dcfe-75c36d8013cc.png)

API Gatewayを介さずにLambdaを呼べるとこの制約がなくなり、 **30秒以上かかる処理を同期** で返却できるということになります。

# Function URLsのユースケース

以上のことから、**Function URLs**が活用できる場面は、 **認証が不要で30秒以上処理に時間がかかり同期的に結果を返す必要がある** ではないかと考えました。🤔🤔
ただ、具体的にどんな場面かが思いつきませんでした。😥😥

AWSのブログでは、**API Gatewayの高度な機能を必要としないとき**という表現がされているため、もしかすると **不特定多数のアクセスがあるような場合のコスト削減** が主なメリットなのかもしれません。


最後にAWSブログで紹介されている具体的なユースケースと私なりの考察を記載して終わりにします。

| ユースケース | Function URLs利用のメリット |
| --- | --- |
| Webhookハンドラ | 大量のアクセスあり<br>認証は独自<br>処理時間は短い<br>**API Gatewayの利用料削減に期待** |
| フォームバリデータ | 大量のアクセスあり<br>認証なし<br>処理時間は極端に短い<br>**API Gatewayの利用料削減に期待** |
| モバイル決済処理 | 大量のアクセスあり<br>認証は独自<br>処理時間が30秒を超える可能性あり<br>**30秒以上かかるとAPIはエラーを返却するが内部処理は成功するような不一致ケースが出てしまう。同期で正しくレスポンスを返却することに期待（もしかするとこのユースケースが最有力？）🤔🤔**|
| 広告掲載 | 大量のアクセスあり<br>認証なし<br>処理時間は極端に短い<br>**API Gatewayの利用料削減に期待** |
| 機械学習による推論 | アクセス頻度は低い<br>処理時間が30秒を超える可能性あり<br>**処理に30秒以上かかる場合の動作改善に期待** |
MySQLをMacにインストール

### MacにMySQLをインストールする方法

今回は、[こちら](https://style.potepan.com/articles/19020.html)の記事を参考にして実際に自分のMacにインストールしてみました！

1) HomebrewがMacにインストールされているか確認する
```
brew --version
```
Homebrew バージョン のように出てくればOK
もし、インストールされていない場合は、まずはインストールを行います。
[Homebrew公式](https://brew.sh/index_ja.html)

インストールを終えたら、mysqlをインストールします
```
brew install mysql
```
MySQLがインストールできたら、下記コマンドで起動します

```
$ mysql.server start
Starting MySQL
. SUCCESS! 
```
SUCCESSと表示され、正常に起動されたことが確認できます。
MySQLを停止するときは
```
mysql.server stop
```
使わないときは必ず止めてきましょう。

### MySQLにログインする
```
mysql -uroot -p
```
出るときは、exitでOK
JUnit5でのstaticメソッドメモ



```
MockedStatic<モックにしたい対象クラス> mocked = Mockito.mockStatic(Instant.class);
```

JUnit5でのstaticメソッドの書き方はいろいろあるようだがこれでうまくいったのでメモ。

try(ココ)の中に上記処理を書く。
で、tryの中では変数mocked を使用するわけではなく、
モックにしたい対象クラスの変数をいつものモックの書き方でtryの中で書く。
vscodeに導入したblackが機能しない

## はじめに
[これ](https://qiita.com/tsu_0514/items/2d52c7bf79cd62d4af4a)と[これ](https://qiita.com/sin9270/items/85e2dab4c0144c79987d)を参考にflake8とBlackを導入したものの、保存時にblackの自動整形が行われない

## 状況

setting.jsonを以下の様に設定

```json:settings.json
{
    "python.linting.enabled": true,
    "python.linting.pylintEnabled": false,
    "python.linting.flake8Enabled": true,
    "python.linting.lintOnSave": true,
    "python.formatting.provider": "black",
    "editor.formatOnSave": true,
    "editor.formatOnPaste": false,

    "python.linting.flake8Args": [
        "--max-line-length=119",
        "--ignore=E203,W503,W504"
    ],
    "python.formatting.blackArgs": [
        "--line-length=119"
    ],
} 
```
以下のコードの保存時にフォーマットが行われない。

```python:sample.py
 def foo():
    print(
                "Hello"
        "World"
        )
```

ただし、コマンドライン上でblackを実行するとちゃんと整形される。
```terminal
$ black sample.py
```

## 原因

flake8ArgsとblackArgsの引数の指定方法が間違っていました。
[こちらの記事](https://www.macky-studio.com/entry/2019/07/04/152323)の方法を参考に修正したものが以下

```json:settings.json
{
    "python.linting.flake8Args": [
        "--max-line-length",
        "119",
        "--ignore=E203,W503,W504"
    ],
    "python.formatting.blackArgs": [
        "--line-length",
        "119"
    ],
}


```
ポイントは最大文字数の指定箇所を分割する事でした。
以上。

## 参考文献
[Blackできれいに自動整形！flake8とBlack導入と実行](https://qiita.com/tsu_0514/items/2d52c7bf79cd62d4af4a)

[Pythonのコードフォーマッターについての個人的ベストプラクティス](https://qiita.com/sin9270/items/85e2dab4c0144c79987d)

[【VS Code】BlackとFlake8を使ってきれいなPythonコードを書く！！](https://www.macky-studio.com/entry/2019/07/04/152323)
｢新しいLinuxの教科書｣個人的メモ chapter02

エラーメッセージを良く読み､その内容を理解して対処することが､linuxを使いこなすために重要

>というか､プログラマーエンジニアやっていくためには一番重要だと思う
>エラーメモをこのqiitaとかに書くと良いかもしれない
>おすすめの動画貼って置きます
><iframe width="560" height="315" src="https://www.youtube.com/embed/nbNj4d8_cMU" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

## シェルの役割とlinuxカーネル
例としてdateコマンドを実行する時linuxでは以下の処理が行われる
1. キーボードから入力された､dateという文字列を受け取る
2. dateという名前のコマンドを実行する
3. 見つかったコマンドを実行
4. 実行した結果とsて得られた日時の文字列を画面に表示する

このうち`3`のコマンドを実行する部分は､linuxの本体であるLinuxカーネルが行う

### カーネルとは
osの中核､cpuやメモリなどのハードウェアを管理するとともに､コマンド実行を処理するプロセス管理も行われる

### シェル
人間とカーネルの橋渡し役
人間からのコマンドをカーネルに渡し
カーネルからの結果を人間に渡す

### カーネルとシェルに分かれる理由
* カーネルに手を加えず､シェルだけ変更ができる
* linux以外のosを使うときも同じシェルなら同じように操作できる
* シェルがエラーやクラッシュしたとしてもカーネルへの影響を最小限に抑えられる
->要するにエアバッグみたいな役割?
【Go】ロギングライブラリzapの使い方メモ

# はじめに
Goのロギングライブラリであるzapに関するメモです。

# zapとは
構造化メッセージを自由に構築できる、高速なロギングライブラリです。
ベンチマークによると、標準ライブラリ(fmt, encoding/json)やlogrusより高速とのことです。

https://github.com/uber-go/zap#performance

# 実装
以下が初期化のプログラムです。

```go:logger.go
package logger

import (
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
)

var log *zap.Logger

func init() {
	var err error

	config := zap.NewProductionConfig()

	encoderConfig := zap.NewProductionEncoderConfig()
	encoderConfig.TimeKey = "timestamp"
	encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
	config.EncoderConfig = encoderConfig

	log, err = config.Build(zap.AddCallerSkip(1))

	if err != nil {
		panic(err)
	}
}
```

`zap.NewProductionConfig()`で`config`を定義し、設定を自由にカスタムします。
`config`の中身は以下のようになっているのですが、今回は`EncoderConfig`の設定を簡単にいじってみます。

```go
type Config struct {
	Level AtomicLevel `json:"level" yaml:"level"`
	Development bool `json:"development" yaml:"development"`
	DisableCaller bool `json:"disableCaller" yaml:"disableCaller"`
	DisableStacktrace bool `json:"disableStacktrace" yaml:"disableStacktrace"`
	Sampling *SamplingConfig `json:"sampling" yaml:"sampling"`
	Encoding string `json:"encoding" yaml:"encoding"`
	EncoderConfig zapcore.EncoderConfig `json:"encoderConfig" yaml:"encoderConfig"`
	OutputPaths []string `json:"outputPaths" yaml:"outputPaths"`
	ErrorOutputPaths []string `json:"errorOutputPaths" yaml:"errorOutputPaths"`
	InitialFields map[string]interface{} `json:"initialFields" yaml:"initialFields"`
}
```
`zap.NewProductionEncoderConfig()`で`encoderConfig`を定義し、ロギング時間のキー名`TimeKey`とタイムスタンプ`EncodeTime`の設定を行います。
そして最後に、`config.build(zap.AddCallerSkip(1))`でLoggerを生成します。
`zap.AddCallerSkip(1)`はｍLoggerの呼び出し元ファイルの行番号を表示するために必要となります。

またメッセージのレベルごとにfuncを用意してあげます。

```go:logger
func Info(message string, fields ...zap.Field) {
	log.Info(message, fields...)
}

func Debug(message string, fields ...zap.Field) {
	log.Debug(message, fields...)
}

func Error(message string, fields ...zap.Field) {
	log.Error(message, fields...)
}
```
呼び出し元でloggerを仕込みます。

```go:main.go
package main

import (
	"github.com/suzuki0430/banking-practice/app"
	"github.com/suzuki0430/banking-practice/logger"
)

func main() {
	logger.Info("Starting the application...")
	app.Start()
}
```
プログラムを実行すると、以下のようなメッセージが表示されます。

```
{"level":"info","timestamp":"2022-03-25T21:44:40.626+0900","caller":"banking-practice/main.go:11","msg":"Starting the application..."}
```

# 参考資料

https://qiita.com/emonuh/items/28dbee9bf2fe51d28153

https://christina04.hatenablog.com/entry/golang-zap-tips
【GitHub】基本の使い方


### Githubに初回コミット

```
git init
```
git管理するためのレポジトリを新規作成

```
git add .
```
pushするファイルを選択 git add . で全ファイル選択
特定のファイルを指定したい場合は、git add <ファイル名>

```
git status
```
```
git commit -m"initial commit"
```

```
 git remote add origin リポジトリのURL
```
```
git push origin ブランチ名
```

### ブランチを作成する
新しくブランチを作成し、作成したブランチにチェックアウトできる便利なコマンド！
```
git checkout -b ブランチ名
```

### 作業後にブランチをマージする
(1)git add　でファイルを追加
(2)git status で中身を確認
(3)git commit -m"メッセージ"

ブランチはmasterと同じように git push origin ＜ブランチ名＞！
```
git push origin ブランチ名
```
マージするために一旦、マージ先に移動する
```
git checkout マージ先
```
念の為、git branchで確認！
```
git merge ブランチ名
```
```
git push origin マージ先
```

#### masterにマージした後に新しいbranchを切る！
```
#　1. mainに移動します
git checkout main
# 2. ローカルファイルにファイルを反映させます
git pull origin main
# 3. 新しいブランチを切って作業開始！:D
git checkout -b 新ブランチ名
```


## 番外編　
##### ★branchの切り替えを忘れたまま作業してしまった時の対処法
これはたまにやらかしてしまうのでメモしておきます....
下記のコマンドで作業した内容も本来のブランチ先に引き継いでくれます！
```
git stash
git checkout　ブランチ名
git stash pop
```

##### ★コミットメッセージを間違えた！
commitした後にコミットメッセージを間違えてしまったことがあるのでメモ
※下記コマンドは、直前のコミットメッセージを修正する場合
2つ以上前は、違うコマンドなので注意！
```
git commit --amend -m "新しいメッセージ"
git push --force origin master
```
aws_datasync_location_s3 で Ensure bucket access role has s3:ListBucket permission

## 事象発生条件
- terraform
- AWS DataSync利用
- クロスリージョンのs3が対象
- DataSyncはコピー先にいる

## 事象
- terraformでクロスリージョン間のs３で、aws_datasync_location_s3を利用した時に以下のエラーが発生しました。

```
could not perform s3:ListObjectsV2 on bucket xxxxxx.
Access denied. Ensure bucket access role has s3:ListBucket permission.
```

## 原因

単純にバケットに権限がないのですが、<font color="red">コピー先</font>の場合は、`bucket_access_role_arn`に権限がないだけなのですが、<font color="red">コピー元</font>の場合は、その限りではありません。
```terraform
resource "aws_datasync_location_s3" "xxx" {
  s3_bucket_arn = xxxxx
  subdirectory  = "/"

  s3_config {
    bucket_access_role_arn = xxxxxxxx
  }
}
```

<font color="red">コピー元</font>の場合は、バケットポリシーに権限がありません。
<font color="blue">terraformの実行ユーザの権限</font>がバケットポリシーに割り当てられていないと事象のエラーが発生します。
（試していないないですが、terraformの実行ユーザにバケットポリシーで設定した権限があれば大丈夫かと）
以下の部分の`arn:aws:iam::1111222233334444:role/datasync-config-role`ですね。
```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": [
                    "arn:aws:iam::1111222233334444:role/datasync-config-role",
                    "arn:aws:iam::1111222233334444:role/datasync-transfer-role"
                ]
            },
            "Action": [
                "s3:GetBucketLocation",
                "s3:ListBucket",
                "s3:ListBucketMultipartUploads"
            ],
            "Resource": [
                "arn:aws:s3:::example-source-bucket"
            ]
        },
```

## 参考
- https://qiita.com/calorie/items/8c5f81bd4597246f481f
- https://aws.amazon.com/jp/premiumsupport/knowledge-center/datasync-transfer-cross-account-s3/
ロガーもどきを作る時のコツ

```sample.rb
def put_log(message)
  puts "#{`hostname`.chomp}:#{caller.first}:#{message}"
end

def method_a
  put_log('メッセージ')
end

method_a
```

実行結果

```
LAPTOP-5EMLK46H:sample.rb:6:in `method_a':メッセージ
```

`LAPTOP-5EMLK46H` は私のノートPCのマシン名。

どのマシンでのどのプログラムのどのメソッドでの出来事なのかというのが大事。
cscの作法 その107

# 概要
cscの作法、調べてみた。
練習問題やってみた。

# 練習問題

１０００行超えのソースコードをコンパイルせよ。

# 方針

- githubでソースをお借りして、csc通る様に、変更を加える。


# 参考にしたページ

https://github.com/powerbombkun/Tetris

# コンパイル手順

```
>csc AbstractPiece.cs MainForm.cs  MainModel.cs  ModelController.cs NextBlockControl.cs PieceI.cs  PieceJ.cs PieceL.cs  PieceO.cs  PieceParameter.cs PieceS.cs  PieceT.cs  PieceType.cs PieceZ.cs  Position.cs ResourceUtility.cs TetrisFieldControl.cs tetris.cs


```

# 写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/936b8b42-e28c-f34b-9c6a-bc0e424ae84e.png)

以上。
Azure ADでログインするPCからのNASのファイル共有

# はじめに
　Windows11のログインをAzure ADのアカウントで行っている場合に、NASで利用する[Synology](https://www.synology.com/ja-jp)にエクスプローラからアクセスしてもユーザーIDの認証時、下記のエラーでログインできない、と約1年ぐらいあきらめていました。

　その解決策がわかりましたので、そのメモです。

## MicrosoftアカウントでのWindowsログインでは発生せず

　Microsoftアカウント（Gmailで）を持っており、そちらで同PCにログインした場合は、難なくSynologyのNASシステム（DSM）に設定したアカウントでログインできるという結果に。

https://kb.synology.com/ja-jp/DSM/tutorial/Why_am_I_asked_to_enter_user_credentials_at_every_access_to_my_Synology_NAS

https://kb.synology.com/ja-jp/DSM/tutorial/Why_cant_access_shared_folder

これらのナレッジにある事項はほぼクリアしています。Azure ADのアカウントの場合だと何かが違うと...

## エラーメッセージに注目

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/419691/451dae07-d47f-7eb2-223a-5896c2c49204.png)

　パスワードが違います等ではなく、「指定されたログオン セッションは存在しません。そのセッションは既に終了している可能性があります。」

って何だろうとぐぐると、NASを提供するIOデータさんにこのようなコンテンツがありました。

https://www.iodata.jp/support/qanda/answer/s31035.htm

> ユーザ名」の欄を「ユーザー名\ユーザー名」と変更のうえ設定してください。

**ユーザー名\ユーザー名**てなんでだ?と思いながらやってみると、難なくつながりましたw

## 「ユーザー名\」の部分は何でもよい

　うまくいったもののの、ユーザー名\ユーザー名って何だと考えたところ、\より前の先頭は何でもよい（要はSynologyの認証上はn/a）何だろうと設定変更してみました。
　本認証は、Windows資格情報の仕組みを使っています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/419691/261689d3-8db0-e3e3-3bcf-a0f11531a493.png)

このように変更しても、利用上は変わらずでした。なので、Azure ADのアカウントでWindowsにログインしている場合、NASの認証で行うにはこの形式でと、分かってしまえば何でもない結論でした。

# おわりに

　困っているときには、なかなか回答にたどり着けないものですね。わかってから下記のようなブログも見つかりました（ID前半の記載はIPアドレスでも他でもOKですね）

https://fisf.biz/nas-synology-ds220j/
特定の型をもつオブジェクトの配列から特定のキーとそのキー自身をバリューにもつ型を定義する

## やりたいこと

特定の型のオブジェクトが格納されている配列から、そのオブジェクトの特定のキーとそのキー自身をバリューとするオブジェクトを型定義したかった。

例えば次のような配列から

```typescript
const objects = {
  fruits: [
    { key: 'apple', value: 'りんご' },
    { key: 'orange', value: 'オレンジ' },
    { key: 'grape', value: 'ぶどう' },
  ],
  animals: [
    { key: 'dog', value: '犬' },
    { key: 'cat', value: '猫' },
    { key: 'bird', value: '鳥' },
  ],
}
```

次のような型定義をしたい。
```typescript
type Fruits = {
  apple: "apple";
  orange: "orange";
  grape: "grape";
}

type Animals = {
    dog: "dog";
    cat: "cat";
    bird: "bird";
}
```

今回は各オブジェクトから期待する型を生成できるObjectKey型の作成を目標とした。

```typescript
type Fruits = ObjectKey<typeof objects.fruits>
type Animals = ObjectKey<typeof objects.animals>
```

## 型アサーション
今回は`"dog"`や`"cat"`のような特定の値を定義したいため、型アサーションを利用する。

```typescript
const objects = {
  fruits: [
    { key: 'apple', value: 'りんご' },
    { key: 'orange', value: 'オレンジ' },
    { key: 'grape', value: 'ぶどう' },
  ],
  animals: [
    { key: 'dog', value: '犬' },
    { key: 'cat', value: '猫' },
    { key: 'bird', value: '鳥' },
  ],
} as const
```

## 一応できた

mapped typesを利用して一応、期待する型を表現することはできた。

```typescript
type ObjectKey<T extends string> = {
  [K in T]: K
}

type Fruits = ObjectKey<typeof objects.fruits[number]['key']>

// type Fruits = {
//   apple: "apple";
//   orange: "orange";
//   grape: "grape";
// }
```

しかし、これだと具体的な型を定義する場合に、冗長な記述が必要になる。
またシンプルなstring型を渡すこともできるので、想定外の使い方ができてしまう。

ちなみに文字列を渡すと以下のようになる
```typescript
type ObjectKey<T extends string> = {
  [K in T]: K
}

type Hoge = ObjectKey<'hoge'>

// type Hoge = {
//   hoge: "hoge";
// }
```
これはこれで使い道があるかもしれないが...

## もう少し厳密にしてみた

```typescript
type ObjectKey<T extends Readonly<Array<{ key: string; value: string }>>> = {
  [K in T[number]['key']]: K
}

type Fruits = ObjectKey<typeof objects.fruits>
type Animals = ObjectKey<typeof objects.animals>
```

Tには特定の型を持つオブジェクトを格納した配列しか入れませんという誓約をし、Tの制約を強くすることで型の厳密さがあがった（制約と誓約）。

また、型ObjectKeyから型を生成するときの記述量も減らすことができた。

個人的にはtypeofの記述もなくしたいところだが、今の自分ではやり方がわからなかったので誰か教えて欲しいところ。

満点とは言えないが個人的に満足な型を作ることができた。

## まとめ
TypeScriptで作りたい型を作る過程が最近楽しい。
使い道がわからない機能や使ったことがない機能がたくさんあるので、うまく使いこなせるようになりたい。

## 参考
https://www.typescriptlang.org/docs/handbook/2/generics.html

https://www.typescriptlang.org/docs/handbook/2/mapped-types.html

https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#type-assertions
cscの作法 その106

# 概要
cscの作法、調べてみた。
練習問題やってみた。

# 練習問題

時刻を表示せよ。

# 参考にしたページ

https://lets-csharp.com/solve-maze/

# 写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/0adafa8a-5435-dedc-20b7-fda58c77fae1.png)

# サンプルコード

```

using System;
using System.Windows.Forms;
using System.Drawing;
using System.ComponentModel;
using System.Collections.Generic;

public partial class Form1 : Form {
	List<Image> ImageNumbers = new List<Image>();
	Image ImageColon;
	Timer Timer = new Timer();
	DateTime DateTimeStart = DateTime.Now;
	TimeSpan TimeSpan = TimeSpan.Zero;
	public Form1() {
		Text = "Sebun";
		ClientSize = new Size(220, 140);
		this.DoubleBuffered = true;
		this.BackColor = Color.Black;
		ImageNumbers.Add(Image.FromFile("number0.png"));
		ImageNumbers.Add(Image.FromFile("number1.png"));
		ImageNumbers.Add(Image.FromFile("number2.png"));
		ImageNumbers.Add(Image.FromFile("number3.png"));
		ImageNumbers.Add(Image.FromFile("number4.png"));
		ImageNumbers.Add(Image.FromFile("number5.png"));
		ImageNumbers.Add(Image.FromFile("number6.png"));
		ImageNumbers.Add(Image.FromFile("number7.png"));
		ImageNumbers.Add(Image.FromFile("number8.png"));
		ImageNumbers.Add(Image.FromFile("number9.png"));
		ImageColon = Image.FromFile("colon.png");
		Timer.Interval = 1000 / 60;
		Timer.Tick += Timer_Tick;
		DateTimeStart = DateTime.Now;
		Timer.Start();
	}
	void OnFinish() {
		Timer.Stop();
	}
	private void Timer_Tick(object sender, EventArgs e) {
		TimeSpan = DateTime.Now - DateTimeStart;
		Invalidate();
	}
	protected override void OnPaint(PaintEventArgs e) {
		DrawTime(e.Graphics);
		base.OnPaint(e);
	}
	void DrawTime(Graphics graphics) {
		int minutes10 = TimeSpan.Minutes / 10;
		int minutes1 = TimeSpan.Minutes % 10;
		int seconds10 = TimeSpan.Seconds / 10;
		int seconds1 = TimeSpan.Seconds % 10;
		int milliseconds100 = TimeSpan.Milliseconds / 100;
		int milliseconds10 = (TimeSpan.Milliseconds % 100) / 10;
		Image imageMinutes10 = ImageNumbers[minutes10];
		Image imageMinutes1 = ImageNumbers[minutes1];
		Image imageSeconds10 = ImageNumbers[seconds10];
		Image imageSeconds1 = ImageNumbers[seconds1];
		Image imageMilliseconds100 = ImageNumbers[milliseconds100];
		Image imageMilliseconds10 = ImageNumbers[milliseconds10];
		int a = 22;
		graphics.DrawImage(imageMinutes10, new Rectangle(a * 0, 30, 20, 40));
		graphics.DrawImage(imageMinutes1, new Rectangle(a * 1, 30, 20, 40));
		graphics.DrawImage(ImageColon, new Rectangle(a * 2, 30, 20, 40));
		graphics.DrawImage(imageSeconds10, new Rectangle(a * 3, 30, 20, 40));
		graphics.DrawImage(imageSeconds1, new Rectangle(a * 4, 30, 20, 40));
		graphics.DrawImage(ImageColon, new Rectangle(a * 5, 30, 20, 40));
		graphics.DrawImage(imageMilliseconds100, new Rectangle(a * 6, 30, 20, 40));
		graphics.DrawImage(imageMilliseconds10, new Rectangle(a * 7, 30, 20, 40));
	}
	[STAThread]
	public static void Main() {
		Application.Run(new Form1());
	}
}





```

以上。
[AtCoder]pythonで整数のべき乗の計算にmath.powは使わない（pow() or **を使う）

## 結論
べき乗の計算時はpow or ** を使おう

## math.powの仕様

[公式ドキュメント](https://docs.python.org/ja/3/library/math.html)より引用する
> math.pow(x, y)
x の y 乗を返します。例外的な場合については、 C99 標準の付録 'F' に可能な限り従います。特に、 pow(1.0, x) と pow(x, 0.0) は、たとえ x が零や NaN でも、常に 1.0 を返します。もし x と y の両方が有限の値で、 x が負、 y が整数でない場合、 pow(x, y) は未定義で、 ValueError を送出します。
組み込みの ** 演算子と違って、 math.pow() は両方の引数を float 型に変換します。正確な整数の冪乗を計算するには ** もしくは組み込みの pow() 関数を使ってください

math.pow()は両方の引数をfloatに変換して計算するため、正しくない
※math.pow()の返り値はfloatであることから、floatに変換していることがわかります。



## 整数の場合

下記で結果を確認します。

``` python
import math

def calc_pow(a, b):
    print("pow:{}".format(pow(a, b)))
    print("** :{}".format(a**b))
    print("math.pow:{}".format(math.pow(a, b)))
    print("int(math.pow):{}".format(int(math.pow(a, b))))
    return
if __name__ == "__main__":
    calc_pow(3, 115)

```

結果
```
pow          :7395104114874202511988394360121831439224179537192802907
**           :7395104114874202511988394360121831439224179537192802907
math.pow     :7.395104114874203e+54
int(math.pow):7395104114874203067169776178544793179075482331828453376
```

### 小数点の場合

```python
#　関数は同じため省略
    calc_pow(0.123, 0.456744)
    calc_pow(11000.555, 0.0001)
```

結果
```
pow:     0.38398973983417967
** :     0.38398973983417967
math.pow:0.38398973983417967
int(math.pow):0
pow:     1.0009310032151988
** :     1.0009310032151988
math.pow:1.0009310032151988
int(math.pow):1
```

小数点ではpow or ** とmath.powは同じ結果であった。
そのためpow or **を使用したほうがよい

## pow と ** の違い
下記に詳しい記事がありましたので、ご参照ください
https://qiita.com/R_olldIce/items/ab3f382643e92122f8ef

## 参考資料
https://docs.python.org/ja/3/library/math.html
｢新しいLinuxの教科書｣個人的メモ chapter01

# guiとcli
* gui
  マウスとかとかで操作できる
* cli
  キーボードからコマンドを入力する

# この本がcliを強く進める理由
1.作業効率がよくなる
2.guiの操作を覚えてもあまり意味がない
3.プログラムの連携がしやすい
4.処理の自動化がしやすい

#### 1.作業効率がよくなる
まとめて一気に変更とかができる

例:aで始まるファイルを探す
```言語:ディレクトリ構造
test
 |-apple.txt
 |-abc.txt
 |-apex.txt
 |-beat.txt
 |-cclemon.txt
```
 
```言語:実行したコマンド
ls a*
```

```言語:結果
abc.txt  apex.txt  apple.txt
```
#### 2.guiの操作を覚えてもあまり意味がない
guiの進化は早いため数年たったら使い方が変わってしまう
cliは使い方が大きく変化することはほとんどない

#### 3.プログラムの連携がしやすい
入出力をパイプ`|`とかでつなげてプログラム間でやり取りできる

例
`sample.txt`というファイルから`abc`という文字列を検索して､その出力結果をソート
```言語:sample.txt
abcdefg
badedcc
ertyvvv
ccabc
trewabc
ooppabcaaabc
bbabc
```
```言語:実行したコマンド
grep "abc" sample.txt | sort
```
```言語:結果
abcdefg
bbabc
ccabc
ooppabcaaabc
trewabc
```
abcが入っている行を取り出す->行の最初の文字でソート

#### 処理の自動化がしやすい
よく使うコマンドはファイルに書いてそのファイルを読み込ませれば何度でも繰り返し使える

### ログアウト
サーバーとかでは作業が終わったら基本ログアウトする
```
exit
```
`logout`ではないので注意

### シャットダウン
osを完全に停止
個人のパソコンではよく操作するが､サーバーは基本止めない(シャットダウンしない)

とても重い動作なのでrootユーザーになる必要がある
```言語:シャットダウン
shutdown -h now
```
```言語:再起動
shutdown -r now
```
`shutdown -h now`でシャットダウンできない時
`shutdown`コマンドをフルパスでつかう
```言語:フルパスシャットダウン
/sbin/shutdown -h now
```
さくらvpsにRailsアプリをデプロイするまで (3) NginxとGitHub導入

# 0.道のり

　デプロイまでの道のりは遠い。Herokuだったら一瞬で終わるけど、勉強がてらやってみる。

# 1.Nginxの導入

　WebサーバーであるNginxを導入する。CentOSの標準ではApacheだが、静的コンテンツのやりとりや並列処理に向いているためである。私が開発するアプリは基本的にテキストのやりとりしかしない。Nginxのほうが良い。
　こちらを参考にした。

https://www.sbbit.jp/article/cont1/65256

　導入についてはよい記事があった。

https://zenn.dev/kirk3110/articles/064040d60ca5e3

　まずはyumのレポジトリの一部を変更する。rootユーザーでログインする。

```
# vim /etc/yum.repos.d/nginx.repo
```

```etc/yum.repos.d/nginx.repo
[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/centos/7/$basearch/
gpgcheck=0
enabled=1
```

あとはyum installを行う。

```
# yum -y install nginx --enablerepo=nginx
```

`nginx -v` でバージョンが表示されれば問題なし。あとはWEBサーバーを起動させてから自動起動の設定もさせる。

```
# sudo systemctl start nginx
# systemctl enable nginx.service
```

さくらvpsサーバーのIPアドレスをブラウザに打ち込む。welcome to nginxが表示されれば成功だ。

### うまくいかないとき

うまく表示されない場合はさくらvpsのパケットフィルタ設定とfirewall設定を見直してみると良い。パケットフィルタを有効にしている場合、Web(ポート80/443)を許可しないといけない。

https://manual.sakura.ad.jp/vps/network/packetfilter.html

firewallはこちらが詳しい。

https://knowledge.sakura.ad.jp/10583/


#### おっと
記事を書いている時にrepoファイルが公式のものと異なることに気づいた。
http://nginx.org/en/linux_packages.html

しかし導入してしまったので、このままにする。


# 2. GitHubの導入

　ファイルを自分のPCからぽちぽちアップロードするのはいやなのでgithubを使う。自分のgithubリポジトリからさくらvpsへクローンするのだ。やっていく。

　まずは鍵をサーバー上で作成する。

```
#  ssh-keygen -t rsa -b 4096 -C "aaa@aaa.com"
```

`aaa@aaa.com`　のところにgithubで登録したメールアドレスを入れる。

生成された公開鍵を表示させる。

```
# cat ~/.ssh/id_rsa.pub
```

公開鍵をコピーして、githubの設定画面のところに貼り付けてやる。
詳細は下記のサイトを参考にした。

https://pointsandlines.jp/server-infra/sakura-github

.sshフォルダにconfigファイルを作成し、githubのあれこれを設定していく。

```
# touch .ssh/config
# vi .ssh/config
```

```.ssh/config
Host *
  IdentityFile ~/.ssh/id_rsa
  IgnoreUnknown UseKeychain
```

この文面は公式ページと参考にしたサイトとは異なるが、わたしはこうしたらうまくいった。


https://docs.github.com/ja/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent

あとはgitをcloneしてみる。
```
# git clone git@github.com:(ユーザー名)/リポジトリ.git
```


# 3. つづく

　すこしずつ進んできた。次はHomebrewを入れる。これがすこし手こずったので、詳細を今後書いていく。
スタートアップルーチンという言葉の定義に悩まされた話

最近は１２ステップ組み込みOS本に取り組んでいます。
知らなかった概念が続々登場してくるので都度調べているのですが、理解に時間がかかった用語の紹介を一つします。
「スタートアップルーチン」というもので、どうもLinux(汎用OS)のC言語界隈と組み込み界隈で言葉の定義が微妙に違う気がします。

C言語界隈の記事
https://tanakamura.github.io/pllp/docs/linker.html

組み込み界隈の記事
https://interface.cqpub.co.jp/wp-content/uploads/interface/2012/09/if09_093.pdf

そもそもスタートアップルーチンという言葉はC言語の言葉であり、main関数が呼び出される前の処理、main関数を呼び出して関数の終了をさせるもの、のように見えます。
ld(リンカー)コマンドで生成されたELFファイルは_startというラベルから実行されるようです。

組み込みでスタートアップルーチンと言う場合、CPUのリセット直後に行う処理でRAMやSPの初期化をしてmain関数に遷移するもの、として捉えられているようです。C言語の定義に加えて初期化処理が加わっています。また呼ばれるのもELFファイルの実行時ではなくリセット時という認識に見えます。組み込みでは複数のELFファイルを同時に動かすことが（あまり）ないことからこのような定義になっているのではないかと思います。

また実行開始位置は_startラベルとは限らず、各CPU毎に微妙に異なるラベルから始まるようです。(SH-7750だと:start LPC2388だと_startup:等)



間違っていたらどなたかコメントで指摘していただけると嬉しいです。