OmniAICreator/Qiita-1.07M huggingface dataset:
Nuxt.jsでページが表示される(レンダリング)前に処理を加える方法【middlewareを使用】

Nuxt.jsでページが表示される(レンダリング)前に処理を加える方法になります。
認証の処理や別ページにリダイレクトする時などに使えます。

## middlewareディレクトリにファイルを作成する。

`middleware`ディレクトリ配下にファイルを作成します。

```ts:auth.ts
import { Middleware, Context } from '@nuxt/types'
const auth: Middleware = ({}: Context) => {}
export default auth
```
### リダイレクトする場合

```ts:auth.ts
import { Middleware, Context } from '@nuxt/types'

const auth: Middleware = ({ redirect }: Context) => {
  redirect('/')
}

export default auth
```
### Vuexにアクセスする場合

```ts:auth.ts
import { Middleware, Context } from '@nuxt/types'

const auth: Middleware = ({ store }: Context) => {
  store.dispatch('user/setUserId')
  const userId = store.getters['user/getUserId']
}

export default auth
```

### axiosを使う場合

```ts:auth.ts
import { Middleware, Context } from '@nuxt/types'
import { NuxtAxiosInstance } from '@nuxtjs/axios'

const auth: Middleware = async ({ $axios }: Context) => {
  const response = await $axios.get(
    'https://jsonplaceholder.typicode.com/users'
  )
  console.log(response.data)
}

export default auth
```
`async/await`も使用できます。

その他の使用はNuxtのcontextにまとめられています。

https://ja.nuxtjs.org/docs/2.x/internals-glossary/context/

## レンダリングされる前に処理をしたいページでmiddlewareを設定する

```vue:page.vue
<script lang="ts">
import Vue from 'vue'

export default Vue.extend({
  middleware: 'auth'
})
</script>
```
作成したmiddlewareを使いたいページで設定します。

```js
middleware: ['auth', 'check']
```
複数ある場合は、上記のように配列で記述します。


## middlewareの例

```ts:auth.ts
import { Middleware, Context } from '@nuxt/types'

const auth: Middleware = async ({ store, redirect }: Context) => {
  const userId = store.getters['user/getUserId']
  if (userId) {
    return redirect('/logined')
  }
  redirect('/')
}

export default auth
```
```ts:user.ts
import { GetterTree, ActionTree, MutationTree } from 'vuex'
import axios from 'axios'
export type RootState = ReturnType<typeof state>

export const state = () => ({
  userId: 0
})

export const getters: GetterTree<RootState, RootState> = {
  getUserId: (state) => state.userId
}

export const mutations: MutationTree<RootState> = {
  SET_USER_ID(state, userId) {
    state.userId = userId
  }
}

export const actions: ActionTree<RootState, RootState> = {
  async setUserId({ commit }) {
    try {
      const response = await axios
        .get('https://jonplaceholder.typicode.com/users')
        .catch((error) => error.resopnse)

      if (response.status !== 200) {
        throw new Error('エラー')
      }

      commit('SET_USER_ID', response.data[0].id)
    } catch (error) {
      console.log(error)
    }
  }
}
```
`middleware`はVuexにもアクセスできるので、VuexにユーザID等がセットされているかによって、リダイレクト先を変えたりもできます。

## 参考
https://ja.nuxtjs.org/docs/2.x/directory-structure/middleware/
[入門]sshにおいての疑問点とその解消

# sshの設定
sshの練習に自分のPCにsshでログインしたとき、パスワードでログインしているか、パスフレーズでログインしているか分からなかったので、公開鍵でログインしているかの確認をどうすればいいか調べたので、その備忘録として

## パスワードとパスフレーズ
sshではユーザ認証の段階で**「パスワード」**による方法か**「公開鍵暗号方式」**のどちらかが選べるが、公開鍵暗号方式の方が安全性は高くなる。
詳細は以下を参考に。


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

## 鍵の削除
何度も鍵を作り直したため、いくつも鍵ができてしまった。
そのままでも、特に問題はなかったが整理のために鍵を削除した。
方法としては、sshのフォルダまで移動してrmすれば良い。
詳細は以下を参考に。

https://t-hsn.com/tech/201907/gitlab-sshkey/

## 確認方法
### パスワードとパスフレーズを違うものにする
今回はあくまで確認としてさくっと自分のPCにsshでログインする予定だったので、何も考えずパスワードとパスフレーズを同じにしてしまった。
これでは、sshでパスワード、パスフレーズの入力をするときに同じで、どちらでログインしたかわからない。
2つを違うものにすることで、入力するときにどちらでログインしているか分かりやすくなる。

ただ、今ターミナルを確認してみたところ
おそらくだが、パスワードでログインするときは上のように要求されて、パスフレーズでログインする時では下のように要求される。

```
Password:

Enter passphrase for key '/Users/user_name/.ssh/id_rsa
```



## 公開鍵暗号方式によるsshのログインまでの流れ
簡単に公開鍵暗号法式によるsshのログインの流れをまとめると、
1.公開鍵と秘密鍵をローカルで作成
2.ローカルからリモートに公開鍵を送る
3.リモートに公開鍵を保存
4.ログイン
というのが大変大雑把な流れである。
詳細は以下を参考に

https://qiita.com/suzuki-koya/items/af4b511d40b6362da60a

自分がつまづいたところについてのみ、以下に詳しく書いておく。
### パーミッションとは
パーミッションとは簡単にいうと、ファイル、フォルダへのアクセス権である。
sshでファイルを読み、書き、実行するためには、パーミッションを700に設定しておく必要がある。
詳細は以下を参考に

https://b-risk.jp/blog/2020/08/about-permission/

http://www3.u-toyama.ac.jp/furuta/unix-permit.html

https://qiita.com/jey0taka/items/06f505cc8f407cb21002

### authorized_keysとは
自分の中ではauthorized_keysという鍵(秘密鍵)が、他の鍵のようにあるのかと思っていたが、
**鍵ではなくファイルであり、**ログインする時の鍵を指定する役割を持つようである。
詳細は以下を参考に

https://www.ssh.com/academy/ssh/authorized-keys-file


## メモ
sshと公開鍵暗号方式の理解が頭の中で混ざっていたので、どこでどうつまづいているのか理解できていなかった。
2つを整理すると
sshはリモートログインを安全に行うための手段であり、
公開鍵暗号方式は通信を安全に行うための手段である。
sshの中で、サーバにリモートでログインする時に公開鍵暗号方式が使用されている。
ただ疑問として、sshでリモートログイン中の通信はどうなっているかは、残ったままだけど

あと、一応ローカルでどんな通信が行われたか確認できるコマンドとして

```
ssh -v localhosts
```
があると教えてもらった。
このコマンドを実行すれば、ローカルでどんな通信が行われていたか確認できる。
この方法でもパスワード、パスフレーズのどちらでログインしているか確認できる。

また、今回は自分のPCにリモートログインするというおかしな状況になっているため、公開鍵と秘密鍵を自分で作成して、公開鍵を自分に送るというなんと無駄な操作を行なっているが、実際にsshを行う時には、公開鍵を何らかの方法(おそらくscpなど)で送ることで、認証を行えるようにする。


### sshまでの概略
研究室のmacへsshにゲスト接続しようとしたところエラーが出たので、一旦imacへsshすることで基本事項の確認をしようと思う。

:::note info
基礎知識
クライアント：接続元のサーバー(手元で使うパソコン)
リモートサーバー：接続雨先のサーバー
:::

## 追記
### Mac pro接続時のエラー
2022年から研究で大規模計算する都合上、研究室のmac proやスパコンを使う必要が生じたので、まず研究室のmac proにsshしようとしたところ、以下のようなエラーが出たでの備忘録として解決するまでの過程を載せておく。

```
permission denied (publickey)
```
いろいろなサイトを調べて、何個か試してみたがうまくいかなかったので、とりあえず、他のiMacに接続してみることにした。

### iMacへの接続
iMacへの接続に関しては、こられのサイトを元に行ってみた。

https://atmarkit.itmedia.co.jp/ait/articles/1503/20/news007.html

https://qiita.com/suzuki-koya/items/af4b511d40b6362da60a

結果として成功したのだが、上記の方法でmac proに接続しようとしたができなかった。

### 原因の予測
現在考えられる原因としては、mac proで公開鍵を登録するときにmac pro自身にゲストとしてログインしているためsudoなど権限を持った状態で公開鍵を登録することが必要なのかもしれない
また、もう1点として、各ファイルに対するパーミッションの設定もきちんとしておかないといけない。
DatabricksのMLflowにてExperimentを作成時にフォルダが存在しない場合（RESOURCE_DOES_NOT_EXIST）のエラーへの対応方法

## 概要
DatabricksのMLflowにてExperimentを作成時にフォルダが存在しない場合にはエラーとなるため、事前にフォルダの作成が必要です。

### エラー画面
Experimentを作成しようとすると、下記のようなエラーが表示されました。

