OmniAICreator/Qiita-1.07M huggingface dataset:
コードでAutoLayoutを簡単に書けるライブラリPureLayoutを使ってみた

# PureLayout
コードでAutoLayoutを簡単に書けるライブラリのひとつ。
他にもCartgraphyなどのライブラリが同じような機能を提供してます。

PureLayoutの簡単な使いかたについての紹介はいくつかありますが、少し複雑でより実践的なレイアウトに対しての適用方法を紹介します。

# 例: 等間隔なviewの配置
「複数のViewを等間隔に配置する」
「条件によってViewごとの表示・非表示を切り替える」
「Viewの数が変わってもView同士の間隔は固定」
というレイアウトを実現したい場合。
以前は
 1. 透明なViewを間に挟んで、表示要素の大きさから透明Viewの大きさを計算するやり方
 2. 表示条件の数だけ制約を用意しておいて変更があるたびに付け替えるやり方
のどちらかでやっていたのですが、1だと不要なviewがあるのが気持ち悪いし、2だと制約の記述が増えすぎて読みにくいです。
それがPureLayoutだと以下のように書けます。

```
// 水平方向に配置するviewをまとめるためのviewを用意し、配置するViewをaddしておく
view.addSubview(horizontalContainerView)
horizontalContainerView.addSubview(greenButton)
horizontalContainerView.addSubview(yellowButton)
horizontalContainerView.addSubview(redButton)

// それぞれのviewの制約
horizontalContainerView.autoPinEdgesToSuperviewEdges()
horizontalContainerView.autoSetDimension(.height, toSize: 200.0)
 
greenButton.autoPinEdge(toSuperviewEdge: .top)
greenButton.autoPinEdge(toSuperviewEdge: .bottom)

yellowButton.autoPinEdge(toSuperviewEdge: .top)
yellowButton.autoPinEdge(toSuperviewEdge: .bottom)

redButton.autoPinEdge(toSuperviewEdge: .top)
redButton.autoPinEdge(toSuperviewEdge: .bottom)

// 対象とするViewの配列（グリーン、イエロー、レッドボタン）
horizontalViewArray = [greenButton, yellowButton, redButton]

// 配列に入ったviewを等間隔に水平方向に配置する制約
horizonralArrayConstraints = NSLayoutConstraint.autoCreateAndInstallConstraints {
    horizontalViewArray.autoDistributeViews(along: .horizontal, alignedTo: .horizontal, withFixedSpacing: 20.0, insetSpacing: false, matchedSizes: false)
} as NSArray
```

適用した例
<img width="339" alt="スクリーンショット 2017-03-14 23.26.50.png" src="https://qiita-image-store.s3.amazonaws.com/0/130686/03091569-7e22-51f2-eec3-ef61c0684da5.png">


greenButtonとredButtonだけ表示する場合は配列の中身を更新して、horizonralArrayConstraintsを更新してあげればいいです。
配列の変更と制約更新部分をメソッドに抽出しておくといいかもしれないですね。
（あと非表示のviewはisHiddenで適宜隠してあげてください。）

```
horizontalViewArray = [greenButton, redButton]

horizonralArrayConstraints?.autoRemoveConstraints()
horizonralArrayConstraints = NSLayoutConstraint.autoCreateAndInstallConstraints {
    horizontalViewArray.autoDistributeViews(along: .horizontal, alignedTo: .horizontal, withFixedSpacing: 20.0, insetSpacing: false, matchedSizes: false)
} as NSArray
```
適用した例
<img width="328" alt="スクリーンショット 2017-03-14 23.27.03.png" src="https://qiita-image-store.s3.amazonaws.com/0/130686/6443e7b1-3778-4e6a-e7a4-158a5e0bcab5.png">


PureLayoutを使えばこのように、先にあげた2つの方法よりも簡潔なコードが書けるので気に入っています。
PureLayoutのサンプルを見れば大体のことはできると思うので一度眺めて見てください。
https://github.com/PureLayout/PureLayout/tree/master/PureLayout/Example-iOS/Demos


# そもそもコードで書いていい事あるの？Storyboardでよくない？
そう思っていた時代が自分にもありました。
例えば画面のUIが非常にシンプルな場合はStoryboardだけで完結させるのも良いでしょう。
しかしほとんどのアプリの画面は複雑なレイアウトで構成されています。
また、何かアクションに応じてviewのレイアウトを変えて表示することも良くあると思いますが、そういった場合にStoryboardだけで完結させるのは難しいです。
また、コードとStoryboardを見比べながら作業するのも非常に効率が悪いです。
そしてコードで書くのは複数人で開発する時に特に威力を発揮すると思います。Storyboardのコンフリクト解消って結構辛いですよね。。


# 他にもライブラリあるけどどれ使えばいいの？
Cartgraphyをチラッと見た感じほとんど機能としては変わらない印象でした。
ただCartgraphyの場合、どのViewに制約をつけているかが分かりやすいですね。表現力が高いというか。
この辺はobjective-cで書かれたPureLayoutと、swiftで書かれたCartgraphyの違いでしょうか。
自分は業務ではPureLayoutを使っていますが、個人でCartgraphyも試してみたいと思います。
javascriptでifやswitchを書きたくない時に

# ifやswitch これは便利です
※ifやswitchを否定しているわけではありません。

・例えば特定のtypeによって文字を表示したい場合

```javascript
// if
var type = 'hoge';
function ifFunc(type){
    if (type === 'hoge'){
        console.log('hoge dayo');
    } else if (type === 'fuga'){
        console.log('fuga dayo');
    } else if (type === 'hoo'){
        console.log('hoo dayo');
    }
}

// switch case
function switchFunc(type){
    switch (type){
        case; 'hoge':
             console.log('hoge dayo');
             break;
        case; 'fugue':
             console.log('fuga dayo');
             break;
        case; 'hoo':
             console.log('hoo dayo');
             break;
    }
}


ifFunc(type);
switchFunc(type);
```

# ifやswitchの罠
分岐する際全てをifやswitchを使うと処理を各パターンの時の処理が
ながくなって目的のものを探しにくくなったり、ネストが深くなったりして
可読性がさがることが個人的にありました。

# funcオブジェクトを作成
じゃあ、どうしたかというとオブジェクトを作成して呼び出す形にしました

```javascript
var funcObj = {
    hoge: function(){
        console.log('hoge dayo');
    },
    fuga: function(){
        console.log('fuga dayo');
    },
    hoo: function(){
        console.log('hoo dayo');
    }
}
var type = 'hoge';
var func = funcObj[type];
fun();
```

こうすることでifやcaseと書くことから解放されて
個人的に見やすく書けたのかなとおもっています。

ifやcaseを書かずに書いてみたい方は
試してみてください。
Flexboxで横並びにした画像と、複数行（段落）のテキストを背景色引き伸ばしつつ上下中心にもってくる

#こういうことがしたい
説明がややこしいけど、こういうことがしたかったのです。

