OmniAICreator/Qiita-1.07M huggingface dataset:
ajaxとは?【初心者向け】

#前置き
Ajaxとは、「Asynchronous JavaScript + XML」の略で、ブラウザ内でJavaScriptの通信機能を使って、XML形式のデータを送受信する技術のことです。

#目次
1.他画面遷移とは?
2.自画面遷移とは?
3.非同期通信（Ajax）とは?
4.Ajaxの書き方（jquery）

Ajaxについて知るためには1~3の知識を身につけると理解が深まります。
※非同期通信について理解している方は目次の4まで読み飛ばしてもらって構いません。

#1.他画面遷移とは?
他画面遷移とはログイン画面で新規登録をクリックすると、
アカウント登録画面に移動するように、別のページへ遷移することを意味します。
![](http://yuml.me/diagram/class/[ログイン画面] ->[アカウント登録画面])


#2.自画面遷移とは？
一方、自画面遷移とはログイン画面でログインが失敗して「パスワードが間違っています！」というエラーメッセージが表示されるように同じ画面（同じURL）が帰ってくる処理です。
この時、Ajaxで書かれていなければ、全てのHTMLのソースコードが読み込まれています。（同期通信と言います）
![](http://yuml.me/diagram/class/[ブラウザ] <- ログイン画面のソースコード[サーバ])
同期通信では、ページ表示のためのHTMLとjavascript両方のソースコードが全て帰って来るため、再度ページが更新されています。

#3.非同期通信(Ajax)とは？
非同期通信とは、自画面遷移の一種です。”ログイン画面”でログインに失敗した際、同期通信では”ログイン画面”で使われている全てのHTMLコードとjavascriptコードが帰ってきますが、非同期通信では、ページの更新はせず、「パスワードが間違っています！」というメッセージだけが帰ってきます。
![](http://yuml.me/diagram/class/[ブラウザ] <- パスワードが間違っています！[サーバ])
つまり、必要な情報のみ取得して表示させています。
なので同期通信よりも速度が早くなります。

#4.Ajaxコードの書き方
Ajaxのソースコードの例は以下の通りです。

```javascript

$('#button').on('click', function(){ 
  // Ajax通信を開始
  $.ajax({
    url: 'controller.java',　//接続するクラス名(phpでもok)
    type: 'GET',　　　　　　　 //GET通信なのか、POST通信なのか
    dataType: 'json',　　　　 //javaに送信するデータのタイプ
        data: {　　　　　　    //この形式の書き方をjsonと言います。
        userid: 1,           //useridという変数名に1という情報を保持
        password: 'hoge',
    },

  })
  .success(function(result) { 
      // 通信成功時の処理を記述(resultにはjavaから取得してきた情報を保持している）
  })
  .error(function(result) {
      // 通信失敗時の処理を記述
  });
})
```
Node.jsへのMySQLのインストール方法

node.jsがインストールされているフォルダに移動して、以下のコマンドを実行する。

```
npm install mysql
```
■実行結果
![image.png](https://qiita-image-store.s3.amazonaws.com/0/204260/4a89c62a-10e1-d61d-f971-24831c6dbf8e.png)
pip の version specifier の挙動を確かめるには

# TL; DR

```python
>>> from packaging.specifiers import SpecifierSet
>>> '0.18.1.0' in SpecifierSet('== 0.18.1')
True
```

# `pip` の version specifier

`pip` には、[`npm`](https://semver.npmjs.com/) など他のパッケージマネージャ同様、バージョンを柔軟に指定するための仕組みがあります。

もっともよく使われるのは `==` でしょうか。

```bash
pip install flake8-import-order==0.18
```

この他にも、下記の6種類の比較演算子が使えます。

> - `~=`: Compatible release clause
> - `==`: Version matching clause
> - `!=`: Version exclusion clause
> - `<=`, `>=`: Inclusive ordered comparison clause
> - `<`, `>`: Exclusive ordered comparison clause
> - `===`: Arbitrary equality clause.

https://www.python.org/dev/peps/pep-0440/#version-specifiers

# この version はこの specifier にマッチするか問題

さて、問題です。`== 0.18.1` は `0.18.1.0` にマッチするでしょうか？　`=== 0.18.1` だったら？ `~= 0.18.1` だったら？

詳細な仕様は上記ドキュメントに記載されていますが、細かい挙動がわりと複雑で、意外とすんなりとは理解しづらいものです（本記事の目的から外れるので解説はしません）。

そんなときは、`pip` が使っている [pypa/packaging](https://github.com/pypa/packaging) をそのまま使いましょう！

```python
>>> from packaging.specifiers import SpecifierSet
>>> '0.18.1.0' in SpecifierSet('== 0.18.1')
True
>>> for spec in ['== 0.18.1', '== 0.18.*', '~= 0.18.1', '=== 0.18.1']:
...     for version in ['0.18.0', '0.18.1', '0.18.1.0', '0.18.2', '0.19']:
...         match = version in SpecifierSet(spec)
...         print('{:10s}{:10s} ... {}'.format(version, spec, match))
...     print('-' * 30)
...
```
```
0.18.0    == 0.18.1  ... False
0.18.1    == 0.18.1  ... True
0.18.1.0  == 0.18.1  ... True
0.18.2    == 0.18.1  ... False
0.19      == 0.18.1  ... False
------------------------------
0.18.0    == 0.18.*  ... True
0.18.1    == 0.18.*  ... True
0.18.1.0  == 0.18.*  ... True
0.18.2    == 0.18.*  ... True
0.19      == 0.18.*  ... False
------------------------------
0.18.0    ~= 0.18.1  ... False
0.18.1    ~= 0.18.1  ... True
0.18.1.0  ~= 0.18.1  ... True
0.18.2    ~= 0.18.1  ... True
0.19      ~= 0.18.1  ... False
------------------------------
0.18.0    === 0.18.1 ... False
0.18.1    === 0.18.1 ... True
0.18.1.0  === 0.18.1 ... False
0.18.2    === 0.18.1 ... False
0.19      === 0.18.1 ... False
------------------------------
```

### 公式へのリンク

- :book: ドキュメント https://packaging.pypa.io/en/latest/specifiers/
- :octocat: ソースコード https://github.com/pypa/packaging/blob/master/packaging/specifiers.py

# `~=` を使おう

書きたいことはここまでですが、最後に補足を一つ。

前述の6種類の中では `==` が使われがちではありますが、公式には推奨されていません。

> The use of == (without at least the wildcard suffix) when defining dependencies for published distributions is strongly discouraged as it greatly complicates the deployment of security fixes. 

https://www.python.org/dev/peps/pep-0440/#version-matching

拙訳

> == を（少なくともワイルドカードなしで）公開パッケージに対して使うと、セキュリティフィックスのデプロイが極めて煩雑になります。そのため、できる限り使用しないことをおすすめします。

かわりに、`~=` (compatible release operator) を使うようにしましょう。

これにより

- セキュリティフィックス・バグフィックスに追随しやすい
- 仕様変更に振り回されにくい

の2点を両立できます。
axiosでrequestと同じようにjarを使えるようにする方法

# メモ
ほぼ自分用のメモです axiosでrequestの時に使っていたjarが簡単に使えませんでしたが、他のライブラリを導入することで解決できるようです。

```javascript
request = request.defaults({jar: true}); 
```
requestだとこんな感じのコードのやつです。


# 必要なモジュールの導入

yarnで入れているのでnpmの方は `yarn add` を `npm i` とかに置き換えてください。

```
yarn add axios --dev
yarn add axios-cookiejar-support --dev
yarn add tough-cookie --dev
```

# コード
```javascript
const axiosCookieJarSupport = require('axios-cookiejar-support').default;
const tough = require('tough-cookie');
const cookieJar = new tough.CookieJar();
axiosCookieJarSupport(axios);
axios.defaults.withCredentials = true;
axios.defaults.jar = cookieJar;
```

# 参考資料

https://github.com/3846masa/axios-cookiejar-support
App EngineとCompute Engineのレイテンシー・価格比較

# お題
[前の記事](https://qiita.com/sky0621/items/08d46d521df3729a445a)で[GCP Ping](http://www.gcping.com/)というリージョン別のレイテンシーが出るサイトを紹介したのだけど、
レイテンシーは低くても東京リージョンは他のリージョンより高くつく場合があると書いた。
ので、実際に一覧にしてみる。
最初は主要なサービス別に一覧化しようと思ったものの、一覧にするの意外に面倒で、ひとまずGAEとGCEだけにする。

# 前提
## GAE(App Engine)
https://cloud.google.com/appengine/pricing?hl=ja

- [Standard環境](https://cloud.google.com/appengine/docs/standard/?hl=ja)のJava
- [インスタンスクラス](https://cloud.google.com/appengine/docs/standard/?hl=ja#instance_classes)はデフォルトの「F1」(CPU:600MHz, メモリ:128MB, スケールタイプ:自動)
- １インスタンス１時間あたりの費用

## GCE(Compute Engine)
https://cloud.google.com/compute/pricing?hl=ja

- インスタンスは「n1-standard-1」(仮想CPU数:1, メモリ:3.75GB)
- １インスタンス１時間あたりの費用
- プリエンプティブや継続利用割引は考慮しない

# 実践
レイテンシーの低い順に一覧化。太字は同一サービスでの最安値。

| REGION | MEDIAN<br>LATENCY | GAE | GCE |
|:--|:--|:--|:--|
| 東京<br>(asia-northeast1) | 12ms | $0.07 | $0.0610 |
| 台湾<br>(asia-east1) | 49ms | - | $0.0550 |
| シンガポール<br>(asia-southeast1) | 79ms | - | $0.0586 |
| ロサンゼルス<br>(us-west2) | 109ms | - | $0.0571 |
| シドニー<br>(australia-southeast1) | 114ms | $0.068 | $0.0674 |
| オレゴン<br>(us-west1) | 120ms | - | **$0.0475** |
| ムンバイ<br>(asia-south1) | 137ms | $0.060 | $0.0570 |
| アイオワ<br>(us-central1) | 139ms | **$0.05** | **$0.0475** |
| 北バージニア<br>(us-east4) | 165ms | $0.055 | $0.0535 |
| サウスカロライナ<br>(us-east1) | 169ms | **$0.05** | **$0.0475** |
| モントリオール<br>(northamerica-northeast1) | 175ms | - | $0.0523 |
| ロンドン<br>(europe-west2) | 240ms | $0.060 | $0.0612 |
| ベルギー<br>(europe-west1) | 246ms | **$0.05** | $0.0523 |
| オランダ<br>(europe-west4) | 246ms | - | $0.0523 |
| フランクフルト<br>(europe-west3) | 248ms | $0.060 | $0.0612 |
| サンパウロ<br>(southamerica-east1) | 275ms | $0.075 | $0.0754 |
| フィンランド<br>(europe-north1) | 279ms | - | $0.0523 |

# まとめ
というわけで、レイテンシー重視でなく、とにかく安くというのであれば東京リージョンにこだわる必要はないみたい。
例えば、GCEで台湾リージョンとのレイテンシー差くらいなら許容範囲なら、それだけで１時間あたり$0.006安くなる。
（他の要素を考慮せず）本当に単純に１ヶ月あたりにすると、$3(約341円) の差。
最安値の中で最もレイテンシーの低いオレゴンリージョンだと、$7(約795円) の差。ただ、レイテンシーの差は10倍・・・。

- 東京リージョン：$31.17
- 台湾リージョン：$28.11
- オレゴンリージョン：$24.2725

う〜ん、この差がどれほどのものなのか、たかだか１ヶ月に数100円の差と見るのかどうなのか・・・。
あと、今回はコンピューティング要素の比較だったけど、業種（？）によっては、業務情報をストレージに格納するとして、
それを国外に置くこと自体がNGだったりもするらしいので、やっぱり一概には決められないみたい。
Docker Registry Hub にイメージをpush

localからDocker Hubにimageをpushする方法

# 1. Docker Hubアカウントの作成/レポジトリ作成

Docker Hubアカウントを作成
作成は下記から行えます。

https://hub.docker.com/

レポジトリの作成
上記でアカウント作成後にログインし、Create Repositoryをクリックして
進めていきます。

# 2. Dockerイメージのpush

上記で作成したリポジトリにpushしたいイメージを選択
今回は下記のechoというサンプルイメージをプッシュします。

``` bash
# docker image ls | grep echo
example/echo                               latest              a890aba05da1        2 weeks ago         750MB
```

Docker Hubにログイン

``` bash
# docker longin
...
Login Succeeded
```

ログインが成功したらローカルにある先ほどのイメージに対して
pushしたいリポジトリ名へとタグを作成します。
そしていざ、push

``` bash
# docker tag ローカルにあるimage名 ユーザ名/リポジトリ名:タグ

# docker push ユーザ名/リポジトリ名
...
The push refers to repository [docker.io/ユーザ名/リポジトリ名]
```

これでイメージのpushが完了ですので
あとは他のdocker hostからイメージをpullして実行することができるようになります。
UIPageViewControllerでページ遷移時に処理したいことを書くときのTip

# たまに解説サイトにあるアンチパターン
ページを変わったときにする処理を`UIPageViewControllerDataSource`の`pageViewController`関数中に書く解説サイトをいくつか見ます。

```swift
extension PageViewController : UIPageViewControllerDataSource {

    func pageViewController(pageViewController: UIPageViewController, viewControllerBeforeViewController viewController: UIViewController) -> UIViewController? {
        ... 
        callWhenPageChanged() // ページが変わったら呼びたい処理

        ... /*何かしらのViewControllerをreturnする処理*/
    }

    func pageViewController(pageViewController: UIPageViewController, viewControllerAfterViewController viewController: UIViewController) -> UIViewController? {
        ...
        callWhenPageChanged() // ページが変わったら呼びたい処理

        ... /*何かしらのViewControllerをreturnする処理*/
    }
}
```
`callWhenPageChanged()`は、例えば、`UIPageControl`（インジケータ）の現在ページの操作を変更するための処理などが考えられますね。その場合、遷移先になりうるViewControllerの情報が必要になるのも理解できます。

確かにここの`pageViewController`は、左右にフリックしたときなどに、ページデータを提供するために呼ばれるのは確かです。
しかし、***あくまでページリソースを扱う前提の関数に、そのような処理を書くのは本質的ではないと私は思います。***
というか、***本質的でないというか、この実装は間違えています。*** この２つの関数は現在のページの前後のページにあたるViewControllerを返す関数です。ページが変わるごとに毎回呼ばれるので、毎ページで`callWhenPageChanged`が２回呼ばれますね。


# で、何を使えばいいの？
実は、すでに`UIPageViewControllerDelegate`という素晴らしいDelegateが存在します。
[リファレンス](https://developer.apple.com/documentation/uikit/uipageviewcontrollerdelegate)にもある通り、`UIPageViewControllerDelegate`は、以下2つの実装をサポートしています。

```swift
// ジェスチャーによる遷移が始まる場合に呼ばれる
// willTransitionTo.firstを見れば、次の遷移先のページのインスタンスを見ることができる
func pageViewController(UIPageViewController, willTransitionTo: [UIViewController])

// ジェスチャーによる遷移が終わった場合に呼ばれる
func pageViewController(UIPageViewController, didFinishAnimating: Bool, 
                        previousViewControllers: [UIViewController], 
                        transitionCompleted: Bool)
```
これらは、**ジェスチャーによる画面遷移イベントが発生した呼ばれる関数**です。こちらのどちらかに書くほうが適してますね。

# 現在のページ(ViewController)を取得したい
具体的に、`callWhenPageChanged`を使いたいときの例を書いてみます。

```swift
extension PageViewController: UIPageViewControllerDelegate { 
        // ジェスチャーによる遷移が終わった場合に呼ばれる
        func pageViewController(_ viewController: UIPageViewController, didFinishAnimating: Bool, 
                                previousViewControllers: [UIViewController], 
                                transitionCompleted: Bool) {
                ...
                callWhenPageChanged() // ページが変わったら呼びたい処理

                ...
        }
}
```

では、現在表示されているページ(ViewController)を取得を取得したい場合はどうすればいよいでしょうか？
上記の関数(`didFinishAnimating`がある方)では、第１引数の`viewController.viewControllers.first`が現在表示されているページに当たりますので、それを見てもらえばよいです。

# 追記
以下 @azuma317 さんからコメントを頂いたのでご紹介します。

> DataSourceなので、ページ構成時に呼ばれそうだけど、意外と呼ばれなかったりしますね...
> 遷移後の処理はDelegateに書くべきだけど、transitionCompletedがtrueのときじゃないと、画面遷移を失敗したときにも呼ばれるっぽいです。

```swift:PageViewController.swift
// Delegate内
if completed {
    callWhenPageChanged()
}
```

もし画面遷移が行われないときに`callWhenPageChanged`が呼ばれるとまずいケースもあると思うので、`completed`で分岐させるのは必要ですね。

# 最後に
`UIPageViewControllerDelegate`の使い方をちょっとだけ解説しました。間違っていることがあればご報告お願いします。
単体テストで開始時にモックサーバを起動し、終了時に停止する

## やりたい事
JavaScript の単体テストで、テスト対象のコードがサーバと通信して JSON 形式で受信を受け取る場合、サーバと通信する部分を置き換えてテストコード内部で完結するようにしたい。
しかし、通信する部分をモックで置き換えるのはしたくないので、テスト用に JSON を返すサーバを立てたい、そしてサーバは開始時に起動、終了時に停止させたい。

## どうやるか
[json-server](https://github.com/typicode/json-server) は [こんな感じに](https://github.com/typicode/json-server/issues/153#issuecomment-147356676) サーバの実装をすればできる。
json-server は、パスと返る JSON の内容をコードから指定できるので、テストケースに合わせてテストコード内で修正できる。

## 実装例

```js
var jsonServer = require("json-server");
var assert = require("assert");
var http = require("http");

describe("json test", () => {
    let server;
    before(() => {
        const app = jsonServer.create();
        const router = jsonServer.router(
            {"tasks": [{"description": "first context"},{"description":"second text"}]});
        const middleware = jsonServer.defaults();

        app.use(middleware);
        app.use(router);
        server = app.listen(8080, () => {
            console.log("started");
        });
    });
    after(() => {
        server.close(() => {
            console.log("closed");
        });
    });

    it("test 1", (done) => {
       http.get("http://localhost:8080/tasks", (res) => {
          let body = '';
          res.setEncoding('utf-8');
          res.on('data', (chunk) => {
              body += chunk;
          });
          res.on('end', (res) => {
              res = JSON.parse(body);
              assert(res[0].description == 'first context');
              assert(res[1].description == 'second text');
              done();
          });
       }); 
    });
});
```

### 実行例
```
% ./node_modules/.bin/mocha


  json test
started
GET /tasks 200 9.264 ms - 88
    ✓ test 1 (38ms)

closed

  1 passing (67ms)
```
[メモ][iTerm2]Session "Shell" in tab #1 just terminated

## 事象

　iTerm2を起動したら、更新を促されたので、v3.2.1に更新したら、急に下記のエラーが出て動かなくなりました。

```
Session "Shell" in tab #1 just terminated
```

## 対策

　iTermのPreferences → Profilesにて、下記のように、Commandのラジオボタンを選択してから、<font color="red">/bin/bash -l</font> を設定すれば、iTerm2を問題なく使えました。
<img width="1838" alt="tmp.jpeg" src="https://qiita-image-store.s3.amazonaws.com/0/117156/279d3767-8609-8f6d-7338-a9f1e77dc8e8.jpeg">
firebaseだけじゃない。MongoDBで更新された値をリアルタイムに取得する方法

データベースの値の変更をリアルタイムに取得したい時ありますよね。例えばチャットのメッセージとか何かのログとか。

そのときに便利なのが[Firebase Realtime Database](https://firebase.google.com/docs/database/?hl=ja)です。
無料でも利用できて、データベースの値に追加があったり変更があったらそれを受け取ることができるNoSQLなデータベースです。


今回私は研究プロジェクトの関係で大量のリクエストが発生する問題がありました。
Firebaseだと保存容量が無料枠に収まらない可能性もあり、もともとログ保存用に立っていたMongoDBサーバーでリアルタイムに値を取れないか試してみました。

## Change Streamsを使う
[Change Streams](https://docs.mongodb.com/manual/changeStreams/)
MongoDB3.6以降の機能にChange Streamsというものがあります。
これはデータベースに追加された値をストリームで受け取れる機能です。

以下のような簡単なコードでリアルタイムに値を取得することができます。

```python
from pymongo import MongoClient

client = MongoClient('localhost', 8001)
db = client['db']
collection = db['logs']
st = collection.watch()
while True:
    print(next(st))

```
collectionに`.watch()`をしてあげるだけです。こんなに簡単にできてしまいます。

ただ、この機能はレプリケーションを組んでないMongoDBサーバーだとエラーになってしまいます。
データベースのリアルタイム処理では一貫性を保つことが重要なためです。

## MongoDBでレプリケーションの構築
[MongoDB で 2台構成 の レプリカセット を 構築する 方法](https://garafu.blogspot.com/2018/02/mongodb-2instance-replicaset.html)
このブログがとても詳細にわかりやすく載っているためここでは省略します。

## まとめ
レプリカセットさえ組んでしまえば非常に簡単にリアルタイムに値の取得をすることができますね。
とくにMongoDBのようなNoSQLデータベースはテーブルを組まないため、ログのような即時性が必要なデータとの相性が良いので、このような機能は大変便利だと思います。
TeamViewer13をCentOS7にインストールする

# はじめに
CentOS7にTeamviewer13をインストールしていきます。落とし穴も含めて紹介していきます。
CDコマンド、PRMコマンドの操作方法を理解していることを前提に説明をします。

# インストーラーの取得
以下のサイトから、Redhat、CentOS、Fedora用のRPMパッケージをダウンロードし、任意の場所に配置してください。
https://www.teamviewer.com/ja/
ダウンロートしたパッケージの名前は、「teamviewer_13.2.13582.x86_64.rpm」みたいになっていると思います。

# インストール操作
インストールを進めていきます。
### 注意点：ダブルクリックしてはだめ
GUIでパッケージをダブルクリックしても、「サポート外です」といったメッセージが表示されるだけです。
以下の手順に従い、端末上でインストールを行いましょう。

## 端末を起動し、依存のあるライブラリをインストール
以下のコマンドを入力することで、teamviewerがインストールされます。

```sh

yum install qt5-qtdeclarative qt5-qtwebkit qt5-qtx11extras qt5-qtgraphicaleffects qt5-qtquickcontrols
yum -y install epel-release
rpm -ivh teamviewer_13.0.9865.x86_64.rpm
```
インストール完了後は、GUIのメニューバーの「アプリケーション」→「インターネット」のなかに「Teamviewer」が表示されています。
クリックして起動してください。

### 注意点：依存のあるライブラリを先に入れること
上記のコマンドの上の2行は最後の行より先に行う必要があります。依存しているライブラリを何故か自動で取得してくれません。

# 参考
https://www.underthereign.com/index.php/it-related-information/install-teamviewer-13-on-centos-7
初心者がRailsガイドを1から100まで読んでみる　Railsをはじめよう編その10　バリデーション

####5.10.検証（バリデーション）の追加

バリデーション？
何それおいしいの？

バリデーションとは、入力値が妥当かどうかを検証する機能です。
入力されたデータは最終的にモデルくんが食べるので、バリデーションはモデルくんにしてもらいましょう。

```article.rb
class Article < ApplicationRecord
end
```
今のarticleモデルには何にも実装されていません。
好き嫌いなく全てのデータを食べてくれます。
毒になりそうなものまでもね。

このままじゃarticleモデルくんがおデブになってしまうので、
食事制限してあげましょう。

```article.rb
class Article < ApplicationRecord
	validates :title, presence: true,
            		  length: { minimum: 5 }
end
```
titleに対するバリデーションを設定しました。
`presence`：trueにすれば項目が必須になります
`length`：長さに関する制限ですね。今回は５文字以上。

<img width="338" alt="スクリーンショット 2018-09-29 23.16.04.png" src="https://qiita-image-store.s3.amazonaws.com/0/283826/63fe7b88-b01d-ded8-8291-0604c9de0141.png">
これで保存してみると　…

<img width="448" alt="スクリーンショット 2018-09-29 23.16.32.png" src="https://qiita-image-store.s3.amazonaws.com/0/283826/b7f5b15b-c3df-3cad-7c9b-dd80d73a81c6.png">

「あ」ってタイトルの記事はバリデーションを満たしてないから保存されませんでした。
（うひょーもだめなんだけど、バリデーション追加前に保存したやつだから残っちゃってるね。消したいんだけど）

サイレントで保存されないのは不親切なので、バリデーションの結果NGだったらユーザに教えてあげるようにしよう。

コントローラのnewアクションとcreateアクションを変更しました。

```articles_controller.rb
	def new
  		@article = Article.new
	end
 
	def create
  		@article = Article.new(article_params)
	 
  		if @article.save
    		redirect_to @article
  		else
    		render 'new'
  		end
	end
```

createアクションにif文が追加されていますね。
`@article.save`がtrueだったら保存に成功したその記事へリダイレクトし
falseだったらnewアクションにリダイレクトしている。
saveしようとする時にバリデーションがかかり、NGだったらfalseが返ってくるんだね。

newアクションにインスタンス変数が追加されているけど、何に使うんだろう。

new.html.erbを変更せよと言われている。

```erb:new.html.erb
<h1>New Article</h1>

<%= form_with scope: :article, url: articles_path, local: true do |form| %>
  <% if @article.errors.any? %>
  <div id="error_explanation">
    <h2><%= pluralize(@article.errors.count, "error") %> prohibited
      this article from being saved:</h2>
    <ul>
    <% @article.errors.full_messages.each do |msg| %>
      <li><%= msg %></li>
    <% end %>
    </ul>
  </div>
  <% end %>
  <p>
    <%= form.label :title %><br>
    <%= form.text_field :title %>
  </p>
 
  <p>
    <%= form.label :text %><br>
    <%= form.text_area :text %>
  </p>
 
  <p>
    <%= form.submit %>
  </p>
<% end %>
 
<%= link_to 'Back', articles_path %>
```

なんかながくなったなあ。

追加されたのはこの部分

```erb
  <% if @article.errors.any? %>
  <div id="error_explanation">
    <h2><%= pluralize(@article.errors.count, "error") %> prohibited
      this article from being saved:</h2>
    <ul>
    <% @article.errors.full_messages.each do |msg| %>
      <li><%= msg %></li>
    <% end %>
    </ul>
  </div>
  <% end %>
```

要するに保存に失敗した時にそのエラーメッセージを表示しようということらしい。
さっきnewアクションの中にインスタンス変数を作ったけど、それはこのエラーを表示するために必要だったんだね。
`@article.errors`でエラーの内容を引っ張ってこれるみたい。

「pluralizeは、数値を受け取ってそれに応じて英語の「単数形/複数形」活用を行ってくれるRailsのヘルパーメソッドです。数値が1より大きい場合は、引数の文字列を自動的に複数形に変更します(訳注:pluralizeはたいていの不規則活用にも対応しています)。」
へー。（？？？）

`@article.errors.full_messages`これでエラーメッセージの全文が取得できるって。

<img width="656" alt="スクリーンショット 2018-09-29 23.37.01.png" src="https://qiita-image-store.s3.amazonaws.com/0/283826/04b80f57-963b-5ee0-3e06-5747b2afda21.png">

短すぎるって怒られた！

バリデーションは美味しいのだ！

#参考
Railsガイド
https://railsguides.jp/getting_started.html
PythonでopenCVのインストール

#はじめに
機械学習の前処理のために画像編集する必要があるので、openCVを導入していみました

#実行環境
OS windows10
Python 3.6.4を使用
Anacondaを使用してインストールしました
参考URL
[Python開発環境構築 ー PyCharm × Anaconda](https://qiita.com/tanj/items/d88a3084a092bb106a97)

#環境構築
コマンドプロンプトを立ち上げる
cmdで検索すれば見つかります

```
pip install opencv-python
```

確認はそのままコマンドプロンプト上でpip listで確認

```
pip list
```

#実行
または、実際にimportして使ってみる

```
import cv2
```

<a href="https://www.amazon.co.jp/OpenCV%E3%81%A8Python%E3%81%AB%E3%82%88%E3%82%8B%E6%A9%9F%E6%A2%B0%E5%AD%A6%E7%BF%92%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0-Michael-Beyeler/dp/4839965307/ref=as_li_ss_il?ie=UTF8&qid=1538231938&sr=8-3&keywords=opencv&linkCode=li2&tag=chokex2-22&linkId=19eb0c6fabb6f4039c70b9e5e8f771bd&language=ja_JP" target="_blank"><img border="0" src="//ws-fe.amazon-adsystem.com/widgets/q?_encoding=UTF8&ASIN=4839965307&Format=_SL160_&ID=AsinImage&MarketPlace=JP&ServiceVersion=20070822&WS=1&tag=chokex2-22&language=ja_JP" ></a><img src="https://ir-jp.amazon-adsystem.com/e/ir?t=chokex2-22&language=ja_JP&l=li2&o=9&a=4839965307" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />

参考にしたページ
[ゼロからはじめるPython|マイナビ 第34回　OpenCVをインストールしてみよう](https://news.mynavi.jp/article/zeropython-34/)
Lambdaでお手軽サーバーレス入門（呼び出し元のまとめ編）

前回、[Lambdaでお手軽サーバーレス入門（とりあえず作ってみる編）](https://qiita.com/kakken1988/items/29ec13228f1398f40fec)という記事を書きました。
せっかく作った関数も、誰かに呼んでもらわないと寂しい思いをすると思うので、呼び出し元をまとめてみます。

# とりあえず一覧

* API Gateway → [記事書きました](https://qiita.com/kakken1988/items/bcf052116b2148818930)
* AWS IoT
* Alexa Skills Kit
* Alexa Smart Home
* CloudWatch Events → [記事書きました](https://qiita.com/kakken1988/items/12c1af589ade9f780222)
* CloudWatch Logs
* CodeCommit
* Cognito Sync Trigger
* DynamoDB
* Kinesis
* S3
* SNS
* SQS

たくさんありますねぇ :sweat_smile:

# それぞれをかいつまんで紹介

## API Gateway

私が担当しているプロダクトで最も多用されているものです。
REST APIでLambdaを呼び出せて、結果をクライアントに返せます。
（あとで少し掘り下げて書きます）

## AWS IoT

まだ使ったことがないのですが、Amazon Dash buttonをベースにした魔法のボタンを押すことで実行できそうです。
（そういえば昔、日本にいるときにDash button買ったのに、ベトナムだとAmazonがそもそもないから使えてない…）

## Alexa Skill Kit、Alexa Smart Home

Alexaから呼び出し。
喋ったらプログラムが動くって近未来的！
（いや、すでに現実のものなのね…）

## CloudWatch Events

CloudWatchといえばログをためておくところ、というイメージがめっちゃ強いのですが、イベントを発生させることもできます。
たとえば、ログにある文字が現れたら、とか。
あと、定期的なイベント呼び出しに使えます。
私のプロダクトでは、日次バッチ的に指定時間になったら動く関数があったり、数分ごとに動くものがあったり。
LinuxでいうところのCron的な、Windowsでいうとタスクスケジューラー的な立ち位置ですね。

## CodeCommit

AWSでホストできるGitリポジトリのイベントを拾えます。
プッシュされたりしたら動く関数が作れます。

## Cognito Sync Trigger

すみません、初耳です。

## DynamoDB

DynamoDBのレコード操作をトリガーに動かせます。
レコードが追加されたり編集されたり削除されたりしたら動きます。
SQLでいうところのTRIGGERですね。

## Kinesis

まだ未体験ですが、Kinesisのストリームでイベント発生させることができます。

## S3

S3にファイルを置いたりしたら関数を動かせます。
アプリ側からしたら、S3に置くだけでいいから楽ですね。

## SNS

Pub/SubのSub的ポジション。
SNS自体もいろいろなトリガーがあるので、どんどんチェインさせることができます。

## SQS

キューサービスSQSをウォッチして、キューにデータが入ったら動く関数が作れます。
自前でポーリングしなくてもいいのが楽ですね。

# 次回予告

前回作った関数、せっかくなのでAPI Gatewayから呼び出してみます。
イベントや戻り値にお約束ごとがあるので、それも合わせて紹介します。
次回：[Lambdaでお手軽サーバーレス入門（API Gateway設定編）](https://qiita.com/kakken1988/items/bcf052116b2148818930)
SSHの接続先ごとに、Macのターミナルのテーマ（背景色）を変更する

## 環境
- macOS High Sierra

## 変更手順

### 1. ~/.ssh/configファイルを記載する
開発環境、本番環境それぞれのssh設定を`~/.ssh/config`ファイルに記載します。

```config:~/.ssh/config
## staging
Host app-stg
    Hostname        {ip}
    Port            {port}
    IdentityFile    ~/.ssh/o_msyk
    User            o_msyk
## production
Host app-prd
    Hostname        {ip}
    Port            {port}
    IdentityFile    ~/.ssh/o_msyk
    User            o_msyk
```

### 2. テーマ変更のスクリプトを作成する

`/usr/local/bin/`配下に、`ssh-change-theme`というファイル名のスクリプトを作成する。

```bash:/usr/local/bin/ssh-change-theme
#!/bin/bash
set_profile() {
  /usr/bin/osascript -e "tell application \"Terminal\" to set current settings of first window to settings set \"$1\""
}
if [[ "$@" == app-prd ]]; then
  set_profile "Red Sands"
  ssh $@
  set_profile "Pro"
elif [[ "$@" == app-stg ]]; then
  set_profile "Ocean"
  ssh $@
  set_profile "Pro"
else
  ssh $@
fi
```
### 3. スクリプトのパーミッションを変更する
スクリプトを実行できるよう、chmodコマンドで実行権限を付与する。

```bash
$ chmod 755 /usr/local/bin/ssh-change-theme
```

### 4. aliasを設定する
sshコマンドを実行した時にスクリプトが実行されるよう、`~/.bash_profile` を編集してaliasを貼る。

```:~/.bash_profile
alias ssh="/usr/local/bin/ssh-change-theme"
```

## 実行
通常通り、sshコマンドを実行すると、開発環境、本番環境の場合のみテーマ（背景色）が変わります

### 開発環境に接続する
```
$ ssh app-stg
```
### 本番環境に接続する
```
$ ssh app-prd
```

## 参考
http://labs.septeni.co.jp/entry/20141024/1414120224
PySparkの基本的な関数

# はじめに
[アプリケーションエンジニアのためのApacheSpark入門](https://amzn.to/2DOwZom)を読んでいる。
PySparkの基本的な関数が8章で紹介されていたので、下記で紹介する。

# 基本的な関数
|関数|説明|
|:---|:---|
|read.json|jsonの読み込み|
|read.csv|csvの読み込み
|select|カラムで絞る
|withColumnRenamed|カラム名の変更
|registerTempTable|テーブルの登録
|printSchema|スキーマを表示する|
|show|データの表示
|sql|SQL文で登録したテーブルに対して処理をする
|groupby|グルーピング
|count|カウント
|data_format|あるdateフィールドの変換を行う
|alias|カラム名の変更
|na|null,NaNが含まれているレコードを取得
|drop|レコードを除く
|fill|null,NaNを埋める
|join|DataFrameの結合
|pivot|指定したカラムの値を重複排除しカラムとして扱う
|avg|平均を求める
|orderBy|レコードをカラムの値に応じて並び替える
|toPandas|sparkのDataFrameをPandasのDataFrameに変換する
|agg|groupByしたものについて、渡した関数をgroupごとに実行
|min|最小値を返す
|max|最大値を返す
|filter|特定の条件でレコードを絞り込む
|udf|pythonの関数をユーザー定義関数として保存する
|json|DataFrameをjson形式で書き出す
|csv|DataFrameをcsv形式で書き出す
|partitionBy|指定したカラムでデータを分割し出力する
|cache|DataFrameをcacheしておく
|explain|Sparkの実行計画を表示
初心者がRailsガイドを1から100まで読んでみる　Railsをはじめよう編その９　リンク

####5.9.リンクの追加

前節でさらっと導入されてたリンクについての節だよ。
Webページを作るのに必須と言ってもいいほどのリンクだけどRails上ではどうやって実装するのだろう。

Railsのリンクはビューヘルパーというメソッド集の内の一つだよ。
ビューヘルパーといえばフォームを作る時にも出てきたね。
form_withってやつ。

リンクはどのように書くかというと
`link_to '文字', リンク先のパス`
こんな感じ。

indexビューに新規記事作成ページ（newビュー）へのリンクを貼ってみよう。

```erb:index.html.erb
<h1>Listing articles</h1>

<%= link_to 'New article', new_article_path %>

<table>
  <tr>
    <th>Title</th>
    <th>Text</th>
    <th></th>
  </tr>
 
  <% @articles.each do |article| %>
    <tr>
      <td><%= article.title %></td>
      <td><%= article.text %></td>
      <td><%= link_to 'Show', article_path(article) %></td>
    </tr>
  <% end %>
</table>
```

<img width="305" alt="スクリーンショット 2018-09-29 22.12.47.png" src="https://qiita-image-store.s3.amazonaws.com/0/283826/7cdd4469-5a01-b9ed-4752-fc292c4a547c.png">

↓

<img width="343" alt="スクリーンショット 2018-09-29 22.13.00.png" src="https://qiita-image-store.s3.amazonaws.com/0/283826/53a54c7c-98de-6ddf-82b9-f9125bada610.png">

indexビューに`New article`というリンクができてそれを押すと前に作ったnewビューにジャンプした。

```erb
<%= link_to 'New article', new_article_path %>
```
この書き方だけど、`'New article'`はいいとして、気になるのは`new_article_path`の方だ。

ルーティングを確認してみて
<img width="491" alt="スクリーンショット 2018-09-16 23.04.57.png" src="https://qiita-image-store.s3.amazonaws.com/0/283826/ab48ffb4-94d2-fd33-1d7f-daf056a24d22.png">

Prefixの中に`new_article`がある。
それはnewアクションへのパスだ。
前にも話したけど、Prefix + _pathって書けばそれがアクションへのパスとして使えるんだね。

そういえばindexページにはもう一つリンクがある。

```erb
  <% @articles.each do |article| %>
    <tr>
      <td><%= article.title %></td>
      <td><%= article.text %></td>
      <td><%= link_to 'Show', article_path(article) %></td>
    </tr>
  <% end %>
```
前節で作った記事の一覧から各記事にとべるリンクだ。
ルーティングと照らし合わせてこれを読み解くと、
`article_path(article)`つまりshowアクションへのリンクだ。
パスの後ろに`(article)`って書いてるけど…
`article`は`each do |article|`の`article`で繰り返しの中のひとつひとつの記事が格納されている変数だ。

showアクションってどんなだったっけ

```rb:showアクション
	def show
		@article = Article.find(params[:id])
	end
```
受け取ったリクエストのパラメータの中から:idを取り出してそれでArticleモデルを検索してたんだった。
ということは`article_path(article)`って書けば、そのひとつひとつの記事をパラメータとしてshowアクションへリクエストを送れるということ？

なんかリクエストのとこいまいちよくわかってない感じがするなあ。

ついでにshowビューに戻るリンクもつけたよ。

```erb:show.html.erb
<p>
  <strong>Title:</strong>
  <%= @article.title %>
</p>
 
<p>
  <strong>Text:</strong>
  <%= @article.text %>
</p>

<%= link_to 'Back', articles_path %>
```

<img width="323" alt="スクリーンショット 2018-09-29 22.32.50.png" src="https://qiita-image-store.s3.amazonaws.com/0/283826/3cb2f21e-839d-7d5c-e9a1-44e74b524be4.png">
npmの基本コマンドとSemVer

https://nodeschool.io/#workshopper-list
にnpmの使い方を学べる教材があったのでそこで学んだことをメモしました。
上記のサイトのHow to npmという欄です。
初学者の私でもわかり易かったです。
# コマンド

| コマンド       | 説明                             |   
|:-----------------|:-----------------------|
|npm init --scope=ユーザ名<br>(スコープは任意) |npmの初期化する<br>ここに家を建てます的な|  
|npm adduser|アカウントの作成|
|npm login|https://www.npmjs.com/　にログイン|
|npm whoami|ログインしているアカウントの確認| 
|npm ls|インストールされているパッケージの確認<br> - pkg名<br> - そのpkgのversion<br> - その依存pkg| 
|npm install (省略形 i ) pkg|pkgのインストール<br>--saveオプション (省略形 s)はversion5以降デフォルトになったため<br>version5以上を利用する場合は指定する必要なし<br>package.jsonにバージョンをメモする事で、package.jsonさえあればインストールしたものを共有できる| 
|npm rm pkg名|パッケージのアンインストール|
|npm run <タスク名>|タスクランナの実行(package.jsonのscriptsに命名)| 
|npm publish --access=public<br>(scopeの場合必要)|自作のパッケージの公開<br>※scopeしている場合は次のオプションが必要(--access=public)<br>※事前にアカウント確認メールを確認する必要あり<br>※SemVerに従い、package.jsonのversionを上げる必要あり<br>公開するという事は何かしらのバージョンアップがあったという事| 
|npm version <バージョン番号>|package.jsonのバージョンアップ| 
|npm dist-tag add @pkg名@<バージョン名> <タグ名(任意)><br>|バージョンにdistタグを付ける(beta版とかstable版とか)<br>(dist = distribution, つまりは配布タグ)<br>ex)npm dist-tag add @tomo77777/11-dist-tag@1.0.0 beta<br>| 
| npm publish --tag タグ名 --access=public(scopeの場合必要)|タグ付きでパッケージの公開| 
|npm dist-tag rm @pkg名 タグ名|distタグの削除(dist = distribution, つまりは配布タグ)| 
|npm outdated<br>[出力例]<br>Package Current Wanted Latest Location<br>@linclark/pkg 1.0.1 1.0.3 1.0.3 @tomo77777/13-outdated|npm outdated<br>[出力例]<br>Package Current Wanted Latest Location<br>@linclark/pkg 1.0.1 1.0.3 1.0.3 @tomo77777/13-outdated|  
|npm update|全てのパッケージのバージョンを最新にする<br>(確認してupdateが面倒な場合は npm-check-updates というものがあるらしい)| 

# SemVerについて
SemVer(Semantic Version)
1.2.3
^ ^ ^
| | |___ パッチバージョン。細かい修正をする際に更新する。
| |_____ マイナーバージョン。APIを追加したときに更新する。
|_______ メジャーバージョン。APIの互換性がなくなったときに更新する。
JavaScriptの更新が反映されない

#JavaScriptの更新が反映されない
JavaScriptを修正したはずなのに、ブラウザで閲覧してみると更新が反映されていない。ブラウザにキャッシュが残っていることが原因の可能性がある。


#解決方法
Cache Bustingと呼ばれる手法を使用する。jsファイルの後ろに「?date=180929」などのように日付やバージョン情報を記載する。

```
<script src="/build.js?date=180929"></script>
```
vscodeの表示を日本語化する方法

# vscodeの表示を日本語化する方法

vscodeの表示言語が英語もしくは、他の言語で表示されいる場合、以下の手順で日本語化できます。

※ macのキーで説明しますが、「⌘」はWindowsでは「Ctrl」で置き換えて読んでください。

## 日本語パッケージがインストールされている場合

1.「⌘＋Shift＋p」でキーパレットを開く。
2. キーパレットに「Configure Display Language」を入力し、選択する。
3. locale.jsonファイルが開かれるので、localeを「ja」に修正する。

``` json
{
	// Defines VS Code's display language.
	// See https://go.microsoft.com/fwlink/?LinkId=761051 for a list of supported languages.
	
	"locale":"ja" // Changes will not take effect until VS Code has been restarted.
}
```

## 日本語パッケージがインストールされていない場合

1. 「設定」から「拡張機能」を選択する。
2. 「Marketplaceで拡張機能を検索する」に「Japanese Language Pack for Visual Studio Code」を入力する。
3. 「Japanese Language Pack for Visual Studio Code」をインストールする。

vscodeを再起動すると表示が日本語に変わります。


マーケットプレイスでパッケージを確認できます。
- [Japanese Language Pack for Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=MS-CEINTL.vscode-language-pack-ja)
【備忘録】 Intuneの各種ポリシー（iOSをベースに）

備忘録を兼ねて、あらためてIntuneでのiOS管理で使った内容についてまとめてみました。Office365は新しい機能が随時追加されてるのだけど、Intuneも同様に新しい機能が追加されます。気が付けば管理できる幅が広がっているのはありがたいのだけど、以前のドキュメントと内容が変わる箇所が出るのはお約束ですね。

〇〇ポリシーという言葉がいっぱいですが、順を追っていきましょう。
2020830 内容を組みなおししました。

1．デバイスの設定
1-1.デバイス構成ポリシー
1-2.iOS / iPadOS のソフトウェア更新ポリシー

2.アプリの設定
2-1.アプリ（アプリの配布や禁止）
2-2.アプリの構成ポリシー

3.デバイスの登録とコンプライアンスポリシー
3-1.デバイスの登録制限
3-2.コンプライアンスポリシー

4.条件付きアクセス

---

#1.デバイスの設定
まずは、デバイスそのものの設定にかかわる箇所から。

##1-1.デバイス構成ポリシー
パスワードの桁数は複雑さの設定、Wifiとか、インストール禁止アプリなどのデバイスそのものの設定を行うものです。証明書の配布や、VPNポリシーもここから設定できます。

Automated Device Enrollment (ADE ) と組み合わせると、iOSの「監視モード」も使える。監視モードでは、通常のMDMの設定ではできないような設定も可能になる。特に、「紛失時の位置情報を管理者が探す」機能を使うには監視モードが必須なので、この要件があるだけでも ADE   必須ですね。

※ADE　…以前はDEPという名前だった。[ ADE Apple ]で検索しても違う意味のものが出てくる。ややこしい。

##1-2.iOS / iPadOS のソフトウェア更新ポリシー
ミニマムバージョンを強制するポリシー。たとえば、13.5をミニマムバージョンに設定して、それ未満の場合は強制でアップデートさせることができる。

意識してアップデートしてくれるユーザーばかりだといいんですが、そうでないユーザーもやっぱりいますから強制させるには必須だと思います。ただし、監視モードが必須。

アップデートを遅らせるポリシー、アップデートを禁止するポリシーはありません。ただ、最大90日、ユーザーへの通知を遅らせる機能は別にあります。ただし、ブロックできるわけでもないんですよね。

#2.アプリの設定

デバイスの設定のつぎは、アプリに関する設定にかかわる箇所を。
##2-1.アプリ（アプリの配布）

デバイスにアプリをインストールさせる機能。たとえば、TeamsとEdgeは強制インストール、など。

インストールさせたいアプリアプリごと・グループごとに、強制あるいは任意インストールを設定できる。また、アプリを配布するOSミニマムバージョンを設定できる。13以降のデバイスだけに強制配信、とかも可です。特定URLへのショートカットを配布することもできます。

アプリインストールを禁止する設定はデバイス構成ポリシーで行います。
またVPPというアプリ購入・配布方法を使えばAppleIDがなくても配布できたりします。

##2-2.アプリの構成ポリシー
インストールした後のアプリに対し、設定を行う機能。たとえば、Edgeのブックマークを管理者が強制で設定する、なども可。

アプリによっては、初回起動時にパラメータを設定しなければならないケースもありますが（対象URLやアカウントとか）、この方法でスキップさせることも可能です。

##2-3.アプリ保護ポリシー
対象のアプリを開く際にPINを強制したり、許可したアプリ以外にファイルやテキストをコピーを禁止する制御を行う機能。たとえば、Outlookのメールをコピーしても、Safariにはペーストできなくする、などができます。

適用できるアプリはM365系を除けばまだごく一部。Adobe AcrobatやZoomなどは対応していると書かれていますが、このリストにないアプリでもFoxitのように対応しているケースもあるようです。
#3.デバイスの登録とコンプライアンスポリシー
デバイスの設定もアプリの設定も行ったら、認証認可にかかわる箇所を。
##3-1.デバイスの登録制限
UPN１つ当たりデバイスの登録できる台数を制限できる。たとえば、最大5台まで、最大2台まで、とかも可能。

そもそもデバイス登録できる種類も設定できるので、iOSは使ってない、Andoroidを使ってない、なんてケースの場合はデバイス登録アクセス自体をブロックできる。あくまでデバイス登録できないだけなので、この後の条件付きアクセスと組み合わせて考える必要があります。

##3-2.コンプライアンスポリシー
組織側で定めたポリシーを満たしているかどうかを判定します。たとばデバイスのパスコードがデバイス管理ポリシーの要件を満たしているか、決めた日数の間にアクセスがあるか、などを判定し、「準拠している」「準拠していない」を判定します。

準拠していない場合は、ユーザーにアラートを送るとかデバイスをワイプする、なども可能です。



#4.条件付きアクセス
Intuneの機能ではなく、Azure ADの機能であるけど、「あるグループのユーザーが、あるアプリ（たとえば、Office365)に、あるOSデバイス（たとえばiOSデバイス）からアクセスする場合、特定の条件を満たす場合のみ許可する」というルール設定を行って、認可を制御できます。

たとえば、
・iOSからのOffice365へのログインの場合
・コンプライアンスポリシーに準拠しているデバイスで、
・かつデバイス登録されているデバイスからのアクセスで、
・かつアプリ保護ポリシーで保護されているアプリからの場合は、
認可する、なんてことが制御できます。

細かい制御があれこれできますが、適用対象外のケース（適用対象のグループに所属していない、適用対象のOSでない場合、など）への対応を踏まえて設計しましょう。



#まとめ
iOSでの管理についてまとめてみました。WindowsやMac、Androidでもできるらしいのですが私はほとんど触ってません。

これらのポリシーは、ADのセキュリティグループ単位で設定できる。セキュリティグループごとにどのポリシーを割り当てるかというマトリクス表を作っておけば管理もラクになりそうです。
fishermanのpyenvが有効にならないときの対処法

# 状況
最近fishを使い始めました！
が、fishermanのpyenvを入れているのにpyenvにパスが通っておらず、システムデフォルトのpythonが起動する現象が起こったので、その対処法について書きます。

環境
OS: macOS High Sierra
Shell: fish
Terminal: iTerm2

# 解決策
公式のドキュメントどおりにfishermanをインストールし、fishermanのpyenvを導入していれば、
`$HOME/.config/fisherman/pyenv/conf.d/`の中に`pyenv.fish`というファイルがあるかと思います。
そのファイルの15〜18行目

```sh
if status --is-login
    set -x PATH "$pyenv_root/shims" $PATH
    set -x PYENV_SHELL fish
end
```
のif文とインデントを消して、

```sh
set -x PATH "$pyenv_root/shims" $PATH
set -x PYENV_SHELL fish
```
に変えましょう。
ログインし直せば`$HOME/.pyenv/shims`にパスが通り、普段どおりpythonが使えるはずです。

# 理由
おそらく、こんなことが起こる場合はかなり限らています。
上のコード上で`if status --is-login`がfalseで評価されている場合です。
`status`はfish上でfishがログインシェルかどうかを確認できるコマンドです。

私は標準のターミナルではbashを使い、iTermsではfishを起動するようにしており、つまり
`chsh -s /usr/local/bin/fish`をせずに、iTermsのPreferencesからfishを指定しています。
なので、システム上ではfishがログインシェルではないため、if文が実行されず、pyenvにパスが通らなかったのだと思います。
試しに`status`コマンドを打てば`This is not a login shell`と出るはずです。

# おわりに
わざわざターミナル毎にシェルを変える人はあまりいないような気はするので、この記事が読まれることはないかもしれません。
Amazon VPC ハンズオン

[Amazon VPC](https://qiita.com/leomaro7/items/cee33e0e57ca4bd76efc) も読むことをお勧めします。

リージョンは「アジアパシフィック（東京）」を選択しておいてください。

---
###1.VPCの作成###
「VPC」を開き、「VPC」の作成を開きます。
![スクリーンショット 2018-09-29 20.51.13.png](https://qiita-image-store.s3.amazonaws.com/0/280929/6058f083-c1ef-b6cc-9c02-2da4cfefb499.png)

ステップ 1: VPC 設定の選択
今回は「1 個のパブリックサブネットを持つ VPC」を「選択」します。
![スクリーンショット 2018-09-29 20.53.45.png](https://qiita-image-store.s3.amazonaws.com/0/280929/991657f9-0f7f-24f1-333e-a0f81e2372dd.png)

ステップ 2: 1 個のパブリックサブネットを持つ VPC
今回は以下のように入力し、「VPCの作成」をクリックします。
・IPv4 CIDR ブロック:10.0.0.0/16
・VPC 名:test
・パブリックサブネットの IPv4 CIDR:10.0.0.0/24
・アベイラビリティーゾーン:*ap-northeast-1a
![スクリーンショット 2018-09-29 20.58.58.png](https://qiita-image-store.s3.amazonaws.com/0/280929/def3981b-f1ed-f87d-6bd7-f62cbc4d9231.png)

作成されたVPCが表示されます。
![スクリーンショット 2018-09-29 21.00.50.png](https://qiita-image-store.s3.amazonaws.com/0/280929/675fab61-a443-b15c-fa51-159f8f85bbb2.png)

###2.IGWの確認###
「インターネットゲートウェイ」をクリックすると先程作成したVPCに既にアタッチされていることが確認できます。
![スクリーンショット 2018-09-29 21.01.51.png](https://qiita-image-store.s3.amazonaws.com/0/280929/056e3899-19f6-9853-983a-970883d72092.png)

###3.サブネットの確認###
「サブネット」をクリックすると先程の「10.0.0.0/24」が作成されていることが確認できます。
![スクリーンショット 2018-09-29 21.04.12.png](https://qiita-image-store.s3.amazonaws.com/0/280929/3d68e87d-46e3-ead8-2921-da40ff8bf11c.png)

###4.ルートテーブルの確認###
「ルートテーブル」を確認してすると、0.0.0.0/0がIGWをターゲットとするルーティングがエントリーされていることが確認できます。
![スクリーンショット 2018-09-29 21.07.15.png](https://qiita-image-store.s3.amazonaws.com/0/280929/1e2baff2-18a5-5241-2e35-3da038bdf784.png)



-----
ちなみに↓のページがわかりやすかったです。
[(下準備編)世界一丁寧なAWS解説。EC2を利用して、RailsアプリをAWSにあげるまで](https://qiita.com/naoki_mochizuki/items/f795fe3e661a3349a7ce)
kubernetesのapiVersionとkindの対応表


Kubernetesの「Kind」と「apiVersion」の対応表です。

kindとapiVersionの組み合わせ以外では
エラーとなり起動しません。

また、versionはアップグレードすることもありますが
反映が遅れることもあるのであらかじめご了承ください。

| Kind  | apiVersion |
|:--|:--|:--|
| CertificateSigningRequest | certificates.k8s.io/v1beta1 | 未確認　わかり次第追記します。 |
| ClusterRoleBinding | rbac.authorization.k8s.io/v1 | 未確認　わかり次第追記します。 |
| ClusterRole | rbac.authorization.k8s.io/v1 | 未確認　わかり次第追記します。 |
| ComponentStatus | v1 | 未確認　わかり次第追記します。 |
| ConfigMap | v1 |
| ControllerRevision | apps/v1 | 未確認　わかり次第追記します。 |
| CronJob | batch/v1beta1 |
| DaemonSet | extensions/v1beta1 |
| Deployment | extensions/v1beta1 |
| Endpoints | v1 | 未確認　わかり次第追記します。 |
| Event | v1 | 未確認　わかり次第追記します。 |
| HorizontalPodAutoscaler | autoscaling/v1 | 未確認　わかり次第追記します。 |
| Ingress | extensions/v1beta1 |
| Job | batch/v1 |
| LimitRange | v1 | 未確認　わかり次第追記します。 |
| Namespace | v1 | 未確認　わかり次第追記します。 |
| NetworkPolicy | extensions/v1beta1 | 未確認　わかり次第追記します。 |
| Node | v1 | 未確認　わかり次第追記します。 |
| PersistentVolumeClaim | v1 |Persistent Volumeに命令したり注文をする。|
| PersistentVolume | v1 |kubernetesのストレージがどのように消費されてからどのように提供されるかの詳細を抽象化する
| PodDisruptionBudget | policy/v1beta1 | 未確認　わかり次第追記します。 |
| Pod | v1 |
| PodSecurityPolicy | extensions/v1beta1 | 未確認　わかり次第追記します。 |
| PodTemplate | v1 | 未確認　わかり次第追記します。 |
| ReplicaSet | extensions/v1beta1 |
| ReplicationController | v1 | 未確認　わかり次第追記します。 |
| ResourceQuota | v1 | 未確認　わかり次第追記します。 |
| RoleBinding | rbac.authorization.k8s.io/v1 | 未確認　わかり次第追記します。 |
| Role | rbac.authorization.k8s.io/v1 | 未確認　わかり次第追記します。 |
| Secret | v1 | 未確認　わかり次第追記します。 |
| ServiceAccount | v1 | 未確認　わかり次第追記します。 |
| Service | v1 | DeploymentやRepricasetを起動させるためのツール
| StatefulSet | apps/v1 |未確認　わかり次第追記します。 |
GoでQRコードを出力するサービスを作ってみる

あるページにアクセスしたらQRコードを表示させる機能を作る必要があったので、Goで簡単に作れないか無いか調べたら以下を見つけたので、net/httpを使って簡単にQRコードを生成できるサービスを作ってみます。

https://github.com/boombuler/barcode

# サンプルコード

```golang
package main

import (
	"fmt"
	"github.com/boombuler/barcode"
	"github.com/boombuler/barcode/qr"
	"image/png"
	"net/http"
)

func main() {
	http.HandleFunc("/", handler)
	http.ListenAndServe(":8082", nil)
}

func handler(w http.ResponseWriter, r *http.Request) {
	messages, ok := r.URL.Query()["m"]
	if(!ok || len(messages[0]) < 1) {
		fmt.Fprintln(w, "Missing needed parameter 'm'.")
		return
	}
	qrCode, _ := qr.Encode(messages[0], qr.L, qr.Auto)
	qrCode, _ = barcode.Scale(qrCode, 512, 512)
	png.Encode(w, qrCode)
}
```

# 使い方
パラメータ`m`に好きな文字を入れるとその文字のQRコードを生成して表示してくれます。

```
http://localhost:8082/?m=hoge
```

<img width="636" alt="スクリーンショット 2018-09-29 21.05.14.png" src="https://qiita-image-store.s3.amazonaws.com/0/102944/418b479e-1626-6a8c-874b-acde1f8d7c57.png">
初心者がRailsガイドを1から100まで読んでみる　Railsをはじめよう編その８　データの全表示

####5.8.すべての記事を一覧表示する

記事を一つ表示できたんだから、保存されている記事全部表示することなんてちょちょいのちょいでしょ。

全部の記事を表示するページはどれにしようかなー
<img width="491" alt="スクリーンショット 2018-09-16 23.04.57.png" src="https://qiita-image-store.s3.amazonaws.com/0/283826/92eeca82-e9b2-7908-1f4c-89537dc29864.png">

`articles#index`
これが良さそう

ルートを決めてたら次にやることは
①アクションを作る
②ビューを作る
ですね（もう何回もやってきた）

```articles_controller.rb
class ArticlesController < ApplicationController

	def index
		@articles = Article.all
	end

	def show
		@article = Article.find(params[:id])
	end

	def new
	end
	
	def create
		@article = Article.new(article_params)

		@article.save
		redirect_to @article
	end

	private
		def article_params
    		params.require(:article).permit(:title, :text)
  		end	
end
```
①コントローラにindexアクションを追加しました。
コントローラくんの仕事がだんだんわかってきたけど、モデルくんとビューくんの橋渡しみたいな感じだね。
今回はArticleモデルに保存されているすべての記事をビューに渡したいから
`@articles = Article.all`
と記述して、`@articles`にモデルの中身を全部ぶちこんでいる。
前節で学んだけど、アクション内のインスタンス変数(@ほにゃらら)の中身は、裏でRailsちゃんが働いてて絶えずビューへコピーされる。
`Article.all`と書くことでArticleモデルの全レコードを抽出したことになるらしい（SQL書かないって便利）


```erb:index.html.erb
<h1>Listing articles</h1>
 
<table>
  <tr>
    <th>Title</th>
    <th>Text</th>
    <th></th>
  </tr>
 
  <% @articles.each do |article| %>
    <tr>
      <td><%= article.title %></td>
      <td><%= article.text %></td>
      <td><%= link_to 'Show', article_path(article) %></td>
    </tr>
  <% end %>
</table>
```

②indexビューを作りました。
前にも出てきたけど、`<% ~ %>`で囲まれたところにはRubyが書ける。
アクションで宣言したインスタンス変数もこの中で使用できる。

```erb
  <% @articles.each do |article| %>
    <tr>
      <td><%= article.title %></td>
      <td><%= article.text %></td>
      <td><%= link_to 'Show', article_path(article) %></td>
    </tr>
  <% end %>
```
今回大事なのがこの部分で、

```erb
<% @articles.each do |article| %> 
~ 
<% end %>
```
ここで`@articles`に入っている記事に対してひとつずつ処理を行い

```erb
    <tr>
      <td><%= article.title %></td>
      <td><%= article.text %></td>
      <td><%= link_to 'Show', article_path(article) %></td>
    </tr>
```
そのひとつひとつの記事のタイトルとテキストと、あとその記事へのリンクを表示している。

え？
リンク？

<img width="316" alt="スクリーンショット 2018-09-29 20.57.13.png" src="https://qiita-image-store.s3.amazonaws.com/0/283826/82349b63-1284-fcc0-c925-41ba7bd5d714.png">
<img width="328" alt="スクリーンショット 2018-09-29 20.57.51.png" src="https://qiita-image-store.s3.amazonaws.com/0/283826/5648ecf4-1936-ee1f-35d1-b1a6eaa98b7a.png">
CMakeでOpenCVアプリケーション開発

# この記事について
CMakeを使って、OpenCVアプリケーション開発用プロジェクトを作ります。WindowsとLinuxの両方でビルドできるようにします。

- CMakeを使うことのメリット
	- マルチプラットフォーム対応
	- インクルードパスやライブラリ設定を自動化できる
	- (特に、GitHub等で他の人に渡すときに便利)

## 環境
- Windows10 64-bit
	- Visual Studio 2017 Community
- Ubuntu 16.04 on VirtualBox on Windows 10
- OpenCV 3.4.1



## 対象とするプログラム
定番の、Lenaさんを表示するだけのOpenCVプログラムを考えます。

```c:main.cpp
#include <stdio.h>
#include <opencv2/opencv.hpp>

int main()
{
	printf("Hello\n");

	cv::Mat image = cv::imread(RESOURCE_DIR"lena.jpg");
	cv::imshow("Display", image);

	cv::waitKey(0);
	return 0;
}
```

# OpenCVの準備
## Windows
### OpenCVの取得
カスタマイズ不要なら、公式(https://opencv.org/ )から配布されているバイナリを使用するのが楽です。
https://opencv.org/opencv-3-4-1.html に行き、DownloadのWin packをクリック。
ダウンロードした`opencv-3.4.1-vc14_vc15.exe`を展開後、`c:\opencv`に配置。

### 環境変数の設定
Windowsのシステムのプロパティ→環境変数で、環境変数を設定し、パスも追加します。
- OpenCV_DIR: `C:\opencv\build`
- Path: `%OpenCV_DIR%\x64\vc15\bin` を追加

## Linux (Ubuntu)
だいぶ前にインストールしたので、忘れてしまいました。
とりあえず試すだけなら、aptでのインストールで大丈夫だと思います。最新版が使いたい場合は、ソースからビルドして、最後にインストールすればOKです。
もしかしたら、`export OpenCV_DIR=OpenCVの場所`をしておく必要があるかもしれません。

# プロジェクトの作成
```txt
└─TestOpenCV
    │  CMakeLists.txt
    │  main.cpp
    │
    └─resource
            lena.jpg
```

```txt:CMakeLists.txt
cmake_minimum_required(VERSION 2.8)
project(MyOpenCVProject)

# Copy resouce
file(COPY ${CMAKE_SOURCE_DIR}/resource/ DESTINATION ${PROJECT_BINARY_DIR}/resource/)
add_definitions(-DRESOURCE_DIR="${PROJECT_BINARY_DIR}/resource/")

# Create Main project
set(SOURCES
	main.cpp
)

set(HEADERS
	# main.h
)

add_executable(Main
	${SOURCES}
	${HEADERS}
)


# For OpenCV
find_package(OpenCV REQUIRED)
if(OpenCV_FOUND)
	target_include_directories(Main PUBLIC ${OpenCV_INCLUDE_DIRS})
	target_link_libraries(Main ${OpenCV_LIBS})
endif()


```

CMakeを使うと、一般的にはout of sourceビルドといい、ソースコードとビルドする場所が異なります。そのため、画像等のリソースファイルをいちいちコピーするのが面倒なので、resourceフォルダを自動的にコピーして、その場所を定義しておくようにしました。
次に、main.cppを使って、Mainという実行ファイルを作っています。
最後に、OpenCVパッケージを探して、見つかったらincludeパス設定と、ライブラリリンク設定をしています。


# (おまけ) セルフビルドした、指定の場所にあるOpenCVを使いたいとき
cmake時に、`OpenCV_DIR` に`OpenCVConfig.cmake`の場所へのパス を設定する

```sh
# OpenCVのビルド
apt -y install git libgtk-3-dev libdc1394-22 libdc1394-22-dev ffmpeg libavcodec-dev libavformat-dev libswscale-dev libavresample-dev
git clone https://github.com/opencv/opencv.git --branch 4.5.5 --depth 1
cd opencv && mkdir -p build && cd build
cmake .. -DCMAKE_INSTALL_PREFIX=./install
make -j4
make install

# 自分のプロジェクトの生成
source /root/opencv/build/install/bin/setup_vars_opencv4.sh
cd 自分のプロジェクト && mkdir -p build && cd build
cmake .. -DOpenCV_DIR=/root/opencv/build
```
fortune-modとcowsayでログイン時にメッセージとAAを表示する

[AWSにsshログインした時にスライムを出現するようにしてみた。](https://qiita.com/tu-kun/items/d38452161bfb9da54bcd)を読んで、以前社内サーバーのログインスクリプトにcowsayを仕込んでいたことを思い出しました。

下記環境はRaspberry pi (Raspbian 9.4)。ディストリビューションが違うとパス等は変わるかもしれません。
Redhat系OSではEPELにパッケージがあります。

# cowsay

メッセージをアスキーアートと共に表示させるお遊びツール。

## インストール

```
# apt-get install cowsay -y
```

## 使い方

```
$ /usr/games/cowsay [-f cowfile] MESSAGE
```

こんな風に呼び出します。 -f を省略すると牛が表示されます。

```
pi@raspberrypi:~$ /usr/games/cowsay "諦めたらそこで試合終了ですよ...?"
 __________________________________
< 諦めたらそこで試合終了ですよ...? >
 ----------------------------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||
```

-f でcowfileを指定できます。cowfileは/usr/share/cowsay/cows/にあります。
cowfileにはかなりきわどいものも含まれています。

```
pi@raspberrypi:~$ /usr/games/cowsay -f /usr/share/cowsay/cows/head-in.cow "諦めたらそこで試合終了ですよ...?"
 __________________________________
< 諦めたらそこで試合終了ですよ...? >
 ----------------------------------
    \
     \
    ^__^         /
    (oo)\_______/  _________
    (__)\       )=(  ____|_ \_____
        ||----w |  \ \     \_____ |
        ||     ||   ||           ||
```

# fortune-mod

どこかで聞いたことがあるような、ないような明言を返してくれるツールです。

## インストール

```
# apt-get install fortune-mod -y
```

## 使い方

```
pi@raspberrypi:~$ /usr/games/fortune
It is right that he too should have his little chronicle, his memories,
his reason, and be able to recognize the good in the bad, the bad in the
worst, and so grow gently old all down the unchanging days and die one
day like any other day, only shorter.
                -- Samuel Beckett, "Malone Dies"
```

なんだかそれっぽいメッセージが表示されました。

# cowsay + fortune

cowsayとfortuneを組み合わせて、ランダムなAAにランダムな名言をつぶやかせることが出来ます。

```
pi@raspberrypi:~$ /usr/games/fortune | /usr/games/cowsay -f `find /usr/share/cowsay/cows/ -type f | sort -R | tail -1`
 ______________________________________
/ Your life would be very empty if you \
\ had nothing to regret.               /
 --------------------------------------
     \
      \
        ,__, |    | 
        (oo)\|    |___
        (__)\|    |   )\_
             |    |_w |  \
             |    |  ||   *

             Cower....
```

.bash_profileにスクリプトを仕込むと、ログインごとにAAと名言を表示できます。
名言の代わりにサーバー情報をつぶやかせた方が実用的かもしれません。

プロジェクトをフォークして slimesay とか fortune-anzai とか作りたい気もしますが、著作権違反ですね...
Max8にどうしてもElectronを載っけてUI革命を起こしたかったおれたちは

# はじめに
[前回の記事](https://qiita.com/Yuichi_Yogo/items/a439964034be4e200026)で、普通のNode.jsアプリケーション開発とほぼ変わらない感覚で開発ができることがわかったので、もっと色々試してみました。

**やってみたリスト**

- UIなど
    - Electron
    - React
    - Material UI
- 開発環境など
    - Webpack
    - Babel
- その他
    - Socket.io


# つくったもの
[この動画](https://www.youtube.com/watch?v=8OhOC6rZC9Q)で紹介されてるパッチをほぼそのまま引っ張ってきて、それを動かすコントローラー的なElectronアプリを作ってみました。
![Sep-29-2018 20-08-03.gif](https://qiita-image-store.s3.amazonaws.com/0/148589/f128f493-89eb-ad1f-3cf4-c6d326da9d65.gif)

[音付き動画](https://twitter.com/yuichi_yogo/status/1045997300714168322)

# ソースコード
[github](https://github.com/yuichkun/n4m-electron-ui)

# そもそもの仕組みのおさらい
![intro.001.png](https://qiita-image-store.s3.amazonaws.com/0/148589/5736b335-f80f-eade-96ed-b75cb6b999b8.png)

# 開発のtipsいろいろ
Max上で動かすときはMaxの中にNodeが入っているので、nodeやnpmがインストールされてなくても問題はありませんが、開発時は手元で動かせるように入れておいた方が良いと思います。（もちろんバージョンは揃えて）  

基本的には、普通のNode.jsを書いている感覚で開発してコマンドラインで動作確認などをして大丈夫ですが、`max-api`を使う部分については、MaxでNodeを起動した時でないとモジュールが解決できないので、その部分はwebpackなどのバンドル対象から外した方が吉かと思います。

# で、だから何なの？っていうハナシ

***ここから下は、完全なるチラ裏です（飛ばしてOK）***

今までMaxって、ふつうのエンジニアからしたら結構ハードル高いイメージあったと思うんですよね。
何かプロダクトとか作品作るにしても、特にチームで制作とかしてると、Maxという語彙のない人にとっては学習コストが高く協業しづらいと思ってました。  
今回のリリースでNode for Maxが切り開いてくれた道は一介のWebエンジニアにとって、

- 「え？普通にサーバー書いてて良いの？」
- 「gitでバージョン管理できるの？」*（.maxpatをgitで管理した時のひどさ）*
- 「Maxのことほとんど勉強しないまま、Maxエンジニアとコラボできるの？」

みたいな驚きと共に敷居をぐっと下げてくれた気がします。

だから、これからはハッカソンに行っても、
堂々と**「Maxでやりましょうよ」**とか
**「それ、Maxですぐできますよ」**って言っていいと思うんです！！

Maxがマジでイケてる環境になって、これから色んなイノベーションが沢山出てきそうですね！！！

***ここから上は、完全に個人の意見です***

# おまけ（参考程度）
## Node for Maxとは

Max上でNode.jsのプロセスを立ち上げ、Maxパッチ <=> Node.jsプロセス間で通信するAPIを提供してくれてます。
Maxには元々jsオブジェクトがあるので、とても紛らわしいのですが、新しく導入されたnodeオブジェクトはこれとは全く別の物です。

[この動画](https://www.youtube.com/watch?v=qSZH6fjOcXE)が導入用にわかりやすいかもしれません。

## Electronとは
デスクトップアプリを作れるNode.jsのフレームワークです。
中身は、ChromiumというGoogle Chromeを動かしているエンジンなので、普通のWebで使うようなhtml, css, javascriptといった資産は全て使うことができ、なおかつ裏側はNode.jsが走っているので、パソコン内のファイルシステムにアクセスできたり、とにかくイイトコどりの***イカした環境***です。
【.NET】WPFでウィンドウを最大化しないようにする

# はじめに
WPFアプリケーションを作成した際にタイトルバーを非表示にして、最小化とリサイズは可能としていた。タイトルバーが非表示なので最大化ボタンは無いし最大化されることは無いだろうと思い込んでいました。

ところがユーザーから最大化するとサイズ・グリップ(サイズ変更可能なことが視覚的にすぐ分かるようなフォームの右下のつまみ）を表示が消えて元のサイズに戻せないという報告がありました。

# 原因
Windows 7以降では、画面の上端にアプリケーションを移動させると最大化するようになっています。「Aero Snap」という機能です。
[大画面ディスプレーで大活躍の新機能「Aero Snap」](http://ascii.jp/elem/000/000/456/456143/)

「Aero Snap」はドラッグ・リサイズ中のウィンドウがデスクトップの端に吸い付くように自動リサイズする機能。

* キャプションを画面上端にドラッグするとウィンドウを最大化。
* 左右どちらかにドラッグするとその方向にウィンドウをリサイズ。
* 上下端までリサイズするとウィンドウが上下一杯方向にウィンドウをリサイズ。

# 対応
最大化しようとしたら通常サイズにすることで対応しました。

```csharp
<Window x:Class="Example"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Example" 
        Height="480" Width="600" MinWidth="200" MinHeight="160" 
        WindowStyle="None" ResizeMode="CanResizeWithGrip"
        StateChanged="Window_StateChanged">

private void Window_StateChanged(object sender, EventArgs e)
{
    if (this.WindowState == WindowState.Maximized)
        this.WindowState = WindowState.Normal;
}
```

[[pinvoke] WPFでサイズ変更可能なウィンドウから最小化と最大化を削除するにはどうすればよいですか？](https://code-examples.net/ja/q/52ea4)

# 最後に
Windows 7以降を長く使っている割には「Aero Snap」という機能に気がついてなく、報告をもらってどうやって最大化するんだろうと悩みました。