```python
import mlflow

experiment_path = "/test/folder/expperments_1"
mlflow.set_experiment(experiment_path)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/f30cad6a-4b17-fb0c-a23a-2243f7010828.png)


> INFO: '/test/folder/expperments_1' does not exist. Creating a new experiment
RestException: RESOURCE_DOES_NOT_EXIST: Parent directory /test/folder does not exist.


"mlflow.set_experiment"のドキュメントにてExperimentを作成してくれるとの記載があるのですが、フォルダについての記載がありませんでした。
>If experiment does not exist, create an experiment with provided name.
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/d4f5946e-d83d-cdaf-31d0-29907689174c.png)

引用元：[mlflow — MLflow 1.17.0 documentation](https://www.mlflow.org/docs/latest/python_api/mlflow.html#mlflow.set_experiment)

## エラーへの対応方法
### 1. Databricks Workspaceタブにて、フォルダに移動後に右クリックして、"Create"-->"Folder"を作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/0f48a775-80cc-2a72-b023-914085ff80f9.png)

### 2. 想定のフォルダを作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/ddae6bcc-00e4-5ba0-62e5-74fc782c2616.png)

### 3. 再度、"mlflow.set_experiment"のコードを再実行
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/841a59ec-9a65-dbfe-9bbc-10e90027ead3.png)

### 4. Experimentが作成されていることを確認
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24031/01503159-acc1-1eca-23ca-9d69c69b3d50.png)
要件定義や外部設計時の設計ツール

要件定義や外部設計では様々な設計書、記法がある。
設計時に便利なツール一覧を記載する。

##プロセス中心
・ワークフロー図（業務フロー図）
・機能一覧
・表
・BPMN（Business Process Modeling Notation）
・NSチャート
　個々の処理を長方形で表し、繰り返し実行する場合は入れ子構造に、条件分岐は三角形で表す。
　![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1308027/dfb1e9c4-9853-5293-8de5-c5ce25c2a905.png)

・PAD図
　問題解析図とも呼ばれ、プログラムの制御構造を木構造的に表す図
　http://my-web-site.iobb.net/~yuki/book/bit-pad/

　↓wikipediaのより参考イメージ
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1308027/7a1d063b-2e6a-d4a0-ddd1-9ad0c48f11ee.png)
　https://ja.wikipedia.org/wiki/PAD_(%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2%E8%A8%AD%E8%A8%88)

##データ中心

・データフロー図（DFD）
・CRUD図
・ERD図
・ユースケース図

・オブジェクト図
・ロジックツリー
・オートマトン図（状態遷移図）
・シーケンス図
・デジションテーブル（決定表）
・デシジョンツリー（決定木）

##UML2.0

・クラス図
・オブジェクト図
・パッケージ図
・合成構造図（コンポジット構造図）
・コンポーネント図
・配置図
・ユースケース図
・アクティビティ図
・相互作用図
・シーケンス図
・コミュニケーション図
・相互作用概要図
・タイミング図
・ステートマシン図


###設計書

|No|仕様書分類|仕様書名|備考|
|:-:|:-|:-|:-|
|1|要件定義|システム概要|
|2||システム要件|
|3||外部インターフェイス一覧|
|4||機能一覧|
|5||画面一覧|
|6||画面レイアウト|
|7||帳票一覧|
|8||帳票レイアウト|
|9||業務フロー図|
|10|外部設計書|ファイル一覧|
|11||ファイル定義|
|12||テーブル一覧|
|13||テーブル定義|
|14||ERD|
|15||外部コード定義|
|16||データディクショナリ|
|17||外部インターフェイス定義|
|21||画面メッセージ一覧|
|22||バッチメッセージ一覧|
|23||画面遷移図|
|24||MQ一覧|
|25||ジョブ設計書|
|26||画面設計書|
|27||帳票設計書|
|28||処理機能記述書|
|29||画面説明書|
|30||帳票説明書|
|31||運用設計書|
|32||システム運用マニュアル|
|33||結合(統合)テスト計画書|
|34||テーブル定義書|
|35|コーディング規約|java,PHP等の開発標準規約|
|35||ネーミング規約|クラスやプログラム名等のルールを定義|
|36|内部設計書|プログラム一覧|
|37||プログラム仕様書|
|38||単体テスト計画書|
|39||ジョブ・ステップフロー図|
|40||ジョブフロー図|
|41||移行仕様書|
|42|単体テスト|単体テスト仕様書&結果報告書|
|43|結合テスト|結合(統合)テスト仕様書&結果報告書|
|44|総合テスト|総合(システム)テスト仕様書&結果報告書|
|45|テスト移行計画|移行計画書|
|46|本番移行|本番移行手順書|
|47|マニュアル|ユーザ操作マニュアル|
|48||システム運用手順書|

##編集履歴
21/6/3：作成
22/1/7：UML等一部追記
23/3/21：NSチャート、PAD図を追加
Git squash

# git squash してみた

## gitのコミットが頻雑になったのでスカッシュ実施

コミットが頻雑になってしまったので、コミットを一つにまとめたく、スカッシュしてみました。
以下にまとめます。

```
git checkout master <- target branch
git merge --squash develop <- source branch
git add .
git commit -m "squash merge"
git push
```

今まで勘違いしてました。
source branchでスカッシュしてました。
target branchでやらかしてました。

よもや、よもや、不甲斐なし

### 引用先

https://backlog.com/ja/git-tutorial/stepup/34/
docker-compose buildで詰まった

#エラー

以下のエラーが出た。

```
$ docker-compose build
db uses an image, skipping
test-db uses an image, skipping
chrome uses an image, skipping
Building app
Traceback (most recent call last):
  File "site-packages/docker/utils/build.py", line 97, in create_archive
  File "tarfile.py", line 1970, in addfile
  File "tarfile.py", line 250, in copyfileobj
  File "tempfile.py", line 481, in func_wrapper
OSError: [Errno 28] No space left on device

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "docker-compose", line 3, in <module>
  File "compose/cli/main.py", line 67, in main
  File "compose/cli/main.py", line 126, in perform_command
  File "compose/cli/main.py", line 302, in build
  File "compose/project.py", line 468, in build
  File "compose/project.py", line 450, in build_service
  File "compose/service.py", line 1125, in build
  File "site-packages/docker/api/build.py", line 160, in build
  File "site-packages/docker/utils/build.py", line 31, in tar
  File "site-packages/docker/utils/build.py", line 100, in create_archive
OSError: Can not read file in context: /Users/nami/Desktop/名称未設定フォルダ/Study_quest/名称未設定フォルダ/Study_quest/app/assets/fonts/font_1_honokamin.ttf
[8624] Failed to execute script docker-compose
```

初めは

```
OSError: Can not read file in context
```
で調べていたが解決せず

```
OSError: [Errno 28] No space left on device
```
こちらに注目して調べたところ
dockerの容量が足りないせいでcontextを読み込めずエラーになっていた。

#解決策

```
$ docker image prune
```
とすることで使っていないdockerイメージを削除することができる。
上記を実行しエラー解決に至った。
AWS CodeDeploy 過去のリビジョンを用いてデプロイを行う 先輩に教えてもらった内容メモ

# 目的

- CodeDeployにて過去のデプロイのリビジョンを用いてロールバックデプロイを行う方法を先輩から教えてもらったので忘れないようにメモする。

# 方法

1. 下記のようにAWSのサービス上で操作を行う。
    1. CodeDeployのホームを開く
    1. サイドメニューの「アプリケーション」をクリックする。
    1. デプロイしたいアプリ名をクリックする。
    1. 「リビジョン」をクリックする。
    1. デプロイしたいリビジョンを選択後、「アプリケーションをデプロイする」をクリックする。
    1. 「デプロイグループ」を選択、「リビジョンファイルの種類」を選択する(※リビジョンファイルの種類は基本zipを選ぶ)
    1. デプロイタイプなどのデプロイ設定に表示されている内容に問題が無いことを確認する。
    1. 「デプロイの作成」をクリックする。
    1. 指定したリビジョンを使ってデプロイが開始される。

# 先輩に教えてもらった用語

- リビジョン： 過去デプロイの履歴
- リビジョンファイル： 過去デプロイ時のソースコードなどのファイル
【AWS】S3の暗号化の形式

#プログラミング勉強日記
2021年6月3日

#S3の暗号化
　S3のデータの暗号化は保管時に暗号化形式として以下の4つの形式から選択する。

##SSE-S3
　SSEはepicor server side encryptionの略。標準的に使うもので、S3の標準暗号化式で簡単に利用できる。サーバーサイド側(S3側)で暗号化をする。暗号化キーの作成・管理をS3側で自動的に実施してくれる。
　ブロック暗号の1つである256ビットのAdvanced Encryption Standard(AES-256)という強固な暗号化の仕組みを使ってデータを暗号化する。


##SSE-KMS
　SSE-S3の次によく使われるもので、KMSはkey management serviceの略。AWS KMSに設定した暗号化キーを利用した暗号化を実施する。KMSは暗号キーを作って管理するS3ではない別のサービス。このサービスで鍵を作成し、その上でこの鍵を使ってS3で暗号化する。
　ユーザ側でAWS KMSを利用して暗号化キーを作成・管理することができる。クライアント独自の暗号キーを利用することもできる。そのため、独自に暗号化キーを作って管理をしたい場合に使う。


##SSE-C
　ユーザが指定したキーによるサーバー側の暗号化(SSE-C)を利用することができる。ユーザ独自のキーをSDKなどを介して設定し、S3に使うということをアプリケーション上で組み込むといった複雑な設定ができる。利用設定が管理が複雑になる。
　KMSとS3はマネージメントコンソールのS3の標準機能で使うが、SSE-CはSDKツールを使いながらアプリケーション上で構築するなど複雑な設定になるので基本はあまり使わない。しかし、ユーザが指定した独自のキーを独自に使いたい場合などに使用する。

##クライアントサイド暗号化(CSE)
　クライアントサイド側の暗号化では、S3に送信する前にデータを暗号化する方式。サーバーサイド側の暗号化では、データの送信後に暗号化する。
　KMSなどを利用して暗号化キーを作成・実施することができる。アプリケーション内に保存したマスターキーを利用して、事前に暗号化してそのあとにS3に送るということをアプリケーション上で組み込んで作れる。
Laravelのディレクトリ・ファイル

# ルーティング

## 【/routes/<font color="Red">web.php</font>】

- routes（ラウツ）

# コントローラー

### 【/app/Http/Controllers/<font color="Red">SampleController.php</font>】   

# モデル

### 【/app/<font color="Red">Message.php</font>】 

# マイグレーションファイル

### 【/database/migrations/<font color="Red">2021_06_23_205710_create_messages_table.php</font>】 

# ビュー

## デフォルトのレイアウト

### 【/resources/views/layouts/<font color="Red">default.blade.php</font>】 

## 任意のHtml

### 【/resources/views/samples/<font color="Red">request_form.blade.php</font>】 






# bootstrap ディレクトリ
index.phpを読み込み、最初に呼び出される、各種起動ファイルが配置されたディレクトリです。直接編集する機会は少ない。

## config ディレクトリ
configuration（設定）の略。このディレクトリには、アプリケーションの設定に関する各種ファイルが保存されている。

###app.phpファイル

- アプリケーションの設定ファイル

#### 初期設定
 
```php
'timezone' => 'Asia/Tokyo',

