OmniAICreator/Qiita-1.07M huggingface dataset:
シェルスクリプトで相対パスを絶対パスに変換する正しい方法

## 問題点

某所でファイルの相対パスから絶対パスに変換する方法として以下のようなものが紹介されていました。

```sh
path="$(cd $(dirname "$1") && pwd)/$(basename "$1")"
```

これにはいくつか問題がありますが、わかるでしょうか？

↓

**答え**

1. `cd` の引数がダブルクォートで括られていないので空白が入るパスを正しく扱えない
2. `-` で始まるパスをオプションと誤認識する
3. 改行で終わるパスを正しく扱えない
4. ルート上にあるファイルを指定すると `/` ではなく `//` で始まるパスとなる
5. zsh の場合、環境変数 `PATH` が上書きされる
6. 存在しないディレクトリが含まれていた場合、エラーが出力されるもののエラーにならずに間違ったパスに変換される

1, 2 に関しては簡単なミスレベルなので以下のように書き換えるだけで OK です。

```sh
path="$(cd -- "$(dirname -- "$1")" && pwd)/$(basename -- "$1")"
```

**注意** 古い zsh 4.0 あたり以前は `cd --` に対応していません。Busybox 1.17.0 あたり以前は `dirname --`, `basename --` に対応していません。また（この記事の範囲では考慮する必要はありませんが）`cd -- -` だと「前にいたディレクトリに戻る」という機能になるので、それらに対応する場合は絶対パス以外の頭に `./` をつけるか、`-` で始まるパスの頭に `./` をつける回避策が必要です。

3 はコマンド置換を使うと末尾の連続する改行が取り除かれる事によるものです。例えば以下のような挙動です。

```sh
$ printf 'foo\n\n\n'
foo


# ↑空行が2行出力される
$ echo "$(printf 'foo\n\n\n')"
foo
# 空行は表示されない
```

改行で終わるパスはレアケースなのでそんなパスを使うなということで良いとは思いますが、コマンド置換を使って対応するならこのようになります。

```sh
$ var="$(printf 'foo\n\n\n' && echo _)"
$ var="${var%_}"
$ printf '%s' "$var"
foo


# ↑空行が2行出力される
```

4 は `pwd` の出力が `/` の場合を考えると `//` になるのは明らかです。`//` で始まるパスでもファイルにアクセスすることはできますが、パスを文字列として比較している場合などで問題が出る可能性があります。

5 は知らないとハマってしまいますが zsh では 変数 `path` は 環境変数 `PATH` と紐付いる特殊変数です。環境変数 `PATH` と同じ内容で `:` 区切りのパスを配列として参照することができます。そのため `path=abc` と実行してしまうと 環境変数 `PATH` まで `abc` となってしまいます。

```sh
$ path=abc
$ echo $PATH
abc

$ path=(foo bar baz)
$ echo $PATH
foo:bar:baz

$ date
zsh: command not found: date
# PATH が 書き換えられているためコマンドが実行できなくなる
```

6 が一番問題でエラーにならずに間違ったパスに変換され処理が進んでしまうため重大なバグを引き起こす可能性があります。こうなる理由は `cd` で発生したエラーが後続の `basename` の実行で隠蔽されてしまうからです。

```sh
$ cd /tmp

$ cat test.sh # test.sh に以下の内容で作成
#!/bin/sh
set -e # エラーで停止するようにしても効果はありません
abspath="$(cd -- "$(dirname -- "$1")" && pwd)/$(basename -- "$1")"
echo $?
echo "$abspath を削除"

$ sh ./test.sh no-directory/file # 存在しないディレクトリ上のファイルを指定
./test.sh: 3: cd: can’t cd to no-directory # ← エラーメッセージは表示される
0 # ← 終了ステータスがエラーではない
/file を削除 # ← ルートディレクトリ上のファイルを削除しようとしてしまう
```

## 解決方法

これらの問題を解決した正しい方法は次のようなものです。（3. 改行で終わるパスへの対応は面倒なので省略します。）

```sh
# set -e していれば 下記の || exit $? は不要
dirname="$(cd -- "$(dirname -- "$1")" && pwd)" || exit $?
abspath="${dirname%/}/$(basename -- "$1")"
```

（`dirname` と `basename` はエラーになることはないという前提にしています。ならないですよね・・・？）

## 別解（シェル関数による実装）

簡易な（行数が少ない）コードを求めているのであれば上記のコードで良いのですがシェルスクリプトにするのであれば行数を気にする必要はないと思うのでシェル関数にしました。上記のすべての問題への対応に加えパフォーマンスも向上させています。また相対パスから絶対パスへの変換だけでなく、その逆も実装ししたので別記事にしています。

