OmniAICreator/Qiita-1.07M huggingface dataset:
else-ifを三項演算子(?:)やnull合体演算子(??)に置き換えてみた

# 概要

PHP5.3以降で使用可能な三項演算子`?:`を`if-else`構文の **完全互換だと思いこんで** `else-if`のネストに置き換えて使ってみたら **想定外の挙動** で少しハマったので反省も踏まえ共有してみた。

## 状況

画面上の押されたボタンによってデータベースに対する処理を分ける場面です。
formタグ自体は1つで「登録」「更新」「削除」「キャンセル」のsubmitボタン自体にname属性を持たせ、どのボタンが押されたかを判別しています(**valueの中身は気にしない方向**)

まず最初に書いたコード

```php5:db_ctrl.php
if (isset($_POST['regist'])) {
    $action= "regist";
} else if (isset($_POST['update'])) {
    $action= "update";
} else if (isset($_POST['delete'])) {
    $action= "delete";
} else if (isset($_POST['cancel'])) {
    $action= "cancel";
}
```

動作は問題なし。
でもなんだか冗長というか、我ながら同じ単語何回書くんだと **1人ツッコミ** が入る

で、まずは上記を「`if-else`の短縮構文」の **つもり(思い込み)** で三項演算子`?:`に置き換えてみました

```php5:(PHP5.3以降)db_ctrl.php
$action=
isset($_POST['regist'])? "regist" :
isset($_POST['update'])? "update" :
isset($_POST['delete'])? "delete" : "cancel";
```
最初のコードと比べればだいぶスッキリした。

尤も、この構文だと最後が`else-if`ではなく`else`(或いはswitch文の`default:`)のようになってしまうので **そもそも置き換えられてない** んですけども。

とりあえずテスト。
今回期待する結果は「登録」ボタン押下後で`$action= "regist";`
結果は・・・

```php5:南無った
$action = "delete";
```
**ちーん** :skull:
**なんでやねん！**

