OmniAICreator/Qiita-1.07M huggingface dataset:
4/8 js コードレシピ集 .test replace

# 正規表現でフォームの入力値をチェックする

/文字列パターン/.test(文字列)

placeholder
フォームにあらかじめ入っている、薄いグレーの文字のこと
ユーザーが何を入力したらいいかわかりやすくなる

keyUp
押し下げたボタンを離した時に発生するイベント
つまりクリックして手を離した時に発生する

正規表現のgはグローバルサーチ
対象の要素が、XXX.replace(/abc/g, yuyuyu) なら、XXX要素の中にabcが含まれているかを確認し、replaceでabcを全てyuyuyuに置き換える
https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Regular_Expressions

replace
http://mmorley.hatenablog.com/entry/2016/05/26/010042

```html:html
  <h2>電話番号を入力してください</h2>
  <input id="phoneNumberText" placeholder="xxx-yyyy-zzzz" type="tel">
  <p id="warningMessage"></p>
```

```js:js

// 正規表現
// input要素を取得
const phoneNumberText = document.querySelector('#phoneNumberText');

// 警告メッセージを取得
const warningMessage = document.querySelector('#warningMessage');

// 文字が入力される度にチェックを行う
phoneNumberText.addEventListener('keyup', () =>
{
  // phoneNumberに入力された内容を取得
  const phoneNumber = phoneNumberText.value;

  // 入力された内容に "-" が含まれている場合は空文字''（スペースで埋める)に置き換える
  // replaceは文字列の置換を行う replace(置換前, 置換後)
  // gはパターンと文字列が一致するか確認する
  const trimmedPhoneNumber = phoneNumber.replace(/-/g, '');

  // 0から始まる、10桁か１１桁の数字かどうかをチェック
  // パターン.test.文字列 文字列と要素が一致するかをチェック
  if (/^[0][0-9]{9,10}$/.test(trimmedPhoneNumber) === false)
  {
    // 一致しない場合はエラーメッセージを格納
    warningMessage.innerText = '電話番号を正しく入力して下さい。';
  } else
  {
    // 一致する場合はエラー無し
    warningMessage.innerText = ''
  }
});
```
GitHubでリモートからcloneできないときにやったこと

#GithubのリモートからCloneできない ときの対処

使用PC
Windows10

使用ツール
GitBash

##Cloneしようとすると起きた問題
色々なサイト参考にしつつ、
いざ、githubからCloneすると以下のようなエラー

```
Cloning into 'test'...
Warning: Permanently added the RSA host key for IP address 'xxx.xxx.xxx.xxx' to the list of known hosts.
git@github.com: Permission denied (publickey).
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.
```
githubにリポジトリは確かにあるけど、なぜかこのエラー。
どうやらSSH公開鍵をGitHubに登録するだけでなく、ssh-agentに秘密鍵を登録する必要あるそうです。

##ssh-agentに登録しようとしたらおきた問題
ssh-addで登録できるようなのでトライすると

```
ssh-add ./xxxx/xxxx //公開鍵のパス 
Could not open a connection to your authentication agent.
```

「eval `ssh-agent`」として、ssh-agent を起動しないと、ssh-addできないらしい。
(ほかのOSならevalは要らないらしい)

```
eval `ssh-agent`
ssh-add ~/.ssh/xxxx
Enter passphrase for ~/.ssh/xxxx:  //秘密鍵作成時のパスワード
$ git clone git@github.com:(xxxx/xxxx.git)　//成功しました。
```

これでできるようになりました。
文字化けを解消する方法(日本語)