'locale' => 'ja',
```


#TrustProxies ミドルウェア
AWS上で正しく動作させるファイル

- app/Http/MiddleWare/TrustProxies.php


```php
protected $proxies = '*'; // 全てのプロクシを信頼する。
```





# database ディレクトリ
データベースのマイグレーション（DB設定）ファイルと、初期データの登録を行うためのファイル（シードファイル）などを配置するディレクトリです。

## public ディレクトリ
Laravelアプリケーションのドキュメントルート（公開ディレクトリ）となるディレクトリです。最初に読み込まれる index.php の他、画像、JavaScript、CSSファイルなども配置されます。



# storage ディレクトリ
- 各種データの保管を行う。
- アプリケーションにより使用されるファイルを保存 
- storage/app ディレクトリ、フレームワークが生成するファイル等を保存。 
- storage/framework ディレクトリ、 アプリのログが保存される storage/logs ディレクトリなどが含まれる。

## tests ディレクトリ
自動テストに関するコードを配置するディレクトリです。今回のテキストでは自動テストはとりあげません。

# vendor（ベンダー）  ディレクトリ
- composerでインストールしたパッケージが配置されるディレクトリです。

- Laravelのコアとなる仕組みに関するファイルなどもこのディレクトリに含まれる。



# .envファイル

見つからない場合は、【ls -a】 とコマンドを打つ

- laravel の環境設定ファイルとなる隠しファイル

- DB_CONNECTION=mysql から始まる行をさがす

- DB_DATABASE と DB_PASSWORD の値を編集する















- 
- 
- 
- 




- 1. Laravelで最初に読み込まれるファイルはどのファイルか？
 
・index.phpファイル

- 2. ビューが生成するのは何か？

・HTMLファイル

- ３.ルーティングに関するファイルが配置されるディレクトリはどのディレクトリか？

・routes ディレクトリ

- 3. コントローラやモデルのファイルを配置するのはどのディレクトリか？

・appディレクトリ

- 4. Laravelのドキュメントルートとなるのはどのディレクトリか？

・public ディレクトリ
Python matrix m行n列成分を取り出したい

リストの場合

```py
m = [[10, 20], [30, 40]]
print(m[0][1])
```

```
20
```

matrix クラスを使用する場合

NG

```py
import numpy as np
m = [[10, 20], [30, 40]]
mat = np.matrix(m)
mat[0][1]
```

```
IndexError: index 1 is out of bounds for axis 0 with size 1
```

OK

```py
import numpy as np
m = [[10, 20], [30, 40]]
mat = np.matrix(m)
mat[0].A1[1]
```

```
20
```

# 参考記事

https://qiita.com/inon3135/items/54bf58c7c50c59e8ae3c
VB.NET LabelのSizeが変えれない問題

<h2>環境</h2>
Visual Studio 2019
.NET Framework 4.7.2
<h2>問題</h2>
Windowsフォームアプリケーションでフォームに配置したLabelのプロパティのSizeを変更しても反映されない
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1585226/385d4c6e-a3d9-3dcd-f4a8-70862eff9cde.png)


<h2>解決策</h2>
LabelのプロパティからAutoSizeをFalseにすることで解決しました
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1585226/9902e147-3d18-e908-bb9b-c37a1910397a.png)
Error running pod install Error launching application on iPhone 12 Pro Max.


Flutterでiosをビルド時に以下のエラーに遭遇

```
Error running pod install Error launching application on iPhone 12 Pro Max.
```

ios/Podfileの最初を以下のように修正するとビルドは成功した

```
# Uncomment this line to define a global platform for your project
platform :ios, '10.0'
```
環境変数を利用したコードのCI　process.env.hogeってどうすればいいの？

## はじめに
Node.js(Express)でWeb APIをCallする際のAPI Keyを環境変数にしていた場合に、GitHub ActionsでJestによるCIを回そうとして躓いたのでその時の解決方法を備忘録として残しておく。

## どんなテストをしようとしたか？
Node.js(Express)で以下のようなソースコードを実装していて、これのAPIテスト（あえて今回はモックにしていない）をJest×Supertestで実装し、それをCI上で回そうとしていた。
テスト対象のソースコード（抜粋）は以下。
`${process.env.COUNTRYSTATECITY_API_KRY}`の部分で環境変数を使っている。

```js:controller.js
const axios = require('axios').default;

// dotenv
const dotenv = require('dotenv')
dotenv.config();

// instance for get countries and cities
const instance = axios.create({
    baseURL: 'https://api.countrystatecity.in/v1/',
    timeout: 3000,
    headers: { 'X-CSCAPI-KEY': `${process.env.COUNTRYSTATECITY_API_KRY}` }
})

const allCountries = async (req, res) => {
    try {
        const countries = await instance.get('countries')
        res.send({ countries: countries.data })
    } catch (error) {
        errorHandler(res, error)
    }
}

// 省略
```

テストコードは以下。

```js:test.js
const request = require('supertest')
const app = require('../../../src/server/app')

describe('Get Endpoints (not mocking)', () => {
    it('/allCountries', async () => {
        const res = await request(app).get('/allCountries')
        expect(res.status).toEqual(200)
        expect(res.body.countries[0].name).toEqual('Afghanistan')
    })
// 省略
})
```

ソースコード全体は以下。

https://github.com/yuta-katayama-23/travel-app

※Jest×SupertestでのNode.js(Express)のAPIテストについては[こちらの記事](https://qiita.com/yuta-katayama-23/items/29b91fed629fe758a42d)を参照

## 解決方法（どうするのか？）
GitHubの`Secrets`に環境変数の値を登録し、GitHub Actionsのパイプライン(yaml)でそれを読み込む。
yamlの方は以下のようになり、`envコンテキスト`に`COUNTRYSTATECITY_API_KRY: ${{ secrets.COUNTRYSTATECITY_API_KRY }}`を宣言する事で、Secretsに登録した値が`secrets.COUNTRYSTATECITY_API_KRY`で取得でき、環境変数をCIのRunnerが動く環境に設定できる。

```yaml:jest.yml
name: Testing by Jest

on:
  push:
    branches:
      - "**"

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v2
      - name: package-lockより環境構築
        run: npm ci

      - name: テスト実行
        env:
          GEO_NAME_USERNAME: ${{ secrets.GEO_NAME_USERNAME }}
          WAETHERBIT_API_KEY: ${{ secrets.WAETHERBIT_API_KEY }}
          PIXABAY_API_KEY: ${{ secrets.PIXABAY_API_KEY }}
          COUNTRYSTATECITY_API_KRY: ${{ secrets.COUNTRYSTATECITY_API_KRY }}
        run: npm test
