OmniAICreator/Qiita-1.07M huggingface dataset:
「Docker」＆「Kubernetes」について簡単に解説(学習まとめ)～DockerとKubernetesでできること編

本稿は、筆者個人が学習のまとめとして作成したものですが、一人でも、だれかのお役に立てればと思います。
筆者は、某IT会社にて研修を受けている身で、技術的に(非常に)拙いため、内容に漏れや誤りがあるかもしれませんので、
より詳細で正確な情報については、読者の方々ご自身がネット上の各ソースについてあたっていただければと思います。
それでは、少しの間お付き合いください。


##「Docker」＆「Kubernetes」についてのおさらい
以前の記事に書いた通り、
Dockerは、「コンテナ」と呼ばれるアプリケーションの仮想の実行環境を用意してくれるソフトです。
コンテナとはホストマシンの持っているリソース(CPU＆メモリ＆補助記憶)をいくつかに分割して利用する仕組みのことであり、
一つのコンテナはあたかも、一つの独立した環境であるかのように利用することができ、アプリケーションが実行される単位でもあります。
別の言い方をすれば、コンテナとはマシンのリソースが割り当てられ、アプリケーションのデプロイ／実行が可能な小さな環境といえます。
「仮想的な実行環境」と言われる所以はここにあります。
つまり、ホストマシンが一つの環境であるように、コンテナも一つの環境として見做すことができるということです。

Dockerは、コンテナと呼ばれる仮想の実行環境を用意してくれるのですが、これは、基本的な機能に限られており、
ネットワーク周りの機能が弱く、複数のマシンに跨ったコンテナ同士の通信・連携が難しいという点を抱えています。

ここで登場するのが、Kubernetesです。
Kubernetesは、Dockerの持っている機能や仕組みをそのまま利用した上で、システム全体の機能や仕組みを拡張してくれます。
Kubernetesは、強力なネットワークの機能を活かして、
複数のマシンに跨ったコンテナ同士の通信・連携(コンテナオーケストレーション)を実現したり、
コンテナの監視、コンテナの障害からの自動的な復帰、スケールアップ、ロードバランシングなど様々な機能を提供してくれます。
ですので、(システム全体にとっては、)Dockerは基本的なソフトにあたり、Kubernetesは応用的なソフトにあたると言えます。
ちなみに、Kubernetesでは、アプリケーションを、Dockerのコンテナを複数個まとめあげた「ポッド」と呼ばれる単位で管理します。


##「Docker」＆「Kubernetes」でできること
結局のところ、Dockerと、Kubernetesでなにができるのかと言えば、それは、「マイクロサービス」です。
これは、マーティン・ファウラーという人物が提唱した概念です。
これは、一つのアプリケーションを複数の(極めて)小さな機能に分割し、
アプリケーションを実行する要求が発生した時に、いくつかの機能同士を動的に組み合わせることで、
全体を統合してアプリケーションの動作を決めよう、というものです。

つまり、前述のコンテナやポッドに、マイクロサービスの役割を担わせるということです。
そして、コンテナやポッドの間の仕様的な差異を各種のAPIに吸収させることで、システム全体の統合を図るということなのです。

このことは、システムやアプリケーションを開発する側にとっては、開発のさらなる分業化や、
開発された製品の再利用化を推し進めることになります。加えて、企業同士のさらなる連携も考えられます。
対して、システムやアプリケーションを利用する側にとっては、目的のアプリケーションをより低価格で、
よりスピーディーに手に入れたり、自分の手でアプリケーションをカスタマイズするといったことも考えられます。

さらに、刺激的で興味深いのは、ユーザーコンピューティングが劇的に変わるかもしれないということです。
ユーザーはこれまでの既成の観念に囚われているアプリケーション利用から脱却できるかもしれないということです。

たとえば、ユーザーは、企業が外部仕様を公開しているマイクロサービス同士を適宜組み合わせることで、
目的のアプリケーションを開発、手に入れることができるとします。
すると、ここにイノベーションが起こるかも知れないのです。
企業側がマイクロサービスをブラックボックス化して、簡単な外部仕様を公開することで、ユーザーは技術的に成熟していなくとも、
目的に合ったアプリケーションを開発、手に入れることができるかもしれないということは、今までITとは無縁だった人でさえも、
自分のアイデアを形にすることができるかも知れない可能性を秘めているということです。

これは、”(多くの)個人がアイデアを形にするためにITを駆使する”、
あるいは、”(多くの)個人が社会を変革するだけの力を持つ”、
ということではないでしょうか。いずれにせよ、この「マイクロサービス化の波」は止まりそうにありません。


以上で解説を終えます。
本稿の最後のあたりは、筆者個人の未来予測に過ぎないので、あまり気にしないでください。
必ずそうなるというものではなく、その可能性が今後高まってゆくのではないかという程度のものです。
読者の方々に、最後までお付き合いくださり、ありがとうございました。

##参考サイト
IBMJapanChannel
(今回は動画を参考にさせていただきました)
CSSセレクタ

## セレクタ
###  基本系

#### 要素セレクタで選択

```:css
p { 
  /* CSS記述 */
}
```

#### クラス名で選択

```:css
.classname {
  /* CSS記述 */
}	
```

#### IDで選択

```:css
#idname{
  /* CSS記述 */
}	
``` 

#### 全称セレクタ
全ての要素を選択

```:css
*{
  /* CSS記述 */
}
```
 

#### 複数の要素を選択

```:css
p, div, .classname, #idname{
  /* CSS記述 */
}	
```


###  結合子
#### 子孫要素を選択
階層の深い子要素(孫)もセレクタの対象になります。
例：divの中のp全てにCSSを適用する

```:css
div p {
  /* CSS記述 */
}
```

#### 直下の子要素を選択
１つ下の階層の子要素だけが対象です。(孫要素は対象外)
例：divの直下にあるpだけにCSSを適用する

```:css
div > p {
  /* CSS記述 */
}
```

#### 弟要素を選択
同じ階層にある、指定した要素より後にでてくる要素が対象です。
例：同じ階層にあるh3より後に出てくるa全てにCSSを適用する

```:css
h3 ~ a {
  /* CSS記述 */
}
```

#### 直後の要素を選択
同じ階層にある、指定した要素の後ろ隣にある要素が対象です。
例：同じ階層にあるh3の直後のaだけにCSSを適用する(間に他の要素があると適用されない)

```:css
h3 + a {
  /* CSS記述 */
}
```




### 属性セレクタ
href、class、id、srcなどの属性の値から選択できます。

### 属性値が一致する要素を選択
属性値が一致していれるものを選択します。
例：クラス「classname」を持つp要素だけにCSSを適用する

```:css
p[class="classname"] {
  /* CSS記述 */
}
```

#### 属性値の“一部”が一致する要素を選択
属性値の一部が一致していれるものを選択します。
例：「x」という文字が含まれてる属性値を持つp要素だけにCSSを適用する

```:css
p[class*="x"] {
  /* CSS記述 */
}
```

#### 属性値の“最初”が一致する要素を選択
属性値の始まりが一致しているもの選択します。
例：「a」という文字から始まってる属性値を持つp要素だけにCSSを適用する

```:css
p[class^="a"] {
  /* CSS記述 */
}
```

#### 属性値の“最後”が一致する要素を選択
属性の終わりが一致しているもの選択します。
例：「z」という文字で終わっている属性値を持つp要素だけにCSSを適用する

```:css
p[class$="z"] {
  /* CSS記述 */
}
```