![img01.png](https://qiita-image-store.s3.amazonaws.com/0/25120/f64b407a-9a2b-72e6-5087-736dc85d8b1a.png)

- Flexboxの横並びで上下左右中央
- 片方は画像、片方は段落のあるテキスト
- 幅はそれぞれ50％で幅・高さ可変、レスポンシブ
- 背景色も画像の高さに合わせて全体に伸ばしたい

この複数の段落があるテキスト部分を、 Flexboxで背景も可変に引き伸ばしつつ上下中央に綺麗にもってきたい！
解決したのでメモとして残しておきますー

# もしテキスト部分が一行なら…

テキスト部分が一行(pタグ一個だけとか)なら、上下中心にもってくるのは簡単。
横並びしている、上下中心にもってきたい子要素の方にもdisplay: flex;をかけて、尚且つalign-items:center;をその子要素にだけつければＯＫ。

# 複数段落になるとそれだけじゃうまく中心にならない
複数の段落がある場合、上記の方法だとそれぞれの段落で上下均等に余白ができてしまうのでなんか気持ち悪いことになります。こんなかんじ。

![img02.png](https://qiita-image-store.s3.amazonaws.com/0/25120/f3063c61-f4b4-4d63-281f-3f2e8b2b70e4.png)

# 解決策
簡単でした、、。
要は中の段落がそれぞれバラけて中央配置になるのを防ぐために、そいつらをdivでさらに囲んであげればいいだけです。
ざっくり完成コードこちら。
※リセットなど基本的なスタイルは省略しています

```html:html
<div class="type1">
	<p class="img"><img src="hoge1.png"></p>
	<div class="txtwrap">
		<!-- ここにdivをひとつ追加 -->
		<div>
			<h2>小見出し的なタイトル</h2>
			<p>テキストテキストテキストテキストテキスト<br>
			テキストテキストテキストテキストテキスト<br>
			テキストテキストテキストテキストテキスト</p>
		</div>
	</div>
</div>
<div class="type2">
	<p class="img"><img src="hoge2.png"></p>
	<div class="txtwrap">
		<div>
			<h2>小見出し的なタイトル</h2>
			<p>テキストテキストテキストテキストテキスト<br>
			テキストテキストテキストテキストテキスト<br>
			テキストテキストテキストテキストテキスト</p>
		</div>
	</div>
</div>
<div class="type1">
	<p class="img"><img src="hoge3.png"></p>
	<div class="txtwrap">
		<div>
			<h2>小見出し的なタイトル</h2>
			<p>テキストテキストテキストテキストテキスト<br>
			テキストテキストテキストテキストテキスト<br>
			テキストテキストテキストテキストテキスト</p>
		</div>
	</div>
</div>
```


```sass:scss
.type1,.type2{
  display: flex;
  -webkit-flex-wrap: wrap;
      -ms-flex-wrap: wrap;
          flex-wrap: wrap;
}
.type2{
  -webkit-flex-direction: row-reverse;
      -ms-flex-direction: row-reverse;
          flex-direction: row-reverse;
}
.img{
  width: 50%;
  img{
    width: 100%;
  }
}
.txtwrap{
  background: #ccc;
  width: 50%;
  display: flex;
  -webkit-align-items: center;
          align-items: center; //上下中心にする
  -webkit-justify-content: center;
          justify-content: center; //左右中心にする
  div{
    text-align: left;
  }
}
```

以上メモでした
VMware Horizon 同時利用数の傾向把握について


#概要
インターネット分離で導入する際、見積もり段階で正確にどの程度利用されるか判断ができないため、多くの自治体ではざっくり3割程度の同時接続数で調達されていることが多い。
運用フェーズに入り同時利用数を把握するには、Horizon administratorで確認可能だ。
以下のような課題を解決したい場合はHorizon Tool box が利用できる。

#自治体が抱える課題
・セッションの統計情報の確認（利用傾向の把握）
・ユーザーの接続時間（セッション切断時間の妥当性を検討）
・統計を把握のうえ、セッション切断時間を調整する
・有事の際の影響範囲の確認（どの時間に誰がどのRDSH・VDIを利用していたか）

#解決策

・Event database へのクエリを作りこむ
・Horizon Tool box 2 を利用する

Horizon toolbox 2で出来ること：

・セッション統計情報が確認できる（過去2日、過去７日、過去1ヶ月、過去半年の単位）
・ユーザー単位の接続時間、接続先の仮想ブラウザホストが分かる　

※下記図でいうとMachine Name (RDSH3)が仮想ブラウザホストである。
・ＣＳＶエクスポート

![image](https://qiita-image-store.s3.amazonaws.com/0/169431/558ea2bd-6a77-36a3-ab23-34c53f960e9e.png)


インストール方法：

＜リソース＞ 

https://labs.vmware.com/flings/horizon-toolbox-2#summary
※無償ツールにつきサポートは無いことを注意。

＜手順＞
・MSIファイルをダウンロードのうえ、いずれかのConnection Server にインストールする。
※インストール前に.Net Framework3.5のインストールが必要。（サーバーマネージャーから） 
・インストールによりＯＳ再起動は発生しない。
・インストール後、https://IPアドレス:18443/toolbox へ接続する。
Xamarin の為だけに Visual Studio 2017 をミニマムインストールする

注)こちらは極限まで容量を抑えるための方法です。普通に Visual Studio 2017 with Xamarin を入れたい人は、

* [Xamarin やりたい人向け Visual Studio 2017 インストール手引書 - Xamarin 日本語情報](http://ytabuchi.hatenablog.com/entry/visualstudio2017)

をご覧ください。

Visual Studio 2017 で Xamarin を選択すると20GBくらいディスク容量が必要との噂を聞きまして。

その時、もっとも容量を必要とするのが「Google Android エミュレータ」であるとの情報も得ていました。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">とりあえず標準でXamarinのチェックつけると自動で追加されるAndroidエミュが20GB使うから実機ある人はチェック外しましょう。<a href="https://twitter.com/hashtag/Xamarin?src=hash">#Xamarin</a> <a href="https://twitter.com/hashtag/vs2017?src=hash">#vs2017</a></p>&mdash; SHUNSUKE_KAWAI (@_shunsuke_kawai) <a href="https://twitter.com/_shunsuke_kawai/status/839300865630466048">2017年3月8日</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr"><a href="https://twitter.com/_shunsuke_kawai">@_shunsuke_kawai</a> <a href="https://twitter.com/amay077">@amay077</a> こんな感じ？Nexus～は元々あったんじゃないか疑惑があるので、それ以外かな <a href="https://t.co/gOUlp0Twbx">pic.twitter.com/gOUlp0Twbx</a></p>&mdash; nuits.jp (@nuits_jp) <a href="https://twitter.com/nuits_jp/status/839371528739291138">2017年3月8日</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>

それらを踏まえて、

**Xamarin に必要な Visual Studio 2017 の最小構成**

は、以下です。

![](http://blog.amay077.net/assets/images/posts/visual_studio_2017_minimum_installation_for_xamarin_01.png)

この最小構成だとディスク容量は **「8.27GB」** で済みます(もちろん、Java や Android SDK が既に導入済みであれば、そちらを使用することでさらに容量を減らすことができます)。

**「.NET によるモバイル開発」のみにチェックを付けます。**

さらに、省略可能の選択肢から以下のものを外します。

* ❌ Xamarin Workbooks や Xamarin Profiler は容量的にはどうということは無いので、入れておいても良いです。

* ❌ Android NDKは、普通にAndroidアプリを開発している間は不要です。必要になったら入れましょう。

* ❌ 🤔 Google Android エミュレータが諸悪の権化です。6つくらいのエミュレータを作成するため、ここだけで20GB程度必要になってしまうようです。
エミュレータは必要なものだけ、実行時に作成しましょう。もちろん実機で開発・デバッグするなら不要です。

* ❌ F# 言語サポート。まあ、必要な型は入れてください。

## UWP は？

Xamarin.Forms で UWP アプリも作る！という場合は、図の青枠「ユニバーサルWindowsプラットフォーム開発」にチェックを入れるましょう。「Xamarin用ユニバーサルWindowsなんちゃら〜」も要るかも知れません。

ちなみに UWP も ON にすると追加で9GB程度のディスク容量が必要になります。
Web Apps にインポートする証明書を IIS で作成する

Azure の App Service Web Apps で証明書を設定するには .pfx で出力された証明書ファイルが必要。
今回は IIS で CSR 作成からエクスポートまでを行い、Web Apps へインポートする。

## 準備

- ローカルマシンに IIS を有効にする ([Windows10でIISを（ホームページ）有効化する設定](http://www.wannko.net/windows10/iis/iis_00.html))

## IIS での作業

### CSR を作成

1. インターネット インフォメーション サービス (IIS) マネージャーを起動
2. 機能ビュータブの「サーバー証明書」をダブルクリック
3. 右の操作メニューより「証明書の要求の作成」をクリック
4. 各項目を入力し「次へ」をクリック
5. 暗号化サービス プロバイダで「RSA SChannel Cryptographic Provider」を選択、ビット長で「2048」を選択し「次へ」をクリック
6. CSR を出力するパスと CSR のファイル名を設定し「終了」をクリック


### 作成した CSR を認証局(CA)に申請

1. 出力した CSR ファイルをテキストエディタで開く
2. その中に記載されている「-----BEGIN CERTIFICATE-----」から「-----END CERTIFICATE-----」までをコピー
3. 認証局の証明書発行ページに貼り付けて申請


### 証明書の要求を完了させる

1. 認証局より受信した通知メールの本文に記載されている PKCS#7 形式 (Microsoft IIS 用) の「-----BEGIN NEW CERTIFICATE REQUEST-----」から「-----END NEW CERTIFICATE REQUEST-----」までをコピー
2. 新しくテキストエディタを開き、コピーした証明書を貼り付け、名前をつけて保存 (拡張子を .cer にする)
3. インターネット インフォメーション サービス (IIS) マネージャーを起動
4. 機能ビュータブの「サーバー証明書」をダブルクリック
5. 右の操作メニューより「証明書の要求の完了」をクリック
6. 作成した証明書のファイルを選択、フレンドリ名(ラベルのようなもの)は任意のものを入力
7. 新しい証明書の証明書ストアの選択で「個人」を選択し「OK」をクリック
8. インターネット インフォメーション サービス (IIS) マネージャーの画面を更新し、表示された証明書が消えないことを確認 (表示が消える場合、秘密鍵と紐付いていない可能性がある)


### 中間証明書をインストール

1. 証明書を申請した認証局のサイトへアクセス
2. 中間証明書のページへ行き、申請した製品名の中間証明書を取得
3. 新しくテキストエディタを開き、コピーした中間証明書を貼り付け、名前をつけて保存 (拡張子を .cer にする)
4. 保存した中間証明書を右クリックし、「証明書のインストール」を選択
5. 証明書のインストールウィザードにて、保存場所を「ローカル コンピューター」を選択し「次へ」をクリック
6. 「証明書をべて次のストアに配置する」を選択し「参照」をクリック
7. 「物理ストアを表示する」にチェックし、[中間証明機関] を選択し「OK」をクリック
8. 「次へ」をクリックし「完了」をクリック

### 証明書をエクスポート

1. インターネット インフォメーション サービス (IIS) マネージャーを起動
2. 機能ビュータブの「サーバー証明書」をダブルクリック
3. 作成した証明書を選択し、右の操作メニューより「エクスポート」をクリック
4. エクスポート先を指定し、パスワードを入力 (入力したパスワードは忘れないように保管しておくこと)

## Web Apps での作業

### 証明書をインポート

1. Web Apps を選択し、「SSL 証明書」を選択
2. 「証明書のアップロード」を選択
3. エクスポートした .pfx ファイルを選択し、設定したパスワードを入力して「アップロード」をクリック

### 証明書とドメインをバインド

1. Web Apps を選択し、「SSL 証明書」を選択
2. 「バインディングの追加」をクリック
3. 以下の項目を選択し「バインディングの追加」をクリック
    - ホスト名: 事前に Web Apps に登録しているドメインを選択
    - 証明書: インポートした証明書を選択
    - SSL の種類: IP ベースの SSL を選択
4. Web Apps の URL に HTTPS でアクセスし、適用されているか確認

## 参考

- [HTTPS を使用したアプリのカスタム ドメインのセキュリティ保護 | Microsoft Docs](https://docs.microsoft.com/ja-jp/azure/app-service-web/web-sites-configure-ssl-certificate#bkmk_iismgr)
- [[IIS 7.0以降] 証明書をインストールした後に画面更新や遷移を行うと、証明書の表示が消えてしまいます。｜Cybertrust.ne.jp](https://www.cybertrust.ne.jp/sureserver/support/faq/tech_faq07.html#09)
mysqlerror : (2019, "Can't initialize character set utf8mb4 (path: /usr/share/mysql/charsets/)")

### my.confで文字コード設定確認

```
[client]
default-character-set = utf8mb4
[mysql]
default-character-set = utf8mb4
[mysqld]
character-set-client-handshake = FALSE
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
```

### alter文でdatabase,tableの文字コード変更


### settingsで文字コード指定

```
  'OPTIONS': {'charset':'utf8mb4'}
```

### /usr/share/mysql/charsets/Index.xml の `<charset name="utf8">`　を　`<charset name="utf8mb4">` に書き換え。
MapStructでBeanマッピング その1

MapStruct 1.1.0を使用

MapStructの詳細は公式サイトを参照
http://mapstruct.org/

# 同じフィールドを持つBean同士のマッピング

```java:Bean
public class ProfileForm {
    private String name;
    private int age;
    private String location;

    // constructor/getter/setter
}

public class Profile {
    private String name;
    private int age;
    private String location;

    // constructor/getter/setter
}
```

## Mapperの作成

```java
@Mapper
public interface ProfileMapper {
    ProfileMapper INSTANCE = Mappers.getMapper(ProfileMapper.class);

    public Profile profileFormToProfile(ProfileForm form);
}
```

## 実行

```java
ProfileForm form = new ProfileForm("マイケル・スコフィールド", 30, "アメリカ合衆国");
Profile profile = ProfileMapper.INSTANCE.profileFormToProfile(form);

System.out.println(profile.getName()); // マイケル・スコフィールド
System.out.println(profile.getAge());  // 30
System.out.println(profile.getLocation()); // アメリカ合衆国

```

## フィールドの一部をマッピング対象外にする
フィールドの一部をマッピング対象外にするには、 `@Mapping` アノテーションを利用する。
target属性に対象外にするフィールドと、ignore属性に `true` を設定する。

```java
@Mapper
public interface ProfileMapper {
    ProfileMapper INSTANCE = Mappers.getMapper(ProfileMapper.class);

    @Mapping(target = "name", ignore = true)
    public Profile profileFormToProfile(ProfileForm form);
}
```

# リスト同士のマッピング

## Mapperの修正

```java
@Mapper
public interface ProfileMapper {
    ProfileMapper INSTANCE = Mappers.getMapper(ProfileMapper.class);

    public Profile profileFormToProfile(ProfileForm form);
    // 追加
    public List<Profile> profileFormToProfile(List<ProfileForm> forms);
}
```

## 実行

```java
List<ProfileForm> forms = Arrays.asList(new ProfileForm("マイケル・スコフィールド", 30, "アメリカ合衆国")
                                      , new ProfileForm("リンカーン・バローズ", 34, "アメリカ合衆国"));
List<Profile> profiles = ProfileMapper.INSTANCE.profileFormToProfile(forms);

System.out.println(profiles.get(1).getName()); // リンカーン・バローズ
System.out.println(profiles.get(1).getAge());  // 34
System.out.println(profiles.get(1).getLocation()); // アメリカ合衆国
```

---

# 異なるフィールドを持つBean同士のマッピング

```java:Bean
public class Foo {
    private String foo1;
    private String foo2;

    // constructor/getter/setter
}

public class Bar {
    private String bar1;
    private String bar2;

    // constructor/getter/setter
}
```

## Mapperの作成

```java

@Mapper
public interface FooBarMapper {
    FooBarMapper INSTANCE = Mappers.getMapper(FooBarMapper.class);

    @Mapping(target = "bar1", source = "foo1")
    @Mapping(target = "bar2", source = "foo2")
    public Bar fooToBar(Foo foo);
}
```

`@Mapping` アノテーションでマッピングさせたいフィールド(target)と、マッピングするフィールド(source)を指定する。


## 実行

```java
Foo foo = new Foo("あいうえお", "かきくけこ");
Bar bar = FooBarMapper.INSTANCE.fooToBar(foo);

System.out.println(bar.getBar1()); // あいうえお
System.out.println(bar.getBar2()); // かきくけこ
```


他にもマッピングのための機能があるが、それらは次回。
VMware Horizon Deep Security併用時に仮想マシンが起動できない


Deep Security + NSX + VMwareのDRS の設定を有効にしている環境で、Deep Security Virtual Appliance (DSVA) が停止していると、当該ホスト上の仮想マシンを起動することができない。

DSVAが停止していると、DSVAで管理している仮想マシンの起動ステータスが35%で止まってしまい、正常に起動することができない。DSVAを起動することで、35%で止まっていたステータスも進み、仮想マシンが正常に起動する。仮想マシンが起動しない場合は、DSVAがきちんと起動していることをまず確認。

==参考==
Deep Security Virtual Appliance が停止していると仮想マシンを起動することができない
http://esupport.trendmicro.com/solution/ja-JP/1116638.aspx
MindでHello World(PowerShell編)

# <i class="fa fa-cubes" style="font-size:1em;"></i> 概要
日本語プログラミング言語の**Mind**をWindows10で触ってみます。

# <i class="fa fa-cubes" style="font-size:1em;"></i> インストール
こちらからダウンロードできます。
[日本語プログラミング言語 Mind](http://www.scripts-lab.co.jp/mind/whatsmind.html)

zipファイルを右クリック、プロパティでブロックの解除をしたら、
![mind01.png](https://qiita-image-store.s3.amazonaws.com/0/142879/3dc36dd4-8a90-f361-7ae8-26198376cbd8.png)

適当な場所に展開してください。
本記事では`C:\Work`に`pmind`フォルダを配置しました。

[オペレーションマニュアル](http://www.scripts-lab.co.jp/mind/ver8/doc/operation-manual.html)ではコマンドプロンプトを使うようになっているのですが、本記事ではPowerShell上でコンパイル・実行をします。

以下のような、PowerShellを起動するBATファイルを用意します。
BAT中の`-Command`の直後の`$mHome=*****`のパスはインストール先に合わせて書き換えてください。

```bat:ps_mind.bat
@echo off

REM 【準備】
REM   「$mHome」にMindインストールパスを設定すること。
REM 【実行内容】
REM   ・環境変数PATHへの追加
REM   ・環境変数MLIBPATHの設定
REM   ・ウィンドウタイトルの設定
REM   設定はPowerShellのセッション中のみ有効。環境を汚しません。

powershell.exe -NoLogo -NoProfile -NoExit -Command "&{$mHome='C:\Work\pmind'; $env:Path += \";${mHome}\bin\"; $env:MLIBPATH=\"${mHome}\lib\"; (Get-Host).UI.RawUI.WindowTitle = 'PowerShell - Mind開発'; cd $mHome; ls}"

```

`ps_mind.bat`の置き場所はデスクトップでも`pmind`ディレクトリでも好きな場所でよいです。

# <i class="fa fa-cubes" style="font-size:1em;"></i> 使ってみる

ps_mind.batをダブルクリックすると、PowerShellが開いてカレントディレクトリがMindインストール場所に設定されます。
![mind02.png](https://qiita-image-store.s3.amazonaws.com/0/142879/c0b0a47f-f598-fa2c-1009-fe45c6b2f854.png)

```PowerShell
cd sample
ls
```

でsampleディレクトリに移動し、ファイル一覧を表示してみます。
![mind03.png](https://qiita-image-store.s3.amazonaws.com/0/142879/9f733b28-8d14-8a7f-fe64-ced7fc8592e7.png)

`hello.src`をテキストエディタで開いてみます。
![mind05.png](https://qiita-image-store.s3.amazonaws.com/0/142879/0ed87b79-6a69-392b-dac3-48f9e2c540ef.png)


`hello.src`をコンパイル、実行してみます。

```text
mind hello file
```

mindコマンドの1つ目の引数にソースファイル名、2つ目の引数にライブラリ名を指定します。
![mind06.png](https://qiita-image-store.s3.amazonaws.com/0/142879/a87d1372-d2da-2254-f56a-ccafbf9e2a7e.png)

コンパイルが終わったら、

```PowerShell
ls hello*
```

で生成されたファイルを見てみます。
`hello.exe`と`hello.mco`のセットが実行ファイルです。
![mind04.png](https://qiita-image-store.s3.amazonaws.com/0/142879/3105509b-b658-2a46-6e69-a0c75671393d.png)

```PowerShell
.\hello
```

で`hello.exe`を実行してみます。
PowerShellなので、カレントディレクトリにあるファイルでも`.\`指定を忘れずに。

もう少し長いサンプルを作ってみます。

```Text:test1.src
三回叫ぶとは
	３を　回数指定して
		「ギャー！」を　表示して　改行し、
	繰り返すことですよ。

今何時か答えるとは
	日時を得て
	時を　数値表示し、　「時」を　表示し、
	分を　数値表示し、　「分」を　表示してから
	改行することですよ。

メインとは
	三回叫んで
	今何時か答え、
	三回叫ぶことです。
```

エディタ画面
![mind07.png](https://qiita-image-store.s3.amazonaws.com/0/142879/d82d1306-d373-b509-f18a-f095bdfdec40.png)


```Text
mind test1 file
```

でコンパイルし、`test1.exe`を実行してみます。
![mind08.png](https://qiita-image-store.s3.amazonaws.com/0/142879/7330cb35-e299-5393-01c1-0c514fe4c428.png)
メッセージと時刻が表示されました。

# <i class="fa fa-book" style="font-size:1em;"></i> 参考サイト
* [Mind オペレーションマニュアル](http://www.scripts-lab.co.jp/mind/ver8/doc/operation-manual.html)
* [Mind プログラミングマニュアル](http://www.scripts-lab.co.jp/mind/ver8/doc/index.html)
Microsoft Flowを使ってGoogleカレンダーとOutlookのスケジュールを統合する

仕事の予定とプライベートの予定は会社員であれば、排他的なことが多いのですが時に互いのスケジュールを考慮して計画したい時も発生します。違うメーラーを使っている場合は見比べながらやらないといけません。その際に統合して見れるとかなり便利です。今回は仕事でOutlook、プライベートでGoogleを使っているケースでどのようにやるのかMicrosoft Flowで実現してみたいと思います。

#フローの作成

&nbsp;

Microsoft Flow上のフローはいたってシンプルです。Googleのカレンダーにイベントが追加されれば、Outlookのスケジュールにイベント登録されるという流れです。

&nbsp;


![スクリーンショット 2017-03-05 19.10.46.png](https://qiita-image-store.s3.amazonaws.com/0/159178/0ae067db-8cb7-6e7f-0379-3aff5d785133.png)

&nbsp;


Googleの設定のほうはコピーさせたいカレンダーIDを指定するだけです。Googleカレンダーの下記の場所にあり、このカレンダーIDが選択欄として表示されます。

&nbsp;

![スクリーンショット 2017-03-05 19.13.03.jpg](https://qiita-image-store.s3.amazonaws.com/0/159178/01232c60-dc74-e841-ad45-f5aa1139e857.jpeg)

&nbsp;


![スクリーンショット 2017-03-05 19.24.44.jpg](https://qiita-image-store.s3.amazonaws.com/0/159178/1b2c1d56-ce04-325d-2c92-6fd4bf307d60.jpeg)

&nbsp;

Outlookのほうの設定はGoogleカレンダーから取得できるイベントの項目をOutlookのどこの項目に設定するのかを決めます。Outlookのスケジュールが他人からは見えないようにするには、今回の目的用に新しいカレンダーを作成します。（「自分の予定表」の右に"＋"があるのでそこから新規作成できます。）

&nbsp;


今回は「プライベート予定」を作成

&nbsp;

![スクリーンショット 2017-03-05 19.32.33.png](https://qiita-image-store.s3.amazonaws.com/0/159178/5faceb96-e651-ed66-4974-8a89ef2292aa.png)

&nbsp;



そして、この予定表に対して、Googleカレンダーの各項目をマッピングさせます。

&nbsp;


![スクリーンショット 2017-03-05 20.32.19.png](https://qiita-image-store.s3.amazonaws.com/0/159178/b92347aa-f46c-b9a3-938e-7e148526e44a.png)

&nbsp;

![スクリーンショット 2017-03-05 20.31.37.png](https://qiita-image-store.s3.amazonaws.com/0/159178/56519d71-5ee0-d3af-23f1-5f6132e391f1.png)

&nbsp;

私の場合は開始時間・終了時間とその内容が確認できればOKなのでこんな感じです。


#フローの実行

&nbsp;

まず、Googleに予定を登録します。

&nbsp;

![スクリーンショット 2017-03-05 20.50.55.png](https://qiita-image-store.s3.amazonaws.com/0/159178/356abc5e-1b07-2fde-6daf-19d509b442fa.png)

&nbsp;

登録がされたのをトリガーにMicrosoft Flowが走り始めます。

&nbsp;


![スクリーンショット 2017-03-05 21.18.14.png](https://qiita-image-store.s3.amazonaws.com/0/159178/3eef1bb4-aa59-29cb-9a4a-9fa567b2491b.png)

&nbsp;

実行結果を見ると、該当のスケジュールがトリガーになっているのがわかります。

&nbsp;

![スクリーンショット 2017-03-05 21.20.53.jpg](https://qiita-image-store.s3.amazonaws.com/0/159178/b9f0019c-8e5c-cedd-57b0-c89b6d45e96a.jpeg)

&nbsp;

次にOutLook側の実行結果を見ると、Google側の登録結果が引き継がれているのがわかります。


&nbsp;

![スクリーンショット 2017-03-05 21.21.07.png](https://qiita-image-store.s3.amazonaws.com/0/159178/9f06b30b-f992-0ef4-e4db-03edb8efa71c.png)

&nbsp;


Outlook側のスケジュールを見ると、もちろんその内容が反映されています。


&nbsp;

![スクリーンショット 2017-03-05 21.23.52.png](https://qiita-image-store.s3.amazonaws.com/0/159178/47db754b-8168-195c-f497-df982f5a2e5a.png)

&nbsp;


#まとめ

&nbsp;

幸か不幸か、我々は環境に「慣れて」しまいます。つまり、他人から見て無駄な作業でも本人が気づかないことがたくさんあります。これまで幾つかサービスを作成しましたが、情報を見る場所は１つに集約されているのが効率がよいですね。
python3 で ゼロから考える機械学習【工事中】→中止

#面倒なのでKeras使うh6




巷にはtensorflowやKerasなど機械学習の助けになるライブラリが沢山あるけど
なんとなく自分で適当に書いてみたので、記録のために残しておく
（使わない函数やよくわからんコメントも残しておく）

<h1>「メモ」 なので、、、</h1>

<br>


```ruby:qiita.rb

import numpy as np
#%matplotlib inline
import matplotlib.pyplot as plt
import time
from pylab import *
import random

from numba.decorators import jit



#活性化関数(シグモイド関数)の定義
def sigmoid(x):
    return 1 / (1 + np.exp(x))

#層のノード数
def node_size(size):
    n = np.ones((size, 1))
    return n 

#ノードのサイズ
def node_len(node_size):
    return np.size(node_size)

#重みの初期値をランダムで計算
def weight(row, column):
    weight = np.random.rand(row, column)
    return weight

#活性化関数ReLU
def ReLU(x):
    if x <= 0:
        return 0
    else:
        return x

def softmax(x):
    exp_a = np.exp(x)
    sum_exp_a = np.sum(exp_a)
    y = exp_a/sum_exp_a
    return y

def numerical_diff(f, x):
    #f = x**2 + x + 1
    h=e-4
    return ((f(x+h)-f(x-h))/(2*h))

#誤差函数
def Error_function(output, teacher):
    remainder = output - teacher
    square_of_error= 1/2*(np.sum(remainder))**2
    return square_of_error

start = time.time()


#各層のノード行列のディクショナリ
#何層で学習させるかは、ここで決める。(N0は入力層)
node_d = {0:node_size(4),
          1:node_size(4),
          2:node_size(4)}#自分で設定
roop_1 = len(node_d)
###メモ！重みファイルを読み込む。なければ新規作成。ifで条件

node_d[0] = np.array([[0],[1],[0],[1]])#入力信号
print(node_d)
teacher = np.array([[0],[1],[0],[1]])#教師信号（仮

###メモ！重みファイルを読み込む。なければ新規作成。ifで条件分岐

#各層の重み行列のディクショナリ
#何層で学習させるかは、ここで決める。(W0は使わない)
weight_d = {}

for i in range(1,roop_1,1):
    print("number of weight layer = ", i)
    weight_d[i] = weight(node_len(node_d[i]), node_len(node_d[i - 1]))#自分で設定
    print(weight_d[i])
    
print("\n -> calc. time = ",time.time() - start,"[sec]")

#ノードと重みの計算
#最後の値が出力となる
for i in range(1,roop_1,1):
    print("node = ", i)
    node_d[i] = sigmoid(np.dot(weight_d[i], node_d[i-1]))
    print(node_d[i])

#途中計算結果
print(np.sum(weight_d[1]))
print(np.sum(weight_d[2]))
a=0.5*(np.sum(weight_d[1])-np.sum(weight_d[2]))**2
print("a=",a)
print("erro=",Error_function(weight_d[1],weight_d[2]))

```
取り敢えずこんな感じで書いていく（まだ途中でこの後に誤差逆伝搬を実装する）

~~~
sympyで直線と直線の交点

#後からまとめて、値を代入
もっと短くなるような気もします。

```python
#sympyで直線と直線の交点
from sympy import *
var('x1 y1 x2 y2 x3 y3 x4 y4')
ln12 = Line(Point(x1, y1), Point(x2, y2))
ln34 = Line(Point(x3, y3), Point(x4, y4))
ls=ln12.intersection(ln34)
#print(ls)
input={x1:0,y1:0, x2:1, y2:1, x3:0, y3:1, x4:1, y4:0};print(ls[0].x.subs(input),ls[0].y.subs(input))
input={x1:0,y1:0, x2:1, y2:1, x3:0, y3:1, x4:1, y4:2};print(ls[0].x.subs(input),ls[0].y.subs(input))
#1/2 1/2
#zoo zoo
```

－－－－－－－－－－－－－－
(2021/02/10)
もっと短くなるような気もします。

```python
#sympyで直線と直線の交点
from sympy import *
var('x1 y1 x2 y2 x3 y3 x4 y4')
ls=Line(Point(x1, y1), Point(x2, y2)).intersection(Line(Point(x3, y3), Point(x4, y4)))
#print(ls)
input={x1:0,y1:0, x2:1, y2:1, x3:0, y3:1, x4:1, y4:0};print(ls[0].x.subs(input),ls[0].y.subs(input))
input={x1:0,y1:0, x2:1, y2:1, x3:0, y3:1, x4:1, y4:2};print(ls[0].x.subs(input),ls[0].y.subs(input))
#1/2 1/2
#zoo zoo
```
#最初から、値を代入
```python
#sympyで直線と直線の交点
from sympy import *
print(Line(Point(0,0), Point(1,1)).intersection(Line(Point(0,1), Point(1,0))))
print(Line(Point(0,0), Point(1,1)).intersection(Line(Point(0,1), Point(1,2))))
# [Point2D(1/2, 1/2)]
# []
```
Listの中のオブジェクトは参照だったよね？の確認

Listの中身の加工について覚書

#Listの中のオブジェクトが参照じゃない気がしたからテスト

```java:テスト用クラスを用意

public class Test {
	public static void main(String[] args) {
		TestEntity enttity = new TestEntity();
		TestEntity enttity2 = new TestEntity();
		TestEntity enttity3 = new TestEntity();

		ArrayList<TestEntity> list = new ArrayList<>();
		list.add(enttity);
		list.add(enttity2);
		list.add(enttity3);

		showEntityList(list);
	}

	static void showEntityList(ArrayList<TestEntity> list) {
		System.out.println("エンティティの中身を見ます");

		for (TestEntity a : list) {
			System.out.println(a.a);
			System.out.println(a.b);
			System.out.println(a.c);
			System.out.println(a.d);
		}
	}
}

public class TestEntity {
	String a = "スタート";
	String b = "b";
	String c = "c";
	String d = "d";

}
```

```text:実行結果
エンティティの中身を見ます
スタート
b
c
d
スタート
b
c
d
スタート
b
c
d
```

取り出したオブジェクトの中身を触った場合

```java:メソッドを用意
	/**
	 * エンティティを取り出し、加工するだけ
	 * */
	static void modifyOnly(ArrayList<TestEntity> list) {
		int size = list.size();

		for (int i=0;i<size; i++) {
			TestEntity value = list.get(i);
			value.a = "ハジマリデス(" + i + ")";
			value.b = "2(" + i + ")";
			value.c = "3(" + i + ")";
			value.d = "4(" + i + ")";
		}
	}
```

```java:上記を使ってみる
		TestEntity enttity = new TestEntity();
		TestEntity enttity2 = new TestEntity();
		TestEntity enttity3 = new TestEntity();

		ArrayList<TestEntity> list = new ArrayList<>();
		list.add(enttity);
		list.add(enttity2);
		list.add(enttity3);

		modifyOnly(list);
		showEntityList(list);
```

```text:実行結果
エンティティの中身を見ます
ハジマリデス(0)
2(0)
3(0)
4(0)
ハジマリデス(1)
2(1)
3(1)
4(1)
ハジマリデス(2)
2(2)
3(2)
4(2)
```

#結論
取り出して中身を加工するだけでListの中身に影響あり。

おかしいな、職場でこれやったら書き換わらなくて、わざわざ書き換えたentityをsetし直したら求めた動きをしたんだけどな。
いやまあそもそもこの動きが本来の想定通りなんだけど。

うーん、職場のソースとにらめっこだな。


#追記
@shiracamus さんのおかげでQiita上のソースを見やすくする方を覚えました。
技術的な事以前にQiitaの使い方が分かってない中、ありがとうございます。

ご指摘頂いてマージとか出来るんですね。
ただ知らずに普通に手で直した後にご指摘の内容を確認したらマージ状態になってしまって逆に修正が変な感じになってしまったのは内緒（汗
PythonでFirebase Dynamic Links APIを叩く


# はじめに

[公式のドキュメント](https://firebase.google.com/docs/dynamic-links/create-links) は用意されていましたし、基本その通りにやりば問題ないと思いますが、少し詰まってしまったポイントもあったのでメモがてらまとめます。

# 手順

## Firebaseの設定

[Firebase console](https://console.firebase.google.com) からログイン。
FirebaseのAPI KEYを確認しておく。
次にプロジェクトの設定へ移動。
「アプリを追加」からiOS, Androidそれぞれ以下の値を入力して追加。以下は全て必須。

### iOS

- Bundle ID
- App Store ID
- App ID Prefix

App ID PrefixはUniversal Link用のapple-app-site-associationが裏側で生成されるのでそれに使われる。

### Android

- パッケージ名

## Firebase Dynamic Linksのドメインを確認する

適当に追加してみる。
ここで何かしらエラーが出たらアプリの追加をミスっている。
リンクを追加するとリンク一覧テーブルの左上に以下のようなドメインが表示されているはずなのでメモっておく（重要）。
`https://xxx.app.goo.gl/`

## Pythonから叩いてみる

```python
import requests


url = "https://firebasedynamiclinks.googleapis.com/v1/shortLinks?key=FIREBASE_API_KEY"
data = {
    "dynamicLinkInfo": {
        "dynamicLinkDomain": "xxx.app.goo.gl",
        "link": "http://example.com/",
        "androidInfo": {
            "androidPackageName": "com.example.AndroidApp"
        },
        "iosInfo": {
            "iosBundleId": "com.example.iOSApp"
        }
    }
}
result = requests.post(url, json=data)
```

`result.ok` がtrueなら成功してます。
成功していれば `result.json()` にURLが入ってます。


## 地味にハマったところ

Firebase console上でDynamic Linksを1つ追加しないと前述のドメインが分からない（自分が見逃していただけかもだけど）。
なので最初上記コード例の `dynamicLinkDomain` のドメインは `[firebaseのプロジェクト名].app.goo.gl` かな？と思って試したら以下のようなエラー

```json
{
	'error': {
		'code': 400, 
		'message': 'Request contains an invalid argument.', 
		'status': 'INVALID_ARGUMENT'
	}
}
```

どこが間違っているか分からず消耗してしまいました。

まぁ、他の人は詰まらない部分かもしれませんが自分はうっかり悩んでしまいました。
誰かの一助になればと思って書きました。

以上です。
Spark実験

# 目的
Sparkを使って見るという実験で、全てのペアについて距離を総当りで計算して近傍探索、閾値以下のものについてソートして出力ということをやって見た。
趣旨としては、特徴ベクトルで一定の近傍を探索し、「類似している」ものを提示する、ということである。

# 作業の実際
　pickleからデータを読み込む。キー文字列のベクトルと、特徴量ベクトルのベクトルがタプルとして保存されているので、個別にRDDに変換してzipで結合する。
pickleから読み込んでいるのは、実験に使ったテストデータが、別件の実験でtensorflowで作成したものだったから。

```
import pickle
import numpy as np

# load from pickle
f=open("cvtest3.pickle", "rb")
cv3=pickle.load(f)
f.close()

# re-construct from ([vector of key], [vector of feature vector])
cv3R1 = sc.parallelize(cv3[0])
cv3R2 = sc.parallelize(cv3[1])
cv3R = cv3R1.zip(cv3R2)
```


　キー文字列kiと特徴ベクトルviのペア(ki, vi)から、(ki, kj)のペアとvi, vj間の距離rijを直積を使って求める。

```
# make all i-j pair  as ((i, v_i), (j, v_j))
B=cv3R.cartesian(cv3R)
# change to ((i, j), (v_i, v_j))
C=B.map(lambda x: ((x[0][0],x[1][0]),(x[0][1],x[1][1])))

# calculate Euclid distance
D=C.filter(lambda x:x[0][0]!=x[0][1])
E=D.map(lambda x: (x[0], x[1][0]-x[1][1]))
# ((i, j), r_ij)
F=E.map(lambda x:(x[0], np.sqrt(np.dot(x[1],x[1]))))
F.persist()
```


　一旦、iに対して、それが持つ距離全てをまとめたベクトルを作る。statを使って、iごとにmin/max, 平均/標準偏差などを計算する。これがキーiの周囲の状況を示す。

```
##
## stat1
##

# make new (i, [all r_ij]) vector
G=F.map(lambda x: (x[0][0], x[1]))
H=G.groupByKey()
I=H.map(lambda x: (x[0], list(x[1])))

# stats for each i
J=I.map(lambda x:(x[0], np.array(x[1])))
# (i, (min, mean, std dev, max))
K=J.map(lambda x:(x[0], (np.min(x[1]),np.mean(x[1]),np.std(x[1]),np.max(x[1]))))
```


　一方で、全部の距離だけの統計も求め、閾値をここから得ることにする。
閾値を mean - 2* std_dev としているが、データによっては空集合になったりするので個別に判断してやる必要がある（こういうのこそ人工知能が判断してほしい）。

```
##
## stat2
##

# extract only r_ij
L=F.map(lambda x: x[1])
# obtain stats
L.persist()
l=L.stats()
print(l.min(), l.mean(), l.stdev(), l.max())

thre = l.mean() - l.stdev() * 2
print(thre)
```


　((ki, kj), rij)なるペアから(ki, (kj, rij))を計算し、kiについてまとめる。事前に閾値以下のもののみ抽出しておく。

```
## (i, [(j, r_ij)]) near than thre
O=F.filter(lambda x: x[1] < thre)
P=O.map(lambda x: (x[0][0], (x[0][1], x[1])))
Q=P.groupByKey()
# +magic
R=Q.map(lambda x: (x[0], list(x[1])))
```

　　全ペア間距離から求めた何らかの閾値以下の距離にある、キーiから見て比較的近くにあるキーjの集合を、その距離とともに得る。ついでに、キーiごとに、近傍のキーの数とか、平均/標準偏差などの近傍分布なども結合して出力しておく。

```
# size of i-j pair near by threshold
S=R.map(lambda x: (x[0], len(x[1])))
## join S and K; (i, (num of neighbor, (min, mean, stddev, max)))
SK=S.join(K)

## sort the neighbor list
T=R.map(lambda x: (x[0], sorted(x[1], key=lambda y: y[1])))
DIC=SK.join(T)

## obtain the result as a list
RES=DIC.collect()
```

# 余言
この件は元々はSparkが話題になった2015年6,7月頃に実験してみようと思ったものの、会社のクソ用事のせいで忙殺され、実際に手を動かせたのは2016年1月になっていた（2015年の夏ころは私物のHadoopクラスタの構築に手間取っていた）。2016年1月には、上で言うKの計算まではできていたが、ある要素周囲の状況を求めたところから先が思いつかずそのまま放置された。
その後1年近く、もっとクソな用事で忙殺されていたのがやっとカタがつき、全ての距離分布の平均・標準偏差から出した閾値で近傍リストを作るということを思いつき、1年越しでやっと片付けられた。2015年の流行からだと1.5年遅れである。
【対処法】FFFTPの530エラーでファイルをアップロードできない(vsftpd, CentOS7)

# はじめに
CentOS7.2のサーバーにvsftpdをインストールして、ローカルPCからFFFTPでファイルをuploadしようと思ったら、下記のような530エラーが。。。。
530はログインエラーですが、今回はログイン情報は間違っていませんでした。
すがる気持ちでサポートに連絡しても解決できず。。。。
なんとか対処法を見つけ出せたので、備忘録としてまとめます。
![WS000002.JPG](https://qiita-image-store.s3.amazonaws.com/0/168635/421e5a32-4aa9-df00-403f-5b8b6963391a.jpeg)


# やりたいこと
- vsftpdでファイルをuploadできるようにする
- chrootの設定でホームディレクトリ配下のみupload可能にする


# 入れた設定（/etc/vsftpd/vsftpd.conf） ※変更箇所のみ記載

```
anonymous_enable = NO   ←anonymousユーザーログインの拒否
use_localtime = YES   ←時間ずれ防止
chroot_local_user = YES   ←chrootの許可設定
allow_writeable_chroot = YES   ←★chroot先に書き込む許可（この設定を見つけるまでに苦労しました。。。。）
```

### 上記設定後に、vsftpd再起動

```
# systemctl restart vsftpd
```

これで設定完了です！！


# まとめ
chrootの設定をしたい際は、chroot先の権限（読み書き）が関係してくるようです。
```allow_writeable_chroot = YES```この設定を入れることで、書き込みができるようになるので、結果的にファイルのアップロードができるようになります。
UI設計書を作成するうえでのポイント整理

#はじめに
現在、あるシステムのUI設計書を作成しています。
UIとはユーザーインターフェースの略で、分かり易い表現（意訳）で言うと、画面や帳票のレイアウト、機能、操作性などのことになります。
このUIに対する設計書（UI設計書）をもとにシステムの利用者（エンドユーザー）と打ち合わせを行い、UIに対する合意を取ります。
今回は、このUI設計書を作成するうえでのポイントを整理しました。

##機能に対する説明
 UI設計書はシステムの利用者に対する設計書なので、ユーザー目線に立った分かり易い表現（文章）を心掛けるようにします。
 システム的な表現（内部処理を表すような記述）は基本的には記述しません。

##画面レイアウト、帳票レイアウト
 画面レイアウトや帳票レイアウトは、できるだけ開発するシステムの完成形に近い見た目にしてください。
 そうしないとUI設計の段階では合意を得ていても、実際に完成したシステムの画面や帳票がユーザーの思い描く見た目とは異なってしまい、最悪のケースとしてはこの段階からの作り直しという事態を招く可能性もあります。

 また、画面レイアウトや帳票レイアウトをユーザーに提示する前に、その画面や帳票を実際に開発するうえでの難易度を（開発担当者や有識者に）確認しておくことも重要です。

一度ユーザーに提示し合意を得た要件に対し、後から取り下げを申し出る事態だけは避けたいものです。

##画面遷移図
 画面遷移図は厳密な意味ではUIには含まれませんが、画面や帳票の説明を行ううえで、画面間の関連を表す画面遷移図があると、ユーザーがシステムに対する具体的なイメージを持ちやすくなり、その結果としてUI設計を効率的に進めることが可能となります。


以上
【R】数値を文字列に置換する

今更感はあるが数値を文字列に置換する際にfactor関数を使えば楽にできるのでは？
と思い立ったのでメモ。

```r

require(dplyr)

# データとして10コの1〜4までの乱数を用意
set.seed(71)
x <- floor(runif(n = 10, min = 1, max = (4 + 1)))
data <- tibble(V1 = x)

# 1 : X, 2 : Y, 3 : Z, 4 : Wというように置換する

# 方法1 : ifelseをつかう
data %>% 
  mutate(V2 = ifelse(V1 == 1, 'X', ifelse(V1 == 2, 'Y', ifelse(V1 == 3, 'Z', 'W'))))

# 方法2 : factorを使う
data %>% 
  mutate(V2 = factor(V1, levels = 1:4, labels = c('X', 'Y', 'Z', 'W')))

```

2値を置き換えるのであればifelseで十分だが、値が3種類以上ならばfactor関数を使ったほうが可読性は高い。
ただfactor関数を使った場合は出力結果が文字列型ではない、タイトル詐欺になってしまった…。

**もっとスマートな書き方を教えてもらいました、コメントを参照**
Python 小技: enumerate() と zip() の組み合わせ、文字列が数値変換可能か調べる、文字列を数値としてソート

```
% python --version
Python 2.7.11 :: Anaconda 2.5.0 (64-bit)
```

## `enumerate()` と `zip()` を組み合わせる

```py
for i, (a, b) in enumerate(zip(list_a, list_b)):
    # Do something
```

## 文字列が数値に変換可能か調べる ※ただし正の整数に限る

文字列メソッドの `isdigit()` を使う。文字列中に数字しかない場合には真が、その他の場合は偽が返る。

```py
a = '100'
b = 'hoge100'

a.isdigit() # => True
b.isdigit() # => False
```

他にも `is*()` で色々と調べることができる。

参考: 

- [5. 組み込み型 — Python 2.7.13 ドキュメント](http://docs.python.jp/2/library/stdtypes.html#string-methods)
- [Python で文字列が数値に変換できるか検査する | すぐに忘れる脳みそのためのメモ](http://jutememo.blogspot.jp/2008/09/python_1396.html)

## 文字列を数値としてソート

やりたいこと:

```py
a = ['2', '1', '3', '33', '22', '11']

sorted(a) # => ['1', '11', '2', '22', '3', '33']
# I need `['1', '2', '3', '11', '22', '33']
```

`sorted()` のキーワード引数 `key` に `int()` を渡し、各要素 (文字列) を数値に変換してソートする。

```py
sorted(a, key=int) # => ['1', '2', '3', '11', '22', '33']
```

ソート対象のリストに数値変換できない文字列が含まれているとエラーになるので、その場合は以下のようにする。

```py
a = ['2', '1', '3', '33', '22', '11', 'hoge', 'fuga']

sorted(a, key=lambda x: int(x) if x.isdigit() else x) # => ['1', '2', '3', '11', '22', '33', 'fuga', 'hoge']
```

参考: [2. 組み込み関数 — Python 2.7.13 ドキュメント](http://docs.python.jp/2/library/functions.html#sorted)
Grafana で CloudWatch をデータソースに登録しようとしたら Internal Server Error が出た

# Grafana にデータソース登録

![image](https://qiita-image-store.s3.amazonaws.com/0/65435/8ed81dd8-606f-b7eb-8c34-e5d54aec3893.png)

こんな感じで、Grafana にCloudWatch をデータソースに登録したかったのですが、以下のようなエラーに遭遇しました。

![image](https://qiita-image-store.s3.amazonaws.com/0/65435/68431938-32be-bf29-69ca-01c04257f71c.png)

Internal Server Error っと言われてしまいエラーになってしまいます。

これの原因は、ARNに間違った情報を登録していて、それが邪魔しているから。

認証方法をARNに切り替えます。

![image](https://qiita-image-store.s3.amazonaws.com/0/65435/de9fe17d-f484-ddc7-12b2-bf33107c4952.png)

はい、余計な情報が残っていますね。ここに情報が入っていると、Access & Secret Key 認証を選択していても、
ARNの情報が競合してエラーとなります。

![image](https://qiita-image-store.s3.amazonaws.com/0/65435/d8ae4000-f7f9-6eee-a1e5-8d0a7945818f.png)

ここのARNを消して、それから再度、Access & Secret Key 認証をすると正常に成功します。
つらっ。
CSSスプライトをimgタグでやる

```scss
[type=image],
img {
  object-fit: none;
  object-position: 0 0;

  &:active {
    object-position: 0 100%;
  }
}
```

## サポート状況

http://caniuse.com/#feat=object-fit

![image](https://qiita-image-store.s3.amazonaws.com/0/1172/9b25473a-d70c-776e-533e-711e73d1a6c5.png)
Resource annotationsによる検証

Androidの引数にリソースアノテーションを付けることで、リソースに存在するかが検証できる。


```java:before
    private void handleColorChange(int stringResId, int colorResId) {
        int prefColor = pref.getInt(getString(stringResId), 0);

        ...
    }
```

```java:after
    private void handleColorChange(@StringRes int stringResId, @ColorRes int colorResId) {
        int prefColor = pref.getInt(getString(stringResId), 0);

        ...
    }
```

AndroidStudioだと以下のように教えてくれる。

誤
<img width="433" alt="スクリーンショット 2017-03-14 21.03.28.png" src="https://qiita-image-store.s3.amazonaws.com/0/15319/a613132f-df4e-d5cd-b8cc-45db9bf1a931.png">

正
<img width="518" alt="スクリーンショット 2017-03-14 21.03.49.png" src="https://qiita-image-store.s3.amazonaws.com/0/15319/b6813d2b-0c1e-99cf-00b4-35996fa47e58.png">


## 参考
[Improve Code Inspection with Annotations | Android Studio](https://developer.android.com/studio/write/annotations.html#res-annotations)
pythonでオブジェクトのクラスを調べる

rubyで言うところの.classメソッドみたいなのが欲しい。

```ruby
'Ruby'.class
# => String
```

なんらかのインスタンスがどのクラスから作られたものなのか確認したい。

```python
'Python'.__class__.__name__
# => str
```

`__class__`を使えばクラスが取得できる。さらに`__class__.__name__`を使うとクラス名が取得できる。
processingで動画を書き出す

#概要
評価用にちょっとした動画を作りたい場合に、Processingが簡単にいろいろなことができて便利です。しかし、動画の書き出しは直接はできないようです。

#手順
Movieクラスは存在しますが、ファイル読み込みやカメラキャプチャしかできないようです。
動画ファイルを保存するには、まずコマごとに静止画を書き出して、付属ツールで動画に変換します。
まずは、静止画を各コマごとに以下のように書き出します。


```
void draw(){

    /* 描画処理  */
    saveFrame("frames/######.tif");
}
```

最後はTIFで出力していますが、非圧縮なのでPNGでもよいです。
実行させると指定のフォルダに静止画がたくさんできているはずです。
exitを記述しないと、draw()がずっと呼ばれるので際限なくファイルができてしまいます。。


#動画へ変換
メニューの[Tools]->[MovieMaker]を選びます。
適宜フレームレートを設定してあげればOKです。
has_many through のアソシエーションに条件を追加する

# 例

## 前提

[単一テーブル継承](http://api.rubyonrails.org/classes/ActiveRecord/Inheritance.html) を利用した Character モデルが存在する。

```app/models/character.rb
class Character < ApplicationRecord; end
```

```app/models/female_character.rb
class FemaleCharacter < Character; end
```

```app/models/male_character.rb
class MaleCharacter < Character; end
```

Character モデルは AnimeCharacter モデルを通じて Anime モデルと多対多のアソシエーションを持っている。

```app/models/character.rb
class Character < ApplicationRecord
  has_many :anime_characters
end
```

```app/models/anime_character.rb
class AnimeCharacter < ApplicationRecord
  belongs_to :anime
  belongs_to :character
end
```

```app/models/anime.rb
class Anime < ApplicationRecord
  has_many :anime_characters
  has_many :characters, through: :anime_characters
end
```

```rb
anime = Anime.find_by(title: '偽物語')
anime.characters.pluck(:type, :name)
#=> [["MaleCharacter", "阿良々木 暦"], ["FemaleCharacter", "阿良々木 火憐"], ["FemaleCharacter", "阿良々木 月火"]]
```

ここで、Anime モデルの `characters` アソシエーションに条件を追加し、男性キャラクター (MaleCharacter) あるいは女性キャラクター (FemaleCharacter) のみに絞り込みたい。

## 方法

```app/models/anime.rb
class Anime < ApplicationRecord
  has_many :anime_characters
  has_many :characters, through: :anime_characters
  has_many :male_characters, -> { where(type: MaleCharacter.to_s) },
           through: :anime_characters, source: :character
  has_many :female_characters, -> { where(type: FemaleCharacter.to_s) },
           through: :anime_characters, source: :character
end
```

```rb
anime = Anime.find_by(title: '偽物語')
anime.female_characters.pluck(:type, :name)
#=> [["FemaleCharacter", "阿良々木 火憐"], ["FemaleCharacter", "阿良々木 月火"]]
```
GMO社が被害を受けたStruts 2（CVE-2017-5638）問題で我々は何を学ぶべきか？

GMOペイメントゲートウェイ社（以下GMOPG）という、クレジット決済代行を取り扱う、
国内最大手の会社がクレジットカード番号を流出させたとして、
3/10以降大きく報道されました。

この事故から、我々エンジニアが学ぶべき事は何でしょうか？

# 発生した事象について
## CVE-2017-5638とはなにか
ファイルアップロードにおけるマルチーパートヘッダーの解釈部分に脆弱性があり、
リモートコード実行（RCE）が可能な状態であったらしい
本投稿の趣旨から外れるので、詳しくは調べていません。

## 経緯・経過

- 3/6 脆弱性情報が公開されたらしい (Cf. [Apache Struts 2における脆弱性 (S2-045、CVE-2017-5638)の被害拡大について](https://www.lac.co.jp/lacwatch/alert/20170310_001246.html) )
- 3/8 IPAが情報を掲載 (Cf. [Apache Struts2 の脆弱性対策について(CVE-2017-5638)(S2-045)](https://www.ipa.go.jp/security/ciadr/vul/20170308-struts.html) )
- 3/9 JVNが情報を掲載 (Cf. [JVNVU#93610402 Apache Struts2 に任意のコードが実行可能な脆弱性 緊急](https://jvn.jp/vu/JVNVU93610402/))
- 3/9 GMOPGが調査を開始、同日中に攻撃の可能性を検知し、サイト停止 (Cf. [不正アクセスに関するご報告と情報流出のお詫び](https://corp.gmo-pg.com/news_em/20170310.html?_ga=1.78913564.986315985.1489366916#em00) )
- 3/10 GMOPGが適時開示 (Cf. [不正アクセスに関するご報告と情報流出のお詫び](https://corp.gmo-pg.com/newsroom/pdf/170310_gmo_pg_ir-kaiji.pdf) )

## 影響
Struts はこれまで何度もリモートコード実行（RCE）脆弱性が見つかっているが、
GMOPGという、決済代行最大手が被害にあったとして、大々的に報じられる事となりました。
※GMOPGがSIしたサイトでの被害であり、
　GMOPGのメインビジネスの部分が突破されたわけではないようです。

# どうすれば、回避または、被害を軽減できたか
①Lacの報告によれば、この~~ゼロデイ~~攻撃は、脆弱性情報が公開された直後は、
　攻撃試行も成功も少なかったようである。
※徳丸先生から、「[ゼロデイではない](https://twitter.com/ockeghem/status/843745544921014273)」とご指摘を受けました。
よくよくかんがえたら確かにゼロデイではなかったので訂正します。
　![20170310_01.png](https://qiita-image-store.s3.amazonaws.com/0/138414/7f2044d5-942e-1362-4a7d-34cfa0e4bc2c.png)
（引用元：[Apache Struts 2における脆弱性 (S2-045、CVE-2017-5638)の被害拡大について](https://www.lac.co.jp/lacwatch/alert/20170310_001246.html)）

GMOPGは3/10 18:00から調査を開始して、6時間後にはサイト停止の判断をできているので、
3/7から調査を開始できていれば、このような重大インシデントに繋がっていなかった可能性があります。

②Strutsは、JVNによればリモートコード実行脆弱性（RCE)だけで、過去何度も発生させています。
![SnapCrab_NoName_2017-03-14_19-29-29_No-00.png](https://qiita-image-store.s3.amazonaws.com/0/138414/1d0356df-4130-eb6c-58bf-3f15ae26f32a.png)
(引用元：[JVN iPedia - 脆弱性対策情報データベース](http://jvndb.jvn.jp/search/index.php?mode=_vulnerability_search_IA_VulnSearch))

何度も繰り返し繰り返し同じような脆弱性をだすということは、
・Strutsの開発体制が貧弱か、
・Strutsの設計思想自体がこの脆弱性を排除できないか、
・もしくはその両方
つまり、とても商用で使えないフレームワークであるとも言えます。
※ScutumというWAFの会社は2014年時点でStrutsを「控えめに言ってもどうしようもない」と形容しています。
(Cf. [例えば、Strutsを避ける - WAF Tech Blog ｜ クラウド型 WAFサービス Scutum](https://www.scutum.jp/information/waf_tech_blog/2014/04/waf-blog-036.html))

後知恵かもしれませんが、Strutsを利用するという判断自体が間違いだったかもしれません。

# 我々はエンジニアは、ここから何を学ぶべきか
この常に悪意に晒されるWEB開発世紀末ヒャッハーな世界で、
善良なる小市民である我々はどう自分たちを守るべきでしょうか？

今回の事件から我々が得られる教訓は以下の2点です。

1. 脆弱性情報が公開されたらマッハで対策を打てるようにする
	1. 自社または自分が保守している公開システムで利用しているサードパーティ製のミドルウェア、ライブラリ、フレームワークをすべて把握しておく
	2. 利用しているサードパーティソフトの脆弱性情報を毎日収集する <br>
※[MyJVN](http://jvndb.jvn.jp/apis/myjvn/)はAPIを公開していますので、非常に自動化しやすいと思います。<br>
※Lac社やIPAは、注意喚起情報のRSSを公開しています。<br>
Lac：https://www.lac.co.jp/lacwatch/feed.xml<br>
IPA：https://www.ipa.go.jp/security/rss/info.rdf<br>

2. サードパーティ製品を新たに採用するときは、JVNで過去の脆弱性検出状況を確認する<br>特に似たような問題を数回起こしているような製品は採用を避ける

# 最後に
私は仕事柄、GMOPGの担当者と年数回お会いしていますが、
非常に誠実で信頼できる会社だと思っています。

今回の件で評判を大きく落としてしまいましたが、
コアであるオペーレション能力が大きく毀損したわけではありません。

今回の危機を乗り越えてより優れた会社となることを祈ってやみません。
インスタンスタイプ毎に稼働中のインスタンスとRI数を出力するスクリプト


```
#! /bin/bash
aws ec2 describe-instances --filters "Name=instance-state-name,Values=running" --query "Reservations[].Instances[?InstanceLifecycle!=\`spot\`].[InstanceId,InstanceType]" --output text|awk -F "\t" '{a[$3$2]+=1}END{ for (i in a) print i,"\t", a[i],"\t"}'|sort > running_noaz.txt

aws ec2 describe-reserved-instances --filters "Name=state,Values=active" "Name=instance-type,Values=*" --query "ReservedInstances[].[InstanceType,InstanceCount]" --output text|awk -F "\t" '{a[$1]+=$2}END{ for (i in a) print i,"\t\t",a[i]}'|sort > reserved_noaz.txt

echo "[InstanceType] [Running] [Reserved]"

awk -F "\t" '{a[$1]+=$2;b[$1]+=$3}END{ for (i in a) print i,"\t",a[i],"\t",b[i]}' running_noaz.txt reserved_noaz.txt|sort
```
Docker Remote API 呼び出しのログ

PhpStorm の Docker Remote Interpreters を試してたとき、PhpStorm からどのように API が呼ばれているかを見たかったのですが、ぱっとみ API 呼び出しはログされていなさそうでした。

環境は下記のとおり。

- CentOS 7.3.1611
- Docker Engine 17.03.0-ce

systemd の drop-in で下記のように `--log-level=debug` を追加すると、

```
[Service]
ExecStart=
ExecStart=/usr/bin/dockerd \
    -H unix:///var/run/docker.sock \
    -H tcp://0.0.0.0:2376 \
    --tlsverify \
    --tlscacert=/path/to/ca.pem \
    --tlscert=/path/to/server.pem \
    --tlskey=/path/to/server-key.pem \
    --log-level=debug
```

`journalctl -u docker.service` で API 呼び出しも出てくるようになりました。

```
Mar 14 14:02:02 xxx dockerd[7596]: time="2017-03-14T14:02:02.127110132+09:00" level=debug msg="Calling POST /cont    825 ainers/create"
Mar 14 14:02:02 xxx dockerd[7596]: time="2017-03-14T14:02:02.127110132+09:00" level=debug msg="form data: {\"AttachStdin\":true,...
```

ただ、その他にも凄まじい量のログが吐かれたので常用は辛そうでした。
Linuxで基本的なファイル操作をするために必要なコマンドのまとめ

<table>
<tr><th>コマンド名</th><th>処理内容</th></tr>
<tr><td>pwd</td><td>カレントディレクトリを表示する</td></tr>
<tr><td>cd</td><td>カレントディレクトリを変更する</td></tr>
<tr><td>ls</td><td>ディレクトリ内のファイルを表示する</td></tr>
<tr><td>mkdir</td><td>ディレクトリを作成する</td></tr>
<tr><td>touch</td><td>ファイルを作成する</td></tr>
<tr><td>rm　[-r]</td><td>ファイルを削除する（-rオプションで、ディレクトリを削除する）</td></tr>
<tr><td>rmdir</td><td>空のディレクトリを削除する</td></tr>
<tr><td>cat</td><td>ファイルの内容を表示する</td></tr>
<tr><td>less</td><td>ファイルの内容をスクロール表示する</td></tr>
<tr><td>cp　[-r]</td><td>ファイルをコピーする（-rオプションで、ディレクトリをコピーする）</td></tr>
<tr><td>mv</td><td>ファイル・ディレクトリを移動する</td></tr>
<tr><td>ln　[-s]</td><td>ハードリンクを作成する（-sオプションで、シンボリックリンクを作成する）</td></tr>
</table>
ConoHaでDBネットワークを使う

# ConoHaでDBインスタンスを使う

ConoHaのDBアプリケーションインスタンスについて
確実にポートや文字コードは変えられない。 個人的にお気に入りのlowercaseも使えない。
クエリキャッシュもない。さらにtime_zoneがSYSTEM設定となるが、
SET Grobal コマンドも使えないという条件がある。



## DBインスタンスを作る。
MariaDB10系が生成され、へたにチューニングするより遥かにいい状態で生成される

![ConoHaコントロールパネル.png](https://qiita-image-store.s3.amazonaws.com/0/1088/6c4c581e-91be-65d6-0963-be2c29b33aba.png)

## 次にdatabaseを作成する
![ConoHaコントロールパネル.png](https://qiita-image-store.s3.amazonaws.com/0/1088/1f3a9111-202b-f48f-8122-99563682ffbb.png)
DBのアドレスは外部アクセス可能のものと、プライベートNW経由用の2つがある。
外部からの許可をするならpublicのものを使うことになる。
public.piquo.tyo1.database-hosting.conoha.io
private.piquo.tyo1.database-hosting.conoha.io	



## 次にDB用ユーザを作る
![ConoHaコントロールパネル.png](https://qiita-image-store.s3.amazonaws.com/0/1088/66a5cb51-e7e4-5c6a-b5a4-527b82003211.png)

指定サーバのIPアドレスからしか受け付けないユーザを作っている。
もし、ユーザ作成時の「アクセス元制限」に%をいれていたら、
この時点からpublicアドレスからのアクセスが可能になるため、
ーバは稼働を開始しているので、以下コマンドが利用可能になった状態

```
mysql -h public......io -u xxxx -p xxxxx 
```




# privateNWでアクセスするための設定を行う


## VPSにDB用 NWを追加する。
ConoHaで作成しているVPSはそのままではこのアドレスにアクセスすることができない。
さらにRouteも自分で追加しなければならない。
![ConoHaコントロールパネル.png](https://qiita-image-store.s3.amazonaws.com/0/1088/0f7bba78-319f-485b-ba50-e9306ed5e137.png)


## DBNW用のIPを確認する
![ConoHaコントロールパネル.png](https://qiita-image-store.s3.amazonaws.com/0/1088/54fbcd76-6dfb-b666-2d24-f3c218618ff8.png)

## 確認したDBNW用のIPをサーバに設定する
nmcli connection modify eth2 ipv4.method manual ipv4.addresses "172.xxx.xxx.xxx"

## routeを追加する

ip route add 172.21.140.0/23 via 172.21.140.1 dev eth2

マスクなどの情報が不明の場合はここで計算すると楽。
https://note.cman.jp/network/subnetmask.cgi

## DBにアクセスする
![1__root_koninTodokeHttpServer02____ssh__と_メモ.png](https://qiita-image-store.s3.amazonaws.com/0/1088/afea850c-840b-35f8-187f-a7990ac3b921.png)



## 利用開始に際して
コンフィグにアクセスできず、set grobalコマンドも使えないため、
プログラムの中でset session time_zone='+9:00'を行うように改良する必要があった。
WindowsでOracle用の複数SQLファイルを実行

# WindowsでOracle用の複数SQLファイルを実行

## 環境

- 接続: **ORAUSR/ORAPAS** (ここを書き換える)
- `main.bat` と `sql_caller.sql` の2ファイルを作成し同じディレクトリに配置する
- 呼出SQLファイルはサブディレクトリ `call_sql` に配置

## ファイル構成

```
call-sql
  |- main.bat
  |- sql_caller.sql
  \- call_sql\
       |- CREATE_TABLE.sql
       \- INSERT_DATA.sql
```

起動用

```bat:main.bat

@ECHO OFF
REM ============================
REM SQLファイル実行
REM ============================

ECHO SQL処理開始
sqlplus /nolog @sql_caller.sql
```

SQLファイルの登録用リスト

```sql:sql_caller.sql
-- 接続開始
connect ORAUSR/ORAPAS

-- 呼出SQLファイルの登録
@call_sql\CREATE_TABLE.sql
@call_sql\INSERT_DATA.sql

-- 接続終了
exit
```

## DB接続情報を別ファイルにして読み込み変数へセット

IDファイルを準備

```txt:DB.ID
userID@DBName/password
```

DB接続情報を読み込み

```bat:sample.bat
REM 接続ファイル定義名
SET CONN_FILE=DB.ID
REM -------------------------------------------
FOR /F %%C IN (%CONN_FILE%) DO SET CONNECT=%%C
ECHO %CONNECT%
```
OCNさんのOP25B対策への対策

自宅サーバから外部にメールを送信する際、公式の下記ページを参考にしてドハマりしたので共有。
https://support.ntt.com/ocn/support/pid2990023156

## 方針
- テスト用なので暗号化できてなくてもよい。(Gmailで「このメールは ocn.ad.jp で暗号化されませんでした」のような表示が出る)
- メールサーバの設定を極力減らしたい。

## 結論
- SMTPサーバはsmtp.ocn.ne.jpではなく、smtp.vcseagreen.ocn.ne.jp(※人によって違う。後述)を使う。
- ポート番号は465番ではなく(587番でもなく)25番を使う。
- SSL/TLSもパスワード認証も使わない。

## 経緯
私「OCNさんのsmtpを叩くときも25番は叩けないのですか」
OCNテクニカルサポート(以下:OCNさん)「叩けます」
私「なぬ!? (さっき試したけどできなかったよ…)」
OCNさん「ただしホスト名がvcから始まるものに変わります」
OCNさん「お客様の場合メールアドレスの@より右側がseagreen.ocn.ne.jpですのでsmtp.vcseagreen.ocn.ne.jpになります」
私「(sudo dpkg-reconfigure exim4-configする) あ。通りました」

## 補足
- OCNから提供されるメールアドレスのドメインはcomet.ocn.ne.jp、hyper.ocn.ne.jpなど数10種類あるらしい。
- 一般的に案内されるsmtp.ocn.ne.jpのほうが新しいSMTPサーバだが、SSL/TLSなし・認証なしのニーズもあるのでsmtp.vc○○.ocn.ne.jpも今のところ廃止の予定はないらしい。
- テクニカルサポートで話が通じなかったときは(お互いのために)よりテクニカルな方に変わってもらいましょう。