OmniAICreator/Qiita-1.07M huggingface dataset:
∞_00001 | 【資格試験】 Python 3 エンジニア認定データ分析試験の合格を振り返る

10月1日
下期一日で切りのいいこの日から
アウトプット習慣の定着のため
毎日投稿を開始しますっ!!（断言）

やろうかなぁでやらず終い..
が多い自分の習慣を変えるため
小さくてもいいから習慣を継続したいっ！！


心理学で「ハビットチェーン」という物があり

どんなに小さくてもいいから毎日継続
↓
そしてその結果をカレンダーなどに記録
↓
習慣の継続を視覚的に体感することで、求める習慣を形成

ベイビーステップで積み上げていくので
感想、ご意見、お気軽にいただけると嬉しいです(=ﾟωﾟ)ﾉ



今月チャレンジして無事、合格できた
Python3 のデータ分析試験について振り返り！！

---
- Pythonデータ試験とは
- 出題内容
- 準備
- 結果
- 感想

---

###◇Python 3 エンジニア認定データ分析試験とは

Python 3 エンジニア認定データ分析試験は
一般社団法人Pythonエンジニア育成推進協会
が実施している民間試験になります。


|＜概要＞||
|:-----------------|:------------------|
| 試験名称|Python 3 エンジニア認定データ分析試験|
| 受験料金             |1万円（外税）　学割5千円（外税） |
|  問題数               |40問（すべて選択問題） |
| 合格ライン             |正答率70% |
| 試験センター          | 全国のオデッセイコミュニケーションズCBTテストセンター |
| 主教材          | 「Pythonによるあたらしいデータ分析の教科書」（翔泳社）[Amazon](https://www.amazon.co.jp/dp/B07G39T2B7?ref_=k4w_oembed_aiaznBkQUebHMJ&tag=kpembed-20&linkCode=kpd) |
※ベータ試験受験のために本試験リリース時と変更があるかもしれません。
[出題範囲](https://www.pythonic-exam.com/archives/news/python_data)

###◇出題内容
社団さんのHPにて出題範囲、出題問題数まで書かれています。
[Amazon]

|節|問題数|
|:-----------------|:------------------|
| データエンジニアの役割|2|
| 実行環境構築             |1|
| Pythonの基礎               |3|
| Jupyter Notebook             |1|
| 数式を読むための基礎知識          | 1 |
| 線形代数         | 2
| 基礎解析        | 1
| 確率と統計         | 2
| NumPy        | 6
| pandas         | 7
| Matplotlib        | 6
| scikit-learn         | 8



###◇作戦

今回受けた試験はベータ試験で　～9/30　までに受験する必要があったため
 9/27(金)を受験日に設定。

Python基礎文法試験の傾向が主教材で取り上げた内容が素直に出るとのことだったので、
作戦は
主教材の読込み、jupiterNotebook上でソースの写経
の繰り返し！！
日本語の要件からソースが書ける様になったらスキップして
並べくすべてのソースを自力で再現できる様に練習を繰り返しました。

受験直前は、とにかくテキストの要点を振り返り
- 環境構築方法
- iPythonのコマンド
- JupiterNotebookの動作方法
- 統計_分析など基礎的な数学
- 各ライブラリ（Numpy,Pandas,matplotlib,sckit-learn）の特徴
出題数の多い各ライブラリの特徴の整理は特に重視して行いました。


###◇結果

825/1000点
で合格でした！！

業務経験のない自分としては一発で合格してよかった(^^♪
出題は変化級はほとんどなく、主教材で触れている内容が選択肢にありました。
また、誤りを選択する問題もありましたが消去法で明らかな間違いを探しに行けばスムーズな印象でした。


###◇感想

嬉しいと思える一方で、正直そこまで難解な出題ではなく、
テキストで知った事が素直に出ていた印象です。極端な話、記憶力に自信のある人でも受かってしましたそうなタイプの試験ともいえそうです。

現時点では、
基礎的なPythonの特徴を知り、機械学習やデータ分析で使用するライブラリを触った
と言えるだけという状況です。
大切なのはここから実際に分析してみて自分なりにあーだこーだ言いながら
データをこねくり回してみる経験だと思うので、今後
KAGGLEにチャレンジするか、もしくはサイトのクローリング方法を学習しつつデータ分析する
辺りを進めていこうかなと(*'ω'*)
Mac(iTerm2)でfish + fisherman

##fishのインストール


    $ brew install fish



確認


    $ fish -v

`fish, version 2.7.1`みたいなバージョンが出ればおつけー
## fishの保存場所確認



    $ which fish
     /usr/local/bin/fish

次の作業でこのパスを使います
<img width="233" alt="whichはコマンドの場所がみれるコマンド.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/331789/85097059-d06f-ee0c-25cb-a2f2bf41530d.png">
`which`はコマンドのフルパスが見れる的なやつです



## パスを通す


    $ sudo vim /etc/shells

先ほど`which fish`で確認した`/usr/local/bin/fish`を最後の行に追記。

    # List of acceptable shells for chpass(1).
    # Ftpd will not allow users to connect who are not using
    # one of these shells.

    /bin/bash
    /bin/csh
    /bin/ksh
    /bin/sh
    /bin/tcsh
    /bin/zsh
    /usr/local/bin/fish  ← これ

`/etc/shells`はshellを管理しているとこ。bash、zshとかが元から入ってる


## ログインシェルの変更


    $ chsh -s /usr/local/bin/fish

`chsh`はログインシェルを変更するコマンド。-sをつけないと対話的に動作する。



#### iTerm再起動。


## fishermanを入れる


    curl https://git.io/fisher --create-dirs -sLo ~/.config/fish/functions/fisher.fish


## fishのテーマ変更

https://github.com/oh-my-fish/oh-my-fish/blob/master/docs/Themes.md

ここから好きなテーマを入れる。
力尽きたので参考になりそうな記事のリンクを貼らさせていただいて終わります。


## 参考
以下のサイトを参考にさせていただいてます
https://nonsensej.xyz/articles/wp/741

## 参考になりそうな記事
https://qiita.com/k-waragai/items/396acd783ed03511d57c
[Rails]ローディング機能の実装

#はじめに
今回動画を投稿した後など読み込む時間がかかったりして、待つ時間があったのが気になったので以下のようなローディングのアニメーションの実装をしました。
![6aa53b09fa53faa9eba3cd90fe6d5b59.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435517/2ee28c5b-2278-9191-b305-7ce8b92609cd.gif)

####環境
Rails 5.2.3
Ruby 2.5.1

##実装方法
様々な方法がありますが、私の場合は以下を参考にして`CSS`でアニメーションを作成しました。
####参考資料
https://recooord.org/loading-animation/

####ビューファイル
先ず`application.html.haml`ファイルにローディングアニメーション用のクラスを`body`下に記述します。

```ruby:application.html.haml
%body
 .loader-wrap
   .loader
```

####SCSSファイル
次にSCSSにローディングアニメーション用のレイアウトを記述します。
色々記述してますが、先程の参考資料の中にあるサイトの内容を殆どコピペするだけで実装出来ます。
後は色や大きさなどを変更したりして自分の好みのレイアウトにして下さい。

####使用サイト:Single Element CSS Spinners
https://projects.lukehaas.me/css-loaders/
<img width="1440" alt="スクリーンショット 2019-10-02 0.34.40.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435517/40217dfb-3e37-fddb-20bb-fcfa6c8fcf27.png">


```css:loading.scss
.loader-wrap {
	position: fixed;
	display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 100%;
}


.loader,
.loader:before,
.loader:after {
  border-radius: 50%;
}
.loader {
  color: black;
  font-size: 11px;
  text-indent: -99999em;
  margin: 55px auto;
  position: relative;
  width: 10em;
  height: 10em;
  box-shadow: inset 0 0 0 1em;
  -webkit-transform: translateZ(0);
  -ms-transform: translateZ(0);
  transform: translateZ(0);
}
.loader:before,
.loader:after {
  position: absolute;
  content: '';
}
.loader:before {
  width: 5.2em;
  height: 10.2em;
  background: white;
  border-radius: 10.2em 0 0 10.2em;
  top: -0.1em;
  left: -0.1em;
  -webkit-transform-origin: 5.2em 5.1em;
  transform-origin: 5.2em 5.1em;
  -webkit-animation: load2 2s infinite ease 1.5s;
  animation: load2 2s infinite ease 1.5s;
}
.loader:after {
  width: 5.2em;
  height: 10.2em;
  background: white;
  border-radius: 0 10.2em 10.2em 0;
  top: -0.1em;
  left: 5.1em;
  -webkit-transform-origin: 0px 5.1em;
  transform-origin: 0px 5.1em;
  -webkit-animation: load2 2s infinite ease;
  animation: load2 2s infinite ease;
}
@-webkit-keyframes load2 {
  0% {
    -webkit-transform: rotate(0deg);
    transform: rotate(0deg);
  }
  100% {
    -webkit-transform: rotate(360deg);
    transform: rotate(360deg);
  }
}
@keyframes load2 {
  0% {
    -webkit-transform: rotate(0deg);
    transform: rotate(0deg);
  }
  100% {
    -webkit-transform: rotate(360deg);
    transform: rotate(360deg);
  }
}
```
後は今回はSCSSを使用している為、`@import`で`application.scss`にSCSSファイルを読み込むのを忘れないようにします。

```scss:application.scss
@import "loading";
```

####jQuery
後はアニメーションの設定をJSファイルに記述するだけです。
使用部分は「ページの読み込みが完了したらアニメーションの非表示の部分」まででも問題ありません。

```javascript:loading.js
$(document).on('turbolinks:load', function() {
  $(function(){
    var loader = $('.loader-wrap');
  
    //ページの読み込みが完了したらアニメーションを非表示
    $(window).on('load',function(){
      loader.fadeOut();
    });
  
    //ページの読み込みが完了してなくても2秒後にアニメーションを非表示にする
    setTimeout(function(){
      loader.fadeOut();
    },2000);
  });
});
```

#最後に
画像を使用する方法も他にありましたが、私は今回こちらの方で実装しました。
結構簡単に実装出来るので気になった方は試してみて下さい。
Vue.jsでスクロール時のイベントを便利に定義する

**追記:** この記事でやっていることをプラグイン化しました！ → https://github.com/laineus/vue-scroll-hook

# やりたいこと

わかりづらいので、具体的にやりたかったことを書きます。

自分が作っていたアプリでは、「ページを下のほうにスクロールしたら`トップへ戻る`ボタンを出したい」といった、「スクロールしたときに何かする」的な処理が結構ありました。

そのたびに、↓こんな感じに`created`と`destroyed`でイベントを登録・解除するのがめんどいな、と。

```vue
<script>
export default {
  created () {
    window.addEventListener('scroll', this.onScroll)
  },
  destroyed () {
    window.removeEventListener('scroll', this.onScroll)
  },
  methods: {
    onScroll () {
      // Do something
    }
  }
}
</script>
```

そこで、↓こんな感じに書くだけで、スクロールしたときのフックを定義できるようにしました。

```vue
<script>
export default {
  onScroll () {
    // Do something
  }
}
</script>
```

# 実装

公式ドキュメントをぱっと見した限り、[ディレクティブをカスタマイズする手段](https://jp.vuejs.org/v2/guide/custom-directive.html)はあるようですが、上記のようなフックのカスタマイズは見つかりませんでした。

なので、GlobalなMixinを作って実現しました。

```js:main.js
import Vue from 'vue'
// ..
import GlobalMixin from './GlobalMixin'

Vue.mixin(GlobalMixin)

// ..
```

↓onScrollが定義されていた場合、windowのscrollイベントに登録し、`destroyed`で削除します。

```vue:GlobalMixin.vue
<script>
export default {
  mounted () {
    // Register onScroll event
    if (!this.$options.onScroll) return
    requestAnimationFrame(() => { // ページ遷移の際にVueRouterが実行するy=0へのスクロールを無視するための処理です
      if (this._isDestroyed) return // この数フレームの間にコンポーネントが破棄される可能性を考慮しています
      window.addEventListener('scroll', this.$options.onScroll)
    })
  },
  destroyed () {
    // Unregister onScroll event
    if (!this.$options.onScroll) return
    window.removeEventListener('scroll', this.$options.onScroll)
  }
}
</script>
```

これだけです。

（余計なお世話かもしれませんが、↑このmixinはむやみに拡張しないでください）

そして、冒頭のように各コンポーネントで`onScroll`という名前でイベントを定義するだけです。

```vue
<script>
export default {
  data () {
    return {
      showButton: false
    }
  },
  onScroll () {
    this.showButton = window.scrollY > 100
  }
}
</script>
```

# 余談

公式のカスタムディレクティブの例でまさに[スクロール時のイベントを定義するサンプル](https://jp.vuejs.org/v2/cookbook/creating-custom-scroll-directives.html)があったんですが、ちょっとしっくりこないです…。

```vue
<div id="app">
  <h1 class="centered">Scroll me</h1>
  <div
    v-scroll="handleScroll"
    class="box"
  >
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. A atque amet harum aut ab veritatis earum porro praesentium ut corporis. Quasi provident dolorem officia iure fugiat, eius mollitia sequi quisquam.</p>
  </div>
</div>
```

`@scroll`的な感じで、`.box`がスクローラブルな要素で、そのonscrollに定義される感じがするけど、結局`window`全体のonscrollに定義してるし、そもそも外からイベントを定義したいケースも思いつかない。

`handleScroll`の引数に渡したelementを直接弄ってるのも手続き的で気持ちよくないです…。
Codeforces #587C (1216C) White Sheet

Codeforces #587C (1216C) White Sheet
===

https://codeforces.com/contest/1216/problem/C


あまり言い換えの必要もないが、この問題は以下の通りである。

```
- 白シート、黒シート、黒シートの３つのシートの左下と右上のx,y座標を渡す
- 白->黒->黒の順でシートを張るがこのとき、白のシートが完全に隠れるかを判定せよ
- x,yは x,y < 10^6
```

# １枚目を張ったときにどのような隠れ方があるか


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30938/974da9c0-a2dd-5242-3cbc-af0fa7636ca3.png)![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30938/b03dd5b6-a7b8-2dd3-fd0c-2d1876282490.png)![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30938/9816cda4-b608-eb87-7a6c-1a11dbea472d.png)

- 1: 全く白にかぶらない場合
この隠れ方には全く影響しないので考慮したくていいことは自明である。

- 2: 白の中に完全に入っている黒シート
２枚目のシートで白を隠すには元の四角すべてを隠さないといけないことは直感的に自明である。

- 3: 完全に隠している場合
この場合、２枚目をどのように張ったとしても完全に隠れているので、２回目を張るまでもなく隠れる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30938/4aaa921a-5472-8e08-abdc-db0461ce1276.png)

- 4: 四角を２分する場合
一瞬、２枚目のをどのように張るかの結果に影響を及ぼすように思えるが、「もう一枚」しか張れないので元の四角を張らなければ隠せないことが分かる

- 5 四角の一辺を隠す場合
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30938/fc368dff-3391-3cdf-2b90-38e57abc78c1.png)
この場合、２枚目の結果に影響を及ぼす。元の四角が白い破線まで存在していた場合、5の黒四角をはある１辺の二角を隠すので、二枚目の黒四角は赤線の四角を完全に隠すのならば隠しきれる。

- 6 四角の１角のみを隠す場合
- ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30938/17acd920-3aff-ecdb-600e-3de262013190.png)
多少判断に迷うが、この四角を「もう一枚で」隠すには縦・横が残っている白い部分と同じ以上の四角がなければ隠し切れない。

# ポイント：黒い紙は２枚だけであること
もしもこの問題が2枚の黒ではなく、任意枚数の黒い紙を使えるとするならば状況は変わってくる。例えば、上記の２の場合であっても、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30938/5f44a153-df66-08a5-2247-f0bf6e0655ac.png)