### 疑似要素
[疑似要素の記事](https://qiita.com/takeshisakuma/items/ab77a713070e42c5a114)書きました。

```:css
p::first-letter{
  /* CSS記述 */
}

```

### 疑似クラス
[疑似クラスの記事](https://qiita.com/takeshisakuma/items/ab77a713070e42c5a114)書きました。

```:css
p:hover{
  /* CSS記述 */
}

```

## CSSの詳細度
複数のセレクタで同じプロパティが指定されている場合は、詳細度によってどちらが適用されるか判定されます。
詳細度の位はバージョンナンバーのように、10になっても繰り上がりません。
比較方法：数字を左から順番に比較していく(同点の場合は後から記述されたものが適用される)

|詳細度|セレクタ|
|---|---|
|0,0,0,0|全称セレクタ、:not疑似クラス、結合子|
|0,0,0,1|要素セレクタ、疑似要素|
|0,0,1,0|クラス，:not以外の擬似クラス，属性セレクタ|
|0,1,0,0|ID|
|1,0,0,0|スタイル属性(インラインスタイル)|

疑似要素は詳細度0,0,0,1ですが、別の要素になるのでCSSの効き方が元の要素から独立します。

:not擬似クラス自体は詳細度に加算されないですが、除外対象の詳細度が加算されます。
結合子自体は詳細度に加算されないですが、結合対象の詳細度が加算されます。

!importantが指定されると詳細度に関係なく最優先になります。
!important指定がある同士の比較の場合はどれが優先されるかは詳細度で判断されます。

後で面倒な事になるので、!importantと、CSSでのIDの使用は避けましょう。

#### 詳細度計算ツール
[Specificity Calculator](http://specificity.keegan.st/)
【備忘録】Intuneで、iPhoneで利用できるアプリを制御する

iPhoneをIntuneなどのMDMで管理していると、iPhoneのAppSotreアプリのインストールをどこまでやらせるか悩みどころ。「自由にインストール可」「絶対禁止な、というアプリ以外は自由にインストール可」「許可してるアプリのみインストールのみ可」とざっくり3パターンにわかれてて、後者ほど~~めんどくさく~~セキュリティに厳しくなってくる。

「絶対禁止な、というアプリ以外は自由にインストール可」というのはブラックリストで指定すればOKで、アプリのバージョンアップもユーザーで実施できる。

「許可してるアプリのみインストールのみ可」はホワイトリスト形式で管理することが多いんだけど、AppStoreを禁止にするシナリオと、禁止しないシナリオで勝手がいろいろ変わってくる。

それぞれどんな設定すればいいのか、を備忘録兼ねてまとめてみた。
ちなみに、監視モード前提。DEPにしておけば監視モードになってるはず。

#一部アプリのみ禁止（ブラックリスト形式）

Azureポータル→Intune→デバイスの構成→デバイスの制限→プロファイル、とメニューを掘ってく。
その中の[アプリの表示・非表示]で、[非表示のアプリ]に設定する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/237698/0a274ddf-6eca-7b40-75e7-502ff3a7d3d7.png)

AppStoreのアプリなら、「AppStore アプリ名」で検索して、URLを入力して、アプリ名（管理者がわかる任意の名前でOK)で追加する。
たとえば、LINEならこんな感じ。

| アプリURL|アプリバンドルID |アプリ名|発行元   |
|:-----------------|:--------|:----------|:--------|
|https://apps.apple.com/jp/app/line/id443904275 |(空白）|LINE(任意の名でOK)　　 |(空白でOK)|





このポリシー割り当てたら、インストールはできるのに、表示されない。起動もできない。


iOSの標準アプリは、AppStoreで見つけられないので、バンドルIDを使う。純正アプリのバンドルIDを集めたサイトがあって（多謝！）こちらを参照。
https://emm.how/t/ios-12-list-of-default-apps-and-bundle-id-s/790
業務にMusicは不要でしょ！とかいう場合はこれで非表示にできる。


#一部アプリのみ許可（ブラックリスト形式）

やることは、さっきと同じ。[非表示のアプリ]に、AppStoreを登録すること。

AppStoreを含めたiOSの標準アプリは、AppStoreで見つけられないので、バンドルIDを使う。純正アプリのバンドルIDを集めたサイトがあって（多謝！）こちらを参照。
https://emm.how/t/ios-12-list-of-default-apps-and-bundle-id-s/790

AppStoreなら、

| アプリURL|アプリバンドルID |アプリ名|発行元   |
|:-----------------|:--------|:----------|:--------|
|(空白）|com.apple.AppStore|AppStore(任意の名でOK)|(空白でOK)|

ほかの見せたくないアプリも同じ手順で、非表示のリストに入れておけばよい。


配布したいアプリは、Intune→クライアントアプリで設定する。

この方法だと、そもそもAppStoreが見えないのでユーザー変なアプリを入れようとしないで、あきらめてくれるくれる。アプリはポータルからインストールするしかありません!とシンプルな案内ができる点がメリット。

欠点は、AppStoreがないのでアプリのバージョンアップがめんどくさいこと。アンインストールして、Intuneポータルアプリから再インストールして、再度ログインするとか、面倒。


#一部アプリのみ許可だけど、バージョンアップもさせたい場合（ホワイトリストで管理）

手順はさっきとほぼ同じ。違うところは、[アプリの表示・非表示]で[表示のアプリ]を選んで、表示してもいいアプリを設定すること。

注意点は、「ここにインストールしてもいいアプリは全部登録する」こと。書かないとカメラやSafariなど純正アプリも非表示になる。

・AppStoreは記載する(必須！）
・インストールしていいアプリを表示のアプリに全部登録しておく。
・配布したいアプリは、Intune→クライアントアプリで設定する。

メリ・デメはさっきのブラックリスト形式の逆。

この方法だと、AppStoreは見えるから、バージョンアップはユーザーで実施できる。アカウント情報も持っていける。

デメリットは、AppStoreが見えてしまうので、インストールする操作自体はできてしまうこと。表示リストにないアプリはインストールしても見えないのだけど、ユーザーからするとインストールしたはずなのに！と問い合わせが来る恐れあり。面倒。

#まとめと余談

バージョンアップをラクにさせるか、それともインストールできないという問い合わせさせないか。どっちがいいかは要件次第。

あと、Wifiがないと大きめのアプリはインストールやバージョンアップができない。直近だと、200MB越えのアプリが対象。OutlookやExcelが引っかかってしまう。Teamsは手元でみたら160MBちょいだけど、200MB超えてないからLTEでもインストール可。インストールできません！という問い合わせがあったらこれのせいかもしれない。
hachidoriの「連携設定」で気づいたこと

# hachidori
ノンコーディングでチャットボットが作れてしまうサービス「hachidori」。
少しさわっったところ直感的に作れるので非常に使いやすいと感じました。
そこで、LINEから自作API経由で自社の勤怠入力できるサービスを作ったろ！と、ごにょごにょし始めたのですが、自作APIを呼ぶところでハマったので残しておきます。

※チュートリアルを誤って消してしまったので、チュートリアルを最後までやっていればハマらなかったかもしれませんが。

## 連携設定
hachidoriの「連携設定」は、hachidoriと他のWEBサービスを連携する機能です。
チャットで入力された文字を他のWEBサービスに送ったり、応答をチャットに表示したりできます。
ただ、この連携設定のクセがすごい。

### 正常に通信できたか分からない
連携設定のテンプレートのURLにテスト通信するタイミングは「更新する」ボタンの押下時のようです。
しかし、通信に成功しようが失敗しようが画面からは結果はわかりません。
なので、通信に失敗していた場合でも、URLやクエリーパラメータの編集が誤っているのか？認証情報が誤っているのか？別の理由なのか？原因が全くわかりません。
そして、これがまた厄介なのですが、一度成功したらその時点の事を覚えているらしく、その後に誤った変更をしてしまい本来であれば通信に失敗すべきところが、前回成功時のリクエストを送信してしまい成功してしまったりします。
で、うまくいったやん！と思ってシナリオを動かすと失敗するという。
もし、連携設定をする場合は、hachidori以外で失敗時の原因の切り分けができないか考えておくといいと思います。

### リクエストボディ、リクエストヘッダは固定
HTTPメソッドがGET以外も使えるため、リクエストボディの内容も可変だろうと必死でクエリーの設定を頑張りましたが無駄のようです。
どうもJ定義したもの固定で送られるようなので、可変の情報を送る場合はクエリパラメータでしか送れないことになります。
したがって、GET以外はおまけと考えてよいと思います。

### クエリパラメータ
パラメータが１つだけの場合は問題ないと思いますので、ここでは複数のパラメータを送る場合について書きます。
僕は日付と開始日付と終了時刻の３つのパラメータを送りたいのですが、普通に&で繋いでもエラーになります。
1つ目のパラメータの後ろが`&start_time=0900&end_time=1800`となるように、試行錯誤した結果が下記の表です。

|アンパサンドの違い|設定例|通信結果|編集結果|説明|
|:------|:--------:|:------:|:------:|:------|
|普通の＆|`&`start_time=;#時間1;|失敗|-|-|
|実体参照|`&amp;`start_time=;#時間1;|成功|`&ampstart_time=0900`|パラメータの先頭にampが付く|
|独自のエスケープ？|`&;`start_time=;#時間1;|成功|`&start_time=0900`|期待通り|

## まとめ
ということで、なかなかのクセとマニュアルなしという状態だったので、連携できるまでに随分と時間が掛かってしまいました。。
通信に失敗した時は、せめて原因特定につながるような情報は欲しいところですが、外部通信というちょっと技術寄りのところと、エンジニア以外の方でも作れるサービスというところで、トレードオフになってしまう所なのかなと思います。

しかしながら、このクセを差し引いても十分過ぎるほどのサービスです。本当に簡単にチャットボットが作れてしまうので、アイデアを思いついたらすぐに形にすることが可能です。
そのようなものに無料枠があるというのは本当にありがたいことです。
久しぶりで pyspark 立ち上げたら No module named 'py4j' と出た件

久しぶりで pyspark 立ち上げたら No module named 'py4j' と出た。
で、ぐぐったら、悉く環境変数PYTHONPATHにspark配布物の中の py4j の src zip ファイルを登録しろということだったんだが、やってみると**全く改善しない**。

結局、この件、 ipython が PYTHONPATH から zip を読み込まないことが原因だった。


```sh
$ python3.7
Python 3.7.4 (default, Jul  9 2019, 18:13:23) 
[Clang 10.0.1 (clang-1001.0.46.4)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import py4j
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ModuleNotFoundError: No module named 'py4j'
>>> 
$ env PYTHONPATH=$SPARK_HOME/python/lib/py4j-0.10.7-src.zip python3.7
Python 3.7.4 (default, Jul  9 2019, 18:13:23) 
[Clang 10.0.1 (clang-1001.0.46.4)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import py4j
>>> 
$ env PYTHONPATH=$SPARK_HOME/python/lib/py4j-0.10.7-src.zip ipython
Python 3.7.4 (default, Jul  9 2019, 18:13:23) 
Type 'copyright', 'credits' or 'license' for more information
IPython 7.7.0 -- An enhanced Interactive Python. Type '?' for help.

In [1]: import py4j                                                                                                                     
---------------------------------------------------------------------------
ModuleNotFoundError                       Traceback (most recent call last)
<ipython-input-1-cf59b57a4c3e> in <module>
----> 1 import py4j

ModuleNotFoundError: No module named 'py4j'

In [2]:                                                                                                                                 
Do you really want to exit ([y]/n)? y

```

`export PYSPARK_DRIVER_PYTHON=ipython` してあったため ipython が動いていた＆ dot file 書き換えて xterm 起動しても最初に読み込んだ dot file で設定してしまった PYSPARK_DRIVER_PYTHON が引き継がれて、これ殺しても No module named 'py4j' 出るなぁとしばらくハマった。

----
見つかった例を見るとほぼ全て、 `SPARK_HOME` を環境変数で設定しているけど、これ `PYTHONPATH` に展開させるためだけにあって spark 自体は参照していないので正しいんだよな。今まで設定したことないし。
なんかこう仕組みもわからず全部環境変数って辞めませんかね
iTerm2の便利な画面管理のショートカットを紹介

## iTerm2の便利な画面管理のショートカットを紹介
長い間iTerm2を使ってきて便利だと感じているショートカットを紹介します。

command + D 縦分割
command + T 新規タブ
command + W タブを閉じる

Chromeなどのブラウザのショートカットと似ているので覚えやすいですね。

この記事が参考になれば幸いです。
## 終わりに
私は現在、Web3のサービスの開発をしています。詳しくはこちらの記事をご覧下さい。
        [無料でイーサリアムが当たる、Web3時代の寄付サイトを作った話](https://note.com/kenroda/n/n814347fbdcd7)
micro SD card にubuntu-serverをインストールする方法

# はじめに
RaspberryPiにubuntu-serverをインストールすることになったのでここに方法を備忘録として残しておきます。
## 環境
・MacBookPro（High Sierra）
・[micro SD card](https://www.amazon.co.jp/%E3%82%A8%E3%83%AC%E3%82%B3%E3%83%A0-microSDHC%E3%83%A1%E3%83%A2%E3%83%AA%E3%83%BC%E3%82%AB%E3%83%BC%E3%83%89-Class10-UHS-I-MF-MS032GU11R/dp/B074CRKZP7/ref=sr_1_1?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&keywords=%E3%82%A8%E3%83%AC%E3%82%B3%E3%83%A0+microSDHC%E3%83%A1%E3%83%A2%E3%83%AA%E3%83%BC%E3%82%AB%E3%83%BC%E3%83%89&qid=1565186584&s=instant-video&sr=8-1)
・RaspberryPi 3B+
##方法
### ubuntu-serverのダウンロード
ubuntuの[公式サイト](https://ubuntu.com/download/iot/raspberry-pi-2-3)からRaspBerryPi用のubuntu-serverをインストールします。RaspberryPi 3B+なので ``Ubuntu Server image for Raspberry Pi 3``　をクリックしダウンロードします。 **（ファイルの解凍はしません）**
<img width="1083" alt="スクリーンショット 2019-08-07 23.06.54.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298612/8e01c55d-9dd7-e4f2-699d-b442dfd58c52.png">
### sdcardにubuntu-serverをインストール
次に、ダウンロードしたubuntu-serverをmicro SD card　にインストールします。ターミナルを使用した方法とフリーソフトウェアを使用した方法があります。今回はより簡単なbalenaEtcherというフリーソフトウェアを使用した方法を記述します。
[公式サイト](https://www.balena.io/etcher/)からbalenaEtcherをダウンロードしてアプリケーションを開きます。
<img width="799" alt="スクリーンショット 2019-08-07 23.13.20.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298612/2a1d5f6c-630b-00de-0557-60332c63c1e7.png">
**Select image**をおしてダウンロードしておいた `ubuntu-18.04.2-preinstalled-server-arm64+raspi3.img.xz` を選択します。
次に **Select image** を押して `raspberryPiで使用する micro SD card`　を選択します。
最後に **Flash!**　を押して数分待つと完成です！
# 終わりに
micro SD card のフォーマットの仕方やターミナル操作の仕方は時間があるときに更新します。
carrierwaveで一括uploadしたら同じファイル名で保存された


すっかりiosの仕事がなくなるわ、web系のエンジニアがみんな辞めてAWSからRailsまで触るようになってしまって数ヶ月経ちました
メモがてら

# 結論
色々やったけど元のファイル名を入れるしかなかった

```ruby
class ItemImageUploader < CarrierWave::Uploader::Base
  include CarrierWave::MiniMagick

  def filename
    "#{secure_token}_#{original_filename}" if original_filename.present?
  end

protected
  def secure_token
    var = :"@#{mounted_as}_secure_token"
    model.instance_variable_get(var) or model.instance_variable_set(var, SecureRandom.uuid)
  end
end

```

# 画像を一括upload
carriewaveを使うとmulitipartできた画像を一括でS3にuploadでできてDBに登録できるんだやったね！
https://qiita.com/ggtmtmgg/items/ba5f275c122c83013ea1


#できなかった
5個の画像をuploadしてもmodelをsaveした瞬間全部の画像が「aaaaa.jpg」と同じ名前で保存された

#原因
もうここに書いてるとおり
uploadのインスタンスがひとつだからひとつのファイル名になってた
filenameを呼び出す度に変えるようにしたらうまくいった

https://github.com/carrierwaveuploader/carrierwave/issues/1716

#それでもダメだった
S3にあげたときとDBに保存する時でファイル名が変わってた
RaspberryPi 3B+ でロボット制作【準備編】

# はじめに
友人とRaspberryPiでロボットを作ろうと思い、その過程をここに残そうと思います。
## 用意するもの
・Raspberry Pi 3B+
・micro SD card 32GB
・[Ubuntu Server image for Raspberry Pi 3](https://ubuntu.com/download/iot/raspberry-pi-2-3)
・[キャタピラ](https://www.amazon.co.jp/gp/product/B07KN1BCW6/ref=ppx_yo_dt_b_asin_title_o00_s00?ie=UTF8&psc=1)
・[配線とか色々](https://www.amazon.co.jp/gp/product/B075167Y4D/ref=ppx_yo_dt_b_asin_title_o01_s00?ie=UTF8&psc=1)
・カメラ
・スピーカー
・モバイルバッテリー
・はんだごて
##ロボットの完成予定イラスト
<img width="318" alt="スクリーンショット 2019-08-07 22.56.35.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/298612/4ff7a5ae-9c03-ea92-45fe-c78c57fe665e.png">

## 作業過程【随時更新予定】
・[micro SD card にubuntu-serverをインストールする方法](https://qiita.com/suponjipic/items/2df581b450a35f480e69)
・ubuntuの初期設定（明日更新予定）

# 終わりに
作業期間は夏休み終了（9月30日）までを予定しています。はんだごてや実際にロボットを組み立てるのは8下旬を予定しています。それまでは、ubuntuの設定やssh接続などを試してみようと思います。
Pythonでmongodbを操作する～その１～

#前書
pythonの学習を始めて２日目になります。
pythonと並行してmongodbも学習中のため、どうせなら一緒に勉強しようということでpythonでmongodbを操作してみました。

#当記事の記載範囲
この記事ではpythonでmongodbに接続し、DBの情報を取得するところまで記載しています。
collectionに対するCRUDはおいおい作成していこうと考えています。

#mongodbの起動
インストール方法などは省略させて頂きます。
以下のコマンドでmongodbを起動します。

```
> mongod
```
起動したコンソール上に以下のようなログが出力されます。

```
2019-08-07T20:46:55.219+0900 I NETWORK  [initandlisten] waiting for connections on port 27017
```
このログが出ていれば、mongodbがポート**27017**で接続を受け付けているという状態になります。
※ポート：27017はmongodbのデフォルトで使われるポート

この記事で使用するmongodbのDB、collectionの内容はこのようになっています。

```
> show dbs
admin   0.000GB
config  0.000GB
local   0.000GB
test    0.000GB
> show collections
employee
log
salary
> db.salary.find()
{ "_id" : ObjectId("5d4acf84de925ae437e2c123"), "name" : "山田", "salary" : 300000 }
{ "_id" : ObjectId("5d4acf84de925ae437e2c124"), "name" : "佐藤", "salary" : 400000 }
{ "_id" : ObjectId("5d4acf84de925ae437e2c125"), "name" : "田中", "salary" : 500000 }
```

#pymongoのインストール

以下のコマンドでPythonでmongodbを扱うためのライブラリをインストールします。

```
> pip install pymongo
```

#pythonのコードを書いてみる
早速、mongodbを操作してみます。
やることはDB内に存在するcollection名を取得するだけです。

``` MongoSample.py
from pymongo import MongoClient

class MongoSample(object):

    def __init__(self, name):
        self.client = MongoClient()
        self.db = self.client[name] #DB名を設定

    def collection_names(self):
        return self.db.collection_names()

mongo = MongoSample('test')
print(mongo.collection_names())

```
実行結果

```
/python/MongoSample.py:17: DeprecationWarning: collection_names is deprecated. Use list_collection_names instead.
  return self.db.collection_names()
['employee', 'salary', 'log']
```

取得できましたが、**DeprecationWarning**が出ています。
どうやら**collection_names()**が非推奨なので**list_collection_names**を使うようにとのことです。

MongoSample.pyに定義を追加して実行してみます。

``` MongoSample.py
from pymongo import MongoClient

class MongoSample(object):

    def __init__(self, name):
        self.client = MongoClient()
        self.db = self.client[name] #DB名を設定

    def collection_names(self):
        return self.db.collection_names()

    def list_collection_names(self):
        return self.db.list_collection_names()

mongo = MongoSample('test')
print(mongo.list_collection_names())

```

実行結果

```
['employee', 'salary', 'log']
```
今度は警告なくcollection名が取得できました。

#感想
私はJava以外の言語を久しぶりに勉強してみたので、あれ？ＤＢの操作ってこんなに簡単に出来たっけ？って感じです。
JavaだとＤＢへの接続はSingletonを使うことが一般的だと思いますが、mongodbはどうなんだろ？
トランザクションの制御はどうするんだろ？という新しい課題がたくさん出てきて楽しいなというのが正直な感想です。

#参考
MongoDB API Documentation
https://api.mongodb.com/python/current/api/index.html

書籍：MongoDB 解体新書：これ１冊で即実践レベル！究極の入門書（専門書）
UserWarning: Matplotlib is currently using agg, which is a non-GUI backend, so cannot show the figure. を直す

以下のエラーを直す

```
UserWarning: Matplotlib is currently using agg, which is a non-GUI backend, so cannot show the figure.
```

以下のコマンドで python3-tk を入れれば直る.

```
sudo apt install python3-tk
```
仙台CTF2018 Tri.3 車椅子の仕事人 50

#問題

http://ctf.sectanlab.jp/2018/challenges

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17681/f8b7b316-3bb8-5431-f92c-748a06fde333.png)

#解いてみた

なんかありましたね。ちょっと見たかったけど見てないです。
確か山田君と菅田君が出てたはず。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17681/7b99c23d-3d47-d0fd-ff16-297ada264530.png)

正解です。
仙台CTF2018 Tri.2 無断で仮想通貨発掘 50

#問題

http://ctf.sectanlab.jp/2018/challenges

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17681/bd71cdda-452d-2c79-5c8e-eef2268e4560.png)

#解いてみた

ぐぐります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17681/65fc369c-2529-e74c-af60-07679a5ff6f0.png)

「コインマイナー」っぽかったんですけど、違いました。
「マイニング」違いました。問題に書いてあるか。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17681/1f7efb86-c3ce-a60f-e22c-51b9009280e6.png)

めげずに調べていくと答え見つかりました。
GLSLでクオータニオンを回転行列に変換

## 概要
クオータニオンを回転行列に変換するGLSLの関数です。

```glsl:qua2rot.glsl
mat4 qua2mat( vec4 q ){

	mat4 m = mat4(
		1.0 - 2.0 * pow( q.y, 2.0 ) - 2.0 * pow( q.z, 2.0 ), 2.0 * q.x * q.y + 2.0 * q.w * q.z, 2.0 * q.x * q.z - 2.0 * q.w * q.y, 0.0,
		2.0 * q.x * q.y - 2.0 * q.w * q.z, 1.0 - 2.0 * pow( q.x, 2.0 ) - 2.0 * pow( q.z, 2.0 ), 2.0 * q.y * q.z + 2.0 * q.w * q.x, 0.0,
		2.0 * q.x * q.z + 2.0 * q.w * q.y, 2.0 * q.y * q.z - 2.0 * q.w * q.x, 1.0 - 2.0 * pow( q.x, 2.0 ) - 2.0 * pow( q.y, 2.0 ), 0.0,
		0.0, 0.0, 0.0, 1.0
	);

	return m;

}
```
長い...

## 参考
[○×つくろーどっとコム - やっぱり欲しい回転行列⇔クォータニオン相互変換](http://marupeke296.com/DXG_No58_RotQuaternionTrans.html)
仙台CTF2018 Tri.1 脆弱性の論文 50

#問題

http://ctf.sectanlab.jp/2018/challenges

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17681/89e2e8e0-bee8-7213-e46b-0734e24056ba.png)

#解いてみた

全く分からないのでぐぐります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17681/83dfda13-9551-219f-e0e2-5f6727222faa.png)

ありました。
JavaScriptの即時関数にハマった話


## 概要

- ハマって思い出したシリーズ。より正確には、完全に忘れてて時すでにお寿司シリーズ。
- 以下備忘録。


## 前提

- 以下のようなコードがある


```python
const hoge = function() {
  console.log("call hoge function");
}

(function() {
  console.log("call anonymous function");
})();
```
## 現象

- 最初のコードは無名関数が `hoge` に代入にされているだけにみえる。
- だけど実際には `hoge` は実行されてしまう。
- ブラウザ上で実行すると下記のようになる。

![DevTools_-_qiita_com_igayamaguchi_items_ac48b7e12890351ee55a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1843/03cd0bf5-bb4e-a73f-bdb2-0ef80e1d51f5.png)

- `call hoge function` が表示されてるので `hoge` が実行されているのがわかる



## 原因

Q. なぜ `hoge` が実行されてしまうのか？ -> A. セミコロンが省略されてるから

```javascript
const hoge = function() {
   console.log("call hoge function");
} // <- ここにセミコロンがないのが原因

(function() {
   console.log("call anonymous function");
})();
```
セミコロンが無いので文がまだ続いてると解釈され以下のようなコードを書いてるのと等価になる。

```javascript
const hoge = function() {
   console.log("call hoge function");
}(function() {
   console.log("call anonymous function");
})();
```
つまり代入する前に `function()` を定義したそばから `function()()` として実行されてしまう。

## 対処

- 代入文の最後にセミコロンを書く

```javascript
const hoge = function() {
   console.log("call hoge function");
}; // <- セミコロンかく

(function() {
   console.log("call anonymous function");
})();
```
- 即時関数の前に セミコロンを書く

```javascript
const hoge = function() {
   console.log("call hoge function");
}

;(function() { // <- "(" の前に";" を書く
   console.log("call anonymous function");
})();
```

- この問題は `即時関数` や `セミコロンの自動挿入` など話題と絡めてよく知られている。
- 最近はセミコロンを書かないスタイルを採用するケースは増えているので、即時関数を書く必要がある時は `;` を先頭につけておいた方が親切。
- 古のjQuery の プラギンはそうやってた。

## 即時関数 is 何？

- グローバルスコープを汚染しないように、コード全体を無名関数でくくって、関数スコープでコードを動かすテク
- 参考: https://qiita.com/katsukii/items/cfe9fd968ba0db603b1e

## その他参考

- https://cpplover.blogspot.com/2014/04/javascript.html
- http://www.koikikukan.com/archives/2013/04/09-003300.php
- https://www.webprofessional.jp/why-use-javascript-style-guide/
- https://blog.tai2.net/automatic_semilocon_insertion.html
仙台CTF2018 Lab.3 遮断対象URLの特定 100

#問題

http://ctf.sectanlab.jp/2018/challenges

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17681/96c78473-9564-5bb3-1439-03c5627752c8.png)

#解いてみた

ダウンロード元のURLを答える問題。
とりあえずさっきの問題の答えのファイル名でgrepしてみますか。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17681/ba5a8ee3-dd9b-4aea-3efd-20f54bfbb213.png)

1つだけヒットしました。
これが答え。

たぶんこれも邪道な解き方。正しい解き方はキャッシュをしっかり読み込むんだと思います。
[IECacheView - Internet Explorer Cache Viewer](https://www.nirsoft.net/utils/ie_cache_viewer.html) を使いました。

さっきの答えから知りたいファイル名は分かっているのでそれを探すと答えがあります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17681/863cc9a1-e24c-15f9-d905-af32b7bb43a4.png)

これが答え。
base64url をデコードする

# base64url をデコードする

OpenID Connect に関わるたびに、ID トークンをデコードするために書いてる気がしたので. そもそも Python がパディング無しに対応するオプションを付けてくれればいいのにな…….

```python
import base64

def decode_base64url(s):
  return base64.urlsafe_b64decode(s + b'=' * ((4 - len(s) & 3) & 3))

def encode_base64url(s):
  return base64.urlsafe_b64encode(s).rstrip(b'=')
```
仙台CTF2018 Lab.2 脆弱性攻撃コードの特定 100

#問題

http://ctf.sectanlab.jp/2018/challenges

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17681/320c86ed-3fe5-ca3a-3d8b-e677b057efa3.png)

#解いてみた

webサイト閲覧中に攻撃食らう脆弱性と言えばFlashですよね。もしくはpdfとか。
ちゃんと問題文のフラグの例のファイルもswfになってますし。

ダウンロードしたファイルの中からswfファイルを抽出したところ4つありました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17681/613c7a4b-210c-6039-1af4-a31c919468ed.png)

問題文に内容をテキストに書き換えてると書いてあるのでサクラエディタで開いてみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17681/7b94ba1b-27b0-e737-b207-c7815b432f33.png)