```

GitHub ActionsのSecretsはこんな感じになっており、`secrets.`で取得するkeyで値を登録してある。詳細は「ソースコード全体は以下」のリンクのリポジトリを参照。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1372684/7486c6c5-4cfa-cd31-ecc1-562e3f9873cc.png)

## 実際のJob

- 上記の設定をせずCIを実行した失敗job : https://github.com/yuta-katayama-23/travel-app/actions/runs/902797963
- 上記の設定をしてCIを実行した成功job : https://github.com/yuta-katayama-23/travel-app/actions/runs/902827671

## 参考文献
- [React x Firebase のCIを Github Actions で組む方法](https://note.com/yiio/n/nfb4fc77c4927)
CSSでぷかぷか浮かぶタイトル

#CSSでぷかぷか浮かぶタイトルを作りたい！

```
//css
.title,
.title span {
  position: relative;
  display: inline-block;
}
.title span {
  padding: .65em 4em;
  background: -webkit-linear-gradient(#fe5f95 , #ff3f7f);
  background: linear-gradient(#fe5f95 , #ff3f7f);
  border: 1px solid #fe3276;
  border-radius: 4px;
  color: #fff;
  box-shadow: 10px 10px 15px -10px;
  /* text-decoration: none; */
  text-align: center;
  animation: 3s float ease-in-out infinite;
  animation: 3s float ease-in-out infinite;
}
.title::after {
  position: absolute;
  bottom: -15px;
  left: 50%;
  z-index: -1;
  content: '';
  width: 100%;
  height: 24px;
  background-color: rgba(0, 0, 0, 0.3);
  box-shadow: 10px 10px 15px -10px;
  border-radius: 50%;
  transform: translateX(-50%);
  transform: translateX(-50%);
  animation: 3s shadow ease-in-out infinite;
  animation: 3s shadow ease-in-out infinite;
}
@-webkit-keyframes float {
  50% {
    transform: translateY(-10px);
  }
}
@keyframes float {
  50% {
    transform: translateY(-10px);
  }
}
@-webkit-keyframes shadow {
  50% {
    width: 70%;
    height: 18px;
  }
}
@keyframes shadow {
  50% {
    width: 70%;
    height: 18px;
  }
}
```

```
//HTML
 <h1 class="title"><span>タイトル</span></h1>
```
JenkinsからSlackへ通知する

# ターゲット

- JenkinsからSlackへ通知したい人

# 設定手順

## Slack

- Slackのアプリから「Jenkins CI」を検索し、Slackに追加します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/297616/f1489f34-cdd7-085e-af74-88c362c48f7b.png)

- 新しい設定では、Jenkins CIが通知するチャンネルの設定をします。
- 今回のチャンネルは「#sandbox」を指定し以下の設定を進めます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/297616/2b9e218a-4056-5f1e-5458-2d89ad5a168e.png)

- インテグレーションの設定に「トークン」がランダムで設定されています。
- トークンはJenkinsの設定で利用します。
- 名前や通知時の画像が設定可能ですが、このまま「設定を保存する」で進めます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/297616/fcbc4e4b-2e14-1ae3-9788-668f906eda6d.png)

## Jenkins

### Plugin Install

- プラグインの管理画面（Jenkinsの管理 > プラグインの管理）で「Slack Notification」を検索・チェックし、Install without restart

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/297616/ab388c35-3b7f-f71d-bad6-0443f3a0d732.png)

refs: https://plugins.jenkins.io/slack/

### Create Credentials

- Credentials画面（Jenkinsの管理 > Manage Credentiaals）で、Slackのトークンを設定します。
  - 種類: Secret text
  - スコープ: （任意）
  - Secret: SkackのJenkins CIアプリで発行されたトークン
  - ID: （任意:ビルド時に設定するID）
  - 説明: （任意）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/297616/3b490144-3136-0a7c-ca9f-37f1dc955bc2.png)

# ビルド実行

- Credentialの設定が済んだら以下のようにパイプラインを設定し、ビルド実行し動作の確認を行います。
- WORK_SPACEは自身のワークスペース（Jenkins CIを追加したワークスペース）に置き換えてください。

```
pipeline {
  agent any
  stages {
    stage("send slack") {
      steps {
        slackSend(
          channel: '#sandbox',
          color: 'good',
          message: 'Jenkins message',
          teamDomain: 'WORK_SPACE',
          tokenCredentialId: 'slack-token'
        )
      }
    }
  }
}
```

- 次のようにSlackに通知されれば成功です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/297616/9152b14c-c0fb-0779-e45b-eb649a4dee41.png)

# 関連記事

- [JenkinsにG-Suiteアカウントでログインする](https://qiita.com/ot-nemoto/items/1d9d2b38c6eba70ee708)
- [Jenkinsでaws-cliをつかう](https://qiita.com/ot-nemoto/items/502080184f9705d1f3ba)
【初心者でもわかる】スクロールの途中でバナー広告画像を表示する方法

#どうも7noteです。スクロールしたら途中でピョコッと出てくる画像の作り方を解説

ここ数年でwebのバナー広告がとても増えたように思います。その中でもスクロールしていたら急に出てくるバナー系。

個人的には視線を奪われるのでストレスになり嫌いなのですが、ちゃんと欲しい情報が出てるのならいい仕組みだなと思います。

今回は簡易的に「一定距離スクロールしたら画面の下から出てくるバナー画像」を作っていきます。


![sample.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/661092/c9a3407a-35e1-4df4-f427-b7c86701a1e4.gif)



## スクロールしたら出てくるバナー画像の作り方

```index.html
〜〜〜〜省略〜〜〜〜

<div class="banner">
  <img src="banner.png" alt="">
</div>

〜〜〜〜省略〜〜〜〜
```

```style.css
.banner {
  width: 100%;
  background: #aaa;
  display: none;    /* 最初は非表示にする */
  position: fixed;  /* 表示位置を固定 */
  bottom: 0;
  left: 0;
  padding: 5px;
  box-sizing: border-box;
}
.banner img {
  width: 100%;
}
```

```script.js
$(window).scroll(function () {
  var pos = 800; // ①上からの距離(px)で指定する場合
  var pos = document.body.clientHeight / 3; // ②上からの割合(%)で指定する場合
  if ($(this).scrollTop() > pos) {
    $('.banner').fadeIn();
  } else {
	$('.banner').fadeOut();
  }
});
```
※①か②は好きな方を指定してください。

## 解説

バナーを出すタイミングを決めるために、スクロール量を計測します。
スクロール量の設定方法としては大きく2つの選択があり、

**・上からXXpx進んだら、もしくは下からXXpxのところまできたら**
**・ページ全体の何割スクロールしたか**

上のような2つの方法があります。割合で決めるのか、上、もしくは下からの距離で指定をすることができます。

またorを使って両方の仕様を適応させて、「50%のところまでスクロールされたら、もしくはページが長いときには上から1500pxスクロールされたら、、、」みたいな書き方も可能です。

バナー画像を出すタイミングのスクリプトが書けたら、次は画像を表示する処理を書きます。

今回はfadein、fadeoutを使って表示を切り替えていますが、クラスを付与したら出てくるように表示時用のCSSを書きわける方法もあります。

これで完成ですね。

## まとめ

今回は自作で作る方法を解説しましたが、多くのサイトは専用のツールを導入しているのかな？と思います。

ツールを導入することで、実際にどれくらいの年代や性別の人がどの割合でクリックしたのかなどの計測ができるツールとして売られています。

最初にも書きましたが、個人的にはユーザーの動きに反する広告なのでそのうち廃れるのでは。。。なんて勝手に考えています。(※個人の感想です)

webの業界は流行り廃りが激しいので、また新しい手法がどんどん出てくるでしょう。
時代に合わせたwebが作れるようになりたいものですね。

#### おそまつ！
~ Qiitaで毎日投稿中!! ~
[【初心者向け】WEB制作のちょいテク詰め合わせ](https://qiita.com/7note)
1年前の自分が実装したコードの反省

#【1年前の自分が実装したコードの反省】

コメントは簡潔に書くようにする。
また、コメントが無くてもわかる場合は、ないのがベストかなと思っています。

##1年前のコードを見ての反省。。

実際のコードは記載できないので、だいたいのイメージ。

```java:Java
// 電力量のデータ
int amount;
```
上記のようなことを書いていました。
酷すぎますようね。初めての業務の最初で書いたのがこれです。
何の「量」かわからない。

```java:Java
// （コメントなしでも何か伝わる。）
int ElectricEnergy;
```
こうすることでコメントなしで簡潔にわかります。
当初は「量」を指す変数だからと、Google翻訳で「量」=「amount」
このような感じで書いてしまっていたのだと思います。

##自分がいまチーム開発で意識していること。

自分だけが理解できるような変数名やコメントは書かない。
自分が任せられた業務の範囲は、期待を裏切らないように責任を持ってやり遂げる。
わからないことがあったら、一人で悩まずに先輩のお力を借りる。（簡潔な質問を意識）

このあたりを意識して、今もこれからも継続していきます。

##おわりに。

現在の業務としては、過去に自分の書いたコードの修正をする。
もっと簡潔にわかりやすく書けたのではないかという振り返りをする。
これらがメインで物足りなさはありますが、この期間を有効に使って、自己成長していきます。

記事に関しまして、意識するほうが良いところなどアドバイス頂けますととても嬉しいです。
TwitterのDMにて、Qiitaの記事を見て、技術アドバイスを下さった方がいました。
気にかけていただいて、とても嬉しかったです。ありがとうございました。

これからも継続して、頑張っていこう。

Twitter：https://twitter.com/haruki_9743
dockerコンテナ内でsystemctlを使う

## コンテ内でsystemctlが使えない.....

業務でコピペしてコマンド使ってたらsystemctlコマンドで下記のエラーが出ちゃいました。

```
$ systemctl start mariadb.service
Failed to get D-Bus connection: Operation not permitted
```
どうやらcnetosやubuntuのコンテナ内ではsystemctlが使えないらしいです。


## systemctlとは
そもそもこのコマンドって何なの？ってところですが、systemctlはLinux系で利用されるサービスコントロールをするコマンドらしいです。

## コンテナ内で使う方法
まずコンテナを起動する時に--privilegedオプションをつけ、/sbin/initで実行します。

```
# 例)
docker run -d --privileged --name centos_container centos /sbin/iniｔ
```

次に起動したコンテナにアタッチします。

```
docker exec -it centos_container /bin/bash
```

これで使えるようになるかと思います。
【Ubuntu20.04】Nvidiaドライバーの更新でGPUを認識しなくなる問題


#はじめに
久しぶりにUbuntu20.04LTSを開いたので、sudo apt update と sudo apt upgradeを行ったらエラーが発生。
どうやらnvidiaのドライバの更新をしようとしてエラーが出てるっぽい。
--configure みたいなコマンドを打ってくださいとい表示がされていたので実行。
すると問題なく動いたので良かったのだが、MNISTプログラムを実行するもGPUが動作しない。
仮想環境内でも仮想環境外でもnvidia-smiコマンドは実行可能だし、nvcc -Vでコンパイラのバージョンも確認可能。
バグの原因を調べているとドライバー関連を更新したあとに再起動してないのではないのかという記述を発見。
そういえばsudo apt upgrade でnvidia関連のドライバをインストールしていたことを思い出す。
再起動するといつもなら自然に起動するはずだが、Ubuntuの起動選択画面が表示（最初にインストールしたときに出てくる画面）。
これはなんか怪しいぞと思いつつ起動すると、デュアルモニターの片方が機能していない。
おまけにnvidia-smiコマンドも機能しないということで対処に迫られた。
Ubuntuでの今までの環境構築の経験から原因を予測し対処を試みる。

#解決策
**Nvidiaドライバーがセキュアブートのせいでうまくインストールできなかった**
これが一番考えられる。
セキュアブートを詳しく理解は出来てないが、要するに起動時にサードパーティ製のやつみたいな怪しいのは安全のため起動しないことがあるみたいな機能のはず。
この環境構築時にも一度それで失敗しているのと、他の記事でもドライバのインストールの際はセキュアブート切っておけと書いてある。
インストールがうまく出来ていないのか、起動が出来ていないのか問題を切り分けるため、とりあえず再起動しBIOSでセキュアブートを無効にして再起動してみる。
デュアルディスプレイもちゃんともとに戻り、nvidia-smi nvcc -V どちらも動作を確認。
pytorchのtorch.cuda.is_available()での確認もTrueが返ってきて無事成功しており一安心。
ちなみにドライバーのバージョンを確認したが変わってはいなかった。
何が変わったのかよくわからないが、2021年5月19日22時頃に起こった現象であることをここに記しておく。

#再発防止策
とりあえず直ったが再発防止策のため原因を再度考える。
おそらくsudo apt upgrade　が原因なのだが、そもそもこのコマンドが詳しくは何をしているのか理解していないのが原因だと考えた。

```
sudo apt update
```
インストール可能なパッケージリストの更新を行う
これ自体でパッケージの更新を行っているわけではない。

```
sudo apt upgarade
```
インストール済みのパッケージの更新を行う。
[[1]]によると”アップグレードは主に不具合等を修正して完成度を高めること”であるそうなので、このコマンドでバージョン自体が変わることはなさそうだ。
以上のことを踏まえるとセキュアブートをONにしている限りこのようなことは避けられないと考える。
この論理でいくとセキュアブートは本当に必要なのかという問いに行き着くので調べてみる
**定義)セキュアブート:”デジタル署名を検証し、署名されていないソフトウェアを実行しないようにする技術”（[2]より引用）**
他のサイトも見てみたが、セキュリティ面が強くなるのは間違いないよう。
環境構築などの際に邪魔になるのは間違いないだろうが、ドライバー系をインストールする際はセキュアブートを無効にするというのを意識すれば問題ないだろう。
セキュリティの専門家ではないのでおとなしくONにして、必要な時だけOFFにすることに決めた。
ちなみに[3]によると自宅PCにも使われているUEFIは新しいBIOSの一種みたいなものだそう。
別物なのか気になっていたのでこの際解決しておく。

#おわりに
勝手にアップデートされて勝手にバグるのは勘弁してほしい。
ではこれで！!

#参考文献
[1]:https://timetotravel.space/update_upgrade_chigai/
[2]:https://wakatech.jp/secure-boot 
[3]:https://pc-farm.co.jp/pc_column/pc/4351/


[[1]]: Ubuntu Linuxのapt updateとapt upgradeの違いは何？アップデートには両方必要なの？ 2021/05/19アクセス
[[2]]:【解説】セキュアブートとは？BIOSの後身、UEFIって何？
[[3]]: BIOSとUEFIの違いについて詳しく解説！次世代のレガシーBIOSとは？
Ubuntuでpytorch環境を構築してMNISTを動かす

#はじめに
前回の記事[[1]]でtensorflowの環境を構築した。
pytorchも試してみたくなったのでやってみる。
環境構築といってもpipenvであたらしい仮想環境を作って必要なパッケージをインストールするだけ。
詳しく知りたい人は前回の記事[[1]]を見てください。

#環境
Ubuntu20.04LTS
GPU Geforce RTX 2070 super
GPUドライバー 450.119.03
CUDA 11.0
cuDNN 8.0
python3.8.10
pipenv

#pytorchのダウンロード
pytorch公式[[2]]に書いてあるコマンドを利用してダウンロード。
pipenvには探したところなかったのでpipでインストールした。
最新バージョンはCUDA11.0と合うものがないようだったので、pytorch1.8.0をダウンロード。
コマンドがそのまま書いてあるのでそれを打ち込むだけ。
pipでインストールするのでPipfileに反映されない点に注意。
ちなみにpipenvでインストールしたパッケージをpipenvで消すとpip listにも表示されなくなる。
これはpipenvがpipとvirtualenvの組み合わせだからだろう。

#MNISTプログラムの作成
前回同様公式のは使わずこちらの記事[[3]]のプログラムを参考にする。
コピーして実行するもrequestsパッケージが足りないと言われたのでpipenvでインストール。
再度実行するとエラーが出た。

```
urllib.error.HTTPError: HTTP Error 503: Service Unavailable
```
要するにmnistのダウンロードサイトがなんか使えないらしい。
調べてみるとこのサイト[[3]]が見つかった。
サイトから直接ダウンロードしてデータを参照するパスを書き換えればいいらしい。
ダウンロードして解凍。

```
wget www.di.ens.fr/~lelarge/MNIST.tar.gz
tar -zxvf MNIST.tar.gz
```
このあと

```
train_set = MNIST('./', download=True,
transform=transforms.Compose([
transforms.ToTensor(),
]), train=True)


test_set = MNIST('./', download=True,
transform=transforms.Compose([
transforms.ToTensor(),
]), train=False)
```
のように./にパスを変更する。
実行してみるとうまくいった。

#おわりに
とりあえずpytorchとtensorflowどちらも環境構築と動作確認は出来たので違いを本格的に理解していきたい。
それではまた！

#参考文献
[1]:https://qiita.com/fukuit/items/215ef75113d97560e599
[2]:https://pytorch.org/get-started/previous-versions/
[3]:https://stackoverflow.com/questions/66577151/http-error-when-trying-to-download-mnist-data

[[1]]:PyTorchでMNIST
[[2]]:INSTALLING PREVIOUS VERSIONS OF PYTORCH 
[[3]]:HTTP Error when trying to download MNIST data
AWS EC2 なんとなく初見で使ってみた（やった事のまとめ）

<h1>動機</h1>
　javascriptの学習が進み、簡単なコンテンツの形が出来てきたので、とりあえずwebサーバを立ち上げようと思い立った。

　自前でサーバを用意するとなると、仮にVMやコンテナだったとしても連続稼働させるのは電気代かかるし、インフラをどうしようか考えていた時にAWSの無料枠がある事を偶然知った。
　
　正直、AWSは一切勉強したことも触ったこともなかったが、仕事柄クラウドサービスに触れる機会がある為、「まあなんとかなるだろう。」と思いつきで利用することにしてみた。

<h4>雑記/やったこと</h4>
①EC2について
●　AWSのクラウドコンピューティングサービス
12か月は無料で使える（ただし、OSイメージやCPUやメモリのリソースなどは無料枠の制限がある）
→　OSは馴染みのあるRHEL8を選択
●セキュリティグループ設定
→　インバウンド設定（ssh(22)とhttp(80)のみ）
（とりあえずコンテンツのパーミッションを設定するまでは接続元をマイIPのみに絞る）
●　ssh接続は秘密鍵認証
インスタンス作成時にダウンロードする。teratermで対象IPにssh。
（動的IPなので再起動したら、変わるので注意。elastic ipの設定をすれば固定できるようだが、とりあえず放置。固有ドメイン必要になったら考える。）
●　ユーザはec2-user
rootは基本使わない、sudoersには入ってる。たまにsudoつけ忘れ。
→　useraddで一応作業用ユーザを追加。passwdでパスワード設定
●　apacheが入ってなかったのでyum install。
　 systemctl enable して再起動
●　コンテンツをscpでローカルPCからサーバへ転送。DocumentRootに配置
→　chown、chmodで所有権とパーミッションを設定

●webアクセス試すも403エラー
→　Forbiddenになるので、確認したらSELinuxが原因だった。
一旦、enforcing=disableにしてサーバ再起動でアクセスOK
【Python Threading】time.sleepが邪魔してスレッドを終了出来ない方へ

threadingはフラグ等をチェックせず外部から強制終了させるといったことが出来ないらしいので、ストップフラグを関数に持たせ正常に終了させてあげる必要があります
ですがtime.sleepが文中に存在していると指定した時間が経過するまで次のステップに移行する事が出来ません。なのでストップフラグのチェックが出来なくなり稼働中のスレッドを即座に終了出来ないという訳です

てな訳で

#time.sleep内にストップフラグのチェックを入れる

無論Python標準のtime.sleepにそんなオーバーロードは無いので、time.sleepのロジック部分を拝借してストップフラグの部分をぶち込む感じになります
https://github.com/biosbits/bits/blob/master/python/time.py

```py
import threading
import time

threads = []
flag = False

def fun(num=0):
    t = threading.currentThread()
    while getattr(t, "do_run", True):
        print(f"{num+1} flag's:{flag}")
        #sleep
        start = time.time()
        while time.time() - start < 1:
            if not getattr(t, "do_run", True):
                break

def main():
    threads = [threading.Thread(target=fun, args=(i,)) for i in range(0,5)]
    
    for i in threads:
        i.start()

    #3秒後にスレッドを強制的に落とす
    time.sleep(3)
    for i in threads:
        i.do_run = False
        i.join()
        print("breaked!")

if __name__=="__main__":
    main()

```

おわりです
Slack app + AWS Lambda + API Gateway でつまづいた話

#はじめに
去年、QA業務の契約社員として仕事に復帰してから早半年が経ちまして、何か新しいスキルを得たい＋掌で腐っているJava 8 Goldをちょっと役立たせたいということで、何かChat Bot的なものを作ろうと思いました。

そこで先輩諸兄の記事を参考、もといコピペしてとりあえず動くものを手元に置いて学習していこうと思ったのですが、コピペすらままならない残念なことになり暫く頭を抱えながらあぁでもないこうでもないと試行錯誤して、３時間ほどでコピペに成功しました。コピペで３時間ってお前…。

参考記事が悪いのではなく、無知のままトライしていった僕がそもそもアホだった、と前置きしておきます。念のため。

というわけで、何とかうまくいった訳ですが、つまづいたところをメモでもしておかないと鳥頭の僕は一瞬で忘れてしまうため、こうして備忘録をちまちまと書いた次第です。

#参考記事
https://qiita.com/kamata1729/items/8d88ea10dd3bb61fa6cc
https://qiita.com/kamata1729/items/fc6c31a3039599b48305
感謝。

#コード
ほとんど参考記事そのままなので省略。開発環境はEclipse、ビルドはMaven。どうもEclipseから直接Lambdaへアップロードするとテスト失敗するのは今も謎。ビルドしたjarファイルをブラウザ経由でアップロードすることで動くものは出来ました。

非同期処理はほぼ2つ目の記事そのまま。Node.jsのasyncでも出来るのかもしれない…？

#つまづいたところ：Slack
botのuser idってどこに書いてあるの？

1. とりあえずワークスペースにアプリをインストールする
2. Slackアプリを開いて `▼App`下に表示されている(はず)のインストールしたアプリをクリックする
3. 右上の :exclamation: をクリックする 
4. その他をクリックする

「メンバーIDをコピー」に表示されている `U`から始まる文字列がbotのuser id。これをlambdaの環境変数にぶち込めばOK。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/453397/f0e51971-b42b-d2ed-225a-9e58be5d15e8.png)

#つまづいたところ：lambda
環境変数を間違って設定していた。原因を掘り下げるのに無駄に時間がかかってしまった。

具体的には、`SLACK_APP_AUTH_TOKEN`のxoxp-から始まるものと、`SLACK_BOT_USER_ACCESS_TOKEN`のxoxb-から始まるものをあべこべに設定してしまった。

結果、アプリにメンションつけてチャットしてもbotではなく自分が返事している状態になっていた。バカ。

lambda側で設定する環境変数名とトークンが合っているのが普通・当たり前だろうという先入観のせいで、そこかよ！ってなるまで時間がかかってしまった。

#さいごに
他にもつまづいたところがあったかもしれない。思い出したら追記していこうと思います。
ちょ、待てよ、、営業でも簡単にGCP使えるじゃん

#はじめに

お客様：「いや〜もうオンプレミスで資産を持つのは辛いから、クラウド第一で考えたいんですよ」
私：「・・・・ですよね、クラウド第一ですよね」（クラウドって何やねん）

今から５年前、新卒で営業活動が始まったばかりのシーン。
俺は営業だぞ、、そんなことわかるわけ、、

#教えて、Google先生！

![スクリーンショット 2021-06-03 19.50.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1578917/15c3bf3b-b1f5-8c82-6b0e-cb8a85055269.png)

>クラウドコンピューティング（英: cloud computing）は、インターネットなどのコンピュータネットワークを経由して、コンピュータ資源をサービスの形で提供する利用形態である」
出典：Wikipedia

ちょ、待てよ、、これってサービス利用になるから資産計上ではなくサービス費用計上になるのか。
会計項目が変わるなんて、とんでもないGame Changerだ。
俺もクラウドって触れるのかな？

#GCP登録してみた
Google Cloud Platformを検索し、登録を試みると、[＄３００分の無料クレジット](https://cloud.google.com/free/?hl=ja)が付与されることが判明。
登録を進めていく。

![スクリーンショット 2021-06-03 20.11.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1578917/28734689-a766-4db0-7284-d1b2bc345d7d.png)

その後、Googleアカウントでログイン。
必要情報を入力していく。
![スクリーンショット 2021-06-03 20.25.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1578917/049a8541-912f-f2a3-fdba-eda8e41c6fe9.png)

さらに必要情報を入力していく。
![スクリーンショット 2021-06-03 20.30.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1578917/325276c7-0cdc-22d8-b97f-a91055f3e079.png)

ちょ、待てよ、、こんなに簡単にサービス利用できるのか。素晴らしい。
![スクリーンショット 2021-06-03 20.37.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1578917/60bbdb68-c1f7-4724-9491-c26ab40834c0.png)

営業職の選択肢はなしか。。
いつか追加される日がくることを祈って「その他」で登録。
![スクリーンショット 2021-06-03 20.39.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1578917/e817c624-169e-9087-b588-29582e919c2b.png)

#次回
インスタンスを立ててみる
Twitter Card の使い方

Twitter Card の使い方です。
Link が次のように表示されます。
![twitter_card_jun0301.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/8fcfbac0-e77d-7365-d32b-c62ae0ed17df.png)


html の head に次のような記述を追加します。

```html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta http-equiv="CONTENT-TYPE" content="text/html; charset=utf-8" />
<meta name="twitter:card" content="summary" />
<meta name="twitter:site" content="@ekzemplaro" />
<meta property="og:url" content="https://ekzemplaro.org/storytelling/" />
<meta property="og:title" content="ストーリーテリングのページ" />
<meta property="og:description" content="Storytelling" />
<meta property="og:image" content="https://ekzemplaro.org/png/linux_logo.png" />
<title>ストーリーテリング</title>
</head>
（省略）
```

[Card validator](https://cards-dev.twitter.com/validator) で確認
![twitter_card_jun03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/dee37bd0-5cf0-cdc1-fb4f-8da014a8c5a5.png)

参考ページ
[ツイートをカードで最適化する](https://developer.twitter.com/ja/docs/tweets/optimize-with-cards/guides/getting-started)
[Ruby]配列の要素を結合して一つの文字列にするjoinメソッドについて

## はじめに
joinメソッドについて学習したのでメモとして残しておきます。

## 使い方
joinメソッドは非破壊的メソッドです。
引数がない場合は配列の要素を結合して、一つの文字列にします。
また引数を取った場合は引数を区切り文字として使います。

## 使用例

```
array1 = [1,2,3]
array1 = array.join
p array1
=> "123"

array2 = [1,2,3]
array2 = array2.join("-")
p array2
=> "1-2-3"

array3 = [1,2,3]
array3 = array3.join(" ")
p array3
=> "1 2 3"
```

##参考
https://docs.ruby-lang.org/ja/latest/method/Array/i/join.html

https://techacademy.jp/magazine/19903
SPSS 関連動画のご紹介

# SPSS StatisticsとSPSS Modelerに関連する動画のご紹介です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/855260/e190243b-3183-3e9b-81ba-7f5774bc7a45.png)
プロダクト
タイトル
URL
Statistics
IBM SPSS Statistics 概要
https://www.youtube.com/watch?v=pbVs3cr2mTk&t=27s
Modeler
4分でわかる! IBM SPSS Modeler概要 機能篇
https://www.youtube.com/watch?v=iD6Et_svUZY&t=35s

~~予測分析を始めましょう SPSS Modeler クイック・スタート・ガイド~~
~~https://www.youtube.com/watch?v=cNh2Ebhrehg&t=613s~~

IBM SPSS Statistics - R、Python連携
https://www.youtube.com/watch?v=zkWJU-edfJE

SPSS CADS 分析結果を利用した業務の自動化と展開
https://www.youtube.com/watch?v=gxktNevQ0LY

IBM SPSS Modelerの機械学習・決定木分析
https://www.youtube.com/watch?v=vtCxArBB6qE&t=55s

SPSS Modelerで実践−顧客クラスタリング
https://www.youtube.com/watch?v=i0UncrUsQuU

IBM SPSS Modelerのデータハンドリング機能
https://www.youtube.com/watch?v=2stYxYt8q2U&t=17s

SPSS Modelerの機械学習・ニューラルネットワーク
https://www.youtube.com/watch?v=b3DfApLWKZw&t=2s

IBM SPSS Modelerのオートメーション機能
https://www.youtube.com/watch?v=8fHCfPHrhTk

SPSS Modelerで実践−解約・休眠防止
https://www.youtube.com/watch?v=kcVO6CAP7g8&t=21s

マツモトキヨシHD＋IBM SPSSとCampaignでプロモーションを高度化
https://www.youtube.com/watch?v=YLv3jFrHxNE

SPSS Modelerで実践−リピート率の向上
https://www.youtube.com/watch?v=q9-ESnJqYNU&t=7s

SPSS Modelerで実践−新規顧客の獲得
https://www.youtube.com/watch?v=lFeyME6oJSk

3分でわかるIBM Analytics 前編
https://www.youtube.com/watch?v=OT5m87fMz-8&t=44s

3分でわかるIBM Analytics 後編
https://www.youtube.com/watch?v=uNtoQc_BS7k
MySQL からヘッダ付 CSV ファイルをエクスポートする


MySQL から CSV ファイルを取得するには、通常は SELECT * FROM tablename INTO OUTFILE filename; のようにする。

しかし以下のようにするにはどうしたらいいかな?

- カラム名をヘッダ行として CSV ファイルの1行目に追加したい
- スクリプトで行いたい
- FILE権限の無い MySQL ユーザを使いたい


ということで、python で SELECT 構文を実行し、python 実行ユーザ権限でファイルに書き込む方法を考えた。



```

import pymysql.cursors
import csv

db=pymysql.connect(host="localhost", user="selectuser", password="testpassword" , cursorclass=pymysql.cursors.DictCursor)
cursor=db.cursor()
cursor.execute("USE test")
sql=('SELECT * FROM センサ')
cursor.execute(sql)
rows=cursor.fetchall()
cursor.close()
db.close()

if rows:
    columnNames = list()
    # ヘッダデータを作る
    for i in cursor.description:
        columnNames.append(i[0])
    with open(テーブル,'w',newline='') as 'test.csv':
        # 辞書順序を指定しておく
        csvwriter = csv.DictWriter(csvfile,columnNames,delimiter=",",quotechar='"')
        # ヘッダ行を書き込み
        csvwriter.writeheader()
        for row in rows:
            #  csv データを書き込み
            csvwriter.writerow(row)

```
実行

```


$ python3 export.py

```
結果

```

$ cat test.csv 
id,センサ,温度,湿度,メモ
1,1,22.0,85.0,ストーブON
2,2,17.0,65.0,廊下
```
URLから.phpや.htmlなどの拡張子を消す方法

下記URLから

https\://xxxxx.com/example/test.html

こうしたい

https\://xxxxx.com/example/test

## 実装

```htaccess:.htaccess
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME}\.html -f
RewriteRule ^(.*)$ $1.html
```


htaccessの書き方でした！！
【開発環境構築】DockerでWordpressの開発環境構築をして「Error establishing a database connection」で繋がらないときはwp-config.phpを確認！

<img width="1000" alt="Error_establishing_a_database_connection.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/250884/7a9dfc7d-2a67-937e-2723-955d655612b3.png">

Wordpressの開発環境をDockerで作ろうとしたところ、「Error establishing a database connection」というエラーメッセージが表示されてしまいました。少し詰まったので備忘録として書いておきます。

## 原因1：dockerのvolumeが残ってしまっていた。
**解決策：`docker volume prune`で未使用のvolumeを削除する。**

docker-compose.ymlに下記のように記載していました。

```docker-compose.yml
...
  db:
    image: mysql:5.7
    restart: always
    environment:
      MYSQL_DATABASE: db
      MYSQL_USER: user
      MYSQL_PASSWORD: pass
    volumes:
      - db:/var/lib/mysql

volumes:
  wordpress:
  db:
```

このymlファイルで一度コンテナを起動後、ユーザー名やパスワードを変更して作業をしていたので、dbコンテナに入ってからmysqlに接続しようとしても「パスワードが違います」というメッセージが表示されてしまい、接続ができませんでした。

ymlファイルを見直し、「これ、volumeが残っているから修正した情報が反映されてないのでは...？」と気づき、`docker volume prune`で古いvolumeを削除。再度コンテナを起動したところ、修正後の情報でmysqlへ接続できました。

## 原因2：wp-config.phpのDB_HOSTはDBコンテナ名
**解決策：wp-config.phpのDB_HOSTをDBコンテナ名に変更する。**

```wp-config.php
修正前
/** MySQL のホスト名 */
define('DB_HOST', 'localhost');
↓
修正後
/** MySQL のホスト名 */
define('DB_HOST', 'db'); // ymlに記載したDBコンテナ名
```

wordpressの設定ファイルは、ルートディレクトリにwp-config-sample.phpがあるので、これをwp-config.phpとしてコピーを行い、使用します。この中にDBの接続情報が記載されているのですが、このDB_HOSTの値をdockerで作成するDBのコンテナ名に設定したところ、無事にWordpressの画面が表示されました。

## 最後に
<img width="1000" alt="Error_establishing_a_database_connection.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/250884/5f604060-6f31-f163-095c-fbd1fa1602d9.png">
URLに`http://localhost:8080/wp-admin/`で接続すると、上記のような画面が表示されました。ここに表示されている「Are you sure you have typed the correct hostname?」を見て、原因2を疑うことができました。

それでは！

>参考情報：
>・未使用のコンテナ、volumeなどを一括削除
>https://qiita.com/reflet/items/5caa88abcf1e8964783a

>・Docker: 使っていないボリュームを削除してディスク使用量を節約する
>https://hoge-hogeo-777.hatenablog.com/entry/2019/03/01/183000
Androidにプリインストールされてるアプリをadbコマンドで無効化した。

# adb uninstallでスマホを奇麗にしてやった。

使用者に不要なアプリ入れないでもらえますかね・・。

## ここで書いてる内容
- Win端末にadbコマンドができるように設定
- Androidの開発者モードのOn
- adbコマンドでアプリを削除(無効化)
- adbコマンドで削除したアプリを復活

## 経緯
GPSでナビ運用していたサブスマホがGPS誤検知するようになった。
なので新しいスマホを買うことにした。
性能はそこそこ欲しいけどそんなに予算はない
色々検討した結果、SoftbankのRedmi note 9t 5gが破格だったので買ってみた。
起動してみると画面いっぱいに要らないアプリが。。使いたいアプリを探すのが手間！！

ということで、要らないアプリを一掃することにした。

## 必要なモノ
- Win端末
- Android端末
- 100均で購入したTypeA-Cケーブル

## 環境設定
作業したのと違うパソコンで書いてるので画像はほぼない。

### Win端末にSDK Platform-Toolsをインストール  
インストールといっても、パスを通すだけ。
[SDK Platform-Tools](https://developer.android.com/studio/releases/platform-tools?hl=ja)の赤枠のをクリックしてダウンロード。  
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/743383/0d3bf10e-e4dc-cc5b-5921-1bdf64528b67.png)  
zipを展開して、任意の場所に配置。  
配置したパスをコピーしておく。  
環境変数にパスを登録するので、スタート＞設定＞環境変数を編集  
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/743383/025f44d6-62b0-13c7-3ac1-33544f1c34d4.png)  
新規>パスを入力してOK
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/743383/b99879a4-65fd-c53b-7cb5-72d9afb8bc3f.png)

