OmniAICreator/Qiita-1.07M huggingface dataset:
リモート会議で使えるホワイトボードツール「miro」を触ってみた

この記事は、株式会社富士通システムズウェブテクノロジーが企画する「[いのべこ夏休みアドベントカレンダー 2020](https://qiita.com/jugemsan/items/5761773308fb1df0c23a)」の6日目の記事です。
 （お約束）本記事の掲載内容は私自身の見解であり、所属する組織を代表するものではありません。

#はじめに
リモート会議でブレインストーミング（ブレスト）等をするにあたり、リモートで付箋やホワイトボードを使ってやりたいなということで、数あるツールの中で今回は「**miro**」というツールを触ってみます。

#「miro」とは
[Miro | Free Online Collaborative Whiteboard Platform](https://miro.com/)

トップページの文を雑翻訳すると下記のような感じです。
一言でいえば「オンラインで使えるホワイトボードツール」です。

>ミロはリモートと分散チームのために設計されたコラボレーティブなオンラインホワイトボードプラットフォームです

##利用方法について
トップページの右上「Sign up free」から名前、メールアドレス、パスワードを設定することで利用開始できます。
また、Google、Facebook、Slack、Office365のアカウントでも利用開始できます。
<img width="800" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531905/40925ffb-e9c4-5dad-9df7-cb4a33c171d4.png">

アカウント作成後はチームの情報等を入力することでメインページが開きます。

##料金体系
https://miro.com/pricing/
<img width="800" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531905/49a87ae9-b1cf-6520-f17b-a89b2ec2e01e.png">

基本的な機能であれば無料で使えそうです。
今回は無料版を利用します。いずれ、各プランの内容について細かく調べたいと思います。
（今回はあまり触れません）


#機能の確認
メインページです。
<img width="800" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531905/08fe60ad-2fb4-9aac-08d8-11da019f7a46.png">

「New board」を選択すると下記のようにテンプレートを選択する画面が出ます。
色々なテーマのテンプレートがあり、ブレストだけでなく分析にも使えそうです。
今回は一旦使える機能を見たいので右上の×を選択し、素のホワイトボードを開きます。

<img width="800" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531905/dbd79aea-7106-8757-536b-46a62bca6cb3.png">
<img width="800" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531905/1bb8052a-164f-3178-6cf9-2e74af4c4f84.png">

##手書きペン
まずホワイトボードとして基本の機能、ペンのツールです。
太さや色を変えれるだけでなく、書いた後の線の移動もできます。（アナログではできないことなので便利！！）
<img width="800" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531905/cf2aea46-f6ec-dfd6-a341-72b6e5e8f1e9.png">

また、Smart drawingをONにすることで、下記のように手書きの図形を自動で成形してくれます。

<img width="300" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531905/2f603697-3df8-06a1-1139-1d243ba1d5f9.png">  <img width="300" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531905/ddd3ccda-b5db-2909-104f-d218151f3526.png">

下記一覧が自動成型をしてくれる図形の一覧で、図形から図形へ線でつなぐと矢印化してくれるものもあり、マウスでの書きづらさをかなり補完してくれる感じがします。
<img width="800" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531905/2a44d5e7-a7da-3591-f6fa-f9719fc3c6fd.png">


##付箋
付箋も貼れます。サイズ変更や色変更が可能です。
付箋にタグ付けや絵文字をつけることもできます。

<img width="800" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531905/131e0dda-f6fe-02c8-3814-e57dbd564878.png">

##その他描画機能
図形やテキストも描画できます。また、それらをグループ化することもできるようです。
基本的に描画したものや付箋は移動できますが、逆に移動させたくないものは移動のロックもできます。

##同時編集に関して
無料の機能でも**同時編集は可能**です。ただし、参加者はサインインの必要があります。
無料バージョンではゲストユーザは参照はできますが編集はできません。
編集可能なゲストユーザを招待したい場合は有料化することで可能になります。


#最後に
・ボードに自由に手書きができる
・付箋がはれて移動もできる
・同時に編集ができる
上記の最低限ほしいと思っていた機能は満たしていました。（アナログのホワイトボードより便利すぎるほどに）

今回は自分ひとりで触るのにとどまりましたが、
紹介しきれなかった機能もあるので、今度は複数人で実際に使ってみたうえでの評価もしてみたいと考えています。
CGIとは

#CGIとは

- **C**ommon **G**ateway **I**nterfaceの略で、Webサーバーがクライアントからの要求に応じてサーバーサイドスクリプトを起動するための仕組みのこと。

- 通常、Webサーバーはクライアントからのリクエストを受けると対応するコンテンツを返信するが、あらかじめCGI用のプログラム`(CGIプログラム)`として定義されたコンテンツについてはそのままクライアントに返信せず、それをWebサーバー上で実行したとこの結果を返信する。


#データの渡し方は？

- **コマンドライン引数渡し**・・・データをCGIプログラムに直接渡す方法


- **パス渡し**・・・データをリクエストURLの階層構造に含めて渡す方法
データベースに存在しないIDがURLに入力された場合の処理

※いただいたコメントを参考に内容を修正しました。
元の記事は下部にありますが、ページの表示速度の観点から非推奨となります。

## 本編
データベースに登録されるデータにはプライマリキーのIDが付けられますが、そのデータを削除した場合はそのIDも存在しなくなります。
商品の詳細ページや会員の詳細ページのURLには`:id`があり、この数値を変更することでその数値のIDに該当する詳細ページが表示されますが、もし、存在しないIDが入力された場合には

```
ActiveRecord::RecordNotFound
Couldn't find モデル名 with 'id'=入力された数値
```

というエラーが発生します。

今回行う処理は「存在するIDなら表示し、存在しなければリダイレクトを行う」という物です。

## 環境
Ruby 2.5.7
Rails 5.2.4

## 処理の手順
今回はapplication_controllerにアクションを定義し、リダイレクトさせたい各コントローラーでそのアクションをbefor_actionとして設定する方法で進めていきます。
状況としては商品の詳細ページでURLに商品IDを入力した時の処理と仮定します。

```ruby:application_controller.rb
class ApplicationController < ActionController::Base

  def exist_item?
    unless Item.find_by(:id params[:id])
      redirect_to root_path
    end
  end

```

unless文を使い、条件式が`false`の場合に中の処理を行います。
今回の場合だと、find_byメソッドを使ってItemのIDの中から入力された数値（`params[:id]`）を探してヒットするかどうかを条件にし、ヒットしなかった場合（=`false`）は中の処理である`redirect_to root_path`が実行されると言うものです。

次に商品のコントローラー内に先ほどapplication_controller.rbで定義した`exist?`を`before_action`に設定します。

```ruby:items_controller.rb
class ItemsController < ApplicationController
 
  # URLに:idを含むアクションを指定
  before_action :exist_item?, only[:show, :edit, :update, :destroy]
  ...

  def show
    ...
  end

  ...

end
```

この時にオプションの`only:`で指定するアクションは、表示を伴う`:show`や`:edit`だけでもいいのですが、`:update`や`:destroy`も一応追加しておきます。
（なくてもいいですが、フォームで無理やりパラメータを変更して送信された場合に冒頭のエラーが表示されます。）
これで各アクションの前に、入力されたitemのIDが存在するかどうかを検証するアクション(`exist_item?`)が実行されます。

## まとめ
修正前の弱点であった表示速度が大幅に改善される見込みです。

今後もいただいたコメントは随時検証して行きたいと思います！

最後まで読んでいただきありがとうございました！


なお修正前の記事は以下になりますが、非推奨です。

## 処理の手順（※非推奨）
今回はapplication_controllerにアクションを定義し、リダイレクトさせたい各コントローラーでそのアクションをbefor_actionとして設定する方法で進めていきます。
状況としては商品の詳細ページでURLに商品IDを入力した時の処理と仮定します。

```ruby:application_controller.rb
class ApplicationController < ActionController::Base

  def exist?
    Item.all.each do |item|
      if item.id == params[:id].to_i
        return
      end
    end
    redirect_to root_path
  end

end

```

まず、each文を使って商品のテーブルから全ての商品情報を順番に取得します。
eachの中では１巡ごとにそのitemの`id`が入力された数値と同じかどうかを検証します。
（`.to_i`としているのは、入力された数値は文字列型として認識されているので`item.id`と同じ整数型に揃える必要があるからです。

```
item.id = 0
params[:id] = "0"
if item.id == params[:id] => false
```
）

each文の中でitemのIDと入力された数値（`params[:id]`）が一致した場合、`if`の中の処理、`return`を行います。
`return`が行われると、それいこうのプログラムはスキップし、アクションを終了させるので、`redirect_to root_path`は実行されません。
逆に、each文が終了し、その中で入力された数値とitemのIDが一度も一致しなかった場合は、その後に続く`redirect_to root_path`が実行され、任意のページにリダイレクトを行います。

```ruby:items_controller.rb
class ItemsController < ApplicationController
 
  # URLに:idを含むアクションを指定
  before_action :exist?, only[:show, :edit, :update, :destroy]
  ...

  def show
    ...
  end

  ...

end
```

次に商品のコントローラー内に先ほどapplication_controller.rbで定義した`exist?`を`before_action`に設定します。
この時にオプションの`only:`で指定するアクションは、表示を伴う`:show`や`:edit`だけでもいいのですが、`:update`や`:destroy`も一応追加しておきます。
（なくてもいいですが、フォームで無理やりパラメータを変更して送信された場合に冒頭のエラーが表示されます。）
これで各アクションの前に、入力されたitemのIDが存在するかどうかを検証するアクション(`exist?`)が実行されます。

## 弱点
この方法はレコードの数（今回で言うところの商品数）が多くなればなるほど処理に時間がかかるようになります。
商品が1,000個あればeach文はMAX1,000回回ることになるので、詳細ページなどの表示がかなり重くなってしまいます。

他にいいやり方があるはずなので、見つかり次第更新します┏○
コメント等でも教えていただけると幸いです！
CocoaPods Warning: ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES の対処法

`pod install` でいつものごとくライブラリをインストールすると下記のような警告がでました。


```
[!] The `Hoge [Debug]` target overrides the `ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES` build setting defined in `Pods/Target Support Files/Pods-Hoge/Pods-Hoge.debug.xcconfig'. This can lead to problems with the CocoaPods installation
    - Use the `$(inherited)` flag, or
    - Remove the build settings from the target.
```

警告文を見てみると、どうやら Target で指定してある `ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES` が `Pods-Hoge.debug.xcconfig`(Pods) で設定した値を上書きするので、うまくインストールできなかもしれないとのこと。

### 解決方法

`Target` > `Build Settings` > `ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES` を選択して `Delete` をクリックして設定を削除します。再度 `pod install` すると問題なく、インストールが完了します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/292456/53a86e74-4c5f-aaf9-a851-afc40940363a.png)


[CocoaPods](https://github.com/CocoaPods/CocoaPods/pull/5732) で対応されているもので、Xcode 8 以降で、[空の Framework](https://github.com/CocoaPods/CocoaPods/issues/4203) が含まれる問題を解決するためのようです。ライブラリ単位でこの警告がでているのかは不明なので、詳細がわかり次第追記したいと思います。
[初学者の備忘録]仮想DOMとは。なぜReactを使うのか。

# 執筆背景
現在、就職活動用のポートフォリオを作成しています。
前回の記事では、`React`と`Django`を組み合わせるための調べた結果を書きました。
今回は、前回の続き?といいますか、宣言通り仮想DOMについて分かったことを、不確かだとは思いますがアウトプットしていきます。

# リアルDOMとは
「仮想DOMとは」と言う前に、まずは(リアル)DOMの説明から始めないといけません。
参考にしたサイトは[こちら](https://employment.en-japan.com/engineerhub/entry/2020/02/18/103000)です。
>DOMとはDocument Object Modelの略で、簡単に言うとJavaScriptからHTMLドキュメントを操作するためのAPI（インターフェイス）です

つまり、DOMのおかげでクリック時のイベントを操作したりHTMLドキュメントの操作をできるというものです。
そして、WebブラウザはHTMLの各要素をツリー状に管理していて、これを__DOMツリー__といいます。

WebブラウザーがDOMツリーを持っているのは、HTML要素を管理し、レンダリングするためです。
一方で、レンダリングというのはブラウザにとってコストの高い処理だという側面があります(ここの詳しいロジックはリンク先の記事でご覧ください)。

となれば、そのコストを抑えたいと考えるのが当然。そして、その効果的な方法は無駄なレンダリングを省くこと。

ここで__仮想DOM__が登場します。

# 仮想DOMとは

特徴は以下の通りです(他にもあると思いますが、勉強不足で申し訳ありません)。

1. __ブラウザのDOMツリーをJavaScriptのオブジェクトで表現__
2. __仮想DOMで差分を検知し、その差分のみをリアルDOMへ反映する__

差分のみをリアルDOMに反映するために、変更が最小限に、結果的にレンダリングのコストも抑えられるということです。
注意点として、JavaScriptフレームワークである`React`等も最終的にはリアルDOMを操作しています。また、`JQuery`はリアルDOMを操作するため、仮想DOMとリアルDOMの関係を崩してしまいます。なので、`JQuery`とJavaScriptフレームワークの愛称はよくないようです(半分は自分への呼びかけです笑)。

また、仮想DOM(厳密には仮想DOMを用いたフレームワーク)は開発にもメリットをもたらします。
>UIとロジックを分離できる=「HTMLのどの要素を取得し、書き換えるか」をJavaScript側で把握しなくてよい
最終的なViewの状態が想像しやすい
状態を一元管理できる
DOMの書き換えが最小限になる
スコープが狭くなることで「考えること」が減る

# まとめ
__1.DOMはJavaScriptがHTMLを操作するためのもの__
__2.WebはレンダリングをするためにHTML要素をツリー状に管理__
__3.仮想DOMは変更の差分のみを検出してレンダリングの負担を最小限にするためのもの__
__4.仮想DOMのフレームワークは、開発にも多大な恩恵をもたらしてくれる__

以上が、調べた中で私が分かったことです。
間違えていることや、これも知っておいた方がいい、感想などお待ちしております。

拙い、勉強不足が感じられる記事だとは思いますが、ご覧いただき誠にありがとうございました。
ExcelVBAのみでPDFファイルのページ数を取得する


## はじめに
仕事でPDFファイルを扱うことは多々あります。
ですが、AcrobatReaderのみの環境でVBAから参照可能なAcroPDFではPDFファイルのページ数は取得できません。

## 目的
VBAでPDFのページ数を調べたい。

## 処理フロー
１、PDFファイルをADODB.Streamからテキストファイルとして読み込み
２、読み込んだソースコードから「/Count n」を探す
３、nを数値に変換（＝総ページ数）

<details><summary>**サンプルコード**</summary><div>

```vb
Function getPDFPageCount(ByVal path As String) As Long
On Error GoTo Error1

Dim PDFSourceText As String
With CreateObject("ADODB.Stream")
    .Charset = "UTF-8"
    .Open
    .LoadFromFile path
    PDFSourceText = .ReadText
    .Close
End With

Dim RegExpMatchCollection As Object
Dim RegExpMatch As Object
With CreateObject("VBScript.RegExp")
    .Pattern = "(/Count )\d*"
    .MultiLine = True
    Set RegExpMatchCollection = .Execute(PDFSourceText)
    Set RegExpMatch = RegExpMatchCollection.Item(0)
    getPDFPageCount = CLng(Val(Mid(RegExpMatch.value, 8)))
End With

Exit Function

Error1:

getPDFPageCount = CLng(-1)

End Function

```

</div>

## 解説
PDFファイルの構造上、「/Count 」はソーステキストに1回しか出現しないこと、通常表示される文字列はStreamオブジェクト内に圧縮されているため正規表現にマッチしないことからページ数の抜き出しが可能となっています。

## 補足
「/Count 」の他にも構文解析で読み取れる情報はありそう。
「/Mediabox 」で用紙サイズとか。

## 最後に
ファイルのページ数は結構使い道があるだけにAcroPDFで参照できない（させない）のも納得。
[javascript]jQueryを使う方法

#jQueryとは
jQuery（ジェイクエリー）は、JavaScriptライブラリです。　　　　　
JavaScriptライブラリとは、JavaScriptの処理を簡単に扱えるようにしたプログラムです。

ほとんどのWEBサイトやWEBアプリケーションで使用されています。
例えば、WEBサイトのトップページの画像が横にスライドされたりするのを見たことがあると思いますが、あれもjQueryで実装されています。あとは、SNSなどのいいね機能などです。ハートマークを押すと、ハートに色がついたりするのもjQueryです。

#jQueryを使う準備をする
jQueryを使うには外部ファイルとして、jQueryを読み込む必要があるため、
jQueryの公式サイトからファイルをダウンロードする必要があります。
【jQuery公式サイト】
https://jquery.com/

1.左にあるDownloadをクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/681053/a1155b13-9440-de43-553a-78152bf0b6d8.png)

2.一番上のDownload the compressed〜をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/681053/dbbf7cc6-a7a8-90f4-292c-a71d9695cfbb.png)

3.ダウンロードしたファイルをjsファイルがあるフォルダにコピー
ダウンロードしたファイルを「jquery.min.js」というファイル名に変更して、作成中のアプリケーション内のフォルダへ保存します。

4.htmlファイルにjQueryを読み込ませる
htmlファイルに以下の記述を加えて、jQueryファイルを読み込むようにします。

```index.html
<script src="jquery.min.js"></script>
```

これでjQueryを使う準備はできました。
Synapse SQLプールのデータの分散配置

#Synapse SQLプールは60のディストリビューションが存在する
Azure Synapse Analytics SQLプールには60のディストリビューションという物理的なディスクが存在します。
Synapse SQLプールに投入されるデータはこの60のディストリビューションに様々な方法で分散されて配置されることになります。

実際のデータをどのように分散配置するのかは指定することが可能で、テーブルの定義をするときに分散方法（ディストリビューション）を指定します。

#３つの分散方法
Synapse SQLプールでは３つの分散方法が存在しています。

* ラウンドロビン分散
* ハッシュ分散
* レプリケート分散

ここではそれぞれの特長について簡単に記載します。

##ラウンドロビン分散
全てのディストリビューションに均一にデータが配置されます。デフォルトがこの分散方式であり、テーブル作成時に何も指定しない場合は、この分散方式が指定されます。

指定方法は以下の通りです。

**CREATE TABLE (…)**
**WITH (DISTRIBUTION = ROUND_ROBIN)**

作成例

```SQL
CREATE TABLE ORDERS  (
    O_ORDERKEY       INTEGER NOT NULL,
    O_CUSTKEY        INTEGER NOT NULL,
    O_ORDERSTATUS    CHAR(1) NOT NULL,
    O_TOTALPRICE     DECIMAL(15,2) NOT NULL,
    O_ORDERDATE      DATE NOT NULL,
    O_ORDERPRIORITY  CHAR(15) NOT NULL,
    O_CLERK          CHAR(15) NOT NULL,
    O_SHIPPRIORITY   INTEGER NOT NULL,
    O_COMMENT        VARCHAR(79) NOT NULL
)
WITH
(
	DISTRIBUTION = ROUND_ROBIN
);
```

##ハッシュ分散
ハッシュ分散は、ハッシュ分散アルゴリズムを使用してテーブルに投入されるデータを60のディストリビューションへ分散し格納する方式です。テーブルにはいくつもカラムが存在するかと思いますが、そのうちのどれか１つのカラムを`HASH KEY`として指定する事で、そのカラムの値からハッシュ値を計算し、データをどこのストレージへ配置するのか決定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/697647/fbc00f4f-b1c7-d6c8-21f9-3e9d0b5f38dc.png)


なので、この分散方式を指定することで、同じ値のデータは同じストレージに配置されることになります。

指定方法は以下の通りです。
**CREATE TABLE (…)**
**WITH (DISTRIBUTION = HASH)**

作成例

```SQL
CREATE TABLE ORDERS  (
	O_ORDERKEY       INTEGER NOT NULL,
    O_CUSTKEY        INTEGER NOT NULL,
    O_ORDERSTATUS    CHAR(1) NOT NULL,
    O_TOTALPRICE     DECIMAL(15,2) NOT NULL,
    O_ORDERDATE      DATE NOT NULL,
    O_ORDERPRIORITY  CHAR(15) NOT NULL,
    O_CLERK          CHAR(15) NOT NULL,
    O_SHIPPRIORITY   INTEGER NOT NULL,
    O_COMMENT        VARCHAR(79) NOT NULL
)
WITH(
	DISTRIBUTION = HASH ( O_ORDERKEY )
);
```

##レプリケート分散
もともと、ラウンドロビン分散とハッシュ分散しか存在していませんでしたが、後に追加された分散方式です。
各コンピュートノードのディストリビューションデータベースに格納されるデータの完全なコピーを配置します。要するにすべてのコンピュートノード上に同じデータが保管されることになります。
Synapse SQLプールはテーブル同士の結合の際に、各ディストリビューション間でデータ移動（BROADCAST_MOVE等）が発生し、これがパフォーマンスへの影響につながりますが、このテーブル結合時のデータ移動（BROADCAST_MOVE等）の抑制を期待できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/697647/74c2b174-9910-4217-85d8-1f84dafaff93.png)

ただし、すべてのコンピュートノードに同一のデータを配置するという事は、せっかくのSynapse SQLプールの特長であるMPPによる分散処理のメリットを損ねる可能性もあります。なので、レプリケート分散を使用す際には以下のポイントに注意が必要となります。

* 圧縮後の容量が2GB未満のテーブルに使用する。
* 頻繁な、更新、追加、削除などDMLが行われないテーブルで使用する。
* 基本的にはディメンジョンテーブルで使用する。（ファクトテーブルとの結合が前提）

作成方法は以下の通りです。
**CREATE TABLE (…)**
**WITH (DISTRIBUTION = REPLICATE)**

```SQL
CREATE TABLE NATION  (
	N_NATIONKEY  INTEGER NOT NULL,
    N_NAME       CHAR(25) NOT NULL,
    N_REGIONKEY  INTEGER NOT NULL,
    N_COMMENT    VARCHAR(152)
)
WITH(
	DISTRIBUTION = REPLICATE
);
```

##まとめ
各分散方式の特長と、使いどころを簡単にまとめると以下のような感じになります。

|| ラウンドロビン分散（デフォルト） |ハッシュ分散 | レプリケート |
|:-----------|:-----------|:------------|:-------------|
|**特徴**|・全てのストレージにできるだけ均等に分散<br>・ランダムに分散|・指定した列のハッシュ値に基づいて分散<br>・同じ値は同じストレージに配置|・全てのノードに全てのデータを分散<br>・テーブルのサイズは2GB未満が推奨|
|**使い所**|・大きなファクト表には適さない<br>・ローディングは最も高速<br>・ステージングテーブルに使用<br>・まずハッシュ分散を検討|・大規模ファクト表向き|・小さなディメンション表向き|

##終わりに
次の機会にデータ移動（BROADCAST_MOVE等）の観点を踏まえて、データの分散方式の選定を考えたいと思います。
New Relic メモ 〜Logs(Apache Log)〜

## はじめに
* [前回](https://qiita.com/1ksen/items/048068b1b0c43dfb9f0c)は、Apache Integrationを設定した
* ただ、Apacheのログに書かれているような内容は取れず、あくまで**mod_status**で取れるような内容のみだった
* なので、ログはLogsで取り込みをすることに

## 事前確認

* [OSの対応バージョン](https://docs.newrelic.com/docs/logs/enable-log-management-new-relic/enable-log-monitoring-new-relic/forward-your-logs-using-infrastructure-agent#requirements)を確認する
* Infrastructure Agentのバージョンを確認する（2020/9/1時点で1.11.4以上であること）

```shell-session
# rpm -qa | grep newrelic
newrelic-infra-1.12.2-1.el7.x86_64
```

## Logsの設定

New RelicのLogsの画面から設定ウィザードを立ち上げる。Agentの種類が選べるので、既にインストール済みの**New Relic Infrastructure Agent**をクリック

![1875A135-C92D-4C87-8BF7-018C86021395.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325101/60ef3704-a4de-cdf7-4c7a-f122166156a3.jpeg)

手順が上がってくるので**3. Configure your log sources and other parameters in the logging.d directory.**から実施する。まず、サンプルの設定ファイルの所在を確認。

```shell-session
# ls -ltr /etc/newrelic-infra/logging.d/
合計 20
-rw-r--r--. 1 root root 1097  8月  7 23:18 tcp.yml.example
-rw-r--r--. 1 root root  930  8月  7 23:18 systemd.yml.example
-rw-r--r--. 1 root root 2762  8月  7 23:18 syslog.yml.example
-rw-r--r--. 1 root root 1173  8月  7 23:18 fluentbit.yml.example
-rw-r--r--. 1 root root 1664  8月  7 23:18 file.yml.example
```

色々パターンが提供されているものの、まずは転送することを優先。以下のファイルを作成する。

```yaml:apache_access
logs:
  - name: "test_log"
    file: /var/log/httpd/ssl_request_log
```

Infrastructure Agentを再起動する

```shell-session
# systemclt restart newrelic-infra
```

New Relic Logsの画面を確認すると、ログが転送できていることが確認できる。

![91C916C2-622C-4B22-BC73-3600A201FD43.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325101/059c4ab8-04b1-d732-831b-3ca02161893c.jpeg)

## Logsでやりたいこと
* 送信元IPやUser-Agentの統計を取ったり
* URIごとのレスポンスを計測したり（静的コンテンツ含む）
* そもそものアクセス数のタイムチャート取ったり

これらを作るにあたって、Queryを記載していくのだが、そもそものParsingがどうなっているかが不明。

## Parsing

メニューがあったので、覗き見。

![E4E4AADD-A0C9-4610-AB00-62D472CCC33F.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325101/39ef9f55-3002-69fb-93cd-c5b68fc71ecf.jpeg)

Grok filter形式で記述することで、簡単にエイリアス張れそう。よかったよかった。

![4ED7C583-1D43-4BF2-9846-E24CD36E81FC.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/325101/3d928cb1-be7d-a982-3ef4-435657dd8bd8.jpeg)
LEDのVf カーブ測ってみた。

# 概要

LED のVf カーブを測ってみた。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/187531/d20e05d6-2c3c-e170-ecf9-f1e2577bf5e9.png)


# ターゲットのLED

|色|秋月通販コード|型番|公称Vf|
|:-:|--:|--:|--:|
|赤|https://akizukidenshi.com/catalog/g/gI-06419|OSR50805C1C|2.0v|
|緑|https://akizukidenshi.com/catalog/g/gI-06423|OSG50805C1C|3.3v|
|青|https://akizukidenshi.com/catalog/g/gI-06424|OSB50805C1C|3.2v|
|白|https://akizukidenshi.com/catalog/g/gI-06425|OSW50805C1C|3.3v|
|ウォームホワイト|https://akizukidenshi.com/catalog/g/gI-06426|OSM50805C1C|3.3v|

# 結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/187531/d1083a6b-7b93-07ef-48eb-c6adc1289d30.png)

※1mA高く出ているので、見るときに 1mA 引いてください
WSL2 から起動した VSCode DevContainer に SSH agent で Git の鍵を渡す

__2020/09/04: 「[SSH agent をログイン時に起動するための設定を追加](#ssh-agent-をログイン時に起動するための設定を追加)」 の記述の一部に誤りがあったため修正しました__

微妙にハマったのでメモがてら共有します。
私が使用している distro は Debian ですが Ubuntu とかでもほぼ同じ感じでできると思います。

## 必要なパッケージをインストール

まずは WSL2 に必要なパッケージをインストールします。

```console
$ sudo apt install openssh-client socat
```

`socat` をインストールしておくことが重要です。コンテナから WSL のソケットに接続する際に使用されます。

## SSH Key を作成

Git 接続用の SSH Key を作成します。
既にある場合は改めて作成する必要はありませんが、パスフレーズが設定されている鍵の場合 VSCode の pull や push 機能がハングする可能性があることに注意しましょう([Remote - Containers limitations](https://code.visualstudio.com/docs/remote/containers#_remote-containers-limitations) を参照)。
また、鍵の暗号強度が弱いと使用するイメージによっては怒られてしまって使えないので強いアルゴリズムを使うようにしましょう。

```console
$ ssh-keygen -t ed25519 -P ""
```

公開鍵は GitHub 等に登録しておきます。説明するほどのことでもないので手順については割愛します。

## SSH agent をログイン時に起動するための設定を追加

ログインした際に SSH agent が起動するように `.bash_profile` や `.zprofile` に以下を追加します。

```bash:.bash_profile
if [ -z "$SSH_AUTH_SOCK" ]; then
   # Check for a currently running instance of the agent
   RUNNING_AGENT="`ps -ax | grep 'ssh-agent -s' | grep -v grep | wc -l | tr -d '[:space:]'`"
   if [ "$RUNNING_AGENT" = "0" ]; then
        # Launch a new instance of the agent
        ssh-agent -s &> $HOME/.ssh/ssh-agent
   fi
   eval `cat $HOME/.ssh/ssh-agent`
fi

ssh-add $HOME/.ssh/id_ed25519
```

[公式ドキュメント](https://code.visualstudio.com/docs/remote/containers#_using-ssh-keys)に記載されているものですが、少しアレンジしています。


- `.ssh/ssh-agent` を `$HOME/.ssh/ssh-agent` に変更
  - 相対パスで書くと VSCode でワークスペースを開いた際に解決できなくて死ぬため
- `ssh-add` で秘密鍵を登録する行を追加
- ~~記述するファイルを `.bash_profile` (`.zprofile`) ではなく `.bashrc` (`.zshrc`) に変更~~
  - ~~VSCode の Remote WSL で接続した場合 `.bash_profile` (`.zprofile`) だと読み込まれないため~~
  - ~~`settings.json` に `"terminal.integrated.shellArgs.linux": ["-l"]` を追加することで読み込ませることもできるが、terminal で `code` コマンドが使えなくなるなどのデメリットがある~~
  - (2020/09/04 訂正) DevContainer 起動時の処理は非対話モードのシェルで行われるので `.bash_profile` (`.zprofile`) が読み込まれます 

## DevContainer に入って確認

これで準備は整ったはずです。
VSCode の Remote WSL でリポジトリを開き、`Reopen in Container` をするなどして DevContainer に入ります。
適当に `git fetch` などを実行してみて remote repo につながることを確認してみましょう。

## 参考

- https://code.visualstudio.com/docs/remote/containers
- https://github.com/microsoft/vscode-remote-release/issues/2925
Android アプリ開発者がiOSアプリも開発したくなったので、とりあえずFlutterの導入をしてみた

## 概要
* Androidアプリの開発ばかりやっていたが、iOSアプリの開発も今後やっていきたい。
* Flutterを使用すれば、iOSアプリの開発も今後やっていけそうなので、調べていく。

## 想定している対象者
* Androidアプリの開発であれば経験はあり、iOSアプリの開発の開発もFlutterでやってみたいという方。

## Flutterとは
* Flutterとは Google 製のアプリケーションUI構築ツールキット。
* 構築出来るアプリ
    * モバイルアプリ制作
        * iOS
        * Android
    * Web
    * デスクトップ向けのアプリケーション
* とくにモバイルアプリにおいては、単一のコードから iOS/Android の両方にビルドできる。
* Google によって『The best framework for developing beautiful experiences for any screen』をめざして開発が進められているフレームワーク。
    * ※「技術的な垣根を超え一つのコードベースから様々なポータル端末で同じユーザ体験を実現する」という意味。
* UIは全てコードベース。『UIツールキット』の名前の通り、UIをコードで作成することによりそれぞれのプラットフォーム(iOS/Android)に応じた美麗な UI 画面を作成することができる。
* 使用するプログラミング言語は、Dart。

## 環境構築、ビルド通るまで
[参考 : Flutter開発環境構築(Mac編)](https://qiita.com/akatsukaha/items/3b8a5a6d94a3cdb1e047)

1. Flutter SDKの導入
    1. 公式サイトよりインストール
    1. 任意のストレージに解凍
    1. 環境変数にパスを通す
        * ~/.bash_profileに、以下の様な記述を追加
            * `export PATH="$PATH:/Users/username/Library/flutter/bin:$PATH"`
        * `$ flutter --version` でバージョン取得出来れば完了
1. Flutterプロジェクトの作成
    * `$ flutter create helloworld` を実行
        * ※ここでXcodeがインストールされていない場合、インストールを求めるポップアップが表示されるので、案内の通りに対応して完了。
1. Android 環境の構築
    * Android Studioの環境設定は、すでに対応済みだったため省略
1. Android Studioのプロジェクトの作成
    * 特に特別な設定は無し。空のプロジェクトを適当に作成する。
1. Flutterのサンプルプロジェクトに移動
    * `$ flutter doctor --android-licenses`でライセンスに同意
    * `cd` で作成したFlutterプロジェクトに移動
    * `flutter run` を実行
        * エミュレーターでもいけるらしい。今回は私用端末を使用。
        * 失敗したが、後述の原因を調べてエミュレーターでの起動まで完了。

### 躓いた箇所

#### `flutter run` でエラー発生「`Unable to locate a development device; please run 'flutter doctor' for information about installing additional components.`」
* `flutter emulators` で確認すると、エミュレーターは存在しているが、起動　が出来ない。
* `flutter doctor`を実行してみてと言われているので、実行してエラーが発生していた箇所を確認。

```
`    ✗ Android SDK file not found:
      /Users/username/Library/Android/sdk/build-tools/28.0.3/aapt.`
```
* Android StudioのSDK Managerで存在していないと言われたビルドツールをインストール。
    * 参考 : [SDK Managerを使ってSDKおよびSDK Toolsを追加でインストールする](https://www.javadrive.jp/android/install/index4.html)
* 完了後、再度`flutter doctor`を実行すると、解決していることを確認。
* `flutter run`でエミュレータで起動出来た。
* ※すでにローカル環境にインストールしていたビルドツールで出来ないかと考えたが、パッと分からなかったので、今回は大人しく28.0.3をインストール。

### まとめ
* ローカル環境のストレージがキツキツだったからか、iOSでの実機ビルドまでは行かなかったので次回・・
* 次は、とりあえず色々とコードを見ながら色々といじってみる。
* dartの勉強をする。
* もうちょっとFlutterでは実はこういうことが出来ないという話もありそうだったので、今後まとめたい。(あまり複雑な処理は出来ない気がする。)
searchとeach_with_indexの組み合わせ

今日のドリルで登場した式。

```Ruby
def search(target_num, input)

  input.each_with_index do |num, index|
    if num == target_num
      puts "#{index + 1}番目にあります"
      return
    end
  end
  puts "その数は含まれていません"
end

input = [3, 5, 9 ,12, 15, 21, 29, 35, 42, 51, 62, 78, 81, 87, 92, 93]
search(12, input)
```
これで「4番目にあります」の出力ができる。

一方で、

```Ruby
def search(target_num, input)

  input.each_with_index do |num, index|
    if num == target_num
      puts "#{index + 1}番目にあります"
      return
    else
      puts "その数は含まれていません"
      next
    end
  end
end

input = [3, 5, 9 ,12, 15, 21, 29, 35, 42, 51, 62, 78, 81, 87, 92, 93]
```
こちらはnextを使って、
4番目の12が出るまでif文内の処理が続く、というもの。

一応nextがなくても結果は同じだけど、
読みやすさを考えるとnextがあった方がいいのでは、と思った今日この頃。

この記述に関して昼前まで議論が絶えんかったな。
プログラミングの魅力の一つと言っていいのかもしれない。
Vue.js　宣言的レンダリング

## HTMLでvueを使えるようにする

hmtlでvueを読み込ませませます。

```
<!-- 開発バージョン、便利なコンソールの警告が含まれています -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>

<!-- 本番バージョン、サイズと速度のために最適化されています -->
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
```

以下のサンプルコードのようにscriptタグの最上位にコードを追記します。

## 宣言的レンダリングを試してみる

### サンプルコード

```index.html
<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Product App</title>
</head>

<body>
    <div id="app">
        <h1>{{ product }}</h1>
    </div>
    // プロジェクトにvueを読み込ませる
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="main.js"></script>
</body>

</html>
```

```main.js
var app = new Vue({
    el: '#app',
    data: {
        product: 'Socks'
    }
})
```

### 表示例

![スクリーンショット 2020-09-01 22.49.41.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/701876/e9e3572e-8ef2-1e5f-537c-6a266e5ad5c5.jpeg)


## その他、できること

```js
{{ product + '?' }}
{{ firstName + ' ' + lastName }}
{{ clicked ? true : false }}
{{ message.split('').reverse().join('') }}
```


## コンソールから表示を変更できる

データとDOMが関連付けられ、リアクティブに変化することがわかる。

![スクリーンショット 2020-09-01 23.02.01.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/701876/cf05902a-95c9-52b8-38df-d5205078f582.jpeg)

## ディレクティブを使った要素の束縛 (v-bind)

描画された DOM に特定のリアクティブな振舞いを与えます。

以下に例を示しましょう。ここで宣言されているのは、「この要素の title 属性を Vue インスタンスの message プロパティによって更新して保存する」ということになります。

```index.html
<div id="app-2">
  <span v-bind:title="message">
    Hover your mouse over me for a few seconds
    to see my dynamically bound title!
  </span>
</div>
```

```main.js
var app2 = new Vue({
  el: '#app-2',
  data: {
    message: 'You loaded this page on ' + new Date().toLocaleString()
  }
})
```

もうひとつ例を示します。
「この要素の src 属性を Vue インスタンスの image プロパティによって更新して保存する」という意味です。
もちろんこちらもコンソールを使って、`app.image = ""`で書き換えて上げればリアクティブな書き換えが可能です。

```index.html
<div id="app">
    <div class="product">
        <div class="product-image">
            <img v-bind:src="image">
        </div>
        <div id="product-info">
            <h1>{{ product }}</h1>
        </div>
    </div>
</div>
```

```main.js
var app = new Vue({
    el: '#app',
    data: {
        product: 'Socks',
        image: './assets/vsSocks-green.jpg'
    }
})
```

### ディレクティブの省略記法

v-bindを取ってあげるだけで大丈夫です。

元の形|略式
--- | ---
v-bind:alt="description"|:alt="description"
v-bind:href="url"|:href="url"
v-bind:title="toolTip"|:title="toolTip"
v-bindc:class="isActive"|:class="isActive"
v-bind:style="isStyeled"|:style="isStyeled"
v-bind:disabled="isDisabled"|:disabled="isDisabled"
Gnu-COBOL 集合項目

## 集合項目

- 違う種類のデータをまとめて扱う

```
IDENTIFICATION DIVISION.
PROGRAM-ID. HELLO.

DATA DIVISION.
  WORKING-STORAGE SECTION.
    01 PARENT.                    *> レベル番号「01」は「03」の親要素になる
      03 CHILD1 PIC X(5).         *> レベル番号「03」は「01」の子要素になる
      03 CHILD2.                  *> レベル番号「05」は「03」の子要素になる
        05 GRAND-CHILD PIC X(15).  *> 親要素になる変数は「PIC」を定義することはできない
                                  *> 基本的には「01」「03」「05」など2飛ばしや5飛ばしで付けられる

PROCEDURE DIVISION.
  MAIN SECTION.
    MOVE "PARENT" TO PARENT.
    MOVE 12345 TO CHILD1.
    MOVE "GRAND-CHILD" TO GRAND-CHILD.
    DISPLAY PARENT.
    DISPLAY CHILD1.
    DISPLAY CHILD2.
    DISPLAY GRAND-CHILD.
    STOP RUN.

```

### コンパイル/実行

**コンパイル**

```
USER-no-MacBook-Air:COBOL user$ cobc -x --free hello.cob
```

**実行**

```
USER-no-MacBook-Air:COBOL user$ ./hello
12345GRAND-CHILD    
12345
GRAND-CHILD    
GRAND-CHILD 
```
useRef、forwardRefを理解する

# 概要

useRef、forwardRefは主に、DOMを直接操作(フォーカス、テキストの選択、メディアの再生の管理、アニメーションの発火など)したい場合に使用するものです。

# useRefの基本的な使い方

useRefは、currentプロパティをもつミュータブルなrefオブジェクトを返し、引数で渡した値(引数がなければundefined)がcurrentプロパティに初期値として入ります。

``` react
const Mycomponent = () => {
  const defaultRef = useRef();
  const customRef = useRef("something");
  console.log(defaultRef) // => {current: undefined}
  console.log(customRef) // => {current: "something"}
  console.log(customRef.current) // => something
  return <div />
}
```

HTML要素のref属性にRefオブジェクトを指定すると、currentプロパティにはそのHTML要素のDOMが設定され、DOMへのアクセスや操作が可能になります。

``` react 
const Mycomponent = () => {
  const textRef = useRef();

  useEffect(() => {
    console.log(textRef.current) // => <input type="text">
    console.log(textRef.current.type) // => text
    textRef.current.focus() // フォーカスし入力ができるようになる
  }, [])

  return <input ref={textRef} type="text" />
}
```
Apollo Client 3でページネーション

## はじめに
Apollo Client 3における便利なページネーション機能をご紹介します。

## concatPagination

Apollo Clientのページネーションは、これまでoffsetベースの実装だと`fetchMore`を使った以下のような実装になっていましたが、

### Before
```tsx
<Feed
  entries={data.entries || []}
  onLoadMore={() =>
    fetchMore({
      variables: {
        offset: data.entries.length
      },
      updateQuery: (prev, { fetchMoreResult }) => {
        if (!fetchMoreResult) return prev;
        return Object.assign({}, prev, {
          entries: [...prev.entries, ...fetchMoreResult.entries]
        });
      }
    })
  }
/>
```

### After

Apollo Client 3から、`@apollo/client/utilities`の`concatPagination`を`typePolicies`内で使うことで `updateQuery` の記述の必要がなくなりました（`fetchMore`における`updateQuery`はdeprecated）。

```tsx

const cache = new InMemoryCache({
  typePolicies: {
    Query: {
      fields: {
        entries: concatPagination(),
      },
    },
  },
});
```
```tsx

<Feed
  entries={data.entries || []}
  onLoadMore={() =>
    fetchMore({
      variables: {
        offset: data.entries.length
      }
    })
  }
/>
```

cursorベース向けに、`offsetLimitPagination` や `relayStylePagination` といったutil機能も`@apollo/client/utilities`に用意されています。

## まとめ

今回はApollo Client3で追加されたページネーション機能をご紹介しました。
Azureの新試験AZ-204を旧試験AZ-203と比較してみた

# はじめに
2020年7月、Azureの資格AZ-103を受験し、無事合格しました。次なる資格は、Azure Developer Associateを考えています。ところがこの資格も、最近バージョンが新しくなったようなので、せっかくなのでAZ-203からAZ-204を比較してみることにしました。

AZ-103の関連記事はこちら。
[AZ-103とAZ-104の比較](https://tagfa.wpx.jp/archives/129)
[AZ-103合格体験記](https://tagfa.wpx.jp/archives/225)

# 比較
公式ホームページのスキルアウトラインを元に比較してみました。

AZ-203 https://query.prod.cms.rt.microsoft.com/cms/api/am/binary/RE3VEHC
AZ-204 https://query.prod.cms.rt.microsoft.com/cms/api/am/binary/RE4oZ7B

## 対象者
AZ-204の方が、やや対象者の敷居が高くなっているよう。AZ-203より難しくなっているということでしょうか。

- AZ-203:少なくとも1年の開発経験
- AZ-204:1〜2年のAzureでの高度な開発経験

## 評価されるスキル
| No | AZ-203 | AZ-204 |
|:-:|:-:|:-:|
|  1 |  Azure のサービスとしてのインフラのコンピューティングソリューション開発(10-15%) |  Azure のサービスとしてのインフラのコンピューティングソリューション開発(10-15%) |
|  2 |  Azure のサービスとしてのプラットフォームのコンピューティングソリューション開発 (20-25%) |  Azure ストレージを開発(10-15%) |
|  3 | Azure ストレージを開発 (15-20%)  |  Azure Security の実装(15-20%) |
|  4 |  Azure Security の実装 (10-15%) |  Azureソリューションの監視、トラブルシューティング、最適化(10-15%) |
|  5 |  ソリューションの監視、トラブルシューティング、最適化 (10-15%) |  Azure サービスとサードパーティサービスの連携と活用(25-30%) |
|  6 | Azure とサードパーティサービスの連携と活用 (20-25%)  |   |

	
AZ-204になり、項目が減っています。ただ、AZ-203のNo1とNo2がマージされただけのように見えます。

大きな違いは、AKSが出題範囲外となったことくらいでしょうか。

出題割合としては、VM、AppServiceなどの計算資源系の問題、サードパーティ活用の問題で割合が増加しています。特に、計算資源系は開発でのキモなので、多数の問題が出題されることが想定されます。

例の如く、詳細な比較は以下ブログをご覧ください。
[AZ-203とAZ-204の比較](https://tagfa.wpx.jp/archives/424)

合格したら、また体験記を書こうと思います。
削除機能の実装(foreign_keyを持つ場合)

##概要
Railsで外部キーを持ったモデルを削除する際、単純にルーティングとコントローラーとビューファイルを記述しただけでは実装できず苦しんだのでアウトプットしておきます。

##実装内容
外部キーとして、商品購入に関してデータを結びつけているitem_purchaseを持ったitemというモデルを削除するとします。

このitem_purchaseは、購入した人であるuser_idと、購入された商品であるitem_idを持っています。

ここで、単純にitemを削除すると、item_purchaseにはitem_idだけなくなってしまったレコードが存在してしまいます。

そこで、itemを削除したときにその関連したitem_purchaseのレコードそのものを削除できるように記述していきます。

##実装

まずはモデルのアソシエーションに追加記述しましょう。

```ruby:models/item.rb
has_one :item_purchase, foreign_key: :item_id, dependent: :destroy
```

```ruby:models/item_purchase.rb
belongs_to :item, optional: true
```
ここでは紹介しませんが、userも紐づいているはずなので、そちらも忘れずに記述します。


あとは通常通りにコントローラーにdestroyメソッドを定義してあげたりすればOKです。
[Unity] AppStoreConnectへのUpload時のITMS-90809問題

# 概要
iOS AppをAppStoreConnectにアップロード後、審査結果で下記のような事由でリジェクト。
>ITMS-90809: Deprecated API Usage - New apps that use UIWebView are no longer accepted. Instead, use WKWebView for improved security and reliability. Learn more (https://developer.apple.com/documentation/uikit/uiwebview).

Deprecated(非推奨)扱いになった『UIWebView』というAPIの呼び出しが検知されたため、とのこと。

この記事を読んでいる方はUnityユーザの方が多いと思うので、基本的には直接UIWebViewを呼び出して使っているわけではなく、UIWebViewを利用するライブラリを利用しているものと思われます。

この記事ではそのライブラリの調査方法と、私が遭遇したケースにおける解決方法を記載します。
※調査方法はMaxユーザ向けのため、Windowsユーザは読み替えが必要です:bow:

# 調査方法
まずUIWebViewを利用しているライブラリを見つける必要があります。
XCodeのProjectフォルダの直下でgrepすればあたりがつけられます。

### 実行コマンド

```shell
grep -r "UIWebView" .
```

### 実行結果

```
Binary file ./Libraries/libiPhone-lib.a matches
Binary file ./Pods/Google-Mobile-Ads-SDK/Frameworks/GoogleMobileAdsFramework-Current/GoogleMobileAds.framework/GoogleMobileAds matches
```

今回の私のケースだと上記２件がヒットしました。
上記２件を手がかりに、個別に解決方法を探っていきます。

１行目のlibiPhone-lib.aに関しては、Unityが生成したライブラリの模様。

2行目のGoogle-Mobile-Adsについては、アプリでリワード広告を表示するために利用しているAdmob用のSDKがヒットしているようです。

# 解決方法
## 1. libiPhone-lib.a
結論を先に書くと、UnityのVersionをあげるしか回避方法は見つかりませんでした。
かなり幅広いバージョンが該当するようです。
[[IOS] APPLE THROWS DEPRECATED API USAGE WARNING...](https://issuetracker.unity3d.com/issues/ios-apple-throws-deprecated-api-usage-warning-for-using-uiwebview-when-submitting-builds-to-the-app-store-connect)
上記の再現バージョンには書かれていませんが、2018.3.14でも再現しました。

2018.3と2018.4だと差分が多く移行が大変なので避けたかったですが。。。やむを得ません。
こう言ったことは今後も発生する可能性が高いので、このタイミングでLTS版に上げることにしました。

2019.4(LTS)にバージョンを上げたところ、grep結果にlibiPhone-lib.aは引っ掛からなくなりました。


## 2. GoogleMobileAds SDK
下記を参考に、Google Mobile AdsのSDKを最新化しました。
[ITMS-90809: Deprecated API Usage (UIWebView APIを使用したアプリアップデート) 対策でGoogle-Mobile-Ads-SDKを更新](https://doroidpanic.com/itms-90809-deprecated-api-usage-uiwebview-api%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%97%E3%81%9F%E3%82%A2%E3%83%97%E3%83%AA%E3%82%A2%E3%83%83%E3%83%97%E3%83%87%E3%83%BC%E3%83%88-%E5%AF%BE%E7%AD%96/)

また、併せてGoogleMobileAdsのUnityプラグインを最新化しました。

1. [公式](https://developers.google.com/admob/unity/start?hl=ja)からMobileAdsSDKforUnityをDL
2. Unityプロジェクト内の下記を一度プロジェクト外に退避（コピーではなく移動）
```Assets/GoogleMobileAds, Assets/PlayServicesResolver, Assets/Plugins/Android, Assets/Plugins/iOS```
3. DLしたMobileAdsSDKforUnityを開き、プラグインをインポート
4. UnityでAssets > Google Mobile Ads > settingsからID等を設定
5. Build実行

実施した対策は以上です。

注意したいのが、上記を行っても <font color="Red">grep結果にはGoogleMobileAdsがヒットします</font>。
キチンとバージョンが上がっていれば、審査も問題なく通過します。
（これに気づかず、「アップデートしたのにUIWebViewへの参照が消えない・・・」としばらく悩みこんでしました。。）

# まとめ
上記をもって、無事AppStoreConnectへのアップロード後の審査がOKになりました。

開発期間が長期化するとこう言った問題は必ず付きまといますが、UnityVersionはその時点で最新のLTS版を選択していくのが安全だと感じました。

補足事項などあればコメント頂けると幸いです。
Rails password暗号化　備忘録

Gemfileの編集

```ruby:Gemfile
gem 'bcrypt'
```

　をGemfileに追加。

　その後、ターミナルにおいて

```ruby:ターミナル
bundle install
```
を実行し、gemをインストールする。
 bcryptをインストールすることで, has_secure_passwordメソッドが使用可能になる。

 models/user.rbにhas_secure_passwordを追加

```ruby:models/user.rb
 
has_secure_password
```

 has_secure_passwordメソッドはpassword_digestカラムに保存することになっているので、
ターミナルでchange_users_columnsというファイル名にしてマイグレーションファイルを作成する。

```ruby:ターミナル
rails g migration change_users_columns
```

作成された2020~_change_users_columnsのchangeメソッドに
add_columnを用いてpassword__digestカラムを追加。
また、passwordカラムは必要なくなるためここで消しておく。

```ruby:migrate/2020~_change_users_columns.rb
class ChangeUsersColumns < ActiveRecord::Migration[5.0]

 def change
  add_column :users, :password_digest, :string
  remove_column :users, :password, :string
 end
```

※string:文字列、text:長い文字列、integer:整数

マイグレーションファイルの変更が終了したら、ターミナルでrails db:migrateを実行して
データベースに反映させる。

```ruby:ターミナル
rails db:migrate
```

次に、暗号化されたパスワードを用いてログインできるようにする。

has_secure_passwordメソッドを設定すると、authenticateメソッドを使えるようになる。
authenticateメソッドは渡された引数を暗号化し、password_digestの値と一致するかどうかを判定してくれるので、authenticateメソッドを使って、送信されたメールアドレスと一致するユーザーと、送信されたパスワードが一致するかどうかでログイン処理を行う。

```ruby:users_controller.rb
def login
 @user = User.find_by(email: params[:email])
 if @user && @user.authenticate(params[:password])
                   .
                   .
                   .

 end
end
```

完成。
RMarkdownの数式をgitlabで表示できるよう変換する

# 概要

RMarkdownをmarkdownに変換した時、gitlabでも数式を表示させたい。

lua-filterを使います。

# 本文

gitlabではRMarkdownは直接レンダリングされませんので、一旦md_documentでGLFM ( Gitlab flavored markdown) に変換しないとなりません。

フロントマターに

```
output: 
    md_document:
        variant: gfm
```

と書いておけばknitした時に.mdファイルが生成されますが、この時数式の部分がインラインの
`$...$`は`\(...\)`に、
別行立ての

```
$$
...
$$
```

は

```
\[
...
\]
```

に変換されてしまいます。

Gitlabでは数式を表示するときに、インラインでは``$`...`$``、
別行立てでは

````
```math 
...
``` # end of math block 
````

という書式で表すことになっているので、さらに変換してあげないとなりません。

knitrだかrmarkdown::render、あるいはpandocの拡張でなんとか出来ると良いのですが、~~そこはやり方がわからなかったので、~~

## lua-filterで変換

```lua
function Math(el)
    if el.mathtype == "InlineMath" then
        return {pandoc.RawInline("html","$`"), pandoc.RawInline("html",el.text), pandoc.RawInline("html","`$")}
    else
        return {pandoc.RawInline("html","```math"), pandoc.RawInline("html",el.text),pandoc.RawInline("html","```")}
    end
end
```

をgitlab-md.luaという名称で保存して、

```R
output:
    md_document:
        variant: gfm
        pandoc_args: ["--lua-filter","./gitlab-md.lua"]
```

とすると、Gitlab書式で数式部が変換されたmarkdown書類が生成されます。


## VSCodeで置換(力ずく)

```R
output:
    md_document:
        variant: gfm
```

だけで生成されたmarkdownファイルを
VSCodeの[replace rules](https://marketplace.visualstudio.com/items?itemName=bhughes339.replacerules)拡張を使って、文字列の置換で対応する方法です。

replace rulesの置換ルール設定は以下。

```
"replacerules.rules": {
    "Replace inline math to gitlab": {
        "find": "\\\\\\((.*)\\\\\\)",
        "replace": "$$`$1`$$"
    },
    "Replace math fencing start to gitlab": {
        "find": "\\[",
        "replace": "```math",
        "literal": true
    },
    "Replace math fencing end to gitlab" : {
        "find": "\\]",
        "replace": "```",
        "literal": true
    }
},
"replacerules.rulesets": {
    "Replace math gitlab": {
        "rules":[
            "Replace inline math to gitlab",
            "Replace math fencing start to gitlab",
            "Replace math fencing end to gitlab"
        ]
    }
}
```

Ctrl-Shift-Pからreplace rule: run ruleset...で"replace math gitlab"を呼び出せば、数式部分を一気にgitlab対応に変換できます。

# 他力本願

~~md_documentのvariantにgitlabとでも入力すると自動的に全部正しく変換してくれるのが一番良いのですが、ちょっと手が出ないので猛者の誰かがやってくれるのを願いつつ。~~

lua-filterの書き方がなかなかわからなかったのですが、上記の通り数式だけならなんとかなりました。
find_or_initialize_byのびっくりした挙動を忘れないように残す


## この記事で書くこと

[Railsガイド | find_or_initialize_by](https://railsguides.jp/active_record_querying.html#find-or-initialize-by) の挙動で、驚いたので忘れないように残す。
具体的には、 `find_or_initialize_by` の引数の値が**nil**だった時の挙動について書きます。

## 例示

`params[:name]` には `nil` が入る可能性がある。
`User.name` にはuniq制約がついている。


```rb
user = User.find_or_initialize_by(name: params[:name])
```

この時、どういったsqlが発行されるのか？

### params[:name] がnilではなく、nameが引数のnameのレコードが既に存在している場合

```rb
# params[:name] は `test_user` だとする。
 User Load (1.1ms)  SELECT `users`.* FROM `users` WHERE `users`.`name` = 'test_user' LIMIT 1
```

存在するレコードが返る。

### params[:name] がnilではなく、nameが引数のnameのレコードが存在していない場合

```rb
# params[:name] は `hoge` だとする。
User Load (2.7ms)  SELECT `users`.* FROM `users` WHERE `users`.`name` = 'hoge' LIMIT 1
```

発行されるsqlは同じだが、返る値は、idを持たない、`user.name`が`hoge`のレコード。

### params[:name] がnilの場合 :exclamation:  :exclamation: 

```rb
# params[:name] は `nil` だとする。
User Load (2.7ms)  SELECT `users`.* FROM `users` WHERE `users`.`name` IS NULL LIMIT 1
```

当たり前と言っては当たり前なのだが、`name`に値が入ってないレコードの一件目が返る。
勝手にnilが入ったときには、エラーになるとか、既存のレコードは返却されずに新しいインスタンスが作成されて返されるとか都合の良い解釈を期待するが、そんなことは幻想。
全く意図しないレコードを更新してしまう可能性がある。


`find_or_initialize_by` の引数に**意図せず**nilが入る可能性がある処理を書くことは危ないことがわかった

[実装の中身](https://apidock.com/rails/v6.0.0/ActiveRecord/Relation/find_or_initialize_by)を読んでみると、


```rb
# File activerecord/lib/active_record/relation.rb, line 226
    def find_or_initialize_by(attributes, &block)
      find_by(attributes) || new(attributes, &block)
    end
```

とあり、まず、 `nil`だって立派な値なのだから `find_by` にだってしっかり入っていく。というのが理解できた。

### `find_or_create_by` も同じく注意が必要。


```rb
# 意図してないけど、nilが入ってしまった。。。。。。。
new = User.find_or_create_by(name: nil)
User Load (5.3ms)  SELECT `users`.* FROM `users` WHERE `users`.`name` IS NULL LIMIT 1
```

### まとめ
「えっ！！何か知らないレコードが勝手に更新されてるんですが！！！！！」
を無くすためには、頭の中の勝手な都合の良い解釈をやめ、挙動をしっかり確認しよう。 
nilは意図して使いたいとき以外は引数に入れないようにしようと思います。
axios-mock-adapterで動的なurlのリクエストを取得する方法

# axios-mock-adapterで動的なurlのリクエストを取得する方法

## URLの末尾にパラメータがはいるリクエストの場合
* 例

`/hoge/piyo/0123456789`
`/hoge/piyo/9876543210`

###リクエスト投げる側

``` javascript
export default {
 data() {
    return {
      fuga:null, // fugaが可変
    };
  },
    mounted() {
       this.$axios.get("/hoge/piyo/",{ params: { fuga: this.fuga} })
           .then((response) => {
               console.log(responce)
            })
           .catch((e) => {
               console.log(e)
           });
         });
    }
}
```
### mock

``` javascript

