OmniAICreator/Qiita-1.07M huggingface dataset:
Vue.jsのハマりどころ

## 概要
- 2年くらいVueで開発してるけど、いまだにハマるポイントを書いた
- これから、Vueの開発をする or している人の参考になればと思います！

# propsされた値をv-modelに渡したい
- 親から渡されたデータを子コンポーネントにv-modelで渡したい時
    - ついつい、v-modelでそのまま渡したくなるが、禁物
    - v-modelは、直接データを書き換えてしまう！
- computedするパターンが多い
    - computedは`get``set`の両方を書ける

```javascript
export default {
  props: {
    hoge: {
      type: String,
      required: true
    }
  },
  computed: {
    hogeHoge: {
      get() {
         return this.hoge
      },
      set(value) {
         this.$emit('input', value)
      }
    }
  }
}
```

- また、上記コンポーネントを呼び出す際は以下のようにする
    - `v-model="hoge"`は以下のコードと同義の`syntax suger`
        - `:value="hoge"` `@input="hoge=value"`

```vue:親コンポーネント
<template>
  <clild-component v-model="hoge" />
</template>

// 上記と同義
<template>
  <child-component :value="hoge" @input="hoge=value">
</template>
```

# コンポーネントを再表示するとデータが消える or 不要なデータが残る
- `v-if`などで表示を切り替えする際に、よく起きる
- メモリ上にDOMが残っていることが原因
    - 一見、データが消えたように見えても、メモリ上では保持している
- たいていの場合、`created`内で、propsされた値をDataに移し替えていることが多い

## 解決策として
- propsされた値はコンポーネント中では持たず、`computed`で保持する
    - `emit`で更新する！
- Vuexを使う
C#でrar圧縮