Winキー+R>cmdと入力してEnterでコマンドプロンプトを起動して  
` adb.exe version `
でバージョン情報が出たらOK（出なかったらググって解決してください。）

### Android端末の設定
Android端末で開発者モードをON。

開発者モードは端末によって出し方が違うようだけど、Redmi note(MIUI)は、
設定>デバイス情報>MIUIバージョン連打>追加設定の中に開発者向けオプションが表示された。

開発者モード内のUSBデバッグをONに設定する。

Win端末とAndroidを接続すると、このパソコンでUSBデバッグ許可する？って表示されるので許可する。

### 接続状態の確認。
いきなり作業するのは怖いので、対象の一覧を表示するコマンドを実行する。
`adb.exe shell pm list package`
端末にインストールされているアプリがずらずらっと出てくるはず。（出なかったら略）

ちなみに、コマンドは実行する前にググってどんなコマンドなのか確認しましょう。

これで作業準備完了。

## 対象の確認と削除コマンドの準備
要らないアプリを目視で確認＞Google Playストアで検索
例えばChromeなら
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/743383/e251d2cb-b2d9-47e6-0ad1-a9f92debbf09.png)
`https://play.google.com/store/apps/details?id=com.android.chrome&hl=ja&gl=US`
このようなURLが出てきた。必要なのは`com.android.chrome`この部分だけ。
不要なアプリを片っ端から調べてSakuraEditorに貼り付けていく。  
突然出てきたSakuraEditorはダウンロードしといてください。。編集できればなんでもいいです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/743383/6b0314f7-94c3-bc7e-517f-b1cdf7ca23d5.png)
要らないアプリのリストアップが終わったら以下をコピーする。0の後ろの半角スペースを忘れずにコピーしてほしい。
`adb.exe shell pm uninstall -k --user 0 `
SakuraEditorの1行目、左端にカーソルがある状態で「ALT+↓」をリストの一番下まで行ってから
「CTRL+V」をすると
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/743383/60523886-4fd1-3f43-6aac-315e4d4fe169.png)

