OmniAICreator/Qiita-1.07M huggingface dataset:
[AWS] CloudFront が使用する IP レンジを調べる

すぐわからなくなるのでメモ

```bash
curl -s https://ip-ranges.amazonaws.com/ip-ranges.json | jq  -r '.prefixes[] | select(.service=="CLOUDFRONT")
```

nginx の `set_real_ip_from` ディレクティブを生成するには以下の通り

```bash
$ curl -s https://ip-ranges.amazonaws.com/ip-ranges.json | jq  -r '.prefixes[] | select(.service=="CLOUDFRONT") | .ip_prefix' | awk '{print "set_real_ip_from " $1 ";"}'
set_real_ip_from 13.32.0.0/15;
set_real_ip_from 13.35.0.0/16;
set_real_ip_from 13.54.63.128/26;
set_real_ip_from 13.59.250.0/26;
set_real_ip_from 13.113.203.0/24;
set_real_ip_from 13.124.199.0/24;
set_real_ip_from 13.228.69.0/24;
set_real_ip_from 18.216.170.128/25;
set_real_ip_from 34.195.252.0/24;
set_real_ip_from 34.216.51.0/25;
set_real_ip_from 34.226.14.0/24;
set_real_ip_from 34.232.163.208/29;
set_real_ip_from 35.158.136.0/24;
set_real_ip_from 35.162.63.192/26;
set_real_ip_from 35.167.191.128/26;
set_real_ip_from 52.15.127.128/26;
set_real_ip_from 52.46.0.0/18;
set_real_ip_from 52.47.139.0/24;
set_real_ip_from 52.52.191.128/26;
set_real_ip_from 52.56.127.0/25;
set_real_ip_from 52.57.254.0/24;
set_real_ip_from 52.66.194.128/26;
set_real_ip_from 52.78.247.128/26;
set_real_ip_from 52.84.0.0/15;
set_real_ip_from 52.199.127.192/26;
set_real_ip_from 52.212.248.0/26;
set_real_ip_from 52.220.191.0/26;
set_real_ip_from 52.222.128.0/17;
set_real_ip_from 54.182.0.0/16;
set_real_ip_from 54.192.0.0/16;
set_real_ip_from 54.230.0.0/16;
set_real_ip_from 54.233.255.128/26;
set_real_ip_from 54.239.128.0/18;
set_real_ip_from 54.239.192.0/19;
set_real_ip_from 54.240.128.0/18;
set_real_ip_from 70.132.0.0/18;
set_real_ip_from 143.204.0.0/16;
set_real_ip_from 204.246.164.0/22;
set_real_ip_from 204.246.168.0/22;
set_real_ip_from 204.246.174.0/23;
set_real_ip_from 204.246.176.0/20;
set_real_ip_from 205.251.192.0/19;
set_real_ip_from 205.251.249.0/24;
set_real_ip_from 205.251.250.0/23;
set_real_ip_from 205.251.252.0/23;
set_real_ip_from 205.251.254.0/24;
set_real_ip_from 216.137.32.0/19;
```
Spring Boot 2.0.0 で、組み込みの Tomcat を起動しない

- SpringApplication#setWebEnvironment() が非推奨のため

```java
public class Main {
    public static void main(String[] args) {
        SpringApplication app = new SpringApplication(Main.class);
        app.setWebApplicationType(WebApplicationType.NONE);
        ApplicationContext ctx = app.run(args);
        Main main = ctx.getBean(Main.class);
        // なんか処理
    }
}
```
Wordpressでプラグイン無しでサイトマップ(XML)を作る

現在WordpressのAll in one SEOというプラグインの拡張機能でサイトマップを生成しているのだが、サイトマップ内のURLが投稿、カテゴリ、画像ファイルのリンクなど雑多になっているので、プラグイン無しでサイトマップを動的に生成する関数を作成してみた。

ここでは以下のリンクを参考に投稿、固定ページ、カテゴリ、画像ファイルのリンクを作成してみた。
https://web.contempo.jp/weblog/tips/p914

上記のリンクでは投稿、固定ページのサイトマップに対応しているので、カテゴリ、画像ファイルのサイトマップの関数をメモ。

関数はそれぞれfunctions.phpに記載していく。

###カテゴリサイトマップ

```sitemap_category.php
<?php
add_action( "create_category", "create_xml_sitemap_category" );
add_action( "delete_category", "create_xml_sitemap_category" );

function create_xml_sitemap_category() {
$args = array(
	'order' => 'DESC'
);
$sitemaps = '';
foreach( get_categories( $args ) as $post):
$sitemaps .= 
	"\t".'<url>'."\n".
    "\t\t".'<loc>'. get_category_link( $post->term_id ) .'</loc>'."\n".
    "\t\t".'<priority>1</priority>'."\n".　//任意の優先度を入力
	"\t\t".'<changefreq>monthly</changefreq>'."\n".　//任意の期間を入力
	"\t".'</url>'."\n";
endforeach; 

$sitemap = 
	'<?xml version="1.0" encoding="UTF-8"?>'."\n".
	'<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">'."\n".
	$sitemaps. 
	'</urlset>'."\n";
$fopen = fopen( ABSPATH. "sitemap_category.xml", 'w' );
fwrite($fopen, $sitemap);
fclose($fopen);
}
```

###画像サイトマップ

画像サイトマップの作成方法は以下を参照
https://support.google.com/webmasters/answer/178636?hl=ja

```sitemap_image.php
add_action( "add_attachment", "create_xml_sitemap_image" );
add_action( "edit_attachment", "create_xml_sitemap_image" );

function create_xml_sitemap_image(){
$args = array(
    'post_type' => 'attachment',
    'post_mime_type' => 'image',
    'posts_per_page' => -1,
	'order' => 'DESC'
);

$sitemaps = '';
foreach(get_posts($args) as $post) :
   $caption = $post->post_excerpt ? $post->post_excerpt : ' ';
   $title = $post->post_title ? $post->post_title : ' ';

$sitemaps .= 
"\t".'<url>'."\n".
"\t\t".' <loc>'.get_attachment_link($post->ID).'</loc>'."\n".
"\t\t".'<image:image>'."\n".
"\t\t\t".'<image:loc>'.wp_get_attachment_url($post->ID).'</image:loc>'."\n".
"\t\t\t".'<image:caption>'. htmlspecialchars($caption) .'</image:caption>'."\n".　//任意
"\t\t\t".'<image:title>'. htmlspecialchars($title) .'</image:title>'."\n". //任意
"\t\t".'</image:image>'."\n".
"\t".'</url>'."\n";
endforeach;

$sitemap = 
	'<?xml version="1.0" encoding="UTF-8"?>'."\n".
	'<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1">'."\n".
	$sitemaps. 
	'</urlset>'."\n";
$fopen = fopen( ABSPATH. "sitemap_image.xml", 'w' );
fwrite($fopen, $sitemap);
fclose($fopen);
};
```

後は https://ex.com/sitemap_category.xml, https://ex.com/sitemap_image.xml にそれぞれアクセスすると表示される。
設定ファイル読み込み

```python:sample.ini
[session]
HOST = sample
USER = sample
PASSWORD = sample
```

```pyton:sample.py
#!/usr/bin/env python
# -*- encoding: utf-8 -*-

import ConfigParser

#read ini
inifile = ConfigParser.SafeConfigParser()
inifile.read('/etc/sample.ini')

def _getini(inifile, section, name):
        try:
           return inifile.get(section, name)
        except Exception as e:
           logger.error('could not read configuration:' + name)
           sys.exit(1)

HOST = _getini(inifile, 'session', 'HOST')
USER = _getini(inifile, 'session', 'USER')
PASSWORD = _getini(inifile, 'session', 'PASSWORD')
```
[memo] Pry install

環境：```Ruby2.5.0``` ```Rails5.1.5```

## **Pry install**
```ruby:Gemfile
group :development do
  # pry
  gem 'pry-rails'
  gem 'pry-byebug'
end
```
| gem | 役割 |
|:--|:--|
| pry-rails | rails consoleでirbに代わりpryが起動する |
| pry-byebug | binding.pryでPryを起動した際、ステップ実行を実現する |

```
$ bundle install
```

## **Pryをrails consoleで起動**

```
$ rails c
Loading development environment (Rails 5.1.5)
[1] pry(main)> 
```
GitLabでLDAPSを使う

GitLabのユーザ認証にLDAPを使うケースは、社内運用なら結構あると思う。
そこで、どうせならSSL/TLSを組み合わせたLDAPSを使おうというお話

## 構築環境
* Ubuntu16.04 LTS
* GitLab v10.5.2

:warning:今回は、Let's Encryptではなく、社内のRoot CAを使ったLDAPS認証を目指す。

