OmniAICreator/Qiita-1.07M huggingface dataset:
Python スタイルガイドとリンター

# はじめに

Pythonのスタイルガイドとリンターのまとめ。

# Style Guide

## Google Python Style Guide

Googleオフィシャルのスタイルガイド。

[Google Python Style Guide](https://github.com/google/styleguide/blob/gh-pages/pyguide.md)

## Style Guide for Python Code

PEP8として知られるPython.orgオフィシャルのスタイルガイド。

- [PEP 8 -- Style Guide for Python Code](https://www.python.org/dev/peps/pep-0008/)
- [pep8-ja](https://pep8-ja.readthedocs.io/ja/latest/)

付随してPythonのAPIドキュメンテーションのガイドもある。

[PEP 257 -- Docstring Conventions](https://www.python.org/dev/peps/pep-0257/)

# Linter

PythonはJavaと違って、Linterの機能がケースバイケースで種類がはっきりと分類できない。Linterの機能を style check機能, bug check機能, format機能に大別して、主要なLinterの機能を表形式でまとめたものが下表である。

| tool name                   | style check | bug check | format |
| --------------------------- | ----------- | --------- | ------ |
| pep8                        | x           |           |        |
| pylint                      | x           | x         |        |
| pyflakes                    |             | x         |        |
| flake8 (≒pyflakes+pep8)     | x           | x         |        |
| autopep8                    | x           |           | x      |
| black                       |             |           | x      |
| yapf (mainteined by Google) |             |           | x      |

参考サイト

- https://blog-ja.sideci.com/entry/python-lint-pickup-5tools
- http://books.agiliq.com/projects/essential-python-tools/en/latest/linters.html

名称に8とつくtoolはPEP8に準拠したstyle checkを行うものである。

# ドキュメンテーションスタイル

Pythonではソースコード上にdocstringと呼ばれる、APIを説明する特別なコメントを書く。これは、JavaのJavaDocやC++のDoxgenと同じようなものだが、規約がゆるく何でもアリな仕様。[Pythonのdocstring（ドキュメンテーション文字列）の書き方](https://note.nkmk.me/python-docstring/) によると3つの異なるスタイルが普及している。

1. sphinx
2. numpy
3. google

おおむね、上から順にタイピング量が多い印象。 googleスタイルがおすすめ。
[Golang]マップのキーを確認する際、2つの変数にまとめて代入すると、真偽値が代入される件

# とりあえずコード
```golang:Go：map内に任意のキーがあるか確認する方法
package main
import "fmt"

func main() {

	m := map[string]int{"maeda":165, "yamada":175, "suzuki":180}

	v, ok := m["maeda"] // 「maeda」というキーを探したい場合。

	fmt.Println(m)  // => map[maeda:165 yamada:175 suzuki:180]
	fmt.Println(v)  // => 165
	fmt.Println(ok) // => true　存在する場合trueが返る
}
```
# 解説
キモになるのは、`v, ok := m["maeda"]`ここですね。

`v`と`ok`という変数を用意し、そこに`m["maeda"]`を代入している…
かと思いきや、`ok`の方には、値ではなくbool値が代入されるんですね。

ちなみに、`ok`という変数名を変えてみても結果は同じでした。

# `v`と`ok`をバラバラにすると、bool値は代入されない
```golang:Go：vとokをバラバラにしてみた
package main
import "fmt"

func main() {

	m := map[string]int{"maeda":165, "yamada":175, "suzuki":180}

	v := m["maeda"]
	ok := m["maeda"]

	fmt.Println(m)  // => map[maeda:165 yamada:175 suzuki:180]
	fmt.Println(v)  // => 165
	fmt.Println(ok) // => 165
}
```
このように、変数`ok`の方にも値が代入されてしまいました。
少し馴染みのない挙動ですが、2つ同時に変数の宣言・代入をしたら、bool値が代入される仕様のようです。
LeetCode / Pascal's Triangle

（[ブログ記事](https://mhiro216.hatenablog.com/entry/2019/08/09/222336)からの転載）

[https://leetcode.com/problems/pascals-triangle/]

Given a non-negative integer numRows, generate the first numRows of Pascal's triangle.
<img width="271" alt="スクリーンショット 2019-08-09 13.52.25.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122973/94c7099a-6075-3ab7-c760-39dad83e8e17.png">
In Pascal's triangle, each number is the sum of the two numbers directly above it.

Example:
<img width="107" alt="スクリーンショット 2019-08-09 13.53.07.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/122973/b1f41120-f7a0-d0f3-7639-a59aa8b6fbe9.png">
パスカルの三角形と言われるものを、数列を重ねていくことで作ります。
各々の数列は、上段の数列の2つの値の和になっているのが特徴です。

#### 解答・解説

##### 解法1
私のsubmitした手法です。
愚直にnumRows段目までの数列を1つ1つ作り、積み上げていきます。

上の段の数列の2つの値を足して新たな数列を計算するとき、
l_pre = [0]+ans[-1]+[0]
のように数列の両端に[0]を追加して、
l_nxt = [l_pre[i]+l_pre[i+1] for i in range(len(l_pre)-1)]
のようにすっきりしたループ処理となるようにしていします。

```python
class Solution:
    def generate(self, numRows: int) -> List[List[int]]:
        ans = []
        if numRows > 0:
            ans.append([1])
            for _ in range(numRows-1):
                l_pre = [0]+ans[-1]+[0]
                l_nxt = [l_pre[i]+l_pre[i+1] for i in range(len(l_pre)-1)]
                ans.append(l_nxt)
        return ans
```

##### 解法2
Discussionの中で、これは良いなと思った解法を紹介します。

pascal = [[1]*(i+1) for i in range(numRows)]
として、はじめに全ての値を1にしてnumRows段目までの三角形を作ってしまってから、正しい値を代入します。

解法1と比べて時間・空間計算量は変わりませんが、公式よりもさらにすっきりした美しい解法だと思います。

```python
class Solution:
    def generate(self, numRows: int) -> List[List[int]]:
        pascal = [[1]*(i+1) for i in range(numRows)]
        for i in range(numRows):
            for j in range(1,i):
                pascal[i][j] = pascal[i-1][j-1] + pascal[i-1][j]
        return pascal
```
Naming Convention Pattern

# Capitalization

## Title case

句の先頭が大文字で、単語区切りが半角スペース。

```java:例
/**
 * Title case.
 */
```

## lowercase

すべて小文字で、単語区切りなし。

```java:例
public string lowercase = "string";
```

## UPPER_CASE

すべて大文字で、単語区切りは`_`。`snake_case`の亜種。

```java:例
public static string UPPER_CASE = "string";
```

## CamelCase

### UpperCamelCase

単語の先頭が大文字で、単語区切りなし。

別名：PascalCase, CapWords

```java:例
public class UpperCamelCase {}
```

### lowerCamelCase

句の先頭が小文字で、各単語の先頭が大文字で、単語区切りなし。

別名：dromedaryCase

```java:例
public void lowerCamelCase(){}
```

## snake_case

単語の先頭が小文字で、単語区切りはアンダースコア`_`。

```python:例
def snake_case():
```

## Kebab-Case

単語の先頭は小文字・大文字問わないが統一させる、単語区切りはアンダースコア`-`。

別名：lisp-case, COBOL-CASE, kebab-case or brochette-case

```powershell:例
Get-Process
```

# Underscore

## \_single_leading_underscore

伝統的に、Pythonではprivate変数を意味する。

```python:例
def _private_method():
    pass
```

## single_trailing_underscore_

## \_\_double_leading_underscore

## \_\_double_leading_and_trailing_underscore\_\_

伝統的に、Python や C言語(gcc)では予約された特殊な変数名を意味し、ユーザは使ってはならない。

```python:例
__init__
__line__
```
[Golang]連想配列やハッシュ的なキー管理で定番の、マップの使い方サンプル

# いきなりサンプル
```golang:Go：mapの宣言と代入を別々に
package main
import "fmt"

func main() {

	m := make(map[string]int)
	m["maeda"] = 165
	m["yamada"] = 175
	m["suzuki"] = 180

	fmt.Println(m) // => map[yamada:175 suzuki:180 maeda:165]
}
```

```golang:Go：mapの宣言と代入を同時に
package main
import "fmt"

func main() {

	m := map[string]int{"maeda":165, "yamada":175, "suzuki":180}

	fmt.Println(m) // => map[maeda:165 yamada:175 suzuki:180]
}
```

# 注意！　v1.11系までは出力順がランダムに
実行していて気づいたのですが、どうやら**実行する度に出力されるmapの順番が違います。**

```golang:Go：実行の度に、mapの出力結果が変わる？
package main
import "fmt"

func main() {

	m := map[string]int{"maeda":165, "yamada":175, "suzuki":180}
	m["oda"] = 190

	fmt.Println(m)
}
```

```console:実行1回目
map[yamada:175 suzuki:180 oda:190 maeda:165]
```

```console:実行例2回目
map[oda:190 maeda:165 yamada:175 suzuki:180]
```

```console:実行例3回目
map[maeda:165 yamada:175 suzuki:180 oda:190]
```

こんな感じです。
基本的に、mapはキーの名前を指定して値を参照する、といった使い方になるかと思うので、それほど大きなトラブルにはならないかと思いますが、なんかもやっとしますね。笑

追記)
なお、コメントでご指摘頂いた通り、v1.12系からは出力が固定順に変更されているようです。
RMSLEのはなし

# このページについて
* 評価指標がRMSLEのコンペに参加したときに思ったことを色々とメモします。
* 概要としては、LightGBMとGridSearchCVとRMSLEの話です。細かい話は下記へ
* どなたの役に立つかはわかりませんが（笑）

https://qiita.com/shnchr/items/22868bea27a3a8bf0977

# そもそも評価関数って
* 予測の精度を評価するための関数ですね。
* 以下に回帰で定番のMAE、RMSEを並べたあと、RMSLEを眺めてみたいと思います。

### 平均絶対誤差(MAE,L1_loss)
* まずは、一番わかり易い絶対誤差。
* 予測と実績の絶対差の平均なのでとても理解しやすい。 

```math
\frac{1}{n} \sum_{i=1}^{n} |Pred_{i} - Act_{i}|
```

### 平均二乗誤差(MSE、RMSE、L2_loss)
* もう一つの定番、RMSE（平均二乗誤差）でしょうか。
* 機械学習ライブラリの回帰関数のデフォルトの評価関数だったりします。
    * RMSEの最小化が、誤差が正規分布の最尤推定と同義である背景からでしょう。（最小二乗法）
* LightGBMの回帰タスクのデフォルトもRMSE（L2_loss）ですね。
    * https://github.com/microsoft/LightGBM/blob/master/docs/Parameters.rst#objective

```math
\sqrt{\frac{1}{n} \sum_{i=1}^{n} (Pred_{i} - Act_{i})^{2}}
```

### 対数平均二乗誤差（RMSLE)
* ある値は10、ある値は10億といった、値のレンジが大きな（対数正規分布に近い）データの学習に利用します。
* 先程のRMSEと見比べると下記のような感じ。
    * 対数（log）を計算してから、予測と実績を引き算。
    * 予測と実績の誤差を幅ではなく比率として表現
    * 対数を取る前に、予測、実績共に＋１
        * 予測または、実績が0の場合、log(0)となり計算できなくなるので、＋１する。

```math
\sqrt{\frac{1}{n} \sum_{i=1}^{n} (log(Pred_{i}+1) - log(Act_{i}+1))^{2}}
```

* RMSEとの差分は数式のこの部分。この部分以外の形は一緒。

```math
log(Pred_{i}+1)
```
```math
log(Act_{i}+1)
```

# LightGBM + GridSearchCV(scikit-learn)
* コンペで定番の組み合わせかもしれませんが、、
* LightGBMは、sklearnのインターフェイスを実装しているので、sklearnのグリッドサーチと併用できます。
    * LGBMClassifier（分類）
    * LGBMRegressor（回帰）
* LightGBMで学習し、最適なパラメータはGridSearchCVで学習する。
* そんなときに、コンペの評価関数が、MAEやRMSEならいいのだが、RMSLEだとちょっと困ったことが起きる。
    * GridSearchCVによるパラメータ探索は、RMSLEをターゲットとして実施可能
    * 一方、LightGBMは、標準ではターゲットにRMSLEを指定できない。（独自関数で実装が必要）

|ターゲットとする評価関数|GridSearchCVでの指定方法|LightGBMでの指定方法|
|:---:|:---:|:---:|
|MAE|scoring=**‘neg_mean_absolute_error’**|eval_metric=**'mae'**|
|RMSE|scoring=**‘neg_mean_squared_error’**|eval_metric=**'rmse'**|
|RMSLE|scoring=**‘neg_mean_squared_log_error’** | **※標準では無し** |

# ではどうするか
* 方法はいくつかある。
    * 方法１
        * GridSearchCVは、**‘neg_mean_squared_log_error’**を指定。
        * LightGBMは、**RMSLE関数**を、自分で実装し指定する。（ちょっと面倒くさそう）
    * 方法２
        * GridSearchCV、LightGBM共に、評価関数は、**RMSE**で統一する。
        * ただし、学習の前後で下記の変換を行う。（これだけ）

``` python
# 学習前にy_trainに、log(y+1)で変換
y_train = np.log(y_train + 1) # np.log1p() でもOK

# グリッドサーチし、学習する。
# ちなみに説明変数（X_train、X_test）は変換不要。

# 最後に、予測結果に対しexp(y)-1で逆変換
pred = np.exp(pred) - 1 # np.expm1() でもOK
```

* RMSEとRMSLEの数式上の差分を、上記変換で埋めてあげれば、GridSearchCV、LightGBM共に同じ評価関数で学習ができる。

# 本当にこれで良いか？
```python
In [1]: import numpy as np
In [2]: input = np.arange(1,10,1)
In [3]: input
Out[3]: array([1, 2, 3, 4, 5, 6, 7, 8, 9])

In [4]: output = np.log(input + 1)
In [5]: output
Out[5]:
array([0.69314718, 1.09861229, 1.38629436, 1.60943791, 1.79175947,
       1.94591015, 2.07944154, 2.19722458, 2.30258509])

In [6]: result = np.exp(output) - 1
In [7]: result
Out[7]: array([1., 2., 3., 4., 5., 6., 7., 8., 9.])
```
* np.log1pで変換したデータが、np.expm1で復元できましたね。
* 大丈夫そう！
【IBM CLOUD】無料枠でインスタンス(PHP)作成するには？

# IBM cloudの無償枠でインスタンスを作成する

### 注意点
1. IBM cloudの無料アカウントは作成済み。
2. Google Chromeで作業実施。

## 1.ダッシュボードから"リソースの作成"を選択。
![NoName_2019-8-9_21-13-20_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/479886/a07c525d-7d3a-860d-c126-235db1179f25.png)

## 2.メニューからCloud Foundry>PHPを選択。
![NoName_2019-8-9_21-17-51_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/479886/ac7422df-2399-7f75-d334-f3f7c6faa8a6.png)

## 3. 以下、各種設定を入力し、作成を選択。
- アプリ名を入力すると、ホスト名、組織は自動入力。(ホスト名は入力制限あり。)
- 価格プランは暫定。(ライトの中なら無料に見えたので、その中の最大値の256MBで設定。)
![NoName_2019-8-9_21-24-26_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/479886/58a5e3a9-cd29-8b02-8b99-b5e4c9d6f9fe.png)
![NoName_2019-8-9_21-24-44_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/479886/60986f54-31b8-02d3-38ea-9f7b85e2c2d1.png)

## 4. インスタンスが作成完了したら、アプリURLにアクセスし、画面が表示されることを確認。
- URLはホスト名+.+ドメイン名で構成。
![NoName_2019-8-9_21-26-53_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/479886/7bddbbf8-7fcb-e584-6cc6-d8bf5f36e922.png)
![NoName_2019-8-9_21-28-11_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/479886/d62e453c-7b8a-b7b9-34a0-ed8949e6b279.png)
IntelliJ IDEA で Java の import 宣言を最適化する (Optimize imports)

## Optimize Imports の実行

IntelliJ IDEA のメニューから Code → Optimize Imports を選択する。

Optimize Imports 実施前:
<img alt="intellij1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139365/459d8b27-c72a-048c-dfc9-081b26eb7dff.png">

Optimize Imports 実施後:
<img alt="intellij2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139365/07324ead-07c4-c01f-73ee-a0374b4cda28.png">

(IntelliJ IDEA 2018.3.3 (Community Edition) で確認)

## 最適化の内容

Optimize Imports を実行することで以下のような最適化が行われる。

- 使用していないクラスの import 文を削除
- import 宣言の順番を適切に並び替える
- アスタリスク「\*」によるオンデマンド型インポート宣言 (type-import-on-demand declaration) をクラス毎の個別のインポート (single-type-import declaration) に展開

[Auto import \- Help \| IntelliJ IDEA](https://www.jetbrains.com/help/idea/creating-and-optimizing-imports.html#optimize-imports)

> The Optimize Imports feature helps you remove unused imports, add missing imports, and organize import statements in the current file or in all files in a directory at once.

## Optimize Imports のショートカットキー

Optimize Imports はショートカットキーでも実行可能。
macOS では control + command + O
Linux と Windows では Ctrl + Alt + O

[IntelliJ IDEA DEFAULT KEYMAP](https://resources.jetbrains.com/storage/products/intellij-idea/docs/IntelliJIDEA_ReferenceCard.pdf)

## Type-Import-on-Demand Declarations の設定

Type-Import-on-Demand Declarations (オンデマンドタイプのインポート宣言) は、アスタリスク「*」を使ってパッケージに属するクラスをすべてインポートする Java の文法。

Optimize Import 機能を使うと、同じパッケージの import 文の数が多いとアスタリスク「\*」でまとめられてしまうことがある。

<img width="643" alt="intellij3.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139365/edf10f86-0ab2-b91d-ad99-a8215faabef7.png">

これは、設定 Preferences → Editor → Code Style → Java → Imports の 「Class count to use import with '\*'」 にて、アスタリスク「\*」でまとめる import 文の下限数を設定することができる。

<img width="845" alt="intellij4.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139365/1acbc77b-bf8b-2e66-f878-7f16d671dfa1.png">

(IntelliJ IDEA 2018.3.3 (Community Edition) で確認)

## 自動で Optimize imports を実行する

設定 Preferences → Editor → General → Auto Import の 「Optimize imports on the fly (for current project)」 にチェックを入れることで、ソースコードを修正した際に自動で Optimize imports が実行される。

<img width="692" alt="スクリーンショット 2019-11-20 5.51.20.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/139365/81c6a6e9-8a77-5f63-49a0-2551b47f1682.png">

(IntelliJ IDEA 2019.2.4 (Community Edition) で確認)
7つのコマンドでvenvを使い倒す

# 本記事の目的
venvをささっと使えるようになるためのコマンドをまとめています。

# 前提
venvのインストール、仮想環境の構築は完了しているものとします。

# 1. venvに入る

` $ source ENV_NAME/bin/activate`

※fish を使っている場合

`$ source ENV_NAME/bin/activate.fish`

# 2. venvから抜ける
`$ deactivate`

# 3. 仮想環境へインストールされているパッケージを一覧表示
`(venv) $ pip list`

# 4. requirements.txt生成用パッケージ一覧表示
`(venv) $ pip freeze`

# 5. 仮想環境内パッケージを全てrequirements.txtへ書き出す
`(venv) $ pip freeze > requirements.txt`

# 6. 仮想環境を初期状態に戻す
`$ python -m venv —clear ENV_NAME`

# 7. 仮想環境を削除する
`$ rm -rf ENV_NAME/`
Laravelをインストールしてみる

2019年8月5日
#動作環境を確認する
LaravelはバージョンごとにPHP拡張がインストールされている必要がある。
素でインストールしたphp7.3で確認すると、必要なものがあまり入っていない結果になった。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137858/33615a1d-d098-f715-67f0-847729406b13.png)
###mbstringをインストールする
本当はインストールコマンド一発で行けるはずだった。

```
# yum install --enablerepo=remi,remi-php73 php-mbstring
```

しかし「libonig.so.5」がないと言われてインストールできない。
以下のサイトを参考に、oniguruma5をインストールした。
https://toaruhetare.net/7931

その後再度インストールコマンドを入れたら、正常にインストール出来た。

###PDO,cbmath,xml,toをインストールする

```
# yum install　--enablerepo=remi,remi-php73 -php-pdo
# yum install --enablerepo=remi,remi-pfp73 php-bcmath
# yum install --enablerepo=remi,remi-pfp73 php-xml
```

一発で入れたらよかったよ。
改めて動作環境を確認する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137858/bf58d34d-d626-3ca2-1286-f9cc2d6c301d.png)
Laravelに必要なExtensionは全部入った。

#Composerをインストールする
yumではインストールできなかったので、自力でダウンロードしてインストールしてみる。
Composer公式サイト：https://getcomposer.org/download/
参考サイト：[CentOS7にComposerをインストールする](https://qiita.com/inakadegaebal/items/d370bcb1627fce2b5cd1)

```
$ php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
```

ちゃんとダウンロードできたか確認。

```
$ php -r "if (hash_file('sha384', 'composer-setup.php') === 'a5c698ffe4b8e849a443b120cd5ba38043260d5c4023dbf93e1558871f1f07f58274fc6f4c93bcfd858c6bd0775cd8d1') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
```

「installer verified」と表示されたら、正しくダウンロードされている。
インストール実行。

```
$ php composer-setup.php
```

インストールが終了したら、composer-setup.phpは不要なので削除する。

```
$ php -r "unlink('composer-setup.php');"
```

どこでもcomposerを使えるようにするため、composer.pharを/usr/local/bin/composerの下に移動する。

```
# mv composer.phar /usr/local/bin/composer
```

composerの確認

```
$ composer
```

上手くインストールされていれば、コマンドオプションとかが表示されます。
composerはrootで使わないことが推奨されているそうです。

#Laravelをインストールする
zip,unzipがない、と怒られるので、zipとunzipをインストールしておく。

```
# yum install -y zip unzip
```

Laravelをインストールする。

```
# composer create-project laravel/laravel laravel
```

laravelを立ち上げる前に、以下の設定を行う。
・VirtualBoxで8000番ポートをポートフォワーディングする
・ホストOS、ゲストOSのファイアーウォールを開ける

laravelをインストールしたディレクトリに移動して（インストールしたときにいたディレクトリの直下にある）、laravelを立ち上げる。

```
# php artisan serve --host 0.0.0.0
```

ホストOSでブラウザを立ち上げ、[ipアドレス]:8000にアクセスすると、laravelのサイトが表示される。

|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137858/82eb644d-5f23-0303-1f44-bfbb4c31f8dd.png)|
|:-:|

落とすときはcntl+zで終了させる。
Daskで使用メモリ容量に制限をかける

pandasで処理しきれないデータを扱う際には、pandasライクにout-of-core処理がかけるDaskがよく利用されます。今回の記事はそんなDaskをサーバ１台の環境やローカルのマシンで動かす際にメモリ使用制限をかけたい、という方向けのお話です。
めちゃくちゃニッチな話かもしれませんね。。。需要ないかも。
（少し拡張すれば分散環境にも適用できるので、そちらに興味のある方にも響くことを期待してます。）

##概要
メモリに使用制限をかけるにはDaskの分散処理モード？(distributed)の`LocalCluster`を利用します。`LocalCluster`はローカルのマシンに擬似的な分散処理環境を作ります。擬似的な分散処理環境のため、`scheduler`と`worker`が必要になります。この時、実際に処理をさばく`worker`のメモリ使用量に上限を設定することで、目的のメモリ使用量に制限をかけることを実現します。

##方法
ドキュメントでは下記で`scheduler`と`worker`が立ち上がるとの記載があります。この時、`Client`の引数`memory_limit`を指定することでメモリーの使用制限がかけられます。

```python
from dask.distributed import Client, LocalCluster
cluster = LocalCluster()
client = Client(cluster, memory_limit='~GB')
```

はずでした。。。これが、環境によってできる、できないがあるようです。下記のようなエラーをはいて、`worker`が起動しない場合があります。詳細については[こちら](https://github.com/dask/distributed/issues/1825)をみていただければと思います。

```
・・・・
AttributeError: 'NoneType' object has no attribute 'terminate'
distributed.utils - ERROR - Worker failed to start
```

この場合、明示的に`scheduler`と`worker`をローカルの環境で起動してあげる必要があります。そして`worker`の起動時に`memory-limit`を記載し使用メモリの上限を定めます。

```
$ dask-scheduler
$ dask-worker localhost:8786  --memory-limit '~GB' # this will have to be in a different terminal
```

そしてスクリプト側からは下記の記載で接続が可能になります。

```python
from dask.distributed import Client
client = Client('localhost:8786')
```

あとは`Dask`のAPIにしたがって書くだけです。簡単ですね。

これで、あなたもDaskにメモリ使用上限をかけられるようになりましたね。１台のサーバのメモリを複数人でとり合う等の状況になってしまったら、是非使ってみてください!

##参考　
https://github.com/dask/distributed/issues/1825

https://distributed.dask.org/en/latest/local-cluster.html

https://docs.dask.org/en/latest/setup/cli.html

https://distributed.dask.org/en/latest/manage-computation.html
CODE FESTIVAL 2014 予選A　D - 壊れた電卓

# CODE FESTIVAL 2014 予選A　D - 壊れた電卓


バグに手間取った。

よーく考えると、近似させる数を桁ごとにみると、元の数字と同じ部分(n桁)+元の数字と違う数字1桁（1~9のいずれか）+残りの桁は全て同じ数字、という構成になることがわかる。

一度違う数字を使うと、それより下の桁でいかなる数字を使おうとも元の数字より大きい or 小さいは既に決定している。したがって、使える数字の中から最も小さい or 大きい数字を使い続けるのが最も元の数に近い数となる。


どこの桁で初めて元の数字と違う数が出現するかで15通り、初めて出現する違う数10通り、残りの桁の全てで使う数で10通り。

これを掛け合わせても計算量にはかなり余裕があるので、これで大丈夫。


```python
n, l = input().split()
l = int(l)
 
 
ans = float('inf')
for i in range(len(n)):
    for j in range(10):
        for k in range(10):
            num = n[:i] + str(j) + str(k) * (len(n) - i -1)
            if num[0] == '0':
                num = num[1:]
            if len(set(num)) <= l and num:
                ans = min(abs(int(n) - int(num)), ans)
                
                
print(ans)
```

エラーに悩まされた。先頭が0だと、int()で0はなくなる。これによって、使った数字の種類をカウントする際食い違いが起こっておかしくなった。そして、先頭の0を削除すると今度は空文字列ができてint変換でおかしくなったり。なんとか解決した。
Lake Formation のアップデート履歴

# 自分のための履歴

抜け漏れあるかもなので参考程度に

## 履歴

* 20170815：Lake Formation GA

https://aws.amazon.com/jp/blogs/aws/aws-lake-formation-now-generally-available/
	

## その他

Lake Formationの使い方まとめ
https://qiita.com/pioho07/items/76554a7ac4252858b450

Glueの使い方まとめ
https://qiita.com/pioho07/items/32f76a16cbf49f9f712f
How to fix error on npm install from git private repo

gitのprivate repoからnpm installしようとして以下のエラーが出たときの解決法メモ

```sh
...
npm ERR! Host key verification failed.
npm ERR! fatal: Could not read from remote repository.
npm ERR!
npm ERR! Please make sure you have the correct access rights
npm ERR! and the repository exists.
npm ERR!
npm ERR! exited with error code: 128
...
```

1. `~/.ssh` に行って `ssh-keygen`
2. github で公開鍵を登録
3. `~/.ssh/config`に以下を記載

```
Host github
  HostName github.com
  IdentityFile ~/.ssh/id_rsa
  User git
```

.4. `ssh -T git@github.com`

```bash
Hi <YOUR_NAME>! You've successfully authenticated, but GitHub does not provide shell access.
```

と表示されたらOK（多分）
私がプログラミングを始めた経緯（３）

お久しぶりです。
ドタバタ色々ありまして、四ヶ月ぶりの投稿になります。
自己紹介も終わってないのに放置。よくない。
というわけでここからサボらずやります・・・

私は昨年の八月になんとなーーく興味本位でプログラミングを学びたいと思ってやり始め、ダラダラと試行錯誤しながらも少数のポートフォリオを（一応）作り、少し飽きて放置してしまい、それを死ぬほど後悔をして再びプログラミングを身につけようと走り始めました。
まずはその経緯・経過を思考の整理をしつつここに書き連ねていきたいと思います。長丁場になりますが、お付き合いください。

※時系列順に書いていきたいと思います。２項目ずつくらい目標

1.プログラミングを始めた理由
2.初めてのプログラミング・Python
3.Code○hip・Gee○salonの2択
4.web系言語勉強開始
5.PHP/Wordpress
6.Unityを知る
7.今後

項目　勉強した月日
1~2 2018/08,09末日
（資格の勉強や舞台の活動のため休止）
3~4 2018/11,12,2019/01
（学校のテスト）
5~ 2019/02,03

ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー

前回（四月）までは
3.Code○hip・Gee○salonの2択
までだったと思うので、
今回で4から7くらいまで手短にまとめていきたいと思います。

web系の技術を学び始めたのが具体的には去年の11月末だったかと思います。
とはいえ、そのころは無知でWordpressできればいいのか！と思ってやっていました。
どうにか教材を12月で終わらせ、簡易的なチャットページとWordpressのテーマを作り終えました。
これが二月くらいのこと。いかにサボっていたかがよくわかります。
この当時はそんなに熱を上げてやっていなかったのかもしれません。

そんな中で二月末にTwitterでとある未経験で転職活動中の方のWordpress講座が無料で閲覧できるとのことで、そこで二つ目のWordpressのテーマを作りました。
そこが初めて自力で作ったテーマになります。

そこで力尽きてしまって、web系の勉強は止まってしまいました。

そんなある日、またもやTwitterでVRchatと、それがUnityやC#を駆使していろんなことができる、それをやっている方々がいることを知ります。


「「「「「「「「これだ」」」」」」」」


直感しました。
その時からUnityとC#をやりたいと思うようになりました。
しかし、Code○hipのUnity講座は初っ端で挫折。
C#講座からやっていきました。
この時四月で、すでに激しく後悔しておりました。
ここから転職活動を考え始めました。

正直Unityの未経験募集を探すも、やはりなかなか求人はありませんでした。
C#についても、近い言語のJavaを扱うSESやSIerが多いことを知りました。
いきなりUnityに何もない状態で触れられる環境につくのは、当たり前ですがかなり難しいことに気づきました。
某氏の言うように良質なオリジナルのポートフォリオを作成しなければならないと痛感しました。
しかし、今の職場環境では到底時間が足りないし、そもそも実務についた方がたとえ別の言語であっても実績を積めば評価されるのではないか、考えました。

ここから、
「一旦未経験でSESやSIerに就職してJavaや場合によってはC#を学びつつ、独学でUnityでサービスを作ってリリースする、などの経験を積むのが最善の戦略である」
と考え、転職活動を始めました。

現在、転職活動を終え、都内のSI兼SESの企業に10月から入社予定です。

今後は、まず入社までにJavaSilverを取り、一ヶ月でGoldをとる。
そのあとに基本情報と応用情報の合格を目指していこうかと思います。
ここをなるべく短期で取りつつ、Unityで独学・・・って典型的な全部ダメになるやつやん。。。
って思うこともありますが、まずは一つずつ取れるようにそこに集中してやっていきたいと思います。

応用情報取るまではUnityは息抜き程度になるかな。。。

ここまで呼んでくださいまして、ありがとうございます。

これからは週三回以上は勉強内容とともにポエムも含めて更新していけたらと思います。

頑張ります。
【Git】特定のブランチの git log を見たい



```shell
git log --first-parent <ブランチ名>
```

良い感じに見やすくする

```shell
git log --first-parent --graph --abbrev-commit --decorate <ブランチ名>
```

`--first-parent`
最初の親コミットのみを追う。
つまり、各コミットの最初の親のみをログに表示し、他のすべての親とその親（先祖）は無視する。


参考:
[Git - git-describe Documentation](https://git-scm.com/docs/git-describe)
[How do I run git log to see changes only for a specific branch?](https://stackoverflow.com/questions/4649356/how-do-i-run-git-log-to-see-changes-only-for-a-specific-branch)
Nuxt.js(v2.8.x)のビルドを１行で爆速化。

ビルドを爆速化したければ、nuxt.config.jsに以下１行を追加。

```nuxt.config.js
module.exports = {
  ...
  build: {
    hardSource: true, // ←これ
    ...
  }
}
```

注意として、[ドキュメント](https://ja.nuxtjs.org/api/configuration-build/#hardsource)に記載ありますが、実験的機能です。修正反映漏れがないかエラー出ていないかなど、自身でちゃんとチェックすること。

少し不安があるとはいえ、かなり爆速になるので`hardSource: true`がないと生きていけない体にすぐになる。

すごいぞNuxt!
Adaboost（アダブースト）の詳しい流れ

Adaboostは、ある学習器から新しい学習器を繰り返し改良しながら作っていき、それら全ての学習器から多数決で判定するアルゴリズムです。
各学習器は「弱学習器」と呼びます。弱学習機はランダムな判定よりも高い精度をもつものとします。つまり正解率は$\frac{1}{2}$よりも大きいものとします。
#仮定
・（入力データ）Ｎ個とし、i番目のデータを$x_i$とする。
・（教師データ）$i$番目データ$x_i$に対応する教師データを$y_i$として、$y_i$は1か-1のどちらかをとるとする。
・（学習結果）弱学習器をＴ回作ると設定する。t回目（t=1～T）の弱学習器でデータ$x_i$に対する予想結果を$f^{t}(x_i)$と表し、1か-1のみをとるとする。
・（弱学習器での重み）t回目の弱学習器で算出されたi番目のデータの重みを$w_i(t)$とする。

#アルゴリズム
１．（初期化）１つめの弱学習器の重みは均等とします。つまり$w_i(1)=\frac{1}{N}$です。
以下２～５までを$Ｔ$回繰り返す

　　　　　　　　　-ループ開始-

２．（学習）$ε(t)=\sum_{i=1}^{N}w_i(t)[f^t(x_i)≠y_i]$が最小になる弱学習器$f^{t}$を作ります。
ここで$[f^t(x_i)≠y_i]$は$f^t(x_i)$と$y_i$が一致しないときに$1$、一致するときに$0$をとるものとします。
この式から$ε(t)$は重み$w(t)$による弱学習器の誤分類率を表しています。
特にループ1回目のとき、つまり$ε(1)$は予測を間違えた割合となります。

３．（誤分類率の判定）もし誤分類率$ε(t)$が$0.5$を超えたらループから抜ける。$0.5$を超えると$α(t)$がマイナスになり、下記５の部分が機能しなくなるためです。

４．（信頼度の計算）$α(t)=\frac{1}{2}\ln\frac{1-ε(t)}{ε(t)}$を計算する。$ε(t)$が小さくなると$α(t)$が増えるので、$α(t)$は弱学習器の信頼度を意味します。
※なぜ$\frac{1}{2}$をつけるのかは厳密な計算で出てくるのでここでは割愛します。特に気にしなくて大丈夫です。

上記３と４により、$α(t)>0$となることに注意。

５．（次の弱学習器の重みを更新）$w_i(t+1)=w_i(t)\exp{(-α(t)f^{t}(x_i)y_i)}$
$α(t)>0$、$w_i(t)$の更新の仕方から$w_i(t)>0$となることに注意すると、
・$f^t(x_i)$の予測が外れたときには$w_i(t+1)=w_i(t)×（１より大きい数値）$となり重みを増やしています。一方で$f^t(x_i)$の予測が当たったときには
・$w_i(t+1)=w_i(t)×（１より小さい数値）$となり重みを減らしています。
$x_i$で予測が外れたとする→データの重み$w_i(t)$が大きくなる→次の弱学習器を作る時に、誤分類率$ε(t)$を小さくするためには優先して$x_i$を正解させなければならなくなる。これで$x_i$が次正解しやすくなるように学習させているということです。

６．（重みの正規化）$w_i(t+1)⇐\frac{w_i(t+1)}{\sum_{i=1}^{N}w_i(t+1)}$
これで重みの和$\sum_{i=1}^{N}w_i(t+1)$を$1$に合わせます。誤分類率を最小化するにあたり、$w_i(t)$が相対的に他の$w_i$たちと比べて大きいか小さいかが重要だからです。

　　　　　　　　　-ループ終了-

７．（多数決）最終予測$H(x_i)=sign(\sum_{t=1}^{T}α(t)f^{t}(x_i))$
弱学習器での予想結果である$f(x_i)$に、信頼度$α(t)$で重み付けた加重平均が正となれば最終予測$H(x_i)$は$1$となり、負であれば$-1$となります。信頼度の高い弱学習器の予測結果が最終結果に反映しやすいようになっています。単純な多数決ではなく、信頼度に応じた多数決といえます。

参考・引用
http://www.iip.ist.i.kyoto-u.ac.jp/member/keisuke/resources/11adaboost.pdf
Azure Web AppsでSpringBootアプリケーションを動かす最小構成

# やりたいこと

ちょっとお試しでAzure Web AppsにSpringBoot製のWebアプリをデプロイしたいと思ったのですが、公式チュートリアルを眺めていたら「まずMavenプラグインを構成します」と言われて「そうじゃない」ってなったので、開発環境に依存しないJavaアプリの最小構成についてまとめてみたいと思います。

[(参考)Spring Boot JAR ファイルの Web アプリを Linux 用の Azure App Service にデプロイする](https://docs.microsoft.com/ja-jp/java/azure/spring-framework/deploy-spring-boot-java-app-with-maven-plugin?view=azure-java-stable)

2019年8月現在、アプリのデプロイ方法は大きく以下の3種類のようです。

- リポジトリと連携しビルドパイプラインを組む
- コンテナをコンテナレジストリから取ってきて起動する
- FTPアップロード

以前はOneDrive経由でのデプロイなどもあったような感じですがほぼなくなっています。

![deployment.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/204890/a3838cd9-d883-a5f0-4d82-8e413cb780c7.png)

FTPも基本的には推奨されていないようですので、事実上コンテナ起動かビルドパイプラインかの2択という趨勢です。

ビルドに関してはAzure Pipelinesを利用するかKuduでビルドするかのどちらかが基本という感じでしょうか。
ACRが使える環境であればコンテナ化してACR経由でWebAppsを作るのが恐らく最も簡単な構成方法です。
どちらも詳しい記事が色々ありますので詳細については省略します。

ただせっかくですので今回の検証に利用したDockerfileだけ参考に置いておきます。

```
FROM azul/zulu-openjdk-alpine
VOLUME /tmp
RUN mkdir /app
WORKDIR /app
ENV JAVA_OPTS="-Duser.timezone=Asia/Tokyo"
COPY build/libs/SampleApp.jar /app/SampleApp.jar
ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app/SampleApp.jar --server.port=80" ]
```

alpineベースのOSにzuluがインストールされたイメージが公式から提供されていますので、jarをコピーしてENTRYPOINTを定義するだけ。
後はこれをACRに登録してWebApps側でPULLするように設定すれば終了です。
簡単ですね。

この記事の残りでは、無料範囲で最速で試したい時用にレガシーなFTPで構成する方法についてまとめます。

# Web Appsリソースの作成

Javaアプリを構成します。

[公開]で[コード]を選択、
ランタイムスタックでJava SEを選択します。
オペレーティングシステムは現在のところLinuxのみのサポートのようです。

![webapps-create.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/204890/0e4c3710-c732-6ac3-3701-ef66b86b1f60.png)

# デプロイ

## FTPユーザの作成

先程も貼り付けたポータル画面の[デプロイセンター]からFTPを選択し、[ダッシュボード]を押します。
そうすると、FTPサーバでの接続情報が表示されますので、各種情報をコピーしてFTP接続します。

![ftp.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/204890/7a945c50-ba47-7d79-bc9c-fdc9cf78fee2.png)

## ファイルアップロード

FTPで実行可能jarファイルをアップロードします。
ポータルに表示された接続情報をそのまま利用するとデフォルトでは `/site/wwwroot/`がカレントディレクトリになります。
アップロード先はそのままでOK。

![deploy.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/204890/a9fc67c7-5c82-9e4f-f04a-4e2c3a12357f.png)

# 起動構成

ポータルの
[構成]メニュー → [全般設定]
から設定します。

![configure.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/204890/cf48f9d9-8b63-404a-df6e-fdecf2b72d49.png)

- スタック: (今回は)Java8
- メジャーバージョン: Java SE
- マイナーバージョン: Java SE
- スタートアップコマンド: `java -jar /home/site/wwwroot/SampleApp.jar --server.port=80`

パスを /home/から始めてフルパスで指定しています。
FTPサーバのRootとは若干ズレているところがハマりポイント。

環境変数は
[構成]メニュー → [アプリケーション設定]
で設定しておくとそのまま渡してくれます。

この状態で[保存]を実行すると設定が保存され、WebAppsに反映されます。
起動するまでしばらく待ってアクセスすると動作が確認できます。

# まとめ

終わってみると本当に大したことがない感じですが、「AzureWebAppsでSpringBootを動かす」というキーワードから入ると、パイプラインを組んでビルドをするのが標準だみたいな情報が意外と見つからなかったので、自分なりに整理するのに苦戦した気がします。
次はAzure Reposと連携したAzure Pipelinesによるビルドを試してみたいですね。
C++ Builder 10.2 Tokyo > TMemoryStream > [ilink32 エラー] Error: 未解決の外部シンボル 'int __fastcall System::Classes::TStream::ReadData<char[1000]>(char[1000]&, int)' が XXX.OBJ から参照されています > IDEのバージョン違いで引数の型が違うようになった

```txt:動作環境
RAD Studio 10.2 Tokyo Update 3 
Windows 10 v1903 
```

### Error

- [2017-02-14 C++ Builder XE4 / Socket > ReceiveBuf()では0x00を途中に含めた指定長さの文字列を受信する / ReadBytes()では0x00までの長さの文字列だけを受信する > ReadChar()試用 / ReadString() + memcpy()使用 > ReadStream()使用](https://qiita.com/7of9/items/9fa80d146d3fab63a71b)

上記の実装において「ReadStream()使用」の実装を10.2 Tokyoで試そうとした。

```cpp
int len=1000;
```

下記のエラーが出た。

> [ilink32 エラー] Error: 未解決の外部シンボル 'int __fastcall System::Classes::TStream::ReadData<char[1000]>(char[1000]&, int)' が XXX.OBJ から参照されています

### 対処

http://docwiki.embarcadero.com/Libraries/Rio/en/System.Classes.TStream.ReadData

```cpp
NativeInt __fastcall ReadData(char &Buffer, NativeInt Count)/* overload */;
```

第２引数はint型ではなくNativeInt 型。

`len`の値を引数として渡す時にNativeInt型にキャストするとエラーは出なくなった。


## APIの変更 (intからNativeIntへ) > XE4から10.2 Tokyoへの移植時の落とし穴

XE4:
http://docwiki.embarcadero.com/Libraries/XE4/en/System.Classes.TStream.ReadData

> `int __fastcall ReadData(System::WideChar &Buffer, int Count)/* overload */;`

Tokyo:
http://docwiki.embarcadero.com/Libraries/Tokyo/en/System.Classes.TStream.ReadData

> `NativeInt __fastcall ReadData(System::WideChar &Buffer, NativeInt Count)/* overload */;`
javascriptのArrayにはshiftやunshiftがあるけれど

# JavaScriptのArrayにはshiftやunshiftがあるけれど
これらを実装しているということは内部実装は双方向連結リストなのか？
と試してみたところ、どうやらそんなことはなさそう。

## 実験内容
以下のようなコードで雑に時間を測る

``` javascript
var i = 0;
const unshift = [];
var start = new Date();
while(i < 100000){
    i++;
    unshift.unshift(i);
}
var end = new Date();
console.log('unshift' +  (end.getTime() - start.getTime()));

i = 0;
const push = [];
start = new Date();
while(i < 100000){
    i++;
    push.push(i);
}
end = new Date();
console.log('push' +  (end.getTime() - start.getTime()));
```

実装が双方向連結リストならば、unshiftもpushも計算量O(1)なので、実行時間は変わらないはず。
逆に普通のリストで実装されていると、unshiftの方のみ計算量O(n)になるので大きな時間差が出るはず。

## 実験結果
とりあえず手元にあったjavascript実行環境で。

```
//node
unshift1298
push24

//chrome
unshift1268
push6

//edge
 unshift1352
 push31

```
流石に有意な差と言えそう。

## 結論
javascriptの配列にはshiftやunshiftが組み込み関数として実装されているが、
大量のデータが入っている配列に対して実行するのは危険。
#GoogleChrome の Developer Tool でリダイレクト前のネットワークのログを確認する ( Network > Preserve log  )

#Check the network log before redirection with GoogleChrome Developer Tool (Network> Preserve log)


Network > Preserve log をオンにすれば良いらしい

![image](https://user-images.githubusercontent.com/13635059/62764826-c0f53900-bac9-11e9-967f-78c2ab031e60.png)



# Original by Github issue

https://github.com/YumaInaura/YumaInaura/issues/2272








<!-- Update From Qiita API -->

# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ





# Twitter


https://twitter.com/YumaInaura


<!-- Update From Qiita API -->
HTML <div>組みからの脱却　〜ファーストステップ〜

「まずはdivタグどんどん使っていいからhtml作ってみよう」

今の会社に入った時、DOMってなんぞや？ぐらいの知識しかなかったので、
とりあえず仕事ができるように、そう言われて何の違和感もなく、DIV組みしてきました。

webシステムってSEO一切関係ないから、崩れなければそれでよし。
そこがいちばんのポイントだから、DOMの構造や、
そのほかのタグなんてものは、勉強しなかったわけですよ。

`<img>`タグはbackgroundで代用できるし、
`<list>`、`<dt>`とかも使わなくても`<div>`だけで組めちゃう。
流石に`<table>`とかは使っちゃいますけど。

でもでもでも。

なんかちょっと最近、divでhtml組んでることが恥ずかしくなってきました。
webデザインとかフロントかじってます。って言っときながら。
div組みかよ。って。


そこで「脱div組み」を目指すことにしました！
いろんなサイト見てみたけど、当面はとりあえず以下を意識。

wraper系の、枠組みとかレイアウトに関わるものは`<div>`でOK。
ヘッダーは`<header>`
メニューは`<nav>`
コンテンツ（内容）部分は`<main>`
フッターは`<footer>`

タイトルは`<h1>`〜`<h5>`
テキストは`<p>`
イメージは`<img>`、だけど場合によってはcssのbackgroundでいい。

表は`<table>`
リストは`<ul>`系

とりあえずこんな感じのマークアップから始めてみる。
<section>とか<figure>とか興味あるものは、
その次のステップってことで。

これも意識した方がいいっていうのがあれば、
ぜひコメントください。
学生インターンがAIスタートアップで急成長するために重要な5つのポイント

# はじめに
[Lightblue Technology](https://www.lightblue-tech.com/)代表の園田です。
Lightblue Technologyでは、動作解析を用いたソリューションをものづくりの現場に対し提供したり、情報抽出に特化した自然言語処理を行っています。

Lightblueでは多くのインターン生が活躍しており、その中からジョインしてくれるメンバーも出てきています。バックグラウンドは情報系が多いですが、航空工学や医学、物理など様々なメンバーが開発インターンとして在籍しています。

インターンとして働いてもらっている方はみんな超優秀ですが、その中でも飛び抜けた成長ができているインターンがいるので、全員がそうなるように日々、観察し、仕組み化を進めています。そのポイントを共有してみます。

# 採用される前
インターンに参加するには、まず、採用されなければなりません。
Lightblueではありがたいことに優秀な学生さんに選んでもらえていて、毎日4名ほどの応募があり、その中からきになる人と毎週、カジュアル面談ランチをやってます。（詳細は[wantedlyの会社ページ](https://www.wantedly.com/companies/lightblue-tech)にて）
そこで連絡する時のポイントとしては以下です。

- 写真が本人
- スキルが明確
- 採用側の気持ちがわかっている（新卒採用直結なのか、人手が欲しいのか、優秀な人と出会いたいだけかなど）

また、会った後に採用するかは、社員もインターンも以下の同一の基準で判断しています。

- 一緒に働きたいか（僕以外の社員やインターンに最低1人以上会ってもらっています。）
- プログラミングのスキル
- 算数のスキル

算数は、つるかめ算のようなものを受けてもらっています。これは、プログラミングやデータ分析には数理的な才能が関係することに加え、問題を解く際の反応で会社の雰囲気へのマッチ度も見ています。


# 参加前
採用までにプログラミングについては未経験でもいいのですが、インターンに参加するまでにどこまで勉強してくればいいかなどを聞きましょう。
インターンはプログラミングスクールではないので、完全に受け身だと辛いのと、自分の成長に繋がりません。

また、採用前か参加前には会社のブログを読むのをお勧めします。会社の雰囲気がわかりますし、技術的な前提等もわかります。

# インターン参加中のコミュニケーション
会社によって、メンターとのコミュニケーション方法も異なります。Lightblueではチャットでの質問を中心に、直接話しかける、backlogの課題を立てるを併用しています。それぞれ、重要度や切迫度によって使い分けています。
聞かないと全く作業が進まない場合は、チャットや直接話しかけてもらい、進捗報告やコードの一部のアイデアが欲しい等であれば、backlogです。

わからない状態で1人で悩んで何時間も過ごすのは、時間の無駄ですが、メンターが忙しそうな時に声をかけるのは気がひけると思います。メンターと話し合い、どういった時はどのようなコミュニケーションを取るのがいいのか確認することをお勧めします。

また、インターン生は何をやりたいかを伝え、自分に何が求められているかを把握しましょう。出社頻度や技術によって頼める内容は変わります。他のインターンがやっていて、自分もやりたいことがあれば、メンターに聞いてみましょう。

そうすると、「出社頻度を増やす」であったり、「技術的にここまでできるようになったら」といった具体的な条件を教えてもらえるはずです。そうすることで、メンターとインターン生の良好な関係と成長が達成できるはずです。
基本は技術があって、よくオフィスに来るインターンに、楽しくて重要な仕事を頼みたいはずです。

# 続けること
継続は力なりです。
Lightblueのインターンも、一番長くいるインターンが一番優秀です。
博士課程や医学部生のインターンもいますが、学部生の彼が一番です。
[wantedly 紹介記事](https://www.wantedly.com/companies/lightblue-tech/post_articles/170724)

メンターの立場からは、インターンが長く続けてくれるとスキルアップして、戦力として見るようになります。そうすると待遇もUPしたくなりますし、重要な仕事も任せられるようになります。

様々な会社でのインターンにより経験を積むことも有用ですが、
1社で集中してインターンすることで、学生ではなかなか経験できないような仕事も任せられるようになります。
これは採用側のポジショントークになってしまうかもしれませんが、普通の新卒でも「最低3年」と言いますし、サークルも3, 4年やるとしたら、インターンもそれくらいやるのも楽しいと思います。

# 開発以外の経験
Lightblueのインターン生は外資金融や外資戦略コンサル・ITコンサルに就職する人も多いです。
僕としては、彼ら全員がジョインしてくれるような会社にしなければと思っていますが、本人の希望があれば様々な機会を提供するようにしています。
例えば、就活生であれば、取引先の大企業のインターン担当者への紹介や、
起業に興味があるインターン生には営業への同行、経営会議への参加などです。
小さい会社だとこのような様々な経験ができますが、誰にでも経験させられるものでもないので、積極的に社員とコミュニケーションをとり、コミットすることで自分の成長につなげられるはずです。


# インターンを探している・転職活動中の方へ
僕がpythonを始めたのは2年半前です。僕の周辺の起業している東大生も経験年数としてはそのくらいの人も多いです。
また、物体の認識率を競うILSVRCでディープラーニングが注目されだしたのも6年ほど前で、グーグルトレンドを見ても、社会実装が始まったばかりの技術であることは間違いないです。
<img width="1121" alt="グーグルトレンド.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/370065/355ab3fc-d4c5-17a3-f64c-81403efd2a84.png">
つまり、まだまだキャッチアップできるということです。
僕たちと働きたいと思ったら、まずは焼肉ランチにでも行きましょう。ご応募お待ちしております。
[wantedlyの会社ページ](https://www.wantedly.com/companies/lightblue-tech)
pythonでグラフデータ作成、グラフ表示、CSVファイル作成

```python

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd

# np.linspaceは、線形に等間隔な数列を生成する関数
x = np.linspace(1,10,10)

# np.random.randn()は、平均0、分散1（標準偏差1）の正規分布（標準正規分布）に従う乱数を返す。
y = x + np.random.randn(10)

# データフレーム（二次元配列）を作成する
df = pd.DataFrame([x,y])

# CSV ファイル (employee.csv) として出力
df.to_csv("employee.csv")

# プロットする
plt.plot(x, y, label="test")

# 凡例を表示
plt.legend()

# プロット表示
plt.show()

```
【SprintBoot】org.springframework.jdbc.core.namedparamに定義された3種類のSqlParameterSourceの使い方

`SimpleJdbcInsert`や`NamedParameterJdbcTemplate`などにパラメータを渡す際に用いる`SqlParameterSource`ですが、このインターフェースと同じパッケージ（`org.springframework.jdbc.core.namedparam`）には以下3種類の実装クラスが存在しています。

1. `MapSqlParameterSource`
2. `BeanPropertySqlParameterSource`
3. `EmptySqlParameterSource`

この記事ではこの3種類の`SqlParameterSource`の使い方について書きます。

# MapSqlParameterSource
マップ形式でパラメータを登録していく`SqlParameterSource`です。
一番汎用的なものですが、場合によっては後述する`BeanPropertySqlParameterSource`を使った方が省力化できます。

自分は主に引数をマップしていくような場面で使っています。

```sql:クエリ文字列
SELECT *
FROM hoge_table
WHERE hoge_id = :hogeId
  AND hoge_status = :hogeStatus;
```

```java:クエリ実行（HogeDtoの単体取得処理）
// 初期化は省略
String queryString;
NamedParameterJdbcTemplate jdbc;
BeanPropertyRowMapper<HogeDto> rowMapper;

public HogeDto selectHoge(Integer hogeId, String hogeStatus) {
  MapSqlParameterSource param = new MapSqlParameterSource("hogeId", hogeId)
      .addValue("hogeStatus", hogeStatus);

  return jdbc.queryForObject(queryString, param, rowMapper);
}
```

# BeanPropertySqlParameterSource
オブジェクトを入れるとパラメータとしてよしなに扱ってくれる`SqlParameterSource`です。

自分は主にオブジェクトのフィールドの殆どでプリペアドステートメントを埋めたり、`SimpleJdbcInsert`を使うような場合に使います。

```sql:クエリ文字列
UPDATE hoge_sub_value
SET hoge_value = :hogeValue
WHERE hoge_id = :hogeId
  AND hoge_status = :hogeStatus
```

```java:クエリ実行（hoge_sub_valueの複数更新）
// 初期化は省略
String queryString;
NamedParameterJdbcTemplate jdbc;

public void updateHogeSubValues(List<HogeSubValue> subValues) {
  BeanPropertySqlParameterSource[] params = subValues.stream()
      .map(BeanPropertySqlParameterSource::new)
      .toArray(SqlParameterSource[]::new);

  jdbc.batchUpdate(queryString, params);
}
```

# EmptySqlParameterSource
最後は、パラメータを使わないことを示す`EmptySqlParameterSource`です。

`NamedParameterJdbcTemplate`には`SqlParameterSource`の有無で別々のインターフェースが定義されていますが（e.g. `<T> T query(String sql, SqlParameterSource paramSource, ResultSetExtractor<T> rse)`と`<T> T query(String sql, ResultSetExtractor<T> rse)`）、以下の通り、内部的にはパラメータ有りの実装に`EmptySqlParameterSource`を渡すという形で実装されています。

使う場面はあまり無いと思います。

```java:NamedParameterJdbcTemplate.java（167〜187行目辺り）の実装
@Override
@Nullable
public <T> T query(
    String sql, SqlParameterSource paramSource, ResultSetExtractor<T> rse
) throws DataAccessException {
    return getJdbcOperations().query(getPreparedStatementCreator(sql, paramSource), rse);
}

@Override
@Nullable
public <T> T query(
    String sql, ResultSetExtractor<T> rse
) throws DataAccessException {
    return query(sql, EmptySqlParameterSource.INSTANCE, rse);
}
```
暑さを笑い飛ばせ！プログラミング+ネタ系subredditまとめ


## こんな人におすすめ
* プログラマネタで笑いたい
* 英語を勉強したい
* 外国のプログラマとの雑談力をあげたい

## Reddit/Subredditとは？

[reddit](https://www.reddit.com/)

[Wikipedia](https://ja.wikipedia.org/wiki/Reddit)より
>ウェブサイトへのリンクを収集・公開するソーシャルブックマークサイト。ニュース記事、画像などの紹介や感想募集のトピックを誰でも立てられるソーシャルニュースサイトでもあり、トピックについてのコメントを誰でも書き込める電子掲示板の一種でもある。

> redditでは特定の領域向けに焦点を当てたコミュニティをサブレディット(subreddit)と呼ぶ。

## 本題
### [r/ProgrammerHumor](https://www.reddit.com/r/ProgrammerHumor/)
プログラミング関係のミームといえばここ。プログラミング+ネタ系subredditでは最大級で、ハッカソンを開催していたりもする。

### [r/softwaregore](https://www.reddit.com/r/softwaregore/)
ソフトウェアのゴア画像、ということでバグってて鳥肌の止まらない画像を馬鹿にするsubreddit.

### [r/badcode](https://www.reddit.com/r/badcode/)
クソコードをみんなで笑うところ

### [r/programminghorror](https://www.reddit.com/r/programminghorror/)
プログラムのホラー画像。上二つと何が違うのかを考えてはいけない。

### [r/pcmasterrace](https://www.reddit.com/r/pcmasterrace/)
自作PCを自慢するところかと思いきや半分以上が自作PCのミーム。私は自作PCしないのであんまり覗くことはない。

## その他おすすめ
### [r/dankmemes](https://www.reddit.com/r/dankmemes/) [r/memes](https://www.reddit.com/r/memes/)
ミーム全体のsubreddit。dankmemeはブラック系が多いので注意。ここをみておくとr/ProgrammerHumorのネタがわかったりする

### プログラミング言語・プラットフォーム・フレームワークなどのsubreddit
[r/Python](https://www.reddit.com/r/Python/)とか、[r/node](https://www.reddit.com/r/node/)とか、[r/reactjs](https://www.reddit.com/r/reactjs/)とか。
最新情報や役に立つ記事などが貼られることがあって為になるし、海外の流行を追う事もできる

## まとめ
redditなんて見ずに進捗産めばいいと思うよ
macにdocker-composeでwordpressをたてる

作業ディレクトリを作ってその中に入る。

`docker-compose.yml`を作成し以下を記述。

```yml
version: '3'

services:
  smtp:
    image: schickling/mailcatcher
    ports:
      - 1081:1080
      - 1025:1025
  db:
    image: mysql:5.7
    ports:
      - 3314:3306
    volumes:
      - db_data:/var/lib/mysql
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: somewordpress
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wordpress
      MYSQL_PASSWORD: wordpress

  wordpress:
    depends_on:
      - db
      - smtp
    image: wordpress:5.2.2-php7.3
    volumes:
      - ./work:/var/www/html
    ports:
      - 8003:80
    restart: always
    environment:
      WORDPRESS_DB_HOST: db:3306
      WORDPRESS_DB_USER: wordpress
      WORDPRESS_DB_PASSWORD: wordpress

volumes:
    db_data:
```

`docker-compose up` でbuild、起動。
`localhost:8003` にブラウザでアクセス。

カンタン！！

参考
- [wordpress \- Docker Hub](https://hub.docker.com/_/wordpress/)
- [docker\-composeでwordpress環境をサクッと構築する \- Qiita](https://qiita.com/mom0tomo/items/7e611ac829863d4c5c82)
inteliJでTomcat起動時ルートURLを設定する

intelij ulitimet Edition
Tomcat 9.0.22
を使用してます。

下記画面を開く
Run > Edit Configurations > Tomcat 9.0.22 > Deploymentタグ

<img width="1183" alt="スクリーンショット 2019-08-09 18.25.11.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/230281/742d340e-aa0b-e5ba-3dd7-88f906be78cc.png">

Application context欄にてルートURLを書き換えることができる。
経過時間のloggingを簡易にするhelperメソッド作ってみた

## このページについて

タイトル通りです(2019-08)
いちいち **Before** のように書くのが面倒だったので簡単にしてみました

## Before

```go
func Do() {
    s := time.Now()
    //
    // doAnyFunc()
    //
    e := time.Now()
    log.Print(e.Sub(s))
}
```

## After

msecでロギングしたい例

```go
func Do() {
    defer helper.MillSecTimeTrack(time.Now(), timeTrack())
    //
    // doAnyFunc()
    //
}

func timeTrack() func(v float64) {
	return func(v float64) {
		log.Print(v)
	}
}

func MillSecTimeTrack(start time.Time, loggingFunc func(e float64)) {
	elapsed := time.Since(start).Seconds() * 1000
	loggingFunc(elapsed)
}

```

関数でラップしているのは、経過時間以外にも情報を好きに残せるようにするためです
こんな感じ

```go
func Do() {
    query := "select * from qiita"
    defer helper.MillSecTimeTrack(time.Now(), timeTrack(query))
    //
    // doAnyFunc()
    //
}

func timeTrack(query string) func(v float64) {
	return func(v float64) {
		log.Print(query, v)
	}
}

func MillSecTimeTrack(start time.Time, loggingFunc func(e float64)) {
	elapsed := time.Since(start).Seconds() * 1000
	loggingFunc(elapsed)
}

```





## 参考
htmlのinput imageでimageファイルをbase64に変換して取り扱うための関数


#htmlのinput imageでimageファイルをbase64に変換して取り扱うための関数
htmlのinput imageでimageファイルをbase64に変換して取り扱うための関数が見当たらなかったので作った。  

[demo](https://takashiag.github.io/img2base64/)

async/awaitで使ってください。
promiseでも良い

```javascript:index.js
let image2base64 = input_id => new Promise((resolve, reject) => {
    let fileinput = document.getElementById(input_id);
    if (fileinput == null)
        reject("cant find element");

    let fileData = file.files[0]
    if (fileData === undefined)
        reject("no file")

    if (!fileData.type.match('image.*'))
        reject("file type error");

    let reader = new FileReader();
    reader.onload = () => {
        resolve(reader.result)
    }
    reader.readAsDataURL(fileData);
})
```

## to use 
``<input type="file" accept='image/*' id="file">`` で選択されたファイルを扱うとする。

```js
// idを指定する
let b64 = await image2base64('file') 

// base64をテキストにする
document.getElementById("result").innerText = b64;

// base64をimg.srcにapply
document.getElementById("result2").src = b64;
```

# demo
[まあだいたいこんな感じ](https://takashiag.github.io/img2base64/)
デモに乗ってるソース

```html:index.html
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <script>
        let image2base64 = input_id => new Promise((resolve, reject) => {
            let fileinput = document.getElementById(input_id);
            if (fileinput == null)
                reject("cant find element");

            let fileData = file.files[0]
            if (fileData === undefined)
                reject("no file")

            if (!fileData.type.match('image.*'))
                reject("file type error");

            let reader = new FileReader();
            reader.onload = () => {
                resolve(reader.result)
            }
            reader.readAsDataURL(fileData);
        })
        let henkan = async () => {
            let b64 = await image2base64('file')
            document.getElementById("result").innerText = b64;
            document.getElementById("result2").src = b64;
        }
    </script>
</head>
<body>
<input type="file" accept='image/*' id="file">
<button onclick="henkan()">変更</button>
<div id="result"></div>
<img id="result2">

</body>
</html>
```
k8s自分用チートシート{改}


用途別に分けて使う(≒遊ぶ)ための記事です。
「コマンドをせっかく見たり覚えても身に付かないなぁ～」
という場合に、自分の経験に照らして覚えやすくする効果も期待しました。
(伝わらない表現があったらごめんなさい、ネタ記事ですのでコメントはお控え下さい)

**実行しても当方で責任を負えないコマンドも含まれております、実行は自己責任でどうぞ**

Pod
--------------------

### Podがザキで死んでいく様を見るコマンド

```
kubectl get pod --watch <pod_name> &
kubectl delete pod <pod_name>
```

### 「なかまになりたそうにこちらを見ている」Pod達を見つめ続けるコマンド

```
kubectl get pod -A --watch | awk '$4=="Pending"'
```

### 自分達にザラキし続けるPod達を見守るコマンド

```
kubectl get pod -A --watch | awk '$4=="CrashLoopBackOff"'
```

Node
--------------------

### ガンガンいきすぎてMPが枯渇したNode達を見守るコマンド

```
while kubectl describe node -A | awk '($3=="(100%)" && $1=="memory") || $1=="Name:"' ; do sleep 1 ; done
```

### ずっと馬車から出してもらえないNode達を見守るコマンド

```
while kubectl describe node -A | awk '$3=="(0" || $1=="Name:"' ; do sleep 1 ; done
```


Cluster
--------------------

### メガンテ

```
sudo kubeadm reset && reboot
```
Python3でAtCoder Beginners Selectionをすべて解くためにやったこと

*AtCoder Beginners Selection をすべて解くことができたのでその時にやったことを書き残しておきます。*


##Pythonを触る前までのスペック
+ 理系の大学生として標準的な数学的思考力
+ 学部は非情報系(触れたことある言語はCとC++)

講義の中でC言語やC++を使ってif文やfor文を理解したぐらいで特にプログラミングに関しては<b>素人</b>だと思います。

###やったこと
+ [入門Python2&3対応](https://www.amazon.co.jp/Python入門-2-3対応-細田-謙二/dp/4798026557)を10章まで読みました。
+ AtCoder Beginners Selectionの問題を解きました。

###少しだけ具体的にやったこと

+ [入門Python2&3対応] (https://www.amazon.co.jp/Python入門-2-3対応-細田-謙二/dp/4798026557)を1日2時間程度読みながらソースコード実行したり自分で手を動かして確認しました。ここではリストやタプルや辞書の説明を理解して読み進めました。

+ 次にさっそくAtCoder Beginners Selectionの問題に取り組みました。最初はA問題ですら固まってしまいましたが、標準入力やリストの扱い方などネットで調べて確認して覚えていきました。

<b>ここで最低限のリストがどういうものかといった知識が必要になるので先に[入門Python2&3対応](https://www.amazon.co.jp/Python入門-2-3対応-細田-謙二/dp/4798026557)を読みました。</b>

問題の本質的には理系の学生であれば解けるので後はコードが書けるかどうかです。ここに関しては、

+ <b>インターネットで調べながら毎日AtCoder Beginners Selectionに取り組む、で十分だと思います(インターネットで調べると書籍より詳しいサイトがたくさん出てきました笑)</b>

##まとめ
+ 最低限の文法(変数の扱いや足し算引き算、リストfor文など)を書籍を使って1~2週間程度で理解する。

+ とりあえず書いてみる。8~10問目を解くころには最初のほうで苦戦していた文法も問題なく理解できるようになってるはずです。
WindowsでPATHが通らないよ！ﾑｯｷｨｨｨｨ！！ってあなたへ

# 対象
- Windows利用者
- PATHを通したはずなのに通らない人
- 色々試したけど解決しないで途方に暮れている人
- 最終的にパソコンのせいにして諦めた人

# 具体例
私の場合は、以下の状況で起こりました。

1. VSCodeでC言語をコンパイルしたい
2. WinMGでgccをインストール
3. システム環境変数の編集でgcc.exeのPath "C:\WinMG\bin"を追加 
4. gcc --versionを実行
5. 以下のメッセージが出る

```
C:\Windows\System32>gcc --version
'gcc' は、内部コマンドまたは外部コマンド、 操作可能なプログラムまたはバッチ ファイルとして認識されていません。
```

# やったこと

## PATHの確認

コマンドプロンプトでPATHと入力するだけです。

```
PATH=C:\MinGW\bin;C:\WINDOWS\system32; ～ 以下省略
```

## 優先順位を変える

システム環境変数の編集でC:\MinGW\binを上の方に移動させる。

結果：関係なかった

## \マークと\マークの違い

Windowの場合￥マークと＼（バックスラッシュ）で表示される文字は同じという宿命があります。つまり、文字コードを間違えているのです。

正解は￥マーク、和製キーボードだと右上のキーになります。

結果：関係なかった（実は関係あった）

## Q&Aサイトのパスをコピペ

マークの違いはわかったけど、面倒くさがり屋の僕はコレをしてしまいました。
それが、全ての間違いでした。

PATHには表示されているけど、PATHが通らない。

フルパス C:\WinMG\bin\gcc.exe --version は成功するのに、

いったい、どうなってるんだ俺のPC、、、

いや、実は文字コードの違いが正解だったのです。

## コマンドプロンプトで表示されるPATHをコピペ

コマンドプロンプトでPathと入力して、表示されるPathをコピペして、

続きの gcc.exe --version を入力しようとしました。

あれ？

できない。

そう、Q&Aのサイトでコピペしたパスの文字コードが間違っていたのです。

# 結論

1. ￥マークと＼（バックスラッシュ）の違いに気を付けよう。
2. PATHが通ってるはずなのに、通ってないときは、コマンドプロンプトで表示したPATHをコピペして実行できるか試してみよう。
3. 自分の記憶を疑おう
Railsのサービスクラスを作る前に考えるべきこと

[肥大化したActiveRecordモデルをリファクタリングする7つの方法（翻訳）](https://techracho.bpsinc.jp/hachi8833/2013_11_19/14738#service-object) のサービスクラスは確かに便利ですが、とりあえずで使うと今度はサービスクラスが肥大化したりサービスクラスが乱立したりします

そこでサービスクラスを作る前に後々困らないように考えます

## 1. 実装を狭めるルールを決める

単一責務に誘導することで肥大化を防ぐ方法がよく語られています

* `.call` 実行だけ許可して他を隠蔽する
* 動詞から始めるクラス名に制限する 

### 参考

* [Rails のサービスクラスでのマイルールとちょっとしたコツ](https://qiita.com/QUANON/items/5ef803988c0ad6930e4b) 
* [Railsにおけるサービスクラスのオリジナルルール](https://qiita.com/chrischris0801/items/58a12d17a440b842db02)
* [gem smart_init](https://github.com/pawurb/smart_init) （本記事で用いる）
* [gem trailblazer](https://github.com/trailblazer/trailblazer)（規模が大きいため本記事では言及しない）

## 2. 特定モデルの振る舞いまでサービスクラスにしない

MVC パターンの M は ActiveRecord だけではなくもう少し広いもので、該当モデルの振る舞いなら models フォルダに ActiveRecordクラス以外があっても問題ないという考えによるものです

```ruby
class User < ActiveRecord::Base
  def self.find_or_create_with_hoge(hoge)
    # 略： 肥大化し private 関数などに分離しつつ他の処理から隔離したい
  end
end
```

こんな時に `FindOrCreateUserWithHogeService` を作ると見通しが悪くなります
そこで挙動としてはサービスクラスと同じですが配下に配置するとスッキリします

```ruby:models/user/find_or_create_with_hoge.rb
class User
  class FindOrCreateWithHoge < SmartInit::Base
    initialize_with_args :user, :hoge
    is_callable

    def call
      # 略
    end

    private

    def hogehogehoge
      # 分割
    end
  end
end

# 実行するとき
User::FindOrCreateWithHoge.call(user, hoge)
```

## 感想

ベストプラクティスがなくベタープラクティスを手探りで探ってる感
PHP初心者　クラス継承

学んだ知識
継承...既存のクラスに新しいクラスを作ること

extends..継承するために必要なキーワード、今回は上記の$nameプロパディ、sayHiメソッドが利用可能。

親クラス、小クラス...継承したクラスを小クラス、元々クラス定義していた部分を親クラスという

所感...継承の定義自体は分かったけど、このコードを厳密にどう上手く説明すればいいのか少し難しいところ。
ざっくり言えば小クラスを定義して、Userクラスで設定しておいたプロパディとメソッドを２つのインスタンスに使ったとしか今はそれしか言えない。他のプログラマーさんたちは継承をどういう意味で解釈しているのかが気になるところ。




```
<?php
//クラス定義、親クラス

class User{

  //パブリック
  public $name;

//コンストラクタ
 public function __construct($name){
   //クラスの中の$nameプロパディにアクセス
   $this->name= $name;

 }
  //メソッド、挨拶文
  public function sayHi(){
    echo "私の名前は.$this->name.です";
  }
}
//継承,小クラス($name,sayHiを使うことが出来る)
class MainUser extends User{
  public function sayHello(){
    echo "こんにちはLieF";
  }
}




//インスタンス生成
$hahakigi =new MainUser("hahakigi");
$ai =new MainUser("ai");

//hahakigiインスタンスの挨拶
$hahakigi->sayHi();
$hahakigi->sayHello();

//aiインスタンスの挨拶
$ai->sayHi();
$ai->sayHello();

実行結果
私の名前は.hahakigi.ですこんにちはLieF私の名前は.ai.ですこんにちはLieF