次の4枚が赤い領域を隠せば隠し切ることができるので、例えば、白い四角がどのように分割されているか（あるいは黒の四角の合計がどの領域を隠せているか）をしっかりと保持しなければならない。

# ポイント：今回の場合
あくまで２枚の黒い紙しか使えないため、上記の区分にしたがえば以下のように

|番号|１枚目で隠し切るか|隠しきれる２枚目は何か|
|----|------------------|-------------------------|
|1|NO|元の白い四角と同じサイズ|
|2|NO|元の白い四角と同じサイズ|
|3|YES|-|
|4|NO|元の白い四角と同じサイズ|
|5|NO|隠しきれなかった白い四角を隠せるサイズ|
|6|NO|元の白い四角と同じサイズ|

といえる。

```Python
x1, y1, x2, y2 = map(int, input().split())
x3, y3, x4, y4 = map(int, input().split())
x5, y5, x6, y6 = map(int, input().split())
 
def do_mask(x1, y1, x2, y2, x3, y3, x4, y4):
    # もし、既に隠しきられている場合、その旨を返す
    if x1 == -1:
        return -1, -1, -1, -1
    # 全部隠されている場合
    if x3 <= x1 and x2 <= x4 and y3 <= y1 and y2 <= y4:
        return -1, -1, -1, -1
 
    # パターン５で横長に隠す場合
    if x3 <= x1 and x2 <= x4:
        if y3 <= y1 and y1 <= y4:
            y1 = y4
        if y3 <= y2 and y2 <= y4:
            y2 = y3
 
    # パターン５で縦長に隠す場合
    if y3 <= y1 and y2 <= y4:
        if x3 <= x1 and x1 <= x4:
            x1 = x4
        if x3 <= x2 and x2 <= x4:
            x2 = x3
 
    return x1, y1, x2, y2
 
# 1枚目で隠す
x1, y1, x2, y2 = do_mask(x1, y1, x2, y2, x3, y3, x4, y4)
# 2枚目で隠す
x1, y1, x2, y2 = do_mask(x1, y1, x2, y2, x5, y5, x6, y6)
print("NO" if x1 == -1 else "YES")
```

https://codeforces.com/contest/1216/submission/60982788
Insta360EVOのVR180動画をaviutlで編集してYouTubeにうｐしよう

# VR180動画作成の流れ

以下の画像から動画に飛べます。

