OmniAICreator/Qiita-1.07M huggingface dataset:
受信したメールをPHPで解析してDBに格納する

# はじめに
CentOS上で、メールサーバが受信したメールをPHPで解析して、内容をPostgreSQLデータベースに書き込む処理を作成したときのポイントを備忘録として残す。

# メールの取り込み
Postfixで受信したメールをPHPに取り込む。
メールはPHP実行時の標準入力としてやり取りを行う。

###　Postfixの設定
aliasesにメールを受信したとき起動したいPHPを記載する。

```
○○○○○（ドメイン無しメールアドレス）: ○○○○○（メールユーザ）,"| /○×□/○×□/php /○×□○×□/○×□○×□/.../○×□.php（実行したいPHP）"

【実装例：abcde@example.co.jp宛にメールを送る場合】
abcde: mailuser,"| /usr/bin/php /opt/mail.php"
```

### PHPの記述
PHPの標準入力としてメールが受け渡される。
以下の実装例に従うと、$strMailにヘッダなどを含めメールの情報が全て入っていることになる。

```
【実装例】
$strMail = "";
$stdin = fopen("php://stdin", "r");
if (!$stdin){
	//標準入力オープンエラー
	exit();
}
while (!feof ($stdin)){
	$strMail .= fgets($stdin, 4096);
}
fclose ($stdin);
```