ひとつだけテキストのファイルがありました。ほかはバイナリ。
これが正解。

とはいってもこんな邪道な解き方では不完全燃焼なので一応$MFTも解析してみます。
[fte | Forensicist](https://www.kazamiya.net/fte) を使います。

結果をExcelに張り付けてcrtime(FN)の昇順に並び替えます。
そして一つ前の問題で検知したファイルは1.exeだったので、検索します。
そしたら1.exe直前に作成されたファイルがさっきの答えのファイルでした。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/17681/c47d8cb0-dbed-3875-7042-deaf8bbaacf0.png)

という解き方が本来の解き方な気がします。
k8s: coredns が loop 検出して進まない


参考資料
--------------------
[Debugging DNS Resolution Known issues (kubernetes.io)](https://kubernetes.io/docs/tasks/administer-cluster/dns-debugging-resolution/#known-issues)


TL;DR
--------------------
`/etc/resolv.conf`のDNSサーバIPアドレスが有効かチェックしましょう。
`systemd`が絡むと、色々ややこしそうです → [Known issues (kubernetes.io)](https://kubernetes.io/docs/tasks/administer-cluster/dns-debugging-resolution/#known-issues)。


環境情報
--------------------
- k8s: v1.14.5
- ホストOS: Ubuntu 16.04


状況
--------------------
以下のようなログが出て、`coredns`が止まります。
(`kubectl logs coredns... -n kube-system`でチェック)

```
plugin/loop: Loop (127.0.0.1:55953 -> :1053) detected for zone ".", see https://coredns.io/plugins/loop#troubleshooting. Query: "HINFO 4547991504243258144.3688648895315093531."
```

解決
--------------------

`/etc/resolv.conf`の指すDNSサーバのIPアドレスがダメでした。

```
# nameserver 127.0.0.53  # ← こっちがダメ
nameserver 8.8.8.8       # ← こっちを有効に
```

`kubelet`を再起動して、その後にクラスタを再起動しました。
(クラスタ再起動は`sudo kubeadm reset`後に`sudo kubeadm init ...`を順次実行)

```
sudo systemctl restart kubelet
```

複数の環境でk8sを動かしているので、別々の原因で障害が起きて、時間はかかるが勉強になります。。
公式サイトの[Tasks (kubernetes.io)](https://kubernetes.io/docs/tasks/)でk8sの機能を試したいだけなのですが（;・ω・)=3
とりあえずLinuxユーザーを追加するだけのAnsibleスクリプト

レガシーChefが動かなくてLinuxユーザー追加できなくて困った。
ということでAnsibleで場当たり的に解決したので備忘録。

# Inventory file

**hosts** に ユーザーを追加するサーバーの情報と、SSHの接続設定を記載します。

```init:hosts
[web]
xxx.xxx.xxx.xxx # ユーザーを追加したいサーバーのIP

[all:vars]
ansible_ssh_user={{ SSHするユーザー名 }}
ansible_ssh_private_key_file=~/.ssh/{{ 秘密鍵 }}
```

# playbook

**playbook.yml** に実際にユーザー追加の処理を記載した playbook を作成します。今回作るユーザーはパスワード無しで sudo できるようにします。

```yaml:playbook.yml
- hosts: all
  sudo: true
  vars:
    username: {{ 追加するユーザーの名前 }}
    password: {{ MD5ハッシュ化したパスワード }}
  tasks:
    - name: add a new user
      user: name={{ username }} password={{ password }} state=present

    - name: no password sudoable
      lineinfile: dest=/etc/sudoers.d/{{ username }} line="{{ username }} ALL=(ALL) NOPASSWD:ALL" create=yes owner=root group=root mode=0440

    - name: mkdir .ssh
      file: dest=/home/{{ username }}/.ssh/ state=directory owner={{ username }} group={{ username }} mode=700

    - name: add authorized keys
      file: dest=/home/{{ username }}/.ssh/authorized_keys state=touch owner={{ username }} group={{ username }} mode=600

    - name: copy publickey
      copy: src=~/.ssh/{{ 公開鍵 }} dest=/home/{{ username }}/.ssh/authorized_keys
```

# 実行

```sh
$ ansible-playbook -i hosts playbook.yml -u {{ SSHするユーザー名 }}

PLAY [all] *********************************************************************************************************

TASK [Gathering Facts] *********************************************************************************************
ok: [xxx.xxx.xxx.xxx]

TASK [add a new user] **********************************************************************************************
changed: [xxx.xxx.xxx.xxx]

TASK [no password sudoable] ****************************************************************************************
changed: [xxx.xxx.xxx.xxx]

TASK [mkdir .ssh] **************************************************************************************************
changed: [xxx.xxx.xxx.xxx]

TASK [add authorized keys] *****************************************************************************************
changed: [xxx.xxx.xxx.xxx]

TASK [copy publickey] **********************************************************************************************
changed: [xxx.xxx.xxx.xxx]

PLAY RECAP *********************************************************************************************************
52.196.24.246              : ok=6    changed=5    unreachable=0    failed=0
```

こんな感じの結果になればきっとうまくいっているはず。最後に追加したユーザーでSSHできるか確認しましょう。

```sh
$ ssh {{ 追加されたユーザーの名前 }}@xxx.xxx.xxx.xxx
```

# 参考

+ https://qiita.com/komitomo/items/e78855fa1ccee1737ac7
+ https://blog.5000164.jp/2015/11/28/ansible-sudo/
+ https://blog.pinkumohikan.com/entry/use-sudo-command-without-password


# おわり

🙌
rubysolo/dentakuの使い方

rubysolo/dentakuを使うことにより、安全に数学的および論理的な式を評価することが出来ます

https://github.com/rubysolo/dentaku

#使い方

##シンプルな評価
```ruby
calculator = Dentaku::Calculator.new
calculator.evaluate('1 + 1')
#=> 2
```

##変数の参照
```ruby
calculator.evaluate('hoge + 1', hoge: 1)
#=> 2 

#複数変数を宣言する場合
calculator.evaluate('hoge + huga + piyo', hoge: 1, huga: 2, piyo: 3)
#=> 6
```
<br>
変数の値をメモリに保存してから、それらの保存された値に対して式を評価することもできます

```ruby
calculator.store(one: 1)
calculator.evaluate('one + 1')
#=> 2
```
##例外処理
`evaluate`が評価する式にエラーがある場合、`evaluate`は`nil`を返します。
例外をそのまま返したい場合は`evaluate!`を使用します

```ruby
calculator.store(one: 1)
calculator.evaluate('aaa  + 1')
#=> nil

calculator.evaluate!('aaa + 1')
#=> UnboundVariableError: no value provided for variables: aaa
```

##組み込み関数
dentakuにはあらかじめ式の評価に使える関数がいくつか備わっています。

Math: `+`, `-`, `*`, `/`, `%`, `^`, `|`, `&`
Also, all functions from Ruby's Math module, including `SIN`, `COS`, `TAN`, etc.
Comparison: `<`, `>`, `<=`, `>=`, `<>`, `!=`, `=`,
Logic: `IF`, `AND`, `OR`, `NOT`, `SWITCH`
Numeric: `MIN`, `MAX`, `SUM`, `AVG`, `COUNT`, `ROUND`, `ROUNDDOWN`, `ROUNDUP`
Selections: `CASE`
String: `LEFT`, `RIGHT`, `MID`, `LEN`, `FIND`, `SUBSTITUTE`, `CONCAT`, `CONTAINS`
<br>
###if
if文はif(条件式, 真, 偽)のように使用できます

```ruby
calculator.evaluate('if(hoge >= 1, hoge + 1, -1)', hoge: 1)
#=> 2
calculator.evaluate('if(hoge >= 1, hoge + 1, -1)', hoge: 0)
#=> -1
```
<br>
###switch
switch文は`switch(変数, 条件1, 返り値1, 条件2, 返り値2..., else返り値)`のように書けます

```ruby
calculator.evaluate('switch(hoge, 0, 1+1, 1, 2+2, -1)', hoge: 0)
#=> 2
calculator.evaluate('switch(hoge, 0, 1+1, 1, 2+2, -1)', hoge: 1)
#=> 4
calculator.evaluate('switch(hoge, 0, 1+1, 1, 2+2, -1)', hoge: 2)
#=> -1
```
rubyでいうところのこんな感じです

```ruby
 case hoge
   when 0
     1+1
   when 1
     2+2
   else
     -1
 end
```
##自作関数
dentakuでは組み込まれている関数以外にも自身で関数を定義できます
定義には`add_function`を使用します
`add_function(:関数名, :返り値の型, ->(引数1, 引数2, ...) { 処理 })`

```ruby
#階乗の関数定義
calculator.add_function(:pow, :numeric, ->(mantissa, exponent) { mantissa ** exponent })
calculator.evaluate(pow(2, 2))
#=> 4
```

##コメントの挿入
```ruby
calculator.evaluate('hoge + 1 /* This is a comment */', hoge: 2)
```
単一責任原則vsカプセル化

本記事は元々AnonymousDiaryに投稿したものですが、初コメで「Qiitaでやれ」とアドバイスを頂き、こちらにも投稿してみることにしました。

ざっと見た感じ以降のような文体はQiitaにそぐわないかもしれませんが、書き直すのも面倒であった為、何卒ご容赦下さい。

ここではID登録してないとコメントできないようなので、匿名の方が良い方は[こちら](https://anond.hatelabo.jp/20190807204928)までお願いします。

以下の「初投稿につき～」はこちらでも同様です。ご指摘は参考にさせて頂きます。

---

初投稿につき至らない点があるかもしれないが容赦してほしい。が、指摘は受け入れる所存。

俺はとあるUIコンポーネントライブラリ開発者だが、先日議論されたあるコンポーネントの設計について悩み続けている。

これを読んでくれた人の設計センスや知識、経験から、第三者の率直な意見を聞きたい。

悩んでいることの概要は、

- `単一責任原則`に基づいて責務を減らすべきか、
- `カプセル化`するために責務を増やすべきか

ざっくり言えばこの2択だ。
どちらも間違った考えだとは思えないので、そもそもどちらかの捉え方がおかしいのだと思う。そういった意見も聞きたいが、まずは読んでみてほしい。

---

設計対象のコンポーネントは、よくある触って動かせる`スライダー`である。下記リンク先のようなものだ。

https://material-ui.com/components/slider/

前提として、このコンポーネントの構成要素を下記とする。

- `背景バー`：全体を表すバー
- `ノブ`：選択された位置を表す、ユーザーが動かせる部分
- `進捗バー`：バーの左端からノブの位置までを色づける部分

加えて、下記も前提としてほしい。

- 構成要素それぞれもコンポーネントとする
- `進捗バー`は横幅を変えて表示するだけで見た目の要件を満たす

`Slider`というコンポーネントクラスを作るとして、これらの構成要素をライブラリ-ユーザー間でどう分担するかという点で、AさんとBさんで意見が割れた。

それぞれの意見を要約すると下のようになる。Aさんはカプセル化を狙い、Bさんは単一責任原則を重視している。

- Aさん「`Slider`クラスは構成要素3つを隠蔽し、ユーザーは`Slider`インスタンスだけを作成すれば良い。」
- Bさん「ユーザーは構成要素3つをそれぞれ作成してから、`Slider`クラスにセットする。」

Aさんの構成イメージは下記のような感じ

```
画面
└ Slider         (ユーザーが作成)
   ├ 背景バー
   ├ ノブ
   └ 進捗バー
```

Aさん案の場合だと、`Slider`クラス内部で勝手にそれぞれの要素を作成し、自分の子にするなりして表示する。


Bさんの構成イメージは下記のような感じ

```
画面
├ 背景バー     (ユーザーが作成)
├ ノブ         (ユーザーが作成)
├ 進捗バー     (ユーザーが作成)
└ Slider       (ユーザーが作成)
   ├ 背景バーへの参照    (ユーザーが指定)
   ├ ノブへの参照        (ユーザーが指定)
   └ 進捗バーへの参照    (ユーザーが指定)
```

Bさん案では、ユーザーが構成要素それぞれを作成し、`Slider`にそれを食わせる。
`Slider`はAさん案のように各構成要素を構築する必要はなく、`ノブ`の移動や`進捗バー`のサイズ変更だけすれば良い。



Aさんはユーザーが制御する必要のない`背景バー`、`ノブ`、`進捗バー`の構成を隠蔽(カプセル化)しようと提案したが、
Aさん案に対し、Bさんは`単一責任原則`の観点から「各構成要素の構築や表示」という責任を外すべきだと訴え、Bさん案を提示した。
またBさんは、コンポーネントはユーザーが扱うべきものであり、コンポーネントがコンポーネントを内部で勝手に使用しているのは混乱を招くとの見方もしている。
ただしAさんの考えの通り、実際に各要素の構成をユーザーが制御するユースケースは存在しない。



その場では`単一責任原則`を持ち出したBさん案で決定された。
しかしなんとなくAさん案派だった俺はモヤモヤしたまま家に帰り、本当に`単一責任原則`に反しているのか、カプセル化よりも大事なのかと悩み続けている。
ここまでが事実となる。

---

さて本当にBさんが正しかったのか、あるいは単一責任原則の捉え方が間違っているのか、はたまた・・
第三者による意見が聞きたい。周りのコメントに左右されない率直な意見が望ましい。なんとなくな意見も歓迎する。


満たすべき機能は見た目だけではないがそこは置いておいてほしい。

---

以下は個人的な意見とか思ったことや疑問など。

- Bさんは日々アンチオブジェクト指向をうたっている。カプセル化もとい隠蔽が大嫌いであり参照透過性を重視したのかもしれない。Bさん案は参照透過なのだろうか。
- アンチオブジェクト指向のプロが設計した場合どうなるのだろう。
- Atomicデザイン的にはAさん案な気がする。
VSCodeの拡張機能で依存関係を知らなかった

VSCodeの拡張機能をインストールしても依存関係が解決できていない場合は補完機能などが動作しなかったりします。

実際に自分がハマりました・・・
Kubernetesの拡張機能をインストールしたのですが、補完機能が動いていませんでした。

![スクリーンショット 2019-08-07 21.05.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/388313/1447d306-88bf-942c-6e7e-fb8c5f93119f.png)

これをインストールするだけでは動作しないので依存関係タグにある拡張機能も合わせてインストールが必要でした。
![スクリーンショット 2019-08-07 21.05.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/388313/b36274a8-1fbe-b87e-e5b0-7358e4012ae9.png)

これを知らなくて、なんで補完機能が動かないの！！！！！！って叫んでました。。。。。
Expatを使ってPythonでXMLを解析する話

# Expatを使ってpythonでxmlを解析する話

## 結論

```python
from textwrap import dedent
from xml.parsers import expat

class xml_parser:
    def __init__(self, xml):
        self.xml = xml
        self.p = expat.ParserCreate()

        # parse setting
        self.p.StartElementHandler = self.start_element # start tag
        self.p.EndElementHandler = self.end_element # end tag
        self.p.CharacterDataHandler = self.char_data # tag value

    def start_element(self, name, attrs):
        print('Start element:', name, attrs)

    def end_element(self, name):
        print('End element:', name)

    def char_data(self, data):
        print('Character data:', repr(data))

    def parse(self):
        self.p.Parse(self.xml, 1) # parse xml

    def parse_file(self, filename):
        self.p.ParseFile(filename) # only byte code
```

## 背景

XMLファイルをpythonから解析するときに、Expatを使うと早いと聞いたため、exampleをやってみた話です。使いまわしが少しでもできるように、クラスで実装をしました。

## 実行してみた

- 実行環境
    - windows 10 64-bit
    - python 3.7.3
- 事前ダウンロード&インストール
    - 標準搭載のため不要

```python
# main program
def main():
    src = dedent("""<?xml version="1.0"?>
    <parent id="top">
    <child1 name="paul">Text goes here</child1>
    <child2 name="fred">More text</child2>
    </parent>""").strip()

    ins = xml_parser(src)
    ins.parse()


if __name__ == "__main__":
    main()

```

```powershell
# output
<?xml version="1.0"?>
<parent id="top"><child1 name="paul">Text goes here</child1>
<child2 name="fred">More text</child2>
</parent>
Start element: parent {'id': 'top'}
Start element: child1 {'name': 'paul'}
Character data: 'Text goes here'
End element: child1
Character data: '\n'
Start element: child2 {'name': 'fred'}
Character data: 'More text'
End element: child2
Character data: '\n'
End element: parent
```

## Expat関数

start_element関数、char_element関数、end_element関数とその引数の名称は、どうやらハンドラとして認識させるために固定のようです．

### start_element関数

tagを発見したときに行う処理です。各引数については以下の表通りになります。

| 引数  | データ型 |      例       |
| :---: | :------: | :-----------: |
| name  |   str    |   'parent'    |
| attrs |   dict   | {'id': 'top'} |

### char_element関数

tagの値を取得するときに行う処理です。

### end_element関数

終わりのtagを発見したときに行う処理です。

## 参考文献

- [xml.parsers.expat --- Expat を使った高速な XML 解析](https://docs.python.org/ja/3/library/pyexpat.html)
- [Searching XML Documents](https://flylib.com/books/en/2.243.1.97/1/)
WPA2パーソナルとWPA2エンタープライズの違い

##何をやるのか？
Wifiホットスポット構成(無線LANの認証)のWPA2パーソナルとWPA2エンタープライズの違いを噛み砕いていく。

##WPA2パーソナルとWPA2エンタープライズの意味

|用語|意味|
|:---|:---|
|WPA2パーソナル|暗号化の規格がWPA2で、事前共有鍵（PSK)を使って認証するやり方。つまり事前に設定されているパスワードで認証されるということ。
|WPA2エンタープライズ|暗号化の規格がWPA2で、認証サーバを使って認証するやり方。つまり、事前に設定されたパスワードはなく、外部に任せるやり方。

##似ている所と違う所
###似ている所
どちらも無線LANにおける認証のやり方である。
どちらも通信の暗号化はWPA2で行う。
###違う所
認証のやり方が違う。
**パーソナル**
事前に設定した暗号鍵を使ってうまく行けばOKと判断する
**エンタープライズ**
認証サーバに問い合わせて認証する

##用途
###パーソナル
個人使用の無線LAN機器であればパーソナルが推奨されます。個人用とや少人数であれば、少数の機器に対して暗号機を設定する手間よりも、認証サーバを用意する負担の方が大きくなるため、少人数に向いていると言えます。
###エンタープライズ
認証サーバを用意する負担よりも、たくさんの機器に対して暗号機を設定する手間の方が大きくなるため、企業などで利用する際にはこちらが向いています。

##参考
https://wa3.i-3-i.info/diff283security.html
【Content-Security-Policy】インラインスクリプトを読み込む

# Content-Security-Policy

`header("Content-Security-Policy: default-src 'self';"); `

- クロスサイトスクリプティング(XSS)攻撃に対する耐性を高めるためのセキュリティ機能
- js, css, 画像などをサイト自身の[オリジン](https://developer.mozilla.org/ja/docs/Glossary/Origin)のみから読み込む
- インラインスクリプトやインラインスタイルも読み込まない。

```html
<html>
    <head>
        <meta charaset="UTF-8">
        <title>インラインスクリプト</title>
    </head>
    <body>
        < script>
            alert("hello world");
        </script>
    </body>
</html>
```

# インラインスクリプトを許可したい


https://developers.google.com/web/fundamentals/security/csp/?hl=ja

>ナンスを使用するには、script タグに nonce 属性を指定します。この値は、信頼できる参照元リストに含まれる値と一致する必要があります。 

> 続いて、nonce- キーワードに付加したナンスを、script-src ディレクティブに追加します。


```php
<?php
$token = Token::get(); // ワンタイムトークンを生成
header("Content-Security-Policy: script-src 'nonce-{$token}';");
?>

<script nonce="<?=$token?>">
    alert("hollo world");
</script>
```

インラインスタイルなども同じ方法で読み込める。
What are some main reason to learn SAP FICO

What is SAP?

SAP FICO is a core useful element in SAP ERP Central element that permits a corporation to manage all of its monetary knowledge. the aim of SAP FICO is to facilitate firms to generate and manage monetary statements for analysis and coverage and help with effective business designing and decision-making. SAP FICO consists of 2 modules, SAP Finance (FI) and SAP dominant (CO), every of that is employed for specific monetary processes. SAP FI deals with overall monetary coverage and accounting whereas SAP CO focuses additional narrowly on designing and observation prices. SAP FI and SAP CO were originally free as separate modules however are currently therefore tightly integrated that several folks sit down with them as merely one module. If you want to learn SAP FICO, then join Intellipaat <a title="SAP FICO Course" href="https://intellipaat.com/sap-fico-s4-hana-finance-training/">SAP FICO Course</a>
.

Reasons to learn SAP FICO.

As expressed by Gartner, advanced analytics market, involving money services and different trade is gauged at $2 billion. there's associate increasing interest on the improvement of Business performance by incorporating Advanced Analytics. information availableness goes quickly. New sources of information ar known with enhanced acceptance of economic science and money Modeling. It conjointly helps in understanding money viability of a company.

According to Therese Tucker (Forbs) finance and accounting fields ar slowly being evolved with continuous enhancements within the technology. there's improvement of visibility and management of information. it's serving to to provide a lot of stress of business intelligence. because of cloud based mostly solutions, it's straightforward to implement technology, despite of monetary and different constraints. Automation method of FICO method has influenced Finance functions and with the assistance of latest development, FICO is taking part in role of an efficiethe nt competitive mortal.
UiPath イケてるワークフローの作り方 - 条件分岐編 - 


UiPathイケてるワークフローの作り方シリーズの「条件分岐編」です！

僕自身、UiPathアカデミーを受講後いくつかワークフローを作成してきましたが、いろんなアクティビティを使っていくうちに、「今までの俺の作り方ダサかったじゃん！！！」って思うことが多々あったので、みなさんに共有したいと思います。

# 前振り

**■数日前の自分**

シーケンスの時は「条件分岐」アクティビティだよね～、知ってる知ってる。
フローチャートのときは「フロー条件分岐」アクティビティ使えばいいよね～～

**■今の自分**

シーケンスは「条件分岐」
フローチャートは「フロー条件分岐」

はい、別にそれでも大丈夫です。ちゃんと動きますし。。

でも、それではイケてないワークフローを作ってしまう可能性があるよ！！！！

> イケてない。全然イケてない。 ダサい、ダサすぎる。

そんなこと言われないようにきちんと、状況に応じたアクティビティを使いましょう！！！


# true or falseの条件分岐のススメ

条件がtrueだったらこの処理をして、falseだったら別の処理をするというような、true or falseの条件分岐の場合について紹介します。

## イケてないtrue or false条件分岐

さて、以下の画像をご覧ください。

これは、変数numberに数値が入っており、50以上だった場合はメッセージボックス、50未満だった場合はスローアクティビティでエラーを出すようになっています。

このアクティビティはイケてるでしょうか...？

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/238739/046792be-8c00-807b-ca12-aaccfb9a05c6.png)

答えは、「イケてない。」です。

動くのは確かに動くんです。でもイケてない。

このように、trueの場合は何かの処理をして、falseの場合はエラーを出したいときは `trueか確認` アクティビティを使いましょう！！

## イケてるtrue or false条件分岐

イケてるワークフローはこちら↓↓

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/238739/e9c28074-b01a-fe66-446e-4d775c653a58.png)


これだけだと、あれ？元の方が良かったんじゃない？？って思われるかもしれません。でもtrueの場合の処理が多くなるとめちゃくちゃ見づらくなりますよね。

では、もう少し処理が複雑になった場合はどうなるでしょうか。条件分岐のtrueの処理の方に繰り返し処理を入れてみました。

左側が条件分岐アクティビティを使用している場合で、右側が`trueを確認アクティビティ`を使用している場合です。

右のほうがよりスマートで、ログ内容も目で見えるので分かりやすくないですか！？

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/238739/5c3251d6-4266-d245-bf96-2187ad84fecb.png)


今回は`trueを確認アクティビティ`だけ紹介しましたが、その逆の`falseを確認アクティビティ`もありますので、ぜひ使ってみて下さい！！

# パターン別条件分岐のススメ

変数の中がAだったら、Aの処理をする。BだったらBの処理をする。CだったらCの処理をする...という風にパターン別に条件分岐をしたい場合について紹介します。

## イケてないパターン別条件分岐のススメ

最初にすーっごくいけてない条件分岐のワークフローをお見せします。
これは、だれがどう見てもイケてない。。。。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/238739/e9b0b7c3-efe4-b0c9-1158-52ae572b7f6f.png)

シーケンスの条件分岐の中に条件分岐をいれて、さらに条件分岐をいれて、条件分岐をいれて...ｵｴｯ



じゃあ、じゃあフローチャートにすればいいよね！！

というわけでフローチャートを作ってみました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/238739/81b4b6d1-3fa5-aae5-97f1-18e474e0ae3a.png)


フローチャートは左上から右下に流れるように書くのでこんな感じになるかと思います。

1つ目よりは見やすくなりましたが...画面の幅とりすぎて、でかいｗ
でかすぎて見にくい！！というわけで残念ながらちょっとイケてない。。


# イケてるパターン別条件分岐のススメ

というわけで、イケてるパターン別条件分岐を作りたいなら`スイッチアクティビティ`を使いましょう！！

スイッチアクティビティを使用するとこんな感じになります↓↓

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/238739/a3852da8-50cc-2e22-fadb-7c8289d2ec86.png)