[![YouTubeへのリンクです](http://img.youtube.com/vi/gnrbmpXDRL4/0.jpg)](http://www.youtube.com/watch?v=gnrbmpXDRL4)


そもそもVR180動画というのは、左右に並んだステレオ超広角カメラからの映像を録画したものである。
YouTubeでは360度動画やステレオ180度動画が再生できる。視点をグリグリしたりできる。
このための動画が撮影できるのがInsta360EVOである。
このカメラを用いてYouTubeにアップするまでの流れは以下のとおりである。

- Insta360EVOで撮影する。
- 公式アプリでinsv形式のファイルからH264のmp4に書き出す。
- 書きだされたファイルをaviutl(1.1.0以降)で読み込み、加工して出力する。
- VR180 Creatorでメタデータを書き込む。
- つべにうｐ

# そこに至るまでの試行錯誤

## Insta360EVOの動画にぼかしをかけたいんですが…

動画を公開するにあたり、
例えば人の顔やスピードメーターなど後々トラブルとなりうる情報は予め消しておくほうがいい。
GoProの場合だとmp4が直接出力されるため、編集ソフトは好きなものを使える。
一方Insta360ではinsvという独自のファイル形式になっており、
どのみち一度は公式アプリを通さないとならない。
当然それなら公式アプリでちゃっちゃと作れればいいのだけど、
このような加工は公式アプリではできないという結論に達した。
ので、いったん書き出して別の編集ソフトを使うことにする。

問題になりそうなところとして

- 解像度が高い(5K,5760x2880)
- すなわち動画ファイルの容量が大きい(1分50秒のH264動画で1.5GBくらいになった)

## aviutlで編集がしたい

Adobe Premier Pro用の直接読み込みプラグインが用意されているようだが、
このためだけにライセンス購入はかなり高い。
そこでaviutlを使いたいので限界まで頑張ってみる。

### メモリが足りない(1.0.0)->1.1.0で解決

aviutl最大の問題点は32bitアプリケーションであり、扱えるメモリの制限がある。
結論としては1.0.0系列ではこの解像度の動画は取り扱えなかった。
システム設定から解像度を6000x4000とかにすると起動時点でメモリ確保に失敗する。
6000x3000だとぎり大丈夫だが読み込むとやはりメモリが確保できない。
そこで、1.1.0rc2を試すことにする。
こちらは扱えるメモリに制限がないためまったく問題なく読み込める。
ちなみに、後述のエンコード時に16GBメモリのマシンでも12GB付近で推移するため、
メモリ自体はあんまり食っていないように見える。

### NvEncでエンコードできない(解像度に制限がありどうやってもできない)

x264では1分50秒のエンコードに1時間もかかっている。
パフォーマンスを見ていると純粋にCPUしか使っていない。これはもったいない。
そこでnvencを利用してみるが、ただちに失敗してしまう。
どうやら4096x4096までという制限があるようで、幅が抵触している。残念。
なおInsta360公式アプリはgpuを使ってくれるので爆速でエンコード終了する。

### VR180のステレオ動画にうまくエフェクトを重ねられない(未解決)

当たり前なんだけど右目と左目で独立した動画が含まれているため、
ぼかしやモザイクをそれぞれに配置しなければならない。
今回は勘でやっているが、もし両眼で違和感なくやりたいとかなると…
厳密にやろうとするならば投影式と距離から左右の投影点を逆算して配置を決めることになるだろうか。
これは自分でaviutlのカスタムエフェクトを書くしか無いような気がする。

## 編集済み動画をVR180と認識させるためには

出力された動画はただの左右の同期された映像が含まれるだけのめっちゃでかい動画にすぎない。
これをVR180であると認識させるためにはメタデータを書き込む必要がある。

これはねえ、YouTubeのヘルプがわかりづらいと思うんですよ…
360度動画の場合は以下のページから情報が取得できる。
https://support.google.com/youtube/answer/6178631
VR動画の場合はこちら。
https://support.google.com/youtube/answer/6316263
どちらも、360 Video Metadata アプリを使うとしている。
https://github.com/google/spatial-media/releases/latest

一方、VR180の場合はここにリンクはなく、
VR180 Creatorというアプリが利用できる。
https://vr.google.com/vr180/apps/
動画ファイルにメタデータを埋め込むための機能もある。


# VR180動画を編集してみた感想

## YouTubeでは5K再生や全方位、ステレオ動画を扱えるのがいい。

カメラの技術向上に対して受け入れる幅が広いというのは純粋にありがたい。
ニコニコ動画だと解像度を落としたりパースペクティブに直したりしないといけないので
凄さが伝わりづらいというところがある。
一方コミュニケーションツールとしてはニコ動のほうが優れていると思う。

## 中間ファイルが大きくなりすぎる

結局、オリジナルの動画ファイルに加えて
変換済みのmp4,編集済みのmp4,メタデータを書き加えた最終成果物、
というファイルが出力される。
中間生成物たる動画ファイルのサイズは最終成果物の2倍もある。

## エンコードに時間がかかりすぎる

NvEncが使えないのは痛い。
高解像度故に時間がかかるから時短をしたいのに、
高解像度故にgpuが使えずにより時間がかかるというのは悪循環。

## 左右の視差を考慮した配置決めがしたい

equirectangularの投影式を用いて距離を適当に与えればできなくはないとは思う。

## Insta360EVOのマイクは時速40km以上では何の役にも立たない

ゴオゴオ音とともに、ピィィィという高周波のものすごい風切音が混入してしまう。
しかも周波数解析してみたが各周波数帯にまんべんなく含まれており、
単純にBPFでは切れないことがわかった。
正直レビューのために残しておこうかと思ったのだけど
長時間聞いていると体調悪くする可能性のある音であったため、無音の動画となった。
これはマイクの位置が非常に悪く、左右のレンズの下、若干外側にマイク穴がある。
これだと風防をつけるとレンズに写り込んでしまう。
Python3でメールアドレスが到達可能かチェックする

SESなどを利用していて、[バウンスメール](https://ja.wikipedia.org/wiki/%E3%83%90%E3%82%A6%E3%83%B3%E3%82%B9%E3%83%A1%E3%83%BC%E3%83%AB)を極力排除したい場合。
メールアドレスの正規表現チェックだけでは、メールアドレスとしての書式チェックはできても実際に使える（到達可能な）メールかのチェックができません。

ライブラリ`dnspython`を使うとDNSからMXレコードを取得できるため、ドメインとアドレスの存在チェックをかけることができます。

---

# `dnspython`のインストール

```
pip install dnspython==1.15.0
```

または

```
pip install git+https://github.com/rthalley/dnspython
```

# 実装

```python:mail_address_check.py
import re
import dns.resolver
import socket
import smtplib

mail_address = input("input mail address:")

# メールアドレス構文チェック
match = re.match('[A-Za-z0-9._+]+@[A-Za-z]+.[A-Za-z]', mail_address)
if match == None:
    print('Syntax error')
    exit()

# ドメインチェック
mail_domain = re.search("(.*)(@)(.*)", mail_address).group(3) # ドメイン部分の取り出し
try:
    records  = dns.resolver.query(mail_domain, 'MX')
    mxRecord = records[0].exchange
    mxRecord = str(mxRecord)
    print(mxRecord)
except Exception as e:
    print('None of DNS query names exist')
    exit()

# メールアドレス存在チェック
local_host = socket.gethostname()

server = smtplib.SMTP(timeout=5)
server.set_debuglevel(0)

try:
    server.connect(mxRecord)
    server.helo(local_host)
    server.mail('test@example.com')
    code, message = server.rcpt(str(mail_address))
    server.quit()

    if code == 250:
        print('Address exists') # 250 OK
    else:
        print('Address does not exists')
except Exception as e:
    print(e)
```

# 実行結果
```
>python mail_address_check.py
input mail address:hogehogehoge
Syntax error

>python mail_address_check.py
input mail address:hoge@hogefugapiyo.com
None of DNS query names exist

>python mail_address_check.py
input mail address:**********@gmail.com
Address does not exists
```

---

# 参考サイト

[Python Email Verification Script](https://www.scottbrady91.com/Email-Verification/Python-Email-Verification-Script)
【Oracle】DBA_SOURCEからソース文を綺麗に抽出して表示する



最近業務関連でOracleやMySQLを使用することが増えて色々調べ物をする機会があったので、その際のちょっとした忘備録

# ストアド・プロシージャのテキストソースを調べるには...

ViewのテキストはDBA_VIEWSの中にデータがあるが、DBA_PROCEDURESには類似のカラムは存在しない。
プロシージャやファンクションのテキストを知りたいときはDBA_SOURCESから抽出する必要がある。

**DBA_SOURCES**
Oracle公式のドキュメントは[こちら](https://docs.oracle.com/cd/E16338_01/server.112/b56311/statviews_2064.htm#i1588578)

公式ドキュメントを参照していただいてもわかるかと思うが、DBA_SOURCESはテキストソース1行ずつをデータとして持っている。
そのため、

```sql:badExample
  select * from dba_sources where name="***"
```

単純に抽出するのではダメで、

```sql:goodExample
  select text from dba_sources where name="***" order by line
```
綺麗に抽出する場合は逐一このようにtextだけをlineカラムでソートして表示する必要がある。
Python(3.4)で最大公約数を求めるコーディング

先日のABC142のD問題で、最大公約数を求める必要があった。
愚直にロジックを考えていたのだが、ほかの回答者のソースコードを見たらなんと既存の関数があるではないか。
ということで備忘録。

from fractions import gcd
p = gcd(m,n)

これだけ。

※なお、gcd = Greatest Common Divisor（最大公約数）とのこと。
FunctionComputeで.NET Coreが使える話 (1)

## きっかけ
Alibaba CloudのFunction Computeについて調べていたところ、使用出来る言語にC#が含まれていたので調べてみました。

---

## Function Compute
公式ドキュメントには、以下の説明がありました。
他社クラウドと同様にイベント駆動型のサーバーレスなサービスです。
> Alibaba Cloud Function Compute は、イベント駆動型のフルマネージドコンピューティングサービスです。Function Compute を使用すると、管理や O＆M を考慮することなく、あらゆる種類のアプリケーションやサービスをすばやく構築できます。マルチメディアデータを処理する一連のバックエンドサービスを数日で完了できます。

---

## 他社サービスとの使用言語比較
2019/10/01現在、他社のイベント駆動型のサーバーレスなサービスと使用言語について比較しました。

**比較したサービス**

* AWS Lambda
* Azure Functions
* GCP Cloud Functions
* Alibaba Function Compute

---

|  | AWS | Azure | GCP | Alibaba |
|:--------|:-----:|:-----:|:-----:|:-----:|
| Java  | 〇 | 〇 | × | 〇 |
| PHP   | × | × | × | 〇 |
| Node.js | 〇 | 〇 | 〇 | 〇 |
| C#    | 〇 | 〇 | × | 〇 |
| Ruby   | 〇 | × | × | × |
| Python | 〇 | 〇 | 〇 | 〇 |
| Go     | 〇 | × | 〇 | × |
| PowerShell &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | 〇 | 〇 | × | × |
| F# | × | 〇 | × | × |
| TypeScript &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; | ×| 〇 | × | × |

---

## Function Computeで使えるC#について
Function Computeは.NET Core2.1ランタイムをサポートしています。
現在の**.NET Coreは2.1がLTS**となっていて、2系は2.2まで出ています。
**2019年9月下旬に.NET Core 3.0がリリースされました。**

おそらく今後3.x系に移行すると思いますが、3.x系がLTSにならないとFunction Computeのランタイムもアップデートされない可能性があると予想されます。
そのため、ローカル環境での開発はバージョンに注意する必要があります。
.NET Coreの2.x系と3.x系では色々と変更が入っているので、予め3.x系にアップデートしても修正箇所が少なくて済むようなコード設計にしておくと楽だと思います。

---

## Function ComputeでC#の関数を作成する
OSSにファイルをアップロードまたは、zipファイルをアップロードする必要があります。
~~Java以外のランタイムとは関数の設定画面が異なるので、手順が整理出来次第記事を追加していきます。~~
記事追加しました！(2019/10/03)
https://qiita.com/cube8080/items/ce27de96138b1aecad6b

---

![alibaba_function.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254932/af2bee55-ea01-5c07-a87e-fd14ea30e116.png)
(最近画面のUIが変わったので公式ドキュメントと実際の画面が異なっている場合があります。)

---

* Function Compute C# SDK
https://github.com/aliyun/fc-csharp-sdk

* Function Compute C# Libraries
https://github.com/aliyun/fc-dotnet-libs 

---
Homebrew caskでVirtualBox・Vagrantをインストールして起動するまで

#前提
・`Homebrew`がインストールしてある
・`Homebrew cask`がインストールしてある
・インストール先を`/Applications`に変更してある

#手順
・`VirtualBox`のインストール
・`Vagrant`のインストール
・`box`の追加
・`vagrantfile`の生成
・vagrantの起動
・SSH接続
・vagrantの停止

##Vagrantのインストール
```:ターミナル
$ brew cask install vagrant
$ brew cask install vagrant-manager
```

##VirtualBoxのインストール
```:ターミナル
$ brew cask install virtualbox
```

※以下のようなエラーが出た場合

```:ターミナル
There was an error while executing `VBoxManage`, a CLI used by Vagrant
for controlling VirtualBox. The command and stderr is shown below.

Command: ["startvm", "4fb35db2-bba9-4110-9cfd-63914883615e", "--type", "headless"]
```

システム環境設定 > セキュリティの画面で許可してください。

##boxをインストールすると生成されるVirtualBox VMsというディレクトリの場所を変更したい場合

デフォルトではユーザー名ディレクトリの直下に生成されます。


まず、VirtualBoxのアプリを起動
環境設定で、デフォルトの仮想マシンフォルダーを編集する

boxをインストールした後でも変更できるので調べてみてください。
アプリ内で操作は完結します。

##boxの追加

```:ターミナル
$ vagrant box add centos/7
```

`centOS7`をインストールします。
実行すると、providerが聞かれます。
今回は`VirtualBox`を利用しているので３を選択。

```:ターミナル
==> box: Loading metadata for box 'centos/7'
    box: URL: https://vagrantcloud.com/centos/7
This box can work with multiple providers! The providers that it
can work with are listed below. Please review the list and choose
the provider you will be working with.

1) hyperv
2) libvirt
3) virtualbox
4) vmware_desktop

Enter your choice:
```

以下のように表示されたらインストール成功

```:ターミナル
==> box: Successfully added box 'centos/7' (v1905.1) for 'virtualbox'!
```

##vagrantfileの初期設定
```:ターミナル
$ vagrant init centos/7
```

##vagrantの起動
```:ターミナル
$ vagrant up
```

##ssh接続
```:ターミナル
$ vagrant ssh
```

##vagrantの停止
```:ターミナル
$ vagrant halt
```

#最後に

##ぼくのディレクトリ構成
```
/Users/ユーザー名/VirtualMachine
├── VirtualBox VMs
│   └── centos7_default_1569940899284_29391
│       ├── Logs
│       │   ├── VBox.log
│       │   ├── VBox.log.1
│       │   └── VBox.log.2
│       ├── centos-7-1-1.x86_64.vmdk
│       ├── centos7_default_1569940899284_29391.vbox
│       └── centos7_default_1569940899284_29391.vbox-prev
└── centos7
    └── Vagrantfile
```

今回はcentOS７をインストールして仮装環境を構築しました。
仮装環境を起動するには、`vagrantfile`のあるディレクトリで`vagrant up`をすると起動します。

`VirtualBox VMs`は、boxをインストールすると生成します。
生成場所の変更は、上に記述してあります。

##参考
https://www.gatch.site/entry/vagrant-virtualbox-mac#virtualboxのインストール
http://www.vagrantbox.es/
https://qiita.com/sudachi808/items/3614fd90f9025973de4b
https://qiita.com/ohuron/items/057b74a42b182b200ae6
プログラミング初心者がEclipseやめてはじめてみたVSCode入門

###はじめに

入社してからJavaを触り始めて半年のプログラミング初心者です。
新人研修でJavaに初めて触れてからというものずっとEclipseで開発をしていました。
圧倒的VScode派の先輩にその存在を教えてもらったので軽率に始めてみました。
今回は、WindowsでJavaの学習を行うためにVSCodeをインストールしたのでJava用の環境を整えます

はじめて記事を投稿するので間違っている点などがあればが指摘お願いいたします。
プログラミングど素人の過去の自分に教えてあげるつもりで書いてます

#VSCodeってなんぞ
VSCode はMicrosoft社が開発したソースコードエディタ
Javaに限らずpython,PHP,Go,HTML,CSS,C++,C#,JavaScriptなどなど様々な言語に対応しています

これ以上の説明はできないので間違った説明をする前に「もっと知りたい！」という方がいらっしゃればこちらの記事を参考にしてください
[なぜ、VSCodeを使うのか？](https://qiita.com/lldev2/items/46d55f71bdc1af2e3b10)

テキストエディタとしても優秀なのはなぜかが分かりやすく書かれているのでオススメです


##開発する前の準備

まずVSCodeをインストールする前に用意するものがあります
###JDKのインストール

だけです
インストールしてJDKのパスを覚えておいてください

![JDK_PATH.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/481361/009affa8-8df1-5ad0-483e-e1db99850b48.png)

こんなかんじでだいたいProgramFiles > Java の中に入っているパターンが多いです

次はVSCodeをインストールします


##VSCode インストール

ここから本番です

[VisualStudio Code](https://www.microsoft.com/ja-jp/dev/products/code-vs.aspx)

↑のリンクからダウンロードできます
一番下の`VisualStudio Code 無料ダウンロード` ボタンをクリックすればOKです
とっても簡単ですね

インストールが完了したら展開してください

次は拡張機能の追加を行います

##拡張機能の追加
拡張機能を追加できるのは数多くあるVSCodeの利点の一つです
Extentionという積み木みたいなマークのところで拡張機能の追加を行います
`Ctrl + shift + X`で拡張機能の検索を行います
![JAVA_extentions.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/481361/9f9e7c2e-5fb9-b06e-c57b-7c9b05a859b8.png)

↑の`Java Extention Pack`をインストールすれば、Javaが使えるようになります。

最後にJDKの設定を行います

##JDKの設定
最後に、設定を開きインストールされているJDKをVSCodeに設定します
左下の歯車ボタンをクリックすると設定を検索できます
`setting.json`で検索をかけて編集をします

![setting.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/481361/19aa19e8-0ffa-47d0-03ba-0df34817daa1.png)


以下をsetting.jsonに追記してください。
注）追加するときは前行の最後に`,（コンマ）` を忘れると怒られちゃいます
    , で区切ってから追記してください

```
{
"java.home": "C:\\Program Files\\Java\\jdk-12.0.2"
}
```


setting.jsonを保存してVSCodeを再起動すれば、環境構築終わりです

お疲れさまでした。

環境構築が苦手な私でもあまり苦しまずにできましたし、コードも見やすくテキストエディタとしてもよくておすすめです。

よいVSCodeライフを!
Gazebo error : fatal error: sdf/sdf.hh No such file or directory

# fatal error: sdf/sdf.hh No such file or directory

```console
$ colcon build --symlink-install

make[2]: *** 'libTelloPlugin.so' に必要なターゲット '/usr/lib/x86_64-linux-gnu/libignition-common1.so.1.0.1' を make するルールがありません.  中止.
make[2]: *** 未完了のジョブを待っています....
In file included from /usr/include/gazebo-9/gazebo/common/common.hh:8:0,
                 from /usr/include/gazebo-9/gazebo/gazebo_core.hh:19,
                 from /usr/include/gazebo-9/gazebo/gazebo.hh:20,
                 from /home/k-koh/ros2_ws/src/tello_ros/tello_gazebo/src/tello_plugin.cpp:3:
/usr/include/gazebo-9/gazebo/common/Battery.hh:25:10: fatal error: sdf/sdf.hh: そのようなファイルやディレクトリはありません
 #include "sdf/sdf.hh"
          ^~~~~~~~~~~~
compilation terminated.
make[2]: *** [CMakeFiles/TelloPlugin.dir/src/tello_plugin.cpp.o] Error 1
make[1]: *** [CMakeFiles/TelloPlugin.dir/all] Error 2
make: *** [all] Error 2
---
Failed   <<< tello_gazebo	[ Exited with code 2 ]
Aborted  <<< tello_driver                                                            
Aborted  <<< turtlebot3_node
Aborted  <<< tello_description                                       

Summary: 10 packages finished [6.41s]
  1 package failed: tello_gazebo
  3 packages aborted: tello_description tello_driver turtlebot3_node
  1 package had stderr output: tello_gazebo
  4 packages not processed
```

# Fixed
```console
$ sudo apt-get purge libgazebo9-dev
$ sudo apt-get install -y libgazebo9-dev
$ rosdep install --from-paths . --ignore-src --rosdistro dashing -y
$ sudo apt-get install ros-dashing-gazebo*
```
高度情報試験対策　よく出る略語一覧

高度情報試験（主にシステムアーキテクト）対策第２弾、今回は午後２のシステム設計やシステム戦略などの分野を中心に、よく出される略語関連を簡単にまとめてみました。[こちら](https://yk0807.com/techblog/2019/10/01/%e3%82%b7%e3%82%b9%e3%83%86%e3%83%a0%e3%82%a2%e3%83%bc%e3%82%ad%e3%83%86%e3%82%af%e3%83%88-%e5%8b%89%e5%bc%b7%ef%bc%92%e3%80%80%e3%82%88%e3%81%8f%e5%87%ba%e3%82%8b%e7%95%a5%e8%aa%9e%e4%b8%80%e8%a6%a7/)の自分のブログと同じ内容です。

**BABOK ビジネスアナリシス知識体系ガイド Business Analysis Body Of Knowledge**　ビジネスアナリシスの計画と監視、引き出し、要求管理とコミュニケーション、エンタープライズ・アナリシス、要求分析、ソリューションの評価と妥当性確認、基礎コンピ天使という7つの知識エリアを体系づけている。

**BCP 事業継続計画 Business Continuity Planning** 災害などの緊急事態が発生したときに、企業が損害を最小限に抑え、事業の継続や復旧を図るための計画

**BPMN ビジネスプロセスモデリング表記法　Business Process Model and Notation**　ワークフローとしてビジネスプロセスを描画するグラフィカルな標準記法

**BSC バランスト・スコアカード　Balanced Scorecard**  「財務」「顧客」「社内ビジネスプロセス」「学習と成長」の4つの視点で業績管理指標をバランスよく組み合わせ、戦略実行や業績評価を行うためのツール

**DFD 機能情報関連図　Data Flow Diagram** 対象業務の処理過程と情報の流れを統一記述規則に基づいて表現したもの。

**EVA アーンド・バリュー分析  Earned Value Analysis**  予算および予定の観点からプロジェクトがどのように遂行されつつあるかを定量的に評価し、コスト効率と進捗率を一度に把握するためのプロジェクト管理の技法

**FMEA 故障モードと影響解析　Failure Mode and Effects Analysis** 故障・不具合の防止を目的とした、潜在的な故障の体系的な分析方法

**FTA フォルトツリー解析　Fault Tree Analysis** 故障・事故の分析手法、下位アイテム又は外部事象、若しくはこれらの組合せのフォールトモードのいずれが、定められたフォールトモードを発生させ得るか決めるための、フォールトの木形式で表された解析
 
**KPI 主要業績評価指標　Key Performance Indicator** 企業目標の達成度を評価するための主要業績評価指標

**NPV Net Present Value 正味現在価値**　ある将来に受け取れる価値が、もし現在受け取れたとしたらどの程度の価値を持つかを表すもの

**RFI 情報提供依頼書 Request For Information**　各種事業への参画能力についての情報を収集するための文書（事務手続）

**RFP 提案依頼書　Request For Proposal** システムの導入や何らかの業務を委託する際に、IT企業に「○○したいので最適な提案を下さい」と依頼するための文書

**ROI 投資利益率　Return On Investment** 投資額に対してどれだけ利益を生み出しているかを見る尺度　（投資利益率 %）＝ 100 ×（当期純利益）÷｛（期首総資本＋期末総資本）÷ 2 ｝
javascriptのMapは中身が入っていてもJSON.stringifyすると空に見える

掲題の通り

``` javascript
const hoge = new Map();
hoge.set(1,1);
console.log(JSON.stringify(hoge));// {} が出力される
```

正しい動作なので慌てずに中身をentriesなどで取り出して検証しましょう。
カスタムフィールドのメモ

#カスタムフィールドを実装したい
WordPressのカスタムフィールドは、投稿にタイトルやコンテンツ以外の入力欄を追加できる機能。

ECサイトなど、ある程度決まったフォーマットで様々なコンテンツを作成する必要があるときに効果的。


例えば、
- ファイルをアップロードできる
- チェックボックスやラジオボタンで選択できる
- 決まった項目を入力するテキストボックス
など



#投稿画面にカスタムフィールドを追加する方法
導入が簡単かつ、効率的な運営ができるのがプラグインを使った方法。

Custom Field Templateが使いやすそうと感じた。


カスタムフィールドの基本的な仕組み
入力欄に入力された内容は、「ポストメタ（post_meta)と呼ばれるデータとして、投稿本体と一緒にデータベースに保存される。
入力内容をページに表示するためには、保存されたポストメタを取得し、HTMLに出力するようなプログラムをテンプレートファイルに記述する必要がある。




##テンプレートコンテンツの設定例

````
[link]
type=checkbox
value = linknone
valueLabel = リンクなし
````

１行目の[]で囲まれた部分。
これが、テキストフィールドに入力された値を取得するのに必要な「キー」になる


値を取得するには、`post_custom()`関数を使います。
値をHTMLに出力するのではなく、返す。


取得した値が文字列の場合、文字列が返ってくる。
値を取得できなかった場合、falceが返ってくる。


````php
post_custom('link')
````

入力欄がテキストフィールドやテキストエリアだった場合→文字列が返る
チェックボックスやラジオボタンなど値が複数の場合→配列が返る


###カスタムフィールドの値を使った条件分岐


````php
<?php if(post_custom('link')):?>
//値が取得できたときに行う処理
<?php endif;?>
````



###チェックボックスの値を一つずつ処理する


````php
<?php $post_custom = post_custom('link')(
//取得した値を変数$post_customに代入
if($post_custom):
//$post_customがfalse出ない時だけ処理
?>
````


##プラグインAdvanced Custom Fieldsが使いやすかった

https://www.kerenor.jp/advanced-custom-fields-checkbox/
https://www.kerenor.jp/loop-sorted-by-customfield/
二段階認証を実装するまでに調べたこと

二段階認証を実装するにあたり、自分が調べたことをまとめました。
何か間違ったことがあれば、コメントいただけると幸いです！

## 二段階認証?二要素認証
英語では、二段階認証を「Two-Factor-Auth」と訳しますが、日本語では「二段階認証」と「二要素認証」は明確に異なります。
二段階認証の説明をする前に、認証の3要素について説明する必要があります。

### 認証の三要素
私たちが普段Webサービスを利用する際に、アカウントが自分のものか、認証を行います。その代表的な手段として「メールアドレス」と「パスワード」が一般的です。ですが、一個人を特定する方法として、他にも種類があります。それらを3つに分類したものを「認証の3要素」と呼んだりします。以下のように分けられます。

##### ユーザが知っていること（知識情報）
`ID・パスワード` `秘密の質問`

##### ユーザが持っているもの（所持情報）
`電話番号` `キャッシュカード` `ワンタイムパスワード用トークン（ハードウェア・ソフトウェア）`

##### ユーザ自身の特徴（生体情報）
`指紋認証` `顔認証`

### 結局どう違うの？
認証の3要素を用いて、一個人を特定することは変わりません。ただ、認証の回数や認証要素の数で変化します。以下が違いとなります。
#### 二段階認証
`認証回数を2回以上`に分ける認証方法を表します。極端なことを言えば、
`一回目：メールとパスワードで認証、二回目：メールとパスワードで認証`でもOK。ただ、そんなザルな認証方法はないので、二回目の認証をSMSでの認証を行うことがよくみられる実装です。

#### 二要素認証
`認証要素を2つ以上組み合わせる`認証方法を表します。例えば、ATMで現金を引出す際に、キャッシュカードと指紋認証で認証を行なった場合、二要素認証となります。

※二回目の認証をSMSで認証を行なった場合、二段階認証でありかつ二要素認証となります。

それでは、次に二段階認証でよく用いられるワンタイムパスワードについて説明します。

## ワンタイムパスワード(OTP)の仕様について
ワンタイムパスワード(以下、OTP)の仕様については、独自で決めるのではなく、IETFのRFCに仕様がまとまっており、それに準拠して実装を行う。

## OTPの生成方法は大きく二つある
### HOTP (HMAC-Based One-Time Password)
秘密鍵と認証回数を用いて計算し、OTPを生成する。認証回数をクライアントとサーバーで保持しており、認証回数が変わることで、OTPも変更となる。つまり、OTPを使用しなければ、OTPが変わることはない。

HOTPを求めるには以下の計算式を用いる。

```
HOTP(K, C) = Truncate(HMAC-SHA-1(K,C))
K... 秘密鍵
C... 変動する値 =>認証回数を用いることが多い
```

#### HOTPでのデータのやりとり
![TOTP_HOTP (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175906/49d3cf6d-6b35-52d4-0c5c-6d3b936b2d88.png)


### TOTP (Time-Based One-Time Password)
認証回数と秘密鍵を用いて、HOTPを計算した。RFCでは、認証回数を時間に変更して計算したものを、TOTPと定義している。つまり、計算式は下記のように整理される。

```
TOTP(K, T) = HOTP(K, C) 
HOTP(K, T) = Truncate(HMAC-SHA-1(K,T))
T = (Current Unix Time - T0) / X
X...TOTPを再生成するまでの時間
T0...数え始めの時間(Unix時間を使うのが通常なので、0がデフォルト)
```

#### TOTPでのデータのやりとり
![TOTP_HOTP.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175906/d92f9fd0-f8ba-7080-8ece-c34fa0d5a917.png)


## [参考]用語の整理
・HMAC(Hash-based Message Authentication Code)...ハッシュ関数を組み合わせたメッセージ認証符号の一つで、秘密鍵とメッセージ(データ)とハッシュ関数を用いてい計算する。
※組み合わせるハッシュ関数によって、HMAC-XXXと表示を分ける。

## [参考]RFCとは
```
RFCとは、インターネット技術の標準化などを行うIETF（Internet Engineering Task Force）が発行している、技術仕様などについての文書群。
TCP/IP関連のプロトコル（通信規約）の標準仕様などが記されたもので、インターネット上で公開されており誰でも入手・閲覧することができる。
```
## 参考URL
[「二要素認証」と「二段階認証」の違い](https://www.segunabe.com/2018/08/31/passclipnews180831/)
[RFC6238: TOTP: Time-Based One-Time Password Algorithm](https://tools.ietf.org/html/rfc6238)
[RFC4226:HOTP: An HMAC-Based One-Time Password Algorithm](https://tools.ietf.org/html/rfc4226)
[TOTPを実装する ](https://blog.web-apps.tech/implementing_totp/)
[RFC6238 Time-based One-time Password Algorithm (TOTP)の仕組みのメモ ](https://qiita.com/shrkw/items/426a7f1a59f42e0bd523)
[Time-based One-time Password algorithm](https://en.wikipedia.org/wiki/Time-based_One-time_Password_algorithm#Algorithm)
EncryptedSharedPreferences使ってみる

# 概要
Androidで暗号化して保存する仕組みを自前で実装するのが大変でしたが、JetpackのSecurityに`EncryptedSharedPreferences`という便利なものが登場したので触ってみました。
まだ2019/10月時点でalpha版なので使えるのは少し先になりそうです。
KeyStoreで色々と苦労したのでもっと早く出てきてほしかったです。

# 使ってみる

ライブラリを入れる。現時点で[1.0.0−alpha02](https://developer.android.com/jetpack/androidx/releases/security?hl=ja)です。

```build.gradle
def security_version = "1.0.0-alpha02"
implementation "androidx.security:security-crypto:$security_version"
```

保存する

```MainActivity.kt
val masterKeyAlias = MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC)
val preferences = EncryptedSharedPreferences.create(
    "secret_shared_prefs",
    masterKeyAlias,
    applicationContext,
    EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
    EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)

val editor = preferences.edit()
editor.putString("hoge", "hoge")
editor.apply()
```

SharedPreferencesと同じ実装なのですごく使いやすいです。

minSDK23以下で利用する場合はOS6系未満のときに独自に暗号化などするする必要があります。また、そのときは5系のOSが6にアップデートしたときにデータ移行なども考えないとデータが消えてしまいます（現時点でどれくらいアップデートユーザがいるかは不明ですが）

```AndroidManifestt.xml
 <uses-sdk tools:overrideLibrary="androidx.security" />
```

```MainActivity.kt
private fun getEncryptedSharedPreferences() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    val masterKeyAlias = MasterKeys.getOrCreate(MasterKeys.AES256_GCM_SPEC)
    EncryptedSharedPreferences.create(
        "secret_shared_prefs",
        masterKeyAlias,
        applicationContext,
        EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
        EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
    )
} else {
    // Android5系以下では利用できないので独自に暗号化が必要(ここでは単にSharedPreferencesを利用)
    getSharedPreferences(
        "secret_shared_prefs",
        Context.MODE_PRIVATE
    )
}

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    val preferences = getEncryptedSharedPreferences()
    val editor = preferences.edit()
    editor.putString("hoge", "hoge")
    editor.apply()
}
```

なお、バックアップでの利用は不可になります。

#リンク
[Developers](https://developer.android.com/reference/androidx/security/crypto/EncryptedSharedPreferences)
[動作確認用リポジトリ](https://github.com/rmorimot/EncryptedSharedPreferencesSample)
Amazon Photosで一括削除できなかったのでスクリプト書いた

## きっかけ
アマゾンのプライム会員になると、Amazon Photosというサービスを利用できます。

外部リンク : [Amazonプライムフォトが超最強！RAWも無制限にバックアップ可能](https://xn--pckxe.jp/prime-photo)

画像のみなら容量制限がなく、枚数制限もなく、劣化もしないという神サービスなのですが
画像枚数が一定枚数を超えると**一括削除できません**。

最初の方は1枚選ぶと「すべて選択」というボタンが出現していたのですが、3000枚を超えたあたり？で出なくなったようです。
1枚ずつ選んで消すなんて修行はしたくなかったので、スクリプト書きました。

画像を選択してスクロールしていくだけのスクリプトです。
ChromeのデベロッパーツールからConsoleを開いて(Ctrl + Shift + J)貼り付けて実行すると
3000枚まで自動選択されます。※一度に選択できる上限

削除できたらリロードして貼り付けて～を繰り返してください。

うまくいかない場合はtimeとかいじってみてください。

```javascript
const time = 0;
let selectCount = 0;
let ngCount = 0;
const id = setInterval( async () => {
    try {
        let tmp = 0;
        document.querySelectorAll('div[class*=selector]').forEach(element => {
            if(!element.className.includes("selected")) {
                element.click();
                tmp++;
                ngCount = 0;
            }
        });
        selectCount += tmp;
        
        if(tmp === 0) {
            if(ngCount > 10) {
                end(id);
            } else {
                ngCount++;
            }
        } else if(selectCount >= 3000) {
            end(id);
        }

        await new Promise(resolve => setTimeout(() => resolve(), time));
        
        scrollBy(0, 400);
    } catch (error) {
        end(id, false);
    }

})

const end = (id, click = true) => {
    if(click) {
        document.querySelector("button[class=trash]").click();
    }
    clearInterval(id);
}
```
【Rails】Slim基本文法【初心者】

#はじめに
Railsを使った開発で使うことになるであろうSlimについて簡潔にまとめてみました。

#Slimとは
Railsで使用できるRuby製のHTMLテンプレートエンジン。

#Slimのメリット
HTMLをよりシンプルに見やすく書くことができる。

#Slim導入
Slimジェネレータを提供してくれる`slim-rails`とERB形式のファイルをSlim形式に変換してくれる`html2slim`という２つのGemをインストール

```
gem 'slim-rails'
gem 'html2slim'
```

#Slimへ変換
すでにあるerb形式のファイルをSlim形式に変換するときは以下のコマンド

```
$ bundle exec erb2slim 変換したいerbファイルのパス --delete
```

#Slim基本文法
`<>`が不要、</div>や<% end %>等の閉じタグも不要
`<%= %>` → `=`
`<% %>` → `-`
id指定 → `#`
class指定 → `.`
コメント → `/`
改行 → `|`

#ERBとSlimの比較
最初にERB形式

```example.html
<div class="contents nav">
  <ul class="navbar-nvv">
    <% if current_user %>
      <li><%= link_to("MyPage", user_path, class: "nav-link") %></li>
    <% else %>
      <li><%= link_to("LogIn", login_path, class: "nav-link") %></li>
    <% end %>
  </ul>
  # これはコメントです
  <p id="greeting">Hello World!!</p>
</div>
```
次がSlim形式

```example.html.slim
.contents.nav
  ul.navbar-nav
    - if current_user
      li= link_to "MyPage", user_path, class: "nav-link"
    - else 
      li= link_to "LogIn", login_path, class: "nav-link"
  / これはコメントです
  p#greeting Hello World!!
```

#さいごに
かなりスッキリしましたね！
以上Slimの基本文法でした。
Chainerの「ディープラーニング入門」をやってみた。（第３章）

ディープラーニング入門、ようやく最後です。

第１章と第２章のメモは次の二つ。
https://qiita.com/iaintsorrykamio/items/8f378c194e58b977a4ef
https://qiita.com/iaintsorrykamio/items/ca10cb220903eea9b8f6


# Step3. ディープラーニング入門

## 13. ニューラルネットワークの基礎

ようやくニュートラルネットワークについて学んでいきます。

### ニューラルネットワークの基本的な流れ
前の層の出力値に線形変換（重回帰分析をベクトルで計算しているイメージ）と非線形変換（**活性化関数**による変換）を施すことを繰り返して出力層に計算結果を出す。

* **活性化関数の例**：従来、**シグモイド関数**が用いられてきたが、近年は**ReLU**（入力が負の時は出力が0、入力が生の時は出力はそのまま）が用いられている。

このようなやり方は変数のままで解を求めている（解析的に解いている）ので、複雑な関数の時には最適解を出すのが困難。

### ニューラルネットワークの訓練

そこで、繰り返し数値計算を行うことで最適解を求める方法が実用的には用いられている。そこで、目的関数（平均二条誤差とか交差エントロピー）の値を最小にするようなパラメータを求めることで、ニューラルネットワークを訓練する。その最適化アルゴリズムの一つが**勾配降下法**。

実際にはミニバッチ学習という方法で、データセットを分割して行う確率的勾配降下法が使用されている。

### 誤差逆伝播法

層数が多いニューラルネットワークでは、上のやり方では膨大な時間がかかってしまう。そのため出力側から入力側に向かう順電播で求めた勾配を、経路を逆にたどるようにして掛け合わせることで、パラメータについての目的関数を計算することができる。

だけでは、正直よくわからない（チュートリアルを読んでも雰囲気しかわからない）ので、要勉強箇所ですね。。。

## 14. Chainerの基礎

計算はChainerがやってくれるので、ひたすらコードを実行していきます。

## 15. Chainerの応用

Chainerの機能を活用して、結果を改善する方法を学びます。（一気に色々日本語で言われて混乱したが、とりあえず次に進む）

## 16. トレーナとエクステンション

**トレーナ**というのは訓練ループ、つまりミニバッチをネットワークに入れて、損失関数や勾配を計算したりする流れを段階ごとにまとめて、まとめたものを言うようです。

アップデータを使えば明示的にコードを書かずに済むし、エクステンションを使って訓練ループの中に付加的な処理を入れることができるということらしいです。

# まとめ

知らない単語もいっぱい出てくるし、ただこれだけを使ってディープラーニングを学ぶのは少し難しいなぁと個人的に思いました。
この記事をちまちま書いている間に、業務の方でディープラーニングを学ぶ機会があって、オライリーの『ゼロから作るDeep Learning』を読んだりしたので、後半なんとか持ち直して理解できるようになったかなぁという感じです。

きっかけとしては良い教材だと思うので、ここで挫けずにいろいろ学んでいくしかないですね、結局。
Pythonクローリング＆スクレイピング 第1章まとめ

#はじめに
現在作りたいと思っているWebアプリがあって、そのためにはある分野のWeb上のデータを自動で収集してくる必要があるため、「Pythonクローリング＆スクレイピング［増補改訂版］
―データ収集・解析のための実践開発ガイドー」加藤耕太・著を購入した。

自分はアウトプット不精なのでこの本を読み進めながら内容をまとめてQiitaに公開していくことにする。

並行してFlaskフレームワークでのWebアプリ開発についてもアウトプットしていけたらと考えている。

サブPCを購入したのでサンプルプログラムはSourceTreeでも使ってメインとサブで共有して行く予定。

#第1章 クローリング・スクレイピングとは何か
##クローラ
Web上のページの情報を取得するためプログラム。
高速でデータを取得することができるので、使用の際は相手側のサーバへの負荷を考えないといけない。
##クローリング
>Webページのハイパーリンクをたどって次々にWebページをダウンロードする作業。

##スクレイピング
>ダウンロードしたWebページから必要な情報を抜き出す作業。



##Linuxの環境構築
といった概要の説明があったところで、Pythonを使ったクローリング・スクレイピングの前に、Wgetというツールを使ったデータの取得を行うため、Linuxの環境構築が必要となるのだが
注釈に

>Windows Subsystem for Linux（WSL）を使っている方は、これでUbuntu 18.04を動かしても良いでしょう。ただし本書では検証を行っていないため不具合などが発生してもサポートできません。

とありましたので**じゃあWSLでやってやるか**、ということでMicrosoft Storeからダウンロード。
![無題.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253705/8d1af9de-85a3-adff-5526-34f6811e095c.png)
↑WSLでUbuntu18.04を動かしている様子

こちらのサイトを参考にして日本語化。結構時間がかかるので注意。
[WSLのUbuntu環境を日本語化する：Tech TIPS](https://www.atmarkit.co.jp/ait/articles/1806/28/news043.html)

##Wgetでクローリング
といったところでWgetを使ってWebサイトをクローリングする項目へ
まず最初はこの本の版元の技術評論社からロゴ画像とトップページのデータを取得するというもの。
`$ wget <URL>`
で取得が可能

取得データについては↓
[WindowsからLinuxファイルへのアクセスが可能に ～「Windows 10 19H1」におけるWSLの改善](https://forest.watch.impress.co.jp/docs/news/1170221.html)
を参考にし `explorer.exe .`コマンドでカレントディレクトリをWindowsのエクスプローラーで開いて、きちんと保存されていることを確認。

<img width="1128" alt="qiita02.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253705/f8787771-71a5-d29b-019b-860bc7ed1e42.png">


`wget -r --no-parent -w 1 -l 1 --restrict-file-names=nocontrol <URL>`
でページ内のリンクを辿って再帰的にクローリング
オプションの意味は以下の通り

- -rオプション→再帰的なクローリングの指定
- -lオプション→リンクをたどる深さ
- -w→ダウンロードをする間隔(秒)
- --no-parent → 親ディレクトリをクローリングしない
- --restrict-file-names=nocontrol→URLに日本語が含まれる
場合に、日本語のファイル名で保存

` sudo apt install tree`
して
`tree <URL>`
で↑でクローリングしたサイトのディレクトリ構造を表示
実際のサイトと比べるときちんとリンク1つ辿ってクローリングされてることがわかる

##Unixコマンドの基礎知識

標準ストリーム→標準入力・標準出力・標準エラー出力
パイプ(|)→ `〇〇コマンド XXXX | △△コマンド XXXX` 〇〇コマンドの標準出力を△△コマンドの標準入力に渡している例

- catコマンド→引数で与えたファイルを出力する
    - `cat ファイル名`

- grepコマンド→引数で与えた文字列や正規表現にマッチする行を抜き出す
    - 例：`cat ファイル名 | grep 文字列or正規表現パターン`→catの引数のファイルからgrepの引数にマッチしたものを出力する
 

- cutコマンド→指定した文字列で区切られたテキストの列の一部を取り出す
    - 例：`cat ファイル名 | cut -d , -f 1,2`→catの引数のファイルから , で区切られた1，2列を出力する

- sedコマンド→引数で検索する文字列と置換する文字列を指定すると、前者を後者に置き換えて出力する
    - 例:` cat ファイル | sed 's/A/B/g'`→catの引数のファイルのAをBに置き換えて出力する
gは一行で複数マッチしてもすべて置き換えるというオプション

- wcコマンド→文字数や行数を数えるコマンド
    - 例:`cat ファイル名 | wc -l` →ファイルの行数を数える(-lオプション) 

##ここまでのまとめ
Unixコマンドだけでもクローリング・スクレイピングができるが、複雑なスクレイピングに対応するには汎用的なプログラミング言語の力が必要…

というところでいよいよPythonを使ったクローリング・スクレイピングへ
AWS Amplify ConsoleでSPAのときのリダイレクト設定

# 問題点

SPAサイトをAWS Amplify Consoleで自動デプロイしようとしていたときにブラウザから特定のサイトにアクセスするとき、 `403 Access dennied`になっていたのでその対策を調べた結果を載せておく

# 原因

SPAのページ遷移はサーバーリクエストをせずにHTML5のhistory.pushState()で遷移される。そのため、ブラウザからのアクセス（サーバリクエスト）があった場合はindex.htmlに遷移するように設定する必要がある

# 解決策

Amplifyのメニューの`rewrites and redirects`から以下を設定

![スクリーンショット 2019-10-01 23.10.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134845/b82c1951-bba2-8d83-8d53-fd179b0b0eea.png)

# 参考
https://docs.aws.amazon.com/ja_jp/amplify/latest/userguide/redirects.html
M5StickVをデジカメにしてみた。

## きっかけ
先日、北海道森町の集まりで、某若狭さんからM5StickVを紹介していただく。
本来は機械学習のデータを使った画像認識向けのもののようだけど(QVGA(320×240ドット)とかで解像度低いし)、
ただ、色々調べてみたら、「プログラミングできるデジカメ」として可能性がありそうだったので、買ってみた。

- カメラついてる
- デフォルトでボタンついてる (若狭さんにM5Cameraを推奨されたけど、~~そっちにはデフォでないよねたぶん~~ Bボタンはあるっぽい？)
- (micro)SDカードスロットついてる
- そして安価(￥3,000くらい)
- プログラミングできる

= 単体で動く！(RasPi+WebCamとか用意しなくてもいい！)
ということで、かなり興奮していたんですが、これだけでなく

- LEDフラッシュがついている
- バッテリーもついている
- 拡張性も高い

ときたもんだ。解像度以外は完全にカメラ向きだろうと。

2012年くらいにIKEAが出していた段ボールデジカメKNÄPPAを出したり https://www.youtube.com/watch?v=OGGFuD5n5go 、
同時期に国内メーカーでライブラリを公開するのをウリにしたカメラを出したり(メーカーと機種名を忘れた...検索しても全然出てこない...ソニーでいうところの「レンズスタイルカメラ」ですね)、
今年2019年に入ってからは、Canonが海外でしか使えなかったEDSDK（EOS Digital Software Development Kit）を日本でも使えるようにしたり、
結構ものづくり欲を高めるカメラを出してきたように思えます。どうもあまり流行っている感じはしませんが。。。

元々、子供たちにプログラミングを教える機会もありそうだったので、教材としてもいいかなと。

## まずはどんなものを作るか

- 撮影前にプレビュー画像が出ている
- ボタン押す
- 画像が保存される

まずはシンプルにこれを目指します。

## 参考
以下のページを参考にしています。

- maixpy 覚書(SIOSALTさん) http://ssj.siosalt.tokyo/?p=72
    - 写真の撮り方はこちら
- Wi-FiがないM5StickVを、M5StickCと繋ぎLINEに投稿してみるまでの手順(@aNo研 nnnさん) https://qiita.com/nnn112358/items/5efd926fea20cd6c2c43
    - ボタンの使い方はこちら

あとはOpenMVとか、MicroPython、MaixPy関連の情報が参考になるようです。

- M5StickV上で動くMicroPythonのコマンド情報をまとめている方がいらっしゃいましたので、今後こちらも参考にします。  https://qiita.com/Lathe/items/7fbfccafb879de4bf11e

## 作り方
microSDカード直下に以下のboot.pyファイルを入れ、そのカードをM5StickV本体に差し込んで、USB-Cケーブルで電源と繋げば勝手に起動します。

## 実際のコード
上記URLにあるSIOSALTさんのコードをベースに、@aNo研 nnnさんのボタン操作の部分を追加してみました。（両者ともコード改造の上転載していいかまだ許可取り中ですが、暫定的に載せてます。まずかったら引っ込めますので…）
ほぼそれぞれの使えるところを使わせてもらった感じです。そういやボタンの省略形ってbtnでなくてbutなのかー。
~~で、 結局Aボタンを押しても撮影出来てません。何故なんだ。~~ 解決しました。詳細はコード内コメントにて

```python3:(boot.py)
import sensor
import image
import lcd
import time
from Maix import GPIO # ボタン入力で使います
from fpioa_manager import fm, board_info # @midori564 さんからご指摘いただきましたので1行追加。(何故か私のものは無くても動く→原因解説しているソースありました。 https://maixpy.sipeed.com/en/libs/builtin_py/ )

#タイマー初期設定
clock = time.clock()

#LCD初期設定
lcd.init()
lcd.direction(lcd.YX_LRUD) # デフォルトだとLCD上下逆のため設定。YX:横長 LR 左右順 UD上下順

#カメラ初期設定
sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA)
sensor.set_hmirror(0) # デフォルトだとカメラがミラーに設定されているため
sensor.run(1)

#保存ファイル名初期設定
i = 0 #ファイル名用

#シャッターボタン(ButtonA)初期設定
fm.register(board_info.BUTTON_A, fm.fpioa.GPIO1)
but_a = GPIO(GPIO.GPIO1, GPIO.IN, GPIO.PULL_UP) # GPIO36を指定すると止まってしまったが、桃治トイレBot(Twitter:@momojitoiletbot)さんにfm.register()の設定をした上でGPIO1を使うとうまくいく旨教えてもらい解決しました！

#画面表示
while True:
    clock.tick()
    img = sensor.snapshot()
    lcd.display(img)

#シャッターボタンを押したら
    if but_a.value() == 0:

#画像をJPEG形式に保存
        filename = "/sd/{0:0=8}.jpg".format(i) # iの数値からファイル名を生成。00000000.jpg から連番
        img.save(filename) # ファイル名の初期設定値(filename)で写真を保存
        i += 1 # ファイル名の数値を1つ増やす
        lcd.draw_string(10,20,filename) # ファイル名を表示
        time.sleep(1.0) # 保存した写真をちょっとだけ固定表示
```

## 今後どういったものを作りたいか
作っている本人がプログラミング初心者に近いので、
デジカメの基本機能・カスタマイズ要素として、

- 現在、起動ごとにファイル名がリセット・ファイル上書きしてしまうので、その改善
- 起動画面・起動音
- 動作音・シャッター音
- ファイル名を日時分秒プラスαで表現
- Exifデータ(日時場所カメラの情報などのメタデータ)の埋め込み
- セルフタイマー
- 画面回転(縦/横)
- 設定画面

M5StickVの本来の能力を引き出すために

- スマイルシャッター
- 監視カメラ機能(人だけを撮影する)

などもやっていければいいなあと思いました。
xml

## 対象

```ruby

<nicovideo_thumb_response status="ok">
  <thumb>
    <video_id>sm2959233</video_id>
    <title>ニコニコ動画流星群</title>
    <description>
ニコニコ動画で人気のある名曲(極一部、趣味)を繋いでひとつの曲にしてみました(約4回目)。mylist/1535765user/145217
</description>
    <thumbnail_url>http://tn.smilevideo.jp/smile?i=2959233</thumbnail_url>
    <first_retrieve>2008-04-11T05:05:52+09:00</first_retrieve>
    <length>14:05</length>
    <movie_type>mp4</movie_type>
    <size_high>40265605</size_high>
    <size_low>38847215</size_low>
    <view_counter>6396439</view_counter>
    <comment_num>1450707</comment_num>
    <mylist_counter>108509</mylist_counter>
    <last_res_body>
これ見ると平成最後が やっぱりニコニコ最高 いくぞ! 平成 ★=ー おっくせんまん!おっ おっくせんまん!おっ おっくせんまん!おっ おっくせんまん!おっ おっくせんまん 鈍痛☆鈍痛☆...
</last_res_body>
    <watch_url>https://www.nicovideo.jp/watch/sm2959233</watch_url>
    <thumb_type>video</thumb_type>
    <embeddable>1</embeddable>
    <no_live_play>0</no_live_play>
    <tags domain="jp">
      <tag category="1" lock="1">音楽</tag>
      <tag lock="1">アレンジ</tag>
      <tag lock="1">ニコニコ動画流星群</tag>
      <tag lock="1">空気の読めるWMP</tag>
      <tag>ニコニコメドレーシリーズ</tag>
      <tag>600万再生</tag>
      <tag>simoyuki</tag>
      <tag>SP1時代の奇才</tag>
      <tag>ありがとう</tag>
      <tag>原点にして頂点</tag>
      <tag>重要ニコニコ文化財</tag>
    </tags>
    <genre>音楽・サウンド</genre>
    <user_id>145217</user_id>
    <user_nickname>しも</user_nickname>
    <user_icon_url>
https://secure-dcdn.cdn.nimg.jp/nicoaccount/usericon/defaults/blank_s.jpg
</user_icon_url>
  </thumb>
</nicovideo_thumb_response>
```

## ソース

```
require "rexml/document"

require "open-uri"
url = "http://ext.nicovideo.jp/api/getthumbinfo/sm2959233"
doc = REXML::Document.new(open(url).read)


p doc.elements

doc.elements.each('//nicovideo_thumb_response/thumb/tags/tag') do |elm|
  
    p elm.text
    p elm.attributes 
    
  end
```

## 操作

- タグベースで指定する
- /区切り
- textメソッド
- 属性
```
require "rexml/document"


xml = <<-EOS
  <root>
    <a name="a1">
      <b>かぼちゃ</b>
      <b>はくさい</b>
      <b>にんじん</b>
      <c>きゃべつ</c>
    </a>
    <a name="a1">
      <b>牛肉</b>
      <b>豚肉</b>
    </a>
    <a name="a3" price="1000"></a>
  </root>
EOS

doc = REXML::Document.new(xml)

p doc.elements
p doc.elements['root/a[2]/b'].text

p doc.elements
p doc.elements['root/a[3]'].attributes['price']
```



# 記事

- xml 作り方
https://uxmilk.jp/25936
- xml 操作
https://thr3a.hatenablog.com/entry/20190316/1552735266
【これであなたも情報通！！】転職活動透明化らぼ x kiitokに参加してきました #転職透明化らぼ #kiitok_meetup

面白そうなイベントに参加してきました。

「**転職活動の透明化！！**」

なんだかすごそうです。スッケスケにしようというわけです。

公式はこちら↓
https://rtlabo.connpass.com/event/142944/

透明化というのは、ここでは「**求職者側と採用側の情報格差を無くして、互いに幸せになろう！**」という意味のようです。いくつかシリーズとして開催されるらしく、今回は「スタートアップ企業の見分け方」というテーマで開催されました。

いいですね、とても自分の考え方に合っています。自分は、情報格差の是正、つまり、適切な情報共有が仕事をスムーズに回すためには一番大事だと信じて疑いません。

そんな感じで、自分の信念にとてもマッチした今回のイベント。さて、参加してみてどうだったでしょうか？

以下の項目ごとに、自分なりに振り返ってみました。

- なにが良かった
- なぜ良かった
- なにを課題と感じた
- 次にどうしたいか


## なにが良かった
転職活動のときに、採用側にどんな質問をすれば良いかわかったことです。たとえば、どれくらいの市場を獲得したいのかといったような質問は、求職者側では思いつかない質問だと思います。

## なぜ良かった
面接はどうしても形式的になりがちなので、質問者の意図がわかると面接がただの作業にならず、互いに意味のある有意義な時間になると思ったからです。

採用側が求職者に対してする質問は、人を採用することを通して自社を良くしたいという意図が表れるものだと思います。人の想いに触れると、言葉にできない充実感を得られるときがあります。

## 何を課題と感じた
自分が採用側に質問するときに、相手を試してやろうという意図から、マウント的な質問や態度を取ってしまう可能性があるかもしれないと思いました。また、「採用側にする質問あるある」のように、新しくフォーマット化してしまうと、形骸化する可能性があるかもしれないと思いました。

## 次にどうしたいか
採用側の意図を踏まえつつ、マウントのような強い態度でもなく、かといって卑屈にもならず、互いのニーズと想いを開示してゆけるような面接にしたいと思いました。