# メール解析
メールパーサとして「[php-mime-mail-parser](https://github.com/php-mime-mail-parser/php-mime-mail-parser)」を使用する。
インストールは色々試したが、composerを使うのがやっぱり安定。

```
【実装例】
$parser = new PhpMimeMailParser\Parser();
$parser->setText($strMail);

$subject = $parser->getHeader('subject');
$body = $parser->getMessageBody('text');
...など
```
更に本文の編集やチェックをする場合には自分で処理を記載する。

# その他
DB接続方法は[こちら](https://qiita.com/ga_ku/items/01191cc2fecf4a4313d2)を参照。

### PostgreSQLのトランザクション処理

```
$dbh = new PDO("pgsql:host=$DBHOST;port=$DBPORT;dbname=$DBNAME;user=$DBUSER;password=$DBPASS");
【トランザクション開始】
$dbh->beginTransaction();
【トランザクション終了】
$dbh->commit();
```

### 自動採番された値の取得（SQL）
トランザクション内で採番された値ならSQLで簡単に取得可能。

```
【実装例1】
INSERT INTO table名(A項目, 自動採番項目) VALUES (:A項目, currval(\'XXXXXX\'))
【実装例2】
SELECT currval(\'XXXXXX\')
※XXXXXXは、nextval等で使用している名前。
```

### プリペアドステートメント
SQL中の値をパラメータ化できる。
SQLインジェクション対策になる。

```
【実装例】
$dbh = new PDO("pgsql:host=$DBHOST;port=$DBPORT;dbname=$DBNAME;user=$DBUSER;password=$DBPASS");
$prepare = $dbh->prepare('UPDATE table名 SET status = :stat, ymd = :ymd');
$prepare->bindParam(':stat', $status, PDO::PARAM_STR);
$prepare->bindParam(':ymd', $ymd, PDO::PARAM_STR);
```

# 参考
参考にさせていただいた記事一覧（順不同）
感謝感激雨あられ
https://packagist.org/packages/php-mime-mail-parser/php-mime-mail-parser
http://big1to.com/development-note/661
https://qiita.com/keizokeizo3/items/37d6b03ed9234844c891
http://skill-up-engineering.com/2018/07/21/%E3%83%A1%E3%83%BC%E3%83%AB%E3%83%91%E3%83%BC%E3%82%B5%E3%83%BCmailparse%E3%81%A8php-mime-mail-parser%E3%81%AB%E9%96%A2%E3%81%97%E3%81%A6/
https://noumenon-th.net/programming/2016/02/16/transaction/
https://bituse.info/php/37
phpMyAdminで文字を使う時の注意

プログラミング初心者であるため、内容に誤りがあるかもしれません。
もし、誤りがあれば修正するのでどんどん指摘してください。

#phpMyAdminで文字のテーブルを作る
データベースを簡単に使うことができるphpMyAdminを使用して、テーブルを作ります。
例えば、人名を作る際は、下図です。

| 名前      |       データ型 |    長さ    |照合順序|属性|
|:-----------------|------------------:|:------------------:|:------------------:|:------------------:|
| 人名           |              CHAR |         10       |

名前は、作りたいオプション名を書く。
データ型は、文字の場合「CHAR」を選択する。
長さは、もし10の場合、最大文字数が10です。
属性は、とりあえず選択しなくても実行します。

これだけで行うと、うまくINSERTができません。
なぜなら、照合順序がほったらかしになっているからです。

#照合順序を変更する
ここで照合順序を変更する必要があります。
これができていなかったため、制作も時間がかかりました。

|照合順序|
|:------------------:|
| utf8_general_ci |

これを選択することでうまく文字がINSERTができるようになりました。

#まとめ
データベースが必要なときに、phpMyAdminが便利です。
しかし、テーブルを作るときに注意が必要です。
Autoyaメモ（途中）

流れがさっぱりわからないので殴り書き、
サードパーティーを魔改造するなら資料とコメント残して！！

**◆AutoyaEntryPoint.cs**

起動時シーンロード前にこのメソッドが呼び出されるみたい
**RuntimeInitializeOnLoadMethod**属性の**RuntimeInitializeLoadType.BeforeSceneLoad**のおかげっぽい


```
        [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
        private static void EntryPoint()
        {
            autoya = new Autoya(Application.persistentDataPath);
        }
```



◆参考URL
https://www.urablog.xyz/entry/2018/02/11/164734


**◆AutoyaConstructor.cs**

**AutoyaMainthreadDispatcher**をAddComponentしてDontDestroyに常駐にする。
（Autoyaの処理周りをこいつが担っているっぽい）

```
if (go == null)
{
    go = new GameObject("AutoyaMainthreadDispatcher");
    this.mainthreadDispatcher = go.AddComponent<AutoyaMainthreadDispatcher>();
    GameObject.DontDestroyOnLoad(go);
}
```


その後、うちのソースだとキャッシングシステムが使用可能になるまで待ち受けてから
InitialチェックしAutoya使用可能状態とする。

```
    while(!Caching.ready)
        yield return null;

    InitializeAppManifest();
    InitializeAssetBundleFeature();

    isReady = true;
}
```


**◆AppManifestImplementation.cs**
 マニフェストが初期化されキャッシュされる。

```
        private void InitializeAppManifest()
        {
            _appManifestStore = new AppManifestStore<RuntimeManifestObject, BuildManifestObject>();
        }
```


**◆アセットバンドルロード用スクリプト**
　１． `AutoyaConstructor.cs` にてAutoyaの準備完了を待つ
　２． 独自ラッパー関数`AssetBundleLoader.cs`にて


Autoya参考URL
https://sassembla.github.io/Autoya/docs/en/assetbundle0.html
Web应用程序在iOS环境中返回上一页不能自动刷新页面

## 背景
Web应用程序中，在列表页面选中并点击进入子页面处理事务，完成之后返回上一页并刷新列表是非常常规的操作。在Android环境中非常正常，然而在iOS环境中返回上一页之后并不能自动刷新页面。

## 寻找原因
其实返回的代码也只是常规的`window.history.back()`，问题还是在与浏览器方面，简单在网上搜一下就可以搜到很多的解决方法了。

## 解决
导致该原因是因为iOS的缓存机制问题，iOS对返回上一页的操作往往只会读取缓存中的页面，所以在返回到上一页的时候需要强制刷新当前页面：

```html:solution1.html
<!-- monitor the onpageshow event and set reload -->
<script type="javascript">
window.onpageshow = function(event) {
    if (event.persisted) {
        window.location.reload() 
    }
};
</script>
```

```html:solution2.html
<!-- create a new iframe to force the page different -->
<script type="javascript">
var $iframe = $('<iframe src="/favicon.ico"></iframe>').on('load', function() {
    setTimeout(function() {
        $iframe.off('load').remove()
    }, 0)
}).appendTo($('body'));
</script>
```

## 参考
[Prevent safari loading from cache when back button is clicked](https://stackoverflow.com/questions/8788802/prevent-safari-loading-from-cache-when-back-button-is-clicked)
[Is \*onbeforeunload\* cached on Safari (macOS)?](https://stackoverflow.com/questions/40727989/is-onbeforeunload-cached-on-safari-macos/40896361?noredirect=1#comment69043078_40896361)
fastlaneでマイルストーンに紐付いたIssueの一覧を取得する

自動化を進めるにあたりザッと作ったやつをメモ。

基本的には[こちらの記事](https://qiita.com/eielh/items/6890b18974180deb5c61)とほぼ同じ処理をlane化したものです。
[github_api](https://docs.fastlane.tools/actions/github_api/)のレスポンスからjsonを取り出すあたりの記述がもっさりしているのが微妙なので、もっと良い書き方あれば教えていただけると嬉しいです。

```rb:fastfile
lane :get_issues_with_milestone do |options|
    title = options[:title]
    milestone_state = options[:milestone_state]
    issue_state = options[:issue_state]

    url = YOUR_REPO # e.g. "fastlane/fastlane"
    token = YOUR_GITHUB_API_TOKEN

    # Milestoneの取得
    UI.message("Getting milestone on GitHub | Title: #{title}, State: #{milestone_state}")

    milestones_result = github_api(
      api_token: token,
      http_method: "GET",
      path: "repos/#{url}/milestones?state=#{milestone_state}"
    )

    # 指定されたタイトルに一致するものを抽出
    milestones = milestones_result[:json]
    milestone = milestones.find { |m| m['title'] == title }

    # 一致しなければ終了
    if milestone.nil? then
      UI.message("No milestones")
      next
    end

    milestone_number = milestone['number']

    UI.success("Milestone \##{milestone_number} found")
    UI.message(milestone)

    # 取得できたMilestoneの`number`をもとに、Issueを取得
    UI.message("Getting issues on GitHub | Milestone number: \##{milestone_number}, State: #{issue_state}")

    issues_result = github_api(
      api_token: token,
      http_method: "GET",
      path: "repos/#{url}/issues?milestone=#{milestone_number}&state=#{issue_state}"
    )

    issues = issues_result[:json]

    if issues.nil? then
      UI.message("No issues")
      next
    end

    UI.success("Issues found")
    UI.message(issues)
  end
```

実行結果は以下のようになります。

```sh
$ bundle exec fastlane get_issues_with_milestone milestone_title:0.0.1 milestone_state:all issue_state:all
[✔] 🚀 
[11:58:25]: ------------------------------
[11:58:25]: --- Step: default_platform ---
[11:58:25]: ------------------------------
[11:58:25]: Driving the lane 'ios get_issue_with_milestone' 🚀
[11:58:25]: Getting milestone on GitHub | Title: 0.0.1, State: all
[11:58:25]: ------------------------
[11:58:25]: --- Step: github_api ---
[11:58:25]: ------------------------
[11:58:25]: Milestone #1 found
[11:58:25]: {"url"=>"https://api.github.com/repos/some/repo/milestones/1", …}
[11:58:25]: Getting issues on GitHub | Milestone number: #1, State: all
[11:58:25]: ------------------------
[11:58:25]: --- Step: github_api ---
[11:58:25]: ------------------------
[11:58:26]: Issues found
[11:58:26]: [{"url"=>"https://api.github.com/repos/some/repo/issues/1", …}]
```

自分たちのチームでは、Release作成時に上記の方法でIssueを取得し、descriptionを自動で生成するようにしています。

ただ、Release作成の処理内にMilestoneおよびIssueの取得処理も含めると、laneの記述が長くなりがちです。
そのため、これらの処理は個別の[Custom action](https://docs.fastlane.tools/create-action/)として定義しておき、Release作成用laneはこれらを呼び出すようにして利用しています。

### Gist
  - [タイトル指定によるマイルストーン取得用Action](https://gist.github.com/gaussbeam/606fdbec2457bda2e7496adbee2dc577)
  - [マイルストーンに紐付くIssue取得用Action](https://gist.github.com/gaussbeam/eec123391e88231ce6757ed9accd58df)
IntelliJ CEでKotlin Gradleの開発環境をつくる

Android Studio以外でKotlinを書いてみたいので、IntelliJ CEをインストールして開発環境を構築してみる。

## 環境

- IntelliJ IDEA 2018.3.5 (Community Edition)
- Build #IC-183.5912.21, built on February 26, 2019
- JRE: 1.8.0_152-release-1343-b28 x86_64
- JVM: OpenJDK 64-Bit Server VM by JetBrains s.r.o
- macOS 10.14.4

## 環境構築

### 前提
既にAndroid開発環境は整ってるので、Javaインストールとかは説明しない

IntelliJ CEは `brew cask`でインストールした。

### プロジェクト作成

まずは Create new Project
IntelliJ CEを起動して Create new Project

--- 
Gradle > Kotlin(JVM) を選択してNext

<img width="869" alt="スクリーンショット 2019-03-29 11.53.43.png" src="https://qiita-image-store.s3.amazonaws.com/0/52227/de9e5994-3931-f858-2dae-c60b5e392238.png">

--- 

GroundIdとArtifactIdを入力
この２つを何に使うのかは不明！

<img width="858" alt="スクリーンショット 2019-03-29 11.44.42.png" src="https://qiita-image-store.s3.amazonaws.com/0/52227/b16ff579-4f0d-9433-9f97-90c1d554bbbc.png">

--- 

Use auto-import にチェックON

<img width="869" alt="スクリーンショット 2019-03-29 11.44.56.png" src="https://qiita-image-store.s3.amazonaws.com/0/52227/535eec59-2375-bebe-a93e-b6b0a7559600.png">

--- 

プロジェクト名を入力

<img width="869" alt="スクリーンショット 2019-03-29 11.45.12.png" src="https://qiita-image-store.s3.amazonaws.com/0/52227/9eedfd04-62bd-77b4-cadb-289390767c9d.png">

--- 

プロジェクトが開かれる
画像のkotlinディレクトリを右でメニューを表示して、 New > Kotlin File/Class

<img width="1398" alt="スクリーンショット 2019-03-29 11.51.02.png" src="https://qiita-image-store.s3.amazonaws.com/0/52227/aa85e6f8-d819-8c97-96ef-1faf1b67e663.png">

--- 

ファイル名を入力、今回はとりあえずmainと入力

<img width="461" alt="スクリーンショット 2019-03-29 11.51.18.png" src="https://qiita-image-store.s3.amazonaws.com/0/52227/08d0f54a-2853-8887-ecb6-2dbb458a1546.png">

---

あとは main.kt に簡単なコードを書いて動作するかテスト

```kotlin

fun main() {
    println("hello kotlin")
}
```

## .gitignore作成

terminalで `git init` のあとに `.gitignore` を作るんだが、簡単に作る方法が分からない。

`gibo`だと以下でできそうだが、色々と足りない気がする。
（.DS_Storeとか入ってないし）

```
gibo dump kotlin gradle jetbrains > .gitignore
```

良さげなのはGitHubの JetBrains/kotlin のgitignoreがあった。

とりあえずこれをコピペで貼り付けておけばいいんでなかろうか

kotlin/.gitignore at master · JetBrains/kotlin 
https://github.com/JetBrains/kotlin/blob/master/.gitignore

```
.DS_Store
.idea/shelf
/android.tests.dependencies
/confluence/target
/dependencies/repo
/dist
/local
/gh-pages
/ideaSDK
/clionSDK
/android-studio/sdk
out/
/tmp
workspace.xml
*.versionsBackup
/idea/testData/debugger/tinyApp/classes*
/jps-plugin/testData/kannotator
/js/js.translator/testData/out/
/js/js.translator/testData/out-min/
.gradle/
build/
!**/src/**/build
!**/test/**/build
*.iml
!**/testData/**/*.iml
.idea/libraries/Gradle*.xml
.idea/libraries/Maven*.xml
.idea/artifacts/PILL_*.xml
.idea/modules
.idea/runConfigurations/JPS_*.xml
.idea/runConfigurations/PILL_*.xml
.idea/libraries
.idea/modules.xml
.idea/gradle.xml
.idea/compiler.xml
.idea/inspectionProfiles/profiles_settings.xml
.idea/.name
.idea/artifacts/dist_auto_*
kotlin-ultimate/
node_modules/
.rpt2_cache/
libraries/tools/kotlin-test-nodejs-runner/lib/
local.properties
```

IntelliJ + Kotlin + Gradleのgitignoreのいい作り方があったら教えてほしい。
#python スクリプトに shebang を書いてファイル直接指定で実行できるようにする

なんだよこのエラーメッセージ‥と思っていたら、python コマンドを指定せずに実行して、shell として評価されていた、そんなこと、よくありませんか。

```
$ ./hello.py
./hello.py: line 2: syntax error near unexpected token `"Hello py"'
./hello.py: line 2: `print("Hello py")'
```

shebang を書けばもうそんな悲劇とはおさらばです。

```py
#!/usr/bin/env python3

print("Hello py")
```

ほらね。

```
$ chmod +x ./hello.py
```

```
$ ./hello.py  
Hello py
```

# Original by Github issue

https://github.com/YumaInaura/YumaInaura/issues/982








<!-- Update From Qiita API -->

# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ





# Twitter


https://twitter.com/YumaInaura


<!-- Update From Qiita API -->
[経過観察中]仮想マシン（VMWare）内のUbuntu18.04 でフルスクリーンにしても画面サイズが追従されない。ときどき固まる

# 環境

- マルチディスプレイ環境
- 4Kモニタ
- ホスト:Windows 10 64bit
- ゲスト:Ubuntu18.04.2 LTS

# 症状

仮想マシン起動時に小さいウインドウサイズ（800x600とか）で表示されます。ここでフルスクリーン表示した際に画面が追従してくれないことがあります。Ubuntuの解像度設定でも4Kサイズが表示されず。また、そこそこの頻度で固まります。

18.04の導入当初は問題なかったのですが、いつからか～おそらくUbuntu本体のアップデートを重ねるうちに～時々発生するようになってました。
当初は発生頻度が低かったので、問題が発生した時に再起動して対応していましたが、最近になって頻度が増えてきたので本腰を入れて調査しました。

私のググラビリティが低いのかと思いますが上位に表示される対処方法は役に立たず解決まで時間を要しました。誰かの参考になれば幸いです。

# 効果のなかった対応例

```vmware ubuntu resolution fullscreen not working``` とかで検索すると上位に以下のような対処方法が出てきますが、私の場合は全く効果ありませんでした。

- VMWare-Toolsを再インストールする
- グラフィック設定（3Dグラフィックスのアクセラレーション」にチェック、「モニタでホストの設定を使用」を選択）

![](https://i.gyazo.com/9c99dfadf3c4410835b4d563d8570b52.png)

# 効果のありそうな対応（経過観察中）

事象発生時にopen-vm-toolsサービスを再起動すると良いようです。

```bash
$ systemctl restart open-vm-tools.service
```

## 根本対応
以下が良さそうです。

open-vm-toolsサービスの設定ファイルを編集

```bash
$ sudo vi /lib/systemd/system/open-vm-tools.service
```

unitセクションに以下を追記

```bash
After=graphical.target
```

# 参照

- https://github.com/vmware/open-vm-tools/issues/303
- https://github.com/vmware/open-vm-tools/issues/253
Formについて

#Formタグでフォームを書いてみよう

###例)

```php5

<form action="{{ url('/message/add')}}" method="POST" class="form-horizontal">
  {{ csrf_field() }}
  <textarea rows="6" name="message"></textarea>
  <button type="submit" name="add">
   追加
  </button>
</form>


//route

Route::post('/message/add', function(Request $request){
});

```

###解説

```

action=送信先プログラムのURLを指定する
method=送信の際の転送方法（HTTPメソッド）を指定する

入力された情報はパラメーターとして送信されます。
取得方法はRequestクラスのプロパティ$requestとします。

{{ csrf_field() }}はcsrf(クロスサイトリクエストフォージェリ)対策の記述です。

```

#Formファサード

laravelcollective/htmlに定義されています。

###例)
```php5

 {{ Form::open(array('url' => '/test', 'method' => 'post')) }}
    <input type="text" id="name">
    <input type="submit">
  {{ Form::close() }}
```

###解説
```
action属性は'url'でPathを指定します。
method属性はメソッド名を指定します。

```

#引数を入れない場合
```
{{ Form::open() }}


→下記のように変換される。
<form method="POST" action="http://同じurl" accept-charset="UTF-8">
<input name="_token" type="hidden" value="somelongrandom string">
```

POSTメソッドを使用してフォームを開始し、
actionに現在のURLを用いて、accept-charset="UTF-8"を追加します。
また、CSRF対策にtokenが追加されます。

#ファイルをアップロードする

```
{{Form::open(['files' => true])}}


→HTMLは下記のようになりenctype="multipart/form-dataが追加される

<form method="POST" action="http://currenturl" accept-charset="UTF-8"
  enctype="multipart/form-data">
<input name="_token" type="hidden" value="somelongrandom string">
```
タスクやチケットが閉じられなくなる5つのケースと対処法

[Trac](https://trac.edgewall.org/)、[Redmine](https://www.redmine.org/)、[Trello](https://trello.com/)、[Jira](https://www.atlassian.com/software/jira)といろんなプロジェクト管理ツール（バグトラッキングツール）を使ってきました。
ここ最近では[GitHub](https://github.com)を使っていて、Issueを使って開発を行っています。
タスクをチケットやIssueといった形で管理していますが、いつも長いあいだ閉じられないチケットが発生していました。
こういったチケット、タスクについては意図的に閉じたり、閉じることができる仕組みにしていかないと残り続けることになります。
忘れ去られて残っているチケット、タスクを確認するだけでも大変な作業になることがあるので、その対処について考えてみました。

# ケース1: 完了の定義が曖昧
タスクのチケットではタスクを完了させる事が目的となります。
ですがそのチケットを見ただけではどうすれば完了かが不明確な場合があります。
特にチケットを作成する人とタスクを処理する人が異なる場合、お互いが思っている「ここがゴールだよね」と思っているところが違っているとチケットが消化されない確率が上がります。

対処としては「完了(done)の定義」を明記することです。（アジャイル開発手法の一つであるスクラム開発では「完成(done)の定義」[^1]として取り扱っています。）

ただし「完了(done)」を何にするのか、というところは難しい議論になります。「○○が動作すること」で通じる場合もあれば「○○をクリックして次のページに遷移して、○○が表示されて、○○は赤くなっていること。それをIE8（！）、FF、Chrome63で動くことの確認。」かもしれないです。

「doneの定義」で検索すると色々と出てくるので参考にしておくと良いです。
https://www.google.com/search?q=done%E3%81%AE%E5%AE%9A%E7%BE%A9

[^1]: [スクラムガイド2017](https://www.scrumguides.org/docs/scrumguide/v2017/2017-Scrum-Guide-Japanese.pdf) p15

# ケース2: 情報が少なすぎる
チケットについての情報が少なすぎる場合です。
例えば「ボタンの色を変更する」というタスクがあった場合に、どのボタンなのか、何色にするのか、という情報が無い場合です。
チケットを作成した時にはチャットや会話の流れで明らかになっていたとしても、チケットのみを見た場合に何をすれば良いのかが特定できない場合、後から見返した際に手を付けられなくなり、放置される原因になります。
ただし情報を細かく書くことはそれだけ時間を使うことにもつながります。「軽微な修正の1つのチケットを書くのに1日掛かりました」みたいなケースも見てきたので、いかに短時間で正確に、かつ必要十分な情報を伝えるか、ということがポイントになります。
この「いかに短時間で正確に、かつ必要十分な情報」については画像のキャプチャが非常に有効です。
「百聞は一見にしかず」という言葉にあるとおり、いろんな手段で良い情報を正確に伝えていきましょう。

# ケース3: 複数人がアサインされている
チケットの担当者が複数人の場合です。
複数人が携わるチケットの場合には安易に複数人をアサインしがちですが、その反面、責任が曖昧になり、チケットが放置される原因になります。
放置された原因を聞き取りをしてみると「○○さんの作業待ちだった」ですとか「○○さんがやるものだと思った」といった内容で止まりがちです。
できる限り1人で完結できるに分解し、複数人が関係する場合には複数のタスクに分割することを検討しましょう。


# ケース4: 不要なチケットを閉じる（保管しておく）仕組みがない
残念ながら放置されたチケットは定期的に閉じるか、目に付かないところに置くようにします。
そのため、定期的に閉じるためのルール作りも重要です。具体的には「3ヶ月間動きが無いチケットは無条件に閉じる」といった手立てが有効です。
ソフトウェア開発では色々と環境が変わっていく事が多いです。長い間放置されてしまったチケットでは、依存しているサービスに変更があったり、顧客の要求が変わったり、といった環境的要因から手を付けられなくなることがあります。そういったチケットは積極的に閉じてしまった方が良いです。
「やっぱり必要だった」場合には再度オープンするか、新規にチケットを立て直す方が良いです。（個人的には新規に立て直しを行い、refs #123 などで過去のチケットに関連を付けておきます）


# ケース5: 期間が長い
チケットの期間が長い場合です。見るからに1ヶ月以上掛かりそうなチケットの場合、閉じられなくなる可能性が高いです。
スクラム開発では開発期間を「スプリント」（1週間〜1ヶ月）という単位に区切って開発を行いますが、スプリントをまたぐ見込みのタスクは危険です。
スプリントをまたぎそうなほど大きいタスクの場合には、スプリントの範囲に収まるようにタスクを分解する方が良いです。

# まとめ
まとめです。下記のようなチケットには注意をしましょう。

- 完了の定義が曖昧
- 情報が少なすぎる
- 複数人がアサインされている
- 不要なチケットを閉じる（保管しておく）仕組みがない
- 期間が長い


良いソフトウェア開発ライフを！
Colaboratoryショートカット備忘録

Colaboratoryのショートカットでよく使うものを自分用にまとめておく．

接頭辞　「⌘/Ctrl + M」 があるものは，
「⌘/Ctrl + M」 を一度打ってからキーを叩く．

#セルの操作

| 動作             |       接頭辞　　 |    キー             |
|:-----------------|------------------:|:------------------:|
|選択セルを実行|| ⌘/Ctrl + Enter|
| コードセル追加　上  |    ⌘/Ctrl + M |        a        |
| コードセル追加　下  |    ⌘/Ctrl + M  |       b      |
| 選択したセルを削除  |    ⌘/Ctrl + M |        d        |
| 選択セルより前を全て実行 |   |       ⌘/Ctrl + F8     |
| 選択セル以降を全て実行 |   |       ⌘/Ctrl + F10     |
| 行番号の表示/非表示 |    ⌘/Ctrl + M |      l       |
| 出力の表示/非表示 |    ⌘/Ctrl + M |      o       |
|セル操作のRedo||⌘/Ctrl + Shift + z|
|テキストセルに変換| ⌘/Ctrl + M|m|
|コードセルに変換| ⌘/Ctrl + M|y|
|実行を中断| ⌘/Ctrl + M|i|
||||

#編集操作

| 動作             |       接頭辞　　 |    キー             |
|:-----------------|------------------:|:------------------:|
| オートコンプリート  |               |         tab      |
|アンインデント|  |Sift + Tab|
|コメントアウト|  |⌘/Ctrl + /|
|ショートカットキーの確認|⌘/Ctrl + M|h|
|ランタイムを再起動| ⌘/Ctrl + M|.|
||||
||||
【CPM 向上施策】スクロールで DFP (DoubleClick for Publishers) を表示する

#はじめに
DFP (DoubleClick for Publishers) でウェブサイトに広告枠を表示する場合、インプレッション数（広告が表示された数）に対して、クリックされる割合が高いほど、表示された広告がクリックされやすい枠とみなされて広告枠の価値が高まります。
しかし、スマートフォンなどでスクロールして見ていく縦長のサイトの場合、サイトの下の方に設置された広告はユーザーに視認されずにページから移動されてしまうことがあります。このような広告の場合、サイトの初期描画時から広告を表示していると、**見られていないのにインプレッションが加算されて広告枠の価値を下げてしまっている**と想定できます。
今回、広告価値の指標である CPM（広告表示1,000回あたりにかかる掲載コスト）を上げる施策で、**一定の位置までスクロールした場合に DFP 広告を表示させて、広告枠の無駄なインプレッションを減らす**対応を行ったので紹介したいと思います。

<font color="Red">※この記事は、すでにサイトに DFP が導入されていることを前提とします。</font>

#スクロールで DFP を表示する

実装は以下の通りです。

## HTML
```HTML:HTML
<body>
...（略）
...（略）
...（略）
...（略）
<div id="div-gpt-ad-123456789-0"></div>
...（略）
</body>
```
（スクロールで表示させたい広告枠）

## JavaScript
```JavaScript:JavaScript
var $win = $(window);
var $banner = $('#div-gpt-ad-123456789-0');

// スクロールイベント登録
$win.on('scroll.dfp1',function(){
	// 広告の最上部がウィンドウに現れる500px手前まで来たら
	if($banner.offset().top-500 < $win.scrollTop()+$win.height()) {
		// スクロールイベントを解除
		$win.off('scroll.dfp1');
		// 広告表示
		googletag.cmd.push(function() {
			googletag.defineSlot('/1234/travel/asia', [300, 250],'div-gpt-ad-123456789-0').addService(googletag.pubads());
			googletag.display("div-gpt-ad-123456789-0");
		});
	}
});
```

実装のポイントを以下に記載します。

- 広告の読み込みを見せないようにするため、広告の最上部がウィンドウに現れる前に広告表示処理を実行する
- 広告を表示した後はスクロールイベントを発生させたくないため、名前空間をもたせて登録したイベントを解除する

#まとめ
上記の実装によって、想定通り広告のインプレッションが減り、CPM 向上につながりました！
コンテンツが見られない場合の無駄な広告表示がなくなり、効率の良いサイトになりました！

#参考
- [Google アド マネージャー ヘルプ　Google サイト運営者タグの例](https://support.google.com/admanager/answer/1638622?hl=ja&ref_topic=4390040)
Heroku利用の準備手順 (1)

<h3>0. 背景</h3>
<p>
Webアプリを作って無料公開したいので、外堀から埋めています。<br>
Webに関する私の知識レベルは、素人に毛が生えた程度だと思います。<br>
尚、本記事はHerokuとはどんなサービスかを知っている前提で進めます。
<ul>
 <li>PC環境 : Windows 10 (64bit)</li>
 <li>アプリ開発環境 : Flask (Python) 想定</li>
</ul>
</p>

<h3>1. Gitのインストール</h3>
<p>
Herokuの利用には、Gitのインストールが前提条件となるようです。<br>
公式ページよりインストーラをダウンロードして、インストールします。<br>
<img width="725" alt="git_site.png" src="https://qiita-image-store.s3.amazonaws.com/0/374906/d7c4b01c-177f-a815-693f-7fa6295d29ab.png">
<b>情報ソース</b>
<ul>
 <li><a href="https://git-scm.com/">Git公式ページ</a></li>
 <li><a href="https://qiita.com/toshi-click/items/dcf3dd48fdc74c91b409">自分用 Git For Windowsのインストール手順 (参考させて頂いた記事)</a></li>
 <li><a href="https://qiita.com/kakiuchis/items/de28ff33e1728707adf5">git-bash on windowsでherokuコマンドを使う方法 (参考させて頂いた記事)</a></li>
</ul>
</p>

<h3>2. Herokuの登録</h3>
<p>
Herokuの利用には、アカウント登録が必要になります。<br>
登録画面には"Company name"欄もありますが、個人の趣味利用での登録もできます。
<img width="932" alt="heroku_site.png" src="https://qiita-image-store.s3.amazonaws.com/0/374906/6d7310e8-3520-1657-58df-003a7c8d0d5b.png">

<ul>
 <li><a href="https://jp.heroku.com/">Heroku公式ページ</a></li>
 <li><a href="https://qiita.com/Arashi/items/b2f2e01259238235e187">Heroku初心者がHello, Herokuをしてみる (参考させて頂いた記事)</a></li>
</ul>
</p>

<h3>3. Heroku CLIのインストール</h3>
<p>
多くのHeroku導入の記事には "toolbeltをインストール"とありますが、<br>
本記事の時点では Heroku Command Line Interface(CLI) になったようです。<br>
<br>
アカウント登録後の画面(下図)から順を追っていきます。<br>
(1) アプリ開発環境はFlaskを想定しているので、"Python"を選択します。
<br>
<img width="920" alt="0_afterpros.png" src="https://qiita-image-store.s3.amazonaws.com/0/374906/76e7a993-d0c5-7159-72c6-726ea6f1fca0.png">
<br>
HerokuでサポートするデータベースはPosgreSQLのようです。<br>
Webアプリにデータベースを用いる場合は注意が必要なようです。<br>
(2) "I'm ready to start"を選択します。
<br>
<img width="562" alt="registered.png" src="https://qiita-image-store.s3.amazonaws.com/0/374906/9454a99d-3dda-57ca-1698-84dfa041be10.png">
<br>
(3) Heroku CLIのインストーラをダウンロードして、インストールします。
<br>
<img width="574" alt="2_setup.png" src="https://qiita-image-store.s3.amazonaws.com/0/374906/552486d0-3453-ed50-0d9c-47b3d8b9477e.png">
<br>
Heroku CLIのインストールが完了したら、ログインができることを確認しましょう。
(4) コマンドプロンプトから "heroku login" でログインします。
<br>
<img width="572" alt="login.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/374906/2ee24c1a-7869-6f26-c2c7-0675a615c73c.png">
<br>
ログインできることを確認できたら、ログアウトして終了します。<br>
(5) コマンドプロンプトから "heroku logout" でログアウトします。<br>
<br>
力尽きたので、今回はここまで。。
</p>
iPadでＲ：RStudio Cloud

iPad でＲを使うなら、ほぼ [RStudio Cloud](https://rstudio.cloud/) 一択である。米RStudio社が提供しているクラウドコンピューティングのサービスである。アカウントを作ってデータをアップロードすれば、あとはローカル版の RStudio と使い勝手はほぼ、というかほとんど変わらない。ただキーボードはあった方がよい。

# 使いはじめ

[RStudio Cloud のサイト](https://rstudio.cloud/)でアカウントを作る (email アドレスと、自分の名前的な文字列) か、または GitHub アカウントでログインする。後者でも結局は RStudio Cloud のアカウントが作られる。

最初に、プロジェクトを作る。プロジェクト名は後で変えられるのでなんでもよい。するとローカル版の RStudio と同じ画面が出てくる。プロジェクトは、自分のワークスペース内に作られるという位置づけで、基本的には本人にしかアクセスできないが、右上の🔅みたいなボタン -> Access で公開するように設定できる。ワーススペースは別に作ることもできる。作るときにそのワークスペースを共有したい相手を指定できる。なお左の柱は、柱内をクリックすれば隠れる。
![ず１s.png](https://qiita-image-store.s3.amazonaws.com/0/377279/93086bdd-fe5f-6937-fed7-10c5f93fdf73.png)

# データのアップロード

右下のペインの Files タブで Upload というボタンをクリックすると、アップロードするファイルを選ぶダイアログボックスが出てくる。ここでアップロードしたファイルはスクリプト内からは /cloud/project/ というパスで見える (全部小文字)。zip ファイルはアップロード先で自動的に展開されるので、ディレクトリを丸ごと上げたい時は zip ファイルにする。

# スクリプトのアップロードと保存

左上の File メニューから Open File... を選ぶと、/cloud/project/ 内のリストが表示され、その中からスクリプトファイルを選べる。なのでスクリプトも、上のデータのアップロードと同じ手順でアップロードしておけばよい。mac なら ⌘-S で (Windows ならたぶん ctrl-S で) スクリプトは  /cloud/project/ に保存される。

# プロット画像など

プロットは左下の Plots パネルに出てくるが、コードでファイルに保存すると例によって /cloud/projet/ 内に保存される。Files パネルで画像ファイルをクリックすると、ブラウザで別タブを開いて表示される。

# RStudio Cloud の利点と欠点

iPad などでシームレスに mac や PC での解析作業を続けられるのは非常に大きな利点である。また無料でもある (将来的には有料プランを用意する可能性はあるらしいが)。利用制限もない。欠点は、ネットワーク接続が必要なことである。新幹線の中などではトンネルの度に接続が切れる上にトンネルは多いので、ストレスフルである。また、全然日本語化はされていないし、今後もされないと思う。

以上は[スマホでＲ](https://qiita.com/piccolist/items/80734ccaa2d1a4c846a7)とあわせて本に書いた。[Booth](https://sliderule.booth.pm/)か[技術書典６](https://techbookfest.org/event/tbf06)[お台場計算尺](https://techbookfest.org/event/tbf06/circle/33970004)で。
はじめてパスを使う

#画像を読み込む方法
パスをつかって、ファイルがどこからのものか表す必要がある。
##パスとは、
どこにファイルがあるか教える文字列のこと。
##ルートディレクトリとは、
ファイル階層の最上位を指す。（/）
##絶対パスとは、
階層構造の頂点（ルートディレクトリ）から目的地までのルート。ユーザーがどこで作業中でも同じルートになる。
利点：目的地を間違えにくい。
##相対パスとは、
ユーザーの作業地点から目的地までのルート。絶対パスと違って、ユーザーの作業地点によって変わる。
利点：ルートディレクトリがそのまま引っ越ししてれば、修正しなくていい。

##相対パスをつかって画像を読み込む
cssから見て、
・同じ階層の別のフォルダなら＝「フォルダ名/」
・1つ上の階層なら＝「../」
###実際にやってみる
![無題.png](https://qiita-image-store.s3.amazonaws.com/0/380575/598f79b5-9e59-67ec-7b12-6f4ffe5649dc.png)
こんなファイルの場合、
cssのstyle.cssで背景画像としてimgの7a768e...の画像を使いたいとき。
style.css~css~img~7a768e...の順に辿る。
つまり、
1.style.cssから1つ上の階層のcssに上がるため＝「../」
2.cssから同じ階層のimgに行くために＝「img/」

結果、style.cssには![無題.png](https://qiita-image-store.s3.amazonaws.com/0/380575/7c27a84b-9ac4-1ea2-7f46-ee3de8188902.png)
となる。
#jq コマンドで結果が空配列の場合に何も出力しない例

# 問題

空配列がそのまま標準出力されてしまう。

```
$ echo '[]' | jq '.'
[]
```

# 解決

```
$ echo '[]' | jq 'select(length > 0)'
```

配列の中身があっても大丈夫

```
$ echo '[1,2,3]' | jq 'select(length > 0)'
[
  1,
  2,
  3
]
```

# ダメな例

以下の書き方だと中身がある場合に配列が崩れてしまう。

```
$ echo '[1,2,3]' | jq '.[]'
1
2
3
```

# Original by Github issue

https://github.com/YumaInaura/YumaInaura/issues/981








<!-- Update From Qiita API -->

# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ





# Twitter


https://twitter.com/YumaInaura


<!-- Update From Qiita API -->
$(document).delegate()在iOS web环境下无响应

## 背景
最近公司在开发HTML5 Web应用程序，需要在Android和iOS平台上面运行。然而我发现在Android中可以正常响应的按钮在iOS中却不能正常工作，所以有了这篇文章。

## 寻找原因
其实在iOS环境下并不是所有按钮都不能正常工作，`<button>`标签的按钮还是表现得很出色的，而有问题的按钮一般都是以非`<button>`包裹的，需要额外响应点击事件的标签。

```html:test.html
<div>
    <i class="icon iconfont icon-delete"></i>
    <span class="delete">Delete</span>
</div>

<script type="javascript">
    $(document).delegate('.delete', 'click', function () {
        var _this = $(this);
        // do something here...
    });
</script>
```

所以问题可能出现在`$(document).delegate()`这个方法上面了。

## 解决
最后在网上找到了解决方法，原因是在iOS环境（safari）中不会去响应没有事件冒泡的标签，所以只要使需要响应点击事件的标签强制响应就好了。这里给出两种方法：

```html:test_solution1.html
<!-- add additional style to the tag -->
<style>
.delete {
    cursor: pointer;
}
</style>
```

```html:test_solution2.html
<!-- add onclick="" to the tag -->
<div>
    <i class="icon iconfont icon-delete"></i>
    <span class="delete" onclick="">Delete</span>
</div>
```

## 参考
[jQuery .on() and .delegate() doesn't work on iPad](https://stackoverflow.com/questions/10165141/jquery-on-and-delegate-doesnt-work-on-ipad)
[Why doesn’t my javascript click event work on iOS/iPhone?](https://fjorgedigital.com/insights/blog/why-doesnt-my-javascript-click-event-work-on-iosiphone/)
配列からスライド窓を取得するやつを書いた

# はじめに

時系列データを機械学習させるときにスライド窓というのを使うらしいので、そういつやつを書いた。こんなん[scikit-learn](https://scikit-learn.org/stable/)あたりが持ってるんじゃね？と思ってググったんだけど意外といいサンプルが出てこなかった。自分のググり力が低いせいに違いないが、時間がもったいないので自作することにしました。せっかく作ったので貼っておきます。

# やりたいこと

こういう配列を

```
[10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29]
```

こうしたい

```
[[10 11 12 13 14 15 16 17 18 19]
 [11 12 13 14 15 16 17 18 19 20]
 [12 13 14 15 16 17 18 19 20 21]
 [13 14 15 16 17 18 19 20 21 22]
 [14 15 16 17 18 19 20 21 22 23]
 [15 16 17 18 19 20 21 22 23 24]
 [16 17 18 19 20 21 22 23 24 25]
 [17 18 19 20 21 22 23 24 25 26]
 [18 19 20 21 22 23 24 25 26 27]
 [19 20 21 22 23 24 25 26 27 28]
 [20 21 22 23 24 25 26 27 28 29]]
```

要するに、指定した列数（上記は10）で一個ずつ値をずらした配列つくって最後の値までの分を行として並べたいわけである。こういうのをスライド窓（Sliding Window）というらしい。時系列データを機械学習するときの教師データとしてよく使われるみたいだ。あんまよくわかってないけど。

# 関数を書いた

こんな感じ。[numpy.arange](https://docs.scipy.org/doc/numpy-1.15.0/reference/generated/numpy.arange.html)がなければオレに光は射さなかっただろう

```getSlidingWindow.py
import numpy as np

def getSlidingWindow(a, size, step=1):
    if not ((type(size) == type(0)) and (type(step) == type(0))):
        raise Exception("type(size) and type(step) must be int.")
    if step > size:
        raise Exception("step must not be larger than size.")
    if size > len(a):
        raise Exception("size must not be larger than array length.")
    a = np.asarray(a)
    h = ((len(a)-size)/step)+1
    indexer = np.arange(size)[None, :] + step*np.arange(int(h))[:, None]
    window = a[indexer]
    return window
```

実行してみる

```run.py
a = list(range(10,30))
print(a)
print('-----')
print(getSlidingWindow(a, 10))
```

結果は以下のようになる。期待通り

```
[10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29]
-----
[[10 11 12 13 14 15 16 17 18 19]
 [11 12 13 14 15 16 17 18 19 20]
 [12 13 14 15 16 17 18 19 20 21]
 [13 14 15 16 17 18 19 20 21 22]
 [14 15 16 17 18 19 20 21 22 23]
 [15 16 17 18 19 20 21 22 23 24]
 [16 17 18 19 20 21 22 23 24 25]
 [17 18 19 20 21 22 23 24 25 26]
 [18 19 20 21 22 23 24 25 26 27]
 [19 20 21 22 23 24 25 26 27 28]
 [20 21 22 23 24 25 26 27 28 29]]
```

値をスライドするステップ数も指定可能

```run.py
a = list(range(10,30))
print(a)
print('-----')
print(getSlidingWindow(a, 10, 3))
```

3つずれたスライド窓になる

```
[10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29]
-----
[[10 11 12 13 14 15 16 17 18 19]
 [13 14 15 16 17 18 19 20 21 22]
 [16 17 18 19 20 21 22 23 24 25]
 [19 20 21 22 23 24 25 26 27 28]]
```

# まとめ

いまやりたいことにはこれで十分。いろいろな時系列データを処理してみたいと思います。
(PuTTYの入った) windows 環境で GitHub を ssh で使用する場合の注意

GitHub のプライベートリポジトリの制限が緩和され、コードを置く場所として非常に使い勝手が良くなったので、一部のコードを上げるべく準備をしたのですが。。。

**ドハマリました＾＾；**

# 結論

結論を先に言うと環境変数 GIT_SSH に「plink.exe」の入った環境では、接続は「plink.exe」が使用されるので、「ssh」の config 等は意味がありません。以下の 2 点のいずれかを選択してください。

参考サイト：[Git for Windowsでplink(putty)を使う](http://d.hatena.ne.jp/hogelog/20120627/p1)

## puttyに接続先のホスト情報を登録する
(私はこちらを選択しました)

> putty.exeから接続先を設定しておく。例えば接続先 github.com、ログイン名git、あと秘密鍵を入力し、github というセッション名で保存しておくと以下のように接続先を指定できる。

```
$ git clone github:te2ji/test.git
```

## pageantに鍵を登録する
> pageantを起動して秘密鍵を追加しておくと以下のようにして接続先を指定できる。

```
$ git clone git@github.com:te2ji/test.git
```


# 切り分けまでの手順
「git」「ssh」あたりは、適当に使っていたため、切り分けに時間がかかってしまいました。参考サイトと切り分けに必要なログを吐き出す方法をメモしておきます。

## GitHub への接続
まず参照すべきは公式です。
[Connecting to GitHub with SSH](https://help.github.com/en/articles/connecting-to-github-with-ssh)
本来であれば、このとおり進めればよいはずですが＾＾；

```
$ ssh -T git@github.com
```

までつつがなく進められます。
で、実際、`git clone`等を実行しようとすると

```
ERROR: Repository not found.
fatal: Could not read from remote repository.
```

正直、意味が分からなかったのですが、切り分けのためのデバッグ方法を模索します。

## Git のデバッグ
[10.8 Gitの内側 - 環境変数](https://git-scm.com/book/ja/v2/Git%E3%81%AE%E5%86%85%E5%81%B4-%E7%92%B0%E5%A2%83%E5%A4%89%E6%95%B0)

> デバッグ
Gitが何をしているか、 本当に 知りたいですか？ Gitには、組み込みのトレースのほぼ完全なセットが備わっており、ユーザがする必要があるのは、それらをオンにすることだけです。 これらの環境変数に設定可能な値は次の通りです。
…
GIT_TRACE は、どの特定のカテゴリにも当てはまらない、一般的なトレースを制御します。 これには、エイリアスの展開や、他のサブプログラムへの処理の引き渡しなどが含まれます。

つまり環境変数を設定することで、アクセス詳細が確認できるようになると。

```
set GIT_TRACE=true
$ git clone git@github.com:te2ji/test.git
```

するとログにおかしなモノが。。。

```
09:08:34.502035 run-command.c:640       trace: run_command: unset GIT_DIR; 'C:\Program Files\putty\plink.exe' github 'git-upload-pack '\''te2ji/test.git'\'''
```

ここで初めて`ssh`ではなく`plink`使ってんじゃん。。。ってなるわけです。
参考までに、linux 上で該当箇所はこんな感じ。

```
trace: run_command: 'ssh' 'git@github.com' 'git-upload-pack '\''te2ji/test.git'\'''
```

で、試しに接続してみると Time Out

```
$ plink git@github.com
FATAL ERROR: Network error: Network error: Connection timed out
```

問題箇所が特定できました。
で、`plink`使用した「GitHub」接続方法を検討したところ、結論で紹介したサイトに辿り着きます。

設定を入れた後に接続してみます。

```
$ plink github
Using username "git".
Access granted. Press Return to begin session.
Server refused to allocate pty
Hi te2ji! You've successfully authenticated, but GitHub does not provide shell access.
```
お疲れ様でしたｗ


# 余談1
PuTTY を使い慣れていないと、鍵の登録で問題を発生させる可能性があります。
PuTTY で使用する秘密鍵は putty 形式なので、GItHub 公式の手順で作成した OpenSSH 形式の鍵を変換する必要があります。

ざっくり説明すると以下のような手順です。
・`PuTTYgen`で OpenSSH 形式の鍵を load
・save private key で putty 形式の保存
・PuTTY で使用する鍵に putty 形式で保存したものを指定

ハマらないようにね。

# 余談2
原因は、環境変数 GIT_SSH が`plink`を指していることなのですが、変更の経緯は追えていません。
もしかすると変更は「PuTTY」が導入されたタイミングではなく、別のタイミングで GIT_SSH は変更されたのかも。

ご存知の方がいれば指摘してください。

# 余談3
`plink`の接続が Time Out なのに

```
ERROR: Repository not found.
```
って、おかしくない？って思ったけど、今回はコレ以上追いかけない^^;
【個人開発者】として初のインタビュー記事が公開されました

ので、記念に投稿！

インタビューしてくださった[開発会議](https://qiita.com/svfreerider/items/def03b636df78eeea0e6)さんに感謝です。

**あなたの一日一善が冒険になるワクワクする「まちかどルート」の作り方**
https://devtalk.jp/interviews/2
LogServiceを用いてMySQLバイナリログを収集する

RDSリカバリーに大事なバイナリログをLogServiceでどのように収集するのかにご関心をお持ちの方がいるかと思い、今回の記事はRDSバイナリログの収集について、紹介したいと思います。


###実現手法
下図のように、LogtailがMySQLスレーブインタラクティブプロトコルを実装している為、スレーブノードとしてマスターノードにDumpプロトコルを送信し、マスターノードはDump要求を受信した後、自身のバイナリログをLogtailにプッシュします。Logtailはリアルタイムでイベント解析、フィルタリング、データ解析などをし、解析されたデータはログサービスにアップロードします。

<img width="758" alt="スクリーンショット 2019-03-21 16.52.13.png" src="https://qiita-image-store.s3.amazonaws.com/0/265269/323e90dd-f7d4-bca7-93d5-4fdbcd06ac60.png">

###手順について　　　　　　　　　　　　　　　　　　　　　　　　　
まず、バイナリログを行モードになっているのかを確認します。

```ruby:qiita.rb
mysql> show variables like "log_bin";
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| log_bin       | ON    |
+---------------+-------+
1 row in set (0.02 sec)

mysql> show variables like "binlog_format";
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| binlog_format | ROW   |
+---------------+-------+
1 row in set (0.03 sec)
```
次は、testuserという名前のユーザーを作成し、下記のコマンドで権限を付与します。

```ruby:qiita.rb
GRANT SELECT, REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'testuser'@'%';
FLUSH PRIVILEGES;
```
そして、LogService側でProjectとLogStoreを作成していきます。LogStoreのデータソースのBINLOGを選択してから、プラグイン設定のところに、RDSに関しての必要な詳細情報を設定します。（パスワードなどの情報を守る為、こちらで一旦ダミーデータを入力し、後からLogtailの/usr/local/ilogtail/user_log_config.jsonで修正するのをおすすめします。）

```ruby:qiita.rb
{
  "inputs": [
    {
      "type": "service_canal",
      "detail": {
        "Host": "************.mysql.rds.aliyuncs.com",
        "User": "testuser",
        "Password": "*******",
        "ServerID": 32355,
        "IncludeTables": [
          ".*\\..*"
        ],
        "ExcludeTables": [
          "mysql\\..*"
        ],
        "TextToString": true
      }
    }
  ]
}
```

###テストする

testdbでtest_dbという名前のテーブルを作成し、INSERT INTO、UPDATEとDELETEなどのDML文を実行します。

```ruby:qiita.rb
CREATE TABLE test_tb
(
PersonID int,
LastName varchar(255),
FirstName varchar(255),
Address varchar(255),
City varchar(255)
);

INSERT INTO test_tb (PersonID, LastName, FirstName, Address, City)
VALUES (1, 'Tom B. Erichsen', 'Skagen 21', 'Stavanger', 'Norway');

UPDATE test_tb
SET FirstName = 'Alfred Schmidt', City= 'Frankfurt'
WHERE PersonID = 1;

DELETE FROM test_db WHERE PersonID =1;
```
下記のように、LogStoreでバイナリログが収集されるようになりました。

<img width="1354" alt="スクリーンショット 2019-03-24 10.42.41.png" src="https://qiita-image-store.s3.amazonaws.com/0/265269/c639284f-fe4f-42ad-6c24-fa213febab6f.png">

###最後
いかがでしたでしょうか、LogServiceを用いてRDSバイナリログの収集手法を紹介させて頂きました。また、収集したログをOSSやTableStore、MaxComputeなどのAlibaba Cloudのサービスと連携して、大量データの長期保存・分析をすることもできます。 この辺については、今後ご紹介させて頂きたいと思います。
ここ5年ほどのJavaを簡単に振り返ってみる

転職が決まって、転職先でJavaを使うことになるので[ブログで書いた記事](https://yk0807.com/techblog/2019/03/29/%E3%81%93%E3%81%935%E5%B9%B4%E3%81%BB%E3%81%A9%E3%81%AEjava%E3%82%92%E7%B0%A1%E5%8D%98%E3%81%AB%E6%8C%AF%E3%82%8A%E8%BF%94%E3%81%A3%E3%81%A6%E3%81%BF%E3%82%8B/)をこちらにも投稿して見る。

[Wikipediaのページ](https://ja.wikipedia.org/wiki/Java)や[JDK公式ページ](http://openjdk.java.net/projects/)によると、大体こんな感じ。
2014年3月　[Java8](http://openjdk.java.net/projects/jdk8/features)（ラムダ式、型アノテーション、Date and Time API 、JavaFX（Swingより高機能なGUIツール）など）
2017年9月　[Java9](http://openjdk.java.net/projects/jdk9/)（言語レベルでのモジュール化のサポートなど）
2018年3月　[Java10](http://openjdk.java.net/projects/jdk/10/)（ローカル変数型推論など）
2018年9月　[Java11](http://openjdk.java.net/projects/jdk/11/)（ネストベースのアクセスコントロールなど、**OracleJDKの有償化！！**）
2019年3月　[Java12](http://openjdk.java.net/projects/jdk/12/)（JVM定数のAPIなど）

こうして見ると、5年前のJava8で色々な機能が追加されたのが目につく。中でも、今更ながらラムダ式の導入はかなり大きかったのではないかと。
ラムダ式の例としては、こんな感じ。

```Java
package Lambdatest;
import java.util.function.*;

public class LambdaTest {
	public static void main(String[] args) {
		double x1 = 3.0;
		double y1 = 4.0;
		BiFunction<Double, Double, Double> z = (x, y) -> Math.sqrt(x * x + y * y);
		System.out.println(z.apply(x1, y1));
	}
}
```

これと同じことをラムダ式を使わずにやろうとすると、無名クラスを使ったり、結構ややこしいことになるんではと思う。
そういえば、C++も言語仕様が大きく追加されたC++11からラムダ式が使えるようになったんだったな。

他にも色々な機能が増えて、ここ数年で本当に進歩したんだなあ。とはいえ、いいことばかりではなくJava11からOracleJDKが有償化されてしまった（個人で使う分には大丈夫みたいですが）のは多くの人にとっては痛そうですね。。。OpenJDKの方は無償で使うことができるのですが、サポート期間が短かったりするので、悩みどころですね。
#追記
コメント欄で情報をいただいたので、少しだけ追記します。
[Amazon Corretto](https://aws.amazon.com/jp/corretto/)というOpenJDK互換の無償のディストリビューションがあるようです。インストール方法などは[こちら](https://qiita.com/lc-tsuchiya/items/3776e1c1ecadb4dc5b99)を参考にして見てください。
#jq コマンドでオブジェクトの配列から key の value で検索絞り込みする例

# オブジェクトの配列から検索する場合

map と select を組み合わせて使う

```sh
$ echo '[{"answer": "yes"} , { "answer" : "no"}]' | jq 'map(select(.answer == "yes"))'
[
  {
    "answer": "yes"
  }
]
```

# フラットな複数個以上のJSONから検索する場合

select だけで良い

```sh
$ echo '{"answer": "yes"} { "answer" : "no"}' | jq 'select(.answer == "yes")'
{
  "answer": "yes"
}
```


# Original by Github issue

https://github.com/YumaInaura/YumaInaura/issues/979








<!-- Update From Qiita API -->

# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ





# Twitter


https://twitter.com/YumaInaura


<!-- Update From Qiita API -->
"NSLocationWhenInUseUsageDescription"を設定しろとAppleからメールが来る

2019/03/28の16:30くらいから、AppStoreへ提出用のアップロードをすると
以下のようなメールが返ってきて失敗してしまうようになった。
（ほぼ同じ状態のアプリを16:10にアップロードしたときは成功したのに・・・）


> **App Store Connect**
--
> Dear Developer,
> 
> We identified one or more issues with a recent delivery for your app, "***". Please correct the following issues, then upload again.
> Missing Purpose String in Info.plist File. Your app's code references one or more APIs that access sensitive user data. The app's Info.plist file should contain a NSLocationWhenInUseUsageDescription key with a user-facing purpose string explaining clearly and completely why your app needs the data. Starting spring 2019, all apps submitted to the App Store that access user data will be required to include a purpose string.If you're using external libraries or SDKs, they may reference APIs that require a purpose string. While your app might not use these APIs, a purpose string is still required. You can contact the developer of the library or SDK and request they release a version of their code that doesn't contain the APIs. Learn more (https://developer.apple.com/documentation/uikit/core_app/protecting_the_user_s_privacy).

> Best regards,
> 
> The App Store Team


読んで字のごとく、位置情報にアクセスするAPIを使ってるならちゃんとinfo.plistに
`NSLocationWhenInUseUsageDescription`を書けよって意味なんですが、
私は位置情報なんて使ってませんし、`CLLocationManager`に関する処理も書いてません。

そこで、位置情報を使う時に利用するframeworkで検索すると`CoreLocation.framework`が
targetsの`Linked Frameworks and Libraries`に・・・。

## 対策
targetsから`CoreLocation.framework`を削除して、Cleanしてから再度ビルドしてアップロードするも、リジェクト。
確認すると全てのtargetsから消したのになぜかプロジェクトツリーにframeworkが居座っていたので、
`Remove Refrence`で削除。

が、ダメ。

英文検索してみると、以下のような情報が。
https://github.com/twitter/twitter-kit-ios/issues/90
> Upon submission to the app store this framework is generating a rejection even though I am not using Location for tweets.
> App Storeへの送信時に、このフレームワークはツイートの場所を使用していないにもかかわらず拒否を生成しています。（Google翻訳）

とりあえず、TwitterKitを使っているとTweetComposeを利用するときに強制的にAPIが使われているようで・・・。
このレスポンスにもあるように、以下の情報をinfo.plistに追加して申請してみます。

色々と検索してみると、他にも使っていないのに自動レスポンスでこのメールを受け取ってる人が多数いるようですね・・・。

```
NSLocationWhenInUseUsageDescription
Your location is required to share you location within tweets
Twitterでのツイート時にあなたの場所を共有する場合に利用します。
```

```xml:info.plist
<key>NSLocationWhenInUseUsageDescription</key>
<string>Your location is required to share you location within tweets</string>
```

とりあえずUploadを自動リジェクトされることはなくなりました。
completed processing.のメールも飛んできたので大丈夫そうです。

追記 : 審査も通りました。
Triggerベース

/**
 * TriggerCoreクラスが必ず継承するクラス
 */
public abstract class BaseTriggerCore {

    /**
     * 保存前のレコード一覧
     */
    protected SObject[] oldObjects;

    /**
     * 保存後のレコード一覧。
     */
    protected SObject[] newObjects;

    /**
     * 操作実施前のオブジェクトMap。キーはカスタムオブジェクトID、値はレコード。
     */
    protected Map<Id, SObject> oldMap;
    /**
     * 操作実施後のオブジェクトMap。キーはカスタムオブジェクトID、値はレコード。
     */
    protected Map<Id, SObject> newMap;

    /**
     * コンストラクタ。Trigger変数から操作前後のオブジェクト情報を渡す。
     * @param oldObjects 保存前のレコード一覧
     * @param newObjects 保存後のレコード一覧
     * @param oldMap 操作実施前のオブジェクトMap
     * @param newMap 操作実施後のオブジェクトMap
     */
    public BaseTriggerCore(SObject[] oldObjects, SObject[] newObjects,
            Map<Id, SObject> oldMap, Map<Id, SObject> newMap) {
        this.oldObjects = oldObjects;
        this.newObjects = newObjects;
        this.oldMap = oldMap;
        this.newMap = newMap;
    }

    /**
     * トリガーの処理を実行する。
     * [before, after], [insert, update, delete, undelete]のどれであるかを判別し、
     * 自動的に実行するメソッドを選ぶ。
     * @param isBefore Beforeトリガーかどうか
     * @param isInsert 行った操作がInsertかどうか
     * @param isUpdate 行った操作がUpdateかどうか
     * @param isDelete 行った操作がDeleteかどうか
     * @param isUndelete 行った操作がUndeleteかどうか
     */
    public void invoke(boolean isBefore, boolean isInsert,
            boolean isUpdate, boolean isDelete, boolean isUndelete) {
        //ロールバックポイントの取得
        Savepoint sp = Database.setSavepoint();
        try {
            if(isBefore) {
                if(isInsert) {
                    this.onBeforeInsert();
                } else if(isUpdate) {
                    this.onBeforeUpdate();
                } else if(isDelete) {
                    this.onBeforeDelete();
                }
            } else {
                if(isInsert) {
                    this.onAfterInsert();
                } else if(isUpdate) {
                    this.onAfterUpdate();
                } else if(isDelete) {
                    this.onAfterDelete();
                } else if(isUndelete) {
                    this.onAfterUndelete();
                }
            }
        } catch(Exception e) {
            Database.rollback(sp);
            throw e;
        }
    }

    /**
     * before insertの処理を実行する。
     */
    protected virtual void onBeforeInsert() {
    }

    /**
     * after insertの処理を実行する。
     */
    protected virtual void onAfterInsert(){
    }

    /**
     * before updateの処理を実行する。
     */
    protected virtual void onBeforeUpdate(){
    }

    /**
     * after updateの処理を実行する。
     */
    protected virtual void onAfterUpdate(){
    }

    /**
     * before deleteの処理を実行する。
     */
    protected virtual void onBeforeDelete(){
    }

    /**
     * before deleteの処理を実行する。
     */
    protected virtual void onAfterDelete(){
    }

    /**
     * after undeleteの処理を実行する。
     */
    protected virtual void onAfterUndelete(){
    }

}
外付けHDDをUSBに挿しても動かないのはアダプタが原因らしい(電流編)

#概要
- 外付けHDDが挿しても動かないです
- 物理的な仕様が確定していないおかげで一苦労
- USBのバスパワーは解決策にならない
- 結局、アダプタが原因でした（おま電）

## 内蔵にすれば解決？
- そんなことはない（三国志並感）
- SATAケーブルが壊れることもあるし、むしろUSBの方が耐久性はある

場合によっては外付けを**敢えて使う**こともある。


##ドライバは関係ない
USBにHDDを挿したが認識どころかHDDの電源が入らない。
他のPCに挿しても同様の状態

つまりドライバは関係なし。（ドライバやパーツがOSに対応していれば）

## 電源は"付いている"
物理的に接続をしている状態

##おま電（おまえの電源の規格が違うんじゃねーの）
"付いている"のに電源が入らないという点から、ACアダプタを確認した。 
ACアダプタが某国製なのは問題外として、電流値を確認する。 
実は、USBのバスパワーでも同様の問題があり、HDDによっては起動しない現象があるため。  

アダプタに貼っているシールでは**1.5A**だったが、HDDやケースによっては**2A**が必要。 
よって2Aのアダプタを使用したところ無事動いた。 

2.5inの場合も2A必要と思われるが未検証。
#jq コマンドは #JSON 的には不正な、フラットなオブジェクトの連続も解釈してくれるっぽい

# invalid JSON

配列の中にあるわけでもなく、フラットな構造でオブジェクトが並んでいるもの。

```
{ "alice": "liddel"}
{ "bob": "jobs" }
```

JSON 自体でこの構造が許容されているのかと思いきや、どうやら不正らしい。

![image](https://user-images.githubusercontent.com/13635059/55201222-5f60bc00-5205-11e9-9aad-85fa12b81bc7.png)

https://jsonformatter.curiousconcept.com/

# jq


```shell
$ echo '{ "alice": "liddel"} { "bob": "jobs" }' | jq .
{
  "alice": "liddel"
}
{
  "bob": "jobs"
}
```

- 解釈してくれる。
- おそらく正規のJSONを二回に分けて解釈したという扱いかと思われる。
- え、ドキュメント読みなさいって？はい、そうですよね。


# Original by Github issue

https://github.com/YumaInaura/YumaInaura/issues/978








<!-- Update From Qiita API -->

# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ





# Twitter


https://twitter.com/YumaInaura


<!-- Update From Qiita API -->
[Ryby] 引数とは

# 引数とは
変数にはスコープというものがあり使える範囲が決まっています。
変数は**変数を定義したメソッドないでしか使う事ができません**。実際のコードで説明していきます。

```変数.rb
name = "ゆーいち"
puts name
#=>"ゆーいち"
```
これはスコープの範囲なので変数を使う事ができます。次を見て見ましょう。

```変数.rb
name = "ゆーいち"
def yuichi
puts name
end

yuichi
#エラー
```
このようにメソッド内で変数nameを使おうとしていますが、nameという変数はメソッドの外で定義しているためメソッド内でnameを認識できずエラーになってしまいます。
これを解決してくれるのが**引数**です。

## 引数の定義
```引数.rb

def yuichi(name)
puts name
end

name = "ゆーいち"
yuichi(name)
#=>"ゆーいち"
```
これでスコープの問題を解決できました。
何をしているかというと、yuichiというメソッドを呼び出す際にメソッドに変数nameを渡しています。

```引数.rb

name = "ゆーいち"
yuichi(name)
```
この部分ですね、それを受け取ったメソッドはその値を変数としてメソッド内で使う事ができます。
ここで（）内に定義しているものを**本引数**と言います。

```引数.rb

def yuichi(name)
puts name
end
```
この部分になります。ここで受け取る際の()内に定義したものを**仮引数**と言います。

また仮引数と本引数は**違う名前**でも構いません、
例えば、

```引数.rb

def yuichi(lastname)
puts lastname
end

name = "ゆーいち"
yuichi(name)
#=>"ゆーいち"
```
このように書くこともできます。ただし仮引数の名前はメソッド内で使える変数なのでメソッド内でも仮引数の名前を使わなくてはなりません。

```引数.rb

def yuichi(lastname)
puts name　#nameは使えない
end

name = "ゆーいち"
yuichi(name)
#エラー
```
こういうのだったり

```引数.rb

def yuichi(lastname)
puts lastname
end

name = "ゆーいち"
yuichi(lastname) #変数nameをメソッドの渡せていない
#エラー
```

こういうのはできないので注意しましょう。


## 最後に
今回は引数について説明していきました。
変数は特に初学者の方はメソッドの呼び出しや、引数の受け渡し、変数の定義などが重なってごっちゃになってしまいがちだと思います。一つ一つ順をおって確認していく事が大事です。

最後まで読んでいただきありがとうございました。
#jq コマンドで要素全体を配列で囲う、もしくは逆に解除する例


```sh
$ echo '{ "alice": "liddel", "bob": "jobs" }' | jq '[.]'
[
  {
    "alice": "liddel",
    "bob": "jobs"
  }
]
```

```sh
$ echo '{ "alice": "liddel", "bob": "jobs" }' | jq '[.]' | jq '.[]'
{
  "alice": "liddel",
  "bob": "jobs"
}
```


# Original by Github issue

https://github.com/YumaInaura/YumaInaura/issues/977








<!-- Update From Qiita API -->

# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ





# Twitter


https://twitter.com/YumaInaura


<!-- Update From Qiita API -->
Windows10端末から共有サーバ（NAS)にアクセスできない事象の解消方法


# 背景

社内の業務用PCを新しくしたら、共有フォルダ（NAS）にアクセスすることができなくなった。

# 環境
OS:Windows10

# 原因
NAS の SMB バージョンが古く、Windows10 で SMB 1.0/CIFS のチェックが外れていて、アクセスできない。
※同じWin10でもWin7からアプデートしたものとかはアクセスできていたのでどこかの時点からチェックが外れているみたいです。

# 解決策

・Windows10 の SMB 1.0/CIFSを許可する
・NASのSMBのバージョンを上げる。

今回NASのSMBのバージョンは社内事情で上げれなかったのでWin10の設定を変更する方法を紹介します。NASのSMBのバージョンを上げて解消する（とは思うのですが）試せていません。

# 手法
コントロールパネル>>プログラムと機能>>Windowsの機能の有効化または無効化>>SMB 1.0/CIFS関連のチェックをONにする。>>パソコンを再起動する。

同じ現象でお困りの方の助けになれば幸いです。
Selenium WebDriverの稼働チェックをするお話

SeleniumのWebDriver が 今動いているかどうかチェックするいい感じのメソッドがどうもないようなので、上手い方法ないかを検討。

## とりあえず implicitly_wait(0) を応用してみる

```python:
from selenium import webdriver

def __init__(self, executable_path):
    self.executable_path = executable_path
    self.launch_driver()

def healthcheck_browser(self):
    try:
        # webdriverにWaitをいれる処理。デフォルト値0を入力し、
        # エラーが発生しないかをチェック
        self.driver.implicitly_wait(0)
    except Exception:
        # すでに quit されていれば エラー になるので再起動をかける
        print("The webdriver is not working.")
        launch_driver()
    else:
        print("The webdriver is now working.")

def launch_driver(self):
    self.driver = webdriver.Chrome(executable_path=self.executable_path)
Volume License版 Office 2019 インストール方法

# こまったちゃん
office 2019はVolume License Centerからダウンロードできるものはデベロッパーツールとオンラインサーバーなるもので、どうやってインストールするかはググらないとわからないっていう不親切さ。リンクの日本語もなんだかなぁレベル。
最終的にTwitterのフォロワーさんからの助言で解決できたのでメモ

#Office 2019 Deployment Toolのダウンドーロと展開
VLSCかMSダウンロードセンター( https://www.microsoft.com/en-us/download/details.aspx?id=49117 )からダウンロードし、適当なフォルダーに展開する。
setup.exeとサンプルのConfigurationが展開される。

#Configurationファイルの作成とエクスポート
↓これで作ると正確で楽
https://config.office.com/officeSettings/configure#

インストール・展開の設定の展開元はOffice Content Delivery Network(CDN)にした。
ローカルソースを選択し「不足している言語があるときにCDNにフォールバック」をオンにしておくと、指定したファオルダの下にOfficeフォルダが作成され、ファイルがダウンロードさる。
ライセンスとアクティブ化はMAKを入力し、自動ライセンス承認、自動的にEULAに同意するをオンにした。

一通り入力したら右上の「エクスポート」からConfigrationファイルをダウンロードする。

#ダウンロード
先に展開したsetup.exeと作成したConfigrationファイルを適当なフォルダにコピーする。
コマンドプロンプトを「管理者権限」で立ち上げ、下記コマンドを順に実行する。

setup /download configrationfile.xml
setup /configure configrationfile.xml

これで、インストール終了！！