コンパクト！！見たい処理の部分だけ見れるのが良いですね～～

フローチャートでやりたい場合は`フロースイッチアクティビティ`があるので、そちらを使用してみてください！

# おわりに

UiPathには標準搭載のアクティビティが結構あります。一つ一つ見ていくと「へ～、こんなアクティビティあったんやー！」って思うこともしばしばあります。

できるだけいろんなアクティビティの用途を知っておくと、状況に応じて簡潔で見やすく分かりやすいワークフローを作成することができるので、時間があるときにでもアクティビティを漁ってみてください！

そんな時間ねえよっていう人はこの記事を見て、「へぇ～～～」って思っていただけると嬉しいです。
No module named 'apiclient'　エラー(YouTube Data API(v3))


YouTubeAPIを使ってプログラムを実行する時に躓いたので、今後自分と同じ人がいた場合のためのメモです。

#環境
エディター VScode
VScodeで選択されていたバージョン python 3.7.3
パスが通っているバージョン python 3.7.4
Youtube Data API(v3)を使うためにインストールしたもの
```$ $pip install --upgrade google-api-python-client
```

#エラー文
```ModuleNotFoundError: No module named 'apiclient'```
#原因
自分は複数のバージョンのPythonを入れていたためVScodeで選択されていたバージョンはパスが通っておらず実行しても選択されているバージョンには入っていないため、実行すると'apiclient'エラーがでた。