export default {

  mock.onGet('/hoge/piyo/').reply(config => {
       if(config.params.fuga == '0123456789') {
         res = 'param1'
        }
        if(config.params.fuga == '1234567890') {
         res = 'param2'
        }
        return [200, res]
      }),
}
```


## URLの途中にパラメーターが入るようなリクエストの場合
* 例

`/hoge/0123456789/piyo`
`/hoge/9876543210/piyo`


###リクエスト投げる側
  
``` javascript
export default {
 data() {
    return {
      fuga:null, // fugaが可変
    };
  },
    mounted() {
       this.$axios.get("/hoge/" + this.fuga + "/piyo")
           .then((response) => {
               console.log(responce)
            })
           .catch((e) => {
               console.log(e)
           });
         });
    }
}
```
### mock

``` javascript

function checkRequestUrl(path = '') {
  // ":"から始まる単語構成文字(a-zA-Z_-^9)を"/"を含まない文字列を許容するように置換する
  path = typeof path === 'string'
    ? new RegExp(path.replace(/:\w+/g, '[^/]+'))
    : path
  return path
}

export default {
  checkRequestUrl,
  mock.onGet(checkRequestUrl('/hoge/:fuga/piyo')).reply(config => {
        // パラメータを取得してパラメータごとに返却値を変更する
        var params = config.url.match(/\/hoge\/(.+)\/piyo/);
        let res = ''
        if(params[1] == '0123456789') {
         res = 'param1'
        }
        if(params[1] == '1234567890') {
         res = 'param2'
        }
        return [200, res]
      }),
}
```

# 参考
[How to mocking a http request with route params using axios-mock-adapter](https://stackoverflow.com/questions/46954860/how-to-mocking-a-http-request-with-route-params-using-axios-mock-adapter)
ここが変だよ老舗ベンダー

某老舗ベンダーの大規模プロジェクトを２次受けで携わったときの理不尽な記憶です。

# 絶対にうまくいかないウォーターフォール開発

設計〜製造〜試験と上流工程から下流工程に順にやっていく開発ですが、システム開発では絶対にうまくいきません。なぜなら、どの工程においても**「今からでも変えられる」**という意識があるからです。

ウォーターフォール開発は多分元々は建設・建築系の工程から来てると思うのですが、それらは物理的な資材や土地に対して設計しているので、あとから変えるのは容易ではないと思います（多分）。

ただ、PCの中のプログラムの話では、その気になればいつでも仕様・設計変更できます。物理的な資材が無駄になることもありません。

以前知り合いのエンジニアが**「システム開発技術は年々進化してどんどん楽に便利に開発できるようになっているはずなのに、エンジニアは一向に楽にならない」**と言っていました。便利になった分、いつでも変更可能になってしまい、「いつまで経っても終わらない」現象に陥ってしまうためと容易に想像できます。

# 存在することだけに意義がある設計書

企業や官公庁などのシステム更改プロジェクトとかだと、先方の担当者が現行仕様の情報や新仕様の方針の情報などを出してくれないと話が進まないのですが、先方も通常業務をしながらの対応なので、**なかなか回答してくれません**。質問表のexcelには数百件の質問が並び、先方もうんざりしていたことでしょう。

そんな中でも、何の根拠で決めたかわからないスケジュールの期限は迫ってきますが、情報がないので、こちらの努力ではどうしようもありません。
それでも「進捗遅れ」という事実を作りたくない上層部はどうするかというと、**中身がなくてもいいから**設計書を完成させるという暴挙に出ます（設計書はもちろんExcel方眼紙）。

どのくらい中身がないかというと、例えばシステムフロー図なら、

[処理開始]　→　[計算処理]　→　[処理終了]

という、**その[計算処理]の詳細を書く場所なんじゃないの？**というツッコミどころ満載の空っぽの設計書が仕上がります。
最終的に機能名が違うだけで中身はどれも同じなので、**設計書を自動生成するマクロが組まれました**。

で、なぜこんな無駄をしなければいけないかというと、設計書も納品物のためです。
最終的に紙に印刷してキングファイルに閉じたものを納品したのですが、大規模プロジェクトでは**段ボール箱３０箱**くらいになりました。絶対あとから見ることない。

という感じで、情報がないまま基本設計、詳細設計期間は過ぎていき、結局製造工程中に設計しながら開発することになるので、この時点で**ウォータフォールが破綻してます**。

# エンドレス仕様変更

製造の段階になる頃には、**表向きにはスケジュール順調だけど実質的には大遅延中**と現場の人間は気づいているので、やれるところからどんどんやれみたいな感じになり、設計しつつ実装しつつ出来たところからテストしつつになり、何がどこまで進んでいるのかよくわからなくなります。

で、ウォーターフォールの良いところの「最初に仕様・設計をきっちり固めて、以降の無駄な工程を無くす」というのをやっていないので、後になってから仕様がブレまくります。

あとになってから別の機能との接続で問題があることがわかったりして、一度テスト完了まで終わった機能も仕様変更で作り直しになったりします。中には根幹を揺るがすような仕様変更もホイホイ湧いてきます。そしてその仕様変更がまたあとになって別の不都合を生み出し、**負のスパイラルが続きます**。

スケジュール的にはテスト期間であっても、普通に設計からやりなおしていたりするので、この頃には**「今からでも基本設計からやり直したほうがいいものができるのでは？」**と現場の人間は思い始めます。

# 形ばかりの監査

スケジュール的に出荷試験の工程になると、殆どのバグは潰されていて、**少なくとも基本機能はまともに動くはず**なので、出荷できるものに仕上がっているかの監査が入るのですが、そんな時期でも絶賛仕様変更中なので、基本機能もまともに動きません。監査の人も「おいおい・・・」と思っていたと思います。
ただ、そんな状況でもなぜか監査NGにはなりません。注意ということで終わります。「プロジェクトを止めるわけには行かない」という忖度でしょうかね。

# 全然仕上がっていないのにやってくる納品日

納品日には、ドキュメントとソースコードを入れたCD-Rを納品することになるのですが、そのときにはまだ絶賛開発中なので**めちゃめちゃ中途半端なソースコードを納品します**。納品用に「変なコメントは消せ」と指示がでて納品用のソースコードを作ります。なので、納品するソースコードも**後から何の役にも立たないです**。
結局サービスローンチ時までは開発できるので、納品日というのはただの一つの儀式みたいなもので大分形骸化しています。

# サービスローンチ日前後

**全然普通に開発してます**。
機能によってはローンチ後の翌月に初めて使われる機能とかもあるので、そういうのはローンチ後も普通に開発して、「バグ改修」という名目で後からリリースします。

# プロジェクトを終えてエンジニアが思うこと

**今から一から作り直したい**
ferenOSの導入５（プリンタ、スキャナとの接続、導入）

ferenOSで、プリンタとスキャナを使えるようにしたいと思います。

今回、検証したのは、EpsonのPX503-Aというプリンタとスキャナがセットになっている機種です。
パソコンとプリンタとの接続は家庭内の無線LANで行いました。USBケーブルなどでの接続方法での導入の仕方は、これとはまた違ったものになるかもしれません。
##プリンタを接続
1.プリンタを起動して、無線LANにつなぐ。
2.「KDEシステム設定」アプリケーションを起動させ、「System」>「プリンタ」と開く。
「プリンタ」モジュールが開くので、「追加するプリンタを選択」のなかから、「Discovered Network Printers」にある自分が設定したプリンタの機種を選択する。（ここではEPSON PX-503A)選択したら、Nextボタンで先に進む。
3.「ドライバを選択」となるので、任意のドライバを選択する。（結構種類があります。おそらく、有志が開発したものでメーカーが開発したものではないと思いますが・・・。まさかこの機種もあるとは・・・）
4.「Please describe your printer」と続くので、適当に設定したあと「finish」ボタンで設定完了

無事、テストページが印刷できました。

##スキャナの導入
エプソンのLinuxドライバダウンロードページ:[http://download.ebz.epson.net/dsc/search/01/search/](http://download.ebz.epson.net/dsc/search/01/search/)からインストールに必要なファイルを検索してダウンロードします。
ここでは、スキャナドライバの"iscan-bundle-2.30.4.x64.deb.tar.gz"をダウンロード

**インストールは次のコマンドを使用**
`tar xaf iscan-bundle-2.30.4.x64.deb.tar.gz`
`cd iscan-bundle-2.30.4.x64.deb`
`./install.sh`

他にも、core,data,pluginsフォルダ内のdebファイルをdpkgコマンドを使ってインストールすることもできます。
例：coreフォルダ内のdebファイルなら・・・
`dpkg -i iscan-$ver-$rel-$arch.deb`
ここでは
`dpkg -i iscan_2.30.4-2_amd64.deb`
pluginsフォルダの中には、ネットワークの設定に関するdebファイルが入っていて、ネットワークを使わない環境（USB接続）なら
ネットワーク設定のプラグインはインストールしないといった細かい設定ができるようです。
ただし、install.shでもオプションで設定できます。あまり使わないと思います。

**install.shのオプション：**
`./install.sh --help`ヘルプの表示
`./install.sh --dry-run`instal.shによってインストールされるパッケージ(gimpがインストールされます。）
`./install.sh --without-network`ネットワークプラグインを導入しない
`./install.sh --without-network`OCRエンジンを導入しない

インストール後、/etc/sane.d/epkowa.confを編集します。（ネットワーク接続をするとき）
`sudo vim /etc/sane.d/epkowa.conf`
同設定ファイルの52行目にを次のように挿入

```conf:epkowa.conf
net 192.168.2.5 1865
#任意のローカルIPアドレスとポート番号1865（省略可）
```

おおまかな設定は完了です。
`iscan`で実行すると、ぶじに起動できました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/535888/42d33e1d-6b6e-3dcb-ae30-17ac971325b1.png)
SandBoxをふんわり調べてみたよ。


## はじめに
サンドボックス備忘録。

iOSの**App Groups**について調べていく中で

- **サンドボックス**
- **Keychain sharing**
- **App Extentions**

の3つが結構な頻度で出てきました。
自分的によく分からないことだらけだったので見返せるように。
また、間違ったイメージで捉えているかもしれないので正してくれる方がいれば幸いです。


## 一般的なサンドボックス説明


以下、[「サンドボックスとは？セキュリティを向上の仕組みと弱点」](https://japan.norton.com/sandbox-9246)から引用


>サンドボックスを直訳すると、「砂場」という意味になります。
子供が安全に遊べるように砂場が設けられているのと同じように、
コンピューター上に砂場のような仮想空間を設け、
サンドボックス内での動作がサンドボックスの外側に影響を与えないようにする仕組みのことです。

ふーん。

外側に影響を与えない、外側から干渉できないってことなのでしょうか。
App Gropsではこのサンドボックス領域とは別に共有できる領域を使えるということが
機能の概要として説明されていたのでそういうことなのかなと。


#### 誰か教えてください。（他力本願）


セキュリティ的に「シグネチャ」というのが
今までのデータに基づく攻撃を防ぐのに対して
サンドボックスは動作させた上でそのプログラムが危険かどうかを判断する…といったような説明でした。

## iOSのサンドボックス

同じく以下、「サンドボックスとは？セキュリティを向上の仕組みと弱点」から引用

>iOSのサンドボックスは隔離された空間として用意されており、
インストールされているアプリはサンドボックス内で動作します。
そのためアプリから生成された保存データもサンドボックス内に保存され、外部とは隔離されます。


おーん。

iPhone向けのマルウェア対策のセキュリティアプリがないのは
サンドボックス内に隔離されているデータにアクセスすることができず
ウイルススキャンできないためのようですね。

## 最後に

軽くイメージだけつけようと思って調べてましたが
簡単に分かるとか銘打った記事を読んでも結局ふんわりした理解にしか落ち着けませんでした。
手の空いた時にもうちょっと調べて更新できればと思います。

### ~参考サイト~
[「サンドボックスとは？セキュリティを向上の仕組みと弱点」](https://japan.norton.com/sandbox-9246)
(ギリ)20代の地方公務員がRailsチュートリアルに取り組みます【はじめに】

著者の現ステータスはタイトルどおり。
自分の置かれている状況を再確認し、自分の目標を明確にするために、まずは自分語りから始めるよ！！！

##【前提】
・これはRailsチュートリアル（第4版）を進める際の個人的なアウトプットメモです。
・著者は全くの初学者です。タイトルから分かるとおり、現職は全く関係ない職種（IT・Webとは正反対と言っていいかも）で、大学等も全く関係ない学部を卒業しています。間違い・不適切な内容があってもご容赦ください。
・初学者といいつつ、[こちら](https://ryosukemizuta.com/rails_tutorial/#2)の記事を参考に、Progateは一通り学習し、本チュートリアルもすでに2周しています（教えに従い9~14章は2周目からチャレンジ）。でも、正直全然理解できていない…テスト書ける気しない……な状態です。
・3周目となる今回は、過去2周で理解できなかった部分を掘り下げていきながら、極力自分の手と頭を使って取り組んでいきます。IT・Web等の情報技術の用語にも疎いので、都度都度調べながら進めていきます。

##なぜRailsチュートリアルをやるのか
・自分の力で生きるためのスキルを身に付けたい
・「作り手側」にまわりたい（受け身な現職から、能動的な働き方へ）
・時間・場所に囚われないライフスタイルを手に入れたい
・今の世界を支えているのはIT・Webや！おれも使いこなせるようになりたい！（安直）
⇨結果：**Webエンジニアを目指そう！**

・・・なんでITじゃなくてWebか。働き方に余裕がありそう（勝手なイメージ）なのと、そっちの方が**カッコ良さそう**だから。

⇨行動：
スクール入ったほうが手っ取り早いかな。自分を追い込めるし。
→お金がもったいないから、自分で勉強できることはやってからにしよ。
→progateを一通り学習。どの言語がええんやろ。
→スクールで手厚く教えてるのはRailsか〜。やったらRailsチュートリアル終わらしてからスクール入ろ。**（←イマココ）**

という状況です。

##なぜ（安定身分の）公務員から転職したいのか
　はっきり言って、今の職場を強烈に辞めたい！！と思う気持ちはありませんでした。なんなら、将来安泰（と世間一般に思われる）の公務員という身分に対し、手放すのが惜しいなという気持ちも何カケラか残っています。それでもなぜ転職を図っているのか。その理由を整理します。

**・この先のキャリアを考えたとき、今後も続けていきたい・掘り下げていきたいと思えなかったから（とある技術職です）。**
　自分のやりたいことって、これか？？続けていきたいか？？という現況。大学の学部から流れで関連する職種に就いたわけですが、しっくりきていないというのが本音。

**・世の中の流れ・最先端の技術に取り残されていっている環境に、身を置いていることがもどかしくなってきたから。**
　一口に公務員といっても様々ですが、少なくとも私が働く職場は、最新テクノロジーとは無縁の世界。もっといろいろなシステム・ソフトを使えば、働き方を変え、業務効率を向上させられるのにな〜と思う毎日。そしてそれを自覚していない周りの職員たち（特に上の世代の人たち）。なんだかな〜。

**・利潤追求・コスト意識の欠如から醸成される向上心の低さ、変化への消極姿勢に嫌気が差してきたから。**
　上とも被りますが、この（民間との）違いはきっと大きい。本当は公務員こそ、国民のために最も利潤追求・コストカットを目指すべきだと思うのですが。はっきり言うと、リストラが無いぬるい環境ゆえに、切迫せず、向上心が削がれていく・忘れていくんだと思う。本当にどうしようもない職員が（ごく一部ですが）本当に存在します。自分はそんな環境に身を置いていていいのか？？
　仕事に何を求めるかは人それぞれだけど、向上心を忘れて、ただぬくぬくと生きられる金銭を得るためだけに、本当に自分が心から望むことを忘れて（無視して）いいのか。それでは生きながら死んでいるも同然だ、というのが最近の思いです。絶対、将来後悔するだろう。であれば挑んでいく道を選びたい。
　そういえば、転職理由をスプレッドシートにまとめたときに書いたポエムがあったことを思い出したので、恥を忍んで載せておきます。

*今の職場に居ては、10年後、20年後に自分のキャリアに対して、絶対に後悔すると確信したから。生きながら死んでいるようなもの。このままここに居ては、真綿で首を締められながら、ゆっくりゆっくり殺されるようで、でもそのことに気付かない、むしろ心地よささえ感じるような、そんな見えない恐怖がここにはある。*

##まとめ
・圧倒的成長を！圧倒的やりがいを！
・手に職つけてえ！！
・ス○バでドヤァ顔mac！
・挑んでいけ！自分の限界に！！
・世界的ですもんね　乗るしかない　このビッグウェーブに

次回以降、第1章から順番に取り組んでいきます。
今回はこのへんで。

⇨　[第１章へ！](https://qiita.com/t-kawamura1/items/26729ad3969f61c4af76)