こんな感じで準備完了。

## いざ削除
とりあえず1行目だけコピーして、実行してスマホからアプリがなくなったことを確認する。  
問題ないようなら2行目以降をコピーして実行して一掃！

やったー！消えた！
というか、邪魔なものを削除(無効化)する機能を消すなよ、と。

## うっかり間違えて消しちゃった！
安心してください。復旧できます。
削除(無効化)したアプリの復旧は以下のコマンドでできるらしい。
たぶん、2番目のコマンドの方が良さそう。試してないけど。
```
adb.exe shell cmd package install-existing com.android.chrome
adb.exe shell pm enable --user 0 com.android.chrome
```

## おわりに
元々サブスマホはsimなし運用していたんですが、先日の楽天モバイル0円キャンペーンでつい導入しちゃいまして。
楽天はband3と18(18はauから借りてるだけらしい)。
band3は遠くまで届くけど障害物に弱く、band18は障害物に強い特性を持っているらしい。
私の元サブスマホはband18非対応ということで、屋内に入ると圏外になりまくるって状態でした。 → 原因1?

bandの電波塔にはそれぞれ固有のIDが割り当てられているらしく、恐らくそのIDを元にgpsの位置を算出しているんだと思われます。
ただ楽天だけは同じIDの電波塔が3か4個か存在するらしく、私の元サブスマホは古いものでそんなことを知る由もなく。 → 原因2？