#解決方法
ターミナルで```which python```と入力するとパスが通っているPythonバージョンが表示されるのでそれにVScodeで変更してください。そうするとエラーが消えました。

###VScode　バージョン変更方法
1. エディターの左下に下の画像の用の部分があると思うのでクリックして ください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/392275/fa6de832-cd06-976a-0d92-d1dbd515c68b.png)

2. そうすると、バージョンが選択できるバーが出てくると思うのでそこからパスが通っているバージョンを選択してください。
PipenvでDjango開発環境をつくる

#はじめに
Djangoを開発するときに「pip」を使っていたのですが、「pipenv」という便利なツールがあるということで、「pipenv」を使ってDjangoの開発環境を作ってみたので備忘録として残したいと思います。

#Pipenvとは
Pythonで開発するときに、プロジェクト毎のパッケージの管理や仮想環境の構築を自動で行ってくれるツールです。
pipenvが管理するPipfileを共有することで、チームで同じ開発環境を準備することができるみたいです！

Pipenv:人間のためのPython開発ワークフロー
https://pipenv-ja.readthedocs.io/ja/translate-ja/

#Pipenvのインストール
pipが使える環境で以下を実行します。

```
$ pip install pipenv
```
インストールされていることを確認します。

```
$ pipenv --version
pipenv, version 2018.11.26
```
#Pythonのインストール