# RARとは
・リカバリレコード付きの圧縮フォーマット．[リード・ソロモン符号](https://en.wikipedia.org/wiki/Reed%E2%80%93Solomon_error_correction)を付加することでファイルの破損(昨今のNAND flash memory:SSD,USBmemoryは多値化が進みデータが一年程度で揮発する)の修復を可能とする.
・シェアウエアである．
・ZIPと異なりC#にはrar圧縮する機能は組み込まれていない．そのためRar.exeを外部アプリとして呼び出す必要ががある．

# Rar.exeの入手
Rar.exeをexeと同じ階層に配置する必要がある．以下から[ダウンロード](https://www.rarlab.com/download.htm)し7zなどで展開してください
https://www.rarlab.com/download.htm
https://www.rarlab.com/rar/winrar-x64-58b2.exe
https://www.rarlab.com/rar/wrar58b2.exe

# サンプルプログラムの簡易解説
CreateRAR(...)パスを指定してこの関数を呼べば圧縮される
string PathName内のすべてのファイルが圧縮される．
System.Environment.ProcessorCountはシステムの論理プロセッサの数を取得(4 cores 8 threadsなら8)．並列で圧縮する．
ep：アーカイヴからフォルダ構造をなくしたい場合指定する．

```C#:CreateRAR.cs
private void CreateRAR(string PathName) {
    string Extension = ".rar";
    string FileName = "Rar.exe";
    string CompressLevel = " -m5 ";//compress level max 
    string Arguments = " a \"" + PathName + Extension + "\" -rr5 -mt" + System.Environment.ProcessorCount + CompressLevel + "-ep \"" + PathName + "\"";
                /*a             書庫にファイルを圧縮
                  rr[N]         リカバリレコードを付加．5 %が推奨らしい
                  m<0..5>       圧縮方式を指定 (0-無圧縮...5-標準...5-最高圧縮)
                  mt<threads>   スレッドの数をセット
                  ep            名前からパスを除外*/
    ExecuteAnotherApp(in FileName, in Arguments, false, true);
}
private void ExecuteAnotherApp(in string FileName, in string Arguments, bool UseShellExecute, bool CreateNoWindow) {//外部アプリ実行
    System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo {
        FileName = FileName, Arguments = Arguments,
        UseShellExecute = UseShellExecute,
        CreateNoWindow = CreateNoWindow    // コンソール・ウィンドウを開かない
   }).WaitForExit();//終了を待つ
}
tensorflow & python3におけるNeurolab0.3.5でのエラーについて

#事のきっかけ
人工知能が最近のブームになりつつある今日この頃。
ひょんな事で始めたはいいが右も左も分からない状態で、あれこれと手を出していると学習ベクトル量子化という奴を行う際に、ググっても出てこなくて色々やってだいぶ時間を食ったので、ここにメモ兼周知する目的で書こうと思った。(余計なお世話)

##pip3　パッケージ一覧
|Package           |   Version |
|:-----------------|:----------|
|absl-py           |   0.8.0
|astor             |   0.8.0
|cycler            |   0.10.0
|gast              |   0.3.2
|google-pasta      |   0.1.7
|grpcio            |   1.23.0
|h5py              |   2.10.0
|Keras-Applications |  1.0.8
|Keras-Preprocessing | 1.1.0
|kiwisolver          | 1.1.0
|Markdown           |  3.1.1
|matplotlib          | 3.1.1
|neurolab            | 0.3.5
|numpy               | 1.16.5
|pip                 | 19.2.3
|protobuf           |  3.9.1
|pyparsing          |  2.4.2
|python-dateutil    |  2.8.0
|setuptools         |  41.2.0
|six                |  1.12.0
|tensorboard        |  1.14.0
|tensorflow         |  1.14.0
|tensorflow-estimator| 1.14.0
|termcolor          |  1.1.0
|Werkzeug           |  0.15.6
|wheel              |  0.33.6
|wrapt              |  1.11.2

##ソースコード(一部抜粋)
```
text = np.loadtxt('outPut.csv', delimiter=',')
    FEATURE = text[:, :2]
    LABEL = text[:, 2:]

    input_neurons = 10
    output_neurons = 4

    weights = [1 / output_neurons] * output_neurons

    NN = nl.net.newlvq(nl.tool.minmax(FEATURE), input_neurons, weights)

    NN.train(FEATURE, LABEL, epochs=500, goal=-1)
```

##エラーログ
```
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "/Applications/Jetbrains/apps/PyCharm-P/ch-0/192.6603.34/PyCharm.app/Contents/helpers/pydev/_pydev_bundle/pydev_umd.py", line 197, in runfile
    pydev_imports.execfile(filename, global_vars, local_vars)  # execute the script
  File "/Applications/Jetbrains/apps/PyCharm-P/ch-0/192.6603.34/PyCharm.app/Contents/helpers/pydev/_pydev_imps/_pydev_execfile.py", line 18, in execfile
    exec(compile(contents+"\n", file, 'exec'), glob, loc)
  File "/Users/azuma.t/git/tensorflow-hevc/20190917.py", line 61, in <module>
    NN = nl.net.newlvq(nl.tool.minmax(FEATURE), input_neurons, weights)
  File "/Users/azuma.t/py3.7/lib/python3.7/site-packages/neurolab/net.py", line 179, in newlvq
    layer_out.np['w'][n][st:i].fill(1.0)
TypeError: slice indices must be integers or None or have an __index__ method
```

##やり方
```
>>>import neurolab
>>>print(neurolab.__file__)
C:\Users\........\nurolab\__init__.py
```
neurolabの場所を出力させる。場所は、nurolabまでのディレクトリ。

その中の、net.pyの176行目にある
```inx = np.floor(cn0 * pc.cumsum())```
を
```inx = np.floor(cn0 * pc.cumsum()).astype(int)```
に変える事で回避できる。
mysql8系利用時の備忘録

MySQL8系を扱うことになったので、調査した内容をメモしておく。

MySQLはバージョンアップする度に、余計な設定変更されたりするので注意して利用しなければいけない奴だと思っている。もちろんパフォーマンスが改善されたり、アップデートされた機能もあるので、適切に扱ってあげれば大丈夫な子なんです。

漢のコンピュータ道 
http://nippondanji.blogspot.com/2018/05/mysql-80.html

> さようなら、クエリキャッシュ
>> MySQLに特徴的な機能として、多くの方から愛用されたクエリキャッシュは、時代と共にその役割を終え、ついにMySQL 8.0から削除された。クエリキャッシュのような結果をキャッシュする機能を使いたい場合は、アプリケーション側で結果をキャッシュするなど工夫して欲しい。MySQL側でやろうとするとオーバーヘッドが大きくなってしまうからだ。
クエリキャッシュファンには申し訳ないが、MySQL 8.0ではもう使うことはできないので諦めて欲しい。

実に辛い。

MySQLの容量とか圧縮まわり
https://www.slideshare.net/satoshimitani71/mysql-171517476

> information_schema_stats_expiry
>> テーブル統計をキャッシュを保持しておく期間
デフォルトは１⽇（86400秒）
キャッシュがexpireしたら、InnoDBに 「最新の統計情報」を取りに⾏く
information_schema_stats_expiry
どういう効果を意図したパラメータなんでしょう・・・ 
⾃分は 0 にします

是非、意図があるなら自分にも教えてほしい。

FYI https://yoku0825.blogspot.com/2019/05/mysql-80show-table-status.html

MySQL 8.0は何が優れていて、どこに注意すべきか。データベース専門家が新機能を徹底解説
https://employment.en-japan.com/engineerhub/entry/2018/09/18/110000
> log_bin変数のデフォルト値が「0（ログを出力しない）」から「1（ログを出力する）」に変わりました。

ほー。

[MySQL8.0] デフォルトUTF8MB4、そして新しい日本語用照合順序
http://scsk-db.jp/mysql/topics/2018/05/23-090000.html

> MySQL 8.0では、デフォルトの文字コードがUTF8MB4になりました。
従来はlatin1でしたので、近年の文字コード使用傾向に合わせた変更であるといえます。
文字コードと合わせてチェックすべきなのが、照合順序です。
MySQL 8.0では、日本語用の照合順序が新たに作成されています。
utf8mb4_ja_0900_as_csとutf8mb4_ja_0900_as_cs_ksです。

あと、このへんもですね。
Kotlinと図で学んでみるデザインパターン -3章 Template Methodパターン-

# Template Methodパターン
親クラスで処理の枠組みを決め、サブクラスに実装を任せる
![Untitled Diagram.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/187392/1302c863-046f-bdf0-c0eb-803ec18705db.png)

```kotlin
abstract class AbstractDisplay {
    abstract fun open()
    abstract fun print()
    abstract fun close()
    fun display() {
        open()
        repeat(5) {
            print()
        }
        close()
    }
}
```
```kotlin
class CharDisplay(private val ch: CharSequence) : AbstractDisplay() {
    override fun open() {
        print("<<")
    }

    override fun print() {
        print(ch)
    }

    override fun close() {
        println(">>")
    }
}
```
```kotlin
class StringDisplay(private val string: String) : AbstractDisplay() {

    private val width : Int = string.toByteArray().size

    override fun open() {
        printLine()
    }

    override fun print() {
        println("|$string|")
    }

    override fun close() {
        printLine()
    }

    private fun printLine(){
        print("+")
        repeat(width){
            print("-")
        }
        println("+")
    }
}
```
```kotlin
fun main(){
    val d1 : AbstractDisplay = CharDisplay("h")
    val d2 : AbstractDisplay = StringDisplay("Hello World")
    val d3 : AbstractDisplay = StringDisplay("こんにちは。")

    d1.display()
    d2.display()
    d3.display()
}
```
※ Java 言語で学ぶデザインパターン入門をKotlinと図で理解しようとしている学習用アウトプットです。UML書式に沿ってはいません。
[AWS]Amazon S3を使用した環境ごとの条件分岐について

#はじめに
今回個人アプリにS3を導入する際扱っているのが動画の為、無駄に容量を使用したくなかったのでローカルの方ではS3を使用しないように条件分岐させました。今回はその方法を説明します。
##Amazon S3とは
Amazon S3は(Amazon Simple Storage Service)の略で、インターネット経由で使用できるストレージサービスです。主に、画像や動画のファイルの保存に使用します。
特徴としては容量が無制限である事、東京リージョンを使用した場合容量1Gに対して0.025円と安価である事、99.9%の高可用性を持っており、データ消失の心配がほぼない事の主に3つです。

S3のストレージ以外の機能など、詳細に関しては以下の記事も参考にして下さい。
https://service.plan-b.co.jp/blog/creative/4981/
https://dev.classmethod.jp/cloud/aws/cm-advent-calendar-2015-aws-re-entering-s3/

#条件分岐方法
S3の生成方法などの説明は省略します。先ずはGemの導入。`fog-aws`を使用します。動画保存は`carrierwave`を使用しております。

```ruby:Gemfile
gem 'carrierwave'
gem 'fog-aws'
以下略
```

次にuploaderファイルにて条件分岐させる記述をします。
if文を使用し、development(ローカル環境)、test（テスト環境）をファイル形式で保存し、本番環境ではS3に保存するよう条件分岐させています。


```ruby:video_uploader.rb
class VideoUploader < CarrierWave::Uploader::Base
  # Include RMagick or MiniMagick support:
  # include CarrierWave::RMagick
  # include CarrierWave::MiniMagick

  # Choose what kind of storage to use for this uploader:
  if Rails.env.development?
    storage :file
  elsif Rails.env.test?
    storage :file
  else
    storage :fog
  end
以下略
```

次にcarrierwaveを使用してる為config/initializers下に`carrierwave.rb`を作成しif文を使用して保存先の条件分岐をします。

```ruby:carrierwave.rb
CarrierWave.configure do |config|
  if Rails.env.production?
    config.storage = :fog
    config.fog_provider = 'fog/aws'
    config.fog_directory  = 'バケット名'
    config.fog_credentials = {
      provider: 'AWS',
      aws_access_key_id: Rails.application.credentials.aws_access_key_id,
      aws_secret_access_key: Rails.application.credentials.aws_secret_access_key,
      region: 'ap-northeast-1'
    }
  else
    config.storage :file
    config.enable_processing = false if Rails.env.test?
  end
end
```
`if Rails.env.production?`の中では本番環境でS3に動画を保存する記述、else文の中では`config.storage :file`でローカル環境の場合、public/uploades下に動画が保存されるようになります。
`config.enable_processing = false if Rails.env.test?`はテスト環境で動画のアップロード処理をスキップさせています。

その他の説明は今回省略します。

##最後に
今回は条件分岐に関してこの方法で上手くいきました。S3を動画の保存に使用するのは今回はじめてでしたが、使い勝手は画像とほぼ同じでした。現在限定的な導入方法しか理解出来てないと思うので、もう少し今後も理解を深めていきたいと思います。
エンジニアのためのコミュニケーション②

#1.はじめに
第1回目では、エンジニアのコミュニケーション力の重要性について話しました。

エンジニアの会話は、どうしても「**正しさを認めさせること**」が目的となって相手と対立してしまったり、不毛な論争を繰り広げてしまったりしがちです。

もし、あなたがいつも不機嫌そうな表情で部下の隣に座っていたら、それだけで部下は精神的に辛くなってしまいます。部下は、ちょっとした質問や相談をするだけでも「また怒られるのではないか」と気が滅入るのに、開口一番で「これ、違うぞ」と否定されてしまうと、もう駄目です。「**もうこの上司と仕事なんてしたくない」と部下はあなたから離れていきます**。そして、あなたは**自分に原因があることにも気がつかない**でしょう。

もし、「コミュニケーションなんてどうでもいい、技術力さえあれば仕事なんてどうにでもなる」と思っているのならば、**危険です。どうにでもなりません。待っているのはプロジェクトの炎上です。残業地獄です。デスマーチです。**

そのようなことにならないために、以下の二点が大切でした。

・**会話の目的は「問題解決である」と頭に入れておく**
・**相手と仲良くなる**

そして、相手と仲良くなるためのキーワードが**ラポール**でした。
ラポールを作ることで相手との信頼関係を築き、ラポールを維持することで円滑なコミュニケーションを実現できるわけです。これだけでもコミュニケーションは改善されますが、今回は「聞く」をテーマにさらなる改善を目指していきましょう。

#2.聞くことって？
さて、エンジニアはどうしても「論破」願望が強い生き物です。少しでも相手に誤りがあると、それを指摘したくなってしまいます。

「**だって相手が間違っているじゃん**」おっしゃるとおりです。しかし、**いくら間違っているとしても真っ向から否定してしまうとラポールは消滅します**。

ここで具体例を見てみましょう。

「ITエンジニアはパソコンに詳しいからパソコンの故障を直せる」
「**いや、そんなわけないでしょ**」と言いかけたあなたは要注意です。

では、どのような答え方をすれば良いかというと、

「なるほど、**ITエンジニアはパソコンに詳しいからパソコンの故障を直せると思う**んですね！」
「もしよろしければ、もう少し詳しく教えていただけませんか？」

このような答え方をすれば、「**相手がそう考えているという事実**」に同意でき、ラポールを壊すことなく円滑なコミュニケーションを継続できます。

#3.会話が苦手なら相手の気持ちを推測しない
会話が苦手なら**聞き役に徹しましょう**。

会話は、どちらかが話していれば続いていくものです。**手に話し続けてもらえば、「相手の話題に対する知識がなくても問題ない」**のです。

例えば、話し相手がゲームオタクで新作のゲームが発売されたとしたら、相手はそのことについて話したいはずです。ただ、ゲームオタクでもそのジャンルはアクション、RPG、シューティング等細分化されています。

そのため、相手がRPG好きだった場合、新作のシューティングゲームの話をしても、「俺、シューティングは興味ないかな」と興味を持ってくれません。そこで会話が終了して気まずい空気が流れます。

それでは何について聞いたら良いのかと言うと、以下の二点をオススメします。

・**最近一番楽しかったこと**
・**何をしてみたいか**

相手の考え方や感じ方や価値観等が全く分からなくても、これらに対する相手の回答は間違いなく「**楽しかったこと**」であり「**してみたいこと**」であるので、簡単に共感を示すことが出来るのです。

#4.おわりに
次回はもう少し詳しく「聞くこと」について書いていきます。
CSS3による3Dアニメーションで「本を開く」を再現する

CSS3のtransform（preserve-3d）で「本を開く」アニメーションを再現。

今回実装したコードのリポジトリと、それをデプロイしたサイトのURLは以下。

- コード：https://github.com/cacarrot/3d-book
- サイト：https://3d-book.netlify.com/

どこか（忘れた）に載っていた実装例を参考/ベースにしつつ、
指定したURLでカバー画像を変更できるようにした。

WebGL使わなくてもCSSだけでこれだけ表現できる時代って素敵だな。
初投稿/自己紹介

## 自己紹介
- 理系大 電気電子科卒
- Sierベンチャー入社3年目
- 客先で自動車制御基板の組み込みソフトの開発に従事
- Web系エンジニアに転職すべく勉強中
- 現状のスキル
    - matlabモデル設計/m-Script
    - Excel/VBA
    - Python

## 目的
学習内容のアウトプットと自分用の備忘録としてまずは継続して投稿できたらなと考えています。

## 当面の目標
- ProgateでHTML/CSS, Ruby on Railsのチュートリアルを行う。
- ドットインストールでNode.js, Expressのチュートリアルを行う。
- ポートフォリオを作成しつつ転職活動

ひとまずは簡単なWebアプリを作れるようになりたい。
Java 完璧な空白行削除！

いろんなサイトで空白行削除のやり方が記されていますが、完璧な方法をやっと見つけたので、備忘録的に書いておきます。
【 参考サイト 】
連続した空白行削除：http://routesfate.blog80.fc2.com/blog-entry-44.html
文字列抜き出し：https://uxmilk.jp/47897

###【 元データ 】（改行しているところに「\n」を記述しています。
あいう\n
\n
かきく\n
ABC\n
\n
\n
123\n
\n
\n

# すべての空白行を削除 ＆ 最後の改行も削除する
```java:DeleteBlankLine.java
//処理する文字列
String after="あいう\n\nかきく\nABC\n\n\n123\n\n\n";
// 2つ以上連続した改行コードを1つにまとめる
after = after.replaceAll("(\n|\r|\n\r|\r\n){2,}", "\n");
// 空白行をマッチさせて削除する
after = after.replaceAll("[ \t\\x0B\f]+(\n|\r|\n\r|\r\n)", "");
//最後の改行を削除する
if(after.substring(after.length() - 1).equals("\n")){
    after=after.substring(0,after.length()-1);
}
```

###【 結果 】綺麗に整います。
あいう\n
かきく\n
ABC\n
123

「123」の後の「\n」も削除されます。
最後の「\n」を削除しない場合は、上記コード中の下記コードを記述しないでください。

//最後の改行を削除する
if(after.substring(after.length() - 1).equals("\n")){
    after=after.substring(0,after.length()-1);
}
4連結ラベリング/C++

###4連結ラベリング一番簡単なアルゴリズムを記述します
```
const int dx[] = { +1, 0, -1, 0 };
const int dy[] = { 0, +1, 0, -1 };

// matrix dimensions
int row_count=5;
int col_count=5;
const int w = 5, h = 5;
int input[w][h] = { {1,0,0,0,1},
					{1,1,0,1,1},
					{0,1,0,0,1},
					{1,1,1,1,0},
					{0,0,0,1,0} };


// the labels, 0 means unlabeled
int label[w][h];
void find_components();
int main();
void dfs(int x, int y, int current_label);

int main()
{
	find_components();
	std::cout << "Hello World!\n";
	for (int i = 0; i < 5; i++)
	{
		for (int j = 0;j < 5; j++)
		{
			std::cout << label[i][j];
		}
		std::cout << "\n";
	}
}




void dfs(int x, int y, int current_label) {
	if (x < 0 || x == row_count) return; // out of bounds
	if (y < 0 || y == col_count) return; // out of bounds
	if (label[x][y] || !input[x][y]) return; // already labeled or not marked with 1 in m

	// mark the current cell
	label[x][y] = current_label;

	// recursively mark the neighbors
	for (int direction = 0; direction < 4; ++direction)
		dfs(x + dx[direction], y + dy[direction], current_label);
}

void find_components() {
	int component = 0;
	for (int i = 0; i < row_count; ++i)
		for (int j = 0; j < col_count; ++j)
			if (!label[i][j] && input[i][j]) dfs(i, j, ++component);
}
```
spring-batchのTaskletで@BeforeStepは動かない

spring-batchで以下のように、```Tasklet```に```@BeforeStep```を付与するメソッドを追加しても意図通りの動作をしない。

```java
@Component
public class MyTasklet implements Tasklet {
    
    @BeforeStep
    void beforeStep(StepExecution stepExecution) {
        System.out.println("asdfasdf");
    }
```

# 原因
恐らくだが、```Tasklet```にはリスナーの自動登録が無いため、と思われる。

> ItemReaderとかの実装クラスにStepExecutionListenerとかのリスナーを実装しとくと、（少なくともspring-bootと一緒にspring-batch動かす分には）そのリスナーも自動登録する
> [spring-batchはreaderとかでリスナー実装すると自動登録](https://qiita.com/kagamihoge/items/018fdf48b0c5413c2ce6) を参照。

上記の通り、```ItemReader```とかはリスナーの自動登録が有るが```Tasklet```には無い、のが原因と思われる。ソースとかドキュメントをちゃんと追ってないので推測でしかないが。

# 解決策
https://stackoverflow.com/questions/29935824/beforestep-annotated-method-not-being-called

<code>execute</code>メソッド引数の```chunkContext```を使うか、```StepExecutionListener```を実装。
Dartのパッケージマネージャーのpubにはinitコマンドがない

## Dartのパッケージマネージャーのpubにはinitコマンドがない
タイトル通りなのですが、Dartのパッケージマネージャーのpubにはinitコマンドがありません。

npmに慣れていた僕としては、`pub init`でpubspec.yamlが生成されると嬉しいのですが、どうも`pub init`のissueが上がるたびに閉じられているようなので、`pub init`を追加する気はあまりないようです。

じゃあ`npm init`相当のことをしたいときに何を使うのかというと、stagehandを使うようです。

## Stagehand
### Stagehandとは
StagehandとはDartのプロジェクトの雛形を作成するものです。
なので`npm init`とは直接対応していません。

### Stagehandのインストール

```console
$ pub global activate stagehand
```

### Stagehandの使い方
カレントディレクトリに雛形を生成するので、ディレクトリを作成して移動した後stagehandコマンドを使います。

```console
$ mkdir hoge
$ cd hoge
$ stagehand console-full
```

ただのhelpオプションですが、テンプレート一覧を確認するのによく使うことになるかと思います。

```console
stagehand -h
```

### Stagehandのテンプレート一覧

> console-full - A command-line application sample.
package-simple - A starting point for Dart libraries or applications.
server-shelf - A web server built using the shelf package.
web-angular - A web app with material design components.
web-simple - A web app that uses only core Dart libraries.
web-stagexl - A starting point for 2D animation and games.

[stagehand](https://pub.dev/packages/stagehand)より

### 終わりに
個人的には`pub init`コマンドや`pub add`コマンドなどが欲しいです。

結構`pub init`や`pub add`関連のissueが閉じられていたのが気になりました。


## おまけ
`pub init`, `pub add`が欲しい方は、[publican](https://pub.dev/packages/publican)というものを使うと良いかもしれません（使えるのか試してません）。
もし使えなかったら、自前でラッパーを作っても良いと思います。

### 参考
* [stagehand](https://pub.dev/packages/stagehand)
踏み台サーバとトンネルの違い

# 経緯
会社の新人に踏み台とトンネルの違いを教えていて自分も理解が甘かったところがあったのでまとめてみようと思う。

# 踏み台サーバとは？
目的のサーバに接続するための中継サーバである。
<img width="795" alt="スクリーンショット 2019-09-17 21.48.13.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276166/421e6a66-40b6-f301-3c94-fb379dcaed7d.png">

## メリット
- 目的のサーバーに直接アクセスできないため外部から侵入されるリスクを軽減できる。

# トンネルとは？
※ここでのトンネルはSSHポートフォワーディングを使用したものを指す。
ローカルに対するアクセスをリモートに受け流す方法である。
開発DBに接続するとかに使う。
<img width="744" alt="スクリーンショット 2019-09-17 22.21.33.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276166/339809a5-3b9c-fb74-14fe-57693564128a.png">

SSHクライアント（PuTTYやsshコマンド）が通信を待ち受けるようになる。
そこに通信が来ると、接続先のSSHサーバを経由して、指定の接続先（「目的のDB」側）へ通信を転送する。

## メリット
- 目的のサーバーに直接アクセスできないため外部から侵入されるリスクを軽減できる。
（他のサイトみるとわかりやすいって書いてあるけどここわからない人っておおいような。。）
【Swift】カメラが利用できるかチェックする方法

カメラの利用ができるかチェックするためのコードです。

```swift
        // カメラが利用可能かチェック
        if UIImagePickerController.isSourceTypeAvailable(.camera) {
            print("カメラは利用可能")
        } else {
            print("カメラの利用は不可")
        }
```
Azure Databricks で、他の Notebook を呼び出す、基礎: Hello World レベル

## 背景

非常に **小さな処理** などを複数の Notebook から使いまわしたい場合があります。
ずばっとした `Hello-World` のサンプルがあまり無いので、**基礎** 事項をまとめておきます。

注意点:
- 例外処理を書いていません

## Sample Code

### フォルダー構造

以下の様になっています。

```bash
├─ run.ipynb   --- 呼び出し側
└─ tools.ipynb --- 呼び出される側
```

### 呼び出し側 (run.ipynb)
```python
result = dbutils.notebook.run("./tools", 60, {"x" : 1})
print(result)
```

引数 x に 1 を指定しています。

### 呼び出される側 (tools.ipynb)

```python
dbutils.widgets.text("x", "0", "0")
x = getArgument("x")
dbutils.notebook.exit(int(x) + 1)
```

1つの Notebookが、1つの関数程度と捉えてもらった方がいいかもしれません。
`dbutils.wideget.text` を使って、引数 x を定義しています。そして、`getArgument` 関数で、その値を取り出しています。

## 開発上のTips

Azure Databricks ポータル上での実行に便利なネタです。

### 呼び出される側 単体で引数をセットする

見落としがちなのですが、ポータル上の画面上部に引数を設定できるテキストボックスがあります。そちらに設定したい引数を入れます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108143/bc2d4cf3-e686-1e85-6e5c-f351b2c6adf9.png)

### 呼び出し側から、呼び出した先でのエラーを確認する

単純なバグなどの発見に役に立ちます。これ初期には意外と気づかなかったりします...😅

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108143/c2dc6e40-1b60-d237-1bd4-55700b5f6225.png)

一見すると、トラブルシュートに役に立つエラーを出力してくれていません。
ここでは、リンクが設定されている [Notebook job #26] といった、ジョブの実行履歴を見ます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108143/c39f9a16-337c-0c1b-2fb9-4554c8e0d33c.png)

ここでは、SyntaxError だった、という事がわかるかと思います。

### Global 変数が使えない

これも注意が必要です。

## dbcファイル

Source:
https://dahatakestorage.blob.core.windows.net/code/call-other-notebooks.dbc

自分のPC/Macにダウンロードします。それを Azure Databricks のコンソールから、Import してください😊

## Azure Data Factory から Databricks の Notebook を呼び出す

上記も良いのですが😁
結局呼び出し元は、それぞれのNotebookの呼び出し、結果のハンドル、データはファイルとして共有、といった事が増えてくると思います。
Azure には、Azure Data Factory というサービスがあり、上記を比較的簡単に実現できます😊

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108143/51131332-7ad8-0f95-99e1-103754e8dfb3.png)

結局ジョブの実行履歴は管理したいし、PaaSのRDBMSからのデータダンプが意外とサクッとできないし、という事で。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108143/cc0cf99c-a0b8-93c7-c2dd-1f3aa1f09cd3.png)

Azure Data Factory で Databricks Notebook アクティビティを使用して Databricks ノートブックを実行する:
https://docs.microsoft.com/ja-jp/azure/data-factory/transform-data-using-databricks-notebook

Databricks Notebook を実行してデータを変換する:
https://docs.microsoft.com/ja-jp/azure/data-factory/transform-data-databricks-notebook

## まとめ

Azure Databricks だけでも、ある程度の事は出来ます。
ただ、ジョブフロー制御という観点では、C# / Java / Python / JavaScript 等の様な柔軟なフロー制御はそもそも得意ではないので、どこかで限界があります。
うあく使い分けでください。

## 参考

- Notebook Workflows: The Easiest Way to Implement Apache Spark Pipelines:

    https://databricks.com/blog/2016/08/30/notebook-workflows-the-easiest-way-to-implement-apache-spark-pipelines.html

- Notebook Workflows (公式ドキュメント)

    https://docs.databricks.com/user-guide/notebooks/notebook-workflows.html
MAMPでページが見つからない(Not Found)エラーに苦戦した話

#はじめに

MacBookを新しく購入したので、早速PHPの学習に取り掛かろうとMAMPを利用したら以下の画像のエラーが表示されたのでその解決方法メモ。同じような部分で詰まっている人の参考にでもなれば嬉しいです。

<img width="586" alt="スクリーンショット 2019-09-17 21.38.22.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386463/36ecedd7-dc73-cf38-4f8e-4675bbb0bd08.png">

#確認したこと
 - まずは自分で作成したindex.phpが「MAMP/htdocs」の中にあることを確認。 → 問題なし
 - ググってみると「MAMP/conf/apache/httpd.conf」内で「DocumentRoot」で設定している場所が間違ってる可能性あり → "/Applications/MAMP/htdocs"が正しく設定されている。

特におかしな部分もなく困りました。

#解決方法
MAMPのPreferencesの設定が原因でした。
<img width="533" alt="スクリーンショット 2019-09-16 19.07.30.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386463/53dababa-8bb6-c820-08ed-224416c711c2.png">

上の画像の通りに表示されていたのですが、一度「Select」を選択すると何故かiCloudのDocument部分が選択されていました(？)
そのためもう一度「MAMP/htdocs」に設定し直したところ無事phpが表示されました！

#おわりに
ページを表示させるだけに数時間もパソコンと睨めっこしてました。
なぜ「MAMP/htdocs」にRootがなかったのかは不明ですが、これでようやくPHPの学習が出来そうです。
【Swift】エクステンション

#エクステンションとは?
エクステンションとは、すでに存在しているプロパティやメソッド、イニシャライザなどを型を構成する要素に追加する事を可能にする構文です。

#定義方法
エクステンションはextensionで宣言でき、{}内に対象の型に追加したい要素を追加できます。

```
extension エクステンションを定義する対象の型(既存の型） {
  追加したい要素
}
```

#追加可能な要素
##メソッド
エクステンションにはメソッドを追加することが可能で、通常のメソッドと同じように使用できます。
下記サンプルコードの通り、追加したメソッドを普通に使用しています。

```
//String型に新しいメソッドを追加
extension String {
  func printSelf() {
    print(self)
  }
}

let string = "abc"
string.printSelf()

//実行結果
abc
```

##コンピューテッドプロパティの追加
エクステンションで気をつけなければいけないのが、ストアドプロパティの追加はできず、しかしコンピューテッドプロパティの追加はできるという点です。
コンピューテッドプロパティを使用することで既存の型に対して頻繁に行われる処理を型自身に定義でき、メソッドと同じく既存のプロパティと同じように使用することが可能です。

```
extension String {
　//コンピューテッドプロパティのため値を保持しない
  var enclosedString: String {
    return "【\(self)】"
  }
}

let title = "重要".enclosedString + "今日は休み"

//実行結果
【重要】今日は休み
```

##イニシャライザの追加
エクステンションではイニシャライザを追加することも可能です。
そして既存の型にイニシャライザを追加することで、そのアプリ独自の情報から既存の型でのインスタンス生成も可能にします。
次のサンプルコードを見てください。

```
import UIKit

//アプリケーション独自のエラー（固有の情報)
enum WebAPIError : Error {
  case connectionError(Error)
  case fatalError

  var title: String {
    switch self {
      case .connectionError:
          return "通信エラー"
      case .fatalError:
          return "致命的エラー"
    }
  }
  var message: String {
    switch self {
    case .connectionError(let underlyingError):
      return underlyingError.locaizedDescription
        + "再試行してください"
    case .fatalError:
      return "サポート窓口に連絡してください"
    }
  }
}

extension UIAlertController {
  //イニシャライザの引数にwebAPIError型の値をとる
  convenience init(webAPIError: WebAPIError) {
　　
    self.init(title: webAPIError .title,
              message: webAPIError.message,
              preferredStyle: .alert
   }
}

let error = WebAPIError.fatalError
let alertController = UIAlertController(webAPIError: error)
```
上記のコードはアプリケーションでエラーが発生した際に出すアラート画面の実装処理を表しています。
最初に定義されたWebAPIError型内では発生したエラーが何エラーでそれに対応したアラート文を分岐処理で返り値を返しています。
次にエクステンションされているUIAlertControllerですが、これはアラート画面を表示するCocoa TouchのUIAlertControllerというクラスでありSwift既存の用意されたクラスになります。それに対してイニシャライザを追加し、引数に先ほどのWebAPIErrorの分岐処理の結果を引数に与えることで、任意の文字列をアラート画面として出力することを可能にしました。
イニシャライザの追加は以上のように使用することができます。

参考にUIAlertControolerの公式リファレンスを記載しておきます。
https://developer.apple.com/documentation/uikit/uialertcontroller
[PyConJP 2019 レポート] チームメイトのためにdocstringを書こう

Session: https://pycon.jp/2019/schedule/?sessionId=224

参加しました。

# Speaker

ku-mu ([@cocodrips](https://twitter.com/cocodrips)) さん

# 資料

- Youtube Live https://youtu.be/2A3gRyT54Wc
- Slide Share https://www.slideshare.net/cocodrips/docstring-pyconjp2019

# あらまし

メンテナンスしやすいコードを書くために、docstringを書いてみよう

## 何が嬉しい？

- 引き継ぎ。未来の自分とチームメイトに優しい
- 実装と同じ場所に記述するので、改修時にメンテし忘れるリスクが（別立てで書くよりも）少ない
- 引数／戻り値の型を宣言しておくと、IDEの便利機能（型チェックや補完）が利用できる
    - なお type hint でも同様のことが可能
- docstringからAPIのドキュメンテーションを自動生成できる（[sphinx](https://sphinx-users.jp/gettingstarted/index.html)を利用する）

## 書き方

以下の例は、（たぶん）デファクトスタンダードであるreSTスタイルでの記述。

```Python
def func(arg1, arg2):
  """関数の概要を1行で書く
  
  0行以上の詳細情報を書く。
  省略することも可能

  :param arg1: arg1引数の概要
  :type arg1: int  # arg1の型
  :param arg2: arg2引数の概要
  :type arg2: str  # arg2の型
  :rtype: book  # 戻り値の型
  :return: 返り値の説明
  """
```

参考: [Youtube live (8:40付近)](https://youtu.be/2A3gRyT54Wc?t=521)

↑は必ずしも全部書く必要はなくて（動作に支障ないので）、とりあえずでも始めてみると良い。とりあえず、まずは概要だけでも。（詳細な挙動に関する遺言とかを残しておくとよりGood

また、上記の記述のうち型情報に関しては[type hint](https://docs.python.org/ja/3/library/typing.html)を書いてればdocstringへの記述は不要。

type hintを使って上記の例を記述し直すと以下のようになる。

```python
def func(arg1: 型, arg2: 型): -> 返り値の型
  """関数の概要を1行で書く
  
  関数の詳細説明

  :param arg1: arg1引数の概要
  :param arg2: arg2引数の概要
  :return: 返り値の説明
  """
```

参考: [Youtube live (13:40付近)](https://youtu.be/2A3gRyT54Wc?t=823)


PyCharmやVSCodeのようなIDEにはdocstringのテンプレートを自動生成してくれる機能があるので、とっても有用。 ... [14:20付近](https://youtu.be/2A3gRyT54Wc?t=862)

## docstringのスタイル

3つほどある。

- reST ... デファクトっぽい。上記の例はこの形式
- NumPy ... 詳細な記述を書きやすいが、縦に長くなりがち。ただしreSTスタイルよりは人間が読みやすい
- Google ...  書き手にとっても読み手にとってもシンプル。記述が横に長くなる傾向

上記のうち、どれを採用すべきかは基本的に自由。チーム内で統一が取れていれば何でも良い。

（Sphinxによる）ドキュメントの自動生成やtypehintを駆使していくならreSTスタイルがおすすめ。


## Sphinxを利用したドキュメントの自動生成

[15:18〜](https://youtu.be/2A3gRyT54Wc?t=919)

# docstringのカバレッジを計測する [doc-cov](https://pypi.org/project/doc-cov/)

docstringを書くモチベーションになれば、と開発されたそうです。ユーザーもプルリクも絶賛募集中。

- 紹介記事 https://cocodrips.hateblo.jp/entry/2019/02/06/234630
- PyPI https://pypi.org/project/doc-cov/


# まとめ

docstringとsphinxによる自動生成、大昔に試みて何故か挫折していたので「もう１回ちゃんとやってみようかな🧐」と思うきっかけになりました。当時よりはテスト書いたりする意識やスキルが伸びてるはずなので、自分のコード品質を上げるためにやれることはやっていきたいなと前向きなテンションになれました。

doc-covはすごくよさそうです。ドキュメンテーションってテストと同様に敬遠されがちなところがあるなと（自分の実感も含めて）感じるので、こうした可視化ツールによってモチベーションを高めていく、というアイデアはイケてるなぁと。前日の「[Pythonを使ったAPIサーバー開発を始める際に整備したCIとテスト機構](https://pycon.jp/2019/schedule?sessionId=119)」の発表にも共通しますが、敬遠されがちなものを楽しんで取り入れていこうとするメンタルが素敵やなと思いました。

_※以下思いつき_

CIサービスの1ジョブとしてdoc-covの実行を定義しておいて、自動的にSlackとかに「君の書いたdocstringはカバレッジ95%もあるぞ！すごーい！天才！！」みたいに通知してくれる仕組みとか作ったら開発がもっと楽しいものになりそうだと思いました。

「このdocstringは誰々が書いた」を判定する仕組みってどうやって実現するんでしょうね。いいアイデアがあれば知りたいです...
[AWS]EC2にLAMP環境を構築したときの、手順まとめ

# はじめに

今回、まっさらなEC2サーバーにLAMP環境を構築したので、インストール方法と設定手順を、備忘録を兼ねて共有します。

## サーバーについて

今回は、AWSでEC2インスタンスを立ちあげ、WEBサーバーとして用意しました。
このサーバーへのSSH接続の説明を割愛し、これ以降のLAMP環境のインストールと設定について書いていきます。

# Linux編

最初にLinuxの準備です。

## インストール

今回はOSに、`Amazon Linux2`を用いています。
AWSでEC2インスタンスを作った際に、ポチポチっとOSのインストールはできている状態ですので、割愛いたします。

## 各種設定

### 日本語

まずは、OS上の言語を設定します。

```terminal:Linuxの言語設定
sudo vi /etc/sysconfig/i18n
```

↑このコマンドで、`i18n`というファイルを開いて編集します。

```terminal:/etc/sysconfig/i18nの中身：変更前
LANG="en_US.UTF-8"
```

```terminal:/etc/sysconfig/i18nの中身：変更後
LANG="ja_JP.UTF-8"
```

この通り、日本語に設定します。

### 日本時刻に合わせる

```terminal:OS上の時刻確認コマンド
$ date
```

時刻設定は以下の通りです。

```terminal:日本語用のファイルをコピーしてくる
$ sudo cp /usr/share/zoneinfo/Japan /etc/localtime
```

```terminal:ファイル編集コマンド
$ sudo vim /etc/sysconfig/clock
```

↑のコマンドで編集します。

```terminal:ファイルの中身：編集前
ZONE="UTC"
UTC=true
```

`UTC`を`Asia/Tokyo`に書き換えます。

```terminal:ファイルの中身：編集後
ZONE="Asia/Tokyo"
UTC=true
```

これでOKです。
最後に、もう一度`$ date`で時刻が変わったことを確認しておきます。

### パッケージを新しくしておく

ここからは、`yum`を使っていきますので、一応アップデートしておきます。

```terminal:yumをアップデート
$ sudo yum update
```

# Apache編

続いてApacheの準備です。

## インストール

```terminal:インストールのコマンド
$ sudo yum install httpd
```

```terminal:確認
$ yum list installed | grep httpd  
```

## 各種設定


### index.phpを読み込むようにする

初期設定では`index.php`を読み込んでくれないので、読み込んでくれるよう`DirectoryIndex`を変更します。

```terminal:httpd.confファイルの編集コマンド
$ sudo vim /etc/httpd/conf/httpd.conf
```

↑このコマンドで編集を開始します。

```terminal:httpd.confファイルの一部：編集前
<IfModule dir_module>
    DirectoryIndex index.html
</IfModule>
```

↑を
↓に編集します。

```terminal:httpd.confファイルの一部：編集後
<IfModule dir_module>
    DirectoryIndex index.php index.html
</IfModule>
```

### Apacheの起動と確認コマンド

```terminal:起動
$ sudo service httpd start
```

```terminal:確認
$ sudo service httpd status
```

### Apacheを自動で起動するようにしておく

```terminal:自動起動コマンド
$ sudo chkconfig httpd on
```

# MySQL編

Amazon Linux2には、デフォルトでmariaDBが入っていますので、MySQLを使われる方は、念の為アンインストールしておくと良いかもしれません。アンイストール方法は、[こちら](https://qiita.com/yut-nagase/items/780d68a15b05c50c0a42)が分かりやすかったので、リンク貼っておきます。

## インストール

```terminal:インストールのコマンド
$ yum install mysql
```

```terminal:確認
$ mysql --version
```

# PHP編

最後にPHPの準備です。

## インストール

```terminal:インストールのコマンド
$ sudo amazon-linux-extras install php7.2
```

```terminal:確認
$ php --version
```

## 各種設定

### php.iniファイル

```terminal:ファイル編集コマンド
$ sudo vim /etc/php.ini
```

変更内容は

- `Dynamic Extensions`の下の方に、`extension=mbstring`と追記
- `mbstring.language = Japanese`のコメントアウトを外す
- `mbstring.internal_encoding =`のコメントアウトを外し、`=`の後ろに`UTF-8`を追記

この辺りで良いかと思います。

# おまけGit編

Gitのインストールもしておくことが多いので、ついでに書いておきます。

## インストール

```terminal:ファイル編集コマンド
$ sudo yum install git
```
# さいごに

最後までありがとうございます。
足りない部分もたくさんあるかと思いますが、備忘録もかねて共有させて頂きます。

なにか間違えているところ等があれば、コメントいただけると嬉しいです。
jQuery,JavaScriptセレクタ、要素について[備忘録]

本日の備忘録

   ＜jQuery＞

セレクタとは
HTMLの指定方法を記述することでHTMLの要素を取得できる。

よく使用するセレクタ

* IDセレクタ
取得したいHTML要素のid属性の値に#（ハッシュ）を付けたもの
例：　$("#idSelector") // idがidSelectorの要素を取得

* クラスセレクタ
取得したいHTML要素のclass属性の値に.（ドット）を付けたもの
例：　$(".classSelector") // classがclassSelectorの要素をすべて取得

* 要素セレクタ
素セレクタとは、h1やpのようなHTML要素を対象としたセレクタのことです。要素セレクタは取得したいHTML要素の要素名をそのままセレクタとして利用できる
例：　$("h1") // h1要素をすべて取得

* 属性セレクタ
HTMLのタグの属性値を指定したい場合、$("[ 属性 = '値' ]")で属性セレクタを取得できる。
例：　$("input[ type='radio' ]");  // <input type="radio">のHTML要素を取得する

   ＜JavaScript＞

・popメソッド要素は最後の要素を取り出すときに使う

・配列の要素を取得する
例：　console.log(list[2]);

・配列の要素数を取得する
例：　console.log(list.length);

・配列の要素を追加
例：　list.push('Qita');
     console.log(list);

・要素を削除する
例：　list.pop();
     console.log(list);

・先頭の要素を取り除く
例：　list.shift()
     console.log(list);

・split()
split()は、文字列を複数の部分文字列に区切り、文字列の配列に分割します。引数には文字列を区切るための文字を指定する。

・map()
map()は、配列から要素を1つずつ取り出し、引数に与えられた関数の処理を行った結果から新しい配列を作る。

・join()
join()は、配列のすべての要素をつないだ文字列を作成します。引数に文字列を渡すと、その文字列で文字と文字を繋げる。
ホバーしたテーブル行のサムネイルをちょっとだけ拡大PopupするCSS

# 経緯

昔実験的なコードを置いてた某サイトが繋がらなくなって、Codepenに引っ越ししました。
最近、CodepenのpenをQiitaに張り付けられることを知ったので、古いネタですがついでに解説を付けてみようと思いました。

テーブルの各行にサムネイルがありますが、**マウスを重ねた行はちょっとだけ画像が大きくなって飛び出したように表示されます。**

文字の高さに合わせて画像を縮小すると小さすぎてよくわからない、でもサムネイルのためだけに行の高さを増やすのはスペースの無駄づかいになる、そんな時に便利かと。
ちなみに **CSS only** で、Javascript は使ってません。

<p class="codepen" data-height="265" data-theme-id="0" data-default-tab="html,result" data-user="shinodanaoki" data-slug-hash="RwbBqRy" style="height: 265px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="Zoom in image inside table on hover. [css-only] ホバーで拡大するアイコン">
  <span>See the Pen <a href="https://codepen.io/shinodanaoki/pen/RwbBqRy/">
  Zoom in image inside table on hover. [css-only] ホバーで拡大するアイコン</a> by ShinodaNaoki (<a href="https://codepen.io/shinodanaoki">@shinodanaoki</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>

# 解説
HTMLソースの方は、特に何の変哲もない table です。css セレクタのためにサムネイル画像をラップする div タグには "thumb" クラスが付いてます。

## 通常時のスタイル 
まず通常状態の thumb クラス

```css
div.thumb {
    position: relative;
    z-index: 0;
    margin: -0.2em;
}
```
img タグに position:absolute を使うための起点として、 position:relative を指定してます。それとホバーした画像が重なり順で上にでるように z-index:0 を指定してます。 margin: -0.2em は中の img タグが 1.2em と若干行高さより大きい分を吸収する役目です（これがないとホバーの有無で行高さが変わってガクガクする）。 

そしてサムネイル画像のスタイル

```css
div.thumb img {
    width: 1.2em;
    height: 1.2em;
    object-fit: cover;
}
```
1.2em は通常時の画像サイズなので、お好みのデザインに合わせて調節してください。[object-fit: cover;](https://developer.mozilla.org/ja/docs/Web/CSS/object-fit) は画像の縦横比を維持して矩形の中一杯のサイズで表示する指定です。お好みで `contain` などの指定をするのもありでしょう。

## ホバー時のスタイル
CSSは、詳しい人には解説不要でしょうが、[hover疑似クラス](https://developer.mozilla.org/ja/docs/Web/CSS/:hover)を使ってます。一般的な css セレクタの後に :hover と付けて書くと、マウスを重ねた時専用のスタイルを指定できるものです。

ホバー中の thmub クラスのスタイルは、重なり順で他の要素より上に来るように z-index を変えてるだけです。

```css
tr:hover div.thumb {
    z-index: 9999;
}
```

そして、肝となるホバー時の画像タグのスタイルはこれ。:hover 疑似クラスが tr に対して付いてることにご注意ください。これによって、画像だけでなく **テーブル行全体のどこにマウスをかざしてもこのスタイルが適用される** ことになります。

```css
tr:hover div.thumb img {
    width: 2.4em;
    height: 2.4em;
    display: block;
    position: absolute;
    top: 0%;
    left: 25%;    
    margin: -0.7em;
    box-shadow:0px 0px 16px 1px #000000;
}
```

2.4em はホバー時のサイズですので、お好みで変えてください。
display: block; **position: absolute;** でその場で他の要素に重なるように表示されます。
top, left, margin などもホバー時の表示位置に係わってきますので、適宜調整してください。
目立たせるために box-shadow を付けてます。

# おまけ
HTML/CSS の img タグのところ svg やほかのタグに置き換えて使用することもできます。
Jupyter Notebookで仮想環境を使用できなくなってしまった時の対処法

これは備忘録。忘れないため、もう時間を無駄にしないため。

#環境
使用OS
MacOS

各種バージョン
conda : 4.7.11
conda-build : 3.17.8
python : 3.7.3.final.0

#ハマってしまった内容
Anacondaで仮想環境を作成後、その環境にjupyterをインストールし、jupyter notebookを実行しようと思ったところ、Jupyter Notebook上で仮想環境を選択できない。
過去に作成した仮想環境も全て選択できなくなっていた。

#解決するよ
jupyter_notebook_config.pyの最後の行に、以下のように記されていた。

```python:jupyter_notebook_config.py
c.NotebookApp.kernel_spec_manager_class = 'environment_kernels.EnvironmentKernelSpecManager'
c.EnvironmentKernelSpecManager.env_dirs=['C:/Program Files/Anaconda3/envs/']
```

この状態で、ターミナル上で仮想環境（ここでは仮にpy4kasouとするよ）に切り替えてJupyterを起動させる。

```python
(base) ~$ source activate py4kasou
(py4kasou) ~$ jupyter notebook
```

で、以下のようにエラーを吐く。

```python
Arguments that take values are actually convenience aliases to full
Configurables, whose aliases are listed on the help line. For more information
on full configurables, see '--help-all'.
# 〜中略〜
[C 21:15:45.387 NotebookApp] Bad config encountered during initialization:
[C 21:15:45.387 NotebookApp] The 'kernel_spec_manager_class' trait of <notebook.notebookapp.NotebookApp object at 0x1086427d0> instance must be a type, but 'environment_kernels.EnvironmentKernelSpecManager' could not be imported
```

、、、、、、、、、、長い！！！！！！！！！！！ばか！！！！！！！！

（反省タイム）

原因としては、jupyter_notebook_config.pyの下方の2行のうちの

```python:jupyter_notebook_config.py
c.NotebookApp.kernel_spec_manager_class = 'environment_kernels.EnvironmentKernelSpecManager'
```

のせい。ちなみに、こいつをコメントアウトしてJupyter Notebookを起動させると、エラーは回避可能。
しかし、過去に作成した仮想環境も全て使用できなくなる（ここで振り出しに戻していくトリッキーなスタイル）。

以前に仮想環境を作成した際と何が違うのかと過去のメモを見返してみると、すごく簡単なことだった。

```python
(py4kasou) ~$ pip install environment-kernels
```

はい。これだけ。
仮想環境にこれをインストールしていなかったため、jupyterでこの仮想環境を認識できなかった。のかな？

これで、**configファイルのコメントアウトを外して**、再び

```python
(py4kasou ~$ jupyter notebook
```

はい、無事に起動。
解決しましたとさ。

#ちなみに私のJupyterの起動方法
Macを使用しているので、簡単なアプリは作成できる。そう、例えばG-Mailをデスクトップからワンクリックで開いたり、Qiitaを開いたり、もちろん指定した仮想環境でJupyter Notebookを起動したり。
これらについては、簡単にメモとして別記事作成予定。

#終わりに
仮想環境を作成したら、

- jupyterのインストール
- environment-kernelsのインストール
これだけはセットで、忘れずに。過去の自分より、未来の自分へ。

読了感謝。
Railsでformのfield毎にエラーメッセージを表示させる便利設定

備忘録的な内容なので参考までに。
設定の設置場所は`config/initializers/error_customize.rb`

```ruby
ActionView::Base.field_error_proc = proc do |html_tag, instance|
  if instance.is_a?(ActionView::Helpers::Tags::Label)
    html_tag
  else
    method_name = instance.instance_variable_get(:@method_name)
    errors = instance.object.errors[method_name]
    view = ActionView::Base.new
    field_tag = []
    field_tag << html_tag
    field_tag += errors.map do |error|
      view.content_tag(:div, class: "help-block") do
        "#{instance.object.class.human_attribute_name(method_name)}#{error}"
      end
    end
    view.content_tag(:div, class: "has-error") do
      view.safe_join(field_tag)
    end
  end
end
```

参考にしたQiita記事: https://qiita.com/zaru/items/54cd20520feda61f5332

## 自分で手を加えたポイント
このままだと、ただ参考にした記事をパクッてるだけやん、となりそうなので上記の記事を参考に自分なりに修正を加えた箇所について解説をします。

```ruby
ActionView::Base.field_error_proc = proc do |html_tag, instance|
  if instance.is_a?(ActionView::Helpers::Tags::Label)
    html_tag
```

最初のif文のところで、`html_tag.html_safe`という記載に`html_tag`に書き換えました。理由は、私のRubocop先生から`RuboCop::Cop::Rails::OutputSafety`の指摘を喰らったため。ただし、単純に`html_safe`を外しただけでは根本解決になっていのでは？という疑問を持たれそうなので一応補足をすると、pryで覗いたときにこんな感じの挙動をしていることがわかりました。

![image (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191885/a5792b43-7568-c634-cea3-65d5d89ab085.png)

はい、もともと`ActiveSupport::SafeBuffer`クラスのインスタンスなので`html_safe`は不要なんですね。ということで削除しても問題なさそうということがわかったので削除しました。

```ruby
  else
    method_name = instance.instance_variable_get(:@method_name)
    errors = instance.object.errors[method_name]
    view = ActionView::Base.new
    field_tag = []
    field_tag << html_tag
    field_tag += errors.map do |error|
      view.content_tag(:div, class: "help-block") do
        "#{instance.object.class.human_attribute_name(method_name)}#{error}"
      end
    end
    view.content_tag(:div, class: "has-error") do
      view.safe_join(field_tag)
    end
  end
```

後半のelse文のところについては、ごっそりと書き方を変えています。ポイントは2つ。

1つ目は、こちらも同じくrubocop先生から`RuboCop::Cop::Rails::OutputSafety`の指摘を喰らっていたので、`RuboCop::Cop::Rails::OutputSafety`のGoodパターンである`safe_join`にて最終的にHTMLを吐き出す流れを取った点です。

2つ目は、元のコードの場合、発生しているバリデーションエラーの内、最初のエラーのみしか取れないロジックになっていたので、`errors.each`のところですべてのエラーをHTMLとして吐き出す処理を加えた点です。


## まとめ
これで根本的なバグ（最初のエラーしか取れないバグ）は解決し、Rubocop先生からも指摘をされないコードになりました。この設定自体はかなり便利な設定だなぁと思うので、興味がある方はぜひ使ってみてください。大本のロジックについては自分で考えることができなかったので参考にさせて頂いた記事には感謝です。
logrotateでファイル名を前日にする

# 環境

- Linux （Amazon Linux）

# やりたいこと

ログファイルのsuffix（\<filename\>.`YYYMMDD`の`YYYMMDD`部分）と、ファイルに含まれるログの日時を同じにしたい。
以下、nginx, unicorn での設定例。

# 設定

- `postrotate`でファイル名（YYYYMMDD部分）を前日に変更するので、`gzip`はその後に行う。`compress`オプションは使わない。

```/etc/logrotate.d/nginx
/var/www/shared/log/nginx.log {
    create 0664 your_user root # 新しいファイルを作成する（無ければ作る）時のパーミッション、オーナー、グループ
    daily                      # 日次でローテーションをする
    rotate 14                  # 14世代分ログを残す
    missingok                  # ログファイルがなくてもエラーを出さない
    ifempty                    # ログファイルが空でもローテーションする
    dateext                    # ローテーション後のファイルに、日時（-YYYYMMDD）のsuffixを付ける
    sharedscripts              # 複数指定したログファイルに対して、postrotateまたはprerotateで指定したコマンドを実行する
    postrotate                 # endscriptとの間に記述されたコマンドを、ログローテーション後に実行する
        [ ! -f /var/run/nginx.pid ] || kill -USR1 `cat /var/run/nginx.pid`

        /bin/mv /var/www/shared/log/nginx.log-`date '+%Y%m%d'` /var/www/shared/log/nginx.log-`date '+%Y%m%d' -d '1days ago'`
        /bin/gzip /var/www/shared/log/nginx.log-`date '+%Y%m%d' -d '1days ago'`
    endscript
}
```

```/etc/logrotate.d/unicorn
/var/www/shared/log/production.log /var/www/shared/log/unicorn.log {
    create 0664 your_user your_user
    daily
    rotate 14
    missingok
    ifempty
    dateext
    sharedscripts
    postrotate
        /etc/init.d/unicorn restart

        /bin/mv /var/www/shared/log/production.log-`date '+%Y%m%d'` /var/www/shared/log/production.log-`date '+%Y%m%d' -d '1days ago'`
        /bin/gzip /var/www/shared/log/production.log-`date '+%Y%m%d' -d '1days ago'`

        /bin/mv /var/www/shared/log/unicorn.log-`date '+%Y%m%d'` /var/www/shared/log/unicorn.log-`date '+%Y%m%d' -d '1days ago'`
        /bin/gzip /var/www/shared/log/unicorn.log-`date '+%Y%m%d' -d '1days ago'`
    endscript
}
```

# その他

## cronの設定

```/etc/crontab
0 0 * * * root run-parts /etc/cron.daily
```

## dry run
```
sudo logrotate -dv /etc/logrotate.d/nginx
sudo logrotate -dv /etc/logrotate.d/unicorn
```

## 実際に logrotate してみる
```
sudo logrotate -f /etc/logrotate.d/nginx
sudo logrotate -f /etc/logrotate.d/unicorn
```

以下のようなエラーが出る場合は、config （e.g. `/etc/logrotate.d/nginx`） で `su <owner> <group>` という形で指定するか、ディレクトリの owner/group を見直す。

```
sudo logrotate -f /etc/logrotate.d/nginx
error: skipping "/var/www/somewhere/log/nginx.log" because parent directory has insecure permissions (It's world writable or writable by group which is not "root") Set "su" directive in config file to tell logrotate which user/group should be used for rotation.
```
RSA 公開鍵認証による SSH 接続でエラーが出る場合の対処法

SSH コマンドの実行時、次のようなエラーが出る場合には、

```
Bad owner or permissions on /****/****/.ssh/config
```

以下のコマンドを実行してみてください。

```
$ chmod 600 ~/.ssh/config
```

また、例えば、以下のようなエラーが出た場合は、

```
Permissions 0777 for '/****/****/.ssh/id_rsa' are too open.
It is required that your private key files are NOT accessible by others.
This private key will be ignored.
Load key "/****/****/.ssh/id_rsa": bad permissions
****@****: Permission denied (publickey).
```

次のコマンドを実行します。

```
$ chmod 600 ~/.ssh/id_rsa
```

つまり、SSH の設定ファイルや RSA 秘密鍵に関しては、

**アクセス権限がゆる過ぎても**、パーミッションエラーになるということのようです。
Project Euler 60をPythonでやってみる

# 問題60
英語
https://projecteuler.net/problem=60
日本語
http://odz.sakura.ne.jp/projecteuler/index.php?cmd=read&page=Problem%2060

# 解答60
今回は難しかったです。
回答もあまり良いものではないかもしれません。
特に難しいのは最小性で答えが見つかっただけでは確認しきれません。

アルゴリズムに関しては次の記事を参考にしました。
https://tasusu.hatenablog.com/entry/20121119/1353331189

記事と同じようにグラフを作り、サイズ５のクリークを見つけるアルゴリズムを使いました。

ただこのアルゴリズムには問題点があります。
それはグラフの頂点となる素数の上限を決める必要があることです。
この上限値が低いと答えを確定できなかったりそもそも答えが見つからなかったりします。
逆に上限値を大きくしすぎるとグラフを作る計算量が大きくなり過ぎてしまいます。
今回は大体の答えがわかっていたため、この上限値を適切な30000と取りましたが、適切な上限値を与えないと良い働きをしないアルゴリズムになってしまいました。

コードは次のようになります。

```python:ProjectEuler60.py
import sympy as sym
import math
import itertools


def is_Prime_Pairs(num1,num2):
    a = int(str(num1) + str(num2))
    if not (sym.isprime(a)):
        return False
    b = int(str(num2) + str(num1))
    return sym.isprime(b)

def del_vertex(edge_dic):
    dic = {prime:prime_set for prime,prime_set in edge_dic.items() if len(prime_set)>3} #次数3以下のvertexを削除
    return {prime: {q for q in prime_set if q in dic.keys()} for prime, prime_set in dic.items()}

def sum_clique(edge_set,p,clique_set):
    global ans_min
    next_clique_set = clique_set|{p}
    if len(next_clique_set) == 1:
        next_set = edge_dic[p]
    else:
        next_set = edge_dic[p] & edge_set
    
    if len(next_set) < 5-len(next_clique_set):
        return
    
    if len(next_clique_set) == 4:
        ans = sum(next_clique_set) + min(next_set)
        if ans_min == 0 or ans < ans_min:
            ans_min = ans
            # print(ans_min)
            return
    sort_next = sorted([x for x in next_set if x > max(next_clique_set)])
    for q in sort_next:
        sum_clique(next_set,q,next_clique_set)
    return



num_max =30000
primes = {i for i in sym.primerange(3,num_max)}
primes.remove(5) #5はどこともedgeを持たない
edge_dic = {i:set() for i in primes}

# グラフ作成
for p in primes:
    for q in (q for q in primes if q > p):
        if is_Prime_Pairs(p, q):
            # print((p,q))
            edge_dic[p].add(q)
            edge_dic[q].add(p)
print("Phase1")

# 次数3以下のvertexを削除
edge_dic = del_vertex(edge_dic)
print("Phase2")
# 素数の和が最少のクリークを探す
keys = sorted(edge_dic.keys())
ans_min = 0
for p in keys:
    if ans_min > 0 and p > ans_min:
        break
    sum_clique(set(),p,set())

print(ans_min)
```

62.598 seconds
グラフ作成だいたいが60sです。
#エラー解消 syntax error, unexpected tIDENTIFIER, expecting ')'

###したこと
ダミーデータをcreateして､データベースに登録`$rails db:seed`しようとしたら出たエラーです｡

```ruby:エラーメッセージ
$bin/rails db:seed
rails aborted!
SyntaxError: /Users/ホーム/ペアレントディレクトリ/カレントディレクトリ/db/seeds.rb:12: syntax error, unexpected tIDENTIFIER, expecting ')'
```


###答え

｢,｣カンマ抜けでした｡

```ruby:db/seeds.rb
Diary.create(
  title: "夏", ⬅このカンマ
  body: "BBQ､プール､ビアガーデン､水族館"
)

```

細かいミス｡
【Ruby on Rails5】マイグレーションの基本【初学者】

Railsのマイグレーションの基本についておさらいしたので短いですが投稿してみました。
間違っている点などありましたらご指摘頂けますと幸いです。

# マイグレーションの適用
マイグレーションとは、データベーススキーマ（階層構造を持たないOSのディレクトリみたいなもの）の継続的な変更を簡単に行うための仕組みです。

ひとつのマイグレーションファイルがデータベースのひとつのversionと捉えることができ、このデータベースのversionとdb/schema.rbとの構造を一致させる役割を持つのが`Active Record`です。

例えば、以下のようなテーブル構造を持つデータベース`tasks`があるとします。

```ruby:schema.rb
create_table "tasks", force: :cascade do |f|
    t.string "name"
    t.text "description"
end
```

SQLでテーブルを作成する場合のクエリ

```sql
CREATE TABLE tasks(
    id INT NOT NULL AUTO_INCREMENT,
    name VARCHAR(30),
    description VARCHAR(100),
    PRIMARY KEY (id)
):
```

これに対して以下のようにdb/schema.rbを更新します。

```ruby:schema.rb
create_table "tasks", force: :cascade do |f|
    t.string "name"
    t.text "description"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
end
```

schemaに`created_at`と`updated_at`というカラムが追加され、これを実際のデータベースに適用させたいというとき
DSLを使わずに生のSQLを使用していた場合、`ALTER TABLE 構文`などを使用してカラムを追加しなければなりません。
しかし、RubyのDSLであるActive Recordの機能を使用すれば次のコマンドを実行するだけでデータベースのテーブル構造が変更されます。

```ruby
$ rails db:migrate
```

これが`マイグレーションの適用`です。

# まとめ

Active Recordにおけるマイグレーションは、データベース内のカラムやインデックス等に修正を加えるための便利な仕組みであり、データベースのバージョン管理機能でもある？？、ということです。


最後までご覧いただきありがとうございました。

# 参考
[Rails ガイド Active Record マイグレーション](https://railsguides.jp/active_record_migrations.html)
Webhookとセキュリティ

Webhookで決済のような重要なイベントの情報ををやり取りする場合には、リクエストに対する**認証**、**完全性**が保証されていてほしいです。

認証が保証されていなければ、どんなリクエストを送ればいいかさえわかれば、誰でもなりすましてリクエストができてしまいます。

完全性が保証されていないと、途中でリクエストが改ざんされていてもわかりません。

実装者あるいは利用者として、どのような対策があるのか調べて考えてみました。

## 考えられる対策
1. リクエスト自体に認証のための情報を含める        
  - ヘッダ
        - Basic認証
        - Bearerトークン
        - etc.
  - パラメータ
  - ボディ
2. メッセージ認証コードもしくはデジタル署名

| 対策 |	認証 |	完全性 |
|-----|-----|--------|
| 1    | ○ | ✗ |
| 2 | ○ | ○ |

## どのような場合に問題が起きるか
1の場合、リクエスト自体が見れてしまうと任意のメッセージを送れます。また完全性は保証されていません。
2の場合リクエスト自体には鍵が含まれていません。送信時に使う鍵とアルゴリズムがわかると任意のメッセージを送れます。

きちんとした証明書を使ったhttpsであれば、基本リクエスト自体が見られることは無いはずなので、1でも問題ないように思えます。
ただ、以下のようなことをしてしまい、更にその内容が見れるような状態にあると任意のリクエストが送れるようになってしまいます。

- httpで送ってしまう
- ログに残ってしまう

簡単に起こり得そうなので基本的には2が好ましいと思います。

しかし2は送信側にもロジックが必要です。自分がWebhook受け取り側で、送信者が2をしてくれない場合には受信側でできることは1になってしまいます。

## 実際のサービスでの例
触ったことのあるサービスではどのような実装になっているのかいくつか見てみました。

### Stripeの場合
- [Checking Webhook Signatures | Stripe]( https://stripe.com/docs/webhooks/signatures )
    - `Stripe-Signature`ヘッダにHMAC（SHA-256）のメッセージ認証コードがついてくる
    - 鍵はendpoint secretとしてwebhook設定から見れる
    - `Stripe-Signature`はタイムスタンプも含むことでリプレイ攻撃の対策としている

### GitHubの場合
- [Securing your webhooks | GitHub Developer Guide]( https://developer.github.com/webhooks/securing/ )
    - `X-Hub-Signature`ヘッダにHMAC（SHA-1）のメッセージ認証コードがついてくる
    - 鍵は自分で生成したものをwebhook設定から設定する

### SendGridの場合
- [Event Webhook - ドキュメント | SendGrid]( https://sendgrid.kke.co.jp/docs/API_Reference/Webhooks/event.html)
  - メッセージ認証コードは無しで、Basic認証推奨

## 結局どうすれば良いのか
### 実装者として
- 基本メッセージ認証コードをつける
    - 重要かどうかは受け取り側次第のところがある
    - 将来の仕様変更で重要な情報を含むようになるかもしれない

### 利用者として
- 自分にとってそこまで重要ではない情報なら気にしなくていい
- Webhook提供者がメッセージ認証コードをつけてくれているならその検証をする
    - 基本は提供されているライブラリ、ドキュメントにある実装を使う
    - 自分で検証する場合には定数時間の文字列比較アルゴリズムを使う
        - Timing Attack対策
- メッセージ認証コードがない場合、予測不可能性を持った乱数で認証トークンを生成してリクエストのURLに設定し検証する
    - 上と同様、文字列比較は定数時間のアルゴリズムを使う
    - URLにBasic認証の情報を含められるなら使う
        - 自分が使っているサービスでは使えないものがあった
    - だめならリクエストパラメータに認証トークンを入れる
        - ログに残らないよう対策する
            - 例えばRailsだったら`Rails.application.config.filter_parameters`に追加する

## 参考
- [暗号技術入門](https://amzn.to/2O5l5da )
- [Webhookとは？ | SendGridブログ]( https://sendgrid.kke.co.jp/blog/?p=1851)
- [Checking Webhook Signatures | Stripe]( https://stripe.com/docs/webhooks/signatures )
- [Securing your webhooks | GitHub Developer Guide]( https://developer.github.com/webhooks/securing/ )