GitLab 10.5でLet's Encryptがものすごく使いやすくなったっぽいので、気になる人はそちらもチェック
[GitLab 10.5 released with Let's Encrypt integration](https://about.gitlab.com/2018/02/22/gitlab-10-5-released/)
[Let's Encrypt Integration ](https://docs.gitlab.com/omnibus/settings/ssl.html#let-39-s-encrypt-integration)

## 導入手順

### ルート証明書のインストール

```console
$ sudo cp hoge.crt /etc/gitlab/trusted-certs/ #hoge.crtがルート証明書

$ sudo gitlab-ctl reconfigure
```

`gitlab-ctl reconfigure`後に、`/opt/gitlab/embedded/ssl/certs/`へシンボリックリンクが作成される。
セキュリティの観点からか、シンボリックリンクの名前は乱数っぽい名前になっており、元のRoot証明書と同じファイル名でない。

### LDAPS設定
基本的に、GitLabの[LDAP設定](https://docs.gitlab.com/ce/administration/auth/ldap.html)に従うだけで良い。
ここでは通常のLDAP設定は、できているものとして一部の設定を割愛する。

```config:/etc/gitlab/gitlab.rb
gitlab_rails['ldap_enabled'] = true
gitlab_rails['ldap_servers'] = YAML.load <<-EOS # remember to close this block with 'EOS' below
main: # 'main' is the GitLab 'provider ID' of this LDAP server
  # usually 636 for SSL
  port: 636
  #   Deprecated values: "tls" was replaced with "start_tls" and "ssl" was
  #   replaced with "simple_tls".
  encryption: 'start_tls'
  verify_certificates: true
  # Specifies the path to a file containing a PEM-format CA certificate,
  # e.g. if you need to use an internal CA.
  #
  #   Example: '/etc/ca.pem'
  ca_file: ''
  # Specifies the SSL version for OpenSSL to use, if the OpenSSL default
  # is not appropriate.
  #
  #   Example: 'TLSv1_1'
  ssl_version: 'TLSv1_1'
EOS
```

* `port: 636`  
    * 通常ポート番号は636で良い。
* `encryption: 'start_tls'`
    * `start_tls` : TLSを使用する。
    * `simple_tls` : SSLを使用する。
    * `plain` : 暗号化しないので、まず設定しない。
* `verify_certificates: true`
    * 設定した証明書が正しいかLDAPサーバと認証を行う。
    * 認証しない理由がないので`true`で良い。
* `ca_file: /etc/hoge.pem`
    * 試してないけど、ここで証明書設定すればいいのかも
* `ssl_version: 'TLSv1_1'`
    * 使用するSSL/TLSのバージョン指定


### GitLabの再設定

みんな大好き`gitlab-ctl reconfigure`で終わり

```console
$ sudo gitlab-ctl reconfigure
```

終わったときには、LDAPSでユーザ認証ができる。
gcc > mystery > includeしてない関数の使用 | -Wallによる警告の表示 | -std=c99による警告の表示

```txt:動作環境
CentOS 6.8 (64bit)
  - on VMWare Workstation
Python 2.6.6 (r266:84292, Aug 18 2016, 15:13:37) 
Python 3.6.0 on virtualenv
GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)
date (GNU coreutils) 8.4 
tmux 1.6-3.el6
```

### コード

```main.c
#include <stdio.h>

int main(void)
{
	print_hello();
}
```

```print_lib.c
#include <stdio.h>

void print_hello(void)
{
	printf("hello\n");
}
```

### 実行

```bash
$ gcc main.c print_lib.c
$ ./a.out
hello
```

あれ?

main.cにおいてprint_hello()は見えないと思っていたが、上記でエラーが出ない。

何か勘違いしているのだろうか。

### gcc version

```bash
$ gcc --version
gcc (GCC) 4.4.7 20120313 (Red Hat 4.4.7-18)
Copyright (C) 2010 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE
```

### link

- [Calling a function from another file in the same directory in C](https://stackoverflow.com/questions/6618921/calling-a-function-from-another-file-in-the-same-directory-in-c)

> however I noticed that I could call a function from another file without #including it (but it's in the same directory)


### -Wallによる警告の表示

`-Wall`を追加することで警告を出せることに気づいた。

```bash
$ gcc -Wall main.c print_lib.c 
main.c: In function ‘main’:
main.c:5: warning: implicit declaration of function ‘print_hello’
main.c:6: warning: control reaches end of non-void function
```

関連: [ideone > link > -Waddressなどの警告を出す方法 > pragma指定をする](https://qiita.com/7of9/items/ad76951f7de02438e524)


### code v0.2 > ヘッダーファイル追加

```print_lib.h
#ifndef PRINT_LIB_H
#define PRINT_LIB_H

void print_hello(void);

#endif
```

```print_lib.c
#include <stdio.h>
#include "print_lib.h"

void print_hello(void)
{
	printf("hello\n");
}
```

```main.c
#include <stdio.h>
#include "print_lib.h"

int main(void)
{
	print_hello();
	return 0;
}
```

```bash
$ gcc -Wall main.c print_lib.c 
```

警告はでなくなった。
CentOS 7 gcc 7.2.0のソースファイルからのインストール

# 動作確認環境
- 仮想環境 VMware Workstation Player 14.1.1
- OS Windows 10 Pro 64bit

# 仮想環境
- OS CentOS 7.4 (1708) minimalインストール
- メモリ 2GB
- HDD 250GB

# ダウンロード・展開
`/usr/local/src`ディレクトリに移動する。

````
cd /usr/local/src
````
ソースファイルをダウンロードする。

````
wget http://ftp.tsukuba.wide.ad.jp/software/gcc/releases/gcc-7.2.0/gcc-7.2.0.tar.gz
````

ダウンロードしたファイルを展開する。

````
tar zxvf gcc-7.2.0.tar.gz
````
# コンパイル・インストール
展開したディレクトリに移動する。

````
cd gcc-7.2.0
````

CとC++をコンパイル・インストール

````
./contrib/download_prerequisites
mkdir build
cd build
../configure --enable-languages=c,c++ --prefix=/usr/local --disable-bootstrap --disable-multilib
make
make install
````

# エラー対策
`libstdc++.so.6.0.24`のエラーが発生する場合、以下のようにする。
`libstdc++.so.6.0.24-gdb.py`のファイル名を変更する。（参考しないようにする）

````
mv /usr/local/lib64/libstdc++.so.6.0.24-gdb.py /usr/local/lib64/back.libstdc++.so.6.0.24-gdb.py
````
`/usr/local/lib64`ディレクトリを参照するよう`/etc/ld.so.conf.d/`に追加する。

````
echo '/usr/local/lib64' > /etc/ld.so.conf.d/local-lib64.conf
````

# バージョン確認
gccのバージョン確認は`gcc --version`で表示される。

````
gcc (GCC) 7.2.0
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
````
g++のバージョン確認は`g++ --version`で表示される。

````
g++ (GCC) 7.2.0
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
````

# 参考
[Cコンパイラーインストールメモ(Hishidama's C compiler install Memo)](http://www.ne.jp/asahi/hishidama/home/tech/c/install.html)
[Centos7 编译安装 Nginx Mariadb Asp.net Core2 (实测 笔记 Centos 7.3 + Openssl 1.1.0f + Mariadb 10.2.7 + Nginx 1.12.1 + Asp.net. Core 2 ) - vicowong - 博客园](http://www.cnblogs.com/vicowong/p/7234714.html)

---
[目次](https://qiita.com/knutpb1205/items/3ece0cab588afdb13f02)
JavaScriptで連想配列のソート

## 流れ
「JavaScriptでオブジェクトのソートってなんかメソッドあったような。。」
「なんだっけ。。」※そもそも連想配列という言葉すら忘れている
「調べてみるとソートを自分で実装しないといけないっぽいのかな？」
「SQLのorder by的なすごい便利なのあったような気がする？」
といつもなるので備忘録。

## ライブラリ
https://lodash.com/docs/4.17.5
lodashというすごいメジャーなライブラリが便利です。

## 実装
<p data-height="820" data-theme-id="0" data-slug-hash="PQLRQB" data-default-tab="result" data-user="watabean" data-embed-version="2" data-pen-title="vue2.x orderBy" class="codepen">See the Pen <a href="https://codepen.io/watabean/pen/PQLRQB/">vue2.x orderBy</a> by watabean (<a href="https://codepen.io/watabean">@watabean</a>) on <a href="https://codepen.io">CodePen</a>.</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

## 簡単に説明
lodashのインポートはこのように記述
（今回はcodePenで書いていて↓の記述はないです）

```html
<script src="lodash.js"></script>
```

元データはこのような形

```js

    members: [
      { name: 'tanaka', age: 20 },
      { name: 'yamada', age: 25 },
      { name: 'watanabe', age: 29 },
      { name: 'watanabe', age: 27 },
      { name: 'watanabe', age: 25 },
      { name: 'kato', age: 27 },
      { name: 'sato', age: 27 },
    ]
```

１つのキー（name）でソートしたければ以下のような書き方。

```js
_.orderBy(this.members, ['name'], ['asc']);
```

２つのキー（name, age）でソートしたければ以下のような書き方になります。

```js
_.orderBy(this.members, ['name', 'age'], ['asc', 'asc']);
```

`asc`だと昇順、`desc`だと降順になります。
直感的でわかりやすいと思います。

## 関係ない話
Vue.jsだと１系ではorderByフィルタあったけど
２系からはなくなったので自分で書くか、このようにライブラリを使う形になると思います。

# 結論
JavaScriptでの連想配列のソートはlodashでやると簡単でした。

## ソース（codepenで見れるから不要だけど。。）
```html
<!DOCTYPE html>
<html lang="en" >

<head>
  <meta charset="UTF-8">
  <title>vue2.x orderBy</title>
  
  
  <link rel='stylesheet prefetch' href='https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-beta/css/bootstrap.min.css'>

  
  
</head>

<body>

<div id="app" class="container">
  <h3>元データ</h3>
  <ol>
    <li v-for="member in members">{{ member }}</li>
  </ol>
  <h3>１つのキーでソート（name）</h3>
  <ol>
    <li v-for="member in this.getMemberOrderByName">{{ member }}</li>
  </ol>
  <h3>２つのキーでソート（name, age）</h3>
  <ol>
    <li v-for="member in this.getMemberOrderByNameAge">{{ member }}</li>
  </ol>
</div>

<script src='https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.4/vue.min.js'></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.5/lodash.js'></script>

<script>
new Vue({
  el: '#app',
  data: {
    members: [
      { name: 'tanaka', age: 20 },
      { name: 'yamada', age: 25 },
      { name: 'watanabe', age: 29 },
      { name: 'watanabe', age: 27 },
      { name: 'watanabe', age: 25 },
      { name: 'kato', age: 27 },
      { name: 'sato', age: 27 },
    ]
  },
  computed: {
    getMemberOrderByName() {
      return _.orderBy(this.members, ['name'], ['asc']);
    },
    getMemberOrderByNameAge() {
      return _.orderBy(this.members, ['name', 'age'], ['asc', 'asc']);
    }
  }
})
</script>

</body>

</html>

```
Chatwork API v2を使ってRubyでメッセージを投稿する

こちらの記事を参考にしました。

https://qiita.com/tady/items/ac6de448e228a2f631db
faradayを使います。 
https://rubygems.org/gems/faraday

APIのエンドポイントのドキュメント
http://developer.chatwork.com/ja/endpoint_rooms.html#POST-rooms-room_id-messages

## サンプルコード

```ruby
require 'faraday'

ROOM_ID = '' # target chat room id
CHATWORK_TOKEN = '' # your chatwork API token

conn = Faraday::Connection.new(url: 'https://api.chatwork.com') do |builder|
  builder.use Faraday::Request::UrlEncoded
  builder.use Faraday::Response::Logger
  builder.use Faraday::Adapter::NetHttp
end

response = conn.post do |request|
  request.url "/v2/rooms/#{ROOM_ID}/messages"
  request.headers = {
    'X-ChatWorkToken' => CHATWORK_TOKEN
  }
  request.body = {
    :body => 'hogehoge' # => ここに入れる文字が投稿される
  }
end
```

文字列が長すぎたりすると400エラーが返ってくるみたいです。ちょっとはまりました。
https://qiita.com/yutaro23/items/a012de576c43effcd280

以上です。
rmコマンドのalias回避

# rmコマンドのalias回避

運用シェルスクリプトでrmコマンドは、
よく使うと思います。

ですが、linux標準では、

[.bashrc]に

```
alias rm='rm -i' .
```

と設定されているため

## 運用シェルスクリプトでは

```
rm -f <filename>
```

と強制削除をやりたくなるところですが

 rm -f (強制削除) の終了ステータスは常に「0」となるため、判定には使えない…

## なら、どうするか？

その1: unalias rm する。

その2: コマンドをフルパス (/bin/rm)で書く。

その3: ¥rm aaa.txt コマンド先頭にバックスラッシュもしくはエンマークでaliasをエスケープする。


これなら、簡単に回避出来ますね。

## ところが、どっこい…w

```
find <dir> -exec rm {} ¥;
```

もちろん、上記対策をしても
aliasが効いてしまいます。

なぜなら、execオプションは
別プロセスで実行されるため
再度、[.bashrc]が読み込まれからだ。

## だったら、

```
find <dir> | xargs rm
```

なら大丈夫じゃないかと推測して
試してみると案の定、大丈夫。

めでたし、めでたし…(σ≧▽≦)σ

## ちなみに
evalでは、

```
eval ¥rm
```

eliasは無視されない。
だが、

```
eval /bin/rm
```

だと、aliasは無視される  
う～ん！どっちなんじゃ…
LINEをライフログ用インタフェースとして使ってみる

# やること
LINEにテキストを入力したら、Google Spreadsheetに日付＋テキストの行として追記するようにしてみます。

# 背景
いままで、ライフログというと大げさですが、家計簿的に使ったお金や、筋トレ回数、ランニングのペースや距離などを記録しようとしてきました。

自動記録されるようなアプリでも、自分で何かを入力する必要があったりすると、いちいちアプリを選んで入力するのが面倒で、長続きしなかったり、入力が不正確になったりしてしまってました。

ちょっとしたデータならスプレッドシートに記録すればよいですが、スマホからスプレッドシートを開いて入力するのも面倒で、こちらも長続きしません。

入力が簡単ならもう少し長続きするのではと思って、インタフェースとしてお手軽なLINEを使ってGoogle Spreadsheetに入力するようにしてみました。

# 利用するもの

- Google Spreadsheet
- Google App Script
- LINE Messaging API


# 設定のステップ
ちょっと端折り気味ですが、設定方法を説明します。
## 1. Google Spreadsheetを用意する
記録したいスプレッドシートを選ぶ or 作り、そのスプレッドシートIDをメモします。
そのスプレッドシートの中で、LINEからの入力を書き込むシートを作り、その名前をメモします。

## 2. Google App Script上でコードを書いて公開する
Google App Scriptでプロジェクトを作り、以下のコードを貼り付けて保存します。

```
var SPREADSHEET_ID = 'ここにSpreadsheet IDを指定します';
var SHEET_NAME = 'ここにスプレッドシートのシート名を指定します';

function record(event) {
  var today =  Utilities.formatDate(new Date(), 'Asia/Tokyo', 'yyyy/M/d');
  var messageText = '（テキスト、位置情報以外のメッセージ）';
  
  if(event.message.type == 'text') {
    messageText = event.message.text;
  } else if(event.message.type == 'location') {
    messageText = event.message.address;
  }

  // シートへの追記
  var ss = SpreadsheetApp.openById(SPREADSHEET_ID);
  var sheet = ss.getSheetByName(SHEET_NAME);
  sheet.appendRow([today, messageText]);
}

function doPost(e) {
  // LINEからのメッセージ取得
  var evtArray = JSON.parse(e.postData.contents).events;

  evtArray.forEach(function(event) {
    // メッセージタイプの場合にスプレッドシートに記録
    if(event.type == "message") {
      record(event);
    }
  });

  return JSON.stringify({});
}
```
コード内の SPREADSHEET_ID、SHEET_NAME に、「1. Google Spreadsheetを用意する」でメモしたものを指定します。

そのあと、「公開」⇒「ウェブアプリケーションとして導入」を行います。
「アプリケーションにアクセスできるユーザー」は「全員（匿名ユーザーを含む）」に設定しておきます。
公開されるとその URLが表示されます。

## 3. LINE Messaging APIの設定を行う
いろいろなところに設定方法が出ているので、詳細は割愛します。
「プロバイダー」を作って、その下に今回のアプリ用の「Channel」をつくります。

- 今回のアプリはフリーの範囲で動きます
- アクセストークンの「再発行」をクリックします
- 「Webhook送信」は「利用する」にします
- Webhook URLに、Google App Scriptで公開した URLを指定し、「接続確認」を行います
- 「自動応答メッセージ」は「利用しない」にします

以上の設定を行ったら、このChannel基本設定ページの下にあるQRコードを、スマホ等のLINEアプリから読み込めば利用可能になります。
# おわりに
LINEに何か入力して応答するというプログラムではないので、一般的なBotアプリとは趣が異なりますが、こんな使い方もありうるということで、紹介してみました。
.gitignoreが反映されない

#起こったこと
プルリクをしたら6000ファイルぐらい変更をしてると表示されてしまった。
なんらかのきっかけで.gitignoreをいじってしまったらしく正しく書き直した。しかし、いくら直してもプルリクの変更したファイル数が変わらない。
ググると`git rm --cached .`と出てきたが、実行すると全てのファイルがオレンジ色になり怖くて前のcommitに戻した。調べると、複数で作業してる人はやらないほうがいいらしい。

#問題
.gitignoreを正しく記述しても反映されていない。
プルリクしたとき6000ファイルくらい変更されてしまう。
vendor/bundleあたりが多かった。

#解決方法
```
git rm -r --cached [ファイル名]
```
自分の場合は`git rm -r --cached vendor/bundle`　で解決した。

###おまけ
- pushしたあとでもプルリクを出す前であれば`git push --delete origin [ブランチ名]`でpushを戻した

- プルリクを出したあと気づいた場合はプルリクのページから公開を閉じることができる。そのあと、管理者に削除をしてもらう。




#原因（予想）
多分.gitignoreを変更しても一度書いてない状態でaddなどをしてしまうとローカルに残ってしまっていてそこの部分を消してあげないといけないのだと思う。

#参考にしたページ
https://qiita.com/axeralater/items/dd87834643f5264f8e97
https://qiita.com/ytkt/items/a2afd6be8e4f06c1ea25
https://qiita.com/konweb/items/621722f67fdd8f86a017
PHPでJavaScriptを実行

入力欄にJavaScriptを入れられるツールがあってそれを真似するにはどうしたら良いか。

自分は入力欄にJavaScriptを入れられるツールなんて作りたくないなと思っていますので使う機会があるかわかりませんがメモ。

This library is inspired in [ExecJs](https://github.com/rails/execjs), A Ruby library.

[PhpExecJs](https://github.com/nacmartin/phpexecjs)
【MySQL】auto_increment（オートインクリメント）の連番状態をリセット（初期化）する


# 本番公開前にデータを削除する

本番のDBからテストデータを削除して・・・って作業があると思います。
その時、**TRUNCATE**を遠慮なく実行できればいいんですが、できない場合もあると思います。~~知らんけど~~
その場合はたいてい**DELETE**で全件データ消す・・・って対応したりすると思うんですが、idとかに**auto_increment**使ってる場合、連番の状態が残ってしまうので厄介。
この状態もリセットしたい。

# auto_increment（オートインクリメント）の連番をリセット

**DELETE**後に以下のSQLを実行するとauto_increment（オートインクリメント）の状態がリセットされます。

```sql
ALTER TABLE `tablename` auto_increment = 1;
```

**`ALTER TABLE`**・・・テーブル定義を変更するSQL

# おわり
- 毎回忘れるから書いておきました（オレオレスニペット集）
- まあ**TRUNCATE**でいいんじゃないですかね ~~（ROLLBACKしないでしょ）~~

# 参考
- [TRUNCATEとDELETEの違い | アライドアーキテクツ エンジニアブログ](http://tech.aainc.co.jp/archives/4772)
Spring Batch


Spring Batchとは、バッチ処理をつかさどるアプリケーションフレームワークである。Springの特徴であるDIコンテナ、AOP、トランザクション管理機能をベースに、バッチ処理を実行するうえで必要な機能を提供している。

詳細はプログラムを作りながら、追って説明していきます。

# Spring Batchのプロジェクトを作る

## プロジェクトを作成する

http://start.spring.io/
でひな形のアプリケーションを作ります。
依存関係に「Batch」を追加して作成します。

## 実行する
作成したプロジェクトをそのまま実行すると以下のようなエラーが出ます。
これは、SpringBatchがジョブの状態を管理するために、データベースを利用しているために発生するものです。

```bash
Description:

Cannot determine embedded database driver class for database type NONE

Action:

If you want an embedded database please put a supported one on the classpath. If you have database settings to be loaded from a particular profile you may need to active it (no profiles are currently active).
```

## DBの設定を追加する

とりあえず動かすことを優先して、今回はH2を使ってみます。
build.gradleに以下を追加する。

```bash
    compile('com.h2database:h2')
```

application.ymlの記述を追加する

```yaml
spring:
  datasource:
    driverClassName: org.h2.Driver
    url: jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
    username: sa
    password:
```

ここまでやれば、実行する準備は完了です。

# いろいろなパターンを実装する

## 実装方法のパターン
Spring Batchを利用した実装方法には、以下２種類があります。

### タスクレットモデル
自由に処理を記述する方式である。
基本お作法にのっとれば何でも実装できます。

### チャンクモデル
大量データを効率よく処理するための機構です。
一定件数のデータをまとめて入力/加工/出力する方式。入力->加工->出力といった処理の流れを定型化し、一部を実装するだけど、ジョブを作ることができます。

## 起動方法のパターン
Spring Batchで実装したジョブは、いろいろな方法で起動することができます。

### ジョブを指定して実行する

### 定期的に実行する

### Webから非同期で実行する

# 参考サイト
https://terasoluna-batch.github.io/guideline/5.0.0.RELEASE/ja/Ch02_SpringBatchArchitecture.html
nth区切りのdivをつくる。

こういうのに遭遇する度にわすれているのでメモ📝

## 実現したいこと
3個区切りの `<div>` のまとまりをつくる。
最後のまとまりは　３個じゃなくても閉じる。
スライドショーなどの実装に。
　
例👇
![image.png](https://qiita-image-store.s3.amazonaws.com/0/27546/6a84e433-e6b8-9fac-94af-258cf98644f1.png)

## ソース
ここではTwigを使用。

```

{% set no = 0 %}
{% set lists = ['a','a','a','a','a','a','a','a','a','a','a'] %} ※11個の配列
{% set listsLength = lists|length %}

{% for list in lists %}
  {% set no = no + 1 %}
    {% if ( no%3 == 1 ) %} 
     <div class="test-wrap">
    {% endif %}

      <p>item {{ no }}</p>

    {% if ( no%3 == 0 ) %}
      </div>
    {% elseif (listsLength == no)  %}
      </div>
    {% endif %}

{% endfor %}

```
mysql utf8設定で一部の絵文字は使用可能

めちゃめちゃハマった。

## 保存できる絵文字

`[\u2600-\u26FF]` の絵文字は保存できる。
☺ ⛄ ⛅ ⚽ とか。

## 保存できない絵文字

👿とか。
保存できない系文字をjsで検出するには `[\uD800-\uDBFF][\uDC00-\uDFFF]` で正規表現かければ良い。
(いわゆるサロゲートペア)

## 保存できる絵文字一覧

☀☁☂☃☄★☆☇☈☉☊☋☌☍☎☏☐☑☒☓☔☕☖☗☘☙☚☛☜☝☞☟☠☡☢☣☤☥☦☧☨☩☪☫☬☭☮☯☰☱☲☳☴☵☶☷☸☹☺☻☼☽☾☿♀♁♂♃♄♅♆♇♈♉♊♋♌♍♎♏♐♑♒♓♔♕♖♗♘♙♚♛♜♝♞♟♠♡♢♣♤♥♦♧♨♩♪♫♬♭♮♯♰♱♲♳♴♵♶♷♸♹♺♻♼♽♾♿⚀⚁⚂⚃⚄⚅⚆⚇⚈⚉⚊⚋⚌⚍⚎⚏⚐⚑⚒⚓⚔⚕⚖⚗⚘⚙⚚⚛⚜⚝⚞⚟⚠⚡⚢⚣⚤⚥⚦⚧⚨⚩⚪⚫⚬⚭⚮⚯⚰⚱⚲⚳⚴⚵⚶⚷⚸⚹⚺⚻⚼⚽⚾⚿⛀⛁⛂⛃⛄⛅⛆⛇⛈⛉⛊⛋⛌⛍⛎⛏⛐⛑⛒⛓⛔⛕⛖⛗⛘⛙⛚⛛⛜⛝⛞⛟⛠⛡⛢⛣⛤⛥⛦⛧⛨⛩⛪⛫⛬⛭⛮⛯⛰⛱⛲⛳⛴⛵⛶⛷⛸⛹⛺⛻⛼⛽⛾⛿
pythonでAPIからJSON型データ取得・解析・変数格納(pycurl,json)

```python:pygetpost.py
import pycurl,json
from cStringIO import StringIO

#basic curl settings
curl = pycurl.Curl()
data = StringIO()

#API handling
def _curlurl(curlurl, method, exitno):
    data.truncate(0) #truncate old data
    curl.setopt(pycurl.URL, str(curlurl))
    curl.setopt(pycurl.CUSTOMREQUEST, method)
    curl.setopt(pycurl.TIMEOUT, 300) #タイムアウト値追加
    curl.setopt(pycurl.WRITEFUNCTION, data.write)
    #curl.setopt(pycurl.VERBOSE, True)
    curl.setopt(pycurl.SSL_VERIFYPEER, 0)

#curlのエラートラップ
    try:
       curl.perform()
    except Exception as e:
       print 'error occured while curling into API: ' + str(e)
       sys.exit(exitno)

#コマンド結果のエラートラップ（エラーキーはAPIによって違う）
    if json.loads(data.getvalue()).has_key("errorcode"):
       print 'errorcode: ' + json.loads(data.getvalue()).get("errorcode") + '  ||  errormessage: ' + json.loads(data.getvalue()).get("errormessage")
    else:
       return json.loads(data.getvalue())

#get value from API
url = 'https://kfjaslfjaifjaifjl//:8080'
_curlurl(url, 'POST', 1)


```
#注意
SSL_VERIFYPEERで証明書チェックを無視している。要件により証明書の場所を指定するオプションに変更する。
GAE/Node で Memcached を使おうと思ったら bitnami に出会って感動した話

# 経緯

GAE アプリケーション上で Memcache を使いたかった

↓

「たしか内包サービスみたいな感じで GAE メニューにあったなぁ」 と思い、早速[ドキュメント](https://cloud.google.com/appengine/docs/flexible/python/migrating#memcache) を読みに行ってみると...

> The Memcache service is currently not available for the App Engine flexible environment. An alpha version of the memcache service will be available shortly. If you would like to be notified when the service is available, fill out this early access form.

どうやら 2018/03/01 時点では GAE flexible 環境で利用できないみたい
（Node を使う場合は自動的に flexible 環境となる

もうすぐ使えるようになるとのことですが、いつになるかわからないため正式に実装されるまでは自前の Memcache 鯖を立てることにしました

さてどうやって立てようか…

様々なケースを調べる中、あるコミュニティで回答者がお勧めしていたのが bitnami というサービスでした

# bitnami とは

[bitnami](https://docs.bitnami.com/) は様々なアプリケーションのイメージ集 + 各種クラウドサービスへの構築をアシストしてくれるサービスです

本来であれば、自分で使用したいサービスのコンテナ化やスケーリング、ネットワーク設定等を行うところですが、これらをボタン 1 つで代行してくれます

パッケージの中には 今回使用する Memcache をはじめ、wiki、Word Press など 数多くのソリューションが用意されています

<img width="923" alt="スクリーンショット 2018-03-02 16.56.48.png" src="https://qiita-image-store.s3.amazonaws.com/0/41793/3b0ede6d-b996-b692-b756-f3e9c375d84d.png">


# bitnami の使い方

本当に簡単でした

[使いたいサービスのページ](https://bitnami.com/stack/memcached) へアクセスし、`LAUNCH IN THE CLOUD` を押す

そしてこの簡潔でわかりやすい設定項目を選択し、`CREATE` するだけ…っ！！

<img width="999" alt="スクリーンショット 2018-03-02 17.06.25.png" src="https://qiita-image-store.s3.amazonaws.com/0/41793/f3f81075-871a-0067-610c-2bd2ffa9b85e.png">


GCP に戻ってみると…

![スクリーンショット 2018-03-02 17.11.40.png](https://qiita-image-store.s3.amazonaws.com/0/41793/fc6f7933-70e9-ecb0-c5ec-ccf552ee28f3.png)


ちゃんとできてる！すごい！
ご丁寧に各種タグ付けやカスタムメタデータも設定されており、後から見直した際にそのインスタンスがどのような状態なのかひと目で分かるようになっていました

なお、クラスタ版を立てたい場合は [こちら](https://console.cloud.google.com/launcher/details/bitnami-launchpad/memcached-cluster?hl=en) から行います

# 使ってみる


## memcached-cli から

まずはアプリケーションからではなく、 [memcached-cli](https://www.npmjs.com/package/memcached-cli) を使って検証...

```
memcached-cli userName:pass@host:port

**.***.***.***:*****>set test hoge
MemJS SET: using deprecated call - arguments have changed
true
**.***.***.***:*****>get test
hoge
```

できてそう

## Node から

bitnami: memcache イメージの設定的に SASL 認証に対応したクライアントでないと動かないようです

調べた限りでは memcached-cli にも使われている [MemJS](https://github.com/alevy/memjs) というモジュールが対応していました

```text:set-cache
memcached-cli userName:pass@host:port

**.***.***.***:*****>set test huga
MemJS SET: using deprecated call - arguments have changed
true
**.***.***.***:*****>get test
huga
```

```typescript:server.ts
import * as Memjs from 'memjs';

// memcache 部分抜粋
const client = Memjs.Client.create();
client.get('test', (err: any, val: Buffer) => {
    console.log(err, val.toString());
});
```

```text:server-log
null 'huga'
```

無事 CLI でセットした値がアプリケーション側から取得できました！

# おわり

bitnami...

![cf40c9ed70a21327c23402903ad17be9_3172.jpeg](https://qiita-image-store.s3.amazonaws.com/0/41793/27b352f3-6cfe-4d6a-b30c-63dd37ee26e0.jpeg)
Sparkでパラメーターを取得する方法

クライアントからデータを取得する際、いくつかの受け渡し方法が存在します。

### リクエストパラメーター
    
URLの後に?に続いて変数を指定する方法です。
    
request.queryParamsで取得できます
        
### POSTデータ
  
リクエストボディに変数を設定する方法です。
  
request.queryParamsで取得できます。 
    
リクエストパラメーターで同じ変数名が指定されている場合は、値が上書きされてしまうため取得することはできません。    

### パスパラメーター
    
SparkではURLの一部を変数として取得することができます。

request.paramsで取得できます。


### まとめ

取得のサンプルです。
このURLを叩いたときの値の受け取り方は、

````
curl -X POST -d "postparam=hellopost" http://localhost:4567/hellopath/?urlparam=hellourl
```

取得方法は下記の通りです。

````java:
public static void main(String[] args) {

  post("/:pathparam/", (request, response) -> {
    
    System.out.println(request.param("pathparam")); // => hellopathが表示される
    System.out.println(request.queryParams("urlparam")); // => hellourlが表示される
    System.out.println(request.queryParams("postparam")); // => hellopostが表示される

    return null;
  });

}
````
RubyのAxlsxでExcelワークシートを作る(書式設定とか)

# はじめに

ちょっと前にRubyでExcelワークシートを作ることがあったので、そのまとめ。
書式設定とかその辺を中心に。

# 基本

axlsxを使う。
MacでExcelワークシートを作るライブラリとしては、一番高性能?

```{Ruby}
require 'axlsx'
p = Axlsx::Pacpage.new
wb = p.workbook
wb.insert_worksheet(0, :name => "Sheet1") do |sheet|
  sheet.add_row ['name', 'species', 'age']
  sheet.add_row ['pochi', 'dog', '10']
  sheet.add_row ['tama', 'cat', '10']
end
p.serialize 'hoge.xlsx'
```

# ワークシート関数

普通に文字列として入力すればいいみたいです。

```{Ruby}
sheet.add_row ['pochi', '=VLOOKUP(A1,Sheet1!A2:B10,2,FALSE)']
```

# 色の設定

ワークシートにスタイルを登録してから、セルを指定して適用。
多分、行とか列に対してもできるはず。

```{Ruby}
cyan = sheet.styles.add_style(bg_color: 'D9E1F2')
sheet['A1:C1'].each { |c| c.style = cyan }
```

列を追加するときにオプションで追加することもできるらしい。

```{Ruby}
sheet.add_row ['pochi', 'dog', '10'], :style => cyan
```

# 最初の行を固定

多分こんな感じ。

```{Ruby}
sheet.sheet_view.pane do |pane|
  pane.top_left_cell = "A2"
  pane.state = :frozen_split
  pane.y_split = 1
  pane.active_pane = :bottom_left
end
```

# 条件付き書式

数式で指定する場合。数式の頭に = はつけない。
数式内のセル参照は範囲の一番最初のセル基準でいいはず？

```{Ruby}
range = 'C2:C100'
params = {
  type: :expression,
  formula: 'ISNUMBER(C2)',
  dxfId: cyan,
  priority: 1,
}
sheet.add_conditional_formatting range, params
```

# 名前の定義

セル範囲に名前をつけるやつ。

```{Ruby}
wb.add_defined_name 'Sheet2!A2:A10', name: 'species'
```

# 入力規則

セルに入力できる値を制限するやつ。
リストから入力する値を選択させる場合。

```{Ruby}
range = 'B2:B100'
params = {
  type: :list,
  formula1: '=INDIRECT("specied")',  # リスト項目を記述したセル範囲
  showInputMessage: 1,
  showErrorMessage: 1,
  allowBlank: 1  # 空白を許す
}
sheet.add_data_validation range, params
```

# 列を非表示にする

1列目を非表示にする。

```{Ruby}
sheet.column_info[1].hidden
```
[Swift] ローカライズ対応する

#[Swift] ローカライズ対応する
手順：
① 新規ファイル作成より[Strings File]を選択して、「Localizable.strings」という名前のファイルを作成する。

② 作成した「Localizable.strings」をXcode上で選択して、[File inspector]-[Localize...]ボタンを押下し[Base]を選択する。

③ プロジェクトの設定の[Info]-[Localizations]-[+]ボタンを押下し、追加したい言語（Japanese）を選択する。

④ 全てに（ストーリーボードも）チェックをつけて[Finish]を押下する。

⑥ 静的に記載している文言は、「ストーリーボード.string（Japanese）」に記載する。

⑦ ソース上で動的に記載している文言は、「Localizable.strings（Japanese）」以下のルールで記載する。

```
"キー(Key)" = "値(Value)";
```
⑧ ソース上で動的に記載している箇所を、以下のように記載する。

```
var str: String = NSLocalizedString("キー(Key)", comment: "")
```
⑨ 文言取得に失敗した場合、"キー(Key)"がそのまま表示される。
バグを見つけやすようにするために、[Product]-[Scheme]-[Edit Scheme...]-[Run]-[Arguments]-[Arguments Passed On Launch]に以下を追加すると、失敗した場合に、"キー(Key)"の文字列を大文字にしてくれる。

```
-NSShowNonLocalizedStrings YES
```
[memo] MySQL5.7 install on CentOS7.4

## **MariaDBの削除**
CentOS7以降はデフォルトでMariaDBがインストールされているためアンインストールする。

インストール確認

```
$ rpm -qa | grep maria
mariadb-libs-5.5.56-2.el7.x86_64
```

アンインストール、関連ディレクトリ削除

```
$ sudo yum remove mariadb-libs
$ sudo rm -rf /var/lib/mysql
```

## **MySQL install**
リポジトリ追加

```
$ sudo rpm -Uvh http://dev.mysql.com/get/mysql57-community-release-el7-11.noarch.rpm
```

MySQL install

```
$ sudo yum install --enablerepo=mysql57-community mysql-community-server
```

バージョン確認

```
$ mysqld --version
mysqld  Ver 5.7.21 for Linux on x86_64 (MySQL Community Server (GPL))
```

自動起動設定

```
$ sudo systemctl enable mysqld.service
```

起動

```
$ sudo service mysqld start
```

## **初期設定**
### **パスワード設定**

ログに出力されている初期パスワードを用いる。

```
$ cat /var/log/mysqld.log | grep 'password is generated'
2018-02-22T03:46:29.817769Z 1 [Note] A temporary password is generated for root@localhost: hogehoge
```
※ hogehoge 部分が初期パスワード

初期パスワードでログインする。

```
$ mysql -u root -phogehoge
```

新たなパスワードを設定。
※MySQL5.7から「**大小英文字＋数字＋記号の4種を含んだ8文字以上**」がパスワードの条件になった。

```
> SET PASSWORD = 'Password-0123' ;
```

一度ログアウトし、新たなパスワードでログイン確認。

```
> exit
$ mysql -u root -pPassword-0123
```

### **tmpディレクトリ作成**
```
$ sudo mkdir -p /var/lib/mysqltmp
$ sudo chown mysql:mysql /var/lib/mysqltmp
$ sudo chmod 755 /var/lib/mysqltmp
```

MySQL 再起動

```
$ sudo service mysqld restart
```

### **補足**

下記のようなエラーを出力して起動に失敗する事がある。

```bash:/var/log/mysqld.log
[ERROR] InnoDB: The Auto-extending innodb_system data file './ibdata1' is of a different size 768 pages (rounded down to MB) than specified in the .cnf file: initial 65536 pages, max 0 (relevant if non-zero) pages!
```

「DBファイルが不適切」との事なので、初回起動時に作られたファイルを削除してから再起動させる。

```
$ sudo rm -f /var/lib/mysql/ibdata1
$ sudo rm -f /var/lib/mysql/ib_logfile0
$ sudo rm -f /var/lib/mysql/ib_logfile1
$ sudo service mysqld restart
```

以上
Ansible Persistent Connection Plugin

#Persistent Connection Plugin 概要

https://qiita.com/t-tkgh/items/79479d553784e2fe04c6

の記事で解説している通り、Ansible 2.5以降ではPlaybookを跨ぐPersistent Connectionが利用できなくなっています。

そこでCallback Pluginを作成して、
Persistent Connectionで生成されたSSHコネクションのsocketファイルを
Playbook終了前に一時的にrenameして、後続のPlaybookにも存続させたsocketファイルを使用させることでSSHコネクションを使いまわすことを実現しました。
(動作確認version：ansible 2.5.0b1、対象機器：csr1000v、python2.7とpython3.6の動作確認済み)

以下のgithubのリポジトリからcloneして利用できます。

```
git clone https://github.com/t-tkgh/persistentconnection.git
```
 
ansible 2.5以降のPersistent Connectionの仕様変更で困っている人の
とりあえずのワークアラウンドとして使ってもらえればと思います。
願わくば、Playbook間のPersistent Connectionも復活して欲しいところです。


#使用方法

①実行ファイルの格納
以下にコード記載の「persistent_connection.py」をAnsibleの実行ライブラリ配下のへ格納する。
（任意ディレクトリに格納して、ansible.cfgに格納パスを記載しても何故か機能しない…）

```
{Ansibleのライブラリ格納パス}/ansible/plugins/callback/
```
 
②ansible.cfgの変更
（/etc/ansible/ansible.cfg or 実行ディレクトリ/ansible.cfgでも可能）

```ini
callback_whitelist = persistent_connection
```

の記載を追加する

 

③実行スクリプトの変更（適宜）

- tmpdirはPersistent ConnectionのSSHコネクションのsocketファイルの格納パス情報を記載している。
デフォルトでは「/root/.ansible/pc」となっており、実行スクリプトもデフォルトの記載となっている。
PERSISTENT_CONTROL_PATH_DIRの実際の値に合わせて修正する。
  - 変更箇所 : https://github.com/t-tkgh/persistentconnection/blob/master/persistent_connection.py#L22

  
- timeoutはSSHコネクションの存続する時間である。
  persistent_connectionのtimeout値(デフォルトは10sec)に合わせているため、
　この値に合わせて修正する。
  この時、ansible.cfg 以下の値とpersistent_connection.pyのtimeoutを必ず一致させること。
  - 変更箇所：https://github.com/t-tkgh/persistentconnection/blob/master/persistent_connection.py#L24

以下はansible.cfgの記載例。 XXXを60だったり100だったりに置き換える。(sec単位)

```ini
[persistent_connection]
command_timeout=XXX
connect_timeout=XXX
connect_retry_timeout=XXX
```

④Playbookの定義
2.4以前の指定ではなく、2.5以降の新しい指定にのみ対応

varsにてjobidを指定することで、後続の他のPlaybookにおいても同じIDでそのコネクションを流用することができる。

Playbook定義例
(ios_commandモジュールにて「show interface」を実行する例)

```yaml

 - hosts: test
   gather_facts: no
   connection: network_cli
   remote_user: root
   become: yes
   become_method: enable
   vars:
     jobid: test

   tasks:
   -  name: show interface
      ios_command:
        commands: "show interface"
      register: output
```
 

インベントリの内容例

```
[test]
X.X.X.X ansible_ssh_pass=XXXXX ansible_become_pass=XXXXX ansible_network_os=ios ansible_port=22
```
rakeタスクで任意の文字列をモデル名として扱いたいときの手段

## やりたいこと

rakeタスクを実行する際に、引数を添えて、実行したい。
同時に、findやwhereなどで条件は同じで、モデル名がコロコロ変わる変数を用意したい。

つまり、

- rakeタスクに引数を複数添えたい
- rakeタスク内の記述は複数モデルに適用したい


## やったこと

まずはrakeタスクの作成

今回は画像の再アップロード用のタスクを作ります。

```
$ rails g task regenerate_images
```

生成されたrakeタスクに処理を追加していきます。

### 追加前（作成直後のrakeタスクファイル）

```ruby:regenerate_images.rake
namespace :regenerate_images do

end
```

namespaceには生成したrakeタスク名が適用されます。

### 追加後

```ruby:regenerate_images.rake

namespace :regenerate_images do
  desc 'regenerate_images_to_optimize_image_size_and_quality'
  task :selected_model, [:table_name, :id, :max_num] => :environment do |task, args|
    model_name = args[:table_name].classify.constantize
    model_name.find_each(start: args[:id], batch_size: args[:max_num].to_i) do |i|
      p "id: #{i.id}"
      begin
        i.image.cache_stored_file!
        i.image.retrieve_from_cache!(item.image.cache_name)
        i.image.recreate_versions!
        i.save!
      rescue => e
        Rails.logger.error  "ERROR: YourModel: #{i.id} -> #{e.to_s} #{e.backtrace}"
      end
    end
  end
end
```

`desc 'regenerate_images_to_optimize_image_size_and_quality'`
の部分はtaskの説明を加える記述で、タスク実行時には入力の必要はありません。

一方で、タスク一覧を表示する以下コマンドを入力した時にタスク一覧のなかで、desc内の記述が表示されます。

```
$ rake -T
```

実行結果

```
rake regenerate_images:selected_model[table_name,id,max_num]                # regenerate_item_images
```

## rakeタスクの実行

rakeタスクの実行は`$ rake namespace:task名`で可能です。

また、引数を指定したい場合は、配列に渡して、実行できます。

実際に先程お見せしたスクリプトを実行してみると、

例えば

```
$ rake regenerate_images:selected_model[products,100,500]
```

のような呼び出し方になります。


### rakeタスクの引数を複数個指定する

rakeタスクの引数を複数にしたかったので以下の記事を参考にしました。

↓
Rake タスクの作り方（引数を複数設定してみる）https://qiita.com/yoshiokaCB/items/c97ba878469701c3d99b

args[:hoge]で引数として渡した値を指定できます。
※args.hogeでも可

model_nameには、args[:table_name]を代入しているので、"products"が代入されることになります。

次に、モデル名.find_eachを実現したかったので、変数のmodel_nameに入るStringクラスの文字列がClassクラスになるように`classify`と`constantize`メソッドを用いました。

### 今回のまとめ

- rakeタスクの生成と呼び出し
- 複数引数の指定
#Quantopian Algorithm で order_target_value

## order_target_value

[order_target_value](https://www.quantopian.com/help#api-order-target-value "order_target_value")は，とある銘柄をポートフォリオに指定した額だけ保有する注文方法です．

`order_target_value(asset, amount, style=OrderType) `
>asset: Equity/Future オブジェクト
amount: 取引額．正であればLong,負であればShort．
style: 注文方法（指定方法は[order_target_value](https://www.quantopian.com/help#api-order-target-value "order_target_value")を参照）

## アルゴリズム例

（オーダー方法以外は，[#Quantopian Algorithm で order - Qiita](https://qiita.com/shinseitaro/items/4e88c0b05c3452a86fbc#%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0%E4%BE%8B "#Quantopian Algorithm で order - Qiita")にコメントで説明していますのでご参照下さい）

```python
def initialize(context):
    context.security = sid(24)
    schedule_function(rebalance, 
                      date_rule=date_rules.every_day(),
                      time_rule=time_rules.market_close(minutes = 1))

def rebalance(context, data):
    price_history = data.history(
        context.security,
        fields='price',
        bar_count=5,
        frequency='1d'
    )
    average_price = price_history.mean()
    current_price = data.current(context.security, 'price') 
    if data.can_trade(context.security):
        if current_price > (1.01 * average_price):
            # ポートフォリオに1000ドル分のアップル株を保有するように注文する．
            order_target_value(context.security, 1000)
            log.info("Buying %s" % (context.security.symbol))
        elif current_price < average_price:
            order_target(context.security, 0)
            log.info("Selling %s" % (context.security.symbol))
    
    record(current_price=current_price, average_price=average_price)

```
## メモ

order_target_valueは，[order_value](https://qiita.com/shinseitaro/items/16f0f12ad65f428c2f4b "#Quantopian Algorithm で order_value - Qiita")と同様に，株数ではなく〇〇ドル分保有する，という注文ができます．1000ドル分とは，1000ドルを超えないオーダーという意味になります．

order_valueとの違いは，ポートフォリオに〇〇ドル分保有したら，その後，注文トリガーに当たっても取引はしない，というところです．
上記コードで言えば，current_price が 5日平均価格よりも１％高ければ，アップルを1000ドル注文する，というロジックですが，もし既にポートフォリオにアップルを1000ドル分持っていれば，注文はDoneされません．この挙動は，[order_target](https://qiita.com/shinseitaro/items/f1ea0245bba1e7ccc82d "#Quantopian Algorithm で order_target - Qiita")と同じのでご参照ください．

##他のオーダー方法

[#Quantopian Algorithm で order](https://qiita.com/shinseitaro/items/4e88c0b05c3452a86fbc "#Quantopian Algorithm で order - Qiita")
[#Quantopian Algorithm で order_value](https://qiita.com/shinseitaro/items/16f0f12ad65f428c2f4b "#Quantopian Algorithm で order_value - Qiita")
[#Quantopian Algorithm で order_percent](https://qiita.com/shinseitaro/items/943cfafe00dd3841a79e "#Quantopian Algorithm で order_percent - Qiita")
[#Quantopian Algorithm で order_target](https://qiita.com/shinseitaro/items/f1ea0245bba1e7ccc82d "#Quantopian Algorithm で order_target - Qiita")
Raspberry Pi に rtmp サーバーを立てる

Raspberry Pi に rtmp ストリーミングサーバーを立てる方法です。
端末名は、violet.local とします。

ソフトのインストール

```bash
sudo apt install nginx-full
sudo apt install libnginx-mod-rtmp
```

バージョンの確認

```text
$ nginx -v
nginx version: nginx/1.18.0

$ nginx -V
nginx version: nginx/1.18.0
built with OpenSSL 1.1.1n  15 Mar 2022
TLS SNI support enabled
```

Nginx を起動

```bash
sudo systemctl start nginx
```

ブラウザーで http://violet.local  にアクセスすると、
/var/www/html/index.nginx-debian.html が表示される
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/636c13ce-967f-b29a-65e9-48362fb40d7a.png)


停止

```bash
sudo systemctl stop nginx
```


状態を調べる

```bash
sudo systemctl status nginx
```

/etc/nginx/nginx.conf の最後に次の設定をつける

```text
rtmp {
        server {
                listen 1935;
                chunk_size 4096;

                application live {
                play /var/www/nginx/html/video;
                        live on;
                        record off;
                }
        }
}
```

mp4 を保存するフォルダーを作成

```bash
sudo chmod 0777 /var/www/nginx/html
mkdir /var/www/nginx/html/video
```

/var/www/nginx/html/video にサンプルの *.mp4 を入れる

Nginx を　起動する

curl で確認

```bash
curl -o tmp01.mp4 rtmp://violet.local/live/sample.mp4
```

vlc でネットワーク越しに確認

```
vlc rtmp://violet.local/live/sample.mp4
```

次のバージョンで確認しました。

```text
$ uname -a
Linux violet 5.15.32-v8+ #1538 SMP PREEMPT Thu Mar 31 19:40:39 BST 2022 aarch64 GNU/Linux
```
誰がDestroyを呼んだのか調べる方法

## 結論

* OnDisable() 内にログ仕込めばOK

Destroyを呼んだ瞬間は非アクティブになるだけで、実体はまだ消滅していない。
実際にDestroyされるのは同フレームのLateUpdateより後のタイミングになる。

https://docs.unity3d.com/jp/530/Manual/ExecutionOrder.html

## 実験

以下のようなコンポーネントを適当なオブジェクトにつけて実行

```csharp
public class DelayDestroy : MonoBehaviour
{
    private IEnumerator Start()
    {
        yield return new WaitForSeconds(3.0f);
        Destroy(this.gameObject);
    }

    void OnDisable()
    {
        Debug.Log("スタックトレースにDestroyを呼んだコードが出る");
    }

    void OnDestroy()
    {
        Debug.Log("この行からしかスタックトレースに出ない");
    }
}
```

OnDisableの方にはDestroyが呼ばれた箇所も出力される。
![スクリーンショット 2018-03-02 17.49.29.png](https://qiita-image-store.s3.amazonaws.com/0/38840/fa99b2c2-d822-a9a0-66b0-4ab2668a2442.png)
【MySQL】カンマ区切りで登録されているキーワードに対して前方一致検索を行う


# find_in_set()かつLIKE検索みたいなことをしたい
MySQLの**`find_in_set()`**ってLIKE検索みたいなこともできると思ってたんですけどできないみたいで困った。

↓みたいなことやりたかった

```
find_in_set('word%', keyword)
```

要は**＝（イコール）のものしか取れない**んですよね。

# 仕方ないからLIKE文でがんばる

以下のようなカラム「keyword」にカンマ区切りで複数のキーワードを登録してるというテーブル「hoge」があるという想定です。

```
mysql> select * from hoge;
+----+--------------------+-----------------------------------------------+---------------------+---------------------+
| id |  name              | keyword                                       | created_at          | updated_at          |
+----+--------------------+-----------------------------------------------+---------------------+---------------------+
|  1 |  キーワード1        | キーワード1,test,keyword1                      | 2018-02-22 09:48:12 | 2018-02-22 09:48:12 |
|  2 |  キーワード2        | test2,キーワード2,keyword2                     | 2018-02-22 09:48:12 | 2018-02-22 09:48:12 |
|  3 |  キーワード3        | keyword3,キーワード3,aaa                       | 2018-02-22 09:48:12 | 2018-02-22 09:48:12 |
|  4 |  キーワード4        | キーワード4,iiiii,ooooo                        | 2018-02-22 09:48:12 | 2018-02-22 09:48:12 |
|  5 |  キーワード5        | きいわあど５,キーワード5,testarossa             | 2018-02-22 09:48:12 | 2018-02-22 09:48:12 |
+----+--------------------+-----------------------------------------------+----------------------+--------------------+
5 rows in set (0.00 sec)
```

カラム「keyword」にはどんな順番でキーワードが登録されるのかわからないので**先頭 or 2番目以降のカンマ区切りのキーワードに対して前方一致する**ように以下のように書きました。

```
mysql> select * from hoge where keyword like 'te%' or keyword like '%,te%' limit 10;
+----+--------------------+-----------------------------------------------+---------------------+---------------------+
| id |  name              | keyword                                       | created_at          | updated_at          |
+----+--------------------+-----------------------------------------------+---------------------+---------------------+
|  1 |  キーワード1        | キーワード1,test,keyword1                      | 2018-02-22 09:48:12 | 2018-02-22 09:48:12 |
|  2 |  キーワード2        | test2,キーワード2,keyword2                     | 2018-02-22 09:48:12 | 2018-02-22 09:48:12 |
|  5 |  キーワード5        | きいわあど５,キーワード5,testarossa             | 2018-02-22 09:48:12 | 2018-02-22 09:48:12 |
+----+--------------------+-----------------------------------------------+----------------------+--------------------+
```

無事取得することができた。

# おわり
- keywordが大量にあったりデータが多かったらめちゃくちゃ時間かかりそうです・・・

# 参考

- [【MySQL】カンマ区切りデータを扱う at softelメモ](https://www.softel.co.jp/blogs/tech/archives/2738)
- [[MySQL]1カラムに登録されたカンマ区切りデータを検索・抽出する方法（FIND_IN_SET） | Search Light（CakePHP PHP jQuery JavaScript CSS Linux MySQLMac）](http://www.searchlight8.com/mysql_find_in_set/)
vscode-prettier で tsx ファイルも自動的に prettier する

tsx ファイルには `typescriptreact` という Language ID が割り当てられているので、それに対しても設定を行う。

```json
{
    "editor.formatOnSave": false,
    "[typescript]": {
        "editor.formatOnSave": true
    },
    "[typescriptreact]": {
        "editor.formatOnSave": true
    }
}
```
JavaScript:しょうこりもなくFizzBuzz。   からの無限ジェネレータからの takeとか mapとか forEachっぽいものとか

[JavaScript リファレンス](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference)で調べつつ、最近の書き方でやってみた。

```Javascript:
const fizzBuzz = x => 
    x % 3 === 0 && x % 5 === 0 ? "FizzBuzz"
  : x % 3 === 0 ?  "Fizz"
  : x % 5 === 0 ?  "Buzz"
  : x
;

[...Array(100).keys()]
  .forEach( e => console.log( fizzBuzz( e+1 ) ) )
```


効率とかは考えずに取り敢えず見た目でやってます。

+ 三項演算子のネスト?好きかも。ガードっぽく見えてくる。
+ 区切りがわからなくなるらしい。```;```が要る。
+   ```[...Array(100).keys()]```  が ```[0, 1, 2...98, 99]``` ってことらしい。for文ぽいものを脳内で変換するとき便利かも。
+ .forEach()に登録する関数は要素、添字、配列の順で引数をとるらしい。この場合は要素eのみ。全部入りなら  ```(e, i, arr) => console.log( fizzBuzz( e+1 ))```  みたいに書く。引数にかっこが要る。


いっそこれでいいのかな?わかりやすい。※以下、fizzBuzz() は共通なので省略

```Javascript:
[...Array(100)]
  .map( (e, i) => fizzBuzz( i+1 ) )
  .forEach( e => console.log( e ) )
```
配列は繰り返しのための添字だけあればいいし、表示したらもう使わないので

```Javascript:
[...Array(100)]
  .forEach( (e, i) => console.log(fizzBuzz( i+1 )) )
```

いったん戻ってfor文。これはわかる

```Javascript:
for(let i = 0; i < 100; i++ ){
  console.log( fizzBuzz( i+1 ) );
}
```
ジェネレータでrange関数を作って使う

```Javascript:
function* range(n){
    for(let i = 0; i < n; i++) yield i;
}

for(const i of range(100)){
  console.log( fizzBuzz( i+1 ) );
}
```
こんなこともできるのか。いいかどうかは謎。

```Javascript:
function* range(n){
    for(let i = 0; i < n; i++) yield i;
}

[...range(100)]
  .forEach( e => console.log( fizzBuzz( e+1 ) ) )
```
ならこれは?
ひたすら関数をかけ続けるジェネレータ nest と、ジェネレータから有限個だけ取り出す take を定義して

```Javascript:
function* nest(f, x){
  let y=x;
  while(true){
    yield y
    y=f(y)
  }
}
const unlimitedRange = nest( n => n+1, 0 )

function* take(n,g){
  for(let i=0; i<n; i++)yield g.next().value
}

[...take(100, unlimitedRange ) ]
  .map( e => fizzBuzz( e+1 ) )
  .forEach( e => console.log( e ) )
```
いけるんだ...
じゃあこれ。ジェネレータを引数にして関数 f を適用しつづけるジェネレータ mapG をプラスして...

```Javascript:
function* take( n, g ) { for(let i=0; i<n; i++) yield g.next().value }
function* mapG( f, g ) { while(true) yield f( g.next().value ) }
function* nest( f, x ) {
  let y=x
  while( true ) {
    yield y
    y = f( y )
  }
}

[...take( 100, mapG( fizzBuzz, nest( n=> n+1, 1) ) ) ]
  .forEach( e => console.log( e ) )
```
mapがなくなり、これはこれですっきり。
どうせなら.forEach もなくしちゃお。何もせず、副作用だけ起こすジェネレータ attach を作って、

```JavaScript:
function* take( n, g ) { for( let i=0; i<n; i++ ) yield g.next().value }
function* mapG( f, g ) { while( true ) yield f( g.next().value ) }
function* nest( f, x ){
  let y=x
  while( true ) {
    yield y
    y = f( y )
  }
}
function* attach(f, g) {
  let x
  while(true){
    f(x = g.next().value)
    yield x
  }
}
[...take( 100, attach(console.log, mapG( fizzBuzz, nest( n=> n+1, 1) ) ) ) ]
```
わーい。forEachもなくなって一行になったー。
ASP.NET MVC5でbootstrap4.0にする

#やりたいこと
ASP.NET MVC5のプロジェクトテンプレートをbootstrap4.0にアップデートして動かす。
デフォルトはbootstrap3.0が入っている。

#作業環境
Visual Studio 2015

#作業手順
1.nugetパッケージマネージャーコンソールでbootstrap4.0をインストールします。

```console
PM> Install-Package bootstrap -Version 4.0.0 
```

参考：https://www.nuget.org/packages/Bootstrap

2.Visual StudioにインストールされているTypeScriptのバージョンが古いとビルドエラーになります。
（おそらく2.1以降でないとダメっぽい。VS2015故デフォルトでインストールされているバージョンが古い…？2017なら大丈夫です。）
　下記から最新のTypeScriptをダウンロードしてインストールします。

https://www.microsoft.com/ja-jp/download/details.aspx?id=48593

3.popper.jsというモジュールが追加されているのでBundleConfig.csに追記します。

```C#:BundleConfig.cs
            bundles.Add(new ScriptBundle("~/bundles/bootstrap").Include(
                      "~/Scripts/bootstrap.js",
                      "~/Scripts/umd/popper.js",
                      "~/Scripts/respond.js"));
```

このとき、umd配下のものを使用します。
理由は細かく語れるほどの理解度がありませんので省略。。

4.ナビゲーションバーの書式がbootstrap3.0と4.0で違っているので、4.0にあわせて手直しします。
　手直しせずに起動すると、ナビゲーションバーが何も表示されません。

参考：https://getbootstrap.com/docs/4.0/components/navbar/


以上で動くようになりました。

TypeScriptのあたりで意外とハマってしまったのでメモです。
4flgの三項演算子

### 旧：代入処理が１行で書けるので、ちょっとした時に使う。 
```js
let flg=( (a,b)=>(a)? (b)?3:2 :(b)?1:0 ) 
```

### 追記　こっちのほうが可読性が高い 
こんなのいかがでしょう?見た目で条件と値の対応が把握しやすい。 by @ttatsf

```js
let flg = (a,b) => a && b ? 3 : a ? 2 : b ? 1 : 0 
;
//あるいは
//let flg = (a,b) => 
//    a && b ? 3 
//  : a ? 2 
//  : b ? 1 
//  : 0 
//;

console.log(
flg('is','is').toString(2)
,flg('is',null).toString(2)  
,flg(null,'is').toString(2)
,flg(null,null).toString(2)
)//11 10 1 0
;
```