OmniAICreator/Qiita-1.07M huggingface dataset:
kubelet call cni memo

# kubelet が CNI を呼び出すコードを読んだメモ

kubernertes version
branch: master
CommitID: 4e5c781b7dfe70026c1a8870f3e28c711bd57c08

## dockershim/docker_sandbox.go
CNI 呼び出しを調査するための Pod 作成時のコードの読み始めは `docker_sandbox` とした。

`kubernetes/pkg/kubelet/dockershim/docker_sandbox.go` の `RunPodSandbox()` で Pod 用ネットワークの作成が実施されている。

https://github.com/kubernetes/kubernetes/blob/master/pkg/kubelet/dockershim/docker_sandbox.go#L157-L182

肝心な部分は下記の `SetUpPod` の呼び出し。

```go
err = ds.network.SetUpPod(config.GetMetadata().Namespace, config.GetMetadata().Name, cID, config.Annotations)
```

## dockershim/network/plugins.go

`kubernetes/pkg/kubelet/dockershim/network/plugins.go` の `SetUpPod()` が呼び出される。

https://github.com/kubernetes/kubernetes/blob/master/pkg/kubelet/dockershim/network/plugins.go#L371-L383

ここで重要なのは下記。

```go
if err := pm.plugin.SetUpPod(podNamespace, podName, id, annotations); err != nil {
        return fmt.Errorf("NetworkPlugin %s failed to set up pod %q network: %v", pm.plugin.Name(), fullPodName, err)
}
```

`plugin` は `cni` を指定しているのでここで呼び出す `SetUpPod` は `kubernetes/pkg/kubelet/dockershim/network/cni/cni.go` の `SetUpPod()` になる。

## dockershim/network/cni/cni.go

https://github.com/kubernetes/kubernetes/blob/master/pkg/kubelet/dockershim/network/cni/cni.go#L217-L241

```go
_, err = plugin.addToNetwork(plugin.getDefaultNetwork(), name, namespace, id, netnsPath, annotations)
```

上記の `addToNetwork()` のコードが下記。

https://github.com/kubernetes/kubernetes/blob/master/pkg/kubelet/dockershim/network/cni/cni.go#L257-L273

下記の `AddNetworkList()` でようやく CNI のコードへ。

```go
res, err := cniNet.AddNetworkList(netConf, rt)
```

## libcni/api.go

https://github.com/containernetworking/cni/blob/master/libcni/api.go#L250-L261

下記の `"ADD"` を見てわかる通り、CNI plugin のバイナリ実行時に使われる `CNI_COMMAND` にあたるもの。

```go
result, err := c.addOrGetNetworkList("ADD", nil, list, rt)
```

https://github.com/containernetworking/cni/blob/master/libcni/api.go#L164-L177

```go
return invoke.ExecPluginWithResult(pluginPath, newConf.Bytes, c.args(command, rt), c.exec)
```

渡されたプラグインのパスとバイナリ実行時に先ほどインターフェースの追加を意味する `ADD` が渡されている。これでプラグインが実行され、プラグインは `Add` を見て CNI プラグインで定義されている `cmdAdd()` を実行する。
【Railsチュートリアル】pushがrejectされる場合の確認ポイント

#はじめに
この記事は以下のポイントでつまずいた方を対象としています。
・Rails 5.1 (第4版)　1.4.3 Bitbucket　リスト1.11

```:リスト1.11
$ git remote add origin git@bitbucket.org:ユーザー名/hello_app.git
$ git push -u origin --all
```

出力

```
To bitbucket.org:username/repository_name.git
 ! [rejected]        master -> master (non-fast-forward)
error: failed to push some refs to 'git@bitbucket.org:username/repository_name.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
```
#対処
私の場合、一旦レポジトリを削除したのち、以下の手順を行うと解決しました。

