OmniAICreator/Qiita-1.07M huggingface dataset:
Goで不要なブランチを削除するコマンドラインツールを作ってみた

少し前にGoの勉強用で不要なブランチを削除するコマンドラインツールを作ったので簡単にまとめてみます。実際に作ったものはこちらです。
https://github.com/yuzoiwasaki/sweep

## 使い方
こんな感じで不要なブランチを削除できます。

### masterブランチ以外を削除

```sh
$ git branch
* master
  test1
  test2
$ sweep
$ git branch
* master
```

### test1ブランチ以外を削除

```sh
$ git branch
* master
  test1
  test2
$ sweep -v test1
$ git branch
* test1
```

### test1ブランチとmasterブランチ以外を削除

```sh
$ git branch
* master
  test1
  test2
$ sweep -v test1 -v master
$ git branch
* master
  test1
```

## なぜ作ろうと思ったか
Goでコマンドラインツールを作ってみようと思った時に、せっかくなら自分がほしいものを作りたかったからです。

ブランチの削除自体はワンライナーでできますし、エイリアスに登録しておけば毎回わざわざ長いコマンドを入力する必要もないのですが、エイリアスも面倒なのでこういうツールがあっても良いのではないかと思いました。

なんにせよ、何かを作ろうと思った時に自分のほしいものを作るというのは良いモチベーションだと思います（自分がほしいということは、もしかしたら他の人もほしいかもしれないですし）

## コード全体
コード全体としてはこんな感じのコードになります。コマンドラインから引数を受け取って処理した後、シェルコマンドを呼び出すシンプルな構造です。

```go:sweep.go
package main

import (
	"flag"
	"fmt"
	"os/exec"
)

type strslice []string

func (s *strslice) String() string {
	return fmt.Sprintf("%v", multiflag)
}

func (s *strslice) Set(v string) error {
	*s = append(*s, v)
	return nil
}

var multiflag strslice

func main() {
	flag.Var(&multiflag, "v", "Specify the branch you want to exclude")
	flag.Parse()

	if len(multiflag) == 0 {
		multiflag = append(multiflag, "master")
	}

	var b, e string

	for _, s := range multiflag {
		b = s
		e = e + " | grep -v " + s
	}
	cmdstr := "git checkout " + b + " && git branch" + e + " | xargs git branch -D"

	err := exec.Command("sh", "-c", cmdstr).Run()
	if err != nil {
		fmt.Printf("Error! Failed to sweep branches.\n")
	}
}
```

Goには `flag` というコマンドラインオプションをパースできるパッケージがあるので、こちらを使って引数を受け取り処理をしています。
https://golang.org/pkg/flag/

また、最終的にはOS上でシェルコマンドを実行したかったため、合わせて `os/exec` もインポートしています。

## 悩んだところ
`flag` は便利なのですが、そのままでは同じオプションに対して複数の値を受け取ってパースすることができません。これを実現するためには、少し独自に拡張する必要があります。

`flag` は `flag.Var()` を使うことで独自型の変数をバインドすることができます。また `flag` には `Value` というインターフェースが定義されているため、このインターフェースを満たす形で型を定義してあげることで独自に拡張することができます。便利ですね。

>you can create custom flags that satisfy the Value interface (with pointer receivers) and couple them to flag parsing by
>
>flag.Var(&flagVal, "name", "help message for flagname")

・参考
https://qiita.com/hironobu_s/items/96e8397ec453dfb976d4
https://golang.org/pkg/flag/#Value

## 終わりに
以上、簡単ではありますがGoでコマンドラインツールを作ってみた紹介でした。もしよければ使ってみてください。

拙作ですが、同じように初めてGoでツールを作る人の参考になれば嬉しいです。今のところ仕事でGoを使う予定はないのですが、これからも趣味で触っていきたいと思います。
Docker イメージの断捨離を圧倒的に効率化する

こういうのを作りました。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16369/926d996c-5748-9099-d186-a1cfb9c5bb01.gif)

## Docker イメージの断捨離がダルい問題
Docker イメージがディスク容量を圧迫して困ることがありますよね。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16369/346dc2b3-84be-e4d5-50f4-193ab067575f.png)

`docker image prune` や `docker system prune` をすれば dangling なイメージをまとめて削除することができます。danglings (宙ぶらりんな) イメージとは「タグ付けされていない」「どのコンテナも使ってない」イメージのことなので、つまりは「削除しても問題なさそうなイメージをまとめて削除する」ってやつです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16369/9c822e58-255f-c244-f317-8eef04e28c6b.png)


これだけである程度は削除できますが、タグ付けされている不要なイメージまでは削除できません。 `-a` / `--all` オプションを使えばタグ付けされている未使用なイメージをまとめて削除できますが、これだと今度は必要なイメージまで削除してしまうので難しいです。

結局、ちゃんと断捨離しようと思ったら目視でひとつひとつ削除していくしかないのです。

しかしそれが大変で、latest ではないイメージは `<Repository>:<Tag>` と指定するかイメージ ID を直接指定するしかなく、手でポチポチとコピペしていくハメになります。しかも削除順序を間違えると「このイメージはこっちのイメージが依存しているから削除できんよ」などとエラーを吐かれます。やってられるか。

こうした単純作業は効率化するのが IT エンジニアの美徳です。

「リストの中から人間が選択をする」操作を効率化する手段といえば何ですか？
そう、**peco** ですね。

## peco とは
@xtetsuji さんの「[pecoの基礎の基礎](https://qiita.com/xtetsuji/items/05f6f4c1b17854cdd75b)」がわかりやすいです。

> とてもシンプルなツールで **「標準入力から受けた行データをインクリメンタルサーチして、選択した行を標準出力に返す」** コマンドです。
> 
> シンプルゆえに様々な組み合わせで効果を発揮します。あらゆる場面での選択肢を標準入力に渡して、選択された結果を標準出力から受け取って加工してコマンド実行をする、というのが基本的な流れ。

自分も「コマンド履歴を検索して再実行」とか「SSH の接続先を選んで接続」とか「Git リポジトリのブランチを選んで切り替え」とか[^peco.sh] 頻繁に使います。 **控えめに言ってめちゃくちゃ便利。**

[^peco.sh]: peco 使用例： https://github.com/hoto17296/dotfiles/blob/master/zsh/peco.sh

macOS だったら `brew install peco` で入ります。

実はあまり知られていないっぽいですが、 **peco は複数行選択ができます。**
今回はこれを使って Docker イメージを断舎離するやつを作っていきましょう。

## peco で Docker イメージを選択
peco で複数行選択をするためには `control + space` を使いますが、macOS ではこの組み合わせは「入力ソースの切り替え」に割り当てられているので、そのままでは使えません。回避方法は何でもいいですが、今回は「`tab` で複数行選択」が出来るように peco の設定ファイルを書いておきます。

``` json:~/.config/peco/config.json
{
  "Keymap": {
    "Tab": "peco.ToggleSelectionAndSelectNext"
  }
}
```

さて、おもむろに以下のコマンドを実行してみましょう。

``` console
$ docker images | peco
```

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16369/7ac2e5fa-95cf-6782-b417-ea2f180245f0.gif)

docker images の結果を peco に渡して、peco でフィルタリングして、標準出力に流しただけです。

というわけで、Docker イメージをフィルタリングして選択するやつができました。

## 便利スクリプトを書く
あとはもういい感じに仕上げるだけです。

``` sh:~/.zshrc
function peco-docker-images() {
  local images="$(docker images | tail +2 | sort | peco --prompt 'DOCKER IMAGES>' | awk '{print $3}' ORS=' ')"
  [ -z "$images" ] && return
  BUFFER="$LBUFFER$images$RBUFFER"
  CURSOR=$#BUFFER
}

zle -N peco-docker-images
bindkey '^x^i' peco-docker-images
```

イメージを削除するために必要なのはイメージ ID なので、peco の結果に対して awk でイメージ ID だけを取り出して space で結合しています。

これは zsh スクリプトですが、bash でも似たような雰囲気で書けるのではないでしょうか。(知らん)

この例では `control + x` `control + i` で peco が起動して、選択したイメージ ID がプロンプトのバッファに差し込まれます。

![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/16369/926d996c-5748-9099-d186-a1cfb9c5bb01.gif)

これで地道なコピペをすることなく Docker イメージをごっそり断捨離できるようになりました。めでたしめでたし。
Google ColaboratoryでRを実行する方法×2

## はじめに

Rを「端末に依存することなく、クラウド上で実行できたらいいな。」、「欲を言うと、ノートブックとして扱うことが出来たら嬉しい。」、「そもそも、環境構築が苦手だ。」なんてことを思ったことがありませんか？私はあります。そこで、Google Colaboratory（Colaboratory）を利用する方法を調べました。2つの方法があります。

## そもそもColaboratoryでRを利用できるのか

ColaboratoryではPython3しか利用できない雰囲気があります。

以下を実行してColaboratoryで利用可能なカーネルの一覧を確認できます。

```shell
!jupyter-kernelspec list
```

```shell
Available kernels:
  ir         /usr/local/share/jupyter/kernels/ir
  python2    /usr/local/share/jupyter/kernels/python2
  python3    /usr/local/share/jupyter/kernels/python3
  swift      /usr/local/share/jupyter/kernels/swift
```

irがRのカーネルです。

## Google ColaboratoryでRを実行する方法×2