それらが原因でgpsの異常につながったのでは？と邪推してます。
現にsim抜いた元サブスマホは元気にgps表示していますから・・
Docker で MySQL 3306 に接続できなかった 

## エラー内容

Mac の docker で node を使っていたら、以下のようなエラーが出ました。

```
(node:1753) UnhandledPromiseRejectionWarning: Error: connect ECONNREFUSED 127.0.0.1:3306
```

`3306` ということでMySQLに接続できていないようなので、dockerの方を見てみる。
すると以下のエラーが出ていました。

```
[error] --initialize specified but the data directory has files in it. aborting.
```

どうやらファイルが存在していて失敗しているよう。
だがvolumeやめぼしいファイルを消してみたり、ネットを検索して出てきた記事では解決できませんでした。

## 解決策

結果としては以下で解決しました。

- Docker の Menu から Troubleshoot を選択
- `Clean / Purge data` をする
- `Reset to factory defaults` をする

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/68087/3bcaf377-799d-8ab5-869c-cc18f6747792.png)

どっちが効いたのかわからないけどこれで直りました。
mimemagic -v0.3.2がbundle installに失敗する理由と解決法

# なにこれ

mimemagicがrubygems.orgから取り下げられたせいで、
mimemagicのbundle installが失敗するようになった問題の理解と解決方法を備忘録として書く。