```
$ pipenv --three  # Python 3をインストール
$ pipenv --two  # Python 2をインストール
$ pipenv --python 3.7.2 # バージョン指定してインストール
```
実行するとPipfileが作成されます。
Pipfileの中身を確認。

```
[[source]]
name = "pypi"
url = "https://pypi.org/simple"
verify_ssl = true

[dev-packages]

[packages]

[requires]
python_version = "3.7"
```

#仮想環境の構築

```
$ pipenv shell

#実行後
(仮想環境名) $
```
仮想環境から抜け出す場合。

```
(仮想環境名) $ exit
```
#パッケージのインストール
パッケージをインストールする場合は以下のように実行します。

```
$ pipenv install パッケージ名
```

##Djangoのインストール

```
$ pipenv install Django
$ pipenv install django==2.0.6 # バージョンを指定して追加
```
実行後PipfileとPipfile.lockが作成されます。
Pipfileの中身

```
[[source]]
name = "pypi"
url = "https://pypi.org/simple"
verify_ssl = true

[dev-packages]

[packages]
django = "*"

[requires]
python_version = "3.7"
```

##開発環境のみにインストール
--devを指定すると開発環境だけで使用したいパッケージをインストールできます。

```
$ pipenv install --dev Pillow
```
Pipfileの中身