Google ColaboratoryでRを実行する方法は2つあります。
- ノートブックにおける利用カーネルの変更
- セルごとの利用カーネルの変更

## ノートブックにおける利用カーネルの変更

### Step 1：ノートブックの新規作成

Rを利用するノートブックの新規作成をします。

### Step 2：ipynbファイルをローカルに保存

「ファイル」>「ipynbファイルとしてダウンロード」

### Step 3：利用カーネルの書き換え

ダウンロードしたipynbファイルを適当なテキストエディタで開きます。（※ノートブック形式で開くのは×）

その中にこのような記述があるかと思われます。これを…

```ipynb
    "kernelspec": {
      "name": "python3",
      "display_name": "Python 3"
    }
 ```   

以下のように書き換えます。

```ipynb
    "kernelspec":{
      "name":"ir",
      "display_name":"R"
    }
```

差分はこのようになります。

```diff
    "kernelspec":{
-      "name": "python3",
-      "display_name": "Python 3"
+      "name":"ir",
+      "display_name":"R"
    }
```

そして保存します。

### Step 4：Google Driveへアップロード・Colaboratoryで開く

カーネルの書き換えをしたipynbファイルをGoogle Driveへアップロードします。そして、Colaboratoryで開きます。これにより、このノートブックでRを実行可能です。

## セルごとの利用カーネルの変更

### Step 1：ノートブックの新規作成

Rを利用するノートブックの新規作成をします。

### Step 2：Rの有効化

セルごとの利用カーネルとしてRを選択できるようにRの有効化をします。以下のコマンドを実行します。

```shell
%load_ext rpy2.ipython
```

### Step 3：セルの利用カーネルをRに変更

Rでコードを記述した各セルの冒頭に以下を記述します。これを記述したセルでRを実行可能です。

※セルごとに記述する必要があります。

```r
%%R
```

### 注意

慣れてしまうと時折、Step 2を失念してしまうことがあります。以下の出力を確認した場合は思い出してください。

```shell
UsageError: Cell magic `%%R` not found.
```

## まとめ

Google ColaboratoryでRを実行する方法×2を紹介しました。ひとつは「ノートブックにおける利用カーネルの変更」、もうひとつは「セルごとの利用カーネルの変更」です。用途などに合わせて適している方をご利用ください。


## おまけ

以下のコマンドにより、ColaboratoryにおけるRのバージョンなどの情報の取得が可能です。

```
%%R
R.version
```

2020年12月1日現在、ColaboratoryでのRのバージョンなどは以下の通りです。

```shell
               _                           
platform       x86_64-pc-linux-gnu         
arch           x86_64                      
os             linux-gnu                   
system         x86_64, linux-gnu           
status                                     
major          4                           
minor          0.3                         
year           2020                        
month          10                          
day            10                          
svn rev        79318                       
language       R                           
version.string R version 4.0.3 (2020-10-10)
nickname       Bunny-Wunnies Freak Out     
```
Flutterの便利なWidgetや書き方

普段Dart を書いていて個人的に便利だな〜と思ったWidget や書き方を紹介したいと思います。
また今後便利だなと思ったものは随時追加していきます。

## ColoredBox

色をつけたい場合に使用できます。
Containerを使うと色をつけることはできますが、ColoredBoxは色をつけることだけができるWidgetなので役割としても伝わりやすいですし、コードの意味を受け取りやくすなると思います。

```dart
Widget build(BuildContext context) {
  return ColoredBox(
    color: Colors.black87,
    child: ...,
  );
}
```

## LicensePage
ライセンス表記に使用できるWidget です。

```dart:
@override
Widget build(BuildContext context) {
  return LicensePage();
}
```

`LicensePage` を使うと下記のようなページを作成することができます。
ライセンス情報を取得するスクリプトを書いたりすることなくライセンスの表示が可能になっています。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/91583/b519fc11-d2b0-f412-436f-cb33b564fa24.png" width="300" />


## Collection if

条件によってWidget を出し分ける際に三項演算子を使ってWidgetの出し分けをすることがあると思いますが、ifを使ったほうが簡潔に少ない記述量で書くことができます。


三項演算子の場合

```dart
Widget build(BuildContext context) {
  return Column(
    children: [
      context.watch<PageState>.isLoading
        ? const SizedBox.shrink()
        : const UserName(),
    ],
  );
}
```

Collection If を使用した場合

```dart
Widget build(BuildContext context) {
  return Column(
    children: [
      if (context.watch<PageState>.isLoading)
        const UserName(),
    ],
  );
}
```
if を使用した記述ができない場合はDartSDKのバージョンを確認してください。
2.6以上のバージョンが必須です

## Collection for

いままで `map((item) => ....).toList(), `で書いていたコードは下記のように書き換えることができます。

```dart
Widget build(BuildContext context) {
  return Column(
    children: [
      for (var item in context.watch<PageState>().items)
        ListTile(
          title: Text(item.title),
          onPress: () {
          
          },
        ),
    ], 
  );
}
```

for を使用した記述ができない場合はDartSDKのバージョンを確認してください。
2.6以上のバージョンが必須です


下記のような書き方もできます。
しかし条件が複雑になると可読性が悪くなるので、`where` で書けるならwhere で書くことをおすすめします。

```dart
Widget build(BuildContext context) {
  return Column(
    children: [
      for (var item in context.watch<PageState>().items)
        if (item.complete)
          ListTile(
            title: Text(item.title),
            onPress: () {
          
            },
          ),
    ], 
  );
}
```


## extensions

extensions method を使うと既存のクラスにメソッドを追加することができます。

Duration で時間を指定する場合下記のようにextensions を用意しておくと、

```dart
extension DurationExts on int {
  Duration get toSeconds => Duration(seconds: this);
  Duration get toMilliseconds => Duration(milliseconds: this);
}
```
ディレイさせる秒数やAPI通信のタイムアウトの秒数などを下記のように書くことができます。
`Future.delayed(2.toSeconds, () => {});`

extensions の使いすぎると何をしているのかわかりにくくなるので用法・用量を守って正しく使いましょう！
[swift]NavigationBarの戻るボタンを押した時の挙動を操る方法

#はじめに
 Navigationbarの戻るボタンを押した時に、特定の動きをつけたい場合にどうすればよいかの説明を記録しておきたいと思います。
#開発環境
```
macOS 11.0.1
Xcode version 12.2
Swift version 5.3.1
```
#実装したいこと
 今回はNavigationbarの戻るボタン押した時に、子の画面のTextFiledに入力した値を親に渡すことを実装したいと思います。
戻るボタンを押して子から親画面に移動するということは、言い換えると戻るボタンを押すと親画面が現れると言い換えることができます。この、親画面が現れるという時にはUINavigationControllerDelegateのWillShowが呼ばれます。これを利用して、戻るボタンを押した時の挙動を操りたいと思います。