# なぜbundle installが失敗するか

↓のようにmimemagic -v0.3.2を書いてる`Gemfile.lock`があるとします。

```Gemfile.lock
…略
    mimemagic (0.3.2)
…略
```

`bundle install`する時の挙動は、
GemfileとGemfile.lockを見て、
欲しいgemがGemfile.lockに記載されてれば該当のversionをinstallしようとする。
（上の例だとv0.3.2）

ただ、mimemagicはv0..3.2がrubygemsに存在しない。
なので、`bundle install`が失敗する。

# 解決策
↓のように、rubygemsに存在するversionをinstallするようにする。

```Gemfile.lock
…略
    mimemagic (0.3.10)
…略
```

# 参考記事
[mimemagicの最新動向
](https://hackmd.io/@mametter/mimemagic-info-ja)

[セマンティック・バージョニングと、Gemfileのバージョン指定方法 - Gemfileでよく見る`~>`を使いこなす
](https://qiita.com/awakia/items/5745938c192ca1139c63)
PHPStormを更新をしたら、DB接続できなくなったときの対処法

# はじめに
普段、PHPStormにあるデータベースクライアント使用しているのですが、PHPStormを更新したらエラーでクエリが実行できなくなりました

# エラー内容
以下のようなエラーが出るようになりました

```
javax.net.ssl.SSLHandshakeException: No appropriate protocol (protocol is disabled or cipher suites are inappropriate).
```

# 対処法
PHPStorm起動時のJava Runtimeのバージョンを落とすことで回避しました

# 手順
1. Shiftを2回押して、Actions を起動し、 `Choose Boot Java Runtime for the IDE` を入力します
![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103774/9256d59a-455e-d0a3-6e61-fb1809e08284.png)

2. Newのプルダウンで Runtime を選択します（一番数字の小さいものを選択）
![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103774/d4b6dc02-4b7e-3961-abc7-3d038b2088d6.png)
![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103774/de31ce72-35c3-3883-37a2-a15b3200cd81.png)

3. PHPStormを再起動します
![4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/103774/e99a3ff8-6c8d-0728-bc1f-53f658c81e77.png)

# 参考
[Selecting the JDK version the IDE will run under](https://intellij-support.jetbrains.com/hc/en-us/articles/206544879)
[Ruby] 配列についてまとめる

## はじめに
Rubyを学習している中で、配列やハッシュってそもそもなんだっけと、口で説明するように言われても、なかなかできなかったので、今回は初心に戻って、配列についてまとめてみたいと思います。

## 配列とは
配列というのは、1つの変数の中に複数の値を持つことができる値です。例えば「neme」という配列があってその中には、[John, Ken, Michael]が入っている、みたいな感じです。
また、配列は順番で中のデータを管理します。

配列の中の一つ一つのデータは要素と呼ばれます。


## 配列の生成

配列の生成は簡単です。
変数に[]を代入してあげるだけです。変数に複数のデータを入れられる箱を放り込んであげるイメージです。

```
変数 = []
```
この記述で空の配列が完成です。
初めから中身を入れて作ることもできます。

例えば、fruitsという変数にいくつか果物の名前を初めから入れるとこんな感じです↓

```Ruby
fruits = ["apple", "banana", "grape"]
```

要素の順番は左から順に入ります。例ではappleからということになりますね。

## 配列に値を追加

配列に値を追加したくなったとき、もちろん後から追加可能です。
fruitsの例でやってみましょう。追加するときは **<<** を使います。

```Ruby
fruits = ["apple", "banana", "grape"]
fruits << "orange"
```

これで一番最後にorangeが追加されているはずです。

## 添字(そえじ）
配列は順番で値を管理すると言いました。
添字は配列の一つ一つの要素にふられた番号です。気をつけたいのは、0から数え始めます。

fruitsの例で言うと 
appleが0
bananaが1
grapeが2
orangeが3
となります。

添字は配列の中から一つの値を取り出すときに使用します。

例えば、

```Ruby
puts fruits[1]
```

と実行すれば、fruitsの二番目の要素bananaが表示されます。

## 要素の書き換え

添字を利用して要素を書き換えすることができます。
現在 fruits[1]はbananaですが、

```Ruby
fruits[1] = "peach"

puts fruits
```

こうすると、
appleが0
peachが1
grapeが2
orangeが3
と添字の１のbananaがpeachに置き換わっているはずです。


## おまけ

配列を使う際によくこのメソッド使うな〜と個人的に思っているのがlengthメソッドです。

lengthメソッドは配列に対して使うと、いくつ値がその配列に入っているか教えてくれます。

```Ruby
fruits = ["apple", "banana", "grape"]

puts fruits.length
```

とすると、3つの要素が入っているので、３ が返ってきます。

この仕組みを利用していろんなメソッドを定義することが多い気がします。
psycopg2がインストールできない

python3.9に上げた後、pip経由で [psycopg2](https://pypi.org/project/psycopg2/)　のインストールがハマったので、その備忘録

```
pip install psycopg2
```

# エラー

```
Installing collected packages: psycopg2
    Running setup.py install for psycopg2 ... error
    ERROR: Command errored out with exit status 1:
：
中略
：
    ld: library not found for -lssl
    clang: error: linker command failed with exit code 1 (use -v to see invocation)
    error: command '/usr/bin/clang' failed with exit code 1
：
中略
：
```

# 解決策
自分は、.bash_profile に追加

```
export LDFLAGS="-L/usr/local/opt/openssl/lib"
export CPPFLAGS="-I/usr/local/opt/openssl/include"
```

# 感想
brew 経由で入れた **pyenv** をはじめとしたパッケージ（postgresql等）と、その依存関係解決で インストールされた **openssl@ 1.1** との相性が悪いのか？ 

```
# which openssl
/usr/bin/openssl
```
opensslのパスが、brewのパッケージのインストール先である

```
# brew ls openssl
/usr/local/Cellar/openssl@1.1/・・・
：
/usr/local/Cellar/openssl@1.1/・・・
```
を向いてないのが原因のような・・・
シンボリックリンクが張られている訳でもないし・・・

python環境、久々いじると嵌るww

# 参考
[error installing psycopg2, library not found for -lssl](https://stackoverflow.com/questions/26288042/error-installing-psycopg2-library-not-found-for-lssl/39244687#39244687)
[【小ネタ】Macにpsycopg2をインストールする時のメモ](https://dev.classmethod.jp/articles/mac-psycopg2-install/)