- [シェルスクリプトで相対パスと絶対パスを相互に変換する関数](https://qiita.com/ko1nksm/items/88d5b7ac3b1db8778452)

また関連記事としてこちらもどうぞ

- [POSIX準拠でもreadlink -f （完全互換版）](https://qiita.com/ko1nksm/items/873cfb9c6ceb6ef32ec9)
Nuxt.js 【Cannot read property '_normalized' of undefined】エラー時の対処法

Nuxt.js(Vue.js)で`Cannot read property '_normalized' of undefined`のエラーが出た時の対処法です。

## nuxt-linkにtoを指定していないのが原因

```vue
<nuxt-link>HOME</nuxt-link>
```
上記のように`nuxt-link`に`to`を指定しないと発生するエラーです。

```vue
<nuxt-link to="/">HOME</nuxt-link>
```
`to`を指定することでエラーが解消されました。
ChrootDirectoryではまった話。原因=>ルートディレクトのパーミション/fatal: bad ownership or modes for chroot directory component "/" [postauth] 

くっそーーー。

「SFTP専用ユーザ(つまり)かつアクセスできるディレクトリをホームディレクト以下に限定」ではまったので記録。

設定に関しては以下の記事が簡潔にまとまっていてわかりやすかったです。関連コマンドのリンクも掲載されています。感謝

[アクセスをホームディレクトリのみに制限したsftpユーザーの設定 - Qiita](https://qiita.com/uranux_jp/items/77fee7334b0a26d4fcf9)

# 環境

- CentOS Linux release 7.8.2003 (Core)
- OpenSSH_7.4p1, OpenSSL 1.0.2k-fips  26 Jan 2017

# エラー発生

SFTP接続しようとすると、以下のエラーが発生します。(`/var/log/secure`で確認)

```bash:/var/log/secure
fatal: bad ownership or modes for chroot directory component "/" [postauth]
```

ちなみに設定ファイルの`ChrooDiectory`行を消せばログインできるので、基本的な設定はOKで、原因が`ChrootDirectory`絡みであることは確実。

```config:/etc/ssh/sshd_config
Match Group sftponly
  ChrootDirectory /home/%u
  X11Forwarding no
  AllowTcpForwarding no
  ForceCommand internal-sftp
```

# 原因と対処

以下が人気のQ&Aです。

ssh - bad ownership or modes for chroot directory component - Server Fault
https://serverfault.com/questions/584986/bad-ownership-or-modes-for-chroot-directory-component

よくあるエラーみたいですが、ホームディレクトのオーナは`root`だし、パーミッションは755(rootだけ書込み可能)だし、デーモンの再起動もしてるけど解決しない。

しょうがなく他のサーバで同じことを試してみたらあっさりと成功。

とはいえ本当に設置したいサーバで設定したいなぁと思ってモヤモヤしていたら、ふと思いつきました。
「あ、ホームディレクトリでなくてルートディレクトリ("/")のパーミションか？」と

ビンゴでした。

なぜか最上位("/")ディレクトリが775になっていました。  ← なぜ775になっていたかは別途調査。汗

グループの書き込み権限を削除(755に)したところあっさりと解決しました。

くっそー。
QiitaAPIで2020年投稿のストック数が多い記事のタグ情報を調べてみた

#はじめに
ほとんどプログラミング経験のない初心者（VB.Netを少しかじった程度）ですが、最近「モノをつくる」学習の場を与えて貰えたので、自分なりに色々調べて、JavaScriptにチャレンジしてみました。記事の投稿も初で、初めて尽くしで戸惑ってます。。ソースコードがキレイじゃないのもご愛敬。

#目的
Node.jsとQiitaAPI（+axios）を使って今の自分に何ができるか考えてみた。
で、今回は、「今年（2020年）に投稿された記事で、ストック数の多い記事のタグってどんなの？」を調べてみました。
（ストック数が多い記事として、今回はストック数が300以上の記事を対象としてみた。）

#コード

```JavaScript:QiitaAPI.js
// axiosモジュールの読み込み
const axios = require('axios');
axios.defaults.baseURL = 'https://qiita.com/api/v2';

let array1 = [];  // タグ名用
let array2 = [];  // カウント用

// main関数
async function main(page) {

  // QiitaAPIからレスポンス受け取り（ストック>=300 + 作成日>=2020-01 の記事一覧）
  let response = await axios.get(
      '/items?page=' + page + '&per_page=100&query=stocks:' +
      encodeURIComponent('>=300') + '+created:'+ encodeURIComponent('>=2020-01')
  );

  // 取得した記事から[tags]要素を取得
  for (let i=0; i<response.data.length; i++) {
    for (let j=0; j<response.data[i].tags.length; j++) {

        var tagname = response.data[i].tags[j].name;    // タグ名取得

        // 配列に登録があれば、カウントを＋。登録が無いなら配列に追加。
        var result = array1.indexOf( tagname );         // 検索（既に配列にあるか）
        if (result < 0) {
            array1.push(tagname);
            array2.push(1);
        } else { array2[result] += 1; }
    }
  }

  // 結果出力
  if (page==5) {
      for (let i=0; i<array1.length; i++) {
        console.log(array1[i]+', '+array2[i]);
      }
  }
}

// main関数 実行
let promise = Promise.resolve();
for (let k=1; k<6; k++) {
    promise = promise.then(() => main(k));
}
```

##色々ハマった点
####１．QiitaAPIって何がとれるのさ？
[QiitaAPIの仕様書](https://qiita.com/api/v2/docs)を読み込んでみた。（色々取れそうだけど、技術力が追い付かないので断念。）
最初におや？と思ったのは、１回のレスポンスで最大100件、ページ指定も最大100ページ。つまり、１万件まで。
100件以上を取ろうと思うとページを何度か呼び出すしかないのかな。ってことで、main関数をループすることにした。

```.js
  let response = await axios.get(
      '/items?page=' + page + '&per_page=100&query=stocks:' +
      encodeURIComponent('>=300') + '+created:'+ encodeURIComponent('>=2020-01')
  );
```

####２．非同期処理ってなんぞや？
ループしようと思ったはいいけど、上手くいかない。
どうも非同期処理で走るからって理由らしい。正直良く分かってないが、以下サイトを参考に改善してみた。
[PromiseによるJavaScript非同期処理レシピ集](https://sbfl.net/blog/2019/11/04/promise-cookbook/)

```.js
let promise = Promise.resolve();
for (let k=1; k<6; k++) {
    promise = promise.then(() => main(k));
}
```

#結果
結果は、EXCELで集計。
（あまり細かくなってもアレなので、表は上位10件、グラフは記事数7件以上を表示。）
※2020年に投稿された記事で、ストック数が300以上の記事についてタグを集計

|タグ|記事数|
|:-----------|:------------:|
|JavaScript|67|
|Python|58|
|初心者|49|
|機械学習|24|
|新人プログラマ応援|24|
|HTML|16|
|DeepLearning|16|
|GitHub|16|
|Vue.js|16|
|React|16|

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/725039/b6f5eb9d-d5c0-0409-1ad8-bd000e9eca4b.png)

#考察
Qiitaトップのタグ・ランキングとはまた違った結果になった。
上位の「JavaScript」「Python」は、今年も熱い。ストック数も多いということは、興味関心が高く、役立つ情報がまだまだあるってことかなぁ。

興味深いのは、タグ・ランキングでは上位の「Ruby」がランク外。
最近の投稿が少ないか、ストック数が伸びないのか、、、？？

#最後に
JavaScriptの学習も兼ねて今回はチャレンジしてみましたが、もっとより良いアプローチがある気がしました。
そもそも、私の技術力の無さを痛感。（書いてませんが色々断念してます。。。）
まずは書く！調べる！やってみる！
トライアンドエラーで今後も素人ながら挑戦していきます。
なぜテストコードを書く必要があるのか？

自分が担当するプロジェクトでは、参画した時点でテストコードが書かれており、新規コード追加時にテストコードを書く文化が浸透していました。前職ではそのような文化はなく苦労もあったので、自動テストがある程度書かれており、新規コードでは書いていく非常に良いことだと思い、その価値や良さを感じています。

一方で、新しく参画した人や新卒エンジニアに関してはテストコードを書くことが**当たり前になりすぎているんじゃないか？**と感じました。

テストを**「書かされていると感じている方」**や、**「いまいちテストコードを書く意味がわからないという方」**は本記事を読んで少しでもテストをポジティブに捉えてもらえると幸いです。

## 🤔なぜテストコードを書くのか
結論から言うと、**プロダクトのコードの質を高めるための手段の1つ**と私は捉えています。

コードの質を高めるための手段は他にも様々ありますが、そのうちの有効なツールの一つがテストだと考えます。
テストコードを書くことで、**プログラムの振る舞いを担保すること**ができ、これが質の向上に繋がっていきます。


## 🍀テストコードの7つの恩恵
では、テストコードを書くことによって具体的にどんな効果があるのか考えてみました。

### 1. テストそのものの自動化による工数の削減
動作検証が自動化されることにより、リリース時のみでなく今後同じ箇所を検証する時間が削減されます。多くの箇所で使われたり、変更の多いプログラムであるほど、その効果は大きくなります。最も分かりやすい恩恵です。

ただし、手動のテストが全てなくなる訳ではありません。向き不向き、コストパフォーマンスの良し悪しもあるのであくまで手段の１つです。

### 2. 不具合の未然防止につながる
コードを生成する上でテストも同時に実装するため、開発の過程でも不具合率は減少する可能性はあります。実際新規コードに対してテストコードを書くようになってから、バックエンド側での不具合の発生率はかなり減少しました。

また、後々に対象のコードに影響のある箇所を修正してバグが発生してしまった際に、過去に書いたテストのおかげで早期発見に繋がります。これによって**将来の不具合を防止する**という効果も期待できます。（何度か書いててよかったーを経験しました）

### 3. プログラムの振る舞いがテストコードという形で明文化される
私は過去、手動でテストをした際にエクセルなどでテストケースを洗い出し、そのテスト表を元にテストしたりします。しかし、経験上なかなかこうしたドキュメントはその場限りになってしまい、再度使われることは少ないです。

※実装担当者のみしかテストパターンを把握しておらず、退職後誰も触れられない、なんてことも経験してきました。

しかし、テストコードとして書かれていれば、そのコードそのものが**ドキュメントのような役割**も持ちますし、さらにそのテストを再現させることもコマンド一つで済むという利点があります。結果として、**属人化の解消**にもつながる側面を持っています。

### 4. リファクタリングのハードルが下がる
コードの質を高めるためにはテストだけでなく、そもそものコードを改善する必要があります。その際、テストコードがある程度の振る舞いを担保してくれていることで、難易度がかなり下がります。当然それでも怖い面はありますが、テストコードなしの1000行越えのスパゲッティコードを直接リファクタリングするよりも、遥かにハードルは下がると思います。

このように、テストコードを書いてあることで間接的ながら、**コードの質を高めること**に大きく貢献してくれると言えると思います。

### 5. バージョンアップや脆弱性対応への対応ハードルが下がる
かなりテストカバレッジ率が高く、成熟したプロジェクトの話になりますが、バージョンアップなどの影響範囲の大きい作業のハードルが下がります。仮にテストコードが書かれていなかったら、全体に大きく影響のある作業はリスクが高すぎてよっぽどの理由がないとやりたくないです。

[GitHubのRailsのバージョンアップ](https://github.blog/2019-09-09-running-github-on-rails-6-0/)の話などは、社内でもかなり話題になりました。

### 6. コードの質に対する1つの指標になる
テストコードが書かれていると、テストのカバレッジ率（全体のコードのうち、どれだけの実行コードをテストコードが担保しているか）を数値化して出力できるので、定点観測ができるようになります。その結果、指標として検収条件や組織目標として**プログラムの質に対する定量的な指標**を作ることができます。

### 7. モジュールを適切に分割するようになる（かもしれない）
副産物的なものですが、自分は新しい関数を作るときに、テストをどうやってやるかを考えています。その結果、テストしやすい単位でモジュールを分割するようになりました。

下記の記事が非常におもしくわかりやすかったので気になる方はこちらをどうぞ！
[テストしやすい「純粋」な関数とは？ \- Qiita](https://qiita.com/Yametaro/items/3ec5a7d89afa1a0e9f15)

## 🚫 受け身な理由で書かれたテストコードは危険を孕んでいる
テストコードを書く上でのありがちな理由として、

* 検収条件にC0/C1(テストカバレッジ）が90%とあるから
* 会社のルールとして決まっているから

などがあると思います。

カバレッジをあげることに固執しすぎたり、仕方なく書かれたテストコードは、不具合の発見、コードの明文化、プログラムの質の向上といった本来享受したかった**テストコードを書く意義**そのものが抜け落ちてしまい、ただ通るだけのテストになってしまっている場合があります。（わたしもそうなっていたことがあります）

カバレッジ率を意識することや、テストコードを当たり前のように書く文化は決して悪くはありませんが、なんのためにテストコードを書いているのかを忘れてしまうと、**価値の低いテストコード**になってしまったり、最悪の場合**テストコード自体が技術的負債**にもなり得てしまいます。

## 🤔改めて、なぜテストコードを書くのか？
**プロダクトのコードの質を高める１つの手段**として、つまりは上記に述べたような効果も認識した上で、テストコードを活用するのが良いと思います。

組織やチーム内でこれについて議論してみるのも効果的かもしれません。テストコードを書く目的が明確になれば、テストコードをポジティブに捉えられると思います。

## まとめ
自分も偉そうなことを言える立場ではありませんが、少なくとも今は**テストコードを書くことに対してポジティブに捉えられています。**これを読んだ方々が少しでもテストコードを書くことを前向きに捉えてもらえることを祈ります！

それでは、良いテストライフを！
huggingface/transformersの学習済みモデルとpipelineによる感情分析

# 概要
[huggingface/transformers](https://huggingface.co/transformers/)のpipelineクラスを用いて数行のコードで推論を行います。２つBERTベースのモデルを用いて推論を行う方法を紹介します。

#コード
[pipelineクラス](https://huggingface.co/transformers/main_classes/pipelines.html)を用いることで、分類タスクやQAタスクなどを事前学習済みモデルとそのtokenizerを用いて簡単に推論することができるようになります。今回は文がポジティブかネガティブかを判別する文書分類タスクである感情分析を行います。
私の実行環境は、AWSが提供しているSageMakerの`ml.t2.medium`、カーネルは`conda_python3`です。
`requirements.txt`は以下の通りです。

```
tensorboard
transformers
mecab-python3
fugashi
ipadic
```

## 日本語（汎用）BERT
こちらは東北大学が公開しているBERTを用いて感情分析をするコードです。
他のpipelineのタスクも解くことができます。

```python

from transformers import pipeline
from transformers import BertForSequenceClassification
from transformers.tokenization_bert_japanese import BertJapaneseTokenizer

model = BertForSequenceClassification.from_pretrained('cl-tohoku/bert-base-japanese-whole-word-masking')
tokenizer = BertJapaneseTokenizer.from_pretrained("cl-tohoku/bert-base-japanese-whole-word-masking")
nlp = pipeline('sentiment-analysis', model=model, tokenizer=tokenizer)

print(nlp("この商品を買ってよかったです"))

```

上記のモデルから`LABEL_0`（ポジティブ）`LABEL_1`（ネガティブ）のどちらかの値が出力されます。
上記の例の出力結果は、`{'label': 'LABEL_0', 'score': 0.5814786553382874}`でした。
 
## 日本語の感情分析に特化したBERTベースモデル
huggingface/transformersには日本語の感情分析に特化したBERTベースモデルが提供されていました。huggingface/transformersではコントリビューターがモデルの提供を積極的に行っているみたいです。

```python

from transformers import pipeline
nlp = pipeline("sentiment-analysis",model="daigo/bert-base-japanese-sentiment",tokenizer="daigo/bert-base-japanese-sentiment")
print(nlp("この商品を買ってよかったです"))
```
上記のモデルから`ポジティブ`または`ネガティブ`のどちらかの値が出力されます。
例の出力結果は、`{'label': 'ポジティブ', 'score': 0.9867748022079468}`でした。

## まとめ
本投稿ではhuggingface/transformersで簡単に推論する方法を紹介しました！
2つ目の紹介したモデルのほうが、感情分析に特化されたモデルになっているため、精度が高いです。
今後も様々なモデルが簡単に使える様になると思います！
Linuxでリソース使用率上げる方法

Hinemosを勉強している最中、以下の有益な情報をゲットしました。共有いたします。

◆CPU使用率を上げる方法
yesコマンドでCPU負荷を上げることができます。以下のコマンドを2、3分実行し続けて、Ctrl-Cで止めます。

        [root] # yes >> /dev/null
        
◆ファイルシステムIO使用率を故意に上げる方法
大きいサイズのファイルを作成することで、ファイルシステムの空き容量を減らすことができます。以下の例では、10GBのダミーファイルを作成します。作成するファイルのサイズは実際の環境にあわせて調整してください。

        [root] # cd /tmp
        [root] # dd if=/dev/zero of=bigtempfile bs=1M count=10000
        
◆ネットワーク情報量を故意に上げる方法
ファイルをダウンロード、またはアップロードすることで、ネットワーク情報量の値を上げることができます。以下の例では、「ファイルシステム使用率を故意に上げる方法」にて作成したファイルを、マネージャサーバに転送します。

        [root] # cd /tmp
        [root] # scp /tmp/bigtempfile root@172.16.58.243:/tmp/
Airpodsをweb会議に使おうと思ってハマった音声出力設定

#あらすじ

社内でAirPodsをWindowsパソコンにペアリングしてWEB会議に使おうとしたが、なんだかホワイトノイズがザーと入る。音が悪い。何でだろうとハマったお話。

#答え

AirPods には、マイクと音声（低音質）がともに使えるモードと、音声のみを高品質で送れるモードがある。
再生デバイスの選択肢としては、前者のマイクと音声は「Hands-Free AG Audio」となり、後者の高品質音声は「Stereo」。

WEB会議でマイクも音声もともにAirPodsを使うなら、「Hands-Free AG Audio」をツールの設定で選ぶ。マイクをパソコン付属のものだったり、別途持っているのなら「Stereo」を選択するのが基本。




私はよく分からず、動画を見るのに「Hands-Free AG Audio」を使って音が悪いなと悩んだり、WEB会議でマイクを使いたいのに「Stereo」を選んで、マイクの設定がおかしくなったり、やらかしました。
Qiitaって誰向けなの？レベル別投稿を可視化してみた

#はじめに
　とある理由からQiitaを利用することとなったが、正直Qiitaの読み方も知らない（たぶんキータ）、どんな人がどういった目的で利用するツールなのか正直何だかわかってない、アカウント作りたてほやほやの初心者が投稿する。
#目的
Qiitaのレベル別利用者の分布を可視化し、どのような人にとって便利なツールであるかを考察する。

#コード
###初級者、中級者、上級者タグをフォローしている人数を取得する
```
const axios = require("axios");

async function main() {
  let response = await axios.get(
      "https://qiita.com/api/v2/tags/%E5%88%9D%E5%BF%83%E8%80%85"
      );
  console.log(response.data.followers_count);
}

main();
```

#実行結果
初級者：4476件
中級者：0件
上級者：0件

#考察
　中級者、上級者タグが存在していなかったため、タグに紐づくフォロー人数では利用者属性を推察することができなかった。
　一方で、「初級」と検索した際の記事投稿数は1,836件、「中級」と検索した際の記事投稿数は1,572件、「上級」と検索した際の記事投稿数は1,404件だったたため、検索結果からすると幅広いレベルの利用者向けの技術サイトであると推測できる。

#最後に
　・本来は「投稿記事のタイトルや本文から、記事をレベル分けした分布」や「投稿者のプロフィールをもとにした利用者レベル分析」などといったことも考察してみたかったが、抽出方法がわからず、諦めました..
　・Qiitaは、初級者である私にも便利なツールであることがわかった。※実際この記事を投稿するためにいくつかの記事を参考にした。
今後も記事投稿を続ける予定のため、継続して利用しようと思う。
PythonでSeleniumを使ってみる

スクレイピングを勉強した際にSeleniumを使ったのでインストール方法などをまとめてみる。
# 環境
* Windows10(64bit)
* Anaconda3
* Python 3.7.6
* Spyder 4.0.1
* Selenium 3.141.0
* Chrome 85.0.4183.121
* ChromeDriver 85.0.4183.87.0

以下この環境で解説しています。環境が違う方は適時読み替えてください。

# 使うもの
* Selenium 
* Chrome
* ChromeDriver

# Seleniumインストール
Anaconda Promptを開いて

```
pip install selenium
```

Successfully installed seleniumうんたらかんたらと出たら完了

# ChromeDriverインストール
## 自分のChromeのバージョンを確認
「ヘルプ→GoogleChromeについて」から見れます。
もしくはブラウザのアドレスバーに

```
chrome://settings/help
```

と入力しても見れます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/751575/19e01710-9a3f-8186-0de6-07ec003e600e.png)
## GoogleDriverインストール
今回はPythonのみに用いるので、pipでインストールする方法を説明します。
この方法のほかにもChromeDriverをダウンロードして環境変数からPATHを通す方法もあります。そちらの方法では他の用途にもChromeDriverを利用できます。


先ほど確認したChromeのバージョンを用います。
まずSeleniumインストール時と同じくAnaconda Promptを開きます。
そして`pip install chromedriver-binary==[Chromeのバージョン]`と実行します。
私の場合は、

```
pip install chromedriver-binary==85.0.4183.121
```

として実行しました。
多くの方はここでエラーが出ます。
出なかった方は次に進んでください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/751575/21f8fa64-6c00-df1c-f09a-4a7d64f942ef.png)
ここに書かれているのはChromeDriverのバージョン番号です。
エラーが出ないようにするには、ここに書かれているバージョン番号を用いて実行する必要があります。
この中から自身のChromeのバージョン番号よりも少し小さい番号を選択します。
私の場合は、Chromeのバージョンが「85.0.4183.121」だったので、ChromeDriverのバージョンは「85.0.4183.87.0」を選択しました。
そしてこのバージョン番号を用いて、再度以下のコマンドを実行します。

```
pip install chromedriver-binary==85.0.4183.87.0
```

これでSuccessfully installed chromedriver-binaryうんたらかんたらと出れば成功です。

# Webページを開いてテスト
動作するか確認します。
Pythonを実行できる環境で以下のように入力して実行します。ここではSpyderを利用しています。
セキュリティの警告が出た際は「アクセスを許可する」をクリックしてください。

```Python
import time
import chromedriver_binary
from selenium import webdriver

driver = webdriver.Chrome()
driver.get('https://www.google.com/')
time.sleep(5)
driver.quit()
```
`webdriver.Chrome()`：ブラウザを開く
`driver.get('URL')`：指定したURLにアクセス
`driver.quit()`：ブラウザを閉じる

以下のようにChromeが立ち上がり、Googleのページが開けば成功です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/751575/37c612f8-2028-d2d1-e63f-eddc751c6679.png)

# 参考ページ
* [PythonでSeleniumを使ってスクレイピング (基礎)](https://qiita.com/kinpira/items/383b0fbee6bf229ea03d)
* [[selenium向け] ChromeDriverをpipでインストールする方法（パス通し不要、バージョン指定可能）](https://qiita.com/hanzawak/items/2ab4d2a333d6be6ac760)
* [Python + Selenium で Chrome の自動操作を一通り
](https://qiita.com/memakura/items/20a02161fa7e18d8a693)
GatsbyJS ローカルで開発中のページをスマホでも見る方法

ローカルで開発中のページをスマホで確認したい場合は、プライベートIPでアクセス可能にしてあげればスマホでも開発中のページをスマホでも見ることができます

# 実行コマンド
```gatsby develop -H 0.0.0.0
```
# 実行後 
![参考画像1](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/606623/d40016fd-9094-6809-8dce-8c4e5ab67478.png)
スマホで赤枠で囲んでいるURLにアクセスすると開発中のページが、閲覧できます。
※ 接続できない場合は、同一のネットワーク環境出ない可能性があるので、ネットワークの接続先を確認しましょう。
KotlinのTODO関数

# はじめに
小ネタです。Kotlinをプライベートで昔若干触ってましたが、
恥ずかしながら `TODO()` 関数の存在を知りませんでしたので、軽く書かせて頂きます。

# コード

```kotlin
fun main(args:Array<String>) {
    println("Hello")
    TODO("実装途中ですよ")
    println("World")
}
```
上記のコードを実行すると、下記が表示されます。

```
Hello
Exception in thread "main" kotlin.NotImplementedError: An operation is not implemented: TEST
```

# TODOとは
下記のように、未実装を表す `NotImplementedError` を `throw` するだけの関数のようです。
コンパイルは通すけど、未実装を表す時に使えそうです。

```kotlin
public inline fun TODO(reason: String): Nothing = throw NotImplementedError("An operation is not implemented: $reason")
```

# 最後に
業務で使っている方には当たり前のことかもしれませんが、初めて知ったので記事にさせて頂きました。
rails5.2.4 で作成した既存のアプリを5.1.6にダウングレードする


rails5.2.4で開発を進めていたのですが、既存のサービスとバージョンを合わせて管理がしたかったため、ダウングレードを選択しました。
環境はdockerで構築しているため、 ローカルの場合は使用しているPC等のrailsのバージョン変更が必要になります。


##手順

###1.Gemfileのrailsのバージョンを書き換える

```PHP:Gemfile
gem "rails", "5.1.6"
```

###2.bundle update　(dockerのサービス名はwebにしています)

```
$ docker-compose run web bundle update
```

### 3.configの書き換え

application.rbのconfig.load_defaultsが5.2になっているので、5.1に変更

```PHP:application.rb
 config.load_defaults 5.1
```


### 4.Active Recordの設定解除
application.jsのactive_storageの行を削除



```PHP:application.js
//=require active_storage
```

configのactive_storageの行を削除

```PHP:production.rb
config.active_storage.service = :local
```

```PHP:development.rb
config.active_storage.service = :local
```

### 5.secrets.ymlを作成
config配下にsecrets.ymlを作成し、`bundle exec rake secret`で鍵の作成をする。

参考記事
https://qiita.com/tanishilove/items/2801059830e5af1262d7


###6.最後にdevelopment.rbに残っているActive_storageの設定を削除

config.active_record.verbose_query_logsをfalseに変更

```PHP:development.rb
config.active_record.verbose_query_logs = false
```


##最後に

バージョンを下げる機会はなかなかないかと思いますが、困った時に参考になればと。
【RaspberryPi】人感センサを使って部屋の明かりをつける

#背景
ラズパイにhomebridgeを入れることでSiriに頼めば部屋の明かりがつく
けど部屋に行く度、Siriに頼むためにiPhoneを足すのがめんどくなってきた


そこで人感センサをつけてさらに自動化したいと思った

#部品

使った人感センサモジュールはこちら
[Ren He HC-SR501人体赤外線感応モジュール モジュール焦電型赤外線検出器PIRモーション 人体の赤外線の感応器 人感センサースイッチ ボディセンサーモジュール 3個](https://www.amazon.co.jp/gp/product/B07DCKZS5S/ref=ppx_yo_dt_b_asin_title_o00_s00?ie=UTF8&psc=1)

実物がこれ
![S__2981894.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136271/11826c0f-cd9b-9dc6-0f5b-d6443da9e7be.jpeg)
![S__2981892.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136271/a3ef7a5a-5cbd-4bfb-73a7-cfd5b9ed09b1.jpeg)
![S__2981895.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136271/e2ab8f0a-67e0-0cd7-1643-88b58ec6de32.jpeg)

接続はこんな感じ
![S__2981896.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/136271/786df2e1-30db-983d-1512-a220acb70fd4.jpeg)

配線が汚いのは目をつぶってください

このモジュール自体は電源とGNDとoutput用のピンがあるだけでそれぞれにつないでやればいいから簡単

#作り方
[【Raspberry Pi】自作人感センサーの使い方と活用法](https://chasuke.com/motionsensor/)というサイトのコードを参考にテストをしてみました。

私はPthonよりPHPが得意なのと、その他の赤外線家電(主にエアコン)のスクリプトをPHPで書いているという理由で、
このスクリプトをPHPで使えるように変換し、人感センサーからの情報をPHPスクリプトから監視する形を取りました。

##PHPで取得できる形にする
以下のコードでやっているのは人を検知したら`1`を出力するというだけ

```python3
from datetime import datetime
import RPi.GPIO as GPIO

# 使用するGPIO
GPIO_PIN = 18

GPIO.setmode(GPIO.BCM)
GPIO.setup(GPIO_PIN, GPIO.IN)

if __name__ == '__main__':
    try:
        # センサー感知
        if(GPIO.input(GPIO_PIN) == GPIO.HIGH):
            print(1)
        else:
            print(0)
    except KeyboardInterrupt:
        print("終了処理中...")
    finally:
        GPIO.cleanup()
        
```
参考：[【Raspberry Pi】自作人感センサーの使い方と活用法](https://chasuke.com/motionsensor/)



##監視用のPHPスクリプトを作る
次は、先のコードをPHPから一定間隔で取得して、人を検知したら明かりを付けるスクリプトを作る。

```php5:deamon.php
<?php
const GET_DATA_CMD = '先のpythonコードのパス';
const ON_CMD = '明かりをONにするスクリプト';
const OFF_CMD = '明かりを消すスクリプト';
//60秒間人検知しなかったら消す
const TURN_OFF_COUNT=60;
$count=0;

while (1) {
    $data = (int)shell_exec(CMD);
    if($data==1){
        shell_exec(ON_CMD);
        $count=0;
    }else{
        if($count==TURN_OFF_COUNT)shell_exec(OFF_CMD);
    }
    $count++;
    print $count."\n";
    sleep(1);
}
```
上記コードは人を検知したら明かりをつけて、60秒人検知しなかったら電気を消すようにしている

#PHPスクリプトをデーモン化
コマンドの最後に`&`を付けるだけ

```
php deamon.php > log.log &
```

nohupをつけておけばログアウト後も処理を続けれくれるけど`&`を付けるだけもいいみたい
>nohup コマンドを使うとログアウト時に処理を停止させないでプログラムを続けるようにさせることができる。という説明をよくみかけますが、実際には、nohup を使わなくても、プログラムを「&」を使ってバックグラウンドで処理していれば、ログアウト後も起動されたプログラムはそのまま処理を継続します。
引用：[ログアウトした後もプログラムの処理を続ける？（コマンド実行時にnohup）](https://kazmax.zpp.jp/linux_beginner/nohup.html)

デーモン化したものをkillするのには以下コマンドでPIDを調べる

```
$ ps -ef | grep deamon.php
```
そしてkill

```
$ kill -9 [PID]
```
後はctonで特定時間に起動する容易にすれば昼間はOFFにしたりもできる
daemonの自動起動は方法がいっぱいあるけど、今はややこしくなるのでcronで起動するだけにしておく

#参考
- [【Raspberry Pi】自作人感センサーの使い方と活用法](https://chasuke.com/motionsensor/)
【PHP】文字列を固定長に揃える（マルチバイト文字）

## はじめに
マルチバイト文字列を指定の長さで揃えたい

## sprintf
```php
sprintf('%-10s', 'abc'); // "abc       "
sprintf('%-10s', 'あいうえお') // "あいうえお"
```
sprintfではマルチバイト文字のときに上手く対応できない

参考：[PHP: sprintf - Manual](https://www.php.net/manual/ja/function.sprintf.php)

## str_pad
```php
str_pad('abc', 10, ' ',STR_PAD_RIGHT) // "abc       "
str_pad('あいう', 10, ' ',STR_PAD_RIGHT) // "あいう "
```
バイト数換算で計算されるので、マルチバイト文字の場合、指定が上手く対応できない

参考：[PHP: str_pad - Manual](https://www.php.net/manual/ja/function.str-pad.php)

## 以下のような関数を作ってマルチバイト文字列の長さを揃える
```php
/**
 * 指定の文字列の長さまで全角で埋める
 * @return string $input 埋めた後の文字列
 */
 public function mbStrPad($input, $pad_length) {
     while(mb_strlen($input) < $pad_length) {
         $input .= '　';
     }
     return $input;
 }

mbStrPad('あいうえお', 10); // "あいうえお　　　　　"
mb_strlen(mbStrPad('あいうえお', 10)); // 10

```

上記のような関数を作ってあげてマルチバイト文字列の長さを揃えた
Python + Janomeでマルコフ連鎖人工無脳（1）Janome入門

#前書き
Pythonでマルコフ連鎖人工無脳を実装しようと思いました。
さて、形態素解析はなにに投げますかなと調べたところ、
Janomeというのが他のライブラリとの依存関係もなく、
pip一発でさくっとインストールできるそうです。ためしちゃお！

#環境
Python 3.8.5
Janome 0.4.1

#使い方
```python
from janome.tokenizer import Tokenizer

t = Tokenizer()

s = "草わかば色鉛筆の赤き粉の散るがいとしく寝てけずるなり"

for token in t.tokenize(s):
    print(token)
```
Tokenizerクラスを使います。

```python
t = Tokenizer()
```
Tokenizerインスタンスを作って、

```python
for token in t.tokenize(s):
    print(token)
```
解析したい文章をtokenizeメソッドに渡します。
上のように中身を一つ一つ表示させると、こんな感じです。

```
python analysis.py
草      名詞,一般,*,*,*,*,草,クサ,クサ
わかば  名詞,固有名詞,組織,*,*,*,わかば,ワカバ,ワカバ
色鉛筆  名詞,一般,*,*,*,*,色鉛筆,イロエンピツ,イロエンピツ
の      助詞,連体化,*,*,*,*,の,ノ,ノ
赤き    形容詞,自立,*,*,形容詞・アウオ段,体言接続,赤い,アカキ,アカキ
粉      名詞,一般,*,*,*,*,粉,コナ,コナ
の      助詞,格助詞,一般,*,*,*,の,ノ,ノ
散る    動詞,自立,*,*,五段・ラ行,基本形,散る,チル,チル
が      助詞,接続助詞,*,*,*,*,が,ガ,ガ
いとしく        形容詞,自立,*,*,形容詞・イ段,連用テ接続,いとしい,イトシク,イトシク
寝      動詞,自立,*,*,一段,連用形,寝る,ネ,ネ
て      助詞,接続助詞,*,*,*,*,て,テ,テ
けずる  動詞,自立,*,*,五段・ラ行,基本形,けずる,ケズル,ケズル
なり    助詞,接続助詞,*,*,*,*,なり,ナリ,ナリ
```
要素を一つ一つ取り出してやることもできます。
ためしに表層形と基本形、品詞を出力してみました。

```python
from janome.tokenizer import Tokenizer

t = Tokenizer()

s = "寝てけずるなり"

for token in t.tokenize(s):
    print("==========")
    print(token.surface + "　(表層形)")
    print(token.base_form + "　(基本形)")
    print(token.part_of_speech + "　(品詞)")
```
実行結果

```
python analysis.py
==========
寝　(表層形)
寝る　(基本形)
動詞,自立,*,*　(品詞)
==========
て　(表層形)
て　(基本形)
助詞,接続助詞,*,*　(品詞)
==========
けずる　(表層形)
けずる　(基本形)
動詞,自立,*,*　(品詞)
==========
なり　(表層形)
なり　(基本形)
助詞,接続助詞,*,*　(品詞)
```

次章で文章生成を実装していきます。
[Python + Janomeでマルコフ連鎖人工無脳（2）マルコフ連鎖入門](https://qiita.com/GlobeFish/items/17dc25f7920bb580d298)
13. 【Android/Kotlin】Handler（画面遷移を遅延）

#はじめに
DreamHanksのMOONです。

前回はCircleImageViewという外部ライブラリを使用しました。
[12. 【Android/Kotlin】丸いイメージ（CircleImageView）](https://qiita.com/DreamHanks/items/b57d9eb22d70f70c0231)

今回は`Handler`について説明し、`Handler`で画面遷移を遅延してみます。

#Handlerとは
ハンドラは簡単にサブスレッドからメインスレッドへメッセージを受け渡すためのクラスです。

アンドロイドでは、UIの作業をサブスレッドですることは禁止されています。

なので、サブスレッドにUIの作業をしたい場合は`Handler`を使用します。

#画面遷移を遅延
・ローディング画面のActivityを作成

```kotlin:LoadingActivity.kt
package com.example.practiceapplication

import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.os.Handler

class LoadingActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_loading)

        //ハンドラのメソッド呼び出す
        loadingDelay()
    }

    //画面の遷移を遅延するためのメソッド
    fun loadingDelay(){
        //ハンドラを生成し、遅延時間を2秒に設定
        Handler().postDelayed({
            //2秒以降に画面を遷移するためのIntent設定
            val nextIntent = Intent(this, MainActivity::class.java)
            startActivity(nextIntent)
        }, 2000)
    }
}

```

・ローディング画面のレイアウトのxmlを作成
![1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/708649/12a1c37f-d5c1-7543-7ca0-9f473ce7b624.png)

```xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:background="#2a5a4c"
    android:gravity="center">

    <TextView
        android:id="@+id/title"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="DreamHanks"
        android:textColor="#FFFFFF"
        android:textSize="50sp" />

</LinearLayout>
```

・画面遷移させるActivity、xmlを作成
　下記のリンクで確認してください。
　[7. 【Android/Kotlin】バリデーションチェック](https://qiita.com/DreamHanks/items/81511dae61cc9c4a7e63)

#アプリ起動
・アプリを実行する時の初期のローディング画面
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/708649/739d60df-bcea-9fb7-b714-e7ba086ceddc.jpeg" width=50%>

・2秒以降は遷移された画面
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/708649/53500711-1b7e-ba6c-f193-882b2b331d61.jpeg" width=50%>

#終わりに
今回は`Handler`について説明し、`Handler`で画面遷移を遅延しました。

以降の記事については下記のリンク（DreamHanksのブログ）で確認することができます。
[Android/Kotlinアプリ開発](http://blog.dreamhanks.com/android-kotlin%e3%82%a2%e3%83%97%e3%83%aa%e9%96%8b%e7%99%ba/)
Laravelディレクトリ構成＋DBマイグレーション

今回はLaravelディレクトリ構成＋DBマイグレーションを説明していきます。

#ディレクトリ構成
![image.png](https://i.gyazo.com/2fb41000ba954cf5b2cfd12cf52fcd04.png)

| ディレクトリ名 | 役割 |
|:-:|:-:|
| app  | アプリのメインとなるところ  |
| bootstrap  |  初期処理やキャッシュなど |
| config  |  アプリの設定 |
| database  | データベース（マイグレーション）  |
| public  | 画像、JS、CSSなど  |
| resources  | bladeなど（HTML）  |
| routes  | アプリのURL設定  |
| storage  | セッションやログ  |
| tests  | テスト用  |
| vendor  | Comoposerの依存内容  |


#マイグレーション
##マイグレーションとは
SQLを直接使わなくても、データベースを管理できるLaravelの仕組みです。
##マイグレーションファイル
マイグレーションファイルは「どんなテーブルを作るか」というテーブルの設計書です。設計書を作ったらそれを実行しなければテーブルはできないので、この実行にあたるのがマイグレーションです。
##テーブル作成の流れ
**1. マイグレーションファイルを生成**
**2. ファイルにテーブル定義を書く**
**3. マイグレーションファイルを実行して、DBに反映**

###ファイルの場所とファイル名ルール
![image.png](https://i.gyazo.com/149ac69e4e86f22b01589387f1fcee9c.png)
###ファイル生成コマンド

```terminal
 $ php artsan make:migration create_users_table 
```
(例)カラム追加ver

```terminal
$ add_カラム名_to_テーブル名_table
```
###実行コマンド

```terminal
$ php artisan migrate
```

##マイグレーションの中身
**・upとdownメソッド**
　upが実行（作成）で、downが元に戻す（削除）
**・Schemaファサードを使っている**
　例）　Schema::create テーブルを作成
**・カラムの作成はBlueprintオブジェクトのtableメソッドを使う**
　例）　$table->string('name')名前カラムを作成

```php
   public function up()//作成
    {
        if(!Schema::hasTable('blogs')) {//もしblogsというtableがなかったら
            Schema::create('blogs', function (Blueprint $table) {
                $table->id();//idのカラム
                $table->string('title',100);//titleというカラムをstring型で100文字の制限をつけた状態で作る
                $table->text('content');//contentというカラムをtext型で作る
                $table->timestamps();
            });
        }
        
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()削除
    {
        Schema::dropIfExists('blogs');
    }
```

追加したいカラムなどを書き終えたらmigrateしていきます。

```terminal
$ php artisan migrate
```





#終わりに
参考サイトを貼らせて頂きます。

公式ドキュメント
https://readouble.com/laravel/7.x/ja/migrations.html

参考サイト
https://www.youtube.com/watch?v=wkW1spp_LO8
【Python3】画像のリサイズをフォルダー単位で行いたいときに使えるコード

備忘録やOUTPUT的な意味での蓄積（一気に作った系はこれで終わり）

#作成目的
作業用のサイズをすべて変換したいときが定期的に起こったので、作業簡略化のために作成

#作成環境
・windows10
・Anaconda3
・python3.7
・Jupyter Notebook

#ドキュメント
①resizeしたいフォルダー名を入力(png_folderの一つ上のディレクトリ)
②folderがなければcurrent_folder内に、resize_folder を作成する
③幅と高さを指定し、画像をリサイズ(入力をしなかった場合Errorになる)
④すでに同じフォルダー名がある場合、誤操作を防ぐためにErrorになる

#ライブラリの読み込み

```python:All&nbsp;Necessary&nbsp;Libraries.py
import numpy as np
import os
import pathlib
from pathlib import Path
from glob import glob
from PIL import Image
from tqdm import tqdm
```

#PG

```python:image_resize_code
# フォルダ名を入力
folder_name = input('Enter the folder name :')
# pathを取得
p = Path('C:/Users/H3051411/OUT/' + folder_name + '/_png_folder')
new_folder_name = '_resize_folder'
new_folder_path = os.path.join(p, new_folder_name)

# 新しいpathを取得
new_p = Path(new_folder_path)

# フォルダーが存在しない場合リサイズ処理を行う
if not os.path.exists(new_folder_path):
    # 新規フォルダーの作成
    os.makedirs(new_folder_path)
    # 幅と高さの指定
    width = int(input('withsize_input: '))
    height = int(input('height_size_input: '))
    
    # ファイルをリストで取得
    files = list(p.glob('*.*'))
    
    # リサイズ処理
    for f in tqdm(files):
        # 画像ファイルを取得
        img = Image.open(f)
        # 最高品質でリサイズ処理
        img_resize = img.resize((width, height), Image.LANCZOS)
        # ファイル名を取得
        imgname = os.path.basename(f)
        # print(imgname) # 確認用
        # 新規ファイル名を設定
        newfname ='resize_' + imgname
        # print(newfname) # 確認用
        # ファイルを保存する(path指定)
        img_resize.save(new_p/newfname)
else:
    # ファイルが存在する場合Errorを返す
    print('Error：resize_folderはすでに存在しています.')
```

# 課題
・関数化していない
・画像数が増えると時間かかりそう(未テスト)

# まとめ
作業時間が1時間から1分になりました。
あと、もっといい書き方がある気がする。
これは外せない、VSCodeの環境設定

## はじめに
VSCodeの環境設定で、個人的にこれはやっておいた方が便利だと思われるものをピックアップして紹介します。

## 設定

- 自動保存

```
Files: Auto Save = afterDelay
Files:Auto Save Delay = 1000
```
> 1000ミリ秒（1秒）後に自動保存されます。**Ctl+s**を押す手間が省けるのは便利ですが、「あっ元に戻そう！」と思った時に戻せないというリスクもあります。意見が分かれるところではあります。

- タブサイズ

```
Editor:Tab Size = 4
```
> タブの幅です。2にしている人もおられるでしょうが、自分は4が見やすいですわ。

- スペースの表示

```
Editor: Render Whitespace = all
```

> allにするとスペースが入っている事が確認できます。全角スペースが混在しているとエラーになります。

- 行折り返し

```
Editor: Word Wrap = off
```

> onにすれば指定した行数で折り返しをしてくれが、不要な場合はoff。
ラズパイで自宅サーバを立てる

Qrunchのサービス終了に伴い転記
---
title: ラズパイで自宅サーバを立てる
tags: 
categories:  raspberrypi LAMP
author: @glowflowplow
status: public
created_at: 2019-05-01 15:27:10 +0900
updated_at: 2019-05-26 16:36:51 +0900
published_at: 2019-05-26 16:36:51 +0900
---
# ラズパイで自宅サーバを立てる
覚え書き
LampならぬRampを構築する

## 環境
* RaspberryPi
 * RaspberryPi 3 Model-B
* メインPC
 * Windows 10

## 目標の環境
* RaspberryPi
 * OS: Raspbian Stretch Lite 4.14
 * サーバーソフト: Apache2

## サーバーを立てるまでにやること
* RaspberryPiにOSのインストール
* SSHの設定
* セキュリティーの設定
* FTPサーバーの導入
* ルーターの設定
* Apacheの導入
* PHPの導入
* MySQLの導入

## OSのインストール
### OSのダウンロード
Noobsは設定が楽らしいが重いので、今回はRaspbianをインストールする
下のURLからRaspbian Stretch Liteをダウンロード
バージョンは最新安定版の4.14
https://www.raspberrypi.org/downloads/raspbian/
### インストール
インストールガイドに従ってインストールする。
https://www.raspberrypi.org/documentation/installation/installing-images/README.md
SDカードに書き込むには専用のソフトを使用する。
https://www.balena.io/etcher/
OSのイメージを書き込んだSDをラズパイに指してコンセントを繋げばラズパイが起動し、インストールが始まる
特にユーザーがなにかすることはなかったと思う。

### セットアップ
こちらを参考に設定した
https://qiita.com/nanbuwks/items/9a1d46c22e898178015c#%E8%A8%AD%E5%AE%9A%E3%81%A8%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB
デフォルトではユーザー`pi`に対してパスが`raspberry`でログインできる。
```
 sudo raspi-config
```
で設定画面を開く。ここからロケール等の設定を行う。
設定内容は参考サイトに従って設定。
カメラの有効化は要らないかもしれない。


### セキュリティの設定
設定後の再起動が完了したらパスワードを設定する。先にパスワードを設定するとキーボードレイアウトの違いで酷い目に遭う。
こちらのサイトを参考に設定
https://qiita.com/mochifuture/items/00ca8cdf74c170e3e6c6
自動ログインに関しては/etc/lightdm/lightdm.confが見つからなかったので設定せず、
/etc/systemd/system/autologin@.serviceのExecStartの行だけコメントアウトした。

## SSHの設定
前項のセットアップでSSHを有効化してあるので、そこに接続する。
メインPCにTeraTermをインストールする
https://ja.osdn.net/projects/ttssh2/
こちらからTera Term 4.102 (日付: 2019-02-28)をダウンロードしインストール
インストールが完了したらTeraTermを起動
ホスト名：raspberrypi
ユーザー：pi
パスフレーズ：raspberry
で接続する。


## FTPサーバーの導入
こちらのサイトを参考にインストールした。
https://yamaryu0508.hatenablog.com/entry/2014/12/02/102648
vsftpdをインストールし、設定をするだけ


## ルーターの設定
こちらのサイトを参考にインストールした。
https://qiita.com/jun6231jp/items/5596ef0c912c7f57ef0a#%E3%83%AB%E3%83%BC%E3%82%BF%E3%81%AE%E8%A8%AD%E5%AE%9A
細かい部分はルータによって変わるが開くポートと繋げるポートを設定する。


## Apacheの導入～MySQLの導入
またまたこちらのサイトを参考に
https://qiita.com/jun6231jp/items/5596ef0c912c7f57ef0a#apache2%E3%81%AE%E7%AB%8B%E3%81%A1%E4%B8%8A%E3%81%92
これもうこの記事書いた人に怒られても仕方なくなってきたぞ

# おわり
ラズパイでLAMP構築をしてみたかったのと、実績を目に見える形で残したくてこの記事を書いたが、
ほとんどが人のサイトの受け売りで自身の知識が全く関与していないので実績と呼ぶには程遠い。

とりあえずLAMP環境が構築できたのでこれの上にアプリを作ってみたいと思う。
そうすれば実績として人に見せられるものとなるだろう。
Robolectric 4.4でデフォルトになった@LooperMode(PAUSED)についてメモ

Robolectricのアップデートについてのメモです :pencil: 

公式の記事
http://robolectric.org/blog/2019/06/04/paused-looper/


RobolectricはUIとテストで同じスレッドを共有していて、以下のようなパターンでテストが失敗します。
理由は`before, after, between`になりpostを即座に同期的に実行するためです。
本当のHandlerであれば、postが後から実行されるため、うまく通るはずです。

http://robolectric.org/blog/2019/06/04/paused-looper/ より引用

```java
List<String> events = new ArrayList<>();
events.add("before");
new Handler(Looper.getMainLooper()).post(() -> events.add("after"));
events.add("between");

assertThat(events).containsExactly("before", "between", "after").inOrder();
```

そこで `@LooperMode(PAUSED)`が追加されました。これはクラスやメソッドにつけます。Robolectric 4.4以降ではこちらがデフォルトになりました。

主に違うところはこちら

* このモードだと自動的に同期的にHandlerにpostした処理が実行はされない。ShadowLooper APIを使って `ShadowLooper.idle()`など、明示的に実行する必要がある。その代わり以下の改善がされた。
* 未実行のタスクでテストが失敗したらユーザーに教えてくれるようになった
* AndroidXのいくつかのAPI(FragmentScenarioなど)では自動的にキューを空にしてくれる
* バックグラウンドルーパーを使っている場合は本当にスレッドで実行される

他にもいくつかの違う点があるようです。
http://robolectric.org/javadoc/4.4/org/robolectric/annotation/LooperMode.Mode.html
セルの１行と１列を同時選択して十字の選択状態にする方法

```vb
'''
'''目標Sheetに以下のCodeを埋め
'''
Private Sub Worksheet_BeforeDoubleClick _
    (ByVal Target As Range, Cancel As Boolean)
    Call RCSelect(Target)
End Sub


'''
'''共通Moduleに以下のCodeを埋めておく
'''
' 有効範囲を定義
Public Const minCol = 1
Public Const maxCol = 41
Public Const minRow = 4
Public Const maxRow = 5000
' 機能 : アクティブセルの行と列を同時選択する
' 引数 : Target アクティブセルなどのRangeオブジェクト
' 戻値 : なし
Sub RCSelect(Target As Range)
    If Target.CountLarge = 1 Then '単一セル選択時のみイベント発生
        Application.EnableEvents = False
        Dim rng_RC As Range
        Set rng_RC = Union(Range(Cells(Target.Row, minCol), Cells(Target.Row, maxCol)), Range(Cells(minRow, Target.Column), Cells(maxRow, Target.Column)))
        rng_RC.Select
        Target.Activate
        SendKeys "{F2}", True'編集をすぐできるようにしたい場合、この行を使う
        Application.EnableEvents = True
    End If
End Sub

```
参考先：https://chicktackgo.com/excel-vba-rcselect/
ハッカソンに出てみたよっていうお話

![IMG_1650 2.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/637043/1eddc578-9757-029a-0b28-8b303e3ee770.jpeg)
初めまして!僕は兵庫の大学に通っている経済学部の3回生です。理系でもなく情報系でもないのですがエンジニアとして就職したいなって考えてます👨‍💻最近は朝の9時から終電頃までプログラミングに没頭しています。というか、エラーなどに溺れてたらそんな時間になってしまってるという感じです(笑)今は京都の実家に帰省しており、久しぶりに時間に余裕があるので先日参加したハッカソンについて振り返ってみようと思います。
#ハッカソンとはなんぞや？？？
「ハッカソン」(hackathon)とは、ソウトウェアのエンジニアリングを指す「ハック」(hack)と「マラソン」(marathon)を組み合わせたアメリカのIT業界発祥の造語です。基本的には、複数のエンジニアがチームとして力を合わせて決められた期間までに制作物を作るというお祭りのようなものです。(今回はチームを組まずに1人で参戦している方もいらっしゃいました)
#オンラインでのハッカソンてどんな感じ？？
このご時世なのでオフラインで集まることは出来ず、slackやzoomを使って行われました。自分は普段からよく使用していたのであまりストレスは感じませんでしたが、初めてslackとかを使う人は違和感を感じるかもしれません😂(ラインがいいよ〜ってなるかもですw)開発を進めていく上でつまづいた時にアドバイスを下さるメンターのような方がいらっしゃるので、分からないことなどがあればslackで質問をすると的確なアドバイスがもらえます🤔しかもめちゃくちゃ返信が早いのでとても助かりました(笑)
#僕たちが作り上げた制作物はこれ！
![スクリーンショット 2020-09-28 20.07.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/637043/456658d9-7c48-04bd-603e-cd624395dc64.png)
僕たちはAWSの表情認識APIを用いて画像の分析を行い笑顔を数値化し、飲食店などで接客をする授業員のスマイルと時給をつなげるプロダクトを開発しました。詳しくは下記URLをご覧ください！
(http://isa-japan.conohawing.com/?page_id=750)
審査員の方が3人いらっしゃり、その方たちの投票にて結果が決まります。今回のハッカソンは25チームほど参加し入選が5チームで最優秀賞が1チームでした。いちよ最優秀賞もらえました👏僕たちはキックオフの時に「絶対に優勝します！」的なことを言ってしまってたので、優勝できなかったら大恥かくところだったのでよかったです(笑)
#賞を取るためのコツ
実はこのハッカソンの前にもまた別のハッカソンに出ておりそこでは何も賞が取れませんでした…ただ、そこで賞を取られた方が本当に親切な方で、ハッカソンの後にzoomでどんな準備をしたのかなどを詳しく教えていただきました😭(仏ですか？ってくらい本当に良い人ですw)ここでは自分的に、受賞を目指す上で大事なことを3点だけ書いてみたいと思います👍

1.審査員の方とたくさん話す
→審査員の方は莫大な知識を持っておられます。1人で悩んでいる時間も大事かもしれませんが質問することで、時間短縮にもなりますし自分が求めていた以上の知識が得られることもあります。そして何より、審査員の方が求めているものを知れるチャンスです(自分の目線を採点基準に少しでも近づけることはかなり重要かと思います)

2.発表の練習に時間をかけまくる
→制作物の質を高めるために時間をかけたい気持ちはとても分かりますが、なるべく早く完成させて発表の練習に時間をかけるべきかと思います。
どんなにいいものを作っても、採点は発表で全て決まるので伝え方が悪いと意味がありません(今回は5分間でした)逆に、制作物がそんなに良くなくても伝え方がうまければ賞をもらえる可能性は高いと思います！

3.ハッカソン経験を増やす(笑)
→正直なところ、初参加の時はどんな発表をすれば審査員の心に刺さるのかが全く分かりませんでした。なのでハッカソンの参加回数を増やし、実際に賞を取られてるチームの特徴を研究し、自分たちのものにしてまた別のハッカソンに出ることで受賞の確率はアップすると思います。
#ハッカソンに参加した感想
![AB27283E-F295-45D1-8A5C-9BBE31EADA39 2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/637043/a413a400-53ca-e361-cbad-3c4e25ef6a8d.jpeg)
思っていた何倍も楽しくて、忙しかったです(笑)また予定が合う時にハッカソンがあれば間違いなく参加すると思います✅
参加することでエンジニア仲間ができたり、新しい考え方に触れることができます！就活生であれば、エンジニア就活を進めていく上でも、チームで何かを作る経験は間違いなく生きると思います💪

初めてのQiita投稿というのもあり、拙い文章ではあるかもしれませんが最後まで目を通していただきありがとうございました🤲
SQLの小ワザ(指定した日付から、指定した日数分の日付を取得する)

# はじめに
ほぼタイトルで完結していますが、「指定した日付から、指定した日数分の日付を取得するSQL」をご紹介します。
やってる事は何てことない & あんまり使いどころないですが、何かの足しになればと。
※ MySQL5.6の環境で実行しています。

# コード
下記のような感じです。
この例では、 `2017-01-01` から、1000日分の日付を取得しています。

```sql
select
  date_format(date_add('2016-12-31', interval numbers.generate_series day), '%Y-%m-%d') as date
from
(
  SELECT 0 generate_series FROM DUAL WHERE (@num:=1-1)*0 UNION ALL
  SELECT @num:=@num+1 FROM `information_schema`.COLUMNS LIMIT 1000
) as numbers
;
```

# 結果
```
"2017-01-01"
"2017-01-02"
"2017-01-03"
"2017-01-04"
"2017-01-05"
"2017-01-06"
"2017-01-07"
"2017-01-08"
"2017-01-09"
"2017-01-10"
"2017-01-11"
"2017-01-12"
"2017-01-13"
"2017-01-14"
.
.
```

# ちょっと解説
下記の部分で、1〜1000までの数字を取得しています。

```SQL
  SELECT 0 generate_series FROM DUAL WHERE (@num:=1-1)*0 UNION ALL
  SELECT @num:=@num+1 FROM `information_schema`.COLUMNS LIMIT 1000
```
それを、 `date_add` で日付に加算しているだけです。

# 最後に
分かってしまえばなんて事はないコードですが、SQLにあまり触れてないエンジニアの方だと、ぱっと見意味不明だと思います。
正直、あんまり使うケースはない気もします。マスタデータ作成したり、データマート作る時に使ったりくらいですかね・・・。
SQL楽しいです。
SpringBoot学習一覧

#POSTの値を表示する、SpringMVCとは、Model-View-Controller作成
https://qiita.com/jwpks313/items/4c97aaa8713625d43c63

#Spring Data JPA、データの取得や保存
https://qiita.com/jwpks313/items/ce09ee55b13ab06d8ecc
#エラーメッセージ表示、エラーメッセージ表示をカスタマイズ
https://qiita.com/jwpks313/items/aac840ca347f4662bf8d
#データのCRUD操作、locコンテナを確認
https://qiita.com/jwpks313/items/0daa1f87a2e1dd7b0b75
#AOPとは、SpringAOPを試す、ログイン画面を作成する
https://qiita.com/jwpks313/items/7a495acc54d9afba1d55
#カスタムしたログインページを表示1-1
https://qiita.com/jwpks313/items/b6da0411c16e21e30ad8
#カスタムしたログインページを表示1-2、DBのユーザでログインする
https://qiita.com/jwpks313/items/9226cf3d7c565e24d353
FetchでExcelファイルがダウンロードできるページに条件をPOSTしてブラウザダウンロードする

#やりたいこと
タイトル通りなんですが、いろいろ調べてみても直接ファイルが落ちてこなくて試行錯誤してたどり着いたやつです。

##少しだけ解説
headersとしてheaderの内容を記載するのですが、AcceptにExcelであること、responseTypeにblob形式であることが重要なようです。
またfetchで返ってきた値をblob()で処理するとファイル形式(バイナリ形式)として扱われるので無理くりリンク作ってクリックさせています。
https://developer.mozilla.org/ja/docs/Web/API/Fetch_API/Using_Fetch
https://developer.mozilla.org/ja/docs/Web/API/Body/blob

```javascript:example.js

            var filename = 'excelfile';
            var obj = {
                fname: filename,
                format: 'XLSX'
                };
            var method = "POST";
            var body = Object.keys(obj).map((key)=>key+"="+encodeURIComponent(obj[key])).join("&");
            var headers = {
              'Accept': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
              'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8',
              'responseType' : "blob",
            };
            fetch("アクセスするURL", {method, headers, body})
            .then((res)=> res.blob())
            .then(blob => {
                let anchor = document.createElement("a");
                anchor.href = window.URL.createObjectURL(blob);
                anchor.download = filename+".xlsx";
                anchor.click();})
            .then(console.log)
            .catch(console.error);

```


##参考にさせていただきました
[JavaScriptでファイルダウンロード](https://qiita.com/4245Ryomt/items/7dae218db7df66bcfdd0)
[fetch API でも POST したい！](https://qiita.com/legokichi/items/801e88462eb5c84af97d)

##Yellowfinで使う(続き)
[YellowfinのAPIとwebserviceを使ってダッシュボードのレポートを全てExcelでダウンロードする](https://qiita.com/celery/items/83c5cede3e0555e9bb42)
「オブジェクト指向でなぜつくるのか 第2版」感想

[オブジェクト指向でなぜつくるのか 第2版](https://www.amazon.co.jp/%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E6%8C%87%E5%90%91%E3%81%A7%E3%81%AA%E3%81%9C%E3%81%A4%E3%81%8F%E3%82%8B%E3%81%AE%E3%81%8B-%E7%AC%AC2%E7%89%88-%E5%B9%B3%E6%BE%A4-%E7%AB%A0/dp/4822284654)

評判が良さそうだったので読んでみましたので、感想等記載してみます。

#オブジェクト指向でつくる理由は？

この本の題名である、「オブジェクト指向でなぜつくるのか？」という疑問に対する筆者の回答は、
冒頭に書いてあります。

__ソフトウェアを楽に作りたいから__

この本の構成としては、オブジェクト指向でつくると、なぜ楽になるのか、ということが
色々と書いてあります。

#よくある「動物」や「乗り物」から現実的な視点へ

この本では、「動物」や「乗り物」の例や、
オブジェクト指向は、現実の世界をそのままソフトウェアに表現する
という、入門本に書いてありそうな内容を否定し、
もっと現実的なソフトウェア開発の視点でオブジェクト指向をとらえるように導いています。

#プログラミング言語の歴史

オブジェクト指向にたどり着くまでのプログラミング言語の歴史として、
機械語から構造化言語までの歴史、そして構造化言語で残された問題を解決するために
オブジェクト指向が生まれてきたという流れで、オブジェクト指向が登場した理由を説明しています。

つまり、オブジェクト指向は今までのプログラミング言語の延長線上にあり、
突然変異的に表れたものではない、ということです。

#オブジェクト指向=手段

この本のまとめとして記載されている通り、オブジェクト指向は目的ではなく手段です。

オブジェクト指向を勉強した人が、良い感じに設計、コーディングを行ったら、
品質が良いものが出来上がり、トータルで楽ができる、
というのがオブジェクト指向でつくる動機付けとなるはずです。

#対象読者

入門本を理解して、次に読むのに良いと思います。

入門本に記載されている、
「動物」や「乗り物」の例や、
オブジェクト指向は、現実の世界を云々という記載を読んで
「オブジェクト指向の概念は理解したけど、それがどう実装に役に立つの？」
という、当然の疑問をいただいた後に読むと、少し現実の開発に近づけるのではないかと思います。

#感想

全体としてオブジェクト指向の周辺を網羅的に記載しているため、
各記載はさほど深くなく、物足りなさを感じました。
(これは、僕が対象読者から外れていると思われるため仕方がないですが)
入社一年目の新人に読ませるのには丁度良いかな、という印象です。

オブジェクト指向を導入するメリットについては、もう少し深堀りして欲しかったです。

* 工数について、設計にかける工数と、コーディング、保守にかかる工数のバランス
* インタフェースによる再利用に関する具体例

というあたりの内容があるとより良いように思います。
簡単にWebサーバーをローカルで用意する

#Web Server for Chromeを使う

ローカル環境でJavaScriptの動作を確認したいとき、``file:///C:/...``みたいな感じだと動作が確認できない事はよくあります。
そんな時、Chromeのアドオンである「Web Server for Chrome」を使用することで、簡単にサーバーを準備する事ができます。

##インストール
[ここ](https://chrome.google.com/webstore/detail/web-server-for-chrome/ofhbbkphhbklhfoeikjpcbhemlocgigb?hl=ja&)にアクセスして、Chromeのアドオンを追加します。
https://chrome.google.com/webstore/detail/web-server-for-chrome/ofhbbkphhbklhfoeikjpcbhemlocgigb?hl=ja&

![image01.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/10793/041bdb39-df0b-1dc6-206a-6866bc86f1c5.png)

##使いかた
インストールしたら、**「CHOOSE FOLDER」**をクリックしてドキュメントルートとなるフォルダを選択します。
http://127.0.0.1:8887 にアクセスして正常に画面が表示されたら成功です。
![image02.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/10793/999a317c-32d0-4b8a-6484-343cab0c9685.png)

「Web Server for Chrome」を使用するとApacheやIISを立ち上げる必要もなくwebサーバーを用意できます。
以上、「Web Server for Chrome」の紹介でした。

#参考サイト
https://webbibouroku.com/Blog/Article/web-server-for-chrome
Mendixを使ってみる

# はじめに

ローコードプラットフォームの１つMendixを使ってみます。MendixはMendix社が提供するローコード開発基盤で、無料で体験することができます。体験といってもすべての機能を使って、アプリケーションをWebで公開することができます。体験の場合、アプリケーションサーバーは90分で停止されますが、リクエストにより再度起動します。

# 準備

アカウントの作成時にメールを使用します。gmailやyahooなどのメールアドレスは使用できません。入力すると会社または学校のメールアドレスを使用してくださいと英語で表示されます。パスワードは英大文字、小文字、数字、記号を含めた8文字以上で設定します。

# 無料体験版

Mendixのホームページは英語ですが、無料で体験する手順は、ビルドシステム社のホームページで公開されています。

[こちら](https://mendix.buildsystem.jp/mendix/mendix_trial/) をご覧ください。

# 次は

アカウントが準備できたら [Mendixで最初のアプリを作る](https://qiita.com/puffy/items/0c96515f88b85309eaae) でアプリを作ってみましょう。
反弹shell升级交互式shell

具体如下，第一步，在哑 shell 中执行：

```
$ python -c 'import pty; pty.spawn("/bin/bash")'
```
键入 Ctrl-Z，回到 VPS 的命令行中；第二步，在 VPS 中执行：

```
$ stty raw -echo
$ fg
```

回到哑 shell 中；第三步，在哑 shell 中键入 Ctrl-l，执行：

```
$ reset
$ export SHELL=bash
$ export TERM=xterm-256color
$ stty rows 54 columns 104
```
【Looker】Exploreで全体に対する割合を表示する

### ①Exploreを開いて、全体に対する割合を計算したいmeasureを1つ以上選択する

### ②下記赤枠の「計算」をクリック

![スクリーンショット 2020-09-28 16.45.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/311026/aa5409f0-75e2-0171-257a-57971330fa5c.png)


### ②入力フィールドに下記計算式を入力

※存在しないmeasureを指定しているためエラーが表示されていますが、①で選択したmeasureを指定すればエラーはでません。

![スクリーンショット 2020-09-28 16.52.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/311026/2d48391a-a53a-b289-f0d8-fd2e910979ff.png)

### ③Default Formattingを「Percent(0)-123,457%」に変更

※Percent(xx)の括弧内の数字が、小数点の表示に連動しています。

### ④「保存 表計算」をクリック
Laravel初期設定

Laravelでプロジェクトを作成していく際の初期設定をやっていきます。
ここではLaravel ,Composerを導入し終えた状態で進めていきます。また、使うPCはMacです。



#1.初期設定(ターミナル)
まず、ターミナルでMAMPのhtdocs内にプロジェクトを作成していきます。

```terminal
$ cd /Applications/MAMP/htdocs
```
移動できたら、下記のコマンドを入力してblogというアプリを作成します。

```
$ composer create-project laravel/laravel --prefer-dist blog
```
最後に<font color=red> Application set key successfully.</font>と表示されれば、
MAMPのhtdocs内にblogというプロジェクトを作成できました。
次に作成したmyblogに移動して、初期設定を行います。

```terminal
$ cd blog
```
移動できたら初期設定を行います。
権限の設定です。Laravelではログファイルはデフォルトでapp/storage/logsディレクトリの下に作成されます。このディレクトリ以下にnginxはapacheユーザでの書き込み権限が必要です
権限に関しては<a href="https://qiita.com/shisama/items/5f4c4fa768642aad9e06">こちら</a>

```terminal
$ chmod -R 777 storage
$ chmod -R 777 bootstrap/cache
```
storageとcacheがこれで権限が一番緩い状態になります。以上でターミナルによる初期設定は終了です。

#2.初期設定（MAMP）
次にMAMPの設定です。localhostに接続した際のトップページを設定していきます。ここは設定してもしなくても大丈夫です。
1. MAMPを開く。
2. Desktopの左上のバーのところのMAMPを押してPreferenceを押す。
3. 真ん中のselectを押して、/Application/MAMP/htdocs/blog/publicを選択。
4. OKをクリック
5. start serverをクリック
6. localhostにアクセス
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592457/a1317504-2e17-4e9c-afa6-096d2684c924.png)
これはLaravelのトップページがpublic配下に存在するためです。localhostに接続した際に以下の画面が表示されれば正しく接続できています。

![image.png](https://i.gyazo.com/cca7fcdce6a8813374ae7ac300112514.png)




#3.DB作成
webブラウザ上のMAMPの中でTOOLSのPHPmyadminを開きます。
![image.png](https://i.gyazo.com/b345b92078b14eaf9a4be2952b4b2bde.png)
1. サイドバーのnewを押して新しくDBを押す。
2. Create Databaseと出てくるので名前のところに**blog**と追加。
3. 右のセレクトボックスを**utf8mb4_unicode_ci**とする。
4. Createボタンを押す。
 左側のサイドバーにblogと追加されれば完了です。

次にご自身のテキストエディターでblogを開いてください。<font color=red>.env.example</font>というファイルが存在するのでひらいてください。<font color=blue>.env</font>ファイルという似たようなファイルも存在しますが、<font color=red>.env.example</font>の方に記載する事でGitで管理できるので複数人で開発をする際にはこちらに記載する方が良いらしいです。間違ってたらすいません。

![image.png] (https://i.gyazo.com/260425cda507345f5b792d923d3352ce.png)
1. 一行目のAPP_NAMEをlocalhostからblogに変更。
2. DB_PORTをご自身のPORT番号に変更。
3. DB_DATABASEをblogに変更。
4. DB_PASSWORDをrootに変更。
5. 15行目にDB_SOCKET=/Applications/MAMP/tmp/mysql/mysql.sockを追加。
(ご自身のPORT番号やパスワードはweb上のMAMPを開いていただいて、少し下にスクロールしていただくと書かれています。)


次に、mysqlのバージョンによっては文字化けする可能性があるのでそれを防ぐためのコードを追加していきます。テキストエディターで、 **app/Providers/AppServerProviders.php**を開きます。以下の様に変更を加えてください。
1. 6行目にuse Illuminate\Support\Facades\Schema;を追加。
2. 27行目にSchema::defaultStringlength(191);を追加。
![image.png](https://i.gyazo.com/a5c54ea4cb1645f126f4dc8ec648fac3.png)

#Timezone
Timezoneの変更をしていきます。
1. config/app.phpに移動
2. 70行目のUTCをAsia/Tokyoに変更
3. 83行目をlocaleを「ja」に変更

![image.png](https://i.gyazo.com/35f79f98b003c649012aeda45d447796.png)


これで初期設定は終了になります。



#終わりに
以上が初期設定でした。次回はLaravelでMVCの作成をしていきます。参考サイトを貼っておきますので是非確認してみてください。

https://www.youtube.com/watch?v=yaitzPzBzuI&t=600s
https://www.ritolab.com/entry/49
https://readouble.com/laravel/7.x/ja/database.html
https://qiita.com/shisama/items/5f4c4fa768642aad9e06
【備忘録】Windows10 102（英語配列）キーボードの場合にIMEのON/OFF（日本語入力）切り替え方法


# はじめに

以前の記事で[『Windows10 102/109キーボードの変更手順』](https://qiita.com/nak435/items/25adbfb17285db7e35fc)を掲載していたが、自身が「102キーボードで日本語入力のON/OFF」に戸惑ったので、今回も設定手順を残しておく。


## 1. IMEの「設定」を開く

タスクバーの右下の「**A**」もしくは「**あ**」のところを右クリックしてメニューを開く。
![k1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/07134e1d-88c9-df88-4d15-b66ed50a768b.png)

ポップアップしたメニューの「**設定**」をクリック。
![k2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/647460b8-fdcd-52d5-833d-b4586fae9173.png)

## 2.「キーとタッチとカスタマイズ」を選択。

「Microsoft IME」画面から「**キーとタッチとカスタマイズ**」をクリック。
![k3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/4bbbc873-c397-7181-8355-496f61fe7638.png)


## 3.「キーの割り当て」をONにする

「キーとタッチとカスタマイズ」画面にて「キーの割り当て」にある、「**各キーに好みの機能を割り当てる**」をクリックして**オン**にする。
![k4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/cdafa39a-ac1a-4566-13e1-0f1bee5a21ec.png)

**オン**にすると、その下にある4つのキーが割り当て可能となる。しかし、英語配列キーボードの場合は、「無変換キー」と「変換キー」は存在しないはずなので、使用できない。
![k5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/f15f4e28-75d7-fe60-ed94-d98f10041f18.png)


## 4. キーを割り当てる

「Ctrl + Space」か「Shift + Space」のキーにIMEのON/OFFを割り当てる。
![k6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/283293/5359633b-e78d-b3ae-c991-47b7b1822c47.png)


PCの再起動は不要で即時機能するようになる。
「Ctrl + Space」を押す度に**A**/**あ**が交互に切り替わる（トグル式）。

なお、この設定そのものは、英語配列キーボード／日本語配列キーボードに関係なく可能である。

以上