```swift:ChildViewController
import UIKit

                                      //UINavigationControllerDelegateを追加
class ChildViewController: UIViewController,UINavigationControllerDelegate{
  
    @IBOutlet weak var b: UITextField!  
    
    override func viewDidLoad() {
        super.viewDidLoad()

        //NavigationControllerのdelegateはChildViewControllerが委任していることを書く
        navigationController?.delegate = self
        
    }      
        
    func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {

       //下記を書くことで親画面であるParentViewControllerの変数にアクセスできる
        if let controller = viewController as? ParentViewController{
       //処理したい内容を書く
       //今回は実装したい、aは親画面の変数にTextFiledであるbに入力されたtextを渡してあげる
            controller.a = b.text!
        }

    }
}
```
重要なことは
**・class宣言時にUINavigationControllerDelegate
・navigationController?.delegate = selfと委任してやる
・willShow内に実行したいことを書く**
です！
#参考にしたサイト
参考：[navigationbarのバックボタンを押した時に-値を渡したい](https://ja.stackoverflow.com/questions/34521/navigationbarのバックボタンを押した時に-値を渡したい)
（Python Selenium）WebDriver のダウンロード先の設定を確認したい

## WebDriver のダウンロード先の設定を確認する
立ち上げた WebDriver のダウンロード先フォルダを確認するため　chrome://settings　にアクセスしてのダウンロード先の記述を確認します。（**ShadowDOM の中身を検索する必要があったため、通常のJavascript での検索が効きませんでした。**なので、ダウンロード先の記載されているDOMまで、全てを開く操作を記述する必要がありました。）

```WebDriverModule.py
defaultDownloadPathElementName = "defaultDownloadPath"
class WebDriverModule(object):
    def getChromeDefaultDownloadPath(self, driver:WebDriver)->str:
        driver.get('chrome://settings')
        WebDriverWait(driver,15).until(EC.presence_of_all_elements_located)

        shadow_root1_1 = self.expandShadowElement(driver, driver.find_element_by_tag_name('settings-ui'))
        shadow_root1_2 = self.expandShadowElement(driver, shadow_root1_1.find_element_by_tag_name('settings-main'))
        shadow_root1_3 = self.expandShadowElement(driver, shadow_root1_2.find_element_by_tag_name('settings-basic-page'))
        actionModule.clickElement(
            driver,
            shadow_root1_3.find_element_by_tag_name('paper-button')
        )

        shadow_root2_1 = self.expandShadowElement(driver, driver.find_element_by_tag_name('settings-ui'))
        shadow_root2_2 = self.expandShadowElement(driver, shadow_root2_1.find_element_by_tag_name('settings-main'))
        shadow_root2_3 = self.expandShadowElement(driver, shadow_root2_2.find_element_by_tag_name('settings-basic-page'))
        shadow_root2_4 = self.expandShadowElement(driver, shadow_root2_3.find_element_by_tag_name('settings-downloads-page'))
        
        return self.getTextFromElement(
            shadow_root2_4.find_element_by_id(defaultDownloadPathElementName)
        )
        
    def expandShadowElement(self, driver:WebDriver, shadowElement:WebElement)->WebElement:
        shadowRoot = driver.execute_script('return arguments[0].shadowRoot', shadowElement)
        return shadowRoot
    def getTextFromElement(element:WebElement)->str:
        print(element.text)
        return element.text

```

これでShadowDOMが使用されているchromeの設定画面から設定を取得することが出来ました。

以上です。
Makefileののすゝめ

# はじめに
こんにちはRIN1208です。
この記事は[ITRC Advent Calendar 2020](https://adventar.org/calendars/5535)の20日目の記事です。

さて皆さんMakefile書いていますか？
自分はここ半年前から書くようになりました。

##なんでMakefile？
Makefileで検索するとC言語とかの情報がでてきますが別にC言語以外でも使用できます。

使用するメリットとしては 

- プロジェクトをローカルでセットアップ時に実行するコマンドをmake setup みたいな感じでまとめることができる
- よく使うコマンドのショートカットを作成できる


てなわけで書いてみよう

## 書いてみよう

ファイル名はMakefileです。

ここではサンプルとしてdocker-composeのコマンドを書いています。


```makefile
build:
    docker-compose build
up:
    docker-compose up -d
    docker-compose logs -f
down:
    docker-compose down
```

上記のようなmakefileを作成した場合
make down でdocker-compose downが実行され
make buildでdocker-compose buildが実行されるようになります
また make up ではdocker-compose up -d の後に docker-compose logs -fを実行されます。
このように複数コマンドを簡単なmakeコマンドに置き換えることができセットアップ時の手間を軽減することが可能になります。

# 終わりに
ここまで読んでくださりありがとうございます。
makefile書くとコマンド打ったりするのが楽になりますよね。

間違っている点などがございましたらコメントなどで指摘していただけると助かります。
KUSANAGI Runs on DockerでWordpressプラグインのアップデートがうまくいかないときは

#はじめに
Wordpressのプラグインやコアのバージョンアップが失敗していて、原因探っていたところフォルダのパーミッションを変更することで回避できることがわかりました。
手順をまとめておきます。


#Wordpressのプラグインバージョンアップが失敗する
標準のKUSANAGI Runs on Docker環境でプラグインのアップデートをしようとしたら「更新失敗: ディレクトリを作成できませんでした。」というエラーが出てバージョンアップが失敗してしまします。
![img09.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680666/426d6f4a-32d8-326a-f38b-9608bc6c248a.jpeg)

#原因はフォルダのパーミッション
通常Kusanagi RoDは`/home/kusanagi`の下の任意のフォルダにインストールされます。
その時のフォルダのパーミッションは755になっていてこれが原因のようです。
バージョンアップの際は一時的にフォルダのパーミッションを777に変更します。
ついでにファイルパーミッションは666に変更しておきます。

まずはDockerのftpコンテナにログイン
```bash
$  docker-compose exec ftp sh
```

以下、ftpコンテナ内での作業です。

```bash
# cd /home/kusanagi/puroject
# find . -type d -exec chmod 777 {} +
# find . -type f -exec chmod 666 {} +
```

これでパーミッションが変わりました。
wp-config.phpのパーミッションは644である必要があるのでご注意ください。

```bash
# chmod 644 wp-config.php
```

```bash
# ls -al
total 28
drwxrwxrwx    6 kusanagi 1001          4096 Aug  5 05:54 .
drwxr-x--x    3 kusanagi 1001          4096 Oct 11 03:31 ..
drwxrwxrwx    5 kusanagi 1001          4096 Dec 20 14:25 DocumentRoot
drwxrwxrwx    2 kusanagi 1001          4096 Jul 16 10:24 settings
drwxrwxrwx    2 kusanagi 1001          4096 Aug  5 05:54 tools
drwxrwxrwx    4 kusanagi 1001          4096 Jul 16 10:24 wp-config-sample
-rw-r--r--    1 kusanagi 1001          3351 Oct 11 03:44 wp-config.php
```

#再度バージョンアップ
今度は成功しました！
![img10.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/680666/af82df85-aaca-62f8-7530-936adf0a1407.jpeg)


そのままだとセキュリティ的にゆるゆるなのでパーミッションを戻しておくのを忘れずに。
別エントリーで記載していますがuploadsフォルダは775にしておかないと画像アップロードが失敗するのでこちらも更新します。

```bash
# find . -type d -exec chmod 755 {} +
# find DocumentRoot/wp-content/uploads -type d -exec chmod 775 {} +
```
集約の整合性についてArchUnitを用いてテストする③

[集約の整合性についてArchUnitを用いてテストする①](https://qiita.com/logy0704/items/a9ad4f840a3303b2a969)の別バージョン


```java

    @ArchTest
    static ArchRule aggregate_object_only_be_accessed_from_root =
        classes()
            .that().resideInAPackage("com.example.domain")
            .should().onlyBeAccessed().byClassesThat(new DescribedPredicate<JavaClass>("is AggregateRoot") {
            @Override
            public boolean apply(JavaClass input) {
                return input.getAnnotations().stream().anyMatch(a -> a.toString().equals("AggregateRoot"));
            }
        });
```

`@AggregateRoot`が集約ルートに付与されていればシンプルに判定できる。
アノテーション抽出するところはもう少しきれいに書けるはず・・・
VSCodeで手軽にER図を作成する

#はじめに
　アプリケーション制作の序盤に行う、ER図作成をVSCodeで行うための拡張機能です。
![](https://i.gyazo.com/6ad06f025b4892f718f5b1460ede668f.gif)

##VSCodeで検索


`Draw.io Integration`で検索

##使い方
ファイルの拡張子を`.drawio.png`にすると、この拡張機能を使うことができます。
【Laravel8】リレーションを考慮した検索方法〜

laravel初めて５ヶ月が経ちました。
リレーション先の情報を利用して検索機能を実装するときに、少し時間を取られました。。

例えば以下のテーブル構成であったとします。

##### ユーザーテーブル (users_table)
|id | name | email |
|:-----------|------------:|:------------:|
| 1       | user1        | user01@example.com |
| 2     | user2     | user02@example.com       |
| 3     | user3     | user03@example.com       |
##### 中間テーブル (user_subject_table)
|id | user_id | subject_id | score |
|:-----------|------------:|:------------:|:------------:|
| 1       | 1        | 1 |75|
| 2     | 1     | 2       |100|
| 3     | 1     | 3       |90|
| 4     | 2     | 1       |60|
| 5     | 2     | 3       |80|
| 6     | 3     | 1       |60|
| 7     | 2     | 3       |20|
##### 科目テーブル (subjects_table)
|id | name |
|:-----------|------------:|
| 1       | 数学        | 
| 2     | 英語     | 
| 3     | 物理     | 

App\Models\\*

```
class User extends Model
{
    use HasFactory;
    protected $fillable = [
        'name',
        'email',
    ];
    public function subjects() {
        return $this->belongsToMany('App\Models\Subjects', 'user_subject', 'user_id', 'subject_id');
    }
}

class Subject extends Model
{
    use HasFactory;
    protected $fillable = [
        'name',
    ];
    public function users() {
        return $this->belongsToMany('App\Models\User', 'user_subject', 'subject_id', 'user_id');
    }
}

```
with関数は、EagerLoadingという機能で、発行するクエリを少なく、効率的にDBからデータを取得する仕組み。

リレーション先の情報を利用してクエリを発行したい場合、whereHasが利用できます。

whenは第一引数がnull出ない時に第二引数のクエリを実行します。

Userモデルで作成したリレーションはsubjectsでしたので、第一引数にsubjects
第二引数ではsubjects_tableを見た際のクエリです。
続けてuser_subjectを見た時のscoreの条件も含めることができます。

```
class UserController extends Controller
{
    public function index(Request $request)
    {
        //リレーション定義しておく
        $query = User::with('subjects',);

        // 数学の点数を取得
        $math_score = $request->input('math_score')

        //$math_scoreがnullでなければ実行
        $query->when($math_score, function ($query) use ($math_score){

            $query->whereHas('subjects', function($query) {

　　　　　　　　　　 //数学のscoreを持っているuser
                 $query->where('subjects.id', １)

                 //かつ数学のscoreが70点以上のユーザー
                 $query->where('user_subject.score', '>=', 70);
            });
        });

```
このように記述すれば条件にあうuserが取得できます。

```
array:2 [▼
  0 => User{#1 ▶︎}
  1 => User{#2 ▶︎}
]
```

中々便利でした！！
iPhoneからラズパイにミラーリング！RPiPlayとは？

# 1.はじめに
なんで、RapberryPiにAirPlayをしたいと思ったかというと、Macの画面をテレビに写したかったからです。  
「普通に有線でつなげよ！」って感じですが、僕が使っているMacBook AirにはHDMIポートがないんです。それに、変換ケーブルもメッチャ高いし、Thunderbolt2なんてすぐに使わなくなります。  

そこで、家にあるものでどうにかならないかな〜と思ったら**RPiPlay**にたどり着きました。  
# 2.インストール方法
まず、定番のアップデート。

```
$ sudo apt update
$ sudo apt full-upgrade
```
RPiPlayのダウンロード。

```
$ git clone https://github.com/FD-/RPiPlay.git
```
必要なパッケージのインストール

```
$ cd RPiPlay
$ sudo apt-get install cmake
$ sudo apt-get install libavahi-compat-libdnssd-dev
$ sudo apt-get install libplist-dev
$ sudo apt-get install libssl-dev
```
makeする

```
$ mkdir build
$ cd build
$ cmake ..
$ make
```
# 3.使い方
起動するだけだったらこれでOK。

```
$ cd RPiPlay/build
$ ./rpiplay
```
オプションはこんな感じ。

| オプション | 効果 |
|:---|:--|
|-n 名前| AirPlayの所に表示される名前を変更 |
|-b (on/auto/off)|黒い背景を表示するか否か
|-r (90/180/270)| 画面を回転させる |
|-f (horiz/vert/both)| 画面を反転 |
|-l| 低遅延モード |
|-a (hdmi/analog/off)| 音の出力先の指定 |
|-v/-h | ヘルプを表示 |

僕は、名前の変更・黒い背景を表示しないのオプションを付随して使っています。

```
./rpiplay -b -n shion_rpiplay
```
# 4.最後に
YouTubeなどの動画がAirPlayできないのは残念ですが、これだけ使えるのは便利です。  
これで、プレゼンするときに「変換ケーブル忘れた！」ってなっても問題ありませんね！
  
  
情報元：[rpiplay: An open-source AirPlay mirroring server for the Raspberry Pi. Supports iOS 9 and up.](https://github.com/FD-/RPiPlay)
UIAlertControllerをファイルを分けて実装してみる

自分の備忘録としてまとめておきます。

#はじめに
今回は、UIAlertControllerをファイルを分けて実装してみようと思います。

非常に使いやすく、色んな場面で使えるので皆さんも良かったら使ってみて下さい！

#実装
ファイル名はなんでも良いですが、今回は分かりやすく「Alert.swift」にしようと思います。

```swift:Alert.swift
import UIKit

final class Alert {
 // OKのみアラート
 static func okAlert(vc: UIViewController, title: String, message: String, handler: ((UIAlertAction) -> Void)? = nil) {
   let okAlertVC = UIAlertController(title: title, message: message, preferredStyle: .alert)
   okAlertVC.addAction(UIAlertAction(title: "OK", style: .default, handler: handler))
   vc.present(okAlertVC, animated: true, completion: nil)
 }

 // OK&キャンセルアラート
　static func cancelAlert(vc: UIViewController, title: String, message: String, handler: ((UIAlertAction) -> Void)? = nil) {
   let cancelAlertVC = UIAlertController(title: title, message: message, preferredStyle: .alert)
   cancelAlertVC.addAction(UIAlertAction(title: "OK", style: .default, handler: handler))
   cancelAlertVC.addAction(UIAlertAction(title: "キャンセル", style: .cancel, handler: nil))
   vc.present(cancelAlertVC, animated: true, completion: nil)
 }

 // TextField付きアラート
　static func textFieldAlert(vc: UIViewController, title: String, message: String, placeholder: String, securyText: Bool, handler: ((String?) -> Void)? = nil) {
   let textFieldAlertVC = UIAlertController(title: title, message: message, preferredStyle: .alert)
   textFieldAlertVC.addTextField { (textField) in
       textField.placeholder = placeholder
       textField.isSecureTextEntry = securyText
        }
   textFieldAlertVC.addAction(UIAlertAction(title: "OK", style: .default, handler: { (_) in
       handler?(textFieldAlertVC.textFields?.first?.text)
        }))
   textFieldAlertVC.addAction(UIAlertAction(title: "キャンセル", style: .cancel, handler: nil))
   vc.present(textFieldAlertVC, animated: true, completion: nil)
 }

// 自動で消えるアラート
 static func autoCloseAlert(vc: UIViewController, title: String, message: String) {
  let autoCloseAlertVC = UIAlertController(title: title, message: message, preferredStyle: .alert)
  vc.present(autoCloseAlertVC, animated: true) {
   // 1.5秒後に削除
   DispatchQueue.main.asyncAfter(deadline: .now() + 1.5) {
     autoCloseAlertVC.dismiss(animated: true, completion: nil)
     }
   }
 }
```
#使い方
上の実装コードを、呼び出す側ではこうなります。

```swift:ViewController.swift
   // OKボタンのみのアラートを表示
   Alert.okAlert(vc: self, title: "OKアラート", message: "OKボタンのみです！", handler: { (_) in
     // OKボタンを押した後に何かしたい場合の処理を記述
     print("OKボタンを押した後ですよ！")
   })

   // OKボタンとキャンセルボタンがあるアラートを表示
   Alert.cancelAlert(vc: self, title: "OK&キャンセルアラート", message: "キャンセルボタンもあります！", handler: { (_) in
     // OKボタンを押した後に何かしたい場合の処理を記述
     print("OKボタンを押した後ですよ！")
   })

   // TextField付きOK&キャンセルがあるアラートを表示
   Alert.textFieldAlert(vc: self, title: "TextFieldアラート", message: "文字を入力できます！", placeholder: "入力", securyText: false, handler: { (text) in
     // 入力した文字を使う場合の処理を記述
     print("入力した\(text)を表示します！")
   })

  // 自動で消えるアラートを表示
  Alert.autoCloseAlert(vc: self, title: "自動で消えるアラート", message: "自動で消えます！")
```

#まとめ
如何だったでしょうか？

Qiitaを書くの今回が初めてなので、至らぬ点が多いと思います。
後、上のコードよりも、もっと使いやすいよー！っていう実装コードがあったらコメントして下さると嬉しいです！:open_hands:
【デブスト】5つのセッションからみえたアウトプットの重要性

# はじめに
先日オンライン開催されたDevelopers Boost 2020を視聴しました。
とても良い刺激になったので自分なりにここにまとめておこうと思います。

#視聴したセッション

17セッション中、下記5つを視聴しました。

<a href="https://event.shoeisha.jp/devboost/20201212/session/2976/
">コミュニティ活動で差別化をめざすエンジニアとしての一手</a>
<a href="https://event.shoeisha.jp/devboost/20201212/session/2978/
">チームを“群れ”として観察すれば、アジャイル開発はもっと上手くいく</a>
<a href="https://event.shoeisha.jp/devboost/20201212/session/2979/
">OpenAPI Generator による API Client コードの完全自動生成</a>
<a href="https://event.shoeisha.jp/devboost/20201212/session/2989/
">凡人エンジニアの生存戦略</a>
<a href="https://event.shoeisha.jp/devboost/20201212/session/2990/
">不確定要素が強い時代の生存戦略 ― U30が「好きなコト」で突き抜けるためには!?</a>

どれもテーマは異なりますが、アウトプットがキーワードだな思ったので、その重要性について書いていきます。

#なぜアウトプットが重要なのか

アウトレットの有効性が説かれるとき、よく挙げられるのは

* コミュニケーション力やプレゼンスキルなどの基礎的な能力の向上

* 知識の整理、深掘り

だと思います。少なくとも今までアウトプットによる効果は主にこの２つだと思っていました。
でも登壇者の話を聞いているとそれだけじゃなかった・・・

##①周りとの差別化

今日ではインターネットや書籍などインプットの手段はいくらでもあり、アウトプットにこそ価値が生まれます。
何か書いたり発表したり一見簡単そうには見えますが、心理的障壁があって意外と皆やらない。

また、人は知らない人を尊敬しない。つまり　知名度＝その人価値　とも言えます。
知名度をあげるにはまずわかりやすい成果（≒アウトプット）をあげる必要があります。
※これについてはまつもとひろゆき氏がプログラマー勉強法で話されたそうです。

よって、アウトプットすることで周囲との差別化が図れます。

##②セルフブランディング

差別化とも似ているようですが、ここではあえて分けます。

アウトプットを続けていると「□□なら○○さん」と言われたり、他の人よりチャンスが舞い込みやすくなります。（登壇者の加納さんは登壇キャラという言い方をされてました）
また、アウトプットの内容で自分のスキルや志向性をアピールすることもできます。
その内容に共感者が生まれれば自己実現にも繋がります。

従って、アウトプットすることで周囲との差別化だけでなく、内容とやり方次第でセルフブランディングもできてしまいます。

#会社へのメリット

最近、社内でLT大会が開催されてたり部署のミーティングなんかでも発表する機会があるので、アウトプット（ここでは主に発表を指す）することで会社にはどんなメリットがあるか考えてみました。

* 個々のスキルアップ

始めの方でよく聞くに挙げましたが、基礎的なヒューマンスキル/ビジネススキルの向上、知識・技能の定着、これだけでも会社にとって十分なメリットと思います。

* 社員教育

受け手に知識や成功体験が共有されることで、アウトプットする側だけでなく受ける側にも教育的な効果があると思います。

* 広報活動

社外へ向けてアウトプットした場合、社名/製品の認知度が向上したり、興味を持った人が就職先の候補とすれば採用活動にも繋がります。

#まとめ

ここまでの内容をまとめると、アウトプットの効果は基礎的な能力の向上だけでなく、周囲との差別化、ひいてはセルフブランディングにもなりえると言えます。
そしてその人個人だけでなく会社にもメリットがあります。

私自身デブストで各セッションを見てからアウトプットを意識するようになりました。
今後も続けていきたいと思います。がんばるぞー
【AzureAD】3rdパーティ製アプリとの　シングルサインオンと条件つきアクセスを実装して感じた事

3rdパーティ製アプリとのシングルサインと条件付きアクセスの設定を色々試してみました。そこで色々わかったことを纏めてみました。


#１：モバイルで3rdパーティ製アプリからアクセスさせると、条件付きアクセスでintuneに準拠されない


モバイル専用のアプリが用意されている　3rdパーティ製アプリは結構多いですが、
現状ほとんどのアプリが、条件付きアクセスでintune準拠の判定に対応出来ていません。

この理由として、モバイル自体にはintuneのデバイス証明書がインストールされてても、3rdパーティ製アプリがそのデバイス証明書を取得して、AzureADに提示するという実装が出来ていない為だと思われます。デバイス証明が提示できない＝intuneに準拠されていると判定されないということですね。

これにより、例えばAzureADでセキュリティ向上の為に、シングルサインオン+intueデバイス準拠という二要素認証を実現したくても出来ません。
Edge等のブラウザからアクセスさせれば、intune準拠は可能ですが、それだとユーザー側の負担が大きくなりますよね。
これはMicrosoftでどうこう出来ることというよりは、3rdパーティ製アプリ側で実装が必要になる話だと思いますが、現状ほとんどのアプリが実装できていない気がしています。

#２：シングルサインオンやユーザープロビジョニングでネスト構造のSG（セキュリティグループ）が利用できない

ユーザープロビジョニングは連携させるユーザーを指定する必要があるのですが、連携はセキュリティグループでも指定することが出来ます。
ただし、セキュリティグループがネスト（入れ子）構造になっていると、入れ子のSGは連携されません。
ADの考え方では　入れ子のSGを使っていることが多いので、AADCでＳＧを連携させてもプロビジョニングには利用できず。3rdパーティ製アプリの連携するユーザーに合わせたネスト構造でないSGを毎回作成しなければならず、管理も含めて非常に不便です。

シングルサインオンは設定で、連携するユーザーを指定可否を設定できます。
設定しない場合誰でもアクセスは可能になります
もちろん3rdパーティ製アプリ側にアクセスしたユーザーがいなければ、その時点ではシングルサインオンは拒否されます。
ただし3rdパーティ製アプリが　例えばメールアドレスでアクセスしたら勝手にユーザが作成されるアプリだった場合、勝手にユーザーが作成されるのは困るので、Azure側でアクセスするユーザーを制御する必要が出てくると思います。ここにネストのSGが利用できないのは痛いですね

#３：MFAはあくまでユーザーの二要素認証である
モバイルからのアクセスで、3rdパーティ製アプリがintuneに準拠できないなら、MFAで二要素認証にしようって考えることはあると思いますが、このMFAはあくまで、ユーザーの二要素になるのでデバイスの判定はされません。

つまりどういうことかというと、個人のデバイスで3rdパーティ製アプリにアクセスして、個人のデバイスを電話着信で2要素に使うことも可能というわけです。
（デバイスを制御しているわけではないから当然ですよね）
本来であれば、会社至急のデバイスからしかアクセスさせたくないから、会社至急の端末からアクセス且つ、MFAの二要素というのを実現したいところですが。。。。
intuneに準拠させようとすると、1：に戻りアプリからデバイス判定が通らなくなります。
代わりにMFAを利用すると、どのデバイスからもアクセス可能になる気がします。
（運用で、会社の携帯からアクセスしてねって制御するしかないかも）


細かい部分を上げると他にも色々ありますが、
現状気になっているのは、上記3点です。是非何とかしてほしい。。。

どなたかのお役に立てれば幸いです（＾＾）
高校生がFFT(高速フーリエ変換)を理解してみた【第3回】連続フーリエ変換の導入part2

#はじめに
第3回目です。今回は連続フーリエ変換に足を踏み入れます。
具体的には、近似される関数と近似する関数を一般化していきます。
[【第0回】目次と概要](https://qiita.com/nekoMIMI_CatEye/items/d8fcb12132779cf4631c)
[【第1回】単純なモデルを解いてなれる](https://qiita.com/nekoMIMI_CatEye/items/7082f58cfcdeac5bddab)
[【第2回】連続フーリエ変換の導入part1](https://qiita.com/nekoMIMI_CatEye/items/dbc0a90221dcd7c7cd73)

#本記事の対象
高校3年生までの知識がわかっている人
具体的には

* 奇関数と偶関数の性質(原点対称・点対称)

#前回のあらすじ
第1回で出た問題の式の$\sum$の中身を$n\rightarrow\infty$に置き換えました。
このとき、$a_k$をいじれば関数が完全近似されることを確かめました。この式ですね。

```math
\int^{\pi}_{-\pi}(x-\sum^{\infty}_{k=1}a_k\sin kx)^2 dx=\frac{2}{3}\pi^3-\frac{1}{\pi}\sum^{\infty}_{k=1}{b_k}^2+\pi\sum^{\infty}_{k=1}(a_k-\frac{1}{\pi}b_k)^2\\
\left(a_k = -2\frac{(-1)^k}{k} ,　b_k = \frac{-2\pi(-1)^k}{k}\right)
```

#結論から書くと
###フーリエ変換で行っている近似
フーリエ変換では、$f(x)$を、このような式の$A_0$, $A_k$, $B_k$をいじって、近似しています。

```math
f(x) \rightarrow \frac{A_0}{2}+\sum^{\infty}_{k=1}A_k\sin kx+\sum^{\infty}_{k=1}B_k\cos kx
```

第1回で周期関数に近似することがフーリエ変換のようなものと書いた理由はこれです。__これ自体はフーリエ変換ではない__ことに注意してください。

#モデルの近似式とフーリエ変換の近似式の関係
モデルの式とフーリエ変換の関係性についてみていきます。

突然ですが、$x$は__原点に対して点対称__な関数のため、奇関数です。
さて、$\sin x$も__原点に対して点対称__な関数のため、奇関数です。
原点対称の関数はいくら足しても原点対称のままです。
つまりこの式は__奇関数__です。

```math
\sum^{\infty}_{k=1}A_k\sin kx
```

少し脱線します。
偶関数は__$y$軸に対して線対称__な関数です。
偶関数どうし、奇関数どうしなら性質が同じなので近似できます。
さて、ここで問題ですが、偶関数を奇関数、または奇関数を偶関数では近似できるでしょうか。

答えは__NO__です。原点対称と$y$軸対称では性質が異なります。(関数$y=0$に限り両性質を持っていますが......)


さて、話を戻しましょう。周期関数で近似するときに、偶関数である$\sin x$は偶関数部の近似の役割、奇関数部である$\cos x$は奇関数部の近似の役割を担っています。モデルの式は$x$が奇関数の成分しかもっていないため$\sin x$のみで近似することができました。

しかし、このような式はどうでしょうか。

```math
f(x) = x^4 + x^3 + x^2 + x + 1
```

この式は、偶関数と奇関数と定数が合わさった式になっています。
偶関数部分は偶関数である$\sin$で近似することができます。

```math
x^4 + x^2 \rightarrow \sum^{\infty}_{k=1}A_k\sin kx
```
奇関数の部分は奇関数である$\cos$で近似することができます。

```math
x^3 + x^1 \rightarrow \sum^{\infty}_{k=1}B_k\cos kx
```

定数は偶関数に分類することができますが、あえて分けます。

```math
1 \rightarrow \frac{A_0}{2}
```

つまり、感覚的にはフーリエ変換では偶関数部分と奇関数部分と定数部分で近似する式を分担しているということになります。



#第1回の問題を置き換える
さて、フーリエ変換ではこのような近似をすると書きました。

```math
f(x) \rightarrow \frac{A_0}{2}+\sum^{\infty}_{k=1}A_k\sin kx+\sum^{\infty}_{k=1}B_k\cos kx
```

この式が最小になる「$A_0$, $A_k$, $B_k$の値」を見つければ近似終了です。
近似をするには、近似したい式と近似する式の差の2乗(これを最小二乗誤差という)を0に近づければよかったです。

よってこのような問題に置き換えられます。
【問題】次の式の値を最小にするための$A_0$, $A_k$, $B_k$を解きなさい。

```math
\int^{\pi}_{-\pi}\left[f(x)-\left(\frac{A_0}{2} + \sum^{\infty}_{k=1}A_k\sin kx+\sum^{\infty}_{k=1}B_k\cos kx\right)\right]^2 dx
```

#問題を解く
記事が長くなるので解き方は載せませんが、第1回の解法を応用すると解くことができます。
なぜ長くなるかをいくつか挙げると

* 括弧を展開すると16項の多項式になる(まとめると10項)
* 第1回では$\sin\times\sin$の積和を考えたが4パターンすべての組み合わせを考えなければならない

#答え
近似をするための$A_0$, $A_k$, $B_k$の値はこのようになります。

```math
\begin{align}
\begin{array}{rcl}
A_0 &=& \displaystyle \frac{1}{\pi}\int^{\pi}_{-\pi}f(x)dx \\
A_k &=& \displaystyle \frac{1}{\pi}\int^{\pi}_{-\pi}f(x)\sin kxdx \\
B_k &=& \displaystyle \frac{1}{\pi}\int^{\pi}_{-\pi}f(x)\cos kxdx \\
\end{array}
\end{align}
```

#最後に
今回はフーリエ変換に少しふれましたが、どうだったでしょうか。希望があれば解法は載せるかもしれませんが、記事5枚分にはなると思います()。

次回は複素数の視点から近似式を見ていきます。オイラーの公式を使うので、この式を覚えておいてください。

【オイラーの公式】

```math
e^{i\theta} = \cos\theta+i\sin\theta　\theta:極座標形式(r,\theta)の\theta　(伝われ)
```

__極形式__といいます。こういう書き方ができるよーという感じです。
gqlgen のフィールド解決方法の使い分け tips

# gqlgen とは
[gqlgen](https://github.com/99designs/gqlgen) は go 言語製 GraphQL ライブラリで、自分で定義した GraphQL スキーマを元にリゾルバーのインターフェースを生成してくれて、あとはリゾルバーの実装をすれば、簡単に GraphQL のスキーマファースト開発ができるという物です。

## バインド機能

gqlgen にはデータモデルのバインド機能があり、GraphQL の型とアプリケーションの Go の構造体を紐づけて自動でフィールド解決をしてくれるようにすることができます。

```graphql
# entity.gql
type User {
  id: ID!
  name: String!
  tags: [Tag!]!
}
```

```go
// entity/user.go
type User struct {
  ID int
  Name string
}
// entity/tag.go
type Tag struct {
  ID int
  text string
}
```

```yml
# gqlgen.yml
models:
  User:
    model: github.com/yourpkg/entity.User
  Tag:
    model: github.com/yourpkg/entity.Tag
# または
autobind:
  - github.com/yourpkg/entity

```

上記のようにすると User の解決時に ID と Name は自動で User 構造体のフィールドをそのまま利用し、 構造体に存在しない tags だけ以下のようにリゾルバーを書くことで解決することができます。

```go
func (r *userResolver) Tags(ctx context.Context, obj *User) ([]*Tag, error) {
  return r.tagUsecase.GetTagsByUserID(ctx, obj.ID)
}
```

または、構造体を以下のようにすることで、自分でリゾルバーを書かない方法もあります。

```go
// entities/user.go
type User struct {
  ID int
  Name string
  Tags []*Tag
}
```

このようにして、User の取得時に eager loading することで、全てのフィールドを自動で解決してもらうことも可能です。

## 構造体の自動生成機能

gqlgen には Go の構造体定義を GraphQL のスキーマから自動で生成してくれる機能もあります。バインド機能を利用せずにこの機能を使うと、先ほどのスキーマから以下のような構造体を作ってくれます。

```go
type User struct {
    ID        ID       `json:"id"`
    Name      string   `json:"name"`
    Tags      []*Tag   `json:"tags"`
}
```

# どのように使い分けるか

これから新しく gqlgen で GraphQL API を作る場合、「自作構造体へのバインド」or 「リゾルバーの実装」or「スキーマから自動生成したモデル」をどのように使い分けるかのヒントを紹介します。

## 基本的考え方

いきなりですが、自分は基本的に全てエンティティーに対して自動バインドを有効にしています。
そもそも gqlgen の良さは GralphQL のスキーマを先に決めて、それに答えるバックエンドを作る「スキーマファースト開発」ができる点だと考えています。スキーマからリゾルバーの作成を gqlgen に任せ、リゾルバーがアプリケーションのユースケースを呼び出すことで、アプリケーション内部に GraphQL という概念が入り込まないようにしています。なので、GraphQL のスキーマとは全く別に、アプリケーション用のエンティティーを定義しています。その二つが**たまたま**一致する部分を自動バインドで解決してもらい、そうでないフィールドのリゾルバーを個別に実装するという考え方です。

## フィールドのリゾルバーを実装

構造体にバインドして解決させるということは、その構造体がフィールドを満たした状態で存在しなければならず、RDBMS をデータストアにしている場合、上記の Tags などはリポジトリ層で取得する際に必ず JOIN させて eager loading してなければなりません。これは n+1 を回避できるメリットもありますが、必要なフィールドだけリクエストできるという GraphQL がクエリ言語であるという特性を無視していることになります。

そのため、アプリケーション内でも必ず必要となるような最低限の物だけは JOIN させてリポジトリ層がユースケース層に返す時点でフィールドに存在することを保証し、それ以外の物は基本的にリゾルバーに一任するようにしています。リゾルバーが並列で走るため生じる n+1 を解決したい場合は別途データローダーなどを活用して回避しています。

(実際にはリポジトリ層はデータベースのテーブルと対になるテーブルモデルを利用し、エンティティーモデルへの詰替をすることで、gorm 用のタグやメソッドなど DB に関するあれこれがユースケース層に漏れないようにしています)

## スキーマからの構造体自動生成の活用

上記の考えより、スキーマからの自動生成は主な型には基本的には使っていません。しかし、ユースケース層に入り込まず、リゾルバーの層にのみ必要な型のみ、自動で生成しています。
mutation に必要な input 型やページネーション用の型などは GraphQL 専用の型なので、自動生成したものをリゾルバーでのみそのまま利用しています。

(他にも Fragment 用の interface 定義を自動生成に任せ、そのエンティティーがダックタイピング的に該当の Fragment であることを示したりもしていますがここでは割愛。)

# まとめ

- GraphQL スキーマとアプリケーションの型は根本的には別に考える
 - その上で一致したものは gqlgen に任せる
 - 別で考えてもスキーマが要求するものを返すアプリケーションを作るわけだから結局似る
- それ以外はリゾルバーで解決する
    - n+1 を無理に eager loading で解決しようとしない
    - リポジトリ層はシンプルに
- 構造体の自動生成は input などの表層モデルでのみ利用する
    - ビジネスロジックが使うモデルを GraphQL や gqlgen に依存させない

以上です。
ゲーム業界にプログラマとして入りたいなら

# はじめに
この記事は 琉大 Advent Calender 2020 の 20日目の記事となります。
https://adventar.org/calendars/5231

本記事は、ゲーム業界にプログラマとして入って2年目になる私が、業界に入るにあたってやっておいてよかったこと、やっておけばよかったこと、その他どうでもいいことを、訴えられない範囲内で後出しジャンケン的につらつら書き並べていくものになります。
まだまだ学生生活を謳歌する業界志望の学生さん、もうすぐ就活の学生さんも、後出しジャンケンで有利に内定を勝ち取ってください。

# そもそも、ゲーム開発におけるプログラマの立ち位置とは？
ゲーム開発には、(おそらく)どのようなプロジェクトであっても大きく分けて３つの職種があります。
1. 企画
2. 美術
3. 技術(プログラマー)←これ
このうちプログラマーは企画が所望するゲームそのものの実装や、ゲーム開発の機能を実装していきます。
ゲームの面白さを向上させるのは企画の仕事なので、プログラマの仕事は、ゲームの面白さ向上の技術的サポートということになります。
FPSの開発に例えると、例えば新規の銃を実装するのは、実はプログラマの仕事ではなく企画の仕事になります。
この場合、プログラマは銃の追加ツールの実装を行うのが仕事です。
美術チームが作成した銃器ポリゴンを登録し、ダメージや弾速度、発射間隔などのパラメータを企画が設定すれば、新しい銃が登録できるようなツールですね。
あとは、企画が要求したUIを美術がガワだけ作成して、プログラマーがデータを流し込めるようにしたりすることもあります。
このようにして、企画が求める機能を追加したり、改修したりするのがゲームプログラマのお仕事です。

ではお仕事のイメージがなんとなく湧いたところで早速、ゲーム業界に入るために、やっておいてよかったことから列挙していきましょう。

# やっていてよかったこと
### 個人でのゲーム制作
個人やサークルでの自主的なゲーム制作は、ゲーム業界志望の就活において圧倒的なアドバンテージになります。
というか、おそらくこれがないとゲーム業界へ新卒で入るのは難しいんじゃないかと思います。
理由は簡単で、「ゲームを遊びたい人」を選考で弾くためです。
コンテンツの特性上、ゲーム業界は「作りたい人」ではなく「遊びたい人」も目指しがちですよね。
「作りたい人」なんだな、と思ってもらう方法は、ゲームの自主的な制作実績があるか、あるいは制作実績がなくても圧倒的なエンジニアリングスキルがあるかのどちらかです。

### UE4の使用経験
私が就活していた頃はまだUE4は「たまに使われるかな」くらいで、普通のゲームはほとんど自社製ツールを使って制作されていましたが、今では多くのタイトルで使用されるようになって来ました。
DirectX直書きする機会もほとんど無くなりましたし(←偏見)、何か一つゲーム制作ツールを触っておきたい、というパターンなら、UE4C++がダントツでおすすめです。(もちろん、DirectXの知識があることが選考で全く加味されないという意味ではないです)

### 塾講師,家庭教師経験
正弦、余弦定理、覚えてますか？二次方程式の解の公式、覚えてますか？
ベクトルや三角関数、微分積分の知識はゲーム制作において必須です。
とはいえゲーム業界では高卒から採用することも少なくないので、
高校数学や大学数学の完璧な理解が求められることはあまりないんじゃないでしょうか？
逆に、義務教育範囲の数学知識の徹底的な定着と、高校数学範囲の概要は押さえておく必要がありそうです。

### (志望する)企業説明会への参加
どんな組織なのか、企業理念はどんなものか、企業説明会には選考へのヒントが散りばめられています。
ミスマッチを防ぐためにも、きになる企業の企業説明会には参加しましょう。
例えば、このご時世、ちゃんとオンラインでやっているのか、社員を出社させているかどうか、
などで、パンフには現れない社風も読み取れたりします。

### コンピュータアーキテクチャ
wd先生、ありがとう💕

# やっておけばよかったこと
### C++
信じられないかもしれませんが、一部のケースを除いて、基本的に使用言語はC++です。
CもJavaScriptもPHPも嗜んでいたので、面接時には「C++も余裕っすよ」とたかを括っていましたが、
地獄を見ました。C++は腰を据えて、学生時代から逃げずに立ち向かった方がいいです。
ちなみに、BluePrintsは企画がいじるもので、プログラマが触るものではありません。

### (ちゃんと)バージョン管理ツールを使っておく
バージョン管理ツールとは、コードが事故った時にすぐになかったことにしたり、何が原因で事故ったか判別できる、魔法のツールです。
有名どころだと、gitやmercurial、subversionなどですね。
個人開発だと、バージョン管理ツールなくてもなんとかなったりするんですけど、基本的に不可欠です。
いつも呪文だと思ってるコマンド群も、きちんと理解しておきましょう。

### オブジェクト指向、コンポーネント指向をきちんと理解しておく
ゲーム開発の中でも、特に他の開発事業と異なる点は、「仕様変更は当たり前」というところです。
面白さはロジックで説明できないため、「やってみて、修正」の繰り返しになることが多いです。
ということで、仕様変更に対する柔軟性に富んだ開発手法が取られます。
少なくともオブジェクト指向は理解して、実践できるようにしておく必要があります。
そのためにはやはり、自主制作が必須となります。

# Q&A
自分が就活する時、疑問だったこと
#### Q.ゲームの提出を求められた時、どれを出せばウケがいいの？たくさん出した方がいいの？
A.自分の中での、至高の一品を出しましょう。多くて２つ。
そして、できれば学校の課題やゲームジャムなどの短期間イベントではなく自力で時間をかけて作ったものがいいです。
採用する側は、まず「作りたい」のか、「遊びたい」のかを見極めたいと思っているわけですから、自主的に制作したものがあれば「自分は作りたい人ですよ」とアピールすることができます。
課題制作を提出する際には、面接時に「自主的に制作されたゲームはないのでしょうか？」が間違いなく来ると思って回答を用意しておくのが吉です。

#### Q.言語は何を勉強しておけば良いの？
A.迷っているなら、C++一択です。

#### Q.学歴は必要？
A.正直、特殊な業界なのであまり新卒の学生に対して即戦力としての高いプログラムスキルそのものを要求してはいないように思います。
なので、良い学歴というよりは、上記の基礎がしっかり抑えられているのか？を重視しているように(現場の人間としては)感じます。

# 終わりに

なんで空のQiitaに書いてるかって？
使ってたブログのログインpasswordわかんなくなったからです。

もし、何か聞きたいことなどあれば、訴えられない範囲で答えようと思います。

就職氷河期ですが、ゲーム業界は(ゲームセンターは除いて)まだまだ元気です。
みなさんが無事、社会のレールに乗れるよう、応援しています。
Spectral ClusteringをJavaScriptで実装した

# はじめに

「[色々な機械学習処理をブラウザ上で試せるサイトを作った](https://qiita.com/norimy/items/669c19ecf2256b3ecae5)」中で実装したモデルの解説の十一回目です。

今回はSpectral Clusteringの実装について解説します。

デモは[こちら](https://ai-on-browser.github.io/)から。（TaskをClusteringにして、ModelのSpectral clusteringを選択）
実際のコードは[spectral.js](https://github.com/ai-on-browser/ai-on-browser.github.io/blob/master/model/spectral.js)にあります。

なお、可視化部分については一切触れません。

# 概説

やることは簡単で、ラプラシアン行列の固有ベクトルを求めて、その値でクラスタリングするだけです。

ラプラシアン行列や、それを求めるための重み行列にパターンがいくつかありまが、基本は同じです。

詳しい原理などは[こちら](https://mr-r-i-c-e.hatenadiary.org/entry/20121214/1355499195)に詳しく乗っていましたので、参考にしてください。

## 重み行列

重み行列$W$は、距離が近いと大きい値を持つような行列です。

実装では、K近傍とガウシアンカーネルを用いた距離を用意しています。

## ラプラシアン行列

実装でのラプラシアン行列は以下の$L_{sym}$を採用しています。

```math
\begin{eqnarray}
L_{sym} &=& D^{-1 / 2}LD^{-1 / 2}
\\
\\
L &=& D - W
\\
d_{i, i} &=& \left\{ \begin{array}{ll}
  \sum_j w_{i, j} & (i = j) \\
  0 & (i \not= j)
\end{array} \right.
\end{eqnarray}
```

# コード

## Spectral Clustering

```javascript
class SpectralClustering {
	// https://mr-r-i-c-e.hatenadiary.org/entry/20121214/1355499195
	constructor(affinity = 'rbf', param = {}) {
		this._size = 0;
		this._epoch = 0;
		this._clustering = new KMeansModel();
		this._clustering.method = new KMeanspp();
		this._affinity = affinity;
		this._sigma = param.sigma || 1.0;
		this._k = param.k || 10;
	}

	get size() {
		return this._size;
	}

	get epoch() {
		return this._epoch;
	}

	init(datas, cb) {
		const n = datas.length;
		this._n = n;
		this._l = Matrix.zeros(n, n);
		const distance = new Matrix(n, n);
		for (let i = 0; i < n; i++) {
			distance.set(i, i, 0);
			for (let j = 0; j < i; j++) {
				let d = Math.sqrt(datas[i].reduce((acc, v, t) => acc + (v - datas[j][t]) ** 2, 0));
				distance.set(i, j, d);
				distance.set(j, i, d);
			}
		}

		let affinity_mat;
		if (this._affinity === 'knn') {
			const con = Matrix.zeros(n, n);
			for (let i = 0; i < n; i++) {
				const di = distance.row(i).value.map((v, i) => [v, i]);
				di.sort((a, b) => a[0] - b[0]);
				for (let j = 1; j < Math.min(this._k + 1, di.length); j++) {
					con.set(i, di[j][1], 1);
				}
			}
			con.add(con.t)
			con.div(2);
			affinity_mat = con;
		} else {
			affinity_mat = distance.copyMap(v => Math.exp(-(v ** 2) / (this._sigma ** 2)));
		}
		let d = affinity_mat.sum(1).value;
		this._l = Matrix.diag(d)
		this._l.sub(affinity_mat);

		d = d.map(v => Math.sqrt(v))
		for (let i = 0; i < this._n; i++) {
			for (let j = 0; j < this._n; j++) {
				this._l.set(i, j, this._l.at(i, j) / (d[i] * d[j]));
			}
		}

		this.ready = false
		this._l.eigenVectors(data => {
			this._ev = data;
			this.ready = true;
			cb && cb();
		});
	}

	add() {
		this._size++;
		this._clustering.clear();
		const s_ev = this._ev.select(null, this._n - this._size, null, this._n);
		this._s_ev = s_ev.toArray();
		for (let i = 0; i < this._size; i++) {
			this._clustering.add(this._s_ev);
		}
	}

	clear() {
		this._size = 0;
		this._epoch = 0;
		this._clustering.clear();
	}

	predict(datas) {
		return this._clustering.predict(this._s_ev);
	}

	fit(datas) {
		this._epoch++;
		return this._clustering.fit(this._s_ev);
	}
}
```
[Python] BFS（幅優先探索）　ABC007C

#[ABC1007C](https://atcoder.jp/contests/abc007/tasks/abc007_3)
問題文にとても分かり易い説明がある。
参考
[BFS (幅優先探索) 超入門！ 〜 キューを鮮やかに使いこなす 〜](https://qiita.com/drken/items/996d80bcae64649a6580)

```python:サンプルコード
from collections import deque

# (sx, sy) から (gx, gy) への最短距離を求める
# 辿り着けないと inf（出力されることは想定されていない）
def bfs():
    # すべての点の距離を inf で初期化
    d = [[float("inf")] * m for i in range(n)]

    # 移動4方向のベクトル
    dx = [1, 0, -1, 0]
    dy = [0, 1, 0, -1]

    for i in range(n):
        for j in range(m):
            # 地図情報にスタートとゴールを設定
            if maze[i][j] == "S":
                sx = i
                sy = j
            if maze[i][j] == "G":
                gx = i
                gy = j

    # スタート地点をキューに入れ、その点の距離を0にする
    que = deque([])
    que.append((sx, sy))
    d[sx][sy] = 0

    # BFS本体 キューが空になるまでループ
    while que:
        # キューの先頭を取り出す
        p = que.popleft()
        # 取り出してきた状態がゴールなら探索をやめる
        if p[0] == gx and p[1] == gy:
            break
        # 移動4方向をループ
        for i in range(4):
            # 移動した後の点を (nx, ny) とする
            nx = p[0] + dx[i]
            ny = p[1] + dy[i]

            # 移動が可能かの判定とすでに訪れたことがあるかの判定
            # d[nx][ny] != inf なら訪れたことがある
            if 0 <= nx < n and 0 <= ny < m and maze[nx][ny] != "#" and d[nx][ny] == float("inf"):
                # 移動できるならキューに入れ、その点の距離を p からの距離 +1 で確定する
                que.append((nx, ny))
                d[nx][ny] = d[p[0]][p[1]] + 1

    return d[gx][gy]


n, m = map(int, input().split())
# リストのリストとして読込
maze = [list(input()) for i in range(n)]

print(bfs())
```
docker build時にaptの通信で使用するプロキシサーバを指定できるようにする

コンテナをビルドする際、aptのみプロキシサーバを経由させたかったため、aptの通信のみプロキシを通す方法を調べました。

## Dockerfileに記載する内容

`--build-arg`に指定した内容を元に、apt用のプロキシサーバの設定を行うようなDockerfileを作成します。

### `docker run`したときにも`docker build`したときと同じプロキシサーバを使う場合

自分の場合、`docker run`でコンテナを実行する際にもそのプロキシを使用して欲しいため、`/etc/apt/apt.conf.d/`にプロキシの設定を行なっています。

```dockerfile:Dockerfile
FROM ubuntu:20.04
ARG APT_PROXY
RUN if [ "$APT_PROXY" != "" ]; then echo "Acquire::http { Proxy \"$APT_PROXY\"; };" > /etc/apt/apt.conf.d/01proxy; fi
RUN apt update && \
    apt install --no-install-recommends -y curl && \
    rm -rf /var/lib/apt/lists/*
```

まず、2行目のARGで`APT_PROXY`という名前のビルド引数を設定できるようにしています。`APT_PROXY`に指定したプロキシがaptの通信に使われることになります。

1つ目のRUNで`/etc/apt/apt.conf.d/01proxy`にプロキシの設定を行なっています。ビルド時に`APT_PROXY`が指定された場合にのみ`01proxy`を作成するので、`APT_PROXY`が未指定であれば、aptはインターネット上のリポジトリを直接取得します。

2つ目のRUNでは例としてcurlをインストールしています。

### `docker build`だけプロキシを使用して、`docker run`するときにはプロキシを使用しない場合

もし、コンテナビルド時だけプロキシを使用して、`docker run`するときにはプロキシを使用して欲しくない場合は、apt.conf.dに設定する代わりに、以下のようにhttp_proxy環境変数を設定すればビルド時だけ指定したプロキシを使うことができると思います。

```dockerfile:Dockerfile
FROM ubuntu:20.04
ARG APT_PROXY
RUN export http_proxy="$APT_PROXY"; \
    apt update && \
    apt install --no-install-recommends -y curl && \
    rm -rf /var/lib/apt/lists/*
```

## コンテナのビルド方法

`docker`コマンドを使用する場合、以下のようにビルド時に`--build-arg`を使用してプロキシを指定してビルドします。

```shell
$ docker build --build-arg APT_PROXY=http://proxy:8080/ -t apt-proxy-test .
```

docker-composeを使用する場合には、以下のようにargsでAPT_PROXYを設定します。

```yaml:docker-compose.yml
version: "3"
services:
  apt-proxy-test:
    build:
      context: .
      args:
        - APT_PROXY=http://proxy:8080/
    restart: unless-stopped
```

## 参考ページ
* [docker - run apt-get with proxy in Dockerfile - Stack Overflow](https://stackoverflow.com/questions/48749200)
[Ruby  on Rails] カラムの追加と削除

#カラムの追加
`rails g migration add_追加したいカラム名_to_追加先のテーブル名`　でコマンドを実行します。

例えば `posts` テーブルに　`user_id` のカラムを追加したい場合は以下のようになります。

```
$ rails g migration add_user_id_to_posts
```

これによって作成されたマイグレーションファイル（db/migrate）の中身を変更します。
changeメソッドが既に定義されているのでその中に `add_column :追加先のテーブル名, :追加するカラム名, :そのデータ型` を書いていきます。

```
def change 
  add_column :posts, :user_id, :integer
end
```

その後 `rails db:migrate` を実行しましょう。
実行することで初めてテーブルに変更が行われます。

```
$ rails db:migrate
```

これでカラムを追加することに成功しました。

#カラムの削除

`rails g migration remove_削除したいカラム名_to_カラムを削除するテーブル名` でコマンドを実行します。

例えば `posts` テーブルに　`user_id` のカラムを削除したい場合は以下のようになります。

```
$ rails g migration remove_user_id_to_posts
```

カラムの追加と同様にマイグレーションファイルの中身を変更したあとに `rails db:migrate` を実行します。

```
def change 
  remove_column :posts, :user_id, :integer
end
```


```
$ rails db:migrate
```

これでカラムを削除することに成功しました。

カラムの変更後に、開発の初期段階などで一度データベースを空にしたい場合は以下のコマンドを実行します。


```
$ rake db:migrate:reset
```

データベースには何も入っていない状態になります。
Mapと仲良くなりたい【Java初心者】

## はじめに
Java歴5ヶ月目です（もうそんなに経っていたのか）。
今まで避けていたMapとついに関わって、仲良くなりたいと思います。

3ヶ月の研修の間、オンリーArrayListでやってきました。
それでもなんとかなったのです。

しかし、初めて現場に入り、こんなにもMapが使われているとは思いませんでした。
あまりに使ってなかったので、put？ってなりました。やばすぎる。

Mapについてまとめられている記事はたくさんありますが、
Map苦手マンだった私でも分かりやすいと思った部分をまとめていきたいと思います。

## Mapとは
キー（key）と値（value）をペアにして複数のデータを格納できるものです。
「キー」に対応する「値」を探せる辞書のようなものです。

ええっと、りんごは英語でなんて言うんだっけな。。
Mapを使えば、キー「りんご」で、値「apple」を探すことができます。

## Mapを使っていこう！初期化
```
Map<キーの型名, 値の型名> オブジェクト名 = new HashMap<>();

// 例
Map<String, String> map = new HashMap<>();
```

## キーと値のペアを追加する：put
```
map.put("りんご", "apple");
map.put("オレンジ", "orange");
map.put("バナナ", "banana");
```

## キーに対応する値を得る：get
```
System.out.println(map.get("りんご"));
// 出力結果 apple
```

## 拡張for文で値を得る
mapにいくつかデータを入れたのでfor文を使って全て表示したいですよね。
この部分が私の苦手なところでした。
ここからはキーと値が分かりやすいように、キーを商品名、値を値段でやっていきます。

```
Map<String, Integer> fruits = new HashMap<>();
fruits.put("りんご", 128);
fruits.put("オレンジ", 98);
fruits.put("バナナ", 198);
```

### キーも値も表示したい：entrySet、keySet
```
for (Map.Entry<String, Integer> entry : fruits.entrySet()) {
  System.out.println(entry.getKey() + "は" + entry.getValue() + "円です。");
}

// 出力結果
// りんごは128円です。
// オレンジは98円です。
// バナナは198円です。
```
Entryってなんや！長すぎてイヤ！！

エントリ（entry）とはキーと値のペアのことです。
entrySetは全てのエントリを得るメソッドです。

同じことをkeySetでもっとシンプルに書けます。
keySetは全てのキーを得るメソッドです。

```
for (String fruit : fruits.keySet()) {
  System.out.println(fruit + "は" + fruits.get(fruit) + "円です。");
}

// 出力結果
// りんごは128円です。
// オレンジは98円です。
// バナナは198円です。
```
だったらこれだけ覚えときゃいいやん。
教科書、なんで最初にややこしいもの書くのよ。。

### 値だけでいいとき：values
うーん、りんごっていくらだっけなぁ。値段だけ知りたい。

```
for (int value : fruits.values()) {
  System.out.println(value + "円");
}

// 出力結果
// 128円
// 98円
// 198円
```

## その要素が含まれているか：containKey、containValue
```
if (fruits.containsKey("バナナ")) {
  System.out.println("バナナがオススメです。");
}

// 出力結果 バナナがオススメです。

if (fruits.containsValue(98)) {
  System.out.println("お買い得です。");
} 

// 出力結果 お買い得です。
```

## 他のメソッド：size、remove、clear、isEmpty
要素数を得る（size）、要素を削除する（remove）、全要素を削除する（clear）、
ここらへんはListなど他コレクションと同様です。
先ほどの商品名と値段のマップを使います。

```
System.out.println(fruits.size());

// 出力結果 3
```
```
// 「キー：りんご、値：128」を削除。引数はキーだけでOK
fruits.remove("りんご");
```
```
// マップに入れた全ての要素を削除。引数は必要なし。
fruits.clear();
```
```
if (fruits.isEmpty()) {
  System.out.println("申し訳ありません。今日は売り切れです。");
}

// 出力結果 申し訳ありません。今日は売り切れです。
```

## さいごに
Qiitaに書くことで整理されました。
これで少しはMapと仲良くなれたかも？！

## 参考
・[Java言語プログラミングレッスン 第3版(下) オブジェクト指向を始めよう 結城 浩 (著)](https://www.amazon.co.jp/Java%E8%A8%80%E8%AA%9E%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%E3%83%AC%E3%83%83%E3%82%B9%E3%83%B3-%E7%AC%AC3%E7%89%88-%E4%B8%8B-%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E6%8C%87%E5%90%91%E3%82%92%E5%A7%8B%E3%82%81%E3%82%88%E3%81%86-%E7%B5%90%E5%9F%8E/dp/4797371269)
・https://www.tech-teacher.jp/blog/java-map/