調べたところ、こういうことだそうで…
([PHP公式マニュアル](http://docs.php.net/manual/ja/language.operators.comparison.php#language.operators.comparison.ternary)から引用)

**ダメだこいつ`?:`早くなんとかしないと…**

## 代替案としてnull合体演算子(??)を使用

できれば **「中身が'regist'だったら"regist"を入れる」** なんて単語のリピートも1回の記述で済ませたいし
今回のケースは条件`isset()`の`if-else`ネストだから、この三項演算子の下に説明のある**null合体演算子**ってのがいい感じで使えるんジャマイカ？

というわけで、早速さっきのPHPマニュアルで覚えたての*null合体演算子*を使ってみました

```php5:(PHP7以降)db_ctrl.php
$action =
$_POST['regist']??
$_POST['update']??
$_POST['delete']??
$_POST['cancel']?? "";
```
ただ、これだと`$action`の中身が`$_POST`の中身そのままになるので、`<input type="submit" name="action" value="登録">`ってHTML書いてると思いっきり送信ボタンの日本語ラベルがそのまま値(`$action = "登録"`)になるのがネック :cat:

やっぱり基本的にはsubmitボタンにname属性は持たせず`<input type="hidden" name="action" value="regist">`とセットにするのがいいのかな

## 最終的にforeachに落ち着いた
結局のところ以下のコードに落ち着きました…

```php:db_ctrl.php
$actions = ['regist', 'update', 'delete', 'cancel'];
foreach ($actions as $action) {
	if (isset($_POST[$action])) break;
}
```

## 消化不良な部分
今回の三項演算子`?:`のこの想定外の挙動、どうやら**他の言語の三項演算子では**ちゃんと期待通りの結果になる模様 :scream_cat:

なんでPHPだけ違う結果になるのか、 **PHPマニュアル自体が「わかりにくい挙動」に要注意** と警鐘を鳴らす仕様を敢えて採用する理由はなんなんだと軽く調べてみたら **「間違って実装しちゃったけど今更修正できないから」** なんて言う人も…ホンマかいなそれ :fearful:
~~そんなだから海外の言語ランキングで「主軸のない補助輪」とか揶揄されるんじゃ…~~

## 結論、まとめ。
**PHP(5.3以降)の三項演算子(?:)はネストしてはいけない。**  ~~修正しろｙ~~
**PHP7以降のnull合体演算子(??)のネストは可能ではある。**

<details><summary>未熟エンジニアなりの所感（おまけ）</summary>
こんなところまで読んで頂きありがとうございます m(_ _)m
PHPにおける三項演算子(`?:`)の使い所としては「HTML部分にPHPを埋め込む際、`foreach`のように一行にしたい」といった用途向きでしょうか
ネストは避けるとしても、あまり多用しても逆に可読性が悪くなるのかもしれません
null合体演算子(`??`)もPHP7以降なので、環境次第でエラー修正する羽目に陥る確率が高い気が…
**そもそも他言語からPHP ~~に流れてくる~~ も学ぼうとされる方** は少数派かもですが、同じ仕様だと思って **「なんでやねん！:anger:」** と躓かれる方がいるかもしれないと思い投稿しました。
いつも他の方の情報を頂いてばかりの自分の投稿がどなたかのお役に立てば幸いです:pray:
</details>

---
#### あとがき
マークダウン記法の学習と技術情報共有や質問投稿に慣れていく目的も兼ねての初投稿です
MarkdownやQiitaでの投稿自体が初めてなので、主に以下のページを参考にさせていただきました

[Markdown記法 チートシート](https://qiita.com/Qiita/items/c686397e4a0f4f11683d)
vagrantでBridgeをする設定にしてVMへの外部アクセスを許可する

## 概要
vagrantで構築した仮想環境の指定したportに外部からアクセスしたかったので、 `Vagrantfile`の書き方を調べました。デフォルトの`Vagrantfile`では、`NAT`状態なので、ホストマシンからVMあるいは、外部からVMにアクセスすることはできません。そこでネットワークをブリッジして、VMにアクセスできるようにしていきましょう。


**`Vagrantfile`における`config.vm.network "public_network"`の記述が、`Virtual Box`の「ブリッジアダプター」に当たります。**


## 開発環境
vagrant Version: 2.1.1
virtual box: 5.2.20
Mac OS Mojave 10.14.3

## 設定ファイルの変更
基本的には、`vagrant up`する前に、`Vagrantfile`の一部を編集すればいいだけなので、下記のように編集します。

```:vagrantfile
  # Create a public network, which generally matched to bridged network.
  # Bridged networks make the machine appear as another physical device on
  # your network.
   config.vm.network "public_network" #ここの行のコメントをとる
```
設定ファイルの書き換えが終わったら、`vagrant up`で立ち上げます。
その時に、ブリッジするインターフェースを聞かれるので、`en0: Wi-Fi (AirPort)`のように指定してあげます。


ローカルIPを固定する場合は次のようにすると良いです。

```:vagrantfile
  # Create a public network, which generally matched to bridged network.
  # Bridged networks make the machine appear as another physical device on
  # your network.
   config.vm.network "public_network, ip: "192.168.0.2"" 
```

参考：
https://www.virment.com/vagrantfile-settings/
https://www.vagrantup.com/docs/networking/public_network.html
Go 1.13のerrorsへの移行手順

# Go 1.13のerrorsへの移行手順

https://github.com/pkg/errors を利用している前提で紹介します。


## 基本

### errors.Wrap(err, "") を fmt.Errorf(": %w", err)に変更

```go
errors.Wrap(err, "message")
```

```go
fmt.Errorf("message: %w", err)
```

### errors.Cause を errors.Unwrap に変更

```go
err = errors.Cause(err)
```

```go
err = errors.Unwrap(err)
```

### エラーの値の比較をerrors.Isに変更

```go
err = errors.Cause(err)
if err == ErrNotFound {

}
```

```go
// Unwrapは不要
if errors.Is(err, ErrNotFound) {

}
```

### type assertion を Asに変更

```go
if myErr, ok := err.(*MyError); ok {

}
```

```go
var myErr *MyError
if ok := errors.As(err, &myErr); ok {

}
```

<!-- 
## 応用
### fmt.Formatterをerrors.ErrorFormatterに変更

```go
func (e *Error) Format(s fmt.State, v rune) {
    
}
```

```go
func (e *Error) FormatError(p errors.Printer) (next error) {
	p.Print(e.Error())
	e.frame.Format(p)
	return e.err
}
```

## その他
### エラー出力でスタックトレースを表示

```go
err := func1()
fmt.Printf("%+v", err)
```
-->

## その他
### エラー出力でスタックトレースを表示

Go 1.13のerrors パッケージではスタックトレースの表示には対応していません。
スタックトレースの表示をしたい場合には[xerrorsへの移行手順](https://qiita.com/sonatard/items/5afd13a7640e628ee4d2) をご確認ください。

## 関連情報
- [xerrors - 関連情報](https://qiita.com/sonatard/items/802db82e7275f17fe702)
GASを使ってTrelloのボードID・リストID・カードIDを取得する方法

# はじめに
Google Apps Script（通称GAS）を使用することで様々なツールを連携させることができます。

GASとは何でしょうか。公式ではこのように述べています。

>Google Apps Script は、Googleが提供するサーバーサイド・スクリプト環境です。Googleが提供する一大スクリプト環境を是非使いこなしてください。

Googleアカウントを持ち、Googleドキュメントやその他のサービスを利用している者なら誰でも利用できます。詳しくは下記のURLにあるので気になる方は見てください。（ここから先はこれを見なくても分かります）![スクリーンショット 2019-03-01 15.00.22.png](https://qiita-image-store.s3.amazonaws.com/0/240838/452a7f4f-5320-7e3d-c70f-45b84071f8f8.png)


https://qiita.com/t_imagawa/items/47fc130a419b9be0b447

# やりたいこと
スプレッドシートとTrelloの連携です。タスク管理ツールTrelloを用いている会社・組織は非常に多く、私が所属しているプロジェクトでも使っています。

そして様々な組織がより業務を便利にするためにスプレッドシートとTrelloを連携させています。当然何をするかによってその連携方法は変わってきますのでその方法全てをここでは記すことはできませんが、全ての連携の共通部分、Trelloの情報取得のやり方を記載していきます。

# 手順
①TrelloのAPIキーを取得する（30秒）
②Trelloのトークンを取得する（30秒）
③Trelloのユーザー名を取得する（30秒）
④TrelloのボードIDを取得する（1分）
⑤TrelloのリストIDを取得する（1分）
⑥TrelloのカードIDを取得する（1分）

全ての情報取得をするとなると上記の手順が必要になってきます。とは言っても一つ一つは非常に簡単ですので順にやってしまいましょう。

## ①TrelloのAPIキーを取得する（30秒）
Trelloにログインした状態で下記のURLにアクセスするだけです。画像の黄色いところがAPIキーです。

https://trello.com/app-key

![スクリーンショット 2019-03-01 15.00.22.png](https://qiita-image-store.s3.amazonaws.com/0/240838/f0a347fc-4b44-b052-6863-c9a7b4b140ed.png)

## ②Trelloのトークンを取得する（30秒）

APIを取得したページの「開発者向けAPIキー」のところの最後の行にある「トークン」というリンクから取得できます。

## ③Trelloのユーザー名を取得する（30秒）

Trelloで自分のアイコンをクリックすると出てくる「userOOOO」です。

## ④TrelloのボードIDを取得する（1分）

ここからGASを用います。適当なスプレッドシートを作成し「ツール」→「スクリプトエディタ」の順に選択します。
スクリプトエディタを開けたら下記のコードを用います。

```js
function getBoardId() {
  var trelloKey   = "①で取得したAPIキー";//keyを入力してください
  var trelloToken = "②で取得したトークン";//tokenを入力してください
  var userName = "②で取得したユーザー名";//ユーザ名を入力してください
  var url = 'https://trello.com/1/members/' + userName + '/boards?key=' + trelloKey + '&token=' + trelloToken + '&fields=name';
  res = UrlFetchApp.fetch(url, {'method':'get'});
  Logger.log(res);
}
```

これを書けたら保存して三角ボタンを押して実行しましょう。問題なく実行されたら（スコープの許可を求めてくることがありますので承認しましょう）、「表示」→「ログ」の順に選択してログを確認してください。書いてあるはずです。

## ⑤TrelloのリストIDを取得する（1分）
新しいファイルを作成し④と同様に進めていきます。下記のコードを用いてください。

```js
function getListId() {
  var trelloKey   = "①で取得したAPIキー";//keyを入力してください
  var trelloToken = "②で取得したトークン";//tokenを入力してください
  var boardId = "④で取得したボードID";//ボードIDを入力してください

  var url = "https://trello.com/1/boards/" + boardId + "/lists?key=" + trelloKey + "&token=" + trelloToken + "&fields=name";

  res = UrlFetchApp.fetch(url, {'method':'get'});
  Logger.log(res);
}
```

同様にログを見ればリストIDが取得できます。

## ⑥TrelloのカードIDを取得する（1分）
こちらも新規ファイルを作成→コード実行→ログ確認の流れで取得できます。コードは下記です。

```js
function getCardId() {
  var trelloKey   = "①で取得したAPIキー";//keyを入力してください
  var trelloToken = "②で取得したトークン";//tokenを入力してください
  var listId　= "⑤で取得したリストID";//リストIDを入力してください
  var url = "https://trello.com/1/lists/" + listId + "/cards?key=" + trelloKey + "&token=" + trelloToken + "&fields=name";

  res = UrlFetchApp.fetch(url, {'method':'get'});
  Logger.log(res);
}
```

## 最後に
これで連携に必要な情報を取得できました。
スプレッドシートとTrelloの連携についてはたくさんの記事がありますのでやりたいものを検索してやってみてください！
下記にたくさんの情報ありますのでおすすめです。
https://www.virment.com/use-trello-api-google-apps-script/
https://tonari-it.com/category/google-apps-script/
xerrorsからGo 1.13のerrorsへの移行手順

# xerrorsからGo 1.13のerrorsへの移行手順

https://godoc.org/golang.org/x/xerrors を利用している前提で紹介します。

Go 1.13では `%w` でのラップや `Is` メソッド、 `As` メソッドは正式に導入されました。
しかし`%+w` や `%+v` によるスタックトレースの表示の採用は見送られました。

スタックトレースの表示が必要な場合はxerrors パッケージを利用して、不要な場合には標準ライブラリの errors パッケージを利用してください。


### xerrors.Errorf を fmt.Errorf に変更

```go
xerrors.Errorf("message: %w", err)
```

```go
fmt.Errorf("message: %w", err)
```

### 残りのすべてのxerrorsをerrorsに変更する

`New`, `Is`, `As`, `Unwrap` など
https://godoc.org/golang.org/x/xerrors


## 最終確認

xerrorsが見つからないことを確認します。

```sh
$ grep -r "xerrors" ./
```

## 関連情報
- [xerrors - 関連情報](https://qiita.com/sonatard/items/802db82e7275f17fe702)
gitguiでpush時に「permission」と出る場合の解決法

二つのgithubアカウントを切り替えて使うと、片方が片方に対してパーミッションがないので
エラーになります。

下記でデフォルトのユーザを消すと解決できます。Windows10

```
コントロールパネル→ユーザアカウント→資格情報の管理→Windows資格情報→githubの情報を消します。
```
grailsでrun-appしたらブートしなくなった

# はじめに
こんにちは、grailsで色々なものを作っているエンジニアです。

# できごと
ある日、ある依存関係を追加して grailsを起動したら、こんな風にブートすらしなくなってしまいました。

```
load application.groovy
| Resolving Dependencies. Please wait...

CONFIGURE SUCCESSFUL

| Running application...

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':bootRun'.
> A problem occurred starting process 'command 'C:\Program Files\Java\jdk1.8.0_201\bin\java.exe''

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.
| Error Failed to start server (Use --stacktrace to see the full trace)
```
--stacktraceを追加して再度起動してみると、

```
Caused by: java.io.IOException: Cannot run program "C:\Program Files\Java\jdk1.8.0_201\bin\java.exe" (in directory "D:\git_repo\puredash"): CreateProcess error=206, フ ァイル名または拡張子が長すぎます。
        at net.rubygrapefruit.platform.internal.DefaultProcessLauncher.start(DefaultProcessLauncher.java:25)
        ... 5 more
Caused by: java.io.IOException: CreateProcess error=206, ファイル名または拡張子が長すぎます。
        ... 6 more
| Error Failed to start server
```
という、香ばしいエラーが。"D:\git_repo\puredash" のどこが長いんじゃ！と思いましたが、どうやら依存関係をたくさん書いているので、classpathが長すぎてコマンドラインが長くなりすぎてるのが原因のようですね。そんな時は、build.gradle にこう書き足します。

```
grails {
	pathingJar = true
}
```

最初、gradle界隈で同様の事案があるようで(あたりまえか)、いろいろ書いてたらpathingJarタスクはもうあるけど？みたいなエラーが出たので、恐る恐る上記だけにしてみました。ちなみに grails-3.3.9です。それでは皆さん、またがんばりましょう。

# 参考
[[Gradle] Createprocess error=206 への対処 [備忘録]
](https://qiita.com/ksh-fthr/items/4a45d2a61db5a4b812f4)
WinFormsアプリで複数開けるようにしたメインフォームをすべて閉じたときにアプリケーションを終了する簡単な方法

#はじめに
Windows フォームアプリケーションで、複数のフォーム（メインウインドウ）を自由に開いて、かつすべて閉じたときにアプリケーションを終了させるようにします。Multiple Top-level Interface (MTI) というやつです。

#コード

フォームは、次の画面のような、[Button](https://docs.microsoft.com/ja-jp/dotnet/api/system.windows.forms.button)コントロール1つ (buttonOpenという名前) を配置。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/100206/58500f4f-3416-7f59-4418-ff599c47099b.png)
[System.Windows.Forms.Application](https://docs.microsoft.com/ja-jp/dotnet/api/system.windows.forms.application) クラスが、便利に計らってくれます。

```C#:Program.cs
using System;
using System.Windows.Forms;

namespace WindowsFormsApp2
{
    static class Program
    {
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);

            (new Form1()).Show();
            Application.Run(); // <- Form とアプリケーション（メッセージポンプ）終了を連動させず、Application.Exit()で終了メッセージを受け取るまで動作させる。

            //Application.Run(new Form1());
        }
    }
}

```

```C#:MainForm.cs
using System;
using System.Windows.Forms;

namespace WindowsFormsApp2
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void buttonOpen_Click(object sender, EventArgs e)
        {
            (new Form1()).Show();
        }

        protected override void OnClosed(EventArgs e)
        {
            base.OnClosed(e);

            if (Application.OpenForms.Count == 1) // <- 開いているメインフォームの数
            {
                Application.Exit();
            }
        }
    }
}
```

#結果
デバッグ実行させ、任意のフォーム上のOpenボタンをクリックすると、フォームが増殖していきます。右上の×ボタンを使ってフォームをすべて閉じると、アプリケーションがおわってデバッガが終了します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/100206/7504185b-1fda-77d6-1f13-ff7f70f41722.png)
xerrorsへの移行手順



# xerrorsへの移行手順

https://github.com/pkg/errors を利用している前提で紹介します。

Go 1.13以降はスタックトレースの表示が不要でエラーのラップ機能だけでよければ、xerrorsを使う必要はなく、errorsパッケージを使いましょう。


## 基本
### errors.New を xerrors.Newに変更

```go
errors.New("message")
```

```go
xerrors.New("message")
```

### errors.Wrap(err, "") を xerrors.Errorf(": %w", err)に変更

```go
errors.Wrap(err, "message")
```

```go
xerrors.Errorf("message: %w", err)
```

### fmt.Errorf を xerrors.Errorfに変更

```go
fmt.Errorf("message: %v", msg)
```

```go
xerrors.Errorf("message: %v", msg)
```

### errors.Cause を xerrors.Unwrap に変更

```go
err = errors.Cause(err)
```

```go
err = xerrors.Unwrap(err)
```

### エラーの値の比較をxerrors.Isに変更

```go
err = errors.Cause(err)
if err == ErrNotFound {

}
```

```go
// Unwrapは不要
if xerrors.Is(err, ErrNotFound) {

}
```

### type assertion を Asに変更

```go
if myErr, ok := err.(*MyError); ok {

}
```

```go
var myErr *MyError
if ok := xerrors.As(err, &retErr); ok {

}
```

## 応用
### fmt.Formatterをxerrors.ErrorFormatterに変更

```go
func (e *Error) Format(s fmt.State, v rune) {
    
}
```

```go
func (e *Error) Format(s fmt.State, v rune) {
    xerrors.FormatError(e, s, v)
}

func (e *Error) FormatError(p xerrors.Printer) (next error) {
	p.Print(e.Error())
	e.frame.Format(p)
	return e.err
}
```


## 最終確認

errorsが見つからないことを確認します。

```sh
$ grep -r "errors" ./
```

## その他
### エラー出力でスタックトレースを表示

```go
err := func1()
fmt.Printf("%+v", err)
```

## 関連情報
- [xerrors - 関連情報](https://qiita.com/sonatard/items/802db82e7275f17fe702)
全角数字・漢数字を一括して半角数字に変える

引き続き、スプレッドシートで**フォーマットの統一されていない住所一覧**を渡されてキレてる私の覚書です。

前回は、住所に含まれる色んな横棒をハイフンに変えました。[→こちら](https://qiita.com/mori_toma/items/79e38a27f036d55d6165)
ただ、この横棒処理は、番地を表す数字があらかじめ半角になっていることが前提となっています。

というわけで、別途こんな感じの関数が必要かと思います。

```code.js
function num2num(str){ // 全角数字を半角数字に
  var reg;
  var twoBtNum = ['１','２','３','４','５',
               '６','７','８','９','０'];
  var num = ['1','2','3','4','5',
               '6','7','8','9','0'];
  for(var i=0;i<num.length;i++){
    reg = new RegExp(twoBtNum[i],'g'); // ex) reg = /３/g
    str = str.replace(reg,num[i]);
  }
  return str;
}
function kanji2num(str){ // 漢数字を半角数字に
  var reg;
  var kanjiNum = ['一','二','三','四','五',
               '六','七','八','九','〇'];
  var num = ['1','2','3','4','5',
               '6','7','8','9','0'];
  for(var i=0;i<num.length;i++){
    reg = new RegExp(kanjiNum[i],'g'); // ex) reg = /三/g
    str = str.replace(reg,num[i]);
  }
  return str;
}

// 使用例
var add = '宮城県仙台市横浜区二丁目３－４';
var add2 = num2num(add); // add2 = '宮城県仙台市横浜区二丁目3ー4'
var add3 = kanji2num(add2); // add3 = '宮城県仙台市横浜区2丁目3ー4';

```
住所一覧に限らず色んな場面でけっこう使っております。
単純に、replace(/数字/g,"半角数字")を10通りやってるだけですが。
gオプションは、あてはまるもの全部ということになり、「三丁目三ー三」→「3丁目3ー3」と全部変わります。正規表現を使わない場合や、オプション無しの場合は、「3丁目三ー三」になる気がします。

住所に関してひとつ気を付けなければならないことがあって、この関数をやみくもに使うと、八王子→8王子 とか 三鷹→3鷹 という具合になります。
なので、こちらは単体で使うよりは、他の色々な処理と組み合わせて使っていくことが多くなると思います。

他の色々な処理について、またあとで書きます。




【その他の、住所の表記ゆれ対策シリーズ】
・[色んな横棒をハイフンにする](https://qiita.com/mori_toma/items/79e38a27f036d55d6165)
【個人開発】絶対炎上しないSNSを開発した

**自分の趣味趣向にとらわれず色々なつぶやきを見られる**ことが特徴の[Tsubusy](https://tsubusy.com/)というSNSをリリースしました！
9月ごろからコツコツ開発していて、色々紆余曲折あったのですがリリースできて安心しています。
現在京都大学情報学科に在籍していて、授業やバイトをやりながら開発するのはなかなか大変だと思うのですが、他の人ともこうした体験を共有できればいいなと思いまとめてみようと思います。

# リリースしたサービス
* [Tsubusy](https://tsubusy.com/)

# きっかけ
Twitterやfacebookなど色々なSNSがありますが、いつも自分の意見に似たような人ばかり表示されるという風に思ったことはないでしょうか？
Twitterには色々なツイートがあって、それは当然玉石混合なカオスな環境な訳ですが、その中から自分の想像もしなかったような内容をランダムに見られたらいいのになと思ったのがきっかけです。
また、[はてなの匿名日記](https://anond.hatelabo.jp/)を見て、こういう匿名性の高めなインターネットが懐かしくそれに近いSNSのようなものを作れないか、と思っていたところでした。

また、SNSを使っていて悪い方向でツイートがバズると**炎上**してしまったりネットリンチが起こってしまったりという問題点があるということもなんとかならないかなあと思っっていました。

そこで、返信が直接自分の投稿にぶら下がらないボトルレターのようなSNSを作ればいいんじゃないか？ということを思いつき、実際に実装していきました。

# 使用した技術
Ruby on Rails
Bootstrap
nginx
などなど・・・

# 内容・特徴
## トップページ
![スクリーンショット 2019-03-07 12.01.57.png](https://qiita-image-store.s3.amazonaws.com/0/274383/fc4c8ebc-aeea-cadb-c374-f50d872e5b24.png)
トップページはtwi○terを意識したシンプルなものにしました。
右側に表示されている投稿はランダムに表示されるようになっていて、リロードすると他のランダムな投稿が表示されるようになっています。

## ボヤージ機能
![スクリーンショット 2019-03-01 14.10.17.png](https://qiita-image-store.s3.amazonaws.com/0/274383/6179abb5-a310-9bb0-457c-7bb1472e839f.png)
ランダムに他の人の投稿を表示するボヤージ機能を実装しています。
これによって、上で言ったような自分の興味とは無関係に投稿を表示することができます。

## 表示画面
![スクリーンショット 2019-03-07 12.05.25.png](https://qiita-image-store.s3.amazonaws.com/0/274383/68ff36d2-3ce6-5792-d12a-71af38846be5.png)
各投稿についてはこういった感じで表示されるようになっています。
また、他の投稿に対してお気に入りボタン以外でレスポンスを返すことはできません。
なので、投稿した内容についてのレスポンスは基本的にはお気に入りの数だけでわかるということになります。
また、自分の投稿した内容が合計どれくらいお気に入りされているかはプロフィールから確認することができるので、それによって自分の投稿した内容がどれくらい見られているかがわかります。

## 投稿画面
![スクリーンショット 2019-03-07 12.07.45.png](https://qiita-image-store.s3.amazonaws.com/0/274383/0ce6c6fd-307e-6794-a34f-d0dd5a830429.png)
画面の左下の+ボタンを押すと投稿することができます。
このボタンはどこのページに遷移してもついてくるので、どのページからでも投稿することができます。


# 制作のあれこれ
フレームワークとしてdjangoや他のフレームワークを利用するということも考えられたのですが、WEBアプリケーションを作るのが初めてであったという点、日本語での情報が豊富であろうという点からRailsを選択しました。途中でなんども詰まるところがあったのでこれは良い選択だったのではないかと思っています。
また開発していて思ったこととして、やはり英語の情報が圧倒的に多いなということは確実に感じました。僕自身英語が全く読めないということはないのですが、どうしても日本語に比べて読むスピードが落ちてしまうことや専門用語などよくわからない単語が多く英語で読む負担が大きいのでできるだけ日本語での情報を求めてしまう傾向がありますね。

# 課題
正直デザインに関しては詰めきれていないというか、もっと良くできるのではないかなという気がしています。
それに加えて、自分の投稿に対するフィードバックを得づらいのではないかとも少し思っているので、そのあたりのバランスをもう少し考えていく必要があるのではないかなと思います。
[TIIPS] Azure Active Directory B2B で招待したものの、メールが受け取れない場合

短い記事で恐縮です。

Azure Active Directory B2B Collaborationという機能があります。俗にいう Azure AD B2Bってやつ。
他のAzure ADのユーザーを、こちら側のAzure ADにゲスト招待して、こちら側のアプリを使ってもらうっていうときに使います。

お初の方はサポートチームの坂井さんが書かれた記事をどうぞ。
https://blogs.technet.microsoft.com/jpazureid/2017/12/12/about-azure-ad-b2b/

招待されるとメールが送られて、そこに書かれたURLにアクセスしてサインインする必要があります。

しかし、一人でこの機能をテストしているときって、そうそうたくさんメールアドレスなんて持ってないから困るんですよ。

で、気づきました。こんな機能があることを。いまさらなんですけど。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/134539/c9ce1a1f-47fa-6aea-a260-84d7f55d96ed.png)

ゲストを招待した後、そのユーザーのプロファイルを開いて、再度「招待の再送信」をクリックすると、その上でインヴィテーションのURLが表示されるんです。

このURLを Inprivateモードか何かでブラウザを開けばログイン画面が表示されるので、そこからログインすれば招待完了！ってわけです。

いままで気づかなかったことが恥ずかしい。。。。
Django でいい感じのフロントエンド環境を作る


https://qiita.com/zakuro9715/items/ab925594227009251a60

この記事は上記のリメイク記事です。同じ内容を取り扱っています。

# はじめに

django では、デフォルトの場合フロントエンドのビルドに対するサポートがありません。

書いたファイルをそのまま使うのであれば問題ありません。しかし、sass や ts を使いたいときもありますし、minify 等も面倒を見てくれないため、ある程度以上の規模になると、何らかのビルド機構を導入することを考える必要が発生してきます。

本記事では、幾つかの規模ごとに、扱いやすい構成を考えます。

## バニラ - staticfiles

django には staticfiles という app が存在し、これが静的ファイルの配信を司っています。

django-admin 等の公式の app はこの形式です。適当なプロジェクトを作成してみるとわかりますが、django-admin の css は全く圧縮されていません。普通にデプロイすれば、本番環境でも同様です。

django の static は、デフォルトではそのまま配信されるだけです。collectstatic といった static ファイルを集める仕組みはありますが、それだけです。ファイル名さえ一致していればデプロイ時に手動で圧縮することもできますが、個人的にはおすすめしません。

## シンプル構成だがビルドはしたい - django_compressor

まずは django_compressor を導入することを検討しましょう。

django_compressor のメリットは、django の仕組みの上に簡単にビルドを構築できることです。テンプレートタグも提供してくれるため、staticfiles と変わらない感覚で使用できます。

使い方については [Quickstart](https://django-compressor.readthedocs.io/en/stable/quickstart/) を読むのが早いです。INSTALL_APPS と STATICFILES_FINDERS に追加するだけです。

テンプレートの中で使用すると、いい感じに圧 minify してくれます。目的が minify だけの場合はこれで OK です。

```
{% load compress %}

{% compress css %}
<link rel="stylesheet" href="/static/css/one.css" type="text/css" charset="utf-8">
<style type="text/css">p { border:5px solid green;}</style>
<link rel="stylesheet" href="/static/css/two.css" type="text/css" charset="utf-8">
{% endcompress %}
```

更に、django_compressor には precompile の仕組みがあり、これを使うことで sass 等をビルドすることができます。

COMPRESS_PRECOMPILERS を設定することで、任意のコマンドを使用してビルドすることができるようになります。

詳しくは[公式ドキュメント](https://django-compressor.readthedocs.io/en/stable/settings/#django.conf.settings.COMPRESS_PRECOMPILERS)を読んでください。なお、稀に相性の悪いコマンドも存在する模様ですが、ラッパスクリプトを手動で書くことで解決可能です[^1]。

[^1]: https://qiita.com/zakuro9715/items/98dcdf61e09a241a0eb0

## django から解き放たれて - npm

django の仕組みの上に乗れる django_compressor は便利なのですが、規模が大きくなると複雑になりすぎます。たとえば、webpack を precompilers に指定することは可能ですが、その設定ファイルの置き場所など、いろいろと考える必要があります。

結論から言えば、sass の用に単一コマンドでビルドできる規模よりも大きくなると、django_compressor は適さないと考えます。ビルドするという行為をシンプルに扱えるというメリットが薄れ、設定が肥大化します。

最終的には、django とフロントエンドを疎結合にするべきです。フロントエンドのファイルは npm で管理し、ビルドした生成物のみを django が扱う形にします。

また、規模が大きくなってくと、フロントエンド専任のエンジニアが発生するかもしれません。そのような場合において、フロントエンド環境が django の上に乗っていることは、単純にコストです。フロントエンドのファイルは django の上ではなく npm 環境で扱えるほうが、フロントエンドエンジニアの負担は小さくなるでしょう。

Django REST Framework 等を使用して SPA にする場合でも、この形式は採用することができます。

手順は簡単です。フロントエンド専用の app を作成し、その中で npm init します。あとは、npm で build するときの出力先を、app の static ディレクトリと共有させます。そうすることで、npm で build したものが、django 側からは staticfile として認識されます。

npm の環境については、お好みのものを使用するのが良いでしょう。webpack でも良いですし、今から始めるなら parcel というのもアリです。

ただし、この環境では、ファイルを更新するたびに手動でビルドをしならない点に注意してください。npm 側で watch するコマンドを作っても良いですが、static ディレクトリに必ず出力しなければいけないということを忘れないでください。フロントエンドの場合、開発用サーバーはファイルの出力先が違うケースがあります。

## 互いを忘れる - swagger

さて、私が検証しているのはここまでになります。しかし、更にフロントエンドと django を疎結合にするケースについても触れておこうと思います。

これまでのケースでは、あくまでフロントエンドのファイルは django の上に乗っていました。しかし、大きな SPA 等になれば、もはや django の上に乗っている必要はありません。

規模が大きい SPA になった場合、互いを API でつなぎ、swagger 等でインターフェースを共有して、疎結合に、別サービスのような形で切り出してしまうのが良いでしょう。リポジトリから分離してしまっても良いかもしれません。

# さいごに

django におけるフロントエンド環境のワークフローについて、一通りの考察をすることができました。もちろん、プロジェクトによって事情はいろいろですから、これをそのまま使うことができるとは限りません。

この記事がみなさまのより快適な開発環境の構築に役立てば幸いです。
Homebrewでupdateしたらremote: Repository not found.となった時の対応方法

- 環境
    - macOS Mojave version10.14.3

# 事象 : `brew update`したら`remote: Repository not found.`と言われた
```bash
$ brew update
remote: Repository not found.
fatal: repository 'https://github.com/Homebrew/homebrew-boneyard/' not found
Error: Fetching /usr/local/Homebrew/Library/Taps/homebrew/homebrew-boneyard failed!
Updated 2 taps (homebrew/core and homebrew/cask).
==> New Formulae
anyenv                  cafeobj                 entityx                 h3                      libopenmpt              re-flex                 sn0int                  ungit
## 省略
```

# 原因 : リポジトリがなくなったから
## そもそも`homebrew-boneyard`って誰？
boneyardは、日本語で**墓場**でした。
数多な理由で公式で使えなくしたコマンドとformulaを埋葬しているようです。
MySQLあたりを昔インストールしたときにでも使ったのだろう・・・

- [Homebrewでsitecopyはインストールできなくなったんや… - Qiita](https://qiita.com/ksworks/items/5e1fc047ba2bc716eb80)
- [brew bundleが使えなくなったのでとりあえず使えるようにした - Qiita](https://qiita.com/matsu_chara/items/78d0d0299a2f45270046)

## 対応 : リポジトリの参照を消す
[`brew tap`で公式以外のリポジトリをフォーミュラとしてHomebrewに追加できる](https://qiita.com/saa/items/85ed5e914d424fbf9fd6)とのことなのでその逆の[`brew untap`でなくなってしまったリポジトリを消します。](http://hsuzuki.hatenablog.com/entry/2017/02/23/142426)

```bash
# tapしているものを一応確認
$ brew tap
Updating Homebrew...
homebrew/apache
homebrew/boneyard # <<<<<<<<< この方を消す
homebrew/cask
homebrew/core
homebrew/dupes
homebrew/php
homebrew/science
homebrew/versions

# 消す
$ brew untap homebrew/boneyard
Untapping homebrew/boneyard...
Untapped (30 files, 23.2KB).

# 消されたことを確認する
$ brew tap
homebrew/apache
homebrew/cask
homebrew/core
homebrew/dupes
homebrew/php
homebrew/science
homebrew/versions

# 怒られなくなる
$ brew update
Already up-to-date.
```

### が、doctorに「非公式なとこtapしてるからuntapしてみ」って注意されるので全部`untap`する
この間まで、こんな事言われなかったような・・・まぁいいか

```bash
$ brew doctor
Please note that these warnings are just used to help the Homebrew maintainers
with debugging if you file an issue. If everything you use Homebrew for is
working fine: please don`t worry or file an issue; just ignore this. Thanks!

Warning: You have the following deprecated, official taps tapped:
  Homebrew/homebrew-dupes
  apache
  science
  php
  versions
Untap them with `brew untap`.

$ brew untap Homebrew/homebrew-apache
Untapping homebrew/apache...
Untapped (104 files, 95.8KB).

$ brew untap Homebrew/homebrew-science
Untapping homebrew/science...
Untapped (303 files, 11.7MB).

$ brew untap Homebrew/homebrew-php
Untapping homebrew/php...
Untapped (278 files, 4.6MB).

$ brew untap Homebrew/homebrew-versions
Untapping homebrew/versions...
Untapped (106 files, 699KB).

# やっと静まった・・・
$ brew doctor
Your system is ready to brew.
```
[ http ] から [ https ] へ301リダイレクト設定

#「301リダイレクト」とは
サイト引っ越しやSSL化でURLが変更したとき、元々のページの Googleの評価を引き継いだまま、ユーザーを転送できる！


#httpからhttpsへリダイレクトさせる

```
RewriteEngine on
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://exapmle.com/$1 [R=301,L]
```
1行目：リダイレクト機能を有効にする
2~3行目：httpsでなければhttpsにする。

【用語】
*`RewriteEngine On`リダイレクト機能を有効にする
*`RewriteCond`条件に合致したら、`RewriteRule`を実行する。
*`R=301`=301リダイレクト

上の記述だと、
`http://exapmle.com/`
`http://www.exapmle.com/` のどちらでアクセスしても
**`http://exapmle.com/`** にリダイレクトする。

※エックスサーバー はwwwありなし、デフォルトでどちらのURLもアクセスできる仕様。
`http://www.exapmle.com/`を直打ちでアクセスすると、そのまま表示されてしまう。

リダイレクト先URLのwww有無をどちらかに統一させたい場合↓↓

#1.www無しのhttpsのURLに統一する場合
以下コードを.htaccessに記述する。

```
RewriteEngine on
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://exapmle.com/$1 [R=301,L]
RewriteCond %{HTTP_HOST} ^(www\.exapmle\.com)(:80)?
RewriteRule ^(.*) https://exapmle.com/$1 [R=301,L]
```
1~3行目：httpsへリダイレクトさせる記述。
4~5行目：www無しに統一する記述。

#2.www有りのhttpsのURLに統一する場合
以下コードを.htaccessに記述する。

```
RewriteEngine on
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://www.exapmle.com/$1 [R=301,L]
RewriteCond %{HTTP_HOST} ^(exapmle\.com)(:80)?
RewriteRule ^(.*) https://www.exapmle.com/$1 [R=301,L]
```
1~3行目：httpsへリダイレクトさせる記述。
4~5行目：www有りに統一する記述。
nginx + djangoで adminページのsvgが表示されないやつを直す

# 初心者です
nginxとかに関しては全くの初心者で、そんな中引っかかった問題を書く。

# 環境
Docker: 2.0.0.3
django: 2.1.7
nginx: 1.15.9

# 問題
* なんとかDockerでdjango + nginx + postgreの環境を整えて、デフォルトページが表示できた。
* cssとかは動いているのにsvgだけ読み込まんのはなんで？？？？

# わかったこと
* nginx側で静的ファイルをいい感じに振り分けていた。(djangoで/static/...のURIだったときはnginxの方にリクエストを流す)
* どうやら`mime.types`というファイルに、レスポンスするファイルのMIMEをすべて書き連ねないといかんらしい。
* そうしないと`nginx.conf`で設定されている `application/octet-stream` でヘッダが組まれてしまいいい感じにやってくれない

↓どっからかコピペした`nginx.conf`

```conf:nginx.conf
...略
http {
    include /etc/nginx/mime.types;
    default_type application/octet-stream;
    access_log /tmp/nginx.access.log combined;
    sendfile on;
    ...全略
}

```

どうやらmime.typesに書かれていないMIMEが要求された時、ここの`default_type`とやらに勝手になってしまって、正常にMIMEを認識してくれない -> svgとして読み取らんからレスポンスが無い。

というわけでまたまたどっかからコピペしたmime.typesにsvgのMIMEを調べて追加

```text:mime.types
types {
    text/html                             html htm shtml;
    text/css                              css;
    text/xml                              xml rss;
    image/gif                             gif;
    image/jpeg                            jpeg jpg;
    image/svg+xml                         svg;    # <-ココ
    application/x-javascript              js;
    text/plain                            txt;
}
```

無事にsvgが表示されるようになったとさ
ラスボス系後輩ヒロインAIチャットボットを作りたい・Pythonの基礎②

※この記事はQrunchにもクロス投稿しています。
[前回](https://qiita.com/perpouh/items/30ae963561b5fdacd565)の続きから行きます。

そういえばRubyで `str[n]` を見たときはぎょっとしたんですけど、あれ考えてみればchar[]の扱いをStringに取り込んだだけなのでそんな変な動きでもないですね。char[]の存在自体忘れてたけど……char\*とか懐かしすぎる……

## リストとタプルと辞書と集合

|名前|書式|注釈|
|---|---|---|
|リスト|[val]|順番が保証される。重複した値も許可する。上書き可能。|
|タプル|(val)|順番が保証される。重複した値も許可する。上書きできない。|
|辞書|{key:val}|順番は保証されない。キーが一意となる。上書き可能。|
|集合|{val}|順番は保証されない。重複した値は入らない。上書き可能。|

「二通りの意味でPythonicな」という記述に首を傾げてコードを眺めていたのですが、なるほどMonty PythonとPythonのダブルミーニングか……
Monty PythonはあれかなイギリスのTeam Nacsって認識でいいかな。怒られるかな。

タプル、一回読んだだけだとちょっと理解できなかったけどPHPのlist()みたいなことができると思えばだいたい合ってるっぽい？

```php
php > $arr = ['ruby', 'diamond', 'perl'];
php > list($a, $b, $c) = $arr;
php > echo $a;
ruby
php > echo $b;
diamond
php > echo $c;
perl
```

```python
>>> a, b, c = {'ruby', 'diamond', 'perl'}
>>> a
'ruby'
>>> b
'diamond'
>>> c
'perl'
```

ただケツカンマだけはちょっと受け付けない。まあ要素一個のタプルなんて使わないでしょうし別にいいけど。
可変長の引数を取る関数には `*args` てきなことをやるらしい。

リストの方はざっと見た感じ「どう書いても動くな……」という印象。`index, count, join, sort, len, copy` と欲しいものがだいたいあり、脳死状態で書いても安定して動いてくれそう。
中でも「マーベラス！！！」とテンション爆上げ&内心スタンディングオベーションしたのが `in` 構文。

```python
>>> 'fizz' in ['hoge', 'fuga', 'poyo']
False
```

この構文すっごい素敵。エンジニアの手に馴染みやすく英語としてそのまま読み下すこともできる！　最強では？！　好き！

辞書はだいたい連想配列、ハッシュマップと似たようなものなので違和感も疑問も特に無い。dict()を使った変換はCSV読み込みあたりで使いそう？

```php
foreach($line as $key => $val){
  $arr[$key] = $val;
}
```

みたいなこと書かないで済むのは地味に便利っぽい。
辞書のupdate関数はなんでupdate？　と思ったけど要は「Aの辞書をBの辞書で上書きする」みたいなことだと思えばよさそう。Bの辞書に無いものは上書きされない。
こちらも`del, keys, values, items, copy` と大体必要そうなものが揃っていて便利っぽい。updateがあってinsertが無いのちょっともやっとするけど。

集合は数学の集合だと思えばいいらしい。和集合、差集合、積集合、排他的論理和などが取れる。

|名前|記号|例|意味|
|---|---|---|---|
|和集合|&|a & b||
|積集合|｜|a｜b||
|差集合|-|a-b||
|排他的論理和|^|a^b||
|部分集合|<=|a<=b|aはbの部分集合である|
|真部分集合|<|a<b|aはbの真部分集合である|
|上位集合|>=|a>=b|aはbの上位集合である|
|真上位集合|>|a>b|aはbの真上位集合である|
半角パイプ入れられなかった……

```
>>> language = {'python', 'ruby', 'perl', 'java'}
>>> gem = {'sapphire', 'ruby', 'diamond', 'quartz'}
>>> language & gem
{'ruby'}
>>> language ^ gem
{'diamond', 'perl', 'quartz', 'python', 'sapphire', 'java'}
>>> language | gem
{'diamond', 'perl', 'quartz', 'python', 'ruby', 'sapphire', 'java'}
>>> language < gem
False
```

というわけで割合サクッと三章が終わってしまった（見積もりが下手！）ので四章に行きます。
GooglePlayにAppBundleをコマンドでアップロード

前回の[「deploygateにapkをコマンドでアップロード」](https://qiita.com/kaikecchi/items/641dd3b97e04e7ead801)に続き、GooglePlayへの本番アプリのリリースも自動化にも取り組みました。
今まではAndroidStudio上の操作でAppBundleファイルを作成し、GooglePlayへのアップロードは手動でやっていましたが、作業の効率化やミス防止やCI導入を見据えて一連の作業をコマンド化しています。


# AppBundleの導入

AppBundleの詳細については[こちら](https://support.google.com/googleplay/android-developer/answer/9006925)。すでに導入している場合はスキップしてください。


##### 1. アプリ署名への登録
GooglePlayConsoleを開き、「登録するアプリ > リリース管理 > アプリの署名」を選択します。利用規約が表示されるので、内容を確認して問題なければアプリを登録しましょう。

##### 2. 秘密鍵のエクスポートと暗号化
まだ秘密鍵をエクスポートしていないと思うので、まずはエクスポートと暗号化を行います。合意後に表示されている画面の指示に従い、PEPKツールをダウンロードしましょう。PEPKツールで既存のkeystoreから秘密鍵のエクスポートと暗号化をおこないます。

```
$ java -jar pepk.jar --keystore=foo.keystore --alias=foo --output=encrypted_private_key_path --encryptionkey=xxxxxxxxx
```
##### 3. 暗号化された秘密鍵をアップロード
出力されたencrypted_private_key_pathを表示されている画面上のボタンからGooglePlayへアップロードします。新たにアップロード鍵を生成して使用する場合は[こちら](https://developer.android.com/studio/publish/app-signing.html?hl=ja#sign-apk)を参考に。


# gradle-play-publisherの導入

GooglePlayへのアップロードには、[gradle-play-publisher](https://github.com/Triple-T/gradle-play-publisher)を利用します。

##### 1. GooglePlayConsoleとGoogleAPIConsole上のプロジェクトをリンク

GooglePlayConsoleの「設定 > APIアクセス」を開き、プロジェクトをGooglePlayにリンクさせます。プロジェクトが表示されない場合はGoogleAPIConsole上で新規作成し、GooglePlayAndroidDeveloperAPIを有効にしましょう。

<img width="998" alt="スクリーンショット 2019-02-28 14.51.22.png" src="https://qiita-image-store.s3.amazonaws.com/0/315759/fd29aba4-c293-29e5-a80a-27d5d73da11a.png">


##### 2. サービスアカウントキー（JSON）のダウンロード
続いて表示されている画面の「サービスアカウントを作成」ボタンをクリックし、GoogleAPIConsoleでのサービスアカウント作成に進みます。画面の指示に従いサービスアカウントを作成したら、「認証情報 > 認証情報の作成 > サービスアカウントキー」　にてサービスアカウントキー（JSON）をダウンロードします。

<img width="544" alt="スクリーンショット 2019-03-01 13.54.47.png" src="https://qiita-image-store.s3.amazonaws.com/0/315759/583cf1f3-bfb6-8cd8-79b5-64e33a04cd19.png">


##### 3. 作成したサービスアカウントからのアクセスを許可
作成が完了するとGooglePlayConsoleの画面上の「サービスアカウント」欄に作成したサービスアカウントが表示されます。「アクセスを許可」ボタンから適切な権限を設定しましょう。

##### 4. build.gradleの設定
app下のbuild.gradleに記述を追加します。

``` build.gradle
plugins {
    id 'com.android.application'
    id 'com.github.triplet.play' version '2.1.0'
    ...
}
```

ダウロードしたサービスアカウントキー（JSON）をAndroidプロジェクトの適当な場所に配置し、serviceAccountCredentialsで指定します。以下ではbeta版向きにしていますが、製品版をアップロードする場合はtrackをproductionにします。

``` build.gradle
play {
    serviceAccountCredentials = file("your-key.json")
    track = "beta"
}
```


# GooglePlayへのアップロード

コンソールでプロジェクト直下に移動し、まずは以下のコマンドでGooglePlayに登録している画像等のリソースをダウンロードしましょう。

```
./gradlew bootstrapReleasePlayResources
```

GooglePlayに登録してある画像等を変更したい場合は、リソースを更新して以下のコマンドでアップロードできます。

```
./gradlew publishListingRelease
```

いよいよAppBundleをGooglePlayへアップロード！

```
./gradlew publishReleaseBundle
```
※productFlavorsを利用している場合はタスクもそのBuildVariantに合わせましょう。`./gradlew tasks`で確認できます。

以上、簡単アップロードでした (^o^)/
良サイトを置くだけ

#プログラム
[SOURCE MAKING](https://sourcemaking.com/)
[neue.cc](http://neue.cc/)
#ゲーム
[マルペケつくろーどっとコム](http://marupeke296.com/index.html)
[Indie Gamer Forums](http://forums.indiegamer.com/)
#ドキュメント
[C# プログラミングガイド](https://docs.microsoft.com/ja-jp/dotnet/csharp/programming-guide/index)
#英語
[codic](https://codic.jp/engine)
マルチスレッドの勉強→OSの作り方
iPadで10回パスワード入力を間違えて「iTunesに接続してください」状態になったときの復旧方法

## 参考

* [iPad/iPhoneのパスワードを10回間違えた時の初期化・復元方法](http://yattokoo.com/ipad-recovery)

## 対応

* 「iTunesに接続してください」とのことでiTunesに接続するも、接続したことのないPCにつないだところで以下となる。

![2.jpg](https://qiita-image-store.s3.amazonaws.com/0/25728/1bd020b2-eeb9-36ff-4f5b-66d71d2ebadf.jpeg)


### iPadをリカバリーモードにして初期化

* 初期化。

### iCloudからデバイスを削除

* [「iPhoneを探す」をオフにできない時の対処法:図説](http://iphone-sagasu-off.seesaa.net/)

「iPhoneを探す」からオフにしないと、iPadがロックかかったままになる。
PCからiCloudにログインし以下のように x をクリックし削除する。

![1.png](https://qiita-image-store.s3.amazonaws.com/0/25728/4327f758-55ba-3ffc-a027-0467bc186fb0.png)

これでiPadが使えるようになる。
弟が引っ越しに手間取っていた話...それ今の技術でなんとかならんのか？！

# 弟が引っ越しでてんてこ舞いだったんすわ。

この春から新社会人になる3人兄弟の末っ子の弟。不動産屋に足を運んでいい物件を見つけ、意気揚々とそこに決定したようです。しかしその後の手続きで一悶着と言わず2, 3問題点があったらしいのです。それを今(もしくは近未来)の技術でどうにかできないか？との思いに至り、この記事を作成しました。

## その1, 「携帯電話の番号がないので、契約はなかったことに...」
これを家族のグループラインで見たときの私の素直な感想は「そんなことあるんだ？！」でした。そう、様々なコミュニケーションが跋扈するこの現代社会で、弟はSlack(時々LINE)を主に連絡手段としているのです。携帯電話の番号を持たずとも、普段は連絡を取り合えるのだからまぁ良いか、と本人も考えていたようです。私もその意見には賛同しつつも、一方で「やっぱり緊急連絡手段は持っておいたほうが良いのでは」との懸念もありました。私の兄に至っては「電話番号がないからという理由は草」と笑っていましたね。
急いで携帯電話の契約手続きをし、ことなきを得た弟。しかしながらこの時点で沸々と私の疑問が湧き上がってきます。

***AIだのなんだの言ってる現代社会において、前時代的ではあるまいか？***

### それ、ブロックチェーンでどうにかなりませんか？

と、思うわけです、ブロックチェーンエンジニアの皆様。ブロックチェーン技術を使えば、取引は基本ネットワーク上で個人情報等を記録・検証ができるわけですから、これを使わない手はないのではないか、との考えに至ることは当然のようにも思います。
(ブロックチェーンについては勉強不足な部分が多々あるため、間違いなどありましたらどしどしコメントください)

## その2, 「引っ越し業者にわざわざ見積もり取らなきゃならんとか超めんどくせぇ。」

修論などの追い込み作業で忙しい日々を送っている弟にとっては、業者を選ぶとか値段の交渉とか、そんなことで時間を取られている余裕はないのです。そんな弟から吐いてでたようなセリフがこれでした。これには私も激しく同意しました。これに対しては、その弟から現在の技術でなんとかできるような意見が出てきました。

***スマホで撮った写真から荷物の量を見積もるとかできそうだよね？***

### すでに画像認識でそういう技術はあるのでは？

画像認識が脚光を浴びている昨今、それくらいのことはできそうな気がします。物体を検知し、その物体のカテゴリーから、大きさ・重さなんかは簡単に見積もれそうな予感がします。段ボールに詰められた荷物ならなおのこと、段ボールの大きさという規格があるわけですから、それを積み上げたものをスマホでパシャっとするだけで、どれくらいの量を運ぶ必要があるのか(何トントラックが必要なのか)ぐらいは簡単に割り出せそうですね。

## その3, 「住民票と今住んでいるところが違うからやっぱり不動産契約はなかったことに...」
これは住民票を変えていなかったり、家庭事情が複雑な我が家の問題でもあるのですが...これを解消するために、わざわざ住民票を取りに行ったり、転入・転出届を出しに行ったりしておりました。前述のように、平日・休日問わず研究に勤しむ弟にそんな暇はなく、母を巻き込んでの役所手続きとなったようです。ここでも私の疑問が浮かび上がってきます。

***結局、マイナンバーはどうなった？***

### 確かマイナンバーは面倒な行政手続きを簡易なものにするものだったはずでは？
平日に役所に届け出ないといけないということを考えると、「結局マイナンバーとはなんだったのか...」という気持ちにもなります。国民一人一人を識別するためのナンバリングも、インターネット等で気軽に更新できなければ無用の長物というものです。ここら辺はエストニアあたりを早く見習った方が、幸せな日本社会が目指せそうに思います。

## 結論と雑言
今ある(もしくは実現が目前に迫っている)技術を使えば、もっと住み心地の良い社会になると、私は信じています。「TPOとか糞食らえ、俺は自由だ」をモットーに生きる私としては、早くこのような煩わしい手続き社会からの解放を、いち早く望みます。
差分を求める

Rubyには差分を求めるライブラリが存在する

```rb
require 'diff/lcs'
```

`Diff::LCS.diff(A, B)`: 配列の要素に差があれば差分をとる

```rb
Diff::LCS.diff([2, 3, 4, 'b'], [1, 2, 3, 'a', 'b'])
#=> [[["+", 0, 1]], [["-", 2, 4], ["+", 3, "a"]]]
```

`Diff::LCS.sdiff(A, B)`: 配列の要素１つごとに差分があるかを返す

```rb
Diff::LCS.sdiff([2, 3, 4, 'b'], [1, 2, 3, 'a', 'b'])
#=> [["+", [0, nil], [0, 1]], ["=", [0, 2], [1, 2]], ["=", [1, 3], [2, 3]], ["!", [2, 4], [3, "a"]], ["=", [3, "b"], [4, "b"]]]
```

`Diff::LCS::Change`オブジェクトに使えるメソッド

`:<=>`, `:==`, `:inspect`, `:to_a`, `:new_element`, `:old_position`, `:new_position`, `:old_element`, `:changed?`, `:action`, `:adding?`, `:deleting?`, `:unchanged?`, `:finished_a?`, `:finished_b?`, `:<`, `:>`, `:<=`, `:>=`, `:between?`, `:tap`, `:public_send`, `:instance_variables`, `:instance_variable_set`, `:instance_variable_defined?`, `:remove_instance_variable`, `:private_methods`, `:kind_of?`, `:is_a?`, `:instance_variable_get`, `:instance_of?`, `:public_method`, `:extend`, `:define_singleton_method`, `:singleton_method`, `:to_enum`, `:enum_for`, `:===`, `:=~`, `:!~`, `:eql?`, `:respond_to?`, `:freeze`, `:display`, `:object_id`, `:send`, `:to_s`, `:method`, `:nil?`, `:hash`, `:class`, `:singleton_class`, `:clone`, `:dup`, `:itself`, `:taint`, `:tainted?`, `:untaint`, `:untrust`, `:trust`, `:untrusted?`, `:methods`, `:protected_methods`, `:frozen?`, `:public_methods`, `:singleton_methods`, `:!`, `:!=`, `:__send__`, `:equal?`, `:instance_eval`, `:instance_exec`, `:__id__`
CでRubyの拡張ライブラリを作った

#はじめに
この記事を書いた人間は**プログラミング歴1年以下**の超がつくレベルの初心者です。
ところどころ分かりにくいところや間違いがあると思いますのでお気づきになった際にはコメントを残してくださると幸いです。
#作ったもの
Rubyからマウスを操作するための拡張ライブラリ
#使った言語
 - C(ライブラリ本体を記述)
 - Ruby(モジュール)
#概要
ソースコードは[こちら](https://github.com/TakamitsuMaruo/Win32-mouse-keyboard)


 - マウスカーソルの座標を取得したり、カーソルを動かしたりできます。
 - 左クリックと右クリックを出力することも可能です。
 - Cのwindows.hをインクルードしているので**Windows専用**です。(Windows以外の環境が手元にないため未検証ですが恐らくそうです)
 - 32bitの環境でコンパイルしているので**64bitのマシンでは動作しません**。(検証済み)
 - 環境が整ったら64bit版も上げようと思います。
 - **Rubyが動作する環境でご利用下さい**。

#使い方
`require 'mouse' `
または 
(このライブラリを利用するスクリプトが同じディレクトリにある場合)
`require_relative 'mouse'`
#定義されているメソッドと定数
- `getCursorPosX()`
    - カーソルのX座標を取得します。  
- `getCursorPosY()`
    - カーソルのY座標を取得します。  
- `setCursorPos(x,y)`
    - カーソルの位置を移動します。第一引数が移動先のX座標、第二引数はY座標を指定してください。  
- `sendMouseEvent(key)`
    - マウスの左右ボタンの仮想キーコードを出力するメソッドです。
    - 引数には整数または以下の定数を渡してください。  
        - `M_L_DOWN (= 2)`     #マウス左ボタンが押された状態  
        - `M_L_RELEASE (= 4)`  #マウス左ボタンが離された状態  
        - `M_R_DOWN (= 8)`     #マウス右ボタンが押された状態  
        - `M_R_RELEASE (= 16)` #マウス右ボタンが離された状態  
- `getKeyState(key)`
    - マウスまたはキーボードの特定のキーが押されているかを調べます。
        - このメソッドは現在開発中のキーボードを操作するためのライブラリでも実装する予定です。
    - 指定されたキーが押されていないときは0,押されているときはそれ以外の整数を返します。
    - 引数には整数または前項の定数を渡してください。
- `is_cursor_moving?(arg = 0.001)`
    - 引数に指定された間隔でカーソルの位置を比較します。単位は秒です。
    - 戻り値は、移動していれば`true`,していなければ`false`です。
    - そのため、`arg`の値が大きいとカーソルが移動しているか正しく判定できない場合があります。
Cloud9で新規環境を作成できなかった

オレゴンでCloud9の環境作成しようとすると、そのAvailabilityZoneはサポートしていないぜって言われるんだけどなんだこれ。前まで作れたのに突然どうした。

# エラーメッセージ
The AWS CloudFormation stack aws-cloud9-XXX failed with the error: Your requested instance type (t2.micro) is not supported in your requested Availability Zone (us-west-2d).Please retry your request by not specifying an Availability Zone or choosing us-west-2c, us-west-2a, us-west-2b. (Service: AmazonEC2; Status Code: 400; Error Code: Unsupported; Request ID: XXX).

# 直訳すると
AWS CloudFormation でエラーが起きたよ。
t2.microはあなたのAvailability Zone(us-west-2d）でサポートされていないよ。
us-west-2a〜cのどれかを選んでね。

# 原因
Cloud9を構築したVPCのサブネットに原因あり。
VPCを作成するときにサブネットのAZを「指定なし」にしていると、「d」にできあがる。

多分、2dは最近できあがったから期間限定のエラーなのだと思うけど、
ネットを調べても情報がなかったので残しておく。
RailsをGoogle App Engine(Flexible Environment)で動かしてみた感想

2018年末に仕事でGoogle App Engine(GAE)のRailsアプリをリリースしました。

個人としても会社としてもGAEでRailsアプリをリリースするのは初めてだったので、動かしてみた感想などを共有したいと思います。

## 利点

- 手軽に始められる
- httpsのアプリで動かせる(オレオレ証明書とか必要ない)
- デプロイの安定感が高い(イミュータブルデプロイメント)

### 手軽に始められる
なんといってもこれが大きいです。
基本Flexible Environment(FE)はdockerで動くようにコードを書いてれば動くので、app.yamlという設定ファイルだけ用意してdeployすればすぐ動いてくれます。

```app.yaml
env: flex
runtime: custom
service: default
automatic_scaling:
  min_num_instances: 1
```

お手軽さはherokuとほぼ変わらず、GCPの事前知識不要でだいたい動かせるのが魅力です。
(最近のherokuを使っていないので、比較はできないですけども...)

### httpsで動かせる
ローカルでの開発ではオレオレ証明書とか色々考えないといけません。
が、GAEはhttpsのドメインを払い出してくれるので特に考えずにhttpsにできます。

プロジェクトではfrontendにReact.js、backendにRailsという構成で、それぞれ別の人が開発するスタイルだったのですが、それぞれhttps対応するのに手間がかからなかったので結合もスムーズにいけました。

### デプロイの安定感が高い

イミュータブルデプロイメントというらしいですが、GAEはバージョンごとに不変な環境を構築し、トラフィックの向き先をバージョンに割り当てられるようになっているため、安定したデプロイがしやすかったです。

<img width="907" alt="スクリーンショット 2019-03-01 11.33.29.png" src="https://qiita-image-store.s3.amazonaws.com/0/5964/27d54b81-7983-7008-290f-1c012771144b.png">

既存で動いている環境を上書きしたりしないので、新しいバージョンにバグがあってもすぐトラフィックを前のバージョンに戻すことが出来たり、そもそもバージョンごとにURLが割り当てられるので、出す前のバージョンの動作確認をしてから切り替えることができました。

ブルー・グリーンデプロイメントに似てますが、ブルー・グリーンの2環境だけでなくバージョンの数だけ環境を持つことができる点ではこちらの方がより柔軟性が高いです。

またトラフィックを流す割合も設定できるので、カナリアリリースやA/Bテスト的な使い方もできるのも良さそうです（実際にはまだ試していないですが)。

## 欠点

いいところもありますが、もちろん欠点もあります。

- FEはdeploy超遅い。10分弱かかる
- SSHはできるけど、ちょっとの修正がめんどくさい
- 一番弱いインスタンスだと、rails consoleがメモリ不足でたまに落ちる
- トラフィックを受けないプロセスを動かすのはややこしい

### deploy遅い & ちょっとの修正が面倒

これが割とつらいです。やばいミスった直そうというときにdeployに時間かかってしまって開発のスピードが出ません。
Standard Environmentは早いらしいんですが、FEだと時間がかかることが多いようです。

上で書いたイミュータブル環境なおかげで(?)SSHで入っても書き換えで再構築ができないので、再deployする必要があって10分ほど待たされてしまいます。

### rails consoleメモリ問題

単純に少しいいインスタンス使えばいいとは思いますが、rails server起動した状態でrails consoleやろうとするとメモリ不足で立ち上がってくれなかったりしました。

### トラフィックを受けないプロセスを動かすのはややこしい

web serverのプロセスはGAEと相性がいいですが、例えばsidekiqなどのバッチのプロセスなどとはちょっと相性が悪そうです。

当たり前ですが、単純に起動しているインスタンスがある=プロセスが動いてます。

そのため、画面上トラフィック割り当てされてなくてもインスタンスさえ起動していれば、過去のバージョンであっても動いてしまっています。

特にsidekiqなどはredisのキューを見てプロセスが順次処理を実施していくので、過去のバージョンが残ってしまっているとたまにコード修正したのに直ってない！みたいな罠に陥ることがあります。

ということでバージョンを停止してからdeployすると、今度は一時的にダウンタイムが発生してしまうことになってしまいます。

トラフィック切り替えのように厳密に切り替わるわけではないので、重複期間を許すか、ダウンタイムを許すかはプロセスやサービスの仕組みごとに考えるほうが良さそうです。

というかそもそもGAEと相性が悪そうですね。

## まとめ

最初始めるのはいいですが、慣れてきたらCI/CDがうまくできる環境に移行していくと開発のスピードを維持できそうです。

一方デプロイはやりやすいので、本番でうまく使うのは良さそうですね。
リストビューの共有に設定したロールが削除されると「自分にのみ表示」に切り替わる

タイトルのまんまですが、リストビューの公開範囲に設定したロールを削除したらどうなるのか検証したので残しておきます。
出くわす場面は少ないと思いますが、「ロールを設定していたはずが切り替わってる！？」といったときに思い出していただければ幸いです。
まず、あるロールに対して共有したリストビューを作成します。
![view1.PNG](https://qiita-image-store.s3.amazonaws.com/0/260521/85def2c3-3302-4254-66cb-f50b5a58d9f4.png)
そしてロールを削除します。
すると以下のように「自分のみがこのリストビューを表示できる」に自動で変更されました。
![view2.PNG](https://qiita-image-store.s3.amazonaws.com/0/260521/e103de21-87ba-97cb-397d-015f6f8abf82.png)
当然かもしれませんが、ロール&内部下位ロールでも同様です。
以下のようなロール構造で、上位ロールのほうを削除したら勝手に下位ロールに共有されないかなと思って試しましたが、そもそも下位ロールが紐づいている上位ロールは削除できませんでした。。。

テスト上位ロール
&ensp;├ &ensp;テスト下位ロール1
&ensp;└ &ensp;テスト下位ロール2

また、こちらも当然ですが同じロール名を作成しても設定が元に戻ったりはしませんでした。

以上となります。
それでは、よいSalesforceライフを( ^_^)/~
WindowsにCorretto8をインストールする

# WindowsにCorretto8をインストールする

OracleJDK から Amazon Correttoに移行するかもしれないので、Windows10 に Corretto 8をインストールした際の手順を残します。おそらくWindows7でも同じ手順でインストールできると思います。

Macの場合は、こちらの記事が参考になりました。
[[Java]Amazon Corretto8のインストール](https://qiita.com/lc-tsuchiya/items/3776e1c1ecadb4dc5b99)


# Corretto とは？

Amazonが実装したJDK（Javaの開発に必要なツールのキット）です。Javaコミュニティのお墨付きを得ており、Java SE（Java標準仕様）との互換性が保証されています。

Amazon Linux 2, Windows, Macでの利用が可能であり、今後、対応OSは更に増える予定です。



# Corretto 8 とは？

Amazon Corretto 8 は Java 8 用のJDKです。少なくとも2023年6月まで無償のサポートがあります。



# インストーラーのダウンロード

こちらからCorretto 8のインストーラーがダウンロードできます。

https://docs.aws.amazon.com/ja_jp/corretto/latest/corretto-8-ug/downloads-list.html

![image.png](https://qiita-image-store.s3.amazonaws.com/0/221845/15f94d81-4c8c-536d-8666-24612907daae.png)

私の環境はWindows 64bitなので、 **amazon-corretto-8.202.08.2-windows-x64.msi** をダウンロードします。
Windows 32bitなら、お隣の **Windows x86** の方からダウンロードすればよいと思います。

ちなみに、JREというのがありますが、こちらにはコンパイラが入っていません。開発用途ならJDK版が必要です。（JRE版でもJVMやAPIは入っています）



# インストーラーの実行

インストーラーをダブルクリックすると、ウィザードが起動します。画面に従って進めていきます。

![Corretto01.PNG](https://qiita-image-store.s3.amazonaws.com/0/221845/acfdba4d-5244-4644-f707-92527e167254.png)
![Corretto02.PNG](https://qiita-image-store.s3.amazonaws.com/0/221845/0385e748-ef7d-450c-f42a-450db3f10242.png)
![Corretto03.PNG](https://qiita-image-store.s3.amazonaws.com/0/221845/31615a63-d712-bdef-e99e-1dc39f7d4db7.png)
![Corretto04.PNG](https://qiita-image-store.s3.amazonaws.com/0/221845/78c65dbc-bc57-84e2-6c7f-9cd41f819594.png)
![Corretto05.PNG](https://qiita-image-store.s3.amazonaws.com/0/221845/252f3cf5-08ba-1e25-ecfe-1bbcf0486000.png)

ここまでくればインストール完了です。

デフォルトのままなら、以下のパスにインストールされます。

```
C:\Program Files\Amazon Corretto\jdk1.8.0_202
```



# 環境変数を設定する

## シェルがコマンドプロンプトの場合

まず、 `JAVA_HOME` を確認します。

上記のインストール作業によって、自動的にシステム環境変数に `JAVA_HOME` が追加されるはずです。過去に他のJDKを利用していて、もともと `JAVA_HOME` が存在する場合は、値が上書きされます。

正しく設定されたかどうか、以下のコマンドで確認しましょう。

```
echo %JAVA_HOME%
```

`C:\Program Files\Amazon Corretto\jdk1.8.0_202` と表示されれば成功です。

次に、システム環境変数 `Path` の先頭に以下を追加してください。

`%JAVA_HOME%\bin`

過去に他のJDKを利用していて、もともと追加済みの場合は、この作業は不要です。



## シェルがGit Bashの場合

コマンドプロンプトだけでなく、シェルとしてGit Bashも利用している場合、そちらの環境変数は手動で設定する必要がありますので、その手順を書きます。

まず、 `%USERPROFILE%\.bash_profile` をテキストエディタで開きます。なければ作ります。

最終行の後に以下を追加し、保存します。既に `JAVA_HOME` がある場合は `=` の右辺を書き換えます。

```
# Java
export JAVA_HOME='/c/Program Files/Amazon Corretto/jdk1.8.0_202'
export PATH=$PATH:${JAVA_HOME}/bin
```

Git Bashを再起動して、以下のコマンドで正しく設定されたかどうか確認しましょう。

```
echo $JAVA_HOME
```

`/c/Program Files/Amazon Corretto/jdk1.8.0_202` と表示されれば成功です。



# Javaのバージョンを確認する

コマンドプロンプト（またはGit Bash）でJavaのバージョンを確認します。

```
java -version
```

以下のように表示されれば、インストール成功です。おつかれさまでした。

```
openjdk version "1.8.0_202"
OpenJDK Runtime Environment Corretto-8.202.08.2 (build 1.8.0_202-b08)
OpenJDK 64-Bit Server VM Corretto-8.202.08.2 (build 25.202-b08, mixed mode)
```



# 他のJDKに切り替える

システム環境変数の `JAVA_HOME` の値を、他のJDKのインストールパスに変更するだけで、切り替えはできるはずです。

例えば、OracleJDKが `C:\Program Files\Java\jdk1.8.0_172` にインストールされているのであれば、 `JAVA_HOME` にそのパスを指定すれば、CorrettoではなくOracleJDKが有効になります。



# さいごに
結構、簡単に導入できました。
既存のJavaプロジェクトで動作確認しましたが、特に問題はありませんでした。
UE4のデストラクタについて

# よくある問題
ゲームの実装にアクター（Actorクラス）や、
アクターコンポーネント（ActorComponentクラス）を使用すると思います。
これらを破棄するにはDestroyを使用すると思います。

```cpp:Actor
// e.g.
AACtor* Alice;
:
Alice->Destroy(); // ここでデストラクタは呼ばれ…？
```

**実はこの場合、Destroy時にすぐデストラクタは呼ばれません。**

詳しくは後述しますが、
デストラクタが呼ばれるのは**Destroyしたタイミングではありません。**
そのため**処理順**によってはバグに繋がります:scream:

# デストラクタはいつ呼ばれるの？
アクターに対してDestroyをかけた場合は、
IsPendingKill のフラグがたち、
GCなどによってフラグがたっているもの全てが破棄されます。
このときに呼ばれます。

それまでは内部的には**実体が残っているのでデストラクタは呼ばれません。**
[アクターのライフサイクル（公式ドキュメント）](http://api.unrealengine.com/JPN/Programming/UnrealArchitecture/Actors/ActorLifecycle/)

# 終了処理はどう書くの？
ではデストラクタではなく、どこにゲーム中の終了処理を書くかについてです。
**EndPlay** をオーバーライドすることで終了処理を書けます。

```cpp:Actor
class MY_API AAlice : public AActor
{
:
    virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
```
これであればDestroyされたり、
Levelがアンロードされたときに終了処理がすぐ呼ばれます。

# まとめ
デストラクタに終了処理を無闇に実装するのは**処理順の関係上危険です:warning:**
特殊な処理やデバッグ処理を書かない限り、
基本的にデストラクタは書く必要がないでしょう。
[Laravel5] 開発する上で必要最低限な設定や問題点などまとめておく

# 1. Installation
## 1.1 Requirements
Following packages are required to install Laravel.
    + PHP >= 7.1.3
    + OpenSSL PHP Extension
    + PDO PHP Extension
    + Mbstring PHP Extension
    + Tokenizer PHP Extension
    + XML PHP Extension
    + Ctype PHP Extension
    + JSON PHP Extension
    + BCMath PHP Extension

```console
sudo apt install php php-mbstring php-tokenizer php-json php-bcmath
```
## 1.2 Install Composer
```console
sudo apt install composer
```

## 1.3 Install Laravel
Install via installer.

```console
composer global require laravel/installer
```
Setup enviroment $PATH.

```
echo 'export PATH="$PATH:$HOME/.config/composer/vendor/bin"' >> $HOME/.bashrc
source $HOME/.bashrc
```
## 1.4 Creat new application
```
laravel new project_name
```

[1]:https://getcomposer.org/
dockerをサンドボックスにする(ubuntu16.04にapacheの環境構築をする例)

※ サンドボックスとして環境構築や動作検証をしたいケースには役立ちますが、実運用時は別の記事を参考にしてください。

ホストOSと同様の操作で環境構築を**何度でも試せて**、フレームワーク同士の競合を回避できるサンドボックスとして Docker を利用する方法を紹介します。

# ベースイメージからコンテナを作成

`--privileged` をつけて /sbin/init を起動コマンドにすることで、systemctlが利用可能になります。

```
sudo docker run --privileged -d --name con -p 8080:80 ubuntu:16.04 /sbin/init
```

# コンテナに入る

```
sudo docker exec -it con bash
```

# 必要なものをインストールする
コンテナの中で実行します。

```
apt update
apt upgrade -y
apt install -y vim git curl apache2 mariadb-server mariadb-client  
```

# apacheを起動する

```
systemctl start apache2
```

# コミットしてコンテナをイメージ化する
念の為、環境が壊れたときにコンテナを即座に作り直すためのイメージを作っておきます。

※ run 時の起動コマンドに /sbin/init を指定しているため、exitしてもコンテナは起動したままです。

```
exit
```

ホストOSで

```
sudo docker commit con con
```

## コンテナを作り直す
環境構築に失敗してコンテナを作り直す場合は、下記のコマンドを実行します。

```
sudo docker rm -f con
sudo docker run --privileged -d --name cake -p 8080:80 con /sbin/init 
```

起動したら、再度apacheを起動してから環境構築に挑みます。

# 疎通確認
ホストOSのブラウザで http://localhost:8080/ にアクセスして、ページが表示されれば成功です。


# 記事を書いた理由
Googleで apache の構築手順を調べると、「httpd イメージを使ってみよう！」「docker-composeを使って〜」みたいな記事が多いです。

既存のイメージを使えばすぐに構築できますし、運用上は docker compose などを使って１プロセス１コンテナにすることで個別に最新バージョンにアップデートできるなどの利点はありますが、求めているものがそうでないことも多々あります。

例えば、自分は**このフレームワークってどんなものだろう？**という単純な疑問が出たときに、その都度ホストOSを汚していたらキリがありません。だから仮想環境を使います。
とはいえ、その**フレームワーク以外の知識が求められるのが不便**でならないという思いを何度もしてきました。

それを少しでも解消できればなぁと思いながら書きました。
少しでも気楽に環境構築ができる人が増えることを願っています。