**1. 新規リポジトリの作成画面を表示する**
![リポジトリ作成.PNG](https://qiita-image-store.s3.amazonaws.com/0/271991/df3b130f-354e-8c7e-5616-7bdaab93894f.png)

**2. Include a README?　を NOにする**
![変更箇所.PNG](https://qiita-image-store.s3.amazonaws.com/0/271991/6ba799ac-5008-7916-f13f-109746ee5172.png)

以上です。
こうすることでpushがうまくいきました。

#終わりに
README.md がリポジトリと同時に生成されることによってローカルとリモートで競合が発生していたということでしょうか。pullで解決できない理由が分からないですが。。

取り敢えずこれで私の場合は解決したので、もし同じところで躓いた方は参考にしてみてください。
iferrorとiserror

意外と知らなかったGoogle Spreadsheet・Excelの小ネタ。

どっちもエラー判定系の関数ですがちょっと振る舞いが違います。
matchやvlookupのような検索系と合わせて使うことが多いですかね。

↓こんな感じ。matchの結果が見つからずエラーが表示されるのが嫌なときとか。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/23715/f9ed7081-8c27-3536-5f87-cb288ce6cbf1.png)

さて、こんなときにiserrorとiferrorを使うとするとそれぞれどうなるかというと…

# iserror
与えられた式がエラーか否かをチェックします。[（Spreadsheetのリファレンス）](https://support.google.com/docs/answer/3093349)
なので今回のようなお題だとmatchを2回書かないといけない…

```
=if(iserror(match(...)),　"見つからないよ",　match(...))
```

#iferror
エラーなら第二引数の値を返す、そうじゃないなら第一引数。[（Spreadsheetのリファレンス）](https://support.google.com/docs/answer/3093304)
match、1回だけ！！

```
=iferror(match(...), "見つからないよ")
```

***

圧倒的なiferrorの利便性。matchやvlookupは、引数が多い目の関数なので複数回書くのは手間だったんですよね〜。何故かiserrorのExcelのリファレンスがぱっと見つからなかったのでSpreadsheetのを載せました。使い方は変わらないはず。

iserrorしかない2000あたりから使い始めたおっちゃんなので、2007から追加されたらしいiferrorなんて便利な関数は知らなかったんです…
MQTTブローカ「mosquitto」をpythonで使ってみる

##参考サイト
https://librabuch.jp/blog/2015/09/mosquiito_paho_python_mqtt/

##使用するもの
ubuntuプロンプト・・・ブローカ用
anacondaプロンプト二つ・・・pub用、sub用

##anacondaにpahoクライアントをインストール
anacondaPromptにて

pipコマンドインストール

~~~
 sudo apt install python-pip
~~~

paho-mqttインストール

~~~
pip install paho-mqtt
~~~

をする。

##ubuntuのコマンドプロンプトでmosquittoブローカを起動

これだけで起動できる。
~~~
mosquitto
~~~

##pub.py,sub.pyを作成する。

pub.py

~~~
from time import sleep
import paho.mqtt.client as mqtt

host = '127.0.0.1'
port = 1883
topic = 'iktakahiro/a'

# インスタンス作成時に protocol v3.1.1 を指定します
client = mqtt.Client(protocol=mqtt.MQTTv311)

client.connect(host, port=port, keepalive=60)

for i in range(3):
    client.publish(topic, 'ham')
    sleep(0.2)

client.disconnect()
~~~

sub.py

~~~
import paho.mqtt.client as mqtt

host = '127.0.0.1'
port = 1883
topic = 'iktakahiro/a'

def on_connect(client, userdata, flags, respons_code):
    print('status {0}'.format(respons_code))

    client.subscribe(topic)

def on_message(client, userdata, msg):
    print(msg.topic + ' ' + str(msg.payload))

if __name__ == '__main__':

    # Publisherと同様に v3.1.1を利用
    client = mqtt.Client(protocol=mqtt.MQTTv311)

    client.on_connect = on_connect
    client.on_message = on_message

    client.connect(host, port=port, keepalive=60)

    # 待ち受け状態にする
    client.loop_forever()
~~~

メモ帳で作成する場合、utf-8に設定しないとエラーが発生するので注意。
pythonエディタで作りましょう。

##起動を確認する。
anacondapromptで二つのファイルがあるディレクトリに移動し、
一方で、

~~~
python sub.py
~~~

もう一方で

~~~
python pub.py
~~~

subscliberの画面に

~~~
status 0
iktakahiro/a b'ham'
iktakahiro/a b'ham'
iktakahiro/a b'ham'
~~~

となれば成功。
pythonファイルをいじればもっと多くのことができそう。

以上。
Pythonでバイナリ操作＋ファイルのリネーム

## 【経緯】
意外にファイルのバイナリ書き換えとリネームにてこずったので、メモがてら。
特に「ファイルの先頭に追記」にてこずりました。。。

## 【要件　※元ファイルがZipファイル想定】
* ファイルの先頭16バイトを8ずつ入れ替えする
* ファイルの先頭にバイナリで「07」を追記する
* ファイルのリネームを行う

## 【コード】
```python
import os
import shutil

# デスクトップのパスを取得        
def getDesktopPath():
    return os.getenv("HOMEDRIVE") + os.getenv("HOMEPATH") + "\\Desktop" + "\\"

# バイナリの書き換え
def writeBinary(path):
    zip = open(path, 'r+b')        
    # 先頭16バイトの先頭8バイトを取得
    first = zip.read(8)
    
    # 先頭16バイトの残りを取得
    zip.seek(8)
    second = zip.read(8)
       
    # 先頭16バイトを8バイトずつ入れ替える
    zip.seek(0)
    zip.write(second)
    zip.seek(8)
    zip.write(first)
    
    # 先頭1バイトに01を追加    
    zip.seek(0)
    row = zip.readlines()
    row.insert(0, chr(7))
    zip.close()
    
    add = open(path, 'w+b')
    add.writelines(row)
    add.close

# 指定ファイルのパス(Zipファイル想定）
targetPath = 'targetPath'
writeBinary(targetPath)

# ファイルのリネーム
# os.renameを使用してリネームした場合、リネーム後のファイルが既に存在していた場合はOSによって動作を変える
# WindowsはWindowsFileErrorが発生。Linux/Unixは上書き？
# os.rename(targetPath, os.path.abspath(getDesktopPath() + '%s.zip' % 'rename'))
# shutil.moveはmvコマンドと同じ扱いなので、ファイル上書きになる
shutil.move(targetPath, os.path.abspath(getDesktopPath() + '%s.zip' % 'rename'))
```
## 【所感】
ファイルの先頭から追記がどうしても出来なくてこんな感じになりました。
r+bでファイルを開くと末尾に追加になってしまうので、r+bで開いた状態でファイルのバイナリを全部取得→バイナリ操作→一旦開きなおして記載、みたいな感じになりました。きっともっと良い方法がある気がする。。。
ファイルのリネームはshutil.moveを使用していますが、既に同じ名前のファイルが存在している場合にも無視して上書きする動作になっているので、嫌な場合はos.renameを使用する。
総和（シグマ）を用いた漸化式を摂動法で一般化する

#シグマを用いた漸化式を摂動法で一般化する
```math
S_n=\sum_{k=0}^{n}a_k
```
のような総和の式を一般化するのに摂動法と言う方法があるらしいのですが情報が少ないので
手元の情報を元に記事を書いてみました

プログラミング的にも漸化式を一般化することでfor文で回すことなく$O(1)$にできるので大変おいしいはずです。この方法の正式名称はわかりませんが摂動法と教わったので以後摂動法と呼びます
次に以下のような方法でシグマの式を式変形します
##実際に摂動法での式変形をしてみる
```math
S_n=\sum_{k=0}^{n}a_k \\
S_{n+1}=S_n + a_{n+1} \\
```
以上のような式変形を行って一般化をしますので次に具体的な式でやってみましょう

```math
S_n=\sum_{0\leq k \leq n}ax^k=ax^0+ax^1+ax^2・・・ax^n
```
単純に0からkまでの値を二乗して足していくだけの簡単な漸化式ですね(´・ω・｀)
次に総和$S_n$を式変形していきます,$a$は与えられた任意の定数と考えてください
もしかしたら見慣れない$\sum$の書き方だなと思われるかもしれませんが$0$から$n$まで繰り返すと言う意味です

```c
for(int k=0 ; k<=n ;k++)
  a+=a*pow(x,k);
```
これと大体同じ意味です

```math
S_n+ax^{n+1}=ax^0+\sum_{0 \leq k \leq n}ax^{k+1}
```
最初に示したように$S_{n+1}$の形にします

```math
S_n+ax^{n+1}=a+x\sum_{0 \leq k \leq n}ax^{k}
```
なぜか上の式で$ax^0$が$a$に置き換わってますが$x^0 =1$なので$ax^0=a$が成り立ちます
ここで右辺に$\sum ax^{k}$が出てきたので$S_n$に置き換えます

```math
S_n+ax^{n+1}=a+x\sum_{0 \leq k \leq n}ax^{k}\\
S_n+ax^{n+1}=a+xS_n
```

これで$S_n$に右辺も左辺も無事置き換えられたので式変形で一般化していきます

```math
S_n+ax^{n+1}=a+xS_n \\
S_n -xS_n = a-ax^{n+1}\\
S_n(1-x)=a  -ax^{n+1}\\
S_n=\frac{a-ax^{n+1}}{1-x}
```
無事に一般化できましたね。
##実際にプログラムとして走ってもらう
次にプログラミングで動かしてみましょう。
$n=10,a=2,x=3$とします
気分的にプログラム中のカウント変数iをしたので数式も一応添字はiにしておきます

```math
S_n=\sum_{0 \leq i \leq n}2*3^i
```
もちろん一般式も

```math
S_n=\frac{2-2*3^{10+1}}{1-3}
```
ちなみに関数電卓で検算したら177146になった
以下のソースで実行しました。my_pow()が累乗を行う自作関数です
インデント等々はスゴイ適当なので悪しからず。
コンパイラはgcc 5.4.0です

```c
#include<stdio.h>
#define N 10
int my_pow(int a,int b){
int pow=a;
int i=0;
	if(b==0){
	 return 1;
	}
  	for(i=0;i < b-1;i++){
    	a=a*pow;
    	}
return a;
}

void main(){
int a=2;
int X=3;
int x1=0;
int x2=0;

	for(int i=0 ; i <= N ;i++){
		x1+= a * my_pow(X,i);
	}
		x2= (a - a * my_pow(X,N+1)) / (1-X);
printf("%d %d \n",x1,x2);

return ;
}

```
実行結果

```
177146 177146
```
やったぜ(´・ω・｀)
これでアホみたいにfor文をぶん回す必要がなくなりました。
（補足） 2018年7月26日に数式の一部に追記を追加
（補足）　同年11月14日に日本語がおかしい部分があったので修正
Siv3DでローカルファイルをOS規定の手段で開く方法

#やりたいこと
ゲームのドキュメント（html）にゲーム内からアクセスしたい。
つまり下記のような感じ。

```cpp:main.cpp
if (Internet::IsConnected()) {
	Internet::LaunchWebBrowser(L"http://aini-bellwood.jp/game/signbordfactory/manual/index.html");
}
else {
	//ここでローカルのhtmlを読みたい
}
```

#ためしたこと
##Internet::LaunchWebBrowserにローカルファイルのパスを入れる

```cpp:main.cpp
Internet::LaunchWebBrowser(FileSystem::InitialPath() + L"doc/index.html");
```

これはもちろん無理。
ドキュメントに「url:http:// もしくは https:// で始まる URL」と書いてある。

##IEを外部プロセスとして立ち上げる

```cpp:main.cpp
String tmpStr = FileSystem::InitialPath() + L"doc/index.html";
tmpStr = tmpStr.replace(L"/", L"\\");
Optional<ProcessInfo> process = System::CreateProcess(L"C:/Program Files/Internet Explorer/iexplore.exe", L"-new " + tmpStr);
```

一応動いた。でもこれはあまりにも乱暴なのでやりたくない…。
ここでTwitterに助けを求めた。

##system関数を使う

```cpp:main.cpp
system(".\\doc\\index.html");
```

なるほど！！かしこい！！！
でももうちょいスマートにならんかな…ということでReputeless氏に聞いてみた。

##System::LaunchFile()を使う。

```cpp:main.cpp
System::LaunchFile(L".\\doc\\index.html", LaunchVerb::Open);
```

はい！瞬殺！！
FileSystemしか見てなかったから全く気づかなかったよ…。

#まとめ

ということでこんな形に落ち着いた。
今後もこれでいく。

```cpp:main.cpp
if (Internet::IsConnected()) {
	Internet::LaunchWebBrowser(L"http://aini-bellwood.jp/game/signbordfactory/manual/index.html");
}
else {
	System::LaunchFile(L".\\doc\\index.html", LaunchVerb::Open);
}
```
【EC-CUBE】プラグインでDBの値をtwigに渡す方法

[こちら](https://github.com/EC-CUBE/sample-payment-plugin)のサンプルプラグインを拡張して購入手続き画面にbase_infoのshop_nameを表示させてみます。

# TemplateEventでパラメータをセットする方法

```php:/app/Plugin/SamplePayment/SamplePaymentEvent.php
class SamplePaymentEvent implements EventSubscriberInterface
{
    private $baseInfoRepository; // クラス変数を定義

    // コンストラクタインジェクションでBaseInfoRepositoryを取得
    public function __construct(BaseInfoRepository $baseInfoRepository)
    {
        $this->baseInfoRepository = $baseInfoRepository; // クラス変数にセット
    }

    public static function getSubscribedEvents()
    {
        return [
            '@admin/Order/edit.twig' => 'onAdminOrderEditTwig',
            'Shopping/index.twig' => 'onShoppingIndexTwig', // イベントを追加
        ];
    }

    // ...

    public function onShoppingIndexTwig(TemplateEvent $event)
    {
        $BaseInfo = $this->baseInfoRepository->find(1);
        $event->setParameter('BaseInfo', $BaseInfo); // パラメータに値をセット
    }
}
```

上記で `Shopping/index.twig' にて `BaseInfo` で参照可能になる。
独自ブロックで参照したい場合はスニペットで引数として渡してやる必要がある。

```twig:
{# ... #}

{{ eccube_block_sample_payment_credit_form({ Order: Order, form: form, BaseInfo: BaseInfo}) }}

{# ... #}
```

これでブロック内で参照できる

```twig:/app/Plugin/SamplePayment/Resource/template/credit.twig
{% block sample_payment_credit_form %}
    {# BaseInfoでセットした値が参照できる #}
    {{ BaseInfo.shop_name }}

    {# ... #}

{% endblock %}
```



# Form/ExtensionのbuildView関数を使う方法

```php:/app/Plugin/SamplePayment/Form/Extension/CreditCardExtention.php
class CreditCardExtention extends AbstractTypeExtension
{

    // ...

    private $baseInfoRepository; // クラス変数を定義

    // コンストラクタインジェクションでBaseInfoRepositoryを取得
    public function __construct(PaymentRepository $paymentRepository, BaseInfoRepository $baseInfoRepository)
    {
        $this->paymentRepository = $paymentRepository;
        $this->baseInfoRepository = $baseInfoRepository; // クラス変数にセット
    }

    public function buildForm(FormBuilderInterface $builder, array $options)
    {

    // ...

    }

    // buildView関数を作成
    public function buildView(FormView $view, FormInterface $form, array $options)
    {
        // 引数にFormViewが渡ってくるのでvarsに値をセット
        $view->vars['BaseInfo'] = $this->baseInfoRepository->find(1);
        parent::buildView($view, $form, $options);
    }

    // ...

}

```

```twig:/app/Plugin/SamplePayment/Resource/template/credit.twig
{% block sample_payment_credit_form %}
    {# form.varsにセットした値が入っている #}
    {{ form.vars.BaseInfo.shop_name }}

    {# ... #}

{% endblock %}
```

## 補足

`buildForm` : `createBuilder` が呼ばれたタイミングで実行される
`buildView` : `createView` が呼ばれたタイミングで実行される
閲覧中のページの H2 タグの内容を Markdown の見出しレベル2 にする書捨てスクリプト

ブラウザの Dev Tool のコンソールを開いて以下を実行します


```js
document.querySelectorAll('h2').forEach((e) => {
  console.log("## " + e.innerText);
})
```

例えば以下のページに対して実行する。

* [Markdown記法 サンプル集 - Qiita](https://qiita.com/tbpgr/items/989c6badefff69377da7)

結果は以下になる。

```markdown

## 見出し
## 見出し2
## 箇条書きリスト
## 番号付きリスト
## 引用
## 二重引用
## pre記法(スペース4 or タブ)
## code記法
## 強調：<em>
## 強調：<strong>
## 強調：<em> + <strong>
## 水平線
## リンク
## 定義参照リンク
## GitHub Flavored Markdown(GFM)
## GFM:リンクテキスト簡易記法
## GFM:取り消し線
## GFM:pre記法(チルダ×3)
## GFM:pre記法(バッククォート×3)
## GFM:pre記法(シンタックスハイライト)
## GFM:表組み
## GFM:ページ内リンク
## 参照
```
Pythonで指定ディレクトリをZip圧縮する

## 【経緯】
業務でC++とPythonを使うプロジェクトにアサインになりました。業務では初Pythonです。
最初はC++でZipファイル作成しようと思ったんですが、面倒だし分かりにくいし面倒だしでPythonのが良いんじゃねとなりました。（C++歴が一番長いのに）

## 【要件】
* ディレクトリごとZip圧縮する
* 作成したZipファイルはデスクトップに吐き出す
* 画像などのバイナリファイルは処理時間の割に圧縮率が低いので、圧縮をかけない
* 作成するZipファイル名は「圧縮元ディレクトリ名.zip」

## 【コード】
Pythonは[CODEPREP](https://codeprep.jp/)さんや[Progate](https://prog-8.com/)さんで無料枠の基礎部分をちらっとやったことがあるレベルです。
内容に問題があったり記述に問題があればご指摘ください。。

```python
import zipfile
from zipfile import ZipFile, ZipInfo
import os
import shutil

# 例外ファイルリスト
exclusionList = ['.png', '.jpg', '.bin', '.zip']

# 圧縮対象外の拡張子を判断する
def checkCompress(extention):
    for item in exclusionList:
        if extention == item:
            return False
    else:
        return True

# デスクトップのパスを取得        
def getDesktopPath():
    return os.getenv("HOMEDRIVE") + os.getenv("HOMEPATH") + "\\Desktop" + "\\"

# Zipファイルの作成
def createZip(path):
    zipTargets = []
    # pathからディレクトリ名を取り出す
    base = os.path.basename(path)
    # 作成するzipファイルのフルパス
    createFileName = '%s' % 'default'
    zipfilepath = os.path.abspath(getDesktopPath() + '%s.zip' % createFileName)
    print(zipfilepath)
    # walkでファイルを探す
    for dirpath, dirnames, filenames in os.walk(path):
        for filename in filenames:
            filepath = os.path.join(dirpath, filename)
            # 作成するzipファイルのパスと同じファイルは除外する
            if filepath == zipfilepath:
                continue
            arc_name = os.path.relpath(filepath, os.path.dirname(path))
            print filepath, arc_name
            zipTargets.append((filepath, arc_name))
        for dirname in dirnames:
            filepath = os.path.join(dirpath, dirname)
            arc_name = os.path.relpath(filepath, os.path.dirname(path)) + os.path.sep
            print filepath, arc_name
            zipTargets.append((filepath, arc_name))

    # zipファイルの作成
    zip = zipfile.ZipFile(zipfilepath, 'w')
    for filepath, name in zipTargets:
        # 一部のファイルは圧縮をかけずに元ファイルのままZipに追加
        nameStr, extention = os.path.splitext(name)
        if checkCompress(extention):
            zip.write(filepath, name, zipfile.ZIP_DEFLATED)
        else:
            zip.write(filepath, name, zipfile.ZIP_STORED)
    zip.close()

# 圧縮元のディレクトリパス
compressTargetPath = 'compressPath'
createZip(compressTargetPath)
~~~
## 【所感】
業務＋αでちょこちょこスクリプト言語を触っていた影響か、昔ほどスクリプト言語に対して嫌悪感を抱かずにやれました。
Python割と好きです。まだ基本構文にも慣れないですが。。。特にインデントの制約に慣れない。
一年くらい前までは業務ではC++しか触らない人間でしたが、見事にC++は書けなくなってました。

## 【結論】
Pythonは良いぞ

## 【参考リンク】
* http://tnamao.hatenablog.com/entry/20101211/1292094083
* https://note.nkmk.me/python-zipfile/
City Street Orientations 街の道路の向きの調べ方

# 道路の向きを集計する

元ネタは、下記のBlogです。
>Comparing City Street Orientations - Geoff Boeing
http://geoffboeing.com/2018/07/comparing-city-street-orientations/

　[GIGAZINE](https://gigazine.net/news/20180714-city-street-orientations/)でも掲載されましたが、街の道路の向きを調べると、都市の複雑さを観察することができるというものです。

　記事のなかでは、OpenStreetMapのデータと、Pythonを使っているということですが、PostGISで挑戦してみます。

# データ入手
 OpenStreetMapのダウンロードサイトがありますので、調査したいエリアを選択して、入手します。
日本は、国全体ではなく地方毎に分割しています。

- 日本のデータのダウンロード先
 - http://download.geofabrik.de/asia/japan.html

.shp形式をダウンロードすれば、フリーのGISソフトのQGISで表示可能です。

QGISでの表示例
<img src="https://qiita-image-store.s3.amazonaws.com/0/53918/a927f9a8-88cf-7a56-1cce-ef57aa439937.png" height=70% width=70%>
[© OpenStreetMap contributors](https://www.openstreetmap.org/copyright)

# データのロード
PostGISで処理するにために、データベースに読み込む必要があります。
## 範囲選択
<img width="４00"  src="https://qiita-image-store.s3.amazonaws.com/0/53918/84e5d0ef-c2cb-227a-02e7-8d0f5831c232.png">
QGISの範囲選択ツールで調査対象エリアを囲みました。

## DBへの投入
DBツールのインポート機能を用いて、選択範囲のデータをPostgreSQLに投入します。

<img width="70%" height="70%"  src="https://qiita-image-store.s3.amazonaws.com/0/53918/de4a259f-7ee4-a44d-f5a3-05ae60dc1522.png">

<img width="80%" height="80%"  src="https://qiita-image-store.s3.amazonaws.com/0/53918/78531437-f287-c8fd-889d-6ba4dc0af71c.png">

## 集計方針
### 道路の方向の計算方法
　道路は交差点から交差点までを線で結びますが直線とは限りません。また、OpenStreetMapの道路形状は、必ず交差点で分割されているわけではありません。 

　１） 道路形状を構成する点で分割し
　２） ２点間で線分で結び、方位と線分長の算出
　３） 方位毎に線分長を集計する
　　　　　（一方通行は１倍、両方向通行道路は１８０度反転した方位でもカウント）


## 集計クエリ

```sql:count_street_orientations.sql

WITH step2 AS 
(
	-- ２点を結び、線分長と方位を計算
	SELECT
	   id 
	 , path
	 , degrees(ST_Azimuth( geom , LEAD( geom)OVER( PARTITION BY id ORDER BY path ) ) ) AS dir
	 , ST_Distance( geom::geography , LEAD( geom::geography )OVER( PARTITION BY id ORDER BY path ) ) AS dist_meter
	 , oneway
	FROM
	-- 集合体を個々の点にバラす
	(
		SELECT 
		 id , ((pd).path)[1] , (pd).geom AS geom ,oneway
		FROM 
		-- ST_DumpPointsで道路中心線を点に分割した集合体に変換
		(
			SELECT 
				id 
				, ST_DumpPoints(geom) AS pd 
				, oneway
			FROM public.tuduki_road
		) AS base
	) AS step1
) 
-- 順行・逆行の値を集計
SELECT
 degree_10 , SUM( sum )
FROM 
(
	-- 一方通行・両方通行の順方向の集計
	SELECT 
	 TRUNC( dir :: numeric , -1 ) AS degree_10 , SUM( dist_meter )
	FROM step2
	WHERE dist_meter IS NOT NULL 
	GROUP BY 1

	UNION ALL 

	-- 両方向通行の道路方向の反転し集計
	SELECT 
	 TRUNC( CASE WHEN dir :: numeric  < 180 THEN dir :: numeric  + 180  ELSE dir :: numeric  - 180 END , -1 ) AS degree_10 
	 , SUM( dist_meter ) 
	FROM step2
	WHERE dist_meter IS NOT NULL 
	 AND oneway = 'B'
	GROUP BY 1
) AS step3
GROUP BY 1
ORDER BY 1
  ;
```

## 結果
鶏頭図が手元のアプリですぐに描画できなかったので、EXCELのレーダーチャートとして出力しました

![ans.png](https://qiita-image-store.s3.amazonaws.com/0/53918/b5a87fee-c34b-4fef-6785-cadf8b2f0ddc.png)

# まとめ
簡単ではありますが、方位と道路長の集計を実施しました。
SQLでもそれっぽいことができました。
sympyで「点と線分との最短距離(perpendicular)」をquaternionでやろうとした。//solveの引数にmatrixが使えた。

(参考)点と線分との最短距離
https://qiita.com/kkdd/items/b3c5e06798e59fe2768e
(参考)sympyで線分上の最も近い点
https://qiita.com/mrrclb48z/items/dacf38b39cca8ed50b6e
(参考)アフィン変換/平行移動だって変換行列で
https://qiita.com/yuba/items/7fb6a49adfda8fa466d8
(参考)座標変換　回転行列　まとめ
https://qiita.com/MENDY/items/eeb0a4b067e596fd98dd

``` fullscript.py
(2)/2
from sympy import *
var("A B C D E")
var("x y")
var("ct st dx dy ds")
var("x1 y1")
var("x2 y2")
A =Matrix(([ct,-st,dx], [st,ct,dy], [0,0,1]))
B =Matrix(([0,0], [ds,0], [1,1]))
C =Matrix(([x1,x2], [y1,y2], [1,1]))
D =Matrix(([x], [y], [1]))
dict=solve(A*B-C, [ct,st,dx,dy])
A=A.replace(ct,dict[ct]).replace(st,dict[st]).replace(dx,dict[dx]).replace(dy,dict[dy]).replace(ct**2 + st**2,1)
print("A=",A)
E=A.inv()*D.replace(-x1+x2,x2-x1).replace(-y1+y2,y2-y1)
print("H=",E[1])
E[1]=E[1].replace(ds,sqrt( (x2-x1)**2+(y2-y1)**2))
E[1]=E[1].subs({x1:0,y1:0, x2:1, y2:1, x:0, y:1})
print("H=",E[1])
print("H=",float(E[1]))
print('-----------------------------------------------------------------------------------------')
A=A.subs(ds,sqrt( (x2-x1)**2+(y2-y1)**2))
A=A.subs({x1:0,y1:0, x2:1, y2:1, x:0, y:1})
print("A=",A)
E[0]=E[0].subs(ds,sqrt( (x2-x1)**2+(y2-y1)**2))
E[0]=E[0].subs({x1:0,y1:0, x2:1, y2:1, x:0, y:1})
E[1]=E[1].subs({x1:0,y1:0, x2:1, y2:1, x:0, y:1})
E[2]=1
A=A.subs(ds,sqrt( (x2-x1)**2+(y2-y1)**2))
F=A*E
print("E=",E)
print('HX=',float(E[0]),' HY=',float(E[1]))
# A= Matrix([[(y1 - y2)/ds, -(-x1 + x2)/ds, x2], [(-x1 + x2)/ds, (y1 - y2)/ds, y2], [0, 0, 1]])
# H= (x2*(-x1 + x2)/ds - y2*(y1 - y2)/ds)/((-x1 + x2)**2/ds**2 + (y1 - y2)**2/ds**2) - x*(-x1 + x2)/(ds*((-x1 + x2)**2/ds**2 + (y1 - y2)**2/ds**2)) + y*(y1 - y2)/(ds*((-x1 + x2)**2/ds**2 + (y1 - y2)**2/ds**2))
# H= sqrt(2)/2
# H= 0.7071067811865476
# -----------------------------------------------------------------------------------------
# A= Matrix([[-sqrt(2)/2, -sqrt(2)/2, 1], [sqrt(2)/2, -sqrt(2)/2, 1], [0, 0, 1]])
# E= Matrix([[sqrt(2)/2], [sqrt(2)/2], [1]])
# HX= 0.7071067811865476  HY= 0.7071067811865476
```
EUC-JPでserializeされた文字列をUTF-8でunserializeする。


XOOPS Cubeで文字コードをEUC-JPからUTF-8へ変更したときに、DBにEUC-JPでseriarizeした値が保存されてて、それをUTF-8で取り出したいケースがあったんで、そのときにやった方法をメモっときます。

ちなみにXOOPS Cubeでこのケースにあたったのはwaffleモジュールです。

文字列をシリアライズするとその文字列のバイト数とその文字って組み合わせで表現したテキストに変換されるので、EUC-JPでシリアライズされたデータはEUC-JPでアンシリアライズしないと、バイト長変わってしまってアンシリアライズできないんですよね。

ってことで下記の様にしてアンシリアライズしました。


```php
// 内部エンコーディングを EUC-JP にしとく
mb_internal_encoding('EUC-JP');

// DBからとってきた$data はUTF-8になってるのでEUC-JPに変換してからunserialize
$result = unserialize(mb_convert_encoding($data, 'EUC-JP', 'UTF-8'));

// unserializeされた値をUTF-8へ
// https://qiita.com/RyujiAMANO/items/3b7adb23408ad100375d に書いた関数使ってます。
$result = mb_convert_encoding_recursive($result, 'UTF-8', 'EUC-JP');

// 内部エンコーディングを元のUTF-8にもどす
mb_internal_encoding('UTF-8');
```
Apple有線キーボードの線が邪魔だったので迂回させる物体を作った

数年前のモデルのApple純正のテンキー付き有線キーボード、USBハブにもなり非常に優秀なのだが、有線であるからこそその線が邪魔だった。

![IMG_1343.JPG](https://qiita-image-store.s3.amazonaws.com/0/67153/214640ec-3b80-684e-fad9-c084df0db093.jpeg)

そこで、線を迂回させる物体を３Dモデリングし、

![stl.png](https://qiita-image-store.s3.amazonaws.com/0/67153/11856aab-e566-6aff-b83c-c37dd1e0698a.png)

３Dプリンターで出力して...

![IMG_1342.JPG](https://qiita-image-store.s3.amazonaws.com/0/67153/cd0e5033-5a3b-c2a4-fbe9-a2ee34f92b20.jpeg)

キーボードのUSBポートにぶっさして...

![IMG_1344.JPG](https://qiita-image-store.s3.amazonaws.com/0/67153/554c22a8-822f-314d-cc7c-7111bf8c616b.jpeg)
![IMG_1345.JPG](https://qiita-image-store.s3.amazonaws.com/0/67153/eed04900-6deb-d1dd-2f4d-d633625983d1.jpeg)
![IMG_1349.JPG](https://qiita-image-store.s3.amazonaws.com/0/67153/8937394c-b947-fdcd-434f-1bea737c8a7a.jpeg)


線を迂回させることに見事成功したのだった。

![IMG_1351.JPG](https://qiita-image-store.s3.amazonaws.com/0/67153/5a5a9abb-607e-4f03-ed45-0597ce6bd245.jpeg)

めでたしめでたし！
配列やオブジェクトのプロパティも再帰的に文字コード変換する mb_convert_encoding_recursiveを作ってみた


いや、車輪の再発明な感じがすっごいするけど。

オブジェクトのプロパティをまとめて文字コード変換したくて作りました。

mb_convert_variable() が使えればよかったんですが、オブジェクトに対して使うとプロパティの配列中身までは変換されなかったんでしかたなく^^;


```php
function mb_convert_encoding_recursive($mix, $toEncoding, $fromEncoding) 
{
	// 文字列ならmb_convert_encoding実行
	if (is_string($mix)) {
		return mb_convert_encoding($mix, $toEncoding, $fromEncoding);
	}
	// 配列
	if (is_array($mix)) {
		foreach ($mix as $key => $var) {
			$mix[$key] = mb_convert_encoding_recursive($var, $toEncoding, $fromEncoding);
		}
		return $mix;
	}
	// オブジェクト
	if (is_object($mix)) {
		$properties = get_object_vars($mix);
		foreach ($properties as $propertyName => $var) {
			$mix->$propertyName = mb_convert_encoding_recursive($var, $toEncoding, $fromEncoding);
		}
		return $mix;
	}
	// 上記以外ならなんもしない
	return $mix;
}
```
Angular4 -> 6 にアップデートした時にハマったこと

備忘録的に書いていきます。
もっと良いやりかたあるよ！などのご指摘大歓迎です！

まずは公式にならってアップデート
https://update.angular.io/

公式の一連の流れをやればだいたい出来てるはずなので、`ng serve`スタート！


バーン！

```
ERROR in src/app/_components/***/***.component.ts(45,28): error TS2339: Property 'json' does not exist on type 'ArrayBuffer'.
```

怒られた…

どうやらここで怒られている模様

```
let options = { headers: {'Content-Type': 'application/json'}};

this.http.post(url, body, options).subscribe(
  data => {
    this.data = data.json(); // <- エラー発生箇所
  },
  error => {
  },
);
```


`data`の中身を見てみるとそもそもnull
![スクリーンショット 2018-07-24 21.41.29.png](https://qiita-image-store.s3.amazonaws.com/0/274932/b12475c8-717a-795b-9e45-a93250d65086.png)

ググり倒して3時間。
どうやら単純にレスポンスのbodyがnullなだけみたいなんだけど、それ以前のステータスコードとかはどこいった！
てことでoptionsにobserveを追加すれば見れるようになるようだった。

```
let options = { headers: {'Content-Type': 'application/json'}, observe: "response" }; // <- observeを追加
this._http.post(url, body, options).subscribe(
  data => {
    this.data = data['body']; // <- bodyに変更
  },
  error => {
  },
);
```

でも`data['body']`って物凄く気持ち悪い。。。どうにかならないものか。
anancondaの仮想環境でpipを使うときの注意点

# はじめに
conda installできないモジュールをインストールしたいときに、pip installしてもモジュールが使えなくて困ったことがあったので注意点を書きます。

# 問題点
condaで作った仮想環境内でpip installしたモジュールがその仮想環境内で使えない。
## 具体例
仮想環境（ここでは、kasouという名前）は

```sh:terminal
> conda create -n kasou 
```

で作れます。今の所、

```sh:terminal
> conda activate kasou　# 環境によっては、source activate kasou
(kasou) > conda list


# packages in environment at /Users/usename/.pyenv/versions/anaconda3-5.1.0/envs/kasou:
#
# Name                    Version                   Build  Channel
```

とすると、何もないことがわかります。
この状態で、pip　installすると、仮想環境内ではなく、rootのpipが使われてしまうので注意が必要です。
そして、モジュールもrootに入ります。

それでは、確認してみます。
試しに、pipでopencvを入れてみます。

```sh:terminal
(kasou) > pip install opencv-python
```

この段階では、仮想環境内ではopencvは使えません。
入っているか確認するために、以下のようにimportしてみます。

```sh:terminal
(kasou) > python
Python 3.6.5 |Anaconda custom (64-bit)| (default, Apr 26 2018, 08:42:37)
[GCC 4.2.1 Compatible Clang 4.0.1 (tags/RELEASE_401/final)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import cv2
>>>
```

これで、確認できているかと言えばそうじゃないです。
仮想環境内にpythonがないので、rootのpythonをひっぱってきてます。

なので、仮想環境内にpythonを入れて確認します。

```sh:terminal
(kasou) > conda install python
(kasou) > python
Python 3.7.0 (default, Jun 28 2018, 07:39:16)
[Clang 4.0.1 (tags/RELEASE_401/final)] :: Anaconda, Inc. on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import cv2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named 'cv2'
>>>
```

すると、opencvが入っていないことが確認できます。

# 対策
仮想環境内でpipを使いたいときは、condaでpipをインストールしてから、pipを使います。

```sh:terminal
(kasou) > conda install pip
(kasou) > pip install hoge
```

# ちなみに...
## 仮想環境から出る時
仮想環境から出る時はこんな感じ。

```sh:terminal
(kasou) > conda deactivate
```
## 仮想環境を削除する時
仮想環境を削除するときはこんな感じ。

```sh:terminal
> conda remove -n kasou --all
```
# 最後に
わかってたら当たり前のことですが、はじめは気付かなかったのでまとめました。
ubuntuでMQTTブローカー「mosquitto」のインストール方法

#windows10でのmosquittoダウンロード方法

windows10でmosquittoをダウンロードする際、二つ方法がある。
一つは直接サイトからダウンロードする方法。しかし、これはdllファイルをダウンロードするなどでエラーがでてしまい、あきらめた。

そこで、二つ目のubuntuをダウンロードしてそこからパッケージインストールする方法をとった。

##ubuntuのダウンロード

参考サイト：https://coron.tech/tips/windows10-ubuntu/

このサイトに沿ってやればダウンロードできる。

##ubuntuにてmosquittoのインストール

参考サイト：https://qiita.com/kyoro353/items/b862257086fca02d3635

~~~
sudo add-apt-repository ppa:mosquitto-dev/mosquitto-ppa
~~~

~~~
sudo apt-get update
~~~

~~~
sudo apt-get install mosquitto-clients
~~~

~~~
sudo apt-get install mosquitto
~~~

##mosquittoで接続確認

三つターミナルを開く。（pub,sub,broker用)

broker用で

~~~
mosquitto
~~~

とコマンドを打ちbrokerを起動する。ブローカーを起動していないと、pub/subしてもConection refusedとでるので注意。

sub用で

~~~
mosquitto_sub -d -t test
~~~

で接続

pub用で

~~~
mosquitto_pub -d -t test -m "Hello world!"
~~~

とtestトピックに"Hello world!"をpublishする。

sub用をみて

~~~
Hello world!
~~~

とあれば成功。

以上
Gürbüz iskele

![1-koruma-sistemleri.jpg](https://qiita-image-store.s3.amazonaws.com/0/274931/16057f00-c9fe-436f-8d77-4dc721dff9fc.jpeg)

<a href="http://www.gurbuziskele.com.tr/iletisim/"> iskele </a>
<a href="http://www.gurbuziskele.com.tr/"> kiralık iskele </a>
<a href="http://www.gurbuziskele.com.tr/"> ankara kiralık iskele fiyatları </a>
<a href="http://www.gurbuziskele.com.tr/urunlerimiz/dis-cephe-iskele-sistemleri/"> dış cephe iskele sistemleri </a>
<a href="http://www.gurbuziskele.com.tr/"> iskele imalatçıları</a>

![3-süpervizör.jpg](https://qiita-image-store.s3.amazonaws.com/0/274931/d94494e4-53d6-a3cc-893f-bd8fbb551eb6.jpeg)


inşaat iskelesi, inşaat kalıp sistemleri, inşaat güvenlik sistemleri ve iskele-kalıp kiralama satın alma hizmetlerinde Gürbüz iskele 20 yıllık tecrübesiyle yanınızda. 

inşaat sektöründe tüm ihtiyaçlarınıza yanıt verebilen kullanışlı olmasının yanında, mukavemeti yüksek ve pratik kurulum özelliğine sahip iskele sistemlerinin hem üretim hem de projelendirmesini yüksek kapasite ile sürdürmekteyiz.

![4-kiralama.jpg](https://qiita-image-store.s3.amazonaws.com/0/274931/3a0724b2-c362-041e-0ec6-b0059a01bc3e.jpeg)
3階層の一番下のusersを取得したい

#会社>支店>ユーザー　みたいな関係の時一番下のユーザーを取得したい
現場でタスクをこなしている時に、
３階層の一番下のモデルオブジェクトの取得方法がわからなかったので、その備忘録。

下記のような前提。
会社：organization
支店：workspaces
ユーザー：user

```oranization.model.rb
has_many: woekspaces
```

```workspace.model.rb
has_many: users
belongs_to: organization
```

```user.model.rb
belongs_to: workspaces
```

上記の時に
会社に属した、支店に属した、ユーザーたちを取得したい。


通常のActiveRecordを使えば、２階層目までなら
```organization.workspaces```で支店は取得できる。
しかし
```organization.workspaces.users```でユーザーたちを取得しようとしてもできない。
organization.workspaces　これは配列(AR::Baseのスコープオブジェクト)が返却され、
そのスコープオブジェクトにusersメソッドはない。

#解決法
```organization.workspaces.find_by!(id: params[:workspace_id]).users.where(type_labe: “Worker”)```

上記でOK.

```organization.workspaces.find_by!(id: params[:workspace_id])```の部分のfind_byによって支店オブジェクトを一つ特定し取得。（workspace　一つに　複数のusers）

.usersで、その支店オブジェクトに所属しているユーザーたちを取得。

```.where(type_labe: “Worker")```

上記でユーザーのタイプを検索している。

＊*find_byは指定したカラム（１件のみ検索）
＊　find_by!はデータが存在しない場合に、例外を発生させる
＊　whereは検索条件に当てはまるものを***全て***取り出す

#コンソールで確認するといいです

```
rails c --sandbox

organization1 = Organization.create(name: "test1")　　←not null

workspace1 = Workspace.create(organization_id: 1)

workspace2 = Workspace.create(organization_id: 1)　

user1 = User.create(workspace_id: 1, type_label: 'worker',login_id: '1228211', password_digest: 'lfnlan8gbgggblfn')

user2 = User.create(workspace_id: 1, type_label: 'worker',login_id: '1181111', password_digest: 'lfnlanl8blfn')

organization1.workspaces

organization1.workspaces ←organization1に紐づく支店を確認

organization1.workspaces.users　←エラーになることを確認。workspacesからusersは取得できない。

organization1.workspaces.find_by!(id: 1).users ⇦　これは取得できる```

コンソールでメソッドが機能してるか確認するのは大事。
brew doctorで出たエラー”Warning: "config" scripts exist ~~~”を解決したい

#概要
Homebrewのbrew doctorで”Warning: "config" scripts exist outside your system or Homebrew directories.”が出たので，解決した．

#状況
` $ brew doctor ` で診断したら，エラーがたくさんでた．

> Warning: "config" scripts exist outside your system or Homebrew directories.
`./configure` scripts often look for *-config scripts to determine if
software packages are installed, and what additional flags to use when
compiling and linking.
> Warning: Unbrewed dylibs were found in /usr/local/lib.
> Warning: Unbrewed header files were found in /usr/local/include.
> Warning: Unbrewed .pc files were found in /usr/local/lib/pkgconfig.
> ....


- Warning:unbrewedは，「homebrewの管理下ではないファイルがあるから，消してね」という意味．無視してもあまり影響はないらしい．確認したところ，消したら色々問題が出そうなファイルばかりなので，ひとまず放置しておく．
- Warning: "config"・・・は，「Homebrewの管理してないconfigファイルがあるよ．大丈夫？」という意味．トラブルの原因になりそうなので，なんとかする．
    - 問題になったパスは`/anaconda3/bin/（ファイル名）`
    - 実際に`$ echo ${PATH}`でパスを確認したら，「/anaconda3/bin:/」が先頭にいた．

#手順
1.　`$　vi　~/.bash_profile` で，bashの設定ファイルである`.bash_profile`を編集可能にする．
※bashの起動時に読み込むのが「.bash_profile」で，画面生成時に読み込むのが「.bashrc」だそうで，自分は「.bash_profile」を使うことにしている．
2. `.bash_profile`に次の文を挿入．

```
alias brew="env PATH=${PATH/\/anaconda3\/bin:/} brew"
```
※viの編集方法を忘れた場合は，[viの基本的な使い方](https://rat.cis.k.hosei.ac.jp/article/rat/serverliteracy/2004/vi.html)を参照．

3.　`.bash_profile`を保存する．
4. ターミナルを再起動後`$　brew　doctor`して，問題の解決を確認
※ `$ source ~/.bash_profile`では，設定が反映されなかった．なぜだろう．．．


#参考資料
- phpenv入れてる時brew doctorしたら出るWarning消した. https://qiita.com/takc923/items/45386905f70fde9af0e7
-  .zshrcの編集をミスって激しく焦るの巻Add Star. http://d.hatena.ne.jp/seinzumtode/20120106/1325860901
- 【Homebrew】brew doctorのWarning対処方法 (その3) + envコマンドについて. http://www.task-notes.com/entry/20141223/1419324649
- パスを追加したい～.bashrc編～. http://www.itmedia.co.jp/help/tips/linux/l0284.html
- viの基本的な使い方. https://rat.cis.k.hosei.ac.jp/article/rat/serverliteracy/2004/vi.html
Unity 2018.x で 2Dアニメーションツールに何を使おうか...


Unity 2018.x で 2Dアニメーションツールで何を使おうかという脳内ポエム

ペラで仮組みしたものの、物足りないから2Dアニメーションをつけようかなぁ、、と思って、
Unity2018で使えそうな実装択をちょびっと思索した。

- Unity 2018 2D Animaion / IK Package 
- Anima2D
- SpriteStudio 5
- SpriteStudio 6
- AnyPortrait

Unity 2018 2D Animaion / IK Package 
---------------------------------------------------------------------------------

![スクリーンショット 2018-07-24 21.06.36.png](https://qiita-image-store.s3.amazonaws.com/0/6047/d0e0bb95-4b45-cee0-8fc2-2ac2e5c362b9.png)


Unite以降、結構Unityの中の人がふれ回ってたし、PackageManagerでもPreviewとはいえ入るし、ギリ実用かな？と思ったが、フォーラム眺めつつ軽く触った感じ、うん、ダメですね。

- サンプル
	- GitHubから：https://github.com/Unity-Technologies/2d-animation-samples
- ドキュメント
	- PackageManagerの View documentationのリンクから
- ロードマップ
	- https://forum.unity.com/threads/2d-animation-preview-packages.521778/
		- Phase1 / Phase2 に分けて開発、Phase1で様子を見て、ある程度固まってからPhase2の開発する気らしい
			- 複数パーツ対応がPhase2から...（oh...

Anima2D
---------------------------------------------------------------------------------

![スクリーンショット 2018-07-24 21.08.24.png](https://qiita-image-store.s3.amazonaws.com/0/6047/79183ea7-4380-7228-0cf7-e4f0080dfe2e.png)


開発オワってる。
中の人は上記の新システム作ってる。
Unity2017ならありだけど、2018に自力パッチしてくの？ないでしょ。

- ワークフローの例とかせっかくセガさんが丁寧に説明してくれてるのに...
	- http://techblog.sega.jp/entry/2018/03/26/100000

SpriteStudio 5
---------------------------------------------------------------------------------

![スクリーンショット 2018-07-24 21.09.40.png](https://qiita-image-store.s3.amazonaws.com/0/6047/1d384cff-2906-0601-2c57-5f425c061044.png)

SSPlayer5 for Unity の開発が相当前（Unity5系時代）にオワってる。
自力パッチしてくの？ないでしょ。

SpriteStudio 6
---------------------------------------------------------------------------------

![スクリーンショット 2018-07-24 21.12.40.png](https://qiita-image-store.s3.amazonaws.com/0/6047/22de1989-5dcd-cc27-a2c3-b47450304236.png)

Indieライセンスがver5までしかないのでお賽銭必要。とはいえ、Adobe税程度なので、一応視野には入る。
SSPlayer6 for Unity が Unity2018 で動くのか検証する必要がある & 予想組み込みコスト is 死

anyportrait
---------------------------------------------------------------------------------

![スクリーンショット 2018-07-24 21.13.51.png](https://qiita-image-store.s3.amazonaws.com/0/6047/67b1e303-56ed-2fba-7d92-bd4fd1068598.png)

求めていた機能に十分、ワークフローもよさげ。

DEMO版を試してサクッといったので、今回はこれを仮採用して試すことに。
https://assetstore.unity.com/packages/tools/animation/anyportrait-111584

夏コミ向けのリリースをこれで調整してみて、よさげならそのまま、ダメなら、また考えよう。
組み込みでQEMUを使うと何が嬉しいのか

最近QEMUについてよく耳にするようになったが、すぐ忘れるため備忘録として記載
## 実現したいこと
raspberry-piの実機がなくても、 **arm実行ファイル** の検証を行いたい。
しかし、開発に使うPCはintel CPUで、armと命令セットが違うため動かない。
## 実現方法
ユーザーランドとkernelはシステムコールで切れている。
ARM用システムコールをintel用システムコールに変換する。
## 効果
Intel CPU上で、ARMの実行ファイルが動くようになる。
Serverless Framework の schedule 差分更新バグ

### 現象

Serverless Framework （v 1.27.3） で遭遇したバグで、
scheduleを1つのAPIに対して複数定義する場合、追加定義を途中に挿入すると、定義重複とか言われて、エラーで蹴られることがある。（差分更新しようとしてるが、差分維持しようとした配列管理のschedule定義が、挿入により、新しいIndexに新規生成されたscheduleと、内部計算で算出されるARNが衝突する問題）

例：CloudWatchのトリガーをfunctionsにぶら下げて下記のように定義すると思うが、このとき、既存の定義を維持しつつ、新たな定義を間に追加すると、元々一番最後に定義していたやつが、ARN重複で更新できないよ！エラー！！とか言われることがある。

```
      - schedule:
          name: Aggregate-A-${opt:stage}
          description: 'Aggregate A'
          rate: cron(15 * * * ? *)
          enabled: true
          input:
            aggregateNodeMetricsReq:
              foo: 'bar'
      - schedule:
          name: Aggregate-B-${opt:stage}
          description: 'Aggregate B'
          rate: cron(15 * * * ? *)
          enabled: true
          input:
            aggregateNodeMetricsReq:
              foo: 'bar'
```

### 対処策

- scheduleを追加するときは常に最後に追加する
- ARN計算する要素にtimestampとかビルド番号的なのを混ぜる（ただし全トリガー再設定が走って時間かかる）
- 一旦clean or trigger全消去してから、再度設定（もっと時間がry）

APIバージョン的な環境変数用意しておいて、nameとかに付与。
普段は最後に追加して、バージョン変えるときに、整理とかいうハイブリッドな方法が現実的かも。

Issue出てる気もするし、そのうち治るかも。なければIssue出したい気もするが、MPが足りない。
EC2にSwooleをインストールする

## 概要
元々PHPの非同期処理に興味があり、PHPカンファレンス関西で[ハチャメチャに叩く - Speaker Deck](https://speakerdeck.com/uzulla/hatiyametiyanikou-ku)を聞いて来たので、これを機会に始めていきます。

## 環境構築

### PHPをインストール

```bash
yum install -y php72 php72-mbstring php72-pdo php72-devel php7-pear
```

### gccをインストール

```bash
yum install -y gcc gcc-c++
```

### [公式の手順](https://github.com/swoole/swoole-src)に従ってインストール

```bash
cd /usr/local/src
git clone https://github.com/swoole/swoole-src.git
cd swoole-src
phpize
./configure
make && make install
```

### php.iniに追記

```
extension=swoole.so
```

これで `php -i` を実行すると `Swoole` が読み込まれているのが分かります。

```bash
$ php -i | grep sw
swoole
swoole support => enabled
Author => Swoole Group[email: team@swoole.com]
swoole.aio_thread_num => 2 => 2
swoole.display_errors => On => On
swoole.fast_serialize => Off => Off
swoole.unixsock_buffer_size => 8388608 => 8388608
swoole.use_namespace => On => On
swoole.use_shortname => On => On
```

## 動かしてみる

```php:server.php
<?php
/**
 * SwooleでHTTPサーバを立てる
 * @link https://www.swoole.co.uk/
 */
define('SERVER_IP', 'IP');
define('PORT', 9501);
$http = new swoole_http_server(SERVER_IP, PORT);
$http->on('start', function ($server) {
    echo 'Swoole http server is started at ';
    echo 'http://' . SERVER_IP . ':' . PORT . PHP_EOL;
});
$http->on('request', function ($request, $response) {
    $response->header('Content-Type', 'text/plain');
    $response->end('Hello World<br>');
});
$http->start();
```

```
$ curl http://127.0.0.1:9501
Hello World<br>
```

一先ず動きました。
以上でインストールは完了です。

最後まで読んで頂きありがとうございます。

## 参考
* [公式の手順](https://github.com/swoole/swoole-src)
Googleフォームのプルダウンにスプレッドシートの内容を反映させる

備忘録としてメモします。

## はじめに
Googleフォームのプルダウン内にスプレッドシートの内容を反映させたい要望があったので対応しました。
（手打ちでスプレッドシートの内容をGoogleフォームに入力するのって面倒ですよね、、、）

## やったこと
スプレッドシート側で値の変更をして保存した場合、
今回作成したスクリプト（スプレッドシートの特定の列の内容をGoogleフォームのプルダウンに反映させる）が
実行される。

## 手順
①スプレッドシート側に適当にデータを入力する
②Googleフォーム側に適当に項目を追加する
③スクリプトを作成する
④実行する
⑤スプレッドシート側の値が変更されたら自動でスクリプトが実行されるように設定する

### ①スプレッドシート側に適当にデータを入力する
以下のように適当にデータを入力します。

![DJs.png](https://qiita-image-store.s3.amazonaws.com/0/75241/da2228ae-84b0-e273-afa1-edbf9e9254a8.png)

### ②Googleフォーム側に適当に項目を追加する
以下のように適当に項目を追加しました。

![DJアンケート.png](https://qiita-image-store.s3.amazonaws.com/0/75241/abbfbc2a-0730-c1f4-5b6c-a8a39a67f367.png)

### ③スクリプトを作成する
①で作成したスプレッドシートを開き以下の手順でスクリプトエディタを開きます。
ツール>スクリプト エディタ
そして、
以下のコードをコピペして下さい。
（※スプレッドシートとGoogleフォームのIDは、自分のものに変更して下さい）

```.js
function overwriteDjList() {
  
  /**
  // スプレッドシートの情報を取得する
  // 
  **/
  
  //スプレッドシートのID　→「https://docs.google.com/spreadsheets/d/△△△/edit#gid=0」の△△△を↓に記述
  var sheets = SpreadsheetApp.openById('△△△').getSheets();
  
  // シート1の情報を取得
  //（デフォルトのスプレッドシートの場合、シート1という名称になっています）
  var sheet = sheets[0];
  
  // スプレッドシートのA1のセルが「DJ」の場合
  if("DJ" == sheet.getRange("A1").getValue()){
    
    // A行の2行目からコンテンツをもつ最後の行までの値を配列で取得する
    var colA = sheet.getRange(2, 1, sheet.getLastRow() - 1).getValues();
  }
  
  /**
  // Googleフォームのプルダウン内の値を上書きする
  // 
  **/
  
  // GoogleフォームのIDを設定　→「https://docs.google.com/forms/d/〇〇〇/edit」の〇〇〇を↓に記述
  var form = FormApp.openById('〇〇〇');
  
  // 質問項目がプルダウンのもののみ取得
  var items = form.getItems(FormApp.ItemType.LIST);
  
  items.forEach(function(item){
    // 質問項目が「好きなDJを選択して下さい」を含むものに対して、スプレッドシートの内容を反映する
    if(item.getTitle().match(/好きなDJを選択して下さい.*$/)){
      var listItemQuestion = item.asListItem();
      var choices = [];
      
      colA.forEach(function(name){
        if(name != ""){
          choices.push(listItemQuestion.createChoice(name));
        }
      });
      
      // プルダウンの選択肢を上書きする
      listItemQuestion.setChoices(choices);
    }
  });
  
}
```

↓こんな感じ

![コード.png](https://qiita-image-store.s3.amazonaws.com/0/75241/932f61c9-c4c1-0476-c266-f32cd1cd4a32.png)

④実行する

![実行.png](https://qiita-image-store.s3.amazonaws.com/0/75241/50026be9-0174-e0b9-7346-00b622806350.png)

実行ボタンを押すと、
許可を求められる画面が出てくるかと思いますが、許可して下さい。

うまく実行できたら、
Googleフォーム画面を確認してみましょう。
下記のように、プルダウン内にスプレッドシートの内容が反映されていれば成功です。

![DJsss.png](https://qiita-image-store.s3.amazonaws.com/0/75241/714eb47d-4d47-196a-82c6-2ce72e247d16.png)

### ⑤スプレッドシート側の値が変更されたら自動でスクリプトが実行されるように設定する

スクリプトを作成したファイルを開きます。
以下のボタンを押してトリガーの設定を行います。

![トリガー.png](https://qiita-image-store.s3.amazonaws.com/0/75241/906c92a5-5ef8-72dd-0a08-41f83da44300.png)

その後以下のようにしてトリガーの設定を行って下さい。
・トリガーが設定されていません。今すぐ追加するにはここをクリックしてください。
をクリックする
↓
・以下の通りに設定を行う
実行：
　"overwriteDjList"
イベント：
　"スプレッドシートから"
　"値の変更"
↓
・保存


以上で、スプレッドシート側で値の変更をして保存した場合、
今回作成したスクリプト（スプレッドシートの特定の列の内容をGoogleフォームのプルダウンに反映させる）が実行されます。

## おわり
ちなみに、僕はSteve Aokiが好きです。
WP-CLIを使ってWordPressのマルチサイトのURLを一括置換する方法

WP-CLIの便利機能の一つ、検索置換ができる`wp search replace`を使ってマルチサイトのURL一括置換をやってみたところ以下のようにエラーがでてしまいました。

`Error: Site 'example.com' not found. Verify `--url=<url>` matches an existing site.`

やりかたは公式にも書いてあるのですが、ちょっとつまづいたので方法をご紹介します。
# マルチサイト用のデータベース変換

wp search-replace | WordPress Developer Resources https://developer.wordpress.org/cli/commands/search-replace/

マルチサイトの場合`--network` を行うことで検索置換できるらしいのですが、やってみたところデータベースエラーになりました。そこで--urlを使って置換します。

## 本番用のマルチサイトのデータベースを開発用のデータベースに変換する
`$ wp search-replace --url=example.com example.com example.dev`

本番：example.com
開発：example.dev

うまくいった！でもメインサイトのみで、子サイトはDBエラー。

## 子サイト用のtableを変換する
子サイト用のtableを置換するために--networkオプションを使ってマルチサイトの置換します。
`wp search-replace --network 'https://example.test' 'https://example.dev'`

これでメインも子サイトもうまくいきました！
子サイトが２つ以上の場合はためしていませんが、全table対象のためおそらく大丈夫なはずです。
CentOS7でiptablesが動作してるかチェックするwebapiをgolangで作ってみた

# はじめに
iptablesが動いてるかどうかを監視しようと思ったけど、stackdriverのプロセス監視とかで出来なかったのでヘルスチェックが出来るWEB APIを作ってみた。

CentOS7ではiptablesではなく、firewalldで制御する。

## 作ってみた
ソースは以下。(40行もしない程度の簡単なやつ)
https://github.com/HirokiSakonju/iptables-healthchecker

## 動作確認
コンパイルしたバイナリを配置して起動。

```bash
$ sudo ./iptables_checker &
```

### 普通に動作している状態

```bash
$ systemctl status firewalld
● firewalld.service - firewalld - dynamic firewall daemon
   Loaded: loaded (/usr/lib/systemd/system/firewalld.service; enabled; vendor preset: enabled)
   Active: active (running) since Tue 2018-07-24 10:10:57 UTC; 2min 56s ago
     Docs: man:firewalld(1)
 Main PID: 355 (firewalld)
   CGroup: /system.slice/firewalld.service
           └─355 /usr/bin/python -Es /usr/sbin/firewalld --nofork --nopid

Jul 24 10:10:56 localhost systemd[1]: Starting firewalld - dynamic firewall daemon...
Jul 24 10:10:57 localhost systemd[1]: Started firewalld - dynamic firewall daemon.
```

<img width="370" alt="スクリーンショット 2018-07-24 19.50.20.png" src="https://qiita-image-store.s3.amazonaws.com/0/33101/28b64751-19d1-9d7d-63bb-77934cec3146.png">

### firewalldが落ちたとき

```bash
$ sudo systemctl stop firewalld
$ systemctl status firewalld
● firewalld.service - firewalld - dynamic firewall daemon
   Loaded: loaded (/usr/lib/systemd/system/firewalld.service; enabled; vendor preset: enabled)
   Active: inactive (dead) since Tue 2018-07-24 10:55:41 UTC; 51s ago
     Docs: man:firewalld(1)
  Process: 355 ExecStart=/usr/sbin/firewalld --nofork --nopid $FIREWALLD_ARGS (code=exited, status=0/SUCCESS)
 Main PID: 355 (code=exited, status=0/SUCCESS)

Jul 24 10:10:56 localhost systemd[1]: Starting firewalld - dynamic firewall daemon...
Jul 24 10:10:57 localhost systemd[1]: Started firewalld - dynamic firewall daemon.
Jul 24 10:55:41 iptables-test systemd[1]: Stopping firewalld - dynamic firewall daemon...
Jul 24 10:55:41 iptables-test systemd[1]: Stopped firewalld - dynamic firewall daemon.
```

<img width="371" alt="スクリーンショット 2018-07-24 19.57.00.png" src="https://qiita-image-store.s3.amazonaws.com/0/33101/c71b1c0f-31e6-c75f-74f1-dbb6aefc5e35.png">
KotlinでforEachから抜け出す

2020年7月6日追記
現在では、`break` および `continue` が使えるようになっている模様です。
https://kotlinlang.org/docs/reference/returns.html



`forEach`ループから脱出できずにキレそうになったのでメモを残しておきます。

## 抜け出せないコード

コレを実行すると...

```kotlin
(1..10).forEach {
    println("_/_/ $it")
    if (it == 5) {
        return@forEach
    }
}
```

こうなります。

```
_/_/ 1
_/_/ 2
_/_/ 3
_/_/ 4
_/_/ 5
_/_/ 6
_/_/ 7
_/_/ 8
_/_/ 9
_/_/ 10
```

なんでやねん :persevere:

## 抜け出せるコード

こうやるみたいです。

```kotlin
run loop@ {
    (1..10).forEach {
        println("_/_/ $it")
        if (it == 5) {
            return@loop
        }
    }
}
```

実行すると...

```
_/_/ 1
_/_/ 2
_/_/ 3
_/_/ 4
_/_/ 5
```

おっけーです。

`return@forEach`は`break`ではなくて`continue`らしいですね。

こういうのは[公式リファレンス](https://dogwood008.github.io/kotlin-web-site-ja/docs/reference/returns.html)に書いておいて欲しい :droplet:

## こちらを参考にしました
'return' doesn't jump out of forEach in Kotlin
https://stackoverflow.com/questions/48056994/return-doesnt-jump-out-of-foreach-in-kotlin
インスタンスタイプをm3.large から m5.large に移行したら死んだ

# 概要

PVからHVMに変換する作業を行ったらインスタンスが起動しなくなり困った。
変換手順は公式のドキュメントを参考にした。
https://aws.amazon.com/jp/premiumsupport/knowledge-center/migrate-linux-pv-hvm/

## 環境

// TODO: ここに環境を書く
Linux 3.4.66-55.43.amzn1.x86_64 #1 SMP Wed Oct 16 06:26:26 UTC 2013

## 原因

インスタンスタイプとkernelのバージョンが離れすぎていた。
kernelが古いため、必要なドライバなどが入っていなかった。
m5シリーズなどのNITRO世代は要件が変わっており、そのまま移行すると死ぬ。

* NVMeドライバが入っていること
* ENAが有効であること

参考URL: https://dev.classmethod.jp/cloud/aws/change-type-to-m5-nitro-generation/

## 事象

インスタンスが起動しなくなる。
AWSコンソールから画面のキャプチャを取得すると、あからさまに死んでいることがわかった。

## 対応したこと

* yum updateを実行
    * おそらく--securityオプションなどを指定した方がよかったと思うが、全部updateした。今回は問題が無かったが、実際アブナイ。
* grubの設定が更新されなかったので、手動で変更した。
    * /boot/grub/menu.lst
    * /etc/grub.conf

## 所感

* ちゃんと情報を集めてから対応しようね
* 良く読んだらNITROはマグネティックを非推奨としていた
    * t2.smallなど、変換作業用のインスタンスを用いて作業した方がよかったなぁ
* NITROでなければ動作するため、必須でなければm4などを使った方が事故にならなくてよい
[初学者]既存アプリのDBをMySQLに変更する方法

# 目的 
- 以前作成したアプリのDBをMySQLに変更したときのメモ

# 条件
- ruby 2.5.1 
- Rails 5.0.3

# 手順リスト

1. Gemfileに「gem 'mysql2'」を追加
2. database.ymlの内容をMySQLに合わせる


## 1. Gemfileに「gem 'mysql2'」を追加

```ruby:Gemfile
# sqlite3のgemを削除する。
gem 'sqlite3', '1.3.12'

# mysql2のgemをバージョンを指定して追加する。
gem 'mysql2', '~> 0.4.4'
```

##### <font color='red'>gem 'mysql2'は必ずバージョン(0.4系とか)を指定すること。</font>
何も指定しないと現時点最新版（0.5.2）がインストールされます。
mysql2(バージョン0.5系)だと現時点エラーが出ます。
![Image from Gyazo](https://i.gyazo.com/30d81c31ac0e2538fcb6eb33379c780c.png)

記述が終わったら

```bash:お決まりのbundle
bundle
```

![Image from Gyazo](https://i.gyazo.com/4cb9f7e83490da4d0968012dfa56a7d1.png)

## 2. database.ymlの内容をMySQLに合わせる

`config/database.yml`がSQLiteの設定のままなのでMySQLに合わせて変更しましょう

```ruby:config/database.yml
default: &default
  adapter: mysql2
  encoding: utf8
  pool: 5
  username: root
  password:
  host: localhost


development:
  <<: *default
  database: sample_development #　DBの名前。「sample」の部分をアプリの名前に変更すると分かりやい

test:
  <<: *default
  database: sample_test #　DBの名前。「sample」の部分をアプリの名前に変更すると分かりやい

production:
  <<: *default
  database: sample_production
  username: sample_app
  password: <%= ENV['SAMPLE_DATABASE_PASSWORD'] %>
```

変更したら

```ruby:
rails db:setup

# rake db:setup # DBを作成、スキーマをロード、seedデータをロードする
```

実際に動くか確認

```bash
rails s
```
koa-ECTの環境整備

#開発環境を作る。
##node.jsのインストール
* nodistの利用

[Nodistのページ](https://github.com/marcelklehr/nodist)から、「Download the installer from the releases page」のところにあるインストーラをダウンロードしてインストールする。

コマンドプロンプトから、以下の様に実行できれば、OK
```nodist -v```
```v0.8.8``` （2016/12現在）


以下を実行してインストール出来るバージョンを調べる。
```nodist dist```

以下を実行してインストールしたいバージョンをインストールする（10.6.0の場合）
```nodist + 10.6.0```

以下を実行して、nodeの使用するバージョンを設定する（10.6.0の場合）
```nodist 10.6.0```

node.jsのバージョン確認
```node -v
v10.6.0```  （2018/07現在）

以下を実行して、nodeにあったnpmのバージョンにしておく。
```nodist npm match```

npmのバージョンの確認
```npm -v
6.1.0```  （2018/07現在）

###koaとkoa-generatorのインストール

`> npm install -g koa`
`> npm install -g koa-generator`

適当なディレクトリで以下を実行してkoaのテンプレートを作成する
`> koa KoaTest`  (プロジェクト名は任意)

プロジェクト名のディレクトリが作成されて、テンプレートが作成される
プロジェクトディレクトリ（この場合はkoaTest）へ移動する

#ECTパッケージをインストール
`koaTest> npm install -D ect`


npm installを実行する
`koaTest> npm install`



#ECTテンプレートで動作する様に修正
##app.jsの変更
viewsのdefaultをjadeからectへ変更する。
また、module.exports = app;をapp.listen(3000);に変更する。

```app.js
app.use(views('views', {
  root: __dirname + '/views',
  default: 'ect'
}));

//module.exports = app;
app.listen(3000);
```

##viewsの変更

index.jade、index.jadeの拡張子をectへ変更する
index.ect、index.ect

記述をectのものへ変更する

```layout.ect
<!DOCTYPE html>
<html>
  <head>
    <title><%= @title %></title>
    <link rel='stylesheet' href='/stylesheets/style.css' />
  </head>
  <body>
    <% content %>
  </body>
</html>
```

```index.ect
<% extend 'views/layout.ect' %>

<h1><%= @title %></h1>
<p>Welcome to <%= @title %> with ECT</p>
<hr>
<div id="container"></div>
</div>
```

以下を実行して、[http://localhost:3000](http://localhost:3000)へアクセスする。
`koaTest> node app.js`

以下の様に表示されればOK

**Hello World Koa!**
Welcome to Hello World Koa! with ECT