[未来電子テクノロジー](https://www.miraidenshi-tech.jp/intern-content/program/)でインターンをしているrr0096pxです。
プログラミング初心者であるため、内容に誤りがあるかもしれません。
もし、誤りがあれば修正するのでどんどん指摘してください。

#はじめに
今回は、PHPで学生登録フォームを作りました。
しかし、最後に学生表を載せる際に、日本語が文字化けする結果に陥りました。
そこで、見落としがちなミスについて今回はご紹介します。

#エラーコード
問題文は、ここでした。
しかし、何度見直しても間違いがわかりません。

```PHP
if ($mysqli->connect_error){
        echo $mysqli->connect_error;
        exit();
    }else{
        $mysqli->set_charset("utf-8");
    }
```

#間違い箇所
しかし、色々合っているとわかっていながらも消し、書きを繰り返していると、たまたま間違って書いた部分が正解を導きました。
それは、以下です。

```PHP
if ($mysqli->connect_error){
        echo $mysqli->connect_error;
        exit();
    }else{
        $mysqli->set_charset("utf8");
    }
```

つまり、"utf-8"→ "utf8"でした。

#まとめ
これが合っていた理由は、わかりません。
しかし、エラーをなくすためには、一旦疑ってみることが重要だと気付きました。
FirebaseAuthenticationを用いたアプリの自動テスト時におけるreCAPTCHA回避方法

## TL;DR
FirebaseAuthenticationを用いたアプリの自動テスト時のreCAPTCHAを回避するにはappVerificationDisabledForTestingをTRUEにする

## 環境
- Xcode10.1
- Swift4.2
- XCTest

## FirebaseAuthenticationにおけるiOSシミュレータ実行時のreCAPTCHAでコケる問題
FirebaseAuthenticationを利用した認証を利用しているアプリは多いと思いますが、iOSシミュレータで実行する際には認証時にreCAPTCHAを要求されます。自動テストを行うにあたって、reCAPTCHAは大きな壁です。
<img width="320" alt="スクリーンショット 2018-12-20 18.24.04.png" src="https://qiita-image-store.s3.amazonaws.com/0/2891/3783cf28-5260-5192-2c8f-636183657e86.png">

ローカルのmacでXCUITestで実行していた際にはあまり気にならなかったのですが（タイミングの問題もあるかと思いますが）、fastlane snapshotやFirebase Test Labなどで実行する際にほぼ100％失敗してしまい、頭を抱えていました。

## 解決方法：verifyPhoneNumberを呼び出す前にappVerificationDisabledForTestingを TRUEに設定:smiley:

悩んだ挙げ句に公式ドキュメントを確認したところ、解消方法が記載されていました。堂々と記載されており、恥ずかしい気持ちでいっぱいです。

https://firebase.google.com/docs/auth/ios/phone-auth#header_9

> iOS では、verifyPhoneNumber を呼び出す前に appVerificationDisabledForTesting 設定を TRUE に設定する必要があります。これは、バックグラウンドで APN トークンを要求したりサイレント プッシュ通知を送信することなく処理されたりするため、シミュレータでのテストが容易になります。これにより、reCAPTCHA フォールバック フローも無効になります。

```swift
let phoneNumber = "+16505554567"

// This test verification code is specified for the given test phone number in the developer console.
let testVerificationCode = "123456"

Auth.auth().settings.isAppVerificationDisabledForTesting = TRUE
PhoneAuthProvider.provider().verifyPhoneNumber(phoneNumber, uiDelegate:nil) {
                                                            verificationID, error in
    if (error) {
      // Handles error
      self.handleError(error)
      return
    }
    let credential = PhoneAuthProvider.provider().credential(withVerificationID: verificationID ?? "",
                                                               verificationCode: testVerificationCode)
    Auth.auth().signInAndRetrieveData(with: credential) { authData, error in
      if (error) {
        // Handles error
        self.handleError(error)
        return
      }
      _user = authData.user
    }];
}];
```

上記の対応であの忌々しいreCAPTCHAの画面に遷移することなく認証が可能になります。ただし、**ホワイトリストに登録済の電話番号しか認証できなくなる**ため、その点は要注意です。

## 自動テスト実行時のみに有効にする
このままだとマニュアルテスト時に利用するアプリでも登録済の電話番号しか使用できなくなるため、自動テストのみこの動作を行うようにします。
[こちらの投稿](https://qiita.com/akuraru/items/68919c3507cbcd490f42)を参照し、UITestの実行時のみ、このコードが有効になるように分岐させます。


### プロダクトのコード

```swift
#if DEBUG || ADHOC
if ProcessInfo.processInfo.arguments.contains("UITEST") {
    Auth.auth().settings?.isAppVerificationDisabledForTesting = true
}
#endif
```

### テストのコード
UITest起動時に `launchArguments` でUITESTの文字列を渡します。

```swift
let app = XCUIApplication()
app.launchArguments.append("UITEST")
app.launch()
```
Flexboxでの水平スクロールについて

# 概要
横スクロールの実装でflexboxを使ったのでそのメモ。

# 横スクロールの実装
まず、横スクロールさせるブロックとそのアイテムの親子要素を用意します。

```html
<div class="parent">
  <div class="child"></div>
  <div class="child"></div>
  <div class="child"></div>
</div>
<style>
.parent{
  height: 100px;
  width: 300px;
  background-color:cornflowerblue;
}
.child{
  height: 80px;
  width: 80px;
  margin: 10px;
  background-color: aquamarine;
}
</style>
```
<img width="335" alt="画像1.png" src="https://qiita-image-store.s3.amazonaws.com/0/305206/18b351ba-05a8-42d2-43f1-9ad2895916c7.png">

親要素にflexboxにする`display: flex;`と`overflow-x: scroll;`を指定します。

```scss
<style>
.parent{
  display: flex;
  overflow-x: scroll;
}
</style>
```

<img width="331" alt="画像2.png" src="https://qiita-image-store.s3.amazonaws.com/0/305206/790816ae-444a-5fa3-d962-2a9148aa0e58.png">

このままだと、画像のように子要素がオーバーフローするとき、親要素に合わせて、  
子要素の幅が変更されてしまうので、以下の方法のいずれかで子要素のサイズを指定します。

## 1. flex-basisの指定
まず、1つ目の方法は子要素の`flex`の指定です。
**`flex-basis`だけだと拡縮されてしまいます。**

```scss
<style>
.child{
  //1つ目の要素は余裕があるときどのくらい拡大するか, 2つ目の要素は余裕がないときどのくらい縮小するか
  flex: 0 0 80px;
}
</style>
```

## 2. 子要素のmin-widthの指定
2つ目の方法は子要素の`min-width`の指定です。
子要素に`min-width`を指定するとオーバーフローしても`min-width`未満にならないためスクロールできます。

```scss
<style>
.child{
  min-width: 80px;
}
</style>
```

<img width="313" alt="画像3.png" src="https://qiita-image-store.s3.amazonaws.com/0/305206/96b2d684-a765-d3b8-94b0-b13f16e7535f.png">
Githubから脆弱性を指摘されたのでメモ


[![Image from Gyazo](https://i.gyazo.com/5527a6304b23ce4a09413ccb1ca423e9.png)](https://gyazo.com/5527a6304b23ce4a09413ccb1ca423e9)
>
We found potential security vulnerabilities in your dependencies.
Only the owner of this repository can see this message. 
Manage your notification settings or learn more about vulnerability alerts.
依存関係に潜在的なセキュリティ脆弱性が見つかりました。
このリポジトリの所有者だけがこのメッセージを見ることができます。
通知設定を管理するか、脆弱性アラートについて詳しく学んでください。


ということで、セキュリティアラートを見る
[![Image from Gyazo](https://i.gyazo.com/5b06986711b54dd7480408bd48cbf419.png)](https://gyazo.com/5b06986711b54dd7480408bd48cbf419)

>
Remediation
Upgrade actionview to version 5.0.7.2 or later. For example:
```gem "actionview", ">= 5.0.7.2"
```Always verify the validity and compatibility of suggestions with your codebase.

>
修復
actionviewをバージョン5.0.7.2以降にアップグレードしてください。例えば：
```gem "actionview", ">= 5.0.7.2"
```提案の妥当性と互換性をコードベースと常に確認してください。



・GitHubからセキュリティ警告のメールが来た
https://qiita.com/taktakfu/items/471333d3dd2c9e935949
・GitHubから依存関係の脆弱性を指摘されたが、どうすればよいか。
https://teratail.com/questions/118673

を、参考になにも考えずコンソールで`bundle update`

すると、大量のログの中にそれらしき部分が↓

```
Fetching actionview 5.0.7.2 (was 5.0.7.1)
Installing actionview 5.0.7.2 (was 5.0.7.1)
```

これでGemfile.lockだけコミットしてGithubにプッシュしたらアラートは消えた。
PL/SQLを勉強中...

# PL/SQLめも(後で整形)

◆Oracle PL/SQL Programming Design－Oracle PL/SQLでバッチプログラムを設計・開発するために。
　https://oracle.tf17.net/plsql/

◆長時間処理のSQLや遅いSQLの確認方法
　https://oreno-it.info/archives/106
　　※すごいたくさんのポイントが記載されている...(^O^)/

◆なぜ、SQLは重たくなるのか？──『SQLパフォーマンス詳解』の翻訳者が教える原因と対策 
　https://employment.en-japan.com/engineerhub/entry/2017/06/26/110000
---＠下記がポイントとのこと
【原因①】ORMが生成するSQLを確認していない
【原因②】複合インデックスを適切に使えていない
【原因③】複合インデックスの走査範囲を考慮していないため、大なり小なり記号やBETWEENが遅い
【原因④】LIKE句において、ワイルドカードが文字列の前方についている
【原因⑤】テーブル結合が不得意なデータベースで、テーブル結合を多用している
【原因⑥】ORDER BY / GROUP BYで、大量のソートが発生している
【原因⑦】データ量が増えると処理が重たい。「良くないSQL」を書いているから
【原因⑧】複数クエリの総実行時間が長い
大切なのは、データベースの仕組みを理解すること
---

◆コメントを書きすぎるとPL／SQLが遅くなる？
　https://builder.japan.zdnet.com/db-sql/20367356/
---＠下記が重要だと思う。。。
この記事を読んで、私もOracle SQL Developerの環境でSQLを流してみました。

select *
--（コメント３万行）
from table1
--（コメント３万行）
right outer join table2 on xxx
--（コメント３万行）
;
このSQLを流してみたところ
コメントなし→6ms
コメントあり→2000ms
という結果出ました。
---

◆Tips.6 本当にCOUNT(*)は遅いのか？COUNT(列名)は速いのか？～処理時間を計測～
　https://oracle.tf17.net/plsql/?p=258
◆Oracleのパフォーマンス問題はCOUNT(*)の廃止で解決！？
　http://d.hatena.ne.jp/tfurukaw/20060420
---＠★後でFETCHについて要調査
データの存在チェックにはCOUNT(*)を使用しない。OPEN～FETCHで１件だけ取得してFOUND/NOTFOUNDでチェックしましょう！
---

◆Oracle Database パフォーマンス改善 『SQL解析時間の短縮』
　https://www.casleyconsulting.co.jp/blog/engineer/151/
　　※基本的なことが記載されている

◆11 PL/SQLアプリケーションのパフォーマンスのチューニング
　http://otndnld.oracle.co.jp/document/products/oracle10g/102/doc_v1/appdev.102/B19257-01/tuning.html

◆Bulk Insert有無による性能差を、PL/SQL の FORALL文～で計測してみる。 
　https://gonsuke777.hatenablog.com/entry/20160101/1451644311
　　★Bulk Insertは別途要調査

◆超入門「PL/SQL」
　https://www.atmarkit.co.jp/ait/series/5485/

◆Oracle DatabaseのPL/SQLパフォーマンス改善
　https://www.ashisuto.co.jp/product/theme/database/oracle_plsql_performance.html
　　★DBオプロードは別途要調査

◆実践！！PL/SQLチューニング
　https://www.oracle.com/technetwork/jp/ondemand/db-basic/0120-1330-plsql-tuning-297512-ja.pdf

◆PL/SQLパフォーマンス向上
　http://database090212.com/oracle/plsql3_3.html
AVPlayer で再生できない

数十秒の音声を再生したいとおもって、下記コードで試しても再生できなく、エラーが出ることもなく、困っていました。

```swift:再生されないコード
@IBAction private func tappedButton(_ sender: UIButton) {
    let url = URL(string: "https://sample.com/music.mp3")!
    let player = AVPlayer(url: url)
    player.play()
}
```

いろいろ調べてもわからず、結局自分でひらめいて解決しました。

```swift:再生できるコード
var player: AVPlayer?

@IBAction private func tappedButton(_ sender: UIButton) {
    let url = URL(string: "https://sample.com/music.mp3")!
    player = AVPlayer(url: url)
    player?.play()
}
```

function 内で生成したインスタンスがすぐ開放されてしまっていたということですね。
インスタンスを保持しておけるよう、変数を function の外に出して解決しました。
ARC のおかげで日々メモリを意識せずコーディングできてますが、その弊害が出てしまった感じでしょう。

# おまけ: ストリーミング再生は AVAudioPlayer ではない

音声再生する場合 `AVAudioPlayer` を使ってしまいそうになりますが、これは**ローカル**のファイルを扱う物らしいので、
ストリーミング再生したい場合は `AVPlayer` を使います。

参照: https://stackoverflow.com/a/17007441

# 環境

- Swift 4.2
- Xcode 10.1
Nextcloud へ ownCloud クライアントアプリからのアクセスをさせない方法

# はじめに
Nextcloud では無料で使える機能が ownCloud では使えないとか、Nextcloud の開発スピードが早いとか、さまざまな理由で ownCloud から Nextcloud に運用をシフトするケースがあるかと思います。
そうなると運用で気になるのが、クライアント(利用者)の利用状況です。
Nextcloud に移行することにあわせて、これまでの ownCloud のデスクトップクライアントアプリやスマートデバイス向けアプリを使わせないように制限したい・・・そんなケースを想定して、各クライアントのアプリのアクセスを制限する方法をまとめてみました。

# どうやるのか？
各アプリからアクセスされる際の User-Agent で、アクセス許可/拒否を行うことができます。
※除: Android アプリ

# 各アプリの User-Agent
**※User-Agent は 2019年4月5日現在で確認しているものです。**

| OS       |区分      | User-Agent    |
|:---------|:--------|:--------------------|
| Windows | Nextcloud | Mozilla/5.0 (Windows) mirall/<バージョン> (build <ビルドバージョン>) (Nextcloud) |
| Windows | ownCloud | Mozilla/5.0 (Windows) mirall/<バージョン> (build <ビルドバージョン>) |
| macOS | Nextcloud | Mozilla/5.0 (Macintosh) mirall/<バージョン> (build <ビルドバージョン>) (Nextcloud) |
| macOS | ownCloud | Mozilla/5.0 (Macintosh) mirall/<バージョン> (build <ビルドバージョン>) |
| Linux | Nextcloud | Mozilla/5.0 (Linux) mirall/<バージョン> (build <ビルドバージョン>) (Nextcloud) |
| Linux | ownCloud | Mozilla/5.0 (Linux) mirall/<バージョン> (build <ビルドバージョン>) |
| iOS | Nextcloud | Mozilla/5.0 (iOS) Nextcloud-iOS/<バージョン> |
| iOS | ownCloud | Mozilla/5.0 (iOS) ownCloud-iOS/<バージョン> |
| Android | Nextcloud | 【初回接続時】 <br> Mozilla/5.0 (Android) ownCloud-android/<バージョン> <br> 【ログイン後】 <br> Mozilla/5.0 (Android) Nextcloud-android/<バージョン> |
| Android | ownCloud | Mozilla/5.0 (Android) ownCloud-android/<バージョン> |
* `<バージョン>` には アプリのバージョンが入ります。
    - 例1: `3.5.1`
    - 例2: `2.5.1final`
* `<ビルドバージョン>` には アプリのビルドバージョンが入ります。
    - 例1: `20181204`
    - 例2: `11456`
* Androidアプリでは初回接続時において Nextcloud アプリと ownCloud アプリの区別ができないため User-Agent でのアクセス制限はできません。しかし、ownCloud アプリから Nextcloud に接続すると `Precondition failed` メッセージが出て接続できないため、これに任せます。

# Nginx での制限設定例
以下の設定を Nginx 設定ファイルに追加し、Nginx を再起動します。

```
# ownCloud Desktop Client(Windows/Mac/Linux Common)
if ($http_user_agent ~ "^Mozilla/5\.0 \([A-Za-z]+\) mirall/.+ \(build [0-9]+\)$") {
    return 403;
}
# ownCloud App (iOS)
if ($http_user_agent ~ "^Mozilla/5\.0 \(iOS\) ownCloud-iOS+/.+$") {
    return 403;
}
```

**★この記事は、[スタイルズ社のNextcloudサイト](https://nextcloud.stylez.co.jp/) の [Nextcloudブログ](https://nextcloud.stylez.co.jp/nextcloudblog)にも公開しております！**
SereneLinuxを仮想環境で動かす検証@ubuntu 18.04.1LTS  +  VisualBox 6.0.4

#元記事
https://qiita.com/_JG1WWK/items/ed0ac2bd76c094e52eee
新生Linuxディストリビューション　SereneLinux爆誕！早速仮想環境で動かすぞ
上記の通りテストしたら不動だったケースがあったようです。

こちらの記事を書いたのですが当時立ち上げてたLinux環境のマシンは色々あって環境を変えまくってしまったので
以下の環境でテストします
なんかUbuntu18.04でやったら16.04よりvisual boxの挙動が不安定でした・・・
あんまり18.04の環境構成で美味い思いをしたことがないのでもしかしたら16.04でやったほうがいいかもです
症状としてはvisualboxの設定を保存するたびに一分ぐらいフリーズしたりしてました


##環境構成
ホストマシン
・Linux kernel 4.15.0-46-generic
・OS Ubuntu18.04.1LTS
・CPU AMD Ryzen2700X
・RAM DDR4-2400 16GB
・GPU AMD RX480/RX470 
・GPU-Driver　ROCm2.1
・MB ASRock AB350 Gaming K4

仮想環境側
・virtualbox 6.0.4 Ubuntu18.04用debパッケージ
・SereneLinux ベータ版iso version0.1


当環境はLinux環境下で実行しているためWindows環境下などでの再現を保証するものではありません

#環境構築

```
$ wget https://download.virtualbox.org/virtualbox/6.0.4/virtualbox-6.0_6.0.4-128413~Ubuntu~bionic_amd64.deb
$  sudo apt install ./virtualbox-6.0_6.0.4-128413~Ubuntu~bionic_amd64.deb 
```

#仮想環境立ち上げ

![Screenshot from 2019-04-08 05-49-42.png](https://qiita-image-store.s3.amazonaws.com/0/232732/febc47a9-5538-eaf3-3423-7482d5e8991d.png)
visualboxを起動する
![Screenshot from 2019-04-08 05-50-28.png](https://qiita-image-store.s3.amazonaws.com/0/232732/b6157239-a396-d87d-6363-48ecdd2fb39b.png)
Debian64bitで仮想マシンを設定します

![Screenshot from 2019-04-08 05-51-08.png](https://qiita-image-store.s3.amazonaws.com/0/232732/fb516579-ac89-92f4-ff6c-1bb725df3bc1.png)
仮想RAMの割当サイズはここでは2048MBにします

次で仮想HDDを8GB新規作成、ハードディスクのファイルタイプはVDIに設定し任意のディレクトリにファイルの場所とサイズを設定して仮想マシンを作成します

参考までに以下マザーボードの設定など
![Screenshot from 2019-04-08 05-53-32.png](https://qiita-image-store.s3.amazonaws.com/0/232732/0f54d607-6143-2c85-4d82-0b973fcf067c.png)
![Screenshot from 2019-04-08 05-54-08.png](https://qiita-image-store.s3.amazonaws.com/0/232732/9ff291e2-f730-bd5a-1522-0d20c56e1d36.png)
![Screenshot from 2019-04-08 05-54-26.png](https://qiita-image-store.s3.amazonaws.com/0/232732/948a9a0d-966d-74d2-0665-7488f3861ba3.png)

##iso読み込み
![Screenshot from 2019-04-08 05-54-55.png](https://qiita-image-store.s3.amazonaws.com/0/232732/7b67a8bb-8e21-04f8-1ac6-3b99159c73b1.png)
仮想DVDドライブにisoを読み込ませてください![Screenshot from 2019-04-08 05-56-28.png](https://qiita-image-store.s3.amazonaws.com/0/232732/d18f300e-d0d2-9716-a0ba-69eec264321d.png)

システム起動順位を光学ドライブが最上位になるように設定します
![Screenshot from 2019-04-08 06-00-55.png](https://qiita-image-store.s3.amazonaws.com/0/232732/5760f218-af08-80ab-1ae4-50253903599c.png)

![Screenshot from 2019-04-08 06-11-35.png](https://qiita-image-store.s3.amazonaws.com/0/232732/397d99fc-af9c-408b-0d02-8ed7d8bef071.png)
ひとまずこの設定で起動できます。

なんか16.04より不安定なのでUbuntu上で実行する時16.04LSTを使うことをおすすめします
Python競プロerのためのテスト環境構築 with Atom 

# 対象とする人:raising_hand:

これから Python で競技プログラミングを始める方や，すでに競プロerだけどテスト環境を持っていないよって人のための記事です．テスト環境の作り方の記事が見当たらなくて困ったので書きました．単純に標準入力の受け方が知りたい人は以下の記事がまとまっていてすごくいいです．

[Pythonで競プロやるときによく書くコードをまとめてみた](<https://qiita.com/y-tsutsu/items/aa7e8e809d6ac167d6a1>)

例えば入力として

```python
N M
s1 t1 w1 
s2 t2 w3
...
sN tN wN
```

のような複数行の入力があるとき，実行のたびにこれを打ち込むのはとてもとてもつらいです…．この記事では Atom でローカルのテスト環境を作っていきます．VSCode などを使っている人は普通にターミナルが使えると思うので、[Powershellで実行する](#powershellで実行する) から読み進めてください．ただし**MacやLinux**の人は

```
python spam.py < input.txt
```

という風に入力データをtextファイルに書いておいて，リダイレクトして読み込むだけでいいみたいです．お疲れさまでした．以下 Windows10 を想定します．

# Atom と package の導入

以下の記事を参考に Atom と package `platformio-ide-terminal`の導入をしてください（[atom・pythonで競技プログラミングのテスト環境構築](<https://qiita.com/crukky/items/73c1322f5929b1ca5834>)）．これで Atom から簡単に PowerShell を起動できるようになります．

上にあげた記事では

```python 
import sys
f = open('input.txt', 'r')
sys.stdin = f

x = input()
print(x)
```

のようにしてファイルから標準入力を受け取っていますが，競プロではこのまま提出できないので少し不便です（批判しているわけではないです）．__ローカルでテストしてそのまま提出できる__ことを目標にします．

# PowerShellで実行する

Windows では`python spam.py < input.txt` の代わりに

```
Get-Content ./input.txt | python ./spam.py
```

のように実行できます．PowerShell は Atom 下部の [+] から起動できます（下の図）．
![atom_terminal-1554263259387.PNG](https://qiita-image-store.s3.amazonaws.com/0/305855/6c89557f-e7da-1930-1fa1-fe5bb08a8a85.png)

毎回これを打ち込むのは面倒くさいのでスクリプトを書いてさぼります．これから PowerShell スクリプトを作りますが難しくないので初めてでも大丈夫です．（私もこれが2回目なので…）

# スクリプトをかいてラクしたい

先ほどのコードを実行する PowerShell スクリプト`test.ps1`を書きます．

```bash:test.ps1
Get-Content ./input.txt | python ./spam.py
```

注意点ですが PowerShell ではカレントディレクトリであっても相対パスを明示しないとだめです．`hoge.txt` ではなく `./hoge.txt` のように書きましょう（自戒）．

実は PowerShell スクリプトはこのままでは実行できません．実行ポリシーを変更しないと実行できないようになっているからです．そこで Atom から Powershell を起動したら__自動的に実行ポリシーを変更__するようにします．Atom の [file]->[setting]->[Packages]->[platformio-ide-terminal]->[Core]->[Auto Run Command] に 

```
Set-ExecutionPolicy RemoteSigned -Scope CurrentUser
```

を追加します．必要があれば [Working Directrory] も変更しておくといいかもです．私は [Active File] にしました．

これで準備ができました！！！

# 試してみる！

```python:spam.py
import sys
N,M = map(int, sys.stdin.readline().split())
print(N, M)
for _ in range(M):
    s,t,w = map(int, sys.stdin.readline().split())
    print(s,t,w)
```

```python:input.txt
5 3
0 1 4
0 2 3
1 1 2
```

準備ができたらAtom から PowerShellを開いて，`test.ps1`を実行してみてください．標準入力を正しく受け取れたでしょうか？

# 最後に

経験が浅いので，こうしたほうがいいよという指摘などお待ちしております m(__)m．またわかりにくい点は気軽に聞いてください！

# 参考
[PowerShellのリダイレクト](http://d.hatena.ne.jp/MARISHI/20100727/1280232418)
[PowerShellスクリプティングの第一歩](https://www.atmarkit.co.jp/ait/articles/0709/20/news125.html)
【まとめ記事】素人がWebAPI活用ツール作った。

###制作物

バッチファイルを実行すると、チャットツールの使用履歴が指定期間分、テキストで取得できる。
チャットルームは必要に応じて作成し、使用しなくなれば削除する仕様です。

###開発環境

Windows10(1803)
サクラエディタ
VisualStudioCode(1.32)
(Prettierなどの拡張機能インストール済み) 

Node.js(10.15.3)
requestモジュール(6.7.0)

###ソースコード

```Script.js

//Promiseオブジェクト生成：各関数の処理結果や状態を保持してくれる
var promise = Promise.resolve();

//requestモジュールを読み込む
//http通信を行う際に必要なモジュール
var reqM = require('request');

//Fsモジュールを読み込む
//外部ファイル操作に使用する。
var fs = require("fs");

var dataBaseIds = [];

var count = 0;

var promise = Promise.resolve();

promise = promise.then(login)
.then(cHistory)
.then(function loop(databaseIdUrl){
   return new Promise(function(resolve, reject){
      if(count>=dataBaseIds.length){
         console.log("終了しました。");
         process.on('exit', () => {
         process.exit(1);
         });
      }

      var promise2 = Promise.resolve(databaseIdUrl);

      promise2 = promise2.then(setBody)
      .then(call)
      .then(write)
      .then(function increase(completeData){
         return new Promise(function(resolve2, reject){
            count++;
            resolve(databaseIdUrl);
         })
      })
      })
      .then(loop)
   })
.catch(onRejected);

```


###各関数の処理内容

基本的に処理した結果をPromiseオブジェクトで返し、次の関数に引き渡す形式を取っています。

1.ログイン:login()
2.データベースID一覧取得:cHistory()
3.データベースIDごとにチャットルームの詳細情報を取得して、テキストファイルに書き込む
　−3.1.オプション定義:setBody()
　−3.2.WebAPIへPOST:call()
　−3.3.テキストファイル書き込み:write()


###まとめと感想

　作業時間としては、50h程度です。
作業開始当初は「WebAPI一覧(と機能の簡単な概略)」が唯一の頼りで、私自身ProgateでJavaScriptとjQueryを終わらせた程度の知識量しかありませんでした。WebAPIやNode.jsに知見のある方がまわりにいないので、基本一人でモクモクと作業しました。

　中でも非同期処理のループは、実装に時間がかかりました。Promiseを使う前のコードはsetBodyからwriteの流れをfor文で回していました。その結果として、本来時系列順にテキストファイルへ吐き出されるはずの詳細情報が、毎回(時系列)バラバラに吐き出されるという事態に。。。そこからPromiseへ行き着き、可読性やエラー対策などを考えて、制作物を全て作り直しました。
　Promiseに関しては、最初はサンプルコードに対してVSCodeのデバッグ機能やconsole.logを使って処理の流れを理解するところから始めました。応用するのにも、グローバル変数がカウンターに使えなかったり、色々苦労しました。Promise理解から全面改修が完了するまでに5h〜6hはかかりました。。。
Promiseに関しては、別記事で触れようと思います。

個人的には悩む時間の方が長いプロジェクトでしたが、結果的に実用性に足ると評価をいただく事ができたので、非常に有意義なプロジェクトでした。同時に自分の中で「プログラム楽しいな」と感じることができたプロジェクトでした。
ThinkPad X240にUbuntuをインストール

研究室の使っていない中古PCに，Ubuntuを入れて使うことにしました．
研究の前任者と同じ環境を構築したいので，Ubuntu18でなく16.04 LTSをインストールします．
元々本命PCはUbuntuだったので，余裕を持ってインストールすることができたので記事にします．

Ubuntuインストール時に「grub-efi-amd64-signedパッケージを/target/にインストールするのを失敗しました」というエラーメッセージに対処する方法で紹介します．

このエラーはUbuntu18.04でも確認されているようですが，同じように対処できるはずです．

## 今回の環境
- マシン : ThinkPad X240
 - プロセッサ : Intel Core i7-4600U CPU @ 2.10GHz*4
 - メモリ : 7.5GiB
 - OS識別 : 64bit
 - ディスク : 495.6GB
- すでに入ってるOS : ubuntu サーバー
- 新しく入れたいOS : ubuntu 16.04 LTS

## 手順
1. USBを作成
2. PCを起動し，USBからUbuntuを起動
3. Ubuntuをインストールした後のWi-Fiの設定

### 1. USBを作成
僕は16.04でUSBを作成しましたが，最新版の18.04 LTSでする場合の手順を説明します．

まずは，[Ubuntu18.04の日本語RemixのISOイメージ](https://www.ubuntulinux.jp/News/ubuntu1804-ja-remix/ ”Ubuntu18.04ja”)をダウンロード．

次に，[UNetbootin](https://unetbootin.github.io/ "UNetbootin")を使って，Ubuntuのインストールに必要なUSBを作ります．このソフトウェアは，Windows，Mac，Linuxで提供されています．

起動したら以下のような画面になるので，
![スクリーンショット 2019-04-08 2.47.04.png](https://qiita-image-store.s3.amazonaws.com/0/296126/96728c2e-e574-0637-aed3-eb71620fd0dd.png)
以下のように設定します．
![スクリーンショット 2019-04-08 2.48.56.png](https://qiita-image-store.s3.amazonaws.com/0/296126/4c048f7c-01ec-ed4a-00bc-751080beaa5b.png)
すると先ほどのISOイメージをインストールしたブート用のUSBが作れます．"OK"を選択して数分待ってください．
![スクリーンショット 2019-04-08 2.49.16.png](https://qiita-image-store.s3.amazonaws.com/0/296126/6710f815-d486-980f-977f-23f2c5c00c4e.png)
完了したら，USB作成は終わりです．

### 2. PCを起動し，USBからUbuntuを起動
ThinkPad X240では，起動後，F1キーを押してBIOSに入りましょう．

ここで，「セキュアブート(Secure Boot)を無効」にしてください．

さらに，BIOSでの変更を保存後，USBからUbuntuをインストールする際にはWi-Fiにつながずにインストールをしてください．
これをやっていないと，僕の環境では，インストール中に「grub-efi-amd64-signedパッケージを/target/にインストールするのを失敗しました」と出て，インストーラーが強制終了してしまう不都合が起きました．

あとは，インストーラに任せると，20分ほどでインストールが完了し，再起動後にHDDに上書きされたUbuntuを使用することができます．

### 3. Ubuntuをインストールした後のWi-Fiの設定
上記の方法で，Ubuntuをインストールしたとき，Wi-Fiが繋げない，繋ぎ方が分からなくなりました．しかし，これは上記の方法でのみ見つかる不都合ではなかったです．

network-manager周りのバグらしいので，解決方法が載っている記事がたくさんありました．

これに関しては，こちらの記事( http://tamflex.hatenablog.com/entry/2016/08/03/131342 )が分かり易かったです．

これで，Ubuntu16.04 LTSでWi-Fiが使えるようになりました．

突然Firefoxが灰色になってフリーズする現象が起こった人は以下のように対処しましょう．

以下のコマンドを端末で打ち込んで，FirefoxをRefreshしてください．[^1]

`firefox --safe-mode`

これでFirefoxで無事快適なネットサーフィンができるようになりました．

めでたし，めでたし．

### まとめ
「grub-efi-amd64-signedパッケージを/target/にインストールするのを失敗しました」と言うのは，Ubuntu16.04のインストールの際にWi-Fiに繋いだ場合に起こる不都合なようです．

参考
[^1]: https://blogs.yahoo.co.jp/wyamamo/29087731.html
Pimaxが届いたので感想を書いてみる

Pimaxが無事届いて、1週間ほど使ってみたので感想を書いてみます。

##Pimax8kってなに？

https://pimaxvr.com/

VRヘッドセットです。
視野角200度という広さと3840x2160という高解像度が売りのハードです。

Kickstarterで募集していたのでバックしたのですが、
本来発送すると言っていたのが、2017年の12月だったのが遅れに遅れ、
2019年の4月ごろになってやっと行き渡ってきた感じがします。

私のバックしたプランはベースステーションとコントローラも付くやつなのですが、届いたのは本体のみです。
ベースステーションは今年の後半に、コントローラは8月以降という書き込みを見ましたが、これもまた遅れるんでしょうね。
ベースステーションはValveの製品そのままのはずなんですが、遅いのはなんででしょうかねぇ…。

##感想
私が持っているハードが、Oculus Riftなので、それとの比較となります。

画面は抜群にきれいです。
iPhoneのRetina液晶を見たときのような、高解像度感があります。
ViveProと比較したいところですが、ViveProは身近で触れる場所がないのでなんともいえません。

また、視野角200度は本当に広く、一度これに慣れるとRiftに戻ると狭くて仕方ありません。
眼鏡との相性も良いですね。

しかし横より縦の広さが目立ちます。角度にして5度程度しか視野が広くないのですが、この差が結構大きく感じます。
やっぱり下方向が広くて、視界全部がしっかり覆われている感じがあります。

ハードウェアにはIPD(目の間隔)調整ダイヤルと音量ボタン、電源ボタンが付いています。
RiftやViveには電源や音量がないので、新鮮な感じがします。
210度を覆うためかなり横長のハードではありますが、重いと感じることはありません。
実際他のヘッドセットと比較しても軽いらしいですね。

ちなみに、GTX1080で動かしています。
一応推奨スペックとしてはGTX1080Ti以降となっていて、推奨スペックは満たしていないのですが、
大体の場所では気になるほどの動きの悪さは感じませんでした。

ベースステーションもなしで動かしているため、3DoFです。
まぁ、椅子に座って使う分には3DoFでもあんまり不便は感じないんですよね。
ただ、センターがずれているとき、元に戻す方法がないのが困りものです。

##問題点
SteamVRは汎用的なVRのプログラムではありますが、基本的にHTC Viveを想定しています。
そのため、その差異による問題点はあります。

・端がかける
SteamVRの初期画面である、高原の別荘みたいな場所で気が付きますが、
視野の外側にある一部のオブジェクトが出たり消えたりします。
おそらく、Viveの視野で表示外になる場所のオブジェクトを消しているんだと思いますが、
Pimax8kの視野だとそこまで見えてしまうので、オブジェクトが消えちゃうんでしょうね。

・一部ワールドで重い
vrchatでウロウロしたのですが、一部のワールドではやたら重く、3fps程度になってしました。
Riftではちゃんと表示されているので、なんなんでしょうね。
多分、鏡があるとやばいんじゃないかなーとか思っています。

追記：
VRAMの使用量を測ってみると、めちゃくちゃ重くなる場合はVRAMを使い切っていました。
GTX1080は8GBですが、GTX1080Tiは11GB搭載していて、そのVRAMの多さが推奨の理由かと思います。
Riftでも同じワールドに行ってみましたが、メモリは使い切っていていました。
ただ、Riftの場合、最初はカクカクするんですが、数秒すればカクカクが治るんですよね。
メモリを使い切ったあとの挙動が違うんでしょうかね？

・コントローラ未発売
コントローラがないので、XBOXコントローラで動かしています。
今やVRのコントローラといえば両手が動くものが当たり前ですから、
ほとんどのソフトは遊べず悲しいことになってしまいます。

一応、HTC Viveのトラッカーやコントローラが使えるのですが、
Vive付属のコントローラは出来が悪すぎて、OculusTouchに慣れている自分には
あれをわざわざ買いたいとは思わないんですよね。
HTCの新ハードのIndexに期待、でしょうか…。(でも、そのうち届くはずなんだよなぁ…)

##総評
かなり良いハードではありますが、これを1台目にするのはあまりにも不安定すぎて、全くおすすめできません。

もし、予定通りに去年の初期に発売していれば、対応ソフトも増えてよかったんでしょう。
Kickstarterで多額の資金を集めたので、ストレッチゴールとして
ヘッドホン付きストラップ、アイトラッキング装置が無料、無線モジュールの割引クーポンなどを提唱しています。
この辺、有料でもいいので早く欲しいものばかりなんですよね。

去年のうちに出ていれば期待の新星ともてはやされたかもしれません。
しかし、今年になって他社が新ヘッドセットを出してきていているので、
Pimaxも大分見劣りするハードに見えてきています。
Kickstarter組だと、かなりお得な価格でしたが、製品版となると2倍以上の価格になるでしょう。
アクセサリなども含めてすべてが出揃って、ソフトも対応するまで待っても全然問題ないと思います。
kafka-nodeのConsumerを使ってみた

# はじめに
kafka-nodeを少し使う機会があったので、備忘録としてまとめます。
ちなみにnode-rdkafkaも試したけど、開発に使ってるWindowsマシンでビルドできなかったので諦めました。

# Consumerの種類
Consumerは4種類あって、機能差分はこんな感じ。
とりあえず一番良いのをくれって時は、ConsumerGroupStreamを使えばよさげ。

|名前|Stream機能|Group機能|
|---|:-:|:-:|
|Consumer|×|×|
|ConsumerStream|○|×|
|ConsumerGroup|×|○|
|ConsumerGroupStream|○|○|

## Stream機能
StreamAPIで実装されて、バッファを持ってるらしい。多分効率が良い。
ただのConsumerと違って"message"ではなく、"data"でイベント通知されるので注意。

## Group機能
Group機能がないConsumerは、明示的に読み込むパーティションを指定する必要がある。（指定しないとデフォルトの0番パーティションのみ読み込まれて、他のパーティションが読み込まれない）
大抵のユースケースでは「複数パーティション、複数コンシューマでスケールアウトしたら良い感じに自動でパーティション割り当てして欲しい」って感じだと思うので、こちらを選択することになると思われる。
逆に「特定のパーティションは、特定のコンシューマに処理させたい」って要件の場合はGroupじゃないやつを使う。

# 実際に使ってみる
## Kafkaを用意する
dockerでさくっと用意して、パーティション数3のtestトピックに適当にメッセージを入れます。

```bash
docker run -p 2181:2181 -p 9092:9092 --env ADVERTISED_HOST=`docker-machine ip \`docker-machine active\`` --env ADVERTISED_PORT=9092 --name test_kafka spotify/kafka
docker exec -it test_kafka bash
cd /opt/kafka*
bin/kafka-topics.sh --create --zookeeper localhost:2181 --replication-factor 1 --partitions 3 --topic test
bin/kafka-console-producer.sh --broker-list localhost:9092 --topic test
> message1
> message2
> message3
> message4
bin/kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic test --from-beginning
```

## docker machineのIPを確認する
docker machineで動かしているので、ローカルから接続する時のIPを確認しておきます。

```bash
docker-machine ip
# 192.168.99.100
```

## ConsumerGroupStreamで読み込む

```bash:プロジェクトを作成
mkdir kafka-test
cd kafka-test
npm init -f
npm i kafka-node
touch test.js
```

```javascript:test.js
const kafka = require('kafka-node')

const consumer = new kafka.ConsumerGroupStream({
  kafkaHost: '192.168.99.100:9092',
  groupId: 'TestGroup',
  fromOffset: 'earliest'
}, 'test')

consumer.on('data', message => {
  console.log(message)
})
```

```bash:実行結果
$ node test.js
{ topic: 'test',
  value: 'message3',
  offset: 0,
  partition: 0,
  highWaterOffset: 1,
  key: null,
  timestamp: 2019-04-07T16:56:45.611Z }
{ topic: 'test',
  value: 'message2',
  offset: 0,
  partition: 1,
  highWaterOffset: 1,
  key: null,
  timestamp: 2019-04-07T16:56:42.667Z }
{ topic: 'test',
  value: 'message1',
  offset: 0,
  partition: 2,
  highWaterOffset: 2,
  key: null,
  timestamp: 2019-04-07T16:56:40.005Z }
{ topic: 'test',
  value: 'message4',
  offset: 1,
  partition: 2,
  highWaterOffset: 2,
  key: null,
  timestamp: 2019-04-07T16:56:48.987Z }
```
以上です。
【Talend】TalendStudioにカスタムコンポーネントの追加

# 標準コンポーネントとカスタムコンポーネントについて

TalendOpenStudio に標準で組み込まれているコンポーネントは、Talendにより検証されており、使用するには十分な機能を持っています。

Talendのコミュニティ「[Talend Exchange](https://exchange.talend.com)」では、
標準のコンポーネントでは、機能不足であったり、独自にカスタマイズや、新規開発されたコンポーネントが公開されています。
Talendによる検証はされていませんが、世界中の開発者によって検索され利用されたコンポーネントは評価、フィードバックを受けて改良が加えられていきます。

今回は、「[Talend Exchange](https://exchange.talend.com)」から興味を持ったコンポーネント「tWebCrawler」をインストールしてみます。

参考
[Talend Exchangeからコミュニティコンポーネントをインストールする](https://help.talend.com/reader/PeqY~rYY2iqeUe3PXIgorA/JUlRCg7KprKFMVSrrX2ANg)

# カスタムコンポーネントのインストール

Talend Open Studioのツールバーの[Exchange]リンクをクリックし、コンポーネント「tWebCrawler」を選択します。
![custom_crawler_04.jpg](https://qiita-image-store.s3.amazonaws.com/0/165430/215eda50-f60f-1daf-c3ec-1125bacf47c0.jpeg)
「Install」ボタンをクリックします。
![custom_crawler_05.jpg](https://qiita-image-store.s3.amazonaws.com/0/165430/62b29558-1971-bccd-c528-04469bf23647.jpeg)
![custom_crawler_06.jpg](https://qiita-image-store.s3.amazonaws.com/0/165430/7358995b-a136-cb4c-247a-940e03bb3411.jpeg)
インストールされるとInstalled になるとHelpに書いてありましたが、特に変わりませんでした。
![custom_crawler_07.jpg](https://qiita-image-store.s3.amazonaws.com/0/165430/632e2733-bc92-cdb4-2775-12a7dc38782c.jpeg)

試しにジョブを作成してみたところ、コンポーネントの選択肢に「tWebCrawler」が出てきました。
![custom_crawler_08.jpg](https://qiita-image-store.s3.amazonaws.com/0/165430/cb07e74b-0021-38d9-3bdb-cff47df61fbd.jpeg)

試しに私の別の記事をCrawling してみました。
検索キーワード「title」
![custom_crawler_09.jpg](https://qiita-image-store.s3.amazonaws.com/0/165430/4df72c5d-94e4-4a17-0dcd-02e8afac3172.jpeg)

tLogRowで結果を表示してみます。
![custom_crawler_10.jpg](https://qiita-image-store.s3.amazonaws.com/0/165430/e20310fc-191b-0e60-e221-1c05014dff6e.jpeg)
表示を少し絞ってみます。
![custom_crawler_11.jpg](https://qiita-image-store.s3.amazonaws.com/0/165430/3711fc05-86ae-68f9-16bc-b4c188f06fec.jpeg)

実行してみました。
![custom_crawler_12.jpg](https://qiita-image-store.s3.amazonaws.com/0/165430/13525f18-243e-1a6e-b2ef-17d4bd176434.jpeg)

手軽にCrawlingできました。
下記の様な設定もできるようです。
![custom_crawler_14.jpg](https://qiita-image-store.s3.amazonaws.com/0/165430/6588415f-c462-a527-e715-0189eae1ad00.jpeg)

![custom_crawler_13.jpg](https://qiita-image-store.s3.amazonaws.com/0/165430/be4b84ab-e745-346b-6301-764882527def.jpeg)

# まとめ

標準コンポーネントでも、同様なことはできると思いますが、
手軽にCrawling できそうです。
Talend7.1 に対応したコンポーネントは、まだ少ないですが
これから、既存のコンポーネントが徐々に追加されていくと思われます。

気に入ったコンポーネントがあったら、また紹介しようと思います。
自分でも、作ってアップロードしてみたいですね。
redux-saga without redux reconnecting to redux

# やりたいこと

**reduxに依存せずredux-sagaを使う**
さらにその上で、
**pureなreduxを使う**


こちらの記事と方向性は似ていますがredux-sagaまでは捨てられません。
[ReduxでのMiddleware不要論](https://qiita.com/uryyyyyyy/items/d8bae6a7fca1c4732696)

# なにがうれしいか
- pureなreduxが使える。reduxはstoreを管理するだけになりシンプル
- reduxに代わるステート管理の機構やフレームワークへの差し替えがきく

# どうやるか
redux-sagaにはExternal APIとして、runSaga(options, saga, ...args)というredux-saga以外のコンテキストからsagaを実行するAPIが存在することは以外と知られていないかもしれません。以下を参照
https://redux-saga.js.org/docs/api/
これを使えば、redux middlewareにredux-sagaをインストールすることなく任意のsagaを実行できます。
まずは、以下のようなrunSaga()のラッパーを書きます。

```javascript:helper.js
const sagaOptionSingleton = (() => {                                                                                              

	let channelStd = stdChannel();
	let emitter = new EventEmitter();
 
 	emitter.on("action",channelStd.put);
 
 	return {
 	  	channel:channelStd,
 		dispatch:output => {
			emitter.emit("action",output);
 		},
 		getState:() => {}
 	};
 })();

export function runSagaWithFixedOpt(saga){                                                                                                            
  runSaga(sagaOptionSingleton,saga);
}
```
オプションにstdChannelのインスタンスを設定しているところが重要です。
公式ドキュメントではあまり説明されていませんが、
stdChannelはsagaのコンテキストで何らかのデータがyield putされた時sagaのaction channelにバッファするためのインターフェースです。これはシングルトンでなければいけません。
そのため、self executing functionでsagaOptionSingletonを生成し、runSagaのオプションは常にこれを使います。

このように、reduxのミドルウェアではなくなるため、当然ながらこのラッパーを使って実行するsagaやそこからフォークされるsagaの内部でyield putをしても、reduxのstoreには影響が及びません。
storeにデータを書き込みたければ普通にstore.dispatch()を使うだけです。
これでpureなreduxを使うことができるようになりました。

では、react-reduxのmapDispatchToPropsからdispatchされたアクションをsagaはどのように検知するか。

上記と同じ理由で検知できないので、
代わりに上記で書いたヘルパーを更にラップします。

```javascript:helper.js
export function sendToSaga(data){
    function* sendSomethingToSaga(){    
       yield put(data);
    }
    runSagaWithFixedOpt(sendSomethingToSaga);
}
```
つまり非sagaコンテキストから単発のsagaを起動し、putを実行することでsagaへイベントを送ります。
すると、mapDispatchToPropsの実装は以下のようになります。

```javascript
const mapDispatchToProps = dispatch => {
  return {
    increment: () => {
      sendToSaga({ type: 'INCREMENT' });//sagaへイベントを送る
    }
  }
}
```
このようにdispatchを使わなくなりました。（別に使っても良い）

# 結論
reduxに依存することなくredux-sagaを使うことができるようになりました。
Laravelでページ毎にロードするJavaScriptをいい感じにする

# 概要
Laravelのアプリケーションを作っている時に、JavaScriptを1つの大きなファイルにしてレイアウトファイルで読み込むのもいいが、JSファイルが大きくなったときのことを考慮して、ページ毎にロードするJavaScriptをディレクトリ構造からいい感じに分けたい。

# 実装方針
`/` では `public/js/top.js`
`/article/index` では `public/js/article/index.js`
`/article/show` では `public/js/article/show.js`


上記のように `public/js/${controller名}/${action名}.js` といった階層構造(`/` は例外)のJavaScriptを読み込むようにする。

# 実装

artisanコマンドでミドルウェアを作成する。

```
$ php artisan make:middleware LoadJavaScript
```

対象とする画面のルーティングに自作のMiddlewareを通るようにする。

```app/Http/Kernel.php
    protected $middlewareGroups = [
        'web' => [
            \App\Http\Middleware\EncryptCookies::class,
            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
            \Illuminate\Session\Middleware\StartSession::class,
            // \Illuminate\Session\Middleware\AuthenticateSession::class,
            \Illuminate\View\Middleware\ShareErrorsFromSession::class,
            \App\Http\Middleware\VerifyCsrfToken::class,
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
            /* この1行を追加 */
            \App\Http\Middleware\LoadJavaScript::class,
        ],
    ];
```

RequestオブジェクトからURIを取得していい感じに整形してview側で使えるようにする。
`/` のみ直接指定する必要がある。

```app/Http/Middleware/LoadJavaScript.php
<?php

namespace App\Http\Middleware;

use Closure;

class LoadJavaScript
{
    const JAVA_SCRITP_DIR = 'js';
    const JAVA_SCRIPT_EXTENSION = '.js';

    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        $requestRouteName = $request->route()->getName();

        if ($requestRouteName === null) {
            $scriptPath = 'top';
        } else {
            $scriptPath = str_replace('.', '/', $requestRouteName);
        }

        view()->share('scriptPath', self::JAVA_SCRITP_DIR . '/' . $scriptPath . self::JAVA_SCRIPT_EXTENSION);

        return $next($request);
    }
}
```

レイアウトファイルでJSをロードする。

```layout.blade.php
<script src="{{ asset($scriptPath) }}"></script>
```

以上です。
C言語の可変長引数の関数の作り方

可変長引数の関数の作り方をまとめる。

## 可変長引数の関数の宣言と実装
仮引数の可変にする部分を...で書く。

```C
// プロトタイプ宣言
// 第一引数で文字列をもらって、第二引数以降は型も引数の数も特に指定しない
void func(char *arg_1, ...);
```

```C
// 実装
// 第一引数で文字列をもらって、第二引数以降は型も引数の数も特に指定しない例
void func(char *arg_1, ...) {

    ~処理~

}
```

## ①va_listの定義
stdarg.hでは可変数個の引数をリストとして格納できる型としてva_list型が定義されている。
まずは可変長引数の関数内でva_list型の変数を定義する。

```C
va_list ap;
```

## ②va_listの初期化
va_listが指す先を可変長個の引数の最初1個目に向けてやる。
これにはstdarg.hで定義されているva_start()マクロを使う。


```C
// apは①で定義したva_list型の変数、arg_1は引き数リストのうち、可変な部分の直前に置かれる引き数
va_start(ap, arg_1);
```

例えば次のようなコードがあったとすると

```C
void func(char *arg_1, ...) {
    va_list ap;
    va_start(ap, arg_1);
    
    ~処理~

}
int main(void) {
    char *arg_1 = "aaaaa";
    int arg_2 = 5;
    double arg_3 = 3.14;

    func(arg_1, arg_2, arg_3);
}
```

func呼び出すと、実引数は下記のようにスタックに積まれ（Cでは実引数を後ろから積んでいくため）、
va_start(ap, arg_1)が実行されて、apは初期化され、"apが指す位置"はarg_1になる。

#### スタックのイメージ図

```

|arg_1| <---apが指す位置
|arg_2| 
|arg_3|
```

## ③引数リストから値を取り出す

引数リストから値を取り出すにはva_arg()マクロを使う。
va_arg()マクロは"apが指す位置"の次の位置にある値を指定した型で取り出す。
その後、"apが指す位置"を次の位置(取り出した値の位置)に進める。

```C
// apは①で定義し、②で初期化したva_list型の変数、typeは取り出す引数の型
va_arg(ap, type);
```

例えば次のようなコードがあったとすると

```C
void func(char *arg_1, ...) {
    va_list ap;
    va_start(ap, arg_1);
    printf("arg_2: %d\n", va_arg(ap, int));
    printf("arg_3: %lf\n", va_arg(ap, double));

    ~処理~

}
int main(void) {
    char *arg_1 = "aaaaa";
    int arg_2 = 5;
    double arg_3 = 3.14;

    func(arg_1, arg_2, arg_3);
}
```
"apが指す位置"は下記のように進んでいく。

#### スタックのイメージ図

```
va_start(ap, arg_1)を実行した直後

|arg_1| <---apが指す位置
|arg_2| 
|arg_3|
```
```
va_arg(ap, int)を実行した直後

|arg_1|
|arg_2| <---apが指す位置 
|arg_3|
```
```
va_arg(ap, double)を実行した直後

|arg_1|
|arg_2|
|arg_3| <---apが指す位置 
```
## ④使用後のva_list 型変数の処分

manによると「va_start() が実行される毎に、同じ関数内で対応する va_end() が実行されなければならない。」とある。
引数リストの解析が終わったら、va_end() を呼んでやる必要があるようだ。

```C
void func(char *arg_1, ...) {
    va_list ap;
    va_start(ap, arg_1);

    ~処理~
    va_end(ap);
}
```


## 引数の数が分からないため、va_argを何回呼べばいいか分からない

この問題のために、可変長引数関数を作る際には次のような工夫が必要なようだ。

#### (i) printfのように可変でない部分の引数で引数の数を特定できるようにする。
つまり、printfであれば、第一引数が"%s---%d---%lf\n"となっていれば、その後に続く引数の数は3つだとわかる。

#### (ii) 引数リストに番兵（NULLとか）をいれ、それをチェックしてやる。

## 引数の型が分からないため、va_arg(ap, type)のtypeに何を指定していいか分からない

この問題のために、可変長引数関数を作る際には次のような工夫が必要なようだ。

#### (i) printfのように可変でない部分の引数で引数の型を特定できるようにする。
つまり、printfであれば、第一引数が"%s---%d---%lf\n"となっていれば、その後に続く引数の型はchar*型、int型、double型だとわかる。

# 参考
https://linuxjm.osdn.jp/html/LDP_man-pages/man3/stdarg.3.html
LDAPで快適Linux環境 #1 概要

高校の部活で、部員たちが使えるLinux環境を構築することになりました。それなりの人数が同時に使うわけで、誰がどの席を使うかも不特定です。そこで、

- ユーザーとグループをLDAPで管理
- ホームディレクトリをNFSでautomount

とすることにしました。

やったこととしては、

- LDAPサーバーの設定
    - ユーザーとグループの追加
    - schemaの追加
    - automountマップの設定
    - sudoの設定
- LDAPクライアントの設定
    - LDAPログイン
    - ホームディレクトリのautomount
    - sudoの設定をLDAPから取得
    - 使いたいパッケージの追加

といった流れです。
ディストリビューションは師匠に倣ってDebian GNU/Linux stretchを使っていきます。[次回](https://qiita.com/uuu_n/items/a1dbdde83f47bc4364e5)から、詳しい内容に入ります。

# リンク
- [ldifファイルのサンプル](https://github.com/UNIX-lab/ldif)
- [#2 LDAPサーバーの設定](https://qiita.com/zawanume/items/a1dbdde83f47bc4364e5)
- [#3 LDAPアカウントの追加](https://qiita.com/zawanume/items/9a0ba8823180de3b3ab6)
- [#4 LDAPアカウントでログイン](https://qiita.com/zawanume/items/efe59cce54ffbc470216)
- [#5 NFSの設定](https://qiita.com/zawanume/items/2327c590b983ad454937)
- [#6 sudoの設定](https://qiita.com/zawanume/items/f21a18a6e1f50e7fed18)
MojaveではAPFS

前回(https://qiita.com/uuu_n/items/2a72e6b9ebb669e48e9c) 、オンボロMacにOSを入れるときに何も考えずにSSDを「Mac OS 拡張(ジャーナリング)」でフォーマットしました。
ソフトウェアアップデートが来ているとネットニュースで見たので適用しようとすると、「**お使いのMacは最新の状態です。**」嘘だろ？

真っ先に疑うのはMojave Patcherのバグです。困ったときは公式サイトを読もう(ただし英語)。→http://dosdude1.com/mojave/
![Screenshot at 2019-04-08 00-44-40.png](https://qiita-image-store.s3.amazonaws.com/0/370590/f27757ba-5e62-100c-9f1a-5f63fed588cd.png)
要約すると、

- Mac OS 拡張(ジャーナリング)とAPFSがつかえるよ。GUIDパーティションにしてね。
    - Mac OS 拡張(ジャーナリング)にすると、**システム設定からアップデートできないよ。**
        - Late 2009以降ならHigh Sierraと変わらずにAPFSが使えるよ。
        - APFSにネイティブ対応してないマシンでAPFSを使うと、リカバリーパーティションが使えなかったりいろいろ面倒だよ。

どうやらバグではなく仕様のようです。インストールメディアを作って一から入れましょう。いろいろ問題はあるようですがAPFSでやってみます。
![IMG_2377.JPG](https://qiita-image-store.s3.amazonaws.com/0/370590/06d87937-73c3-c6c5-568d-c13fe3801555.jpeg)
前回同様、インストールメディアを外付けHDDに作り、必要なものは避難させておきます。前回との違いは、フォーマットでAPFSを選ぶ点です。
インストールを進めていき、終了して再起動してカーネルパニックまでは想定内。前回同様、再び外付けHDDから起動しパッチを当てましょう。ここで起動時にいちいちハードウェアテストらしき画面が走るようになってますが、気にしない。
<img src="https://qiita-image-store.s3.amazonaws.com/0/370590/bcb2e587-6443-84d9-a5ef-2604a2f6d6d3.jpeg" width=75%>
林檎が表示されたら、祈りましょう。起動に成功すると、初期設定が走るので済ませます。

Macではサードパーティ製のSSDでデフォルトでTRIMが無効になっているので有効にしましょう。
<img src="https://qiita-image-store.s3.amazonaws.com/0/370590/1f1048e4-0fe3-99b4-78fc-34a432874714.jpeg" width=75%>
ターミナルを起動し以下のコマンドを実行します。

```bash
hoge@mac~$ sudo trimforce enable
```
パスワードを入れると、警告文が出てYesかNoか聞かれます。yと入れてEnter。すると再起動します。
<img src="https://qiita-image-store.s3.amazonaws.com/0/370590/2c5734f7-a083-fa8f-6951-0697e88b2800.jpeg" width=75%>
システムレポートでTRIMサポートが「はい」になっていたら成功です。

次からは楽にアップデートできるといいです。
Androidのファイルとパッケージ(フォルダ的なの)の作り方。おまけにクラス拡張方法

すごく基礎の基礎だと思うのですが投稿します(o*｡_｡)o　わ、忘れないように…
わからないけど、qiitaに書くと定着する気がする(✿´ ꒳ ` )いや、気のせいだ、またすぐ忘れる…

#ファイルの追加
<img width="866" alt="スクリーンショット 2019-04-08 0.50.02.png" src="https://qiita-image-store.s3.amazonaws.com/0/133940/0153fc3d-a1fc-1e44-ef04-c853e54e2c9a.png">

#フォルダの追加
<img width="870" alt="スクリーンショット 2019-04-08 0.57.17.png" src="https://qiita-image-store.s3.amazonaws.com/0/133940/6c4757c6-678a-7eba-5b73-63ade4e2d066.png">


#フォルダの中にファイルを入れる
<img width="901" alt="スクリーンショット 2019-04-08 1.00.38.png" src="https://qiita-image-store.s3.amazonaws.com/0/133940/85294b97-b03c-873d-91c5-9ae8818a1536.png">

#使ってみる
※クラスを使うものと、もともとのクラス(String)の拡張を使ったもの。

```TextArrange.kt
package com.example.kiso.Sample

class TextArrange {

    fun sample(){
        println("TextArrangeクラスのsampleです！")
    }
}

fun String.addText(text:String):String {
    return this + text
}
```

```MainActivity.kt
package com.example.kiso

import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import com.example.kiso.Sample.TextArrange
import com.example.kiso.Sample.addText

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        println("おはよう".addText("ございます"))

        val textArrange = TextArrange()
        textArrange.sample()
    }
}
```

出力結果
<img width="697" alt="スクリーンショット 2019-04-08 1.07.01.png" src="https://qiita-image-store.s3.amazonaws.com/0/133940/6621f813-b714-470b-1c2d-67581b9aa4bc.png">
Rails5 with DatetimePicker

## Rails5 with DatetimePicker
検索機能実装するにあたり、登録日時(created_at)や更新日時(updated_at)を検索条件としたい場合(それ以外の場合でも)月日をGUIで指定できるDatepickerは有名ですが、時間も指定できるDatetimepickerというものがあり、そちらで実装してみようと思いました。

## しかし...
ですが、Rails DatetimepickerでGoogle先生にお伺いたて、検索した結果、Bootstrap３まで対応しているDatetimepickerの記事が多く、Bootstrap4を使っているので、採用できませんでした。

## Tempus Dominusの導入
[このQiita記事](https://qiita.com/nozomi53motomachi/items/fef1b90e69b4a3b52bf7)の「Tempus Dominus」を導入します。

### Gemfile

Gemfileに以下を追加します。

```bash:Gemfile
# bootstrap4
gem 'jquery-rails'
gem 'bootstrap', '~> 4.3.1'

# font-awesome
gem 'font-awesome-rails'

# moment.js
gem 'momentjs-rails'

# Tempus Dominus
gem 'bootstrap4-datetime-picker-rails'
```

```bash:Terminal
$ bundle install
```

### application.js

```js:application.js
//= require jquery3

//= require popper
//= require bootstrap-sprockets

//= require moment
//= require moment/ja.js

//= require tempusdominus-bootstrap-4.js
```

tempusdominus-bootstrap-4.jsの前にmomentをimportしてください。
(エラーになります。)

### application.scss

```css:application.scss
// for Bootstrap4
@import "bootstrap";

// for font-awesome
@import "font-awesome";

// for TempusDominus
@import "tempusdominus-bootstrap-4.css";
```

js同様、tempusdominus-bootstrap-4.cssの前にbootstrap、font-awesomeをimportしてください。

### form.html.erb

実際にformを埋め込むところを以下のように記述

```erb:form.html.erb
<div class="input-group" data-target-input="nearest">
    <%= f.text_field :created_at, id: "created_at", class: "form-control datepicker", data: { target: '#created_at'} %>
    <div class="input-group-append" data-target="#created_at" data-toggle="datetimepicker">
        <div class="input-group-text"><i class="fa fa-calendar"></i></div>
    </div>
</div>
```

jsに以下のように記載

```js:js
<script>
  $(function () {
    $('.datepicker').datetimepicker({
      format: 'YYYY-MM-DD HH:mm:ss'
    });
  });
</script>
```

formatとして「2019-01-01 00:00:00」を指定しています。

### 起動

![datetimepicker.gif](https://qiita-image-store.s3.amazonaws.com/0/75277/e5a1878c-ca9f-6961-c14d-6beb6f6a04b5.gif)

## 参考URL
[RailsとBootstrap4 でカレンダー形式の日付入力フォームを実装する](https://qiita.com/nozomi53motomachi/items/fef1b90e69b4a3b52bf7)
[Tempus Dominus](https://tempusdominus.github.io/bootstrap-4/)
[Moment.js](http://momentjs.com/)
xamppでphpmyadminにアクセスできない時

ある書籍を勉強しているとxamppでphpmyadminを開かなければいけなくなったので、書籍のとおりにやってみるとエラーがでて入れなかった。

 

ググるとすぐ解決法が見つかってよかった。

 

xamppフォルダのetc/extra/httpd-xampp.conf/のphpmyadminの部分をググったとおりに書き換えたら開けた。

 

<Directory "/opt/lampp/phpmyadmin">
AllowOverride AuthConfig Limit
Require all granted
Require local
ErrorDocument 403 /error/XAMPP_FORBIDDEN.html.var
</Directory>
Permission deniedのエラー解決方法


~をpythonでやってみたい！
→記事を見つける
→GitHubからソースコードをダウンロードする
→コマンドを実行してインストールする
→Permission deniedのエラーが出てしまった

こんな初心者の初期段階における解決方法

例えば、GitHubに

『『『解凍したディレクトリで以下のコマンドを実行します。
　　　$ python setup.py install』』』

素直にこれを実行すると、
Permission deniedのエラーが出てしまった。

これは、「アクセス権がない!」ということ。
これをクリアするのが、sudoコマンド。
sudoとは管理者（Super User）として実行（Do）、実効せよという意味。

そこで、
$ sudo python setup.py install
とすれば、
解決！！

たったこれだけ！
だが、初心者には恐ろしいプログラミングです。
頑張ります！
Ubuntu 18.04にLAMP環境をインストールする。

**Ubuntu 18.04.2**に**LAMP**をインストールしたので、その時の手順をメモしておきます。

# 1. Taskselをインストール
`$ sudo apt install tasksel`

# 2. Taskselを使ってLAMPをインストール
`$ sudo tasksel install lamp-server`

# 3. インストールしたLAMPのバージョン確認
以下のコマンドを実行して**Version**が表示されれば、問題なくインストールできています。

## 3-1. Apacheのバージョン確認
`apachectl -v`
## 3-2. MySQLのバージョン確認
`$ mysql --version`
## 3-3. PHPのバージョン確認
`$ php --version`

# 4. PHPとApacheの動作確認
**phpinfo()**を使ってPHPとApacheの動作確認をします。

## 4-1. Apacheを起動
`$ sudo service apache2 start`
##
`$ cd /var/www/html`
## 4-2. index.phpの作成
`var/www/html$ vi index.php`
viコマンドの使い方は以下のサイトをご確認ください。
[ｖｉエディタの使い方](https://prev.net-newbie.com/linux/commands/vi.html)

```index.php
<?php
phpinfo();
?>
```
index.phpが作成されているか確認
`var/www/html$ cat index.php`

## 4-3. ブラウザで確認
ブラウザで以下のリンクにアクセスし、PHPの情報が表示されれば問題ありません。
`http://(LinuxのIPアドレス)/index.php`

なお、LinuxのIPアドレスは以下のコマンドで確認できます。
`$ ip a`

#参考記事
[How to Install a LAMP Stack on Ubuntu 18.04](https://www.linode.com/docs/web-servers/lamp/install-lamp-stack-on-ubuntu-18-04/)
[猿にも分かるかもしれない、LAMPの構築方法](https://opensourcetech.hatenablog.jp/entry/2015/02/27/LAMP%E7%92%B0%E5%A2%83_(Linux_+_Apache_+_MySQL_+_PHP)%E3%81%AE%E6%A7%8B%E7%AF%89_on_CentOS_6_6)
OpenCVの勉強②（オブジェクト検出）


opencvの勉強、第2回です。
今回はオブジェクト検出（顔検出）をしたいと思います。
ちなみに、第1回は[こちら](https://qiita.com/takanorimutoh/items/1085c102fa7023f50bc9)です。

# カスケード型分類器の準備
今回は予め用意されたカスケード型分類器を使って、顔検出をしてみたいと思います。

####Anacondaをインストールされた方
Anaconda3フォルダの中の\Lib\site-packages\cv2\dataフォルダに分類器が入っています。

####Anacondaをインストールされていない方
学習済みの分類器を[OpenCVの公式サイト](https://opencv.org/)からダウンロードします。
* 上部にある「Releases」から自身のOpenCV Versionの「Win Pack」をダウンロード
* ダウンロードしたファイルを解凍
* **\opencv\sources\data\haarcascades**の中に分類器が入っています。

今回は**haarcascade_frontalface_default.xml**(正面からの顔を検出する分類器)を使ってみることにします。
分類器**haarcascade_frontalface_default.xml**とサンプル画像(前回使ったhisyo.jpg)は、pythonファイルは同じディレクトリに保存します。

#顔検出の実行
とりあえず、下のコードを使って、顔検出をしてみましょう。

```face.py
import cv2

# 入力画像の読み込み
img = cv2.imread("hisyo.jpg")
    
# カスケード型識別器の読み込み
cascade = cv2.CascadeClassifier("haarcascade_frontalface_default.xml")
 
# グレースケール変換(グレースケールを使用すると、高速に顔検出できるらしい)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    
# 顔領域の探索
face = cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=3, minSize=(30, 30))
    
# 顔領域を赤色の矩形で囲む
for (x, y, w, h) in face:
    cv2.rectangle(img, (x, y), (x + w, y+h), (0,0,200), 3)

# 結果画像を保存
cv2.imwrite("result.jpg",img)

#結果画像を表示
cv2.imshow('image', img)
cv2.waitKey(0)
```

# 顔検出の結果
ばっちり顔検出ができました！
![result.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/353289/4f87e368-730c-2944-4a73-b16efd43a401.jpeg)


他の画像でも試してみましょう。
![pic2.jpg](https://qiita-image-store.s3.amazonaws.com/0/353289/384a0f32-c821-62bc-0457-e9b153866964.jpeg)
![pic2_result.jpg](https://qiita-image-store.s3.amazonaws.com/0/353289/e8f98aa1-2d78-acee-d194-55f5ec33ca76.jpeg)
ばっちり顔検出できました（マスクまで顔検出されました）

![pic.jpg](https://qiita-image-store.s3.amazonaws.com/0/353289/3520b7e4-b005-aa74-1891-d7b3ae7a40dc.jpeg)
![pic_result.jpg](https://qiita-image-store.s3.amazonaws.com/0/353289/20730b58-802e-d773-f623-e3c61145bb28.jpeg)
一部検出できないものや誤検出がありますが、概ね正しく検出できているようです。

#参考文献
[こちら](https://algorithm.joho.info/programming/python/opencv-haar-cascade-face-detection-py/)のサンプルソースを参考にさせていただきました。顔検出の原理もわかりやすく書かれています。