OmniAICreator/Qiita-1.07M huggingface dataset:
特定のプロパティをバインドしているコントロールを取得する

WinFormsのデータバインディングでモデルから対象となるコントロールを取得したい的なケースで使える拡張メソッド。

このままだと毎回`GetAllControls()`が実行されるのでキャッシュするなりしよう。

```csharp

    internal static class ControlExtender {
        /// <summary>
        /// self内のすべてのコントロールを取得する
        /// </summary>
        /// <param name="self"></param>
        /// <returns></returns>
        public static List<Control> GetAllControls(this Control self) {
            List<Control> buf = new List<Control>();
            self.Controls.OfType<Control>().ToList().ForEach(c => { buf.Add(c); buf.AddRange(c.GetAllControls()); });
            return buf;
        }
        /// <summary>
        /// self内でBindingObject.PropertyNameをバインドしているコントロールを1つ取得する
        /// </summary>
        /// <param name="self"></param>
        /// <param name="BindingObject"></param>
        /// <param name="PropertyName"></param>
        /// <returns></returns>
        public static Control ControlOf(this Control self, object BindingObject, string PropertyName) {
            return self.GetAllControls().FirstOrDefault(c => c.DataBindings.OfType<Binding>().Any(b => b.BindingManagerBase.Current == BindingObject && b.BindingMemberInfo.BindingField == PropertyName));
        }
        /// <summary>
        /// self内でBindingObject.PropertyNameをバインドしているコントロールをすべて取得する
        /// </summary>
        /// <param name="self"></param>
        /// <param name="BindingObject"></param>
        /// <param name="PropertyName"></param>
        /// <returns></returns>
        public static IEnumerable<Control> ControlsOf(this Control self, object BindingObject, string PropertyName) {
            return self.GetAllControls().Where(c => c.DataBindings.OfType<Binding>().Any(b => b.BindingManagerBase.Current == BindingObject && b.BindingMemberInfo.BindingField == PropertyName));
        }
    }
```