```
[[source]]
name = "pypi"
url = "https://pypi.org/simple"
verify_ssl = true

[dev-packages]
pillow = "*"

[packages]
django = "*"

[requires]
python_version = "3.7"
```

##アンインストール

```
$ pipenv uninstall パッケージ名
```
##脆弱性のスキャン
パッケージに既知の脆弱性が無いかチェックすることができます。

```
$ pipenv check
```

#スクリプトの設定
Pipfileの[scripts]に実行スクリプトを登録することができます。
`Pipfile`の `[scripts]`の下に設定していきます。

```
[scripts]
start = "python myproject/manage.py runserver"
```
スクリプトを実行します。

```
pipenv run start
```

#requirements.txt生成

```
$ pipenv lock -r
```

#Djangoのプロジェクト作成
仮想環境に入っている状態で以下を実行。

```
$ django-admin startproject プロジェクト名
```

#Djangoアプリ作成
仮想環境に入っている状態で以下を実行。

```
$ cd プロジェクト名
$ django-admin startapp アプリ名
```
#さいごに
「pipenv」を使ってDjangoの環境を作ってみましたが、パッケージで管理できることで、チームで開発する際に便利そうです。
また、パッケージの脆弱性などもチェックできることもうれしいですね！
今後「pipenv」を使って開発していきたいと思います。