[ValidationResult クラス \(System\.ComponentModel\.DataAnnotations\)](https://msdn.microsoft.com/ja-jp/library/system.componentmodel.dataannotations.validationresult(v=vs.110).aspx) あたりと組み合わせて使う。
[Ubuntu 18.04標準機能] gnome-shellの拡張機能を自作してみる (その3)

- [その1](https://qiita.com/Kogia_sima/items/cde2b550085e202a40a5)
- [その2](https://qiita.com/Kogia_sima/items/52ec628de987dd548a64)
- [その3](https://qiita.com/Kogia_sima/items/279c17d79656cbb7460d)

さて、今回は自作した拡張機能を実際にオンライン上で公開してみます。

:warning:先に注意しておきますが、前回の記事で作ったものをそのまま投稿しないでください。同じものを既に私が投稿していますので、機能が重複してしまいます。

# 準備

ファイルをアップロードする前に、いくつかやることがあります。

- [gnome-shellの拡張機能一覧のページ](https://extensions.gnome.org/)に行って、アカウント登録。

ちなみにメールアドレス一つあればすぐに登録できます。

- zipファイルにまとめる

拡張機能で編集したファイルと、metadata.jsonをまとめてzipファイルに圧縮します。今回はextension.jsしか編集していませんので、以下のコマンドでokです。

```console
$ zip -j extension.zip extension.js metadata.json
```

- スクリーンショットを取る(オプション)

どのような拡張機能であるかを明示するために、拡張機能のスクリーンショットを撮っておくと良いでしょう。

# 投稿

[拡張機能一覧](https://extensions.gnome.org/)のページで、上にある「Add yours」ボタンをクリックします。すると、以下のようなページが現れます。

![Screenshot from 2018-05-29 22-50-40.png](https://qiita-image-store.s3.amazonaws.com/0/171615/115efd47-bc19-ab3b-ff2a-8a87f01a47b9.png)

先程作成したzipファイルをアップロードし、規約をよく読んでからアップロードしましょう。

# アップロード後にやる設定

![Screenshot from 2018-05-29 22-53-45.png](https://qiita-image-store.s3.amazonaws.com/0/171615/9557b955-fec5-29ce-6d09-7c408c49dc4f.png)

アップロードが完了したら、拡張機能の説明などを書き加えます。

Upload screenshotボタンでスクリーンショットをアップロードし、さらに左上のアイコン(タイトルの左側)をクリックして、拡張機能のアイコンも変更しましょう。

この状態で、しばらくすると拡張機能が認可され、検索結果一覧にも表示されるようになります。

このチェックの頻度は結構少なく、投稿から認可までに時間がかかったりするので、辛抱強く待ちましょう。


# TO BE CONTINUED ?

この他にも、気象庁のHPから天気予報や現在の天候などを取得して表示するプログラムを作ろうかなーと検討しています。

OpenWeatherという拡張機能だと、予報がコロコロ変わったり、気象庁と全然違う予報を出したりするので、もうちょっと頼れるものにするために気象庁から直接スクレイピングしたいと思っています。
ですが研究生活で忙しいのであまり手が出せない状態です。なので今のところは未定です。

# 参考資料

- [第492回　GNOME Shellの拡張機能を作ってみよう](http://gihyo.jp/admin/serial/01/ubuntu-recipe/0492)
- [GNOME Shell Extension を調べてみた](https://fut-nis.hatenadiary.jp/entry/20120626/1340716798)
- [Step by step tutorial to create extensions](https://wiki.gnome.org/Projects/GnomeShell/Extensions/StepByStepTutorial)
- [How I developed my first gnome-shell extension](https://www.abidibo.net/blog/2016/03/02/how-i-developed-my-first-gnome-shell-extension/)
- [Gnome shell: my first extension](http://smasue.github.io/gnome-shell-tw)
- [GLib 2.0 API Documents](https://people.gnome.org/~gcampagna/docs/GLib-2.0/index.html)
- [Gio 2.0 API Documents](https://people.gnome.org/~gcampagna/docs/Gio-2.0/index.html)
CentOSのバージョンを調べるコマンド

CentOSのバージョンを調べるコマンドは何か
## これ
```
$ cat /etc/redhat-release
```
以下のようなものが表示されるはず

```
CentOS release 6.9(Final)
```
## 参考
http://mawatari.jp/archives/check-centos-version
SalesforceをIDプロバイダとして、外部アプリケーションとSAML認証する

# 概要

SalesforceのユーザでSAML認証して、外部アプリケーションにログインする方法をメモとして残したいと思います
構成はIDプロバイダをSalesforce、サービスプロバイダをログイン対象のWebアプリケーション

# 1. ID プロバイダとしての有効化(Salesforce)

https://help.salesforce.com/articleView?id=identity_provider_enable.htm&type=5

1. 私のドメインを設定
![sfdc_my_domain.png](https://qiita-image-store.s3.amazonaws.com/0/30522/dab5cf29-f7ae-79c7-e679-b133f29408be.png)

2. IDプロバイダの有効化
![sfdc_id_provider_on.png](https://qiita-image-store.s3.amazonaws.com/0/30522/5430d37a-0c55-de6d-1b24-34305e774e22.png)

3. IDプロバイダで使用する証明書の作成もしくは選択
![sfdc_id_provider_makekey.png](https://qiita-image-store.s3.amazonaws.com/0/30522/dc68b4b0-e941-7f76-649a-821a71627565.png)

4. IDプロバイダの設定完了後は「証明書」と「メタデータ」をそれぞれダウンロード
    後述のサービスプロバイダで使用します
![sfdc_id_provider_completed.png](https://qiita-image-store.s3.amazonaws.com/0/30522/e0758938-901e-1ac4-0581-166ddab87cd3.png)

# 2. サービスプロバイダの設定(外部アプリケーション)

以下では外部アプリケーションでの設定になります
設定の詳細は各アプリケーションの手順に従ってください

1. IDプロバイダのログインURL
    前述でダウンロードしたメタデータの **SingleSignOnService**のLocationプロパティを使用します
   （HTTP-POST、HTTP-Redirect形式かはアプリケーションに応じて選択してください）

    ```xml:SAML.xml

    ~ 省略 ~
      <md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://hogehoge.my.salesforce.com/services/auth/idp/saml2/logout"/>
      <md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://hogehoge.my.salesforce.com/services/auth/idp/saml2/logout"/>
      <md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified</md:NameIDFormat>
      <md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://hogehoge.my.salesforce.com/idp/endpoint/HttpPost"/>
      <md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://hogehoge.my.salesforce.com/idp/endpoint/HttpRedirect"/>
   </md:IDPSSODescriptor>
</md:EntityDescriptor>
    ```
2. IDプロバイダのログアウトURL
    前述でダウンロードしたメタデータの **SingleLogoutService**のLocationプロパティを使用します
3. 証明書のインポート
    前述でダウンロードしたSalesforceの証明書をインポート
4. サービスプロバイダのentityIDとAssertionConsumerService（ACS）の取得

# 3. 新規接続アプリケーションの作成(Salesforce)

1. 新規接続アプリケーションの作成  
    エンティティIDとACS URLはサービスプロバイダで取得した値を入力  
件名種別ではSalesforceログイン成功後にログインしたユーザのどの（カスタム）項目を外部アプリケーションに引き渡すのかを選択  
名前ID形式やIdP証明書はダウンロードしたメタデータに合わせて選択してください
![sfdc_new_application.png](https://qiita-image-store.s3.amazonaws.com/0/30522/fccc49d6-cc6d-8a50-278c-b636aa41a426.png)


2. プロファイルもしくは権限セットの付与
![sfdc_application_profile.png](https://qiita-image-store.s3.amazonaws.com/0/30522/ae9dbfa1-6dbd-3920-5ae7-097f7487786b.png)

# トラブルシューティング

## 認証がうまくいかない場合

Salesforceの「ID プロバイダイベントログ」に認証ログが残りますので、Salesforceでの認証で問題の有無を確認できます
[Python3] 環境変数の追加と呼び出し

最近twitterAPIを利用したプログラムを書いてみました．その時に参考にしたプログラムでは，キーをベタ打ちしていたのですが，どうやらセキュリティの観点からはキーを環境変数にいれ，よびだすほうが良いみたいです．たしかに，うっかりキーの書いてあるソースコードをgithubなどに上げてしまった時は面倒なことになります．

# 環境変数の追加
Ubuntuであればbashrcに下記のように追記すればよいです．研究室の計算機はなぜかtcshを使用しているので，ついでに書いておきます．

```shell:bashrc
export KEY=***********
```

```shell:tcshrc
setenv KEY *********** 
```
# Pythonでよびだす
Pythonで環境変数を呼び出すにはosモジュールを使用します．

```python:Python3
import os

print(os.environ.get('KEY'))
```

これで環境変数KEYが呼び出せました．

# 参考
[環境変数の取得 (environ) | Python-izm](https://www.python-izm.com/advanced/environment/)
[シェルの基本操作法（後編３：シェル変数と環境変数）](http://tech.nikkeibp.co.jp/it/article/COLUMN/20060620/241337/)
AIアプリへの道:Python基礎(1)

Aidemy Python基礎

#今日学んだことのまとめ
##所感
JavaとHtml/CSSの基礎は学んだことがあったため
書き方や仕組みにいちいち戸惑うことはなく進めることができた。
表記が特異なものやjavaと比べて簡略化されていることもあるのでその辺は記憶よりも違いを理解することを重視して進めた。

##今日一番の驚き
リスト表記についてが一番自分にとって新しく感じた。
リスト名=[a,b,c]まではいいが、そのあとの要素の削除や入れ替えのやり方が新しかった。
- 削除は、```del リスト名[インデックス番号]```
- 入れ替えは、```リスト名[インデックス番号]=要素```
- 異なるリストに写す場合は、新リスト名=リスト名でOK
- ただし、新リスト名の要素に変更を加えたい場合に
その変更が元のリストにも影響してしまうことを避けるために
```新リスト名=リスト名[:]```として写せばOK.

##他の気づき
###if文
if文は
```if(条件式):
 （インデント）print(実行文)```
else ifは if文と同じインデント位置で```elif（条件式）```と書く。
###and or not
javaでは　and は &&、orは||と表記したが　pythonでは文字で表記できる。
また　```1<=A<=5```　などと繋げて書くことも可能。

おわり！
[Xcode] PrivateFrameworksのframeworkがエラーはないのに動かなくてハマった件

#件の詳細
macOSアプリの開発でトラックパッドの静電容量値が欲しくなったので`MultitouchSupport.framework`を導入したのですが、何一つコンパイルエラーも警告も出ていないにも関わらず、メソッドが発動されないという現象に陥りました。使ったFramework特有の問題かと思い調査してみましたが、前例や解決策は見つかりませんでした。

#原因・解決策
原因は、macOSアプリの開発上システムに関係するようなところをいじろうとする際必ず立ちはだかるやつ「Sandbox」でした。`.entitlements`ファイルを以下のように変更し、Sandboxをキャンセルしたら動くようになりました。

<img width="422" alt="Sandbox.png" src="https://qiita-image-store.s3.amazonaws.com/0/67153/43e8c353-7bcc-538e-6252-e6885ecd894a.png">

Sandboxをキャンセルするとリリースすることはできませんが、今回のアプリは研究用だったため動くことを優先しました。
React-transition-groupをCSS in JSのaphroditeで使う

# 要素のfadein-outでトランジションをしたい
Reactでアプリケーションを作っている中で、モーダル的な要素を扱うのにfadein、fadeoutをしたくなりました。
現在のプロジェクトではCSS in JSとして[aphrodite](https://github.com/Khan/aphrodite)を使っています。
いろいろ試行錯誤した結果、react-transition-groupで期待する動作を作れたので知見として公開したいと思います。


```jsx
// モーダルにする予定のコンポーネント

import React from "react";
import { css, StyleSheet } from "aphrodite";
import { CSSTransition } from "react-transition-group";

const modal = ({ isShow }) => {
  const styles = StyleSheet.create({
    wrap: {
      background: "red",
      width: 200,
      height: 200
    },
    enter: {
      opacity: 0,
      transition: "all 3s"
    },
    enterActive: {
      opacity: 1
    },
    exit: {
      opacity: 1,
      transition: "all 3s"
    },
    exitActive: {
      opacity: 0
    }
  });

  return (
    <CSSTransition
      in={isShow}
      mountOnEnter
      unmountOnExit
      classNames={{
        enter: css(styles.enter),
        enterActive: css(styles.enterActive),
        exit: css(styles.exit),
        exitActive: css(styles.exitActive)
      }}
    >
      <div className={css(styles.wrap)}>modal</div>
    </CSSTransition>
  );
};

export default modal;
```
[![Edit react-transition-group with aphrodite css in js](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/84wz203n0j)


## CSSTransitionGroupコンポーネントにclassNamesでaphroditeのスタイルを渡してあげる
ここが一番のポイントだと思います。
`enter: css(styles.enter)`とすることで、enter時のaphroditeスタイルを渡すことができます。
ちなみにReact-transition-groupのversion1系では`className`ではなく`transitionName`です。

あとはドキュメントを読みつつなんとかなりました。

## あとがき
CSS in JS使いながらReactでトランジッションの実装をどうするのか、やっと理解することができました。
最近はstyled componentsが流行っていますね。そちらではどうやるのか、若干興味があります。
とにかく、これで自由にAphroditeでtransitionを使いこなすことができそうなので、活用していきたい所存です
AlibabaCloudのロードバランサーを動かしてみる

# はじめに
AlibabaCloudのロードバランサーを動かしてみます。

# 準備

[AlibabaCloudのECSを東京リージョンの最安値で起動してみる！(ROS版)](https://qiita.com/wa-ta-ru/items/9af5027860c730c328b5)

を使って起動しておき、VPCとECSが動いてる状態です。

# ロードバランサーを作成します。

## コンソールでロードバランサーを開きます。

![217d793c.png](https://qiita-image-store.s3.amazonaws.com/0/241104/44d81cc9-2c30-dfbb-7351-7953ff593de2.png)

## ロードバランサーを有効化します。
インスタンスは
**インターネット**
にしてください。

![ae525d09.png](https://qiita-image-store.s3.amazonaws.com/0/241104/7e4f5039-0fdd-8a71-e01a-e41dd815301d.png)

## できあがり

![ff363139.png](https://qiita-image-store.s3.amazonaws.com/0/241104/f74ccddb-31cc-30de-86cd-b830ef5eb5c5.png)

これだけだと

- インターネットからアクセスできるロードバランサー
- VPC上で稼働しているECS

ができている状態になります。これから２つをつなげていきます。
バックエンドサーバが _VPC上で稼働しているECS_ となります。

# ロードバランサーとECSをつなげます

## サーバグループを作成

![2a403cde.png](https://qiita-image-store.s3.amazonaws.com/0/241104/2b817629-cb68-94eb-9bca-72c1e0f1a6f3.png)

![bdf13807.png](https://qiita-image-store.s3.amazonaws.com/0/241104/4ce3b8d9-698a-74e5-a68f-aab8f5075601.png)

![2f9274a6.png](https://qiita-image-store.s3.amazonaws.com/0/241104/5cde240a-6e0b-1021-209e-0dcaf06d74e5.png)

## リスナーの作成

![3044110d.png](https://qiita-image-store.s3.amazonaws.com/0/241104/801bb521-24cb-6a15-7169-0e89c958f35d.png)

![15468ae3.png](https://qiita-image-store.s3.amazonaws.com/0/241104/36428c54-dd1f-989c-2082-98b8278423b4.png)

![6e286858.png](https://qiita-image-store.s3.amazonaws.com/0/241104/26120df9-abb5-3902-0051-ba24f31004ac.png)

![e74f9b76.png](https://qiita-image-store.s3.amazonaws.com/0/241104/dd10223b-74b3-2010-54b5-cf5175f5d8ec.png)

![9b38b0cf.png](https://qiita-image-store.s3.amazonaws.com/0/241104/f1f013e5-2e19-164a-c8ca-e7849140090d.png)

# 仕上げ
ちょっと面倒ですが
ロードバランサーとサーバがつながってますが
80ポートのヘルスチェックに落ちてます。
ECSに入って、nginxかhttpdを起動します。

```shell
[root@poc ~]# yum -y install nginx
[root@poc ~]# /bin/systemctl start nginx.service
```

# さいごに

ロードバランサーのIPアドレスをブラウザで開くと

![aa3c9951.png](https://qiita-image-store.s3.amazonaws.com/0/241104/92cecd77-af50-d1ec-14d3-8586bec9e870.png)

このようにアクセスができるようになります。
AlibabaCloudのロードバランサーを知ろう

# はじめに
さて、今回はAlibabaCloudのロードバランサーを学んでみます。

# ドキュメントはこちら

[プロダクトの概要 - プロダクト紹介| Alibaba Cloud ドキュメントセンター](https://jp.alibabacloud.com/help/doc-detail/27539.htm?spm=a21mg.l28256.a3.2.16da5369EN8YXx)

クラウドのロードバランサーなので様々なIaaSと大体が同じになります。
そこを説明していくとドキュメントを読んでくださいとなるので、
少し一般的な説明は省略し、見て欲しいポイントを説明してまいります。

# 基本として覚えるコンポーネントは３つです

- ロードバランサ
- リスナー
- バックエンドサーバー

コンポーネントで構成されるドキュメントの図のようになります。
バックエンドサーバは、ECSですね。

![](http://docs-aliyun.cn-hangzhou.oss.aliyun-inc.com/assets/pic/27539/jp_ja/1498615951085/SLB.png)

[プロダクト用語 - プロダクト紹介| Alibaba Cloud ドキュメントセンター](https://jp.alibabacloud.com/help/doc-detail/27540.htm?spm=a21mg.p38356.b99.7.701f31c7qoYHVp)
と合わせてみるとよいです。

# アーキテクチャ

[アーキテクチャ - プロダクト紹介| Alibaba Cloud ドキュメントセンター](https://jp.alibabacloud.com/help/doc-detail/27544.htm?spm=a21mg.p38356.b99.3.1dbe72b6tEjyXK)

を見てみると

> レイヤー 4 Server Load Balancer は、オープンソースソフトウェアの LVS (Linux Virtual Server)と keepalived を基盤にしています。
> 
> レイヤー 7 Server Load Balancer は、Taobao が開始した Web サーバープロジェクトである Tengine を利用します。Nginx を基盤とする Tengine には、トラフィックの多い Web サイトのニーズに合わせた幅広い高度な機能と特性が追加されています。

とあります。
[淘宝网(淘寶網) 日本站](https://world.taobao.com/)
で使っている
[The Tengine Web Server](http://tengine.taobao.org/)
の技術です。

オープンソースなので中身がわかるというのは、とてもいいですね。
[GitHub - alibaba/tengine: A distribution of Nginx with some advanced features](https://github.com/alibaba/tengine)

![](http://docs-aliyun.cn-hangzhou.oss.aliyun-inc.com/assets/attach/27544/intl_en/1465893509109/architecture.png)

パケット通信のところは割愛して（私にも説明するほどわかってないので、汗）
利用するユーザーとして、嬉しいところは下記の部分でしょう。

> このように業務アプリケーションに影響を与えることなくホットアップグレード、機器故障時のメンテナンスやクラスターメンテナンスを行うことができます。

# 簡単ですが、まとめ
ロードバランサーがブラックボックスでなくアーキテクチャがわかるというのはいいですね。
使うときには気になりませんが
どういった技術を使っているか知ることができるのは
企業の方々は、導入する際に安心を得られるのではないでしょうか。
また、淘宝网で使っているというのもシンプルな説明ができて嬉しいですね。
fishシェルでsnippetsできるpetの使い方備忘録

いつも忘れるので備忘録的にメモする

### 新規追加
``` 
pet new
> Command:ls -al(コマンド)
> Discriotion:show all（コマンドの説明）
```

### 編集
```
pet edit
```

### 一覧表示
```
pet list
> Show all    :ls -al
```

---

公式Readmeより
https://github.com/knqyf263/pet#edit-snippets
Chefのnot_ifで、あるファイルにある複数行が存在するかをチェック


```ruby:
add_text <<'EOC'
foo
bar
EOC

...
   not_if { `cat #{path}`.match('^' + Regexp.escape(add_text)) }
...
```
grep, diff, awk -v RS="", .include?など色々試しましたが、上の様になりました。
(.include?の場合、最初の行の先頭のチェックが難しい。)
Notificationのグループを作る

Android7.0（API Level24）からNotificationのグループを作成することができるようになりました。
Notificationのグループ作成方法を以下で確認していきます。

## グループの作成
1.グループの子となるNotification作成時にsetGroup()メソッドを使用してグループの名前を設定する
2.グループの親となるNotification作成時にsetGroup()メソッドでグループ名を設定し、setGroupSummary()でtrueを渡す

```kotlin
    val CHANNEL_ID = "channel_id"
    val SUMMARY_ID = 0
    val GROUP_KEY = "group_key"

    fun createChildNotification(num :Int): Notification {
        val childNotification = NotificationCompat.Builder(this@MainActivity, CHANNEL_ID)
                .setSmallIcon(R.drawable.ic_stat_name)
                .setContentTitle("Content Title $num")
                .setContentText("Content Text $num")
                .setStyle(NotificationCompat.BigTextStyle()
                        .setBigContentTitle("BigContentTitle $num")
                        .setSummaryText("summary text $num")
                        .bigText("Big Text $num"))
                .setGroup(GROUP_KEY)
                .build()
        return childNotification;
    }
    
    fun addSummaryNotification() {

        val childNotification1 = createChildNotification(1)
        val childNotification = createChildNotification(2)

        val summaryNotification = NotificationCompat.Builder(this@MainActivity, CHANNEL_ID)
                .setContentTitle("Summary")
                .setSmallIcon(R.drawable.ic_stat_name)
                .setGroup(GROUP_KEY)
                .setGroupSummary(true)
                .build()

        val notificationManager = NotificationManagerCompat.from(this)

        notificationManager.notify(1, childNotification1)
        notificationManager.notify(2, childNotification)
        notificationManager.notify(SUMMARY_ID, summaryNotification)
    }
```
<img width="300" alt="スクリーンショット 2018-05-30 5.49.36.png" src="https://qiita-image-store.s3.amazonaws.com/0/46743/4e31a3a6-eb60-f0f7-00cb-462b7bba842b.png">


###　注意点
* 子となるNotificationが１つのときは、Notificationはグループ化して表示されません。
* 子は最大８個までしか表示されず、新しいNotificationから８個を表示します。
* 親のSummaryNotificationと子のSmallIconが異なる場合は、親と子両方にSmallIconが表示されます。
* Android7.0未満の端末ですと、Summaryのみ表示され子のNotificationが表示されません。


##Notificationの自動グループ化
Android7.0以降ではNotificationのグループ化を設定しなくても、自動的にGroup化されます。
APIレベル26のソースコードで確認したところ、以下のクラスにてNotificationの自動グループ化の判定を行なっています。
[com.android.server.notification.GroupHelper](https://android.googlesource.com/platform/frameworks/base/+/master/services/core/java/com/android/server/notification/GroupHelper.java)

自動的にグループ化する条件として、 AUTOGROUP_AT_COUNTが定義されており、同じパッケージ名のアプリが４つ以上のNotificationを表示しようとした時に、自動的にグループを作成します。

自動的に作成されたグループの親NotificationにはPendingIntentが設定されており、CATEGORY_LAUNCHERフラグが付与されているActivityが起動されます。

自動グループ化されたときのIntentでは問題がある場合、自分でグループ化し起動するActivityを指定する必要があります。

Gmailアプリではメールアカウントごとにグループ化されており、Summaryをタップしたときの動作はアカウントの受信ボックスを開くようになっています。

##まとめ
* Android7.0未満の端末ではグループ設定していると、親Notificationしか表示されない
* 子の表示は新しい順に８個までで、古いものは隠れている
* Notificationは自動的にグループ化されるが、親をタップしたときのIntentに注意

##参考
https://developer.android.com/training/notify-user/group
https://material.io/design/platform-guidance/android-notifications.html
String.getBytes()のencodeを自作

# String.getBytes()のencodeを自作
- 対抗先のシステムの文字コードがSJISでユニコードのコードポイントで文字化けが発生する文字も送付する必要があった。
- replaceする2度手間より、エンコード時に置換してしまうほうが早いと判断。

```
private static final Map<Character, byte[]>  conversionCharsetMap = new LinkedHashMap<Character, byte[]>(){
	{
		put('～', new byte[]{(byte) 0x81, (byte) 0x60});
		put('－', new byte[]{(byte) 0x81, (byte) 0x7C});
		put('￠', new byte[]{(byte) 0x81, (byte) 0x91});
		put('￡', new byte[]{(byte) 0x81, (byte) 0x92});
		put('￢', new byte[]{(byte) 0x81, (byte) 0xCA});
		put('―', new byte[]{(byte) 0x81, (byte) 0x5C});
		put('∥', new byte[]{(byte) 0x81, (byte) 0x61});
	}
 };

public byte[] encode(String str, String charsetName){

	Charset charset = Charset.forName(charsetName);

	CharsetEncoder encoder = charset.newEncoder();

	CharBuffer inBuf = CharBuffer.wrap(str);

	ByteBuffer outBuf = ByteBuffer.allocate(inBuf.length() * (int)encoder.maxBytesPerChar());

	CoderResult result;

	// CoderResultがエラーを返す間ループ
	while((result = encoder.encode(inBuf, outBuf, true)).isError()) {

		// リセット
		encoder.reset();

		// マッピング不可なら
		// 例えばTF-8⇒SJIS(MS932ではない)で失敗する文字～∥－￠￡￢―などここに入る
		if(result.isUnmappable()) {

			// 1文字取得（マッピングに失敗した文字）
			char ch = inBuf.get();
			byte[] val = null;

			// この辺にマッピングに失敗したらどうするかの処理を入れる
			// ここではマッピングに失敗した文字のSJIS用のバイトコードをマップから取得している		
			val = conversionCharsetMap.get(ch);


			// エンコード結果用バイトバッファにプット
			outBuf.put(val);
		}
		// 不正入力
		if(result.isMalformed()) {
			// これは基本的にはほとんどない。
		}
	}

	// エンコード結果バッファにフラッシュ
	encoder.flush(outBuf);

	// バッファをフリップ(反転)開始位置に戻す
	outBuf.flip();

	return Arrays.copyOf(outBuf.array(), outBuf.limit());
}
```
GCE で Docker を使ってアプリを継続稼働しているとアプリ内からネットに繋がらなくなることがある

# 突然ネットに繋がらなくなることがある
- 利用者からなんか動かなくなったんですけど？？？と問い合わせが来る
- つらい
- 何も設定を変えていない
- docker image どころか コンテナも変わっていない
- なのに，アプリから外部の通信ができなくなった

何もしてないのに動かなくなった！！！どうしたらいいですか？？！
-

### 結論
[コンテナ通信の理解 — Docker\-docs\-ja 17\.06\.Beta ドキュメント](http://docs.docker.jp/engine/userguide/networking/default_network/container-communication.html#communicating-to-the-outside-world)

ホスト側（GCE上のVMインスタンス）のネットワーク設定がホストメンテナンスで変わった(たぶん iptables が再起動した)っぽい．この場合，docker の daemon を再起動するぐらいしか簡単な解決策が思いつかない．

```console:4.4.0-112-generic#135~14.04.1-Ubuntu-SMP
$ sudo service restart docker
```

これで再度コンテナを立ち上げ直し，中に入って ping などして疎通確認できた．

# 今後どうする
GCE のホストメンテナンスで iptables が再起動し，そのたびに Docker アプリがネット接続できなくなってしまうとなると，そのたびに daemon を再起動しなくてはならなくて，とてもめんどい．めんどいというか，利用者から連絡くるまで気がつけない．Slack 通知などのアラートも出せない．
### 微妙な解決案
ホスト側の /tmp などをコンテナ内のどこかにマウントして，コンテナ内で疎通確認を定期実行してダメならば /tmp に outbound_error とかファイルを書き出して，ホスト側でも定期的にそれを検知して．．．みたいな若干残念な仕組み．．．

### GAE を使え
**ですよね**．でも，ものすごく低コストで運用しなければならないという事情があり，今回は使えない．

### Docker イメージを直接 VM にデプロイ
ベータ版機能ではあるが，GCE には Docker イメージを直接 VM にデプロイできる機能がある．これを利用すれば，おそらくはライブマイグレーションにもちゃんと対応してくれて，メンテナンスが少なくてすむはず．これでいこう!
(いろいろ構築し直さないといけないが．．．．．．．．．．．．．．．．．)
Android(iOS)アプリの開発環境構築【Win10_IntelliJ_Flutter】

# はじめに
Flutterを使ってAndroidアプリを開発しようと社内でなりまして、IntelliJを使おうということになり（なんでAndroid Studioじゃないかは置いておいて）,環境構築で思いのほか苦戦したので、備忘録を残すこととした。
ゴールはFlutterのサンプルアプリがエミュレータ上で動くまで。（初投稿）

# 前提条件
JAVA環境構築済み
仮想環境構築済み

# 環境
OS : Windows10
IntelliJ IDEA Community Edition 【version 2018.1】
https://www.jetbrains.com/idea/
Android SDK 【27.0.3】
https://developer.android.com/studio/
Flutter 【beta, v0.4.4】
https://flutter.io/setup-windows/
Java　【version 1.8.0_171】
http://www.oracle.com/technetwork/java/javase/downloads/index.html
【最終目標】
![最終目標.PNG](https://qiita-image-store.s3.amazonaws.com/0/200345/d34ed7cd-1ef1-b375-cadf-602940c71be0.png)


# 1. Flutterのインストール・環境構築
⑴ Flutterをインストールする。https://flutter.io/setup-windows/
flutter_windows_v0.4.4-beta.zipをダウンロードして、適当な場所に中のflutterフォルダを設置する。
【例】C:\flutter
⑵ `flutter\bin`にPathを通す。

    Path
    C:\flutter\bin
⑶ 下記コマンドをPowerShellで叩き、Flutterがインストール出来たことの確認をする。

    flutter doctor


# 2. Android SDKのインストール・環境構築
⑴ ページ下段のCommand line tools onlyのwindows版をダウンロードする。https://developer.android.com/studio/
⑵ zipを解凍すると、toolsというフォルダが出てくるので、そのフォルダを適当な場所に設置する。
⑶ 環境変数とPathを通す。
【例】C:\android-sdk\tools

    環境変数
    変数名(N):  ANDROID_HOME
    変数値(V):  C:\android-sdk

    変数名(N):  ANDROID_SDK_ROOT
    変数値(V):  C:\android-sdk

    Path
    C:\android-sdk\platform-tools
    C:\android-sdk\tools\bin
    C:\android-sdk\tools

⑷ 以下のsdkmanagerコマンドを叩く。

    sdkmanager --licenses
```
sdkmanager "platforms;android-27"
sdkmanager "build-tools;27.0.1"
sdkmanager "emulator" 
sdkmanager "tools"
```

※下記のエラーが出ることがある。

     Warning: File C:\Users\<<UserName>>\.android\repositories.cfg could not be load.
その場合、適当な場所に中身は空のrepositories.cfgを作る


# 3. IntelliJのインストール・環境構築
⑴ IntelliJ IDEA Community Editionをインストールする。https://www.jetbrains.com/idea/
⑵ Flutterのpluginを入れる。
![Flutterのpluginを入れる.PNG](https://qiita-image-store.s3.amazonaws.com/0/200345/6c8fc17d-4926-70e3-b609-e616bb4d6c40.png)
⑶ JDKとAndroid SDKのPathを設定する。
【Configure > Project Defaults > Project Structure】
![JDKとAndroid SDKのPathを設定する１.PNG](https://qiita-image-store.s3.amazonaws.com/0/200345/13929e9c-006c-3be8-9a5c-25ead7fb7593.png)
【JDK】
![JDKとAndroid SDKのPathを設定する２.PNG](https://qiita-image-store.s3.amazonaws.com/0/200345/58fd6ea1-6e1d-a5c5-77cc-c30828ec48c6.png)
【Android SDK】
![JDKとAndroid SDKのPathを設定する３.PNG](https://qiita-image-store.s3.amazonaws.com/0/200345/f341d943-11ea-23ae-07ea-5a103ddc75cb.png)
⑷ SDK Managerから必要なパッケージをインストールする。
【実行成功時に入っていたパッケージ（試行錯誤の結果なので不必要なものもあり）】
![SDK Managerから必要なパッケージをインストールする.PNG](https://qiita-image-store.s3.amazonaws.com/0/200345/be773e66-065e-56ec-2f4f-ba74bbf32fb3.png)
⑸ エミュレータの作成。
AVD Managerを起動して、エミュレータを作る。パッケージが足りない場合はその都度インストール。
⑹ 実行（完了）！
![実行（完了）！.PNG](https://qiita-image-store.s3.amazonaws.com/0/200345/99bcf018-be02-483c-3b90-812566520c2d.png)


# ※引っかかった箇所
⑴ 二年前に入れたいたAndroid Studioの設定を保持していた。＋「Intel® Hardware Accelerated Execution Manager」のバージョンが古かった。そのせいで”Intel x86 Emulator Accelerator”のインストールが上手くいかなかった。
【参考】：https://qiita.com/endrugus/items/f50587db77d020faee5d
⑵ プロキシの設定をしたまま（プロキシがない環境で）永遠と失敗を繰り返していた。

# 参考URL
最新のzshをインストールする手順

# zshとは

zshはシェルの一種で、CentOSなどの標準シェルである **bash** よりも便利な機能を持ったシェルになります。

開発作業において、 `ls` や `cd` など、ターミナルでコマンドを実行することが多々ありますが、zshに切り替えることで、間違いなく作業効率を上げることが可能です。

具体的に実現できることについては記事の最後にて紹介をしています。


本記事では、zshの最新版をインストールする方法を紹介します。
vagrantに慣れている方であれば、10分もあればインストールは完了し、zshが使用できる状態になります。

なお、yumだと最新のzshをインストール出来ないため、yumは使いません。
2018年5月現在の最新バージョンは、**5.5.1**になります。
最新バージョンはこちらで確認が可能です。
http://zsh.sourceforge.net/Arc/source.html

# OSの用意

今回はCentOS 7.2のvagrantのboxを使います。
以下から **CentOS 7.2 x64** をダウンロードします。

https://www.vagrantbox.es/

vagrantの使い方については割愛します。


# ncurses-develのインストール
zshのインストールには　**ncurses-devel** が必要となります。
以下のコマンドでインストールします。
root権限が必要になります。

```
$ sudo su -
# yum install -y ncurses-devel
```

# zshのダウンロードとインストール

以下のコマンドでインストールを行います。
zshをダウンロードするディレクトリは任意の場所で構いません。

`--enable-multibyte` はマルチバイトを有効にするオプションになります。

```
# /usr/local/src
# wget https://sourceforge.net/projects/zsh/files/zsh/5.5.1/zsh-5.5.1.tar.xz/download -O zsh-5.5.1.tar.xz
# tar xvf zsh-5.5.1.tar.xz
# cd zsh-5.5.1
# ./configure --enable-multibyte
# make && make install
```

# zshを利用可能にする

zshを利用可能なシェル一覧に追加します。
ここに追加することで `chsh` コマンドでシェルの変更が可能となります。

```
# echo /usr/local/bin/zsh >> /etc/shells
```

# シェルの変更
それではユーザーのシェルを変更します。
ここからはrootではなく、普段使用するユーザーで行います。
コマンドを入力しますとパスワードを聞かれますので、入力をします。

```
$ chsh -s /usr/local/bin/zsh
```

それでは一度ログアウトして、もう一度ログインをしてみましょう。

以下の文言が表示されます。
zshに設定ファイルが存在しないために表示されるものになります。
ここでは `0` を入力して空の設定ファイルを作成しましょう。

```
This is the Z Shell configuration function for new users,
zsh-newuser-install.
You are seeing this message because you have no zsh startup files
(the files .zshenv, .zprofile, .zshrc, .zlogin in the directory
~).  This function can help you with a few settings that should
make your use of the shell easier.

You can:

(q)  Quit and do nothing.  The function will be run again next time.

(0)  Exit, creating the file ~/.zshrc containing just a comment.
     That will prevent this function being run again.

(1)  Continue to the main menu.

--- Type one of the keys in parentheses ---
```


# zshを使うと何が便利になるのか

zshを便利に使うためには、設定ファイルをカスタマイズする必要があります。
以下の内容をそのまま使うだけで便利に使うことが出来ます。

具体的に実現できることについても、以下記事にて紹介をしています。

https://qiita.com/d-dai/items/d7f329b7d82e2165dab3
「プログラミング教育.net」に合計３個のブログ記事のフリーランスシリーズを公開しました。

こんにちは！2週間ぐらい前に「プログラミング教育.net」を公開したオリバーです。

みんなさんは次どういうブログ記事を読みたいかをフィードバックを求めたときに、フリーランスについて書いてほしい！って声を多くもらいました。

そこで、今回はフリーランスシリーズを作って、新しい記事を3つ書きました！

### 第1回 フリーランスってなに？フリーランスとして働くのはどんな感じですか？

『多くの人は自由になる、自分の条件で仕事するという意味でフリーランサーになるのは会社のプレッシャー、ストレス、責任などから解放されるというユートピアのような世界で暮らすというイメージをもっている人もすくなくないと思います。しかし、わたしの経験から言うと、「フリーランスで仕事をする」とは、残念ながら全くストレスがない状況を作る近道には決してなりません。』ということについて書いています

[https://プログラミング教育.net/フリーランスになりたい！どうやってなったらいい？/](https://プログラミング教育.net/フリーランスってなに？フリーランスとして働くのはどんな感じですか？/)

### 第2回 フリーランスになりたい！どうやってなったらいい？

『自分のニッチを見つけるのが大切です。一般的な人と違う行動をとると、ユニークな知識が手に入れやすいと思います。
例えば、リモートで国から国へ移動しながら、ノマドフリーランサーとして働いていてたPieter Levelsさんというひとがいました。行き先がリモートワークをしやすい国かどうかわからなかったので、自分で得た知識を活かして、世界のいろんな街をリモートワーカーとしての働きやすさを評価するサイト『Nomad List』を作りました。今はもう月額を支払いしているユーザー数もかなり大きくなっています。』というような記事になっています。

[https://プログラミング教育.net/フリーランスになりたい！どうやってなったらいい？/](https://プログラミング教育.net/フリーランスになりたい！どうやってなったらいい？/)

### 第3回 フリーランスになったけど、どうすればいいの？うまくやっていくためのコツなどをおしえて！

『こういうふうに自分の時間を何円で売ると、もちろん自分の効率をあげるともっと仕事がとれるので、自分の仕事の無駄を減らすのを常に意識したほうがいいです。そして、常にクライアントが提供したもので満足するのを最優先にしたほうがいいです。[…] ただ、1日に24時間しかないので、こういったビジネスプランはあまり大きくならないです。』というような内容でこのシリーズを締めくくります。

[https://プログラミング教育.net/フリーランスになりたい！どうやってなったらいい？/](https://プログラミング教育.net/フリーランスになったけど、どうすればいいの？うまくやっていくためのコツなどをおしえて！/)

ぜひ読んでみてください！

オリバー
Android開発で注意すべきJavaオブジェクトのライフサイクルについてをまとめる

# Android開発におけるライフサイクルの概念
iOSではViewControllerやViewクラスにライフサイクルの概念があって、
オートレイアウトの設定などで非常にややこしかったのです。
なので、Androidの場合はどうなのだろうかと疑問に思っていた。
Android にもActivityにライフサイクルがあることは既知であったのだが、
言語仕様にもライフサイクルがあるというのが本日初めて知った。

もしかするとObjective-CやSwiftにも実は意識してなかったけど、
オブジェクトのライフサイクルがあったのかもしれません。

そのためmJava言語におけるライフサイクルをまとめておきます。

# 3種類のJavaのライフサイクル

大きく分けて３種類のオブジェクトのライフサイクルがある。

　- ローカル変数
　- インスタンス変数
　- クラス変数

## ローカル変数

ローカル変数は、処理のブロック内でのみ利用可能な変数のことである。

``` LocalVar.java
int sampleMethod() {
    int count = 0; // ローカル変数
    return count;
}

```

変数を宣言した箇所で生成されて、ブロックの処理が完了した時点で破棄される。

## インスタンス変数

インスタンス変数は、クラスのフィールドとして宣言する変数のことである。
インスタンス変数のライフサイクルはクラスのインスタンスのライフサイクルと同じで、
親オブジェクトが生成された時に生成され、親オブジェクトがガベージコレクションされる時に破棄される。
ガベージコレクションとは、プログラムが確保したメモリ領域のうち、不要になった領域を解放する仕組みである。


## クラス変数

クラス変数は、クラスのstaticフィールドとして宣言される変数のこと。
もっとも長いライフサイクルをもつ。
クラスロード時に生成されて破棄されるときに一緒に破棄される。

``` LifeCycleSample.java
public class LifeCycleSample {
  public static int classVariable = 1; // クラス変数
  public int instanceVarialbe = 1;     // インスタンス変数

  public void sampleMethod() {
    int localVariable = 1;            // ローカル変数
    return localVariable;
  }
}

```

## ライフサイクルのグッドプラクティス

変数オブジェクトの宣言に関するグッドプラクティスは概ね2パターン。

1. ライフサイクルを短くする。
2. ライフサイクルを長くして性能をあげる。

僕自身はこれまでの現場では変数は必要な箇所で宣言してスコープは最小限に抑えるようにしてきた。
あまりに長く保持していると、別の箇所から意図しないタイミングでその変数が呼び出されて状態が変わったりするのである(笑)。
意図しないプログラムはバグを生む要因になるのは明快であるのでなるべく避けるべき。

なので、僕にとっては1のライフサイクルは短くするパターンがやりやすいかなと思います。
Azure Functionsメモ

# 想定読者
- Kuduがわかる人
- Azure Functionsでちょっと不便を感じてる人

# Problem and Solution

### P1. 関数作るたびにnpm installするの面倒くさい
### S1.  wwwrootでnpm init, npm installして各Functionからシンボリックリンクを貼る
 - 実行コマンド(Kuduで実行)：

```
ln -s D:\home\site\wwwroot\node_modules D:\home\site\wwwroot\HttpTriggerJS1
```

<br>
<br>

### P2. Functions間の共通関数を作って使いたい
### S2. Kuduでwwwrootに移動 => ~/wwwrootに共通関数を定義 => 各Functionでインポート
- 共通関数を定義

```javascript:~/wwwroot/common.js
module.exports.testFunction = function (x){
  ~
  ~
  ~
}
```

 - 各Functionでインポート

```javascript:~/wwwroot/HttpTriggerJS1/index.js
const common = require('../common.js');
 ~
 ~
 ~
common.testFunction(input);
 ~
```

<br>
<br>

### P3. ルーティングしたい
### S3. function.jsonにプロパティ"route: ~"を追加
- パスパラメータ名定義

```function.json
{
  "bindings": [
    {
      "authLevel": "anonymous",
      "type": "httpTrigger",
      "direction": "in",
      "name": "req",
      "route": "{path}/{subpath}"
    },
    {
      "type": "http",
      "direction": "out",
      "name": "res"
    }
  ],
  "disabled": false
}
```

＊ 上記のように定義すると、https://xxxxxxxxxx.azurewebsites.net/api/HttpTriggerJS1/{path}/{subpath} がエンドポイントになる。

 - パスパラメータ取得とルーティング 

```javascript:~/wwwroot/HttpTriggerJS1/index.js
//パスパラメータ設定
const PATH = context.bindingData.path;
const SUBPATH = context.bindingData.subpath;

//以下にルーティングロジックを実装(ifやswitch等)
```

<br>
<br>

### P4. Function内で自分の関数名を取得したい
### S4.  ```context.executionContext.functionName```で取得可

＊ カレントディレクトリは、```context.executionContext.functionDirectory```で取得可。

<br>
<br>

### P5. Function名を変更したい
### S5. （変更はできないので）KuduでFunctionのフォルダを丸ごとコピーして別名で保存

```
cp -rf D:\home\site\wwwroot\HttpTriggerJS1 D:\home\site\wwwroot\HttpTriggerJS1_renamed
```

<br>
<br>

### P6. 他のFunctionで算出された値を参照したい
### S6.  参照先でグローバル変数に代入しておけば他のFunctionから参照可
＊ ただし参照先のFunctionsを実行してからでないと参照不可。

<br>
<br>

### P7. 環境変数を設定して使いたい
### S7.  **[アプリケーション設定]**で設定し、```process.env.propertyName```で参照可能。

<br>
<br>

### P8. エディタ画面小さすぎて開発しづらい
### S8. **[プラットフォーム機能]** => **[開発ツール]** => **[App Serviceエディタ]**でBotとかと同じ大きいエディタが使える。ただテストはできそうなところは見当たらず。

<br>
<br>

### P9. 画面下の実行ログが出ない
### S9.  バグなので他の関数を選んでから戻ったり関数を再起動するしかない。



# おわりに
　Kudu使えばそりゃだいたいできますよねといった感じですが、一つでも役に立つものがあれば嬉しいです。これからもっと効率よく開発できるように頑張ります。


<br>
npm installで作成した実行batファイルの中身がおかしい時

タイトルではbatファイルと書かれていますが、実際に作成されるのはcmdファイルです。Windows環境の話です。

package.jsonでbin属性が指定されたパッケージをnpm installすると、node_modules/.bin/フォルダの中にcmdファイルが作られ、シェルからコマンドを実行する事が出来る。gulpやhttp-serverコマンドの様に。

それを真似して作ってみたが、作成されたcmdファイルの中身は以下のような内容になった。このコマンドを実行しても、jsファイルはnodeで実行されない。

```bat:xxx.cmd
@"%~dp0\..\command\xxxx.js"   %*
```

npmに公開されている既存のパッケージをgit cloneし、npm installすると以下のcmdファイルが作成される。これは想定通り。

```bat:xxx.cmd
@IF EXIST "%~dp0\node.exe" (
  "%~dp0\node.exe"  "%~dp0\..\command\xxxx.js" %*
) ELSE (
  @SETLOCAL
  @SET PATHEXT=%PATHEXT:;.JS;=;%
  node  "%~dp0\..\command\xxxx.js" %*
)
```

この違いがどこから生じるのか確認した。このcmdファイルはnpm install時に作成されるので、npmコマンドのディレクトリを`IF EXIST`でgrep。以下の箇所でcmdファイルの中身が作り分けられていると確認出来た。

```js:\nodejs\node_modules\npm\node_modules\cmd-shim\index.js
  var cmd
  if (longProg) {
    cmd = "@IF EXIST " + longProg + " (\r\n"
        + "  " + longProg + " " + args + " " + target + " %*\r\n"
        + ") ELSE (\r\n"
        + "  @SETLOCAL\r\n"
        + "  @SET PATHEXT=%PATHEXT:;.JS;=;%\r\n"
        + "  " + prog + " " + args + " " + target + " %*\r\n"
        + ")"
  } else {
    cmd = "@" + prog + " " + args + " " + target + " %*\r\n"
  }
```

[githubではここ](https://github.com/npm/cmd-shim/blob/75edc98dec188cca8b819865699a2eaa5e41afae/index.js#L103) になる。

この処理のlongProg変数を遡ると、同ファイルの以下の処理に辿り着く。
ファイルを実際に読み込み、1行目が正規表現にマッチしているかで分岐している。

```
var mkdir = require("mkdirp")
  , path = require("path")
  , shebangExpr = /^#\!\s*(?:\/usr\/bin\/env)?\s*([^ \t]+)(.*)$/
//略
    fs.readFile(from, "utf8", function (er, data) {
      if (er) return writeShim_(from, to, null, null, cb)
      var firstLine = data.trim().split(/\r*\n/)[0]
        , shebang = firstLine.match(shebangExpr)
      if (!shebang) return writeShim_(from, to, null, null, cb)
      var prog = shebang[1]
        , args = shebang[2] || ""
      return writeShim_(from, to, prog, args, cb)
    })
```

よって、package.jsonのbinコマンドで指定されているjsファイルの1行目に以下の記述を加えると、node経由でjsファイルが実行されるcmdファイルが作成される

```:実行されるjsファイルの1行目
#!/usr/bin/env node
```

調べたあとに、[公式ドキュメント](https://docs.npmjs.com/files/package.json#bin)に書いてある事がわかった。母国語で書いていただかないと・・・

![image.png](https://qiita-image-store.s3.amazonaws.com/0/5825/3c2a268e-79cd-0f37-0e0c-022daf6814f7.png)
ブラウザで isomorphic-git を使って git repository を作成する

## やりたいこと

Chromebook のために PWAで完結するエディタを作りたい。markdown の履歴管理程度でいい、ぐらいの気持ちで調べ始めた。

## やる

browserfs を webpack でビルドするのは大変なので、 次の js を書いてしまうか、このJSをローカルに落として普通に読み込む。

```
<script src="https://unpkg.com/browserfs"></script>
```

ここから先は webpack でビルドすることを前提。
browserfs は fs.~Sync を持たないので, pify を使って promise API 化する。
IndexedDB をバックエンドに fs モジュールを初期化して、isomorphic-git から使う

```js
const git = require("isomorphic-git")
const pify = require("pify")

export function setupBrowserFS(): Promise<any> {
  return new Promise(resolve => {
    BrowserFS.configure({ fs: "IndexedDB", options: {} }, (err: any) => {
      if (err) {
        throw err
      }
      const fs = BrowserFS.BFSRequire("fs")
      resolve(window.fs)
    })
  })
}

const main = async () => {
  const fs = await setupBrowserFS(fs)
  const repo = { fs, dir: "/foo" }

  // directory 初期化
  await pify(fs.mkdir)(repo.dir)

  // directory README.md 作成
  await pify(fs.writeFile)("/foo/README.md", `# TEST`)

  // 確認
  const files = await pify(fs.readdir)("/foo")
  console.log("fs files", files) // => ["README.md"]

  // git init
  await git.init(repo)

  // git add README.md
  await git.add({ ...repo, filename: "README.md" })
  
  // git commit -m "Init"
  const sha = await git.commit({
    ...repo,
    author: {
      email: "miz404@gmail.com",
      name: "mizchi"
    },
    message: "Init"
  })
  console.log(sha)
}

main()
```

これで README.md を持つ git repository が作成できた。

## GitHub に Push できるか

現状CORSの制限で不可能

```
Gogs: Supported in v0.11.43
Gitlab: PR Add CORS headers to git clone and git push #219
Bitbucket: PR TODO
Github: PR TODO
```

とりあえず次は gogs を調べる。self hosted な git service ということで、 とりあえず localhost に立ててしまって、ローカルに push できそうな気がする。あとはなんか頑張ればいけそう。
Kerasで出力したモデルをCoreMLで変換したらハマった話

#Kerasでモデル作った
Kerasで良さげなモデルを作ってiOSアプリで動かしたくなったら、coremltoolsを使ってh5ファイルを変換してあげましょう。
※今回はクラス分類するモデルなのでクラスラベル一覧が書かれているtxtファイルも読み込みます。

```python
import coremltools

coremltools.converters.keras.convert('hoge.h5', class_labels='label.txt').save('hoge.mlmodel')
```

そして、出力したmlmodelをswiftプロジェクトに突っ込むだけで[MLModelクラス](https://developer.apple.com/documentation/coreml/mlmodel)として使用できます。あとはクラスのインスタンス作ってデータを入力するだけのはずなんですが、何故か入力データの形式が合わないようで上手くいきません（今回のモデルinputは二次元行列でちゃんとデータもそれに合わせて成形しているのですが……）。

ここでCoreMLモデルのinputに使われる[MLMultiArray](https://developer.apple.com/documentation/coreml/mlmultiarray)のリファレンスをよく見てみると、NSNumberの一次元配列になっているではないですか。

しょうがないので、Keras側でのモデル入力は一次元とし、モデル内部で[Reshape層](https://keras.io/ja/layers/core/#reshape)をaddしてデータを二次元に戻してあげます。

```python
model.add(Reshape((row, column), input_shape=(row*column,)))
```

これで出力したh5をmlmodelに変換してデータ入力するとモデルが無事動きました！やらしい！

#参考

https://apple.github.io/coremltools/generated/coremltools.converters.keras.convert.html
https://qiita.com/akimach/items/d43cd04b5de5fa99bb6a
→自分がハマったとこにも言及されていました！

#おまけ
CoreMLを使うことでこんな使い方ができたり。
http://hahaeatora.hateblo.jp/entry/2018/10/14/183000
PHPでインデックスを使って配列を組み立てた際の動作

自分が思っていたのと違う動作をしていたのでメモ

```php
$list = [];
$list[2] = 'c';
$list[0] = 'a';
$list[1] = 'b';

foreach ($list as $index => $element)
{
    var_dump($index, $element);
}
```

```
int(2)
string(1) "c"
int(0)
string(1) "a"
int(1)
string(1) "b"
```

あれ？こんな動作だっけ
ソートされないのはJavaScriptでも同じだったけ？
と思ったので試してみました。

```js
var list = [];
list[2] = "c";
list[0] = "a";
list[1] = "b";

list.forEach(function(element, index) {
  console.log(index, element);
});
```

```
0 "a"
1 "b"
2 "c"
```

動作違うのかー。

**PHPでは組み立てた後に[ksort](http://php.net/manual/ja/function.ksort.php)を使わないといけない**。PHPの配列は連想配列と言われるけどインデックスでも文字列キーと同じような扱いなのかな。

```php
$list = [];
$list[2] = 'c';
$list[0] = 'a';
$list[1] = 'b';
ksort($list);

foreach ($list as $index => $element)
{
    var_dump($index, $element);
}
```

```
int(0)
string(1) "a"
int(1)
string(1) "b"
int(2)
string(1) "c"
```
Chainerメモ その4

#7. 学習用データ作成（画像リサイズ）
mv images images_origin
mkdir images
python3 chainer_imagenet_tools/crop.py images_origin/ images/

#8. meanファイル作成（画像データなどが入った、学習用バイナリーデータ）
python3 compute_mean.py train.txt
ssh reverse port forwarding + RaspberryPi おすすめのsystemd設定

sshのリバースポートフォワーディングを使うと、

- NATの内側（家庭や企業のLAN内など）に置いたRaspberryPi
- CGNのSIMでインターネットにつながっているRaspberryPi
- グローバルアドレスを持っているが固定IPではないしDynamicDNSなども使いたくないRaspberryPi

などにも任意の場所からリモートログインできるようになり非常に便利ですが、sshのオプションとsystemdのオプションをそれぞれ適切に設定しないとコネクションが切れたときにうまく復帰してくれない。
いまのところうまくいっている設定をメモしておく。


# RaspberryPiの設定

- sshのコマンドラインオプションは[Reverse ssh tunnel を安定運用する](https://qiita.com/syoyo/items/d31e9db6851dfee3ef82)を参考にした
- `Restart=always`でsshのプロセスがどのような終了ステータスの場合も再起動を試みる
- `RestartSec`はサービス再起動までの待ち時間（秒）
- `StartLimitBurst`は、サービスの再起動を停止するまでの試行回数。0に設定すると無限にサービスの起動を試みるようになる

```systemd:/etc/systemd/system/ssh-rpfw.service 
[Unit]
Description=ssh reverse port forwarding service
After=network.target auditd.service

[Service]
User=pi
Group=pi
WorkingDirectory=/home/pi
ExecStart=/usr/bin/ssh -oServerAliveInterval=10 -oExitOnForwardFailure=yes -oTCPKeepAlive=no -N -R 3022:127.0.0.1:22 user@example.com
Restart=always
RestartSec=1
StartLimitBurst=0

[Install]
WantedBy=multi-user.target
```


# sshサーバの設定

- ここで言うsshサーバとは、リバースポートフォワーディングの踏み台（中継）に使うサーバのこと
- このサーバは当然RaspberryPi（前述）とsshクライアント（後述）の両方から接続ができる
- 自分はさくらVPSを使っている

## アカウントの作成と公開鍵の配置

- RaspberryPiからは自動でsshが実行されるので、鍵認証が必須

## sshdの設定

- なくてもいいけど、ないとTCPのタイムアウトまで次の接続ができなくなる
- 以下の設定だとRaspberryPiを停止してから2分弱くらいでTCPソケットが消えて再度接続できるようになる

```sshd_config:/etc/ssh/sshd_config
~~~~ 前略
ClientAliveInterval 30
ClientAliveCountMax 3
~~~~ 後略
```

## TCPの設定

前述の例では3022でLISTENしているが、3022は Registered Port なので、別の（本来このポートをLISTENするはずの）サービスがLISTENする可能性がある。
そのため、 Ephemeral Port の範囲を絞って、あいた範囲をリバースポートフォワーディングの待ち受け用ポートにしようかと思ったが、だるかったのでやめた。
（というのも、FreeBSD handbookの当該の箇所が日本語訳されていなかったので、先にドキュメントの修正をやらないといけない気持ちになってしまった）


# sshクライアントの設定

- ここでいうsshクライアントとは、上記の設定をしたRaspberryPiに対してリモートログインしたいワークステーションなどのこと
- リバースポートフォワーディングのソケットは`localhost`にバインドされているので、多段sshを実行する

```config:~/.ssh/config
Host exmaple.com
  User user
  Host example.com

Host raspberrypi
  HostName  localhost
  Port 2201
  User pi
  ProxyCommand ssh -W %h:%p example.com
```

上記の`raspberrypi`の設定があれば、

```shell-session
$ ssh raspberrypi
```

のみで、RaspberryPiにリモートログインできる。
Chainerメモ その3

#5. 学習用データ作成（画像パスとクラスがセットされたテキストファイル）
python3 chainer_imagenet_tools/make_train_data.py 101_ObjectCategories

#6. 学習用データ作成（画像リサイズ 用スクリプトを修正）
vim chainer_imagenet_tools/crop.py

```python
#!/usr/bin/python
# -*- coding: utf-8 -*-
import cv2
import argparse
import os
import numpy

parser = argparse.ArgumentParser()
parser.add_argument("source_dir")
parser.add_argument("target_dir")
args = parser.parse_args()

target_shape = (256, 256)
output_side_length=256

for source_imgpath in os.listdir(args.source_dir):
  print(source_imgpath)
  img = cv2.imread(args.source_dir+os.sep+source_imgpath)
  height, width, depth = img.shape
  new_height = output_side_length
  new_width = output_side_length
  if height > width:
    new_height = int(output_side_length * height / width)
  else:
    new_width = int(output_side_length * width / height)
  resized_img = cv2.resize(img, (new_width, new_height))
  height_offset = int((new_height - output_side_length) / 2)
  width_offset = int((new_width - output_side_length) / 2)
  cropped_img = resized_img[height_offset:height_offset + output_side_length,
width_offset:width_offset + output_side_length]
  cv2.imwrite(args.target_dir+os.sep+source_imgpath, cropped_img)
```
VBAで Windows APIを使った UTF-8 ←→Unicode相互変換

VBAでUTF-8とUnicodeとの相互変換は ADODB.STREAM を使ったものがよく知られていますが、Windows APIを使った場合のやり方を記します。
Byte型の配列変数を使うので、ファイルの内容を変換する場合等には、ADODB.STREAMを使うやり方に比べて、面倒です。
ファイルとは無関係にメモリ上での相互変換をする場合には、すっきりするかもしれません。

```vb:主となる関数
Private Declare PtrSafe Function MultiByteToWideChar Lib "kernel32.dll" ( _
    ByVal CodePage As Long, _
    ByVal dwFlags As Long, _
    ByVal lpMultiByteStr As LongPtr, _
    ByVal cchMultiByte As Long, _
    ByVal lpWideCharStr As LongPtr, _
    ByVal cchWideChar As Long) As Long

Private Declare PtrSafe Function WideCharToMultiByte Lib "kernel32.dll" ( _
    ByVal CodePage As Long, _
    ByVal dwFlags As Long, _
    ByVal lpWideCharStr As LongPtr, _
    ByVal cchWideChar As Long, _
    ByVal lpMultiByteStr As LongPtr, _
    ByVal cchMultiByte As Long, _
    ByVal lpDefaultChar As LongPtr, _
    ByVal lpUsedDefaultChar As Long) As Long
    
Private Const CP_UTF8 As Long = 65001

'UTF8バイト配列をUnicode文字列に変換
Function FromUTF8(ByRef bData() As Byte) As String
    Dim nBufferSize As Long
    
    If UBound(bData) = -1 Then
        Exit Function
    End If
    
    nBufferSize = MultiByteToWideChar(CP_UTF8, 0, VarPtr(bData(LBound(bData))), UBound(bData) - LBound(bData) + 1, 0, 0)
    FromUTF8 = String(nBufferSize, vbNullChar)
    MultiByteToWideChar CP_UTF8, 0, VarPtr(bData(LBound(bData))), UBound(bData) - LBound(bData) + 1, StrPtr(FromUTF8), nBufferSize
End Function

'Unicode文字列をUTF8バイト配列に変換
Function ToUTF8(ByRef sData As String) As Byte()
    If Len(sData) = 0 Then
        ToUTF8 = ""
        Exit Function
    End If
    Dim nBufferSize As Long
    nBufferSize = WideCharToMultiByte(CP_UTF8, 0, StrPtr(sData), Len(sData), 0, 0, 0, 0)
    Dim Ret() As Byte
    ReDim Ret(0 To nBufferSize - 1)
    WideCharToMultiByte CP_UTF8, 0, StrPtr(sData), Len(sData), VarPtr(Ret(0)), nBufferSize, 0, 0
    ToUTF8 = Ret
End Function

```
以下は上記変換関数のテスト用コードです。

```vb:テストコード
Sub Main()
    Dim sUnicode As String
    Dim bUTF8() As Byte
    sUnicode = "abcあいう"
    
    'Unicode文字列をUTF8バイト配列に変換
    bUTF8 = ToUTF8(sUnicode)
    
    'UTF8バイト配列を16進数表示
    Dim sHex As String
    For i = LBound(bUTF8) To UBound(bUTF8)
        sHex = sHex & Right("0" & Hex(bUTF8(i)), 2) & " "
    Next
    Debug.Print sHex
    
    'UTF8バイト配列を再度Unicode文字列に変換して、表示
    Debug.Print FromUTF8(bUTF8)
    
End Sub

```
CentOS7.xにPostgreSQL10.xをインストールするたった一つの方法

via http://vdeep.net/centos7-postgres
# コマンド

###既存のPostgreSQLを削除する

```bash
sudo yum -y remove postgresql

```

###RPMでPostgreSQL10のリポジトリを登録

```bash
 sudo rpm -iUvh https://download.postgresql.org/pub/repos/yum/10/redhat/rhel-7-x86_64/pgdg-centos10-10-2.noarch.rpm
```

###リポジトリの設定ファイルの編集
```bash
 sudo nano /etc/yum.repos.d/pgdg*.repo
```

[pgdg10]
...省略...
enabled=1
↓
enabled=0

###PostgreSQL10のサーバーをインストール＆自動起動の設定

```bash
sudo yum -y install --enablerepo=pgdg10 postgresql10-server postgresql10-devel postgresql10-contrib
sudo systemctl enable postgresql-10

```
Chainerメモ その2

#4. 学習用データ作成（画像パスとクラスがセットされたテキストファイル スクリプト修正）

vim chainer_imagenet_tools/make_train_data.py

```python
import sys
import re
import os
import shutil

#labels
pwd = os.getcwd()
labels = os.listdir(pwd+os.sep+sys.argv[1])

#make directries
os.mkdir("images")

imageDir = pwd+os.sep+"images"
train = open('train.txt','w')
test = open('test.txt','w')
labelsTxt = open('labels.txt','w')

classNo=0
cnt = 0
#label = labels[classNo]
for label in labels:
        print(label)
        workdir = pwd+os.sep+sys.argv[1]+os.sep+label
        images = os.listdir(workdir)
        labelsTxt.write(label+"\n")
        startCnt=cnt
        length = len(images)
        for image in images:
                print(image)
                imagepath = imageDir+os.sep+"image%07d" %cnt +".jpg"
                shutil.copy(workdir+os.sep+image, imagepath)
                if cnt-startCnt < length*0.75:
                        train.write(imagepath+" %d\n" % classNo)
                else:
                        test.write(imagepath+" %d\n" % classNo)
                cnt += 1

        classNo += 1

train.close()
test.close()
labelsTxt.close()
```
Chainerメモ その１

#1. imagenetの入手

https://chainer.org/
wget https://github.com/chainer/chainer/archive/v3.4.0.tar.gz
tar xzf v3.4.0.tar.gz
cp -r chainer-3.4.0/examples/imagenet ./
cd imagenet

#2. 学習用ツールの準備
git clone https://github.com/shi3z/chainer_imagenet_tools.git

#3. 学習用データ準備
wget http://www.vision.caltech.edu/Image_Datasets/Caltech101/101_ObjectCategories.tar.gz
tar xvf 101_ObjectCategories.tar.gz
自宅の無線環境PCのIPアドレス固定化

自宅で使用しているノートPCをサーバーとし、同じネットワーク内(無線LAN内)にいる他のマシン(今回はiphone)からhttpでアクセス可能とする事を目的とした設定やつまずいた点について紹介します。

環境
windows10 64bit Home

## やる前に考えてたこと
「DHCPだから固定IPの設定にすればいいだけじゃん？」
と思ってました。
具体的には
①ipconfigで表示されるwi-fiアダプタのIPアドレス,サブネットマスク,デフォルトゲートウェイを確認
②コントロールパネルのネットワーク設定から、wi-fiアダプタのipv4のネットワーク設定をDHCP→固定IPに変更
この際①で確認したIPアドレス,サブネットマスク,デフォルトゲートウェイを設定


## やってみた
**だめだった( ;∀;)**
ブラウジングしてみるけど、サーバーが見つからないエラー。
もちろん、アダプタの再起動も試してipconfigで設定が反映されていることを確認。

DHCPに戻すと無事つながりました。
設定が悪いんですね。

## 正しい方法を調査
ググった結果、方法は大まかに2つあるみたいです。
①手動で正しい設定する
上でやってみたことと同じです。
ただ、これはプロバイダーに正しい設定を聞いてねっていう記事が多くそれはめんどいなと思いました。
※もしかしたらモデム(光回線終端装置)の説明書に書いてるかもしれません。これまためんどくさかったので、私は見てません、、、

②DHCPだが、特定のMacアドレスに対して固定IPアドレスを設定する
お、これは簡単そうだ！
ルーターにhttpアクセスして設定するようです。
早速使用しているルーターの型番を確認し操作マニュアルをGet！
※割とwebに転がってます。
こちらを採用し設定してみます。

## ルーターに設定してみる
説明書通りに説明していくと、機種依存した説明になりそうなのでざっと汎用的な説明をしていきます。

前提
・DHCPの設定で、ネットワークに接続していることを確認。
・wi-fiアダプタのmacアドレスを確認。
　※windows10だと[設定]→[ネットワークとインターネット]→[Wi-fi]→[ハードウェアのプロパティ]で確認できます。

手順
①ipconfigで確認できるデフォルトゲートウェイのIPアドレスにブラウザからアクセス。
②「DHCP固定割当設定」のような設定画面を探し出します。
③②で表示される画面に事前に確認したMacアドレスと設定したいIPアドレスを設定します。
**※事前に確認したmacアドレスはA1-B2-C3-D4-E5-F6のような書式ですが。このまま設定してもうまくいかないことがあるようです。私の環境では、A1:B2:C3:D4:E5:F6の書式で設定するとうまくいきました。**
※設定するIPアドレスは、「基本設定画面」の様な画面に表示されているIPアドレスとネットマスクから適当な値を設定します。
例)設定するIPアドレスは基本画面で192.168.23.1/24が表示されている場合、192.168.23.1~192.168.23.255まで設定可能です。
　※192.168.23.255はブロードキャストアドレスなので使用不可です。

ここまで設定して保存したら、wi-fiアダプタを再起動


## 結果

**うまくいきました( ;∀;)**
ipdonfigで確認したipアドレスは設定したものになっており、ブラウジングもできました！
もちろんPC再起動しても固定化されてます。

## 感想
設定しようと思ってから3時間ほどかかりました。
ネットワークの知識があればもっとさっとできたのかなと思いました。

目的はhttpアクセスでそこまでまだできてませんが、そこはまた別記事に書きます。たぶん。
あとはapacheのインストール~設定~起動なので沢山記事がありそうですね。気になる人は別記事ググってください。