#参考
[Pipenv:人間のためのPython開発ワークフロー](https://pipenv-ja.readthedocs.io/ja/translate-ja/)
[Djangoメモ(2) : Python, Pipenv, Djangoのインストールと動作確認](https://wonderwall.hatenablog.com/entry/2018/03/04/220000)
Laravel email(unique)【バリデーションエラー】：Validation rule unique requires at least 1 parameters.

#やりたい事
- 自分でuserformを作成して、Laravelに元々入っているusers_tableにデータを入れたい
- メールアドレスはuniqueで同じものがあれば「既に使用されています」と表示したい



#Error
Validation rule unique requires at least 1 parameters.

#結果
UserFormのbuildFormのemail欄
`'rules' => 'required|unique',`

↓　＊テーブル名を入れた

`'rules' => 'required|unique:users',`

*参考になったサイト
(https://www.oipapio.com/question-5966264)

#Controller
    public function register()
    {

        $form = $this->form(UserForm::class);

        if (!$form->isValid()) {
            return redirect()->back()->withErrors($form->getErrors())->withInput();
        }

        $user = $form->save();
        logger($user);

        Auth::guard()->login($user);

        return redirect(route('customer_top'));
    }

#View
            <div class="card">
                <div class="card-header">Register</div>

                <div class="card-body">
                    <form method="POST" action="{{ route('register') }}">
                        {{ csrf_field() }}

                        @if ($errors->any())
                        <div class="alert alert-danger">
                            <ul>
                                @foreach ($errors->all() as $error)
                                    <li>{{ $error }}</li>
                                @endforeach
                            </ul>
                        </div>
                        @endif

                        {!! form_label($form->name) !!}
                        {!! form_widget($form->name) !!}

                        {!! form_label($form->email) !!}
                        {!! form_widget($form->email) !!}

                        {!! form_label($form->password) !!}
                        {!! form_widget($form->password) !!}

                        {!! form_label($form->password_confirmation) !!}
                        {!! form_widget($form->password_confirmation) !!}

                        <button type="submit" class="btn btn-primary justify-content-center">Register</button>


                    </form>

                </div>
            </div>
        </div>


#Form
    public function buildForm()
    {
        $this
            ->add('name','text',[
                'label' => '氏名',
                'rules' => 'required'
            ])
            ->add('email','email',[
                'label' => 'メールアドレス',
                'rules' => 'required|unique:users',
            ])

            ->add('password','password',[
                'rules' => 'required|confirmed',
                'label' => 'パスワード',
            ])

            ->add('password_confirmation','password',[
                'rules' => 'required',
                'label' => 'パスワード確認',

            ]);

    }

#validation.php
他にもエラーメッセージを日本語に変える方法はあると思いますが、
一番早そうなのでこの方法でやりましたφ(..)
他のエラーメッセージのやり方がありましたら教えていただけると、初心者プログラマー津田は嬉しいでございます!::bow_tone2:

    'unique' => 'このメールアドレスは既に使用されています',
【C#】文字列を大文字/小文字を区別せずに置換する方法

Windowsのパスを置換する時に大文字小文字が入り混じっていて
上手く置換出来なかったのでメモ。

```C#
string srcStr = "abc\Abc\aBc";
string dstStr = Regex.Replace(inStr, "abc", "xyz", RegexOptions.IgnoreCase);

// 結果は"xyz\xyz\xyz"になる
```

String.Replaceではなく**『Regex.Replace』**を使って、
引数にRegexOptions.IgnoreCaseを指定すればOK。
ついつい文字列置換＝String.Replaceを使う癖がついているので
咄嗟に大文字小文字を区別せずにやる方法がわからなかった。