OmniAICreator/Qiita-1.07M huggingface dataset:
[Rails,位置情報] activerecord-mysql2spatial-adapterの使い方

静岡市でフリーランスでWeb開発しているkazuomatzです。

Rails + MySQLで位置情報を扱う需要は、少なからずあるかと思います。

Rails + MySQLで位置情報を扱う場合、[activerecord-mysql2spatial-adapter](https://github.com/rgeo/activerecord-mysql2spatial-adapter)が定番のGemかと思うのですが、このGemの開発が止まっていて、Railsのバージョンアップのたびに、有志の開発者の方が本家からBranchしたバージョンを独自リリースしている状態というエントリーを[記事](https://qiita.com/kazuomatz/items/884c7b5e64a3b7532204)にしたのですが、あまり反響がなかったので、そういう需要はもはやないのかなと思っておりました。

そんな中、この記事を見た方から、そもそもactiverecord-mysql2spatial-adapterの使い方がまとめれているところがあまりないという問い合わせがあったので、簡単に書き留めておきます。

[こちらの記事](https://qiita.com/kazuomatz/items/884c7b5e64a3b7532204)に、Rails 4.2, 5.0, 5.1, 6.0に対応したGemfileの書き方を記述してあります([Rails6.0](https://github.com/kazuomatz/activerecord-mysql2spatial-adapter/tree/rails-6)の対応については、僕がやりました)。こちらを参照にGemfileを記述して、bundle installします。


# config/database.yml

adapterをmysql2spatialにする。ここがポイントです。

```config/database.yml
default: &default
  adapter: mysql2spatial
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: xxxx
  password: xxxxx
  socket: /tmp/mysql.sock
 :
 :
 :
 ```

# マイグレーションファイル

位置情報を含むモデルを作成するためのマイグレーションファイルです。
t.point (t.geometry でもOK）型として宣言します。nullは許容しないようにします。
また、インデックスを作成する場合は、spatial: trueとします。

MySQL 5.6以前の場合、spatial: trueの指定をする場合は、ストレージエンジンがMyISAMである必要があります。MySQL 5.7以降であればInnoDBでＯＫです。

```db/migrate/xxxxxxxxxxxxx.rb
class CreateLocations < ActiveRecord::Migration[6.0]
    def change
	    create_table :locations do |t|
        t.string :name, comment: 'スポット名称'
        t.point :geom, null: false, comment: '緯度経度'
    end
    add_index :locations, :geom, spatial: true
end

```

# Pointクラスを作る
Geometry型に緯度経度を設定するために便利なPointクラスを作っておきます。

```Point.rb
# Geometry型に緯度経度を設定するためのPointクラス
class Point
	def self.from_x_y(x, y)
		x.present? && y.present? ? "POINT(#{x} #{y})" : nil
	end
end
```

# 緯度経度の設定と参照

あとは、以下のようにすれば、設定と参照が可能になります。

```location.rb
location = Location.new
location.name = '東京駅'
location.geom = Point.from_x_y( 139.767125, 35.681236 )
location.save!

# 緯度経度参照
p location.geom.x   # -> 139.767125
p location.geom.y   # -> 35.681236
```


# 2023年9月更新

ことの発端は、AWSのRDSがMySQL5.7を年内にサポートを打ち切りにするという話から。
これまで、いろいろなWebサービスをactiverecord-mysql2spatial-adapterを使って開発してきましたが、MySQL5.7をいよいよMySQL8.0に移行する必要が出てきました。

Rails6.0については、[こちらに書きました](https://qiita.com/kazuomatz/items/884c7b5e64a3b7532204)が、[本家](https://github.com/rgeo/activerecord-mysql2spatial-adapter)から[forkさらたリポジトリ](https://github.com/sebastianiorga/activerecord-mysql2spatial-adapter)をさらに[forkして](https://github.com/kazuomatz/activerecord-mysql2spatial-adapter)何とか対応した経緯があります。

今回、Rails4.2、Rails5.0、Rails5.1で開発されたプロジェクトのデータベースをMySQL8.0に移行して検証したら、位置情報系のカラムの参照や更新でエラーが発生することが判明しました。

```
Mysql2::Error: FUNCTION some_scheme.GeomFromWKB does not exist.
````

この件については[こちら](https://qiita.com/kazuomatz/items/6954bfba1fb1ae837c27)に詳しく書きました。
RubyでLeetCodeを解いてみた Two Sum

https://leetcode.com/problems/two-sum/


>Given an array of integers, return indices of the two numbers such that they add up to a specific target.

>You may assume that each input would have exactly one solution, and you may not use the same element twice.

```
Example:

Given nums = [2, 7, 11, 15], target = 9,

Because nums[0] + nums[1] = 2 + 7 = 9,
return [0, 1].
```

意外とむずいよね

```ruby
# @param {Integer[]} nums
# @param {Integer} target
# @return {Integer[]}
def two_sum(nums, target)
    nums.each_with_index do |num, idx|
        x = target - num
        if num == x
            y = nums.rindex(x)
            next if idx == y
            return [idx, y]
        end
        y = nums.index(x)
        next if y == nil
        return [idx, y]
    end
end
```

一応通りましたが、酷いコード😇
[MySQL][java]日時を受け取る

##概要
MySQLに登録された日時をjavaで取得する方法、javaからMySQLへ日時を登録する方法を紹介する。
MySQLへ接続する方法はこちらを見て頂きたい。https://qiita.com/QiitaD/items/d605b07e849e3bec0722

##MySQLに定義する列
日時をtimestamp方で定義する。列名は"date_time"、フォーマットは"yyyy-MM-dd HH:mm:ss"である。

##MySQLからjavaでの取得

~~~java
    String mySql = "select * from table_name";//日時のあるデータを取得するSQL文
    ResultSet rs = stmt.executeQuery(mySql);  //SQL実行、データを取得
    while (rs.next()) {
        rs.getTimestamp("date_time");         //取得データから日時情報を取得
    }        
~~~

##javaからMySQLへ日時を登録する
例として現在時刻を登録する。

~~~java
    String mySql = "insert into table (date_time) values ('" + getNowDateTime(){ + "')";
    stmt.executeUpdate(mySql);
~~~

~~~java
    /**
     * 現在日時をyyyy/MM/dd HH:mm:ss形式で取得する.<br>
     */
    public static String getNowDateTime(){
        final DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        final Date date = new Date(System.currentTimeMillis());
        return df.format(date);
    }
~~~

現在時刻取得方法はこちらを参照した。https://qiita.com/zuccyi/items/d9c185588a5628837137

##困ったところ
困ったというほどではないが、初心者の方に向けて注意点が2つある。
①SQLの実行文
selectでデータを取得するときはexecuteQueryだが、updateやinsert、deleteの時はexecuteUpdateである。

②シングルクォーテーション
忘れやすいが、今回のサンプルでは日時を'(シングルクォーテーション)で囲まなければならない。

上記2つは私が超初心者時代によく躓いていたので気を付けて頂きたい。

##感想
本記事では日時の扱い方として一例を紹介したが、日時には方が様々なので他にも使い方がある。（DateやLocaleDateTimeなど）
型を変えると変換が面倒になったりするので、よく考えて使いたい。

##参考URL
日付と時刻型
https://www.dbonline.jp/mysql/type/index4.html

timestampとdatetimeの違い
https://qiita.com/ykawakami/items/2449a24e3b82ff0cbab6

timestampの例外
https://ts0818.hatenablog.com/entry/2017/08/11/155011
【TypeScript】ランダムにカラーコードを生成する

`#000000`～`#ffffff`のカラーコードをランダムに生成する関数。

```ts
export const randomColor = () => {
  return "#" + [0, 1, 2, 3, 4, 5]
    .map(_ => Math.floor(Math.random() * 0x10).toString(16))
    .join("");
}
```
`Math.floor(Math.random() * 0x10)`で0～15の乱数を生成して`toString(16)`で16進数文字列に変換。
その処理を要素6つの配列の中で行い6つの16進数文字列を取得する。
最後に`join("")`で結合して"#"とも結合して返却する。

for文を使わず読みやすいかと思います。
Symfony4.4 パスワード変更フォームでパスワードの確認エリアを作成する

# 課題

Symfonyのフォームで、以下のようなパスワードを設定する場合に、再度パスワードを入力させる確認用のテキストフィールドを作りたい。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/133291/8313cfc0-b39d-28bc-c5ca-2139aeee97a2.png)

# TL;DR

ずばり、フォームタイプとして、[RepeatedType Field](https://symfony.com/doc/4.4/reference/forms/types/repeated.html)が用意されている。

これは指定するフォームタイプ。例えば、テキストフィールドとか、パスワードフィールドを2つ用意してくれる。

ちょうど[サンプル](https://symfony.com/doc/4.4/reference/forms/types/repeated.html#example-usage)がそのまんま使えてしまう。

```php
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\Extension\Core\Type\RepeatedType;
// ...

$builder->add('password', RepeatedType::class, [
    'type' => PasswordType::class,
    'invalid_message' => 'The password fields must match.',
    'options' => ['attr' => ['class' => 'password-field']],
    'required' => true,
    'first_options'  => ['label' => 'Password'],
    'second_options' => ['label' => 'Repeat Password'],
]);
```

# 感想

Symfonyの便利機能を発掘するためには、検索キーワードの選択が重要ですね。
Vue.jsとVuexで編集formのdataにstateをコピーして同期させずに使いたい

参考
[[Vue] Storeのstateをコンポーネントのローカルstateにコピーする](https://scrapbox.io/gyarasu/%5BVue%5D_Store%E3%81%AEstate%E3%82%92%E3%82%B3%E3%83%B3%E3%83%9D%E3%83%BC%E3%83%8D%E3%83%B3%E3%83%88%E3%81%AE%E3%83%AD%E3%83%BC%E3%82%AB%E3%83%ABstate%E3%81%AB%E3%82%B3%E3%83%94%E3%83%BC%E3%81%99%E3%82%8B)
[How can I clone data from Vuex state to local data?](https://stackoverflow.com/questions/52581488/how-can-i-clone-data-from-vuex-state-to-local-data)


## 結論

```js
this.formData = JSON.parse(JSON.stringify(this.stateData))
```
## 問題提起

Vue.jsとVuexを使っていて編集formを作っている時に
Vuexのstateから取り出したデータをcomponentのdataオプションに渡して
dataをv-modelでbindして編集してみた。

すると

dataのオブジェクトをbindしたはずが
stateのオブジェクトも一緒に同期して編集されてしまった。

### …後で追記する。

- 1つずつ代入していたエピソードとコード
- 実際の利用例
- 解説
SQLLDRのコントロールファイルをBATファイルに含める方法

## ファイル数が多いのが嫌だ
* OracleのSQLLDRをバッチファイルで実行するとき、CONTROL=オプションでコントロールファイルのパスを指定します  
対象テーブルが増えてくると、実行用のバッチファイル、コントロールファイル、入力データとファイルの数がどんど
ん増えていきます
* そこで、バッチファイルとコントロールを一つのファイルにできないかということ

## 基本的な構造
1. ファイル名の拡張子は.batにします
  拡張子を.batにすることによってダブルクリックでバッチファイルとして起動します
1. CONTROL=で自分自身を読み込むようにします  
  `SQLLDR CONTROL="%~f0"`
  と指定すると自分自身をコントロールファイルとして読み込みます  
1. バッチファイルとして実行する部分はSQLLDRにとって無視できるようコメント行になるようにします  
  `-- 2> NUL & SET NLS_LANG=japanese_japan.ja16sjis`  
  のように書くと、SQLLDRにとっては無害なコメント行で、
  バッチファイルとしては、-- がエラーになるけれども、エラーメッセージはNULにリダイレクトすることによって
  メッセージ出力が抑止され & のあとに記述してあるコマンドが実行されます
1. バッチ部分の最後はEXITを実行するようにすれば以降の行はバッチファイルとしては無視されます  
  `-- 2> Nul & PAUSE & EXIT /b`
  
## 実際の例
  こんな感じで書けます  
  この例では入力となるデータファイルもコントロールファイルの一部として組み入れています
  
```DOS:ORA_SQLLDR.BAT
-- 2> Nul & @ECHO Off & CLS
-- 2> Nul & SET Path=%Path%;C:\Program Files\instantclient_12_2
-- 2> Nul & SET NLS_LANG=japanese_japan.ja16sjis
-- 2> Nul & sqlldr user/pass@HOSTNAME:1521/pdb1 SKIP=1 CONTROL="%~f0"
-- 2> Nul & PAUSE & EXIT /b
-- ここから SQLLDR コントロールファイル
LOAD DATA
INFILE *
TRUNCATE
INTO TABLE SAMPLE_TBL
WHEN VC1 != '--'
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' TRAILING NULLCOLS
(
SEQ 	SEQUENCE(MAX),
VC1,
FL1 	FILLER,
VC2	":VC1 || :VC2",
DT1	"TO_DATE(:DT1, 'yyyy/mm/dd hh24:mi:ss')",
FL2	FILLER,
DT2	"TO_TIMESTAMP(:DT2, 'YYYYMMDDHH24MISSFF')",
NO1 
)
-- ここからロードデータ
BEGINDATA
VC1,FL1,VC2,DT1,FL2,DT2,NO1
AA,FILLER,"B,B",2020/1/1  23:59:59,Filler,20200125010203123456789,9999 
--,FILLER,"B,B",2020/1/1  23:59:59,Filler,20200125010203123456789,9999 
CC,FILLER,"D,D",2020/2/29 23:59:59,Filler,20200229010203123456789,
```

## 実行結果
![SQLLDR.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/477637/24ba3c6d-8630-25d8-021b-b65fea1ad657.png)
Genymotion でPlayerが起動しない"The virtual device got no IP Address"




# 起こったこと

Androidの開発でEmulatorとして、Genymotion を使用しているが、
Player を再起動しようとすると、
よく以下エラーで起動しなくなる:

(今回の事例は、すでに何回か起動はしている状況)

```
The virtual device got no IP Address
```

どうやらPlayer 終了時に使用IP アドレスの管理が上手くいってないようだ。


# 解決法


基本的にはエラー通りにIP Address が使用されている(busy)のようなので
その使用されているIP アドレスを解放(使用プロセスをKill)してやればよいようだ。


すでによくあるエラー事例のようだが、
以下は私の環境でのうまく行く方法。

## Cache 削除
Player 終了後、再度起動できない場合は、以下でCache を削除してみる。
Genymotion本体 の `Settings ->Mics -> Clear Cache`

## プロセスを直接Kill
それでもだめなら、プロセスを直接Kill する。

今回の場合、MacOS付属のActivity Monitor から Java というプロセスを指定し、Force Quit などする。

## 占有Port指定でKill

VirtualBox の設定によるが
`http://127.0.0.1:8181` など8181 port 指定してプロセスを探し、それをKillする。

(`How to find and kill a process running on a port` で検索)



## 再起動
PC やGenymotion を再起動すれば、大抵の場合また起動するようになる。


# 環境
Android Studio 1.5
MacOSX Yosemite 10.10.5
Genymotion 2.12.2


# 参考 (他の事例)

初期設定の問題などは以下

https://stackoverflow.com/questions/29008767/genymotion-the-virtual-device-got-no-ip-address

https://stackoverflow.com/questions/36436253/genymotion-the-virtual-device-got-no-ip-address
jQueryで動的にcloneした要素にプラグインを適用したい

# 背景とか

jQueryで`clone(true)`すれば、全ての要素が引き継がれるとどこかで書いてありましたが、できなかった。そのための備忘録として。

## 対応

`each`を使って、プラグインを適用する。

```js
let clone = $('selector');
clone.each(function (idx, obj) {
  $(obj).hogehoge();
});

// 子要素に適用したい場合
clone.find('.fuga').each(function (idx, obj) {
  $(obj).hogehoge();
});
```
Vimのquickfixリストに目印を付ける vim-quickfixsync プラグインを作成した

# はじめに

僕は普段は[vim-lsp](https://github.com/prabirshrestha/vim-lsp)を導入しているのですが、とある事情でDartを書く時だけは[LanguageClient-neovim](https://github.com/autozimu/LanguageClient-neovim)を使っています。
~~しかしバグなのか、Diagnosticsからsignへの反映がたびたびズレる現象が発生していたため、これを解決する為のプラグインを作成しました。~~
**修正されました。**

[wordijp/vim-quickfixsync](https://github.com/wordijp/vim-quickfixsync)

用途としては

- quickfixリストを利用しているLSPプラグインの目印ズレを修正
- LSPプラグイン未対応の目印の種類を追加する[^1]
- QuickRunの結果に目印を付ける

[^1]: 例えば、LanguageClient-neovimではsignしかつかないが、このプラグインでtextpropを追加する

などが挙げられます。
なお、quickfixリストを使っていないvim-lspではこのプラグインは機能しません
(そもそもズレないので必要にならない)。

# デモ

QuickRunでC++のmakeをした時の様子です、quickfixリストの内容をsignとtextpropへと反映しています。

![demo_quickrun.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51728/e236dd5f-417c-68bc-6858-2119ea950f16.gif)

textpropをワード単位で設定したかったのですが、[getgflist](https://vim-jp.org/vimdoc-ja/eval.html#getqflist())(or [getloclist](https://vim-jp.org/vimdoc-ja/eval.html#getloclist()))のデータには行(lnum)と列(col)しかない為、最初の一文字だけの設定としています。
GCCではデモのように対象ワードを注釈として返してくれてるんですが、これを組み込むのは恐らくコーナーケース対応になるのでどうしようかってところです。

# 使い方

デフォルト設定で動きますので、vim-plugをお使いの方は以下をvimrcに追加して`:PlugInstall`でインストールするだけで動きます。

```vim
Plug 'wordijp/vim-quickfixsync'
```

カスタマイズ設定はREADME.mdをご覧ください。

# おわりに

LSP発展の過渡期故の産物ですが、必要な方はお使い下さい。
[vba vbs cmd tool] 【超便利ツール】Excelの所在ディレクトリ、ファイル名を簡単に表示させ、Copy及び開く

#簡単な手順
##１．手動にて下記のようにイメージでフレームを作っておく。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/509696/fabfd585-89ff-f700-15f1-76c150e1fad0.png)

##２．サンプルコード

```vb
Private Sub CommandButton1_Click()
    Call SetTextToClipboard(TextBox1.Text)'※
End Sub

Private Sub CommandButton2_Click()
    Call SetTextToClipboard(TextBox2.Text)'※
End Sub

Private Sub CommandButton3_Click()
    Call ExecuteCMD("cmd /c explorer " & TextBox1.Text)'※
End Sub

Private Sub UserForm_Initialize()
    TextBox1 = ActiveWorkbook.path
    TextBox2 = ActiveWorkbook.Name
End Sub
```
[※参照先](https://qiita.com/JustsuQ/items/66696581567c482609bb)
ネットが遅い

自宅のインターネットが極端に遅かったのでいろいろ調べました。ネットのスピートチェックはgoogleのものや[fast.com](https://fast.com)などがあります。

一般の家庭では以下のような構成になっていると思います。

![NETSPEED.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/8141be96-ab45-8b42-6c9a-506dee97d822.png)

PCブラウザでのスピードチェックすると数字はaのISPとの契約の10Mとか100Mとかになるはずです。

ところがMac mini 2010の内蔵のAirMacからWiFi Routerに接続すると2Mくらいしか出ません。Windows 7のマシンも同じような状態です。a > bな状態です。有線でつなぐと10Mちゃんとでます。WiFi Routerが10年以上前の11n draftの初期のものなのが原因である可能性はあるのですが、Mac Book Air Originalだと10M近くでます。

このことから上の図のbに問題があることになります。WiFiはこういう相性の悪いケースがあるようです。

結論を書くとMac miniのAirMacを使うのをあきらめてEthernetにWiFi Converterをつないだら契約の10Mになりました。これでa < bになりました。

![スクリーンショット 2020-01-17 15.09.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104066/d02e8875-05ef-e7ba-82af-0ec285d0bfcb.png)

Routerを変えるのも試してみたのですが、ネットワークがいろいろ不調になり、Routerを戻してたまたま手元にあったConverterを試したら、うまくいきました。時々起動後に遅い時があるのでfast.comで確認してConverterを再起動すると直ります。

後日追記 2020/3：ISPが10Mから40Mに帯域を広げてくれて、その結果FASTでは28Mbpsくらいでるようになりました。Routerが遅い可能性があり取り替えたところ30Mpbsを超えられるようになりました。40MpbsにならないのはRouterの問題かISPの問題かは不明です。

自宅内のボトルネックを探すのにiperf3で確認するのも有効な手段です。
Capybaraでtrタグのtdタグを指定してテストする方法

# はじめに
`tr`1行目の`td`3番目と指定したいときに悩んだんで備忘録として残しておきます。

# よく見かけるやつ
```xxx_spec.rb
all('tbody tr')[0]
# tbodyの中の一行目のtrを取得する

all('tbody td')[0]
# tbody中から、tdの一つ目を取得する
```

上記のコードを自分はよく使ってます。
ただ、`日付`を`each`でまわして`table`を作成したときに、`n番目のtd`を取得したいときに問題発生。
1月時点で1行目のみテストする場合は問題ないですが、`tr`の2行目に`td`要素があるかどうかみたいなとき、
1月は31日までなので、２行目まで数えようとしたら、`all('tbody td')[32]`のようにわざわざ要素を数えて、みたいなことしてると3行目の`td`数えるとかしんどーー！！ってなります。
ちなみに、こういう場合月によって末日が変わるので、`travel_to`でテストを書く日付を固定しないといけなくなるので良くないかもしれないです。

# 実装
```xxx.html.haml
%table
  %thead
    %tr
      %th 名前
  %tbody
    %tr
      %td てつお君
      %td ひろみちゃん
    %tr
      %td まさし君
      %td ひろたか君
```
上記のような`table`がある場合、`ひろみちゃん`を取得したい場合はこれだけでいけます。

```xxx_spec.rb
# trの1行目取得
tds = all('tbody tr')[0].all('td')
expect(tds[1]).to have_content 'ひろみちゃん'

# trの2行目のまさし君取得
tds = all('tbody tr')[1].all('td')
expect(tds[0]).to have_content 'まさし君'
```
これでテスト完了です。
ちなみに、`('tbody tr')`の`tbody`としてるのは、`thead`の部分のテストは不要だったので書いていません。
このあたりはご自身が取得されたい要素によって使い分けてもらえればと思います。

# まとめ

ひたすら数えたりとかすることの手間がこれで省ければと思います。
WSLでElixirを使ってみる　～インストール編～

#はじめに
にゃんぱすー！
駆け出しプログラマーのこっぺぱんです
とある先輩からElixirを勧められて、ちょっとはじめてみたんですが、Elixir、記事が少ない(´;ω;｀)
ということで、同じようにちょっとElixirはじめてみようかなと思った初心者のかたの助けになればいいな。と思って記事を書いてみます！
はまり方が初心者のそれなので、全然役に立てないかもですが．．．
いろいろはじめてなので、間違いとか指摘してもらえると嬉しいです☻

#環境
64bitのwindows10
WSLのバージョンはubuntu18.04

#さっそくインストール！
よし、準備は整った！と思いさっそくコマンドを打ち込む
 
```
$ sudo apt install elixir
```
．．．あれ？なんか挙動がおかしい

```
$ elixir -v
elixir: command not found
```

はい。いきなりインストールはだめでした。
まだCUIに慣れてないから全然ですね．．．

#ちゃんと公式のページを見て、再度挑戦
https://elixir-lang.org/install.html
英語で書いてあるからって逃げちゃだめだ。
全部載ってました。
書いてある通りに順にやっていきます。

```
$ wget https://packages.erlang-solutions.com/erlang-solutions_2.0_all.deb 
&& sudo dpkg -i erlang-solutions_2.0_all.deb
$ sudo apt-get update
```
順調順調


．．．あれ？

```
$ sudo apt-get install esl-erlang

Reading package lists... Done
Building dependency tree
Reading state information... Done
Some packages could not be installed. This may mean that you have
requested an impossible situation or if you are using the unstable
distribution that some required packages have not yet been created
or been moved out of Incoming.
The following information may help to resolve the situation:

The following packages have unmet dependencies:
 esl-erlang : Conflicts: erlang-base-hipe
              Conflicts: erlang-crypto
              Conflicts: erlang-syntax-tools
E: Unable to correct problems, you have held broken packages.
```
なにやらはじめに間違えたインストールのせいで、不具合が生じたようです。
「E: Unable to correct problems, you have held broken packages.」でググったら出てきた
[こちらの質問](https://unix.stackexchange.com/questions/389156/how-to-fix-held-broken-packages)を参考にさせていただき、下記のようにコマンドを打てば問題なく進みました。

```
$ sudo apt-get purge 'erlang-base-hipe'
$ sudo apt-get purge 'erlang-crypto'
$ sudo apt-get purge 'erlang-syntax-tools'
$ sudo apt-get update
$ sudo apt-get install esl-erlang
```


#確認してみた
そのあとのもろもろの処理は、たいして問題も起こらずに終わったので、とりあえずElixirが入ってるかどうかの確認を

```
$ elixir -v
Erlang/OTP 22 [erts-10.6.2] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [hipe]
Elixir 1.9.4 (compiled with Erlang/OTP 21)
```
これは、先ほど失敗していたErlangも問題なく入っているみたい．．．？
とりあえずはよさそうです。
#さいごに
いまいち大丈夫なのかわからなかいのですが、とりあえずはインストールできたことかと思われます。
次からは突然インストールするのはやめるべきです（なかなか解決策わかんなかった．．．）
また触っていくなかで不具合があったら記事を書き直すかもしれませんが、今日はこの辺で。
ばいにゃら～
間違って/usr/local/bin/にあるpythonインタプリタを削除してしまったときの解決策。

# はじめに

わたしの開発環境はLinux(Ubuntu)なのですが突然`apt`コマンドが使えなくなり、エラーを確認したところpythonのライブラリに原因があることが判明しました。いくつかエラーが出ており、うろ覚えですが主な原因は`python3-apt`だったと思います。３０分ほど試行錯誤しましたが駄目だったので次のやり方で入れ直しました。


# 参考

[こちらがとても参考になりました！](https://amzn.to/2XNA4eK)


#やり方

https://www.python.org/downloads/source/
ここから削除したpythonインタプリタを見つけて`Gzipped source tarball`からダウンロード。

あとはREADME通りにインストールすれば良い。

```:インストール手順
1. ターミナルを開く
2. ./configure
3. make
4. (make test)
5. sudo make install
```
AIDL通信

①IPC通信なので、送信側はMainThreadですけれど、
受信側はMainThreadではなく別すれどである。
②AIDL通信で送受信側のスレッドは別々ですけれど、
AIDL通信は同期処理です。
例えば、APPからServiceの処理を呼んだ時、Serviceの処理が終わるまで、APPがずっと待っている。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/257905/d17544a5-f0c5-1493-af2b-f3609bf837fb.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/257905/97f5b2f8-b4ee-3e6f-e7eb-1db3af957a80.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/257905/00b535a7-57af-afba-f02b-cad84fe603ef.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/257905/b744ecab-4b33-b970-ce60-996e8fae84d8.png)
Java合併 & マージを解除Excelセル

本論文では、どのように使うかを紹介しますSpire.XLS for Java Excel Java合併 & マージを解除Excelセル

使用ツール： [Free Spire.XLS for Java無料版](https://www.e-iceblue.com/Introduce/free-xls-for-java.html)

Jarファイルの取得と導入：

Method 1：ホームページを通じてjarファイルのカバンをダウンロードします。ダウンロード後、ファイルを解凍して、libフォルダの下の[Spire.xls.jar](https://www.e-iceblue.com/Download/xls-for-java-free.html)ファイルをJavaプログラムに導入します。


Method 2：[maven倉庫](https://www.e-iceblue.com/Tutorials/Licensing/How-to-install-Spire.PDF-for-Java-from-Maven-Repository.html)設置による導入。


合併Excelセル

Spire.XLSにおいて, 私たちは通過できます worksheet. getRange().get().merge()方法でセルの行と列を結合します。

```java

import com.spire.xls.FileFormat;
import com.spire.xls.Workbook;
import com.spire.xls.Worksheet;

public class MergeCells {
    public static void main(String[] args){
        // Workbookの作成例
        Workbook workbook = new Workbook();
        // Excelドキュメントを読み込む
        workbook.loadFromFile("Test1.xlsx");

        //最初のシートを取得
        Worksheet sheet = workbook.getWorksheets().get(0);
        //セル範囲A 1からC 1を結合
        sheet.getRange().get("A1:C1").merge();
        
        //結果ドキュメントを保存
        workbook.saveToFile("MergeCells.xlsx", FileFormat.Version2013);
    }
}
```
![Merge Excel cell.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278784/47b112cd-5748-0cf7-62d4-994d9090a35b.png)


セルの結合を解除

Spire.XLS同時に提供しましたworksheet. getRange().get().UnMerge()方法でセルの結合を解除します。

```java

import com.spire.xls.FileFormat;
import com.spire.xls.Workbook;
import com.spire.xls.Worksheet;

public class UnmergeCells {
    public static void main(String[] args){
        // Workbookの作成例
        Workbook workbook = new Workbook();
        // Excelドキュメントを読み込む
        workbook.loadFromFile("MergeCells.xlsx");

        //最初のシートを取得
        Worksheet sheet = workbook.getWorksheets().get(0);
        //セルの結合を解除する範囲A 1からC 1まで
        sheet.getRange().get("A1:C1").unMerge();

        //結果ドキュメントを保存
        workbook.saveToFile("UnMergeCells.xlsx", FileFormat.Version2013);
    }
}
```
![Unmerge Excel cell.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278784/0d16d2e5-eace-4ff9-24a9-980b0a5c50d9.png)
【初心者向け】Rubyの配列を使用して、オリジナル本登録アプリを作ってみた。

#Rubyの配列を使用した学習をします。
配列が便利ということで、配列を使用して、スクールでおそらくやってない配列を使用した本登録アプリケーションを作ります。

#条件

・本の名前を登録
・値段を登録
・booksという配列に、本の名前（title）と値段（price）をいれていく
・登録が済んだら、登録したデータを取り出すメソッドも作成する
・登録、一覧表示を繰り返し表示させられるよう、メソッドを書いていく


今回は擬似コードなしで書いていきます。

```rb

books = []

def register(books)
  puts "本のタイトルを記載してください"
  book_title = gets.chomp
  puts "本のタイトルを#{book_title}で登録しました"
  puts "販売したい値段を記載してください"
  price = gets.to_i

  books.each do |book_title, price|
  puts "#{book_title}を#{price}円で登録しました"
  end
  book = [book_title, price]
  books << book
end

def book_list(books)
  puts "一覧から番号を選んでください"
  index = 1
  books.each do |book|
    puts "#{index}:#{book[0]}"
    index += 1
  end
  input = gets.to_i
  show(books[input-1])
end

def show(books)
  puts "本のタイトルは#{books[0][0]}"
  puts "値段は#{books[0][1]}円"
end

while true do
  puts "番号を選択してください"
  puts "1:本の登録"
  puts "2:本の詳細"
  puts "3:終了する"

  case  gets.to_i 
  when  1
    register(books)
  when  2
    book_list(books)
  when  3
    exit
  else
    "無効な値です"
  end
end

```

今回は登録したものが、そのまま本の詳細として表示される使用になっています。
あれ、しかも、動作確認すると、

```
番号を選択してください
1:本の登録
2:本の詳細
3:終了する
2
一覧から番号を選んでください
1:qwe
1
本のタイトルはq
値段はw円
```
になっている。値段どこいったｗ
ん、これはどうしたものか？？？

２分くらいで改修できました。


```rb

books = []

def register(books)
  puts "本のタイトルを記載してください"
  book_title = gets.chomp
  puts "本のタイトルを#{book_title}で登録しました"
  puts "販売したい値段を記載してください"
  price = gets.to_i
  puts "#{book_title}を#{price}円で登録しました"
  book = [book_title, price]
  books << book
end

def book_list(books)
  puts "一覧から番号を選んでください"
  index = 1
  books.each do |book|
    puts "#{index}:#{book[0]}"
    index += 1
  end
  input = gets.to_i
  input = input - 1
  puts "本のタイトルは#{books[input][0]}"
  puts "値段は#{books[input][1]}円"
  puts "--------------------------"
end

while true do
  puts "番号を選択してください"
  puts "1:本の登録"
  puts "2:本の詳細"
  puts "3:終了する"

  case  gets.to_i 
  when  1
    register(books)
  when  2
    book_list(books)
  when  3
    exit
  else
    "無効な値です"
  end
end

```

しょーもない処理をしてしまっていたことに気づいた点

①　registerで使ってたeach文いらんやん
②　book_listメソッドでまとめて処理できるやん
③　メソッドをまとめたことによってinput変数で繰り返し処理できるやん
④　動作確認すると、みずらい・・・・横棒いれよう！！

#念の為、動作確認

```
番号を選択してください
1:本の登録
2:本の詳細
3:終了する
1
本のタイトルを記載してください
ビジョナリー・カンパニー
本のタイトルをビジョナリー・カンパニーで登録しました
販売したい値段を記載してください
3800
ビジョナリー・カンパニーを3800円で登録しました
番号を選択してください
1:本の登録
2:本の詳細
3:終了する
1
本のタイトルを記載してください
ビジョナリー・カンパニー飛躍の法則
本のタイトルをビジョナリー・カンパニー飛躍の法則で登録しました
販売したい値段を記載してください
4000
ビジョナリー・カンパニー飛躍の法則を4000円で登録しました
番号を選択してください
1:本の登録
2:本の詳細
3:終了する
2
一覧から番号を選んでください
1:ビジョナリー・カンパニー
2:ビジョナリー・カンパニー飛躍の法則
2
本のタイトルはビジョナリー・カンパニー飛躍の法則
値段は4000円
--------------------------
番号を選択してください
1:本の登録
2:本の詳細
3:終了する
2
一覧から番号を選んでください
1:ビジョナリー・カンパニー
2:ビジョナリー・カンパニー飛躍の法則
1
本のタイトルはビジョナリー・カンパニー
値段は3800円
--------------------------
```

2つ登録してみました。
動きましたね。

プログラミング楽しいですね。
ちなみに、知らない方いたらなんですが、ビジョナリー・カンパニー飛躍の法則、個人的におすすめ本です。
優良企業がなぜ優良企業なのか？　科学的（統計的）に分析した結果がわかります。

ここは違う、ここはこうしたほうがセンスが良い等々ございましたらご指摘いただけますと幸いです。

最後までみていただき、ありがとうございますm(_ _)m
初心者による ES6 引数

#引数のデフォルト
ES6では引数のデフォルト値を宣言するには、「仮引数=デフォルト値」という形式で宣言します。

```javascript:sample.js
function getPluss(a = 0,b = 0){
 return a + b
}

console.log(getPluss(1, 2))
```

##デフォルト値を使う場合の注意点

###1. デフォルト値が適用される場合、されない場合
デフォルト値が適用されるのは、引数が渡されなかった場合です。null, false, 0, 空文字列であっても、引数に渡されているのであればデフォルト値は適用されません。ただし、undefinedは大丈夫です。undefinedは「定義されていない = 渡されていない」だからです。

```
null / false / 0 / ' ' --> デフォルト値が発動しない
undefined --> デフォルト値が発動する
```

##デフォルト値を持つ仮引数は、引数リストの末尾に置く
これは慣例として、デフォルト値を持つ引数の後方に持たない引数を記述するべきではない。

```javascript:sample.js
//よい例
function getPluss(a = 0,b = 0){
 return a + b
}

//よい例
function getPluss(a ,b = 0){
 return a + b
}

//悪い例
function getPluss(a = 0,b ){
 return a + b
}
```
#可変長引数の関数を定義する
ES6では、仮引数の前に「...(ピリオド3つ)」を書くことで可変長引数になります。可変長引数とは、渡された任意個の引数を配列としてまとめて受け取る機能です。

たとえば、

```javascript:sample.js
//...numsで引数を配列として受け取る
function sum(...nums) {
 let result = 0
 for(let num of nums) {
  if(typeof num !== 'number'){
   throw new Error('これは数値ではありません: ' + num)
  }
 result += num
 } 
 return result
}

try {
 console.log(sum(1, 2, 3, 4, 5))
}catch(e){
 window.alert(e.massage)
}
```
この可変長引数を用いることのメリットは

##1. 関数が可変長引数を取ることがわかりやすい
関数ブロック内でも、numsという可変長引数の名前でアクセスできるのでコードの可読性が上がる。

#2. すべての配列操作が可能
可変長引数の配列は、Arrayオブジェクトであるためこれによる配列操作は可能であるため扱いやすい。

#「...」演算子による引数の展開
「...」演算子は、実引数で利用することで、配列を個々の値に分解することができます。

```javascript:sample.js
console.log(Math.max(1, 2, 3, 4, 5)) -> 5

console.log(Math.max([1, 2, 3, 4, 5])) -> NaN(エラー)

console.log(Math.max(...[1, 2, 3, 4, 5])) -> 5
```
実引数の前方に(...)を添えることで、きちんとmaxメソッドが使えるようになる。

#名前付き引数でコードを読みやすくする
ES6では、分割代入を利用することで名前付きでよりシンプルに可読性高く表現できる。

```javascript:sample.js
function getPluss({ a = 1, b = 1}){
 return a + b
}

console.log(getPluss({a : 2, b : 2}))
```
ここで重要なことは、仮引数を

```
{プロパティ名 = デフォルト値, ...}
```
で宣言することで、オブジェクトとして渡された引数を分解！して、関数の配下では個別の引数としてアクセスできることができる。

#参考資料
山田祥寛様　「javascript本格入門」
Chromeがクラッシュする問題とその応急処置

# はじめに
__より簡易な手法を追記しています．ページ下部を参照してください！__

# chromeがクラッシュする
あるバージョン以降のGoogle chromeでは，セキュリティソフトとの相性によって起動しなくなることがあります．

[参考：Chrome 78がクラッシュする](https://qiita.com/bellx2/items/0aefddcf57929904def3)

どうやら，Symantec Endpoint Protectionとの相性(互換性?)が問題のようです．
バージョンアップなどによって解決するそうですが，バージョンアップの権限がないなどの場合は応急措置として

```cmd.exe
"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" --disable-features=RendererCodeIntegrity
```

をコマンドプロンプトから実行することで一時的にchromeを起動することができます．

毎回コマンドプロンプトを開いて実行するのは大変なので，タスクバーに登録してより簡単に（かつ綺麗に）起動する方法を書いておきます．

# 検証環境
- Windows 10 Home
- Symantec Endpoint Protection v12.1.6
- Google chrome v79.0.3945.130

# 手順
## 1.chromeを起動するbatファイルを作成する
メモ帳などを使い，上述のコマンドを書いたbatファイルを作成します

```text:chrome.bat
"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" --disable-features=RendererCodeIntegrity
```

## 2.batファイルを実行するためのvbsファイルを作成する
batファイルのままでも実行は容易ですが，起動のたびにコマンドプロンプトが表示されて邪魔なので，VBSで実行することにします．

```vb:chrome.vbs
Set ws = CreateObject("Wscript.Shell")
ws.run "cmd /c <chrome.batのパス>", vbhide
```

これで，batファイルの実行時にコマンドプロンプトの画面を非表示にできます．

## 3.vbsファイルのショートカットをタスクバーに登録する
vbsファイルはそのままではタスクバーには登録できません（Microsoft ® Windows Based Script Hostというものが登録されてしまいます）．
そこで元のGoogle chromeをタスクバーに登録して，そのリンク先を先ほどのvbsファイルに書き換えます．

- 1 Google chromeをタスクバーにピン留めする．
- 2 タスクバー上のChromeのアイコンを右クリック->[Google chrome]を右クリック->[プロパティ]をクリック
- 3 リンク先の欄を，先ほどのvbsファイルのパスに書き換える
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/353322/11900abc-d860-70b1-9f6d-469bde37711b.png)

# 最後に
途中にも書いた通り，batファイルを作成するなどした時点で十分実用には耐えますが，本記事の手法を用いると

- 余計なウィンドウが表示されない
- タスクバーに登録できる
- アイコンがchromeのままで美しい

といった，ささやかなメリットがあります．（後ろ２つはVBSを使わなくてもできますけどね…ｗ）

# 追記(2020/01/17)
もっと簡単にする方法がありました

- 1 Google chromeをタスクバーにピン留めする．
- 2 タスクバー上のChromeのアイコンを右クリック->[Google chrome]を右クリック->[プロパティ]をクリック
- 3 リンク先の欄を以下の通りに書き換える

```
"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" --disable-features=RendererCodeIntegrity
```

`--disable-features=RendererCodeIntegrity`を末尾に追加するだけでいけます．
こっちのほうが楽ですね．
cakephp4のRequestHandlerでリクエストデータの自動デコードはMIddlewareで

マニュアルはenが最新です

https://book.cakephp.org/4/en/controllers/components/request-handling.html#automatically-decoding-request-data

jaのマニュアルは3のままででした。

https://book.cakephp.org/4/ja/controllers/components/request-handling.html#id3

inputTypeMapがソースコードになかったので戸惑いました
PlayCanvasでVueJS+OnsenUI環境作ってみた

# PlayCanvasでVueJS+OnsenUI環境作ってみた


[【ハンズオン】Vue.jsをPlayCanvasの中で使って3DモデルビュワーなWebページを作る](https://playcanvasjp.connpass.com/event/159113/)
で公式（？）のPlayCanvasでのVueJS環境構築を教えていただいたので、VueJS+OnsenUI環境もできるのではないかと思ってやってみました。

---
## 全体
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142784/19e57c83-c193-bcf3-ef49-a8bd6fe615af.png)

こんな感じでRootにindex.jsを追加して、属性にindex.htmlとOnsenUIで必要なCSS２つセットしてます。

```index.js
/*jshint esversion: 6, asi: true, laxbreak: true*/

const Index = pc.createScript('index');

Index.attributes.add("VueHtml", {type:"asset", assetType:"html"}); // 登録したhtmlを取得
Index.attributes.add("OnsenUICss", {type:"asset", assetType:"css", array: true});

// initialize code called once per entity
Index.prototype.initialize = function() {
//    var self = this; // this書き換え
    const wrapper = document.createElement("div"); // div作成
    wrapper.classList.add("wrapper"); // 作成したdivにwrapperというclass名を指定
    wrapper.innerHTML = this.VueHtml._resources[0]; // 事前に登録していたhtmlをwrapperに流し込み
    document.body.appendChild(wrapper); // bodyにwrapperを追加
    
    // CSS
    const cssElement = document.createElement("style");
    this.OnsenUICss.forEach((css) => {
        cssElement.innerHTML = css._resources[0];
        document.head.appendChild(cssElement);
    });
    
    // VueJS
    const app = new Vue({ // Vue呼び出し
        el: '#app', // id名がappの要素を参照
        template: '#main',
        data() { // 使用するdataを登録
            return({
            });
        },
        methods: { // イベントハンドラ作成
        }
    });

    // canvasを取得
    const canvas = document.getElementsByTagName("canvas")[0]; // canvasを取得
    canvas.classList.add("pcCanvas"); // canvasにclass名を指定
    
    // canvasを移動
    const canvasInsert = document.getElementById('canvas_insert');
    canvasInsert.appendChild(canvas);
};

// update code called every frame
Index.prototype.update = function(dt) {
    
};

// swap method called for script hot-reloading
// inherit your script state here
// Index.prototype.swap = function(old) { };

// to learn more about script anatomy, please read:
// http://developer.playcanvas.com/en/user-manual/scripting/
```

```index.html
<template id="main">
    <v-ons-page>
        <!-- PlayCanvasのcanvas移動先 -->
        <div id="canvas_insert"></div>

        <p style="text-align: center">
            <v-ons-button @click="$ons.notification.alert('Hello World!')">
                Click me!
            </v-ons-button>
        </p>
    </v-ons-page>
</template>

<div id="app"></div>
```

onsenui.cssは[OnesnUI用CSS](https://unpkg.com/onsenui/css/onsenui.css)
onsen-css-components.min.cssは[OnesnUIコンポーネント用CSS](https://unpkg.com/onsenui/css/onsen-css-components.min.css)

をコピペして作成

ExternalScriptには
- https://cdn.jsdelivr.net/npm/vue
- https://unpkg.com/onsenui/js/onsenui.min.js
- https://unpkg.com/vue-onsenui@2.6.2/dist/vue-onsenui.js

を指定したら

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142784/a9218958-ac07-1f3f-b343-0b9a678de085.png)
こんな感じでVueJS+OnsenUIで動きました
RailsアプリケーションにjQueryを導入する方法

RailsでjQueryを導入する方法について記述していく。
アプリケーションを立ち上げて毎回調べるのも面倒なので備忘録として。

## 手順
① 下記gemをGemfileに記述する。

```:Gemfile
gem "jquery-rails"
```

② ターミナルでbundle installを実行する。

```:ターミナル
$ bundle install #bundleでも可
```

③ Gemfile.lockに下記が追加されている事を確認する。

```Gemfile.lock
jquery-rails(n.n.n) #nはinstallした時によってバージョンが異なる為
```

④ application.jsに //= require jquery と //= require jquery_ujs の2行を追加する。

```:application.js
//= require rails-ujs
//= require activestorage
//= require turbolinks
//= require jquery #これを追加
//= require jquery_ujs #これも追加
//= require_tree .
```

⑤ app/views/layouts/application.html.erb内の記述を確認する。

```:application.html.erb
<%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
```

この中の'application'が記述されることで、スクリプトファイルを読み込むためのスクリプトタグが自動的に生成される。

⑥ 正常にjQueryが動くかを確認する。
5までの手順で基本的には実装は完了しているが、念の為動いているかを確認する。
適当にindex.html.erbファイルを作成。下記は1例。

```:index.html.erb
<p>jQuery稼働テスト(未稼働)</p>
```

<img width="235" alt="スクリーンショット 2020-01-17 14.26.51.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/517665/025d69b7-ef16-c942-aeef-c018ba4eb6e4.png">
こう表示される。
ではjQueryの記述を追加しよう。

```:index.html.erb
  <p>jQuery稼働テスト(未稼働)</p>

#ここから追加
  <script type="text/javascript">
  $(document).ready(function() {
    $("p").text("jQuery稼働テスト(稼働中)");
  });
</script>
#ここまで
```

記述としては、ページを読み込んだ際にpタグのテキストを"jQuery稼働テスト(稼働中)"に置き換える、という物だ。
再度ページを読み込む。
<img width="320" alt="スクリーンショット 2020-01-17 14.26.25.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/517665/1eb3e863-c30d-224f-56df-dfdf7bc67686.png">
無事jQueryが動作している事が確認できた。

参考サイト
https://qiita.com/ngron/items/95846bd630a723e00038
https://www.sejuku.net/blog/57790
Windows 10へNode.jsをインストールする

# 概要
- Node.jsをNode.jsのサイトからダウンロードしてインストールします。
- Node.jsの利用方法を説明します。

# Node.jsのインストール

1. Node.jsのダウンロードサイトを開きます。
    1. [Node.js - ダウンロード](https://nodejs.org/ja/download/) 

1. 「LTS版」の《Windows Installer》をクリックしてダウンロードします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520689/54727cbc-3a9a-0b19-85d9-891375f9c1a1.png)

1. ダウンロードしたインストールファイルをクリックしてインストーラーを開きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520689/898d4005-c802-4cfc-dda2-65629a2cf9ec.png)

1. 《Next》ボタンをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520689/fdf1ab0a-7ae8-c3fc-0f44-7c8808d8735a.png)

1. 《I accept the terms in the Licence Agreement》（ライセンス契約の条項に同意します）をチェックして、《Next》をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520689/92e445a5-ab20-2652-3533-0cdf8be7b7fe.png)

1. 《Next》をクリックします。（必要であればインストールフォルダを指定する）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520689/e86830e4-691f-205f-fd52-53522d04a9af.png)

1. 《Next》をクリックします。（基本的にはデフォルトのまま）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520689/9384be42-4b75-8907-0ce9-10a3e9bbff3d.png)

1. 《Next》をクリックします。（ネイティブアドオンのビルドはしないのでデフォルトのまま）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520689/a947fd13-45dc-c165-3c10-c18a50171c21.png)
    1. チェックボックスをチェックするとNode.jsのネイティブアドオンをビルドするための設定をします。  
       ネイティブアドオンについては下部の参考サイトを参照してください。

1. 《Install》をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520689/2d0e6108-ad53-c948-8a12-b0424bf95508.png)

1. ユーザーアカウント制御の画面が表示されるので《はい》をクリックします。

1. 《Finish》をクリックし、インストールを完了します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520689/381de343-3bb9-d9ad-cb17-f5d06396be28.png)

# Node.jsの利用とインストール確認
1. Windowsのスタートボタンを**右クリック**します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520689/14ae4cfa-2cd9-7c06-87c6-d4cd8f88b1f7.png)

1. メニューが表示されるので「Windows PowerShell」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520689/00abb73a-afcb-f46d-8378-c5e3b543c3f6.png)

1. Windows PowerShellの画面が開くのでコマンドを入力してNode.jsがインストールされているか確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520689/f7f9a222-f833-8423-974d-36c96a2bb560.png)
    1. `node --version` Node.jsのバージョン確認コマンド

1. インストールしたバージョン番号が確認できれば正常にインストールされています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520689/b5acffca-75c6-20cc-2393-6a35ebbb5d1a.png)

1. Windows PowerShellやコマンドプロンプトからNode.jsは利用できます。

# 参考サイト
- [Node.js - ダウンロード](https://nodejs.org/ja/download/) 
- [Node.jsのネイティブなアドオンを書く](https://techblog.imagemagic.jp/2018/08/28/node-js%E3%81%AE%E3%83%8D%E3%82%A4%E3%83%86%E3%82%A3%E3%83%96%E3%81%AA%E3%82%A2%E3%83%89%E3%82%AA%E3%83%B3%E3%82%92%E6%9B%B8%E3%81%8F/)
ie11でsubset=japaneseを入れてもGoogle Fontsの和文フォントが読み込まれない

Googl Fontsから欧文フォントと和文フォントを両方読み込む場合、ie11では**欧文フォントだけが読み込まれる**現象が発生しました。
対応策としては、欧文と和文のlinkタグをそれぞれ分けると解消します。

# 背景
Google FontsからEB Garamond、Noto Sans JP、Noto Serif JPの3種類を使用したところ、ie11ではEB Garamondのみが反映され、他の2つが反映されなかった。

```html
// 使用したタグ
<link href="https://fonts.googleapis.com/css?family=EB+Garamond:400,500,500i,700|Noto+Sans+JP:400,500,700|Noto+Serif+JP:500,700&display=swap&subset=japanese" rel="stylesheet">
```

# 対応策

ie11でGoogle Fontsの和文フォントが反映されない対応策をググると、以下のようにLanguagesのJapaneseにチェックを入れるという記事が見つかるがこれでは解決しなかった。

https://stand-4u.com/service/notoserif.html

以下のように、linkタグを欧文と和文で分けることで3種類のフォントが無事反映された。

```html
<link href="https://fonts.googleapis.com/css?family=EB+Garamond:400,500,500i,700&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?Noto+Sans+JP:400,500,700|Noto+Serif+JP:500,700&display=swap&subset=japanese" rel="stylesheet">
```
ie11のためだけにフォントを分けて読むのがしゃくだったので、以下のようにjsでie11の時のみ追加で和文フォントを読み込むようにした。お好きな方で。

```html

<link href="https://fonts.googleapis.com/css?family=EB+Garamond:400,500,500i,700|Noto+Sans+JP:400,500,700|Noto+Serif+JP:500,700&display=swap" rel="stylesheet">
<script>
	var userAgent = window.navigator.userAgent.toLowerCase();
	if(userAgent.indexOf('msie') != -1 || userAgent.indexOf('trident') != -1) {
		var head = document.getElementsByTagName('head')[0];
		var link = document.createElement('link');
		link.setAttribute('rel','stylesheet');
		link.setAttribute('href','https://fonts.googleapis.com/css?family=Noto+Sans+JP:400,500,700|Noto+Serif+JP:500,700&display=swap&subset=japanese');
		head.appendChild(link);
	}
</script>
```

# その他

今回は和文、欧文で分けて読み込むことで解決したけど、なぜそうなるかという根本的な原因は不明。そのため欧文+和文なら必ず発生するのか、分けて読めば必ず解決するのかというと私の試した環境ではそうだったという感じです。

余談ですが、jsなんか使わずコンディショナルコメント```<!--[if IE]>〜<![endif]-->```で対応したかったのですが、ie10以降はコンディショナルコメントが効かなくなったんですね。
2020年1/14にWindows7のサポート終了したし、もうieは対応しなくていいだろと思いましたが、ie11のサポートは2025年10/14まででした。長い。
https://coliss.com/articles/build-websites/operation/work/ie11-end-of-support-countdown.html
顔ボックス検出でDlibとOpenCVのHaarCascadeの比較

顔ボックスの精度（Recall Rateです）は、Dlibのものより、OpenCVのHaarCascadeのほうが優秀です。

Dlibの顔ボックス検出を利用して、データを作っていました。が、アジア人の検出失敗が多いことに気づいた。ためしに、OpenCVのHaarCascadeでも試し、比較しました。

UTKFaceというオープンな顔データを使い比較しました。商用不可で、古く、イメージが小さいのですが、カテゴリー付けがしてあって、人種と性別、年齢情報がついてあって、調査には重宝する。InTheWildの母データは、24,109件あって、アジア系の顔が3,586件。ある程度バランスよい。

InTheWildのイメージから、顔ボックスを検出して、成功したらCropした結果を吐き出す。検出ボックスの幅150pixel以下は捨てる、Laplacian　Meanが50未満なら捨てる（ボケ排除）、という条件を等しく課しています。

Dlibは、4,050件がCrop成功で、アジア系は269件。
OpenCVのHaarCascadeは、4,835件がCropできて、アジア系は361件。

顔ボックスに関しては、Dlibよりも、OpenCVのほうが検出率が高く、使っているトレーニングデータも、よりバランスが取れているようです。DlibのLandmarkを使う人が多いですが、Landmarkに限らず、顔検出のほうでも、Dlibが使っているトレーニングデータは偏っていることがうかがえます。
IExの不思議な動きを抑制するおまじない

例えば`[10, 20, 30, 40, 50]`というリストがあったとして、`Enum.drop`すると文字化けのような値が返ってくる場合があります。Erlang由来とのことですが、個人的にはとっても気持ち悪いのでなんとかしたいと思っていたところ、 @im_miolab さんと @twinbee さんの記事があったので個人的まとめとしました。…奥が深いので詳細は文末の参考URLを :smile: 

```elixir:iex
iex> list = [10, 20, 30, 40, 50]
[10, 20, 30, 40, 50]
iex> Enum.drop(list, 0)
[10, 20, 30, 40, 50]
iex> Enum.drop(list, 1)
[20, 30, 40, 50]
iex> Enum.drop(list, 2)
[30, 40, 50]
iex> Enum.drop(list, 3)  ←[40, 50]と返ってきてほしい
'(2'
iex> Enum.drop(list, 4)  ←[50]と返ってきてほしい
'2'
iex> Enum.drop(list, 5)
[]

足し算するときちんと答えがかえってくる
iex> Enum.drop(list, 3) |> Enum.sum()
90
```

とあるおまじないを入力すると解決します。

```elixir:iex
iex> IEx.configure(inspect: [charlists: :as_lists])
```

入力後の結果は以下。

```elixir:iex
iex> IEx.configure(inspect: [charlists: :as_lists])
:ok
iex> list = [10, 20, 30, 40, 50]
[10, 20, 30, 40, 50]
iex> Enum.drop(list, 0)
[10, 20, 30, 40, 50]
iex> Enum.drop(list, 1)
[20, 30, 40, 50]
iex> Enum.drop(list, 2)
[30, 40, 50]
iex> Enum.drop(list, 3)  ←期待どおり
[40, 50]
iex> Enum.drop(list, 4)  ←期待どおり
[50]
iex> Enum.drop(list, 5)
[]
```


毎回入力するのは面倒だと思うので、`$HOME/.iex.exs`に設定を書くか、別の設定ファイルを作っておいてIExを起動する際に読み込むかした方がいいです。

```bash:bash
$ cat .iex.exs
IEx.configure(inspect: [charlists: :as_lists])

または

$ iex --dot-iex "IEx設定ファイルへのパス"

```


ヘルプはこのあたりを読めばいいかなぁ。

```elixir:IEx
iex> h IEx.configure/1
```

```elixir:IEx
iex> h Inspect.Opts
```


# おまけ
デフォルトでは出力制限が50件となっています。`IEx.configure(inspect: [limit: :infinity])`コマンドを入力すると無制限になります。

```elixir:iex
iex> 1..100 |> Enum.map(& &1)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42,
 43, 44, 45, 46, 47, 48, 49, 50, ...]

iex> IEx.configure(inspect: [limit: :infinity])
:ok

iex> 1..100 |> Enum.map(& &1)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42,
 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62,
 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82,
 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100]
```


# 参考
- [Elixirで大きな変数をファイルに書き出す](https://qiita.com/twinbee/items/380c26e37192f9c4736b)
- [Elixirで整数リストが「謎の文字」として返ってくる現象と、文字列・文字リストについて](https://qiita.com/im_miolab/items/2d41b10ff005b334295d)
Go×CloudWatchでファイル取得状況をカスタムメトリクス化する


今回はAWS-SDKを用いて、大量のデータを取得するEC2インスタンスの1時間当たりのファイル取得量をCloudWatchでカスタムメトリクス化して取得状況を監視するシステムを作成したので、一部をご紹介します。

AWS関連の部分以外はGoの標準パッケージのみで作るシンプルなものになっています。


# Goでファイル取得数を計算する

下記のプログラムで現在のファイル取得数と経過時間を計算します。
コード自体はとてもシンプルです。

```go

package calculator

import (
    "fmt"
    "io/ioutil"
    "math"
    "os"
    "path/filepath"
    "sort"
)

func GetFetchSpeed() (float64, error) {
    dir := `取得したいディレクトリ`
//ディレクトリからファイルを取得
    files, err := ioutil.ReadDir(filepath.Dir(dir))
    if err != nil {
        return 0, err
    }
//編集日時順にファイルをソートします。
    sort.Slice(files, func(i, j int) bool {
        return files[i].ModTime().Unix() < files[j].ModTime().Unix()
    })

    firstFile, err := os.Stat(dir + files[0].Name())
   if err != nil {
        return 0, err
    }

    lastFile, _ := os.Stat(dir + files[len(files)-1].Name())
    if err != nil {
        return 0, err
    }
//最初のファイルを取得してからの経過時間を計算
    elapsedTime := lastFile.ModTime().Sub(firstFile.ModTime())
    if elapsedTime < 0 {
        elapsedTime *= -1
    }
//１時間ごとのファイル取得数
    elapsedMinute := math.Trunc(elapsedTime.Minutes())
    fetchedPerHour := len(files) / int(elapsedMinute) * 60

    return float64(fetchedPerHour), nil
}



```


# 取得した情報をCloudWatchでメトリクス化する。
```go
package metrics

import (
    "fmt"
    "io/ioutil"
    "net/http"

    "github.com/aws/aws-sdk-go/aws"
    "github.com/aws/aws-sdk-go/aws/session"
    "github.com/aws/aws-sdk-go/service/cloudwatch"
)

func getInstanceID() string {
//このアドレスにアクセスするとEC2インスタンスのインスタンスIDを取得することができます。
    resp, err := http.Get("http://169.254.169.254/latest/meta-data/instance-id")
    if err != nil {
        fmt.Println(err)
    }
    defer resp.Body.Close()
    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        fmt.Println(err)
    }
    return string(body)
}

//メトリクスを作成します
func CreateMetrics(value float64) {
    cw := cloudwatch.New(session.New(), &aws.Config{Region: aws.String("ap-northeast-1")})

    dimensionParam := &cloudwatch.Dimension{
        Name:  aws.String("InstanceId"),
        Value: aws.String(getInstanceID()),
    }

    metricDataParam := &cloudwatch.MetricDatum{
        Dimensions: []*cloudwatch.Dimension{dimensionParam},
        MetricName: aws.String("Files per 1Hour"),
        Unit:       aws.String("Count"),
        Value:      aws.Float64(value),
    }

    putMetricsDataInput := &cloudwatch.PutMetricDataInput{
        MetricData: []*cloudwatch.MetricDatum{metricDataParam},
//メトリクスの名前空間
        Namespace:  aws.String("EC2"),
    }
    cw.PutMetricData(putMetricsDataInput)
}


```

この二つのパッケージをmain.goで実行します。

```go

func main() {
    value, err := calculator.GetFetchSpeed()
    if err != nil {
        fmt.Printf("Error while calculatoring speed:%s\n", err)
    }
    if value > 0 {
        metrics.CreateMetrics(value)
    }
}

```

以上になります。

このメトリクス化する仕組みを用いればいろんなものを可視化することができるので、監視や運用に役立つかと思います。
Power BI Tips - 「Webに公開」した際の更新タイミング 

#概要
結論から言うと、ドキュメントはちゃんと読みましょう・・・。
Power BIの感触をお客様に伝える際に、地味にハマった話。

#内容
Power BIサービスに「Webに公開する」という機能がありまして、
作ったレポート等をブラウザで見ることができます。
見る分には、MicrosoftアカウントもPower BIサービスへの登録も不要です。
※ただし、セキュリティ的な機能はないので、URLさえ知っていれば誰でも見れてしまいます。

Power BIを知らないお客さんに、こんな感じにデータが見えますよーという説明のために
よく使っています。


で、とある案件で、データが頻繁に更新されるシステムの見える化に
Power BIを使うことにしたんです。

クラウド上のデータベースからデータを取得するのに、DirectQueryを使用して、
Power BI DesktopからPower BIサービスにpbixを発行。
Power BIサービスにログインして、レポートをWebに公開。

初回の表示時は、ちゃんと最新のデータが取れて表示されていることを確認。
10分ほど待って、再度表示させてみたところ・・・値が変わっていない。

ん、なんで？？？

データベースのテーブルを直接見たところ、データは更新されていました。
Power BI Desktopで「最新の情報を更新」ボタンを押してみたところ、
ちゃんと更新されたデータが表示されるし・・・。

データセットが更新されていないのかと思い、
それらしい設定（データセットの「スケジュールされたキャッシュの更新」項目）を
15分に変更してみても、全然変わらず・・・。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146789/c461b9c2-e18a-6c90-2c64-d67ac7eb7b05.png)


#「Webに公開」機能の制限事項
グー●ルさんとかに聞いてみてたんですが、
海外で同じように悩んでた人がフォーラムに投稿してました。
でも結局わからず。


最終的にMicrosoftの公式ページに辿りついて、確認しました。

で、[Power BI から Web への公開#レポートへの更新とデータ更新](https://docs.microsoft.com/ja-jp/power-bi/service-publish-to-web#updates-to-reports-and-data-refresh)によると
**「レポートまたはビジュアルの更新がユーザーに表示されるには約 1 時間かかります。」**

とのことでしたとさ・・・。
【具体的な数字が分かって良かったです】第5回 転職透明化らぼ-リファラル採用編 参加ふりかえり #転職透明化らぼ

今回は「ブログ枠」で参加しました。
参加の振り返りをしていきます。

イベント情報、発表資料はこちらから確認できます↓
https://rtlabo.connpass.com/event/158873/

## 良かったこと
リファラル採用について、企業がどれくらい力を注いでいるか分かったことです。

印象的だったのは、**エージェント経由よりもリファラル採用のほうが採用率が10倍以上も高い**という数字が示されたことです。

正直、この数字はすごいと思いました。

リファラル採用を推進するためのサービスも紹介されました。興味のある方は、ぜひご覧になってみてください。会社の支援を得ることで、採用活動の負担も減らせると思います。
https://jp.refcome.com/


社会人経験が長い人であれば、「この人と働きたい！」と思える人との出会いが沢山あると思います。そんな経験を活かせるのは嬉しいですね。

私自身、人間的に尊敬できる方と仕事してきた自負がありますので、リファラル採用という切り口は面白いです。さっそく、知り合いの方にお声掛けをしようと思います（その前に自分の転職活動を終わらせないとですが）。

## 思ったこと
懇親会で知り合いの方が、「ほかの会社と比べると自社も意外と悪くないことがわかった」と仰っていて、印象的でした。転職に至らなかったとしても、転職活動をするだけでもメリットはあると思いました。

採用担当の方に、「面接の一時間だと時間が足りなくて、何を質問していいか迷います。どうすれば良いと思いますか？」と尋ねたところ、「ご自身が大切にしてる価値観について、会社がどんな取り組みをしているか訊いてみると良いと思います」とアドバイスを頂きました。なるほどと思いました。

## 改善行動

- 懇親会になったら、採用担当の人と３人以上話す。
- 面接の前日になったら、自己分析した価値観リストを３つ見返す。
- 価値観リストを見返したら、会社のホームページを見て、価値観に合った活動を３つピックアップする

## 最後に
登壇資料を見てみたい方は、以下のリンクをクリックしてください↓
https://rtlabo.connpass.com/event/158873/presentation/
「統計」と「機械学習」の違いの整理で多くの事業会社で「機械学習」が使えない理由が視えてきた！

#統計と機械学習って結局何が違うの？なんで今日から機械学習で予測して金儲けできないの？
機械学習を勉強し始めるとおそらく誰もが疑問に思う。そして、なんで事業会社の多くが日々の業務で今日から使えないの？っていう疑問も出てくる。いろいろな文献があるがいまいち理解に困ったので自分なりに整理しなおした資料。情報を組み合わせてかなり自論を入れています。
This article explains why many companies cannot use machine learning approaches to drive business starting today...

#まずは統計と機械学習の考え方や向き不向きの違いを表にまとめてみた

![統計か機械学習かVer2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/518389/56d3b2c0-4a3d-7ced-05fa-c974102ed460.png)

多くの人が言及しているが互いに関連しているとはいえ、最終目的が異なる。**「機械学習」は予測や判断は行うもののなぜそうなったのかは一般的にはブラックボックスだ。「統計」で行う予測や判断は、なぜそういう結論になったのかの理由付けが重要になり（理由付けを行うための学問であり）、理由はホワイトボックスとなっている。**

#なぜ多くの事業会社が「機械学習のアプローチを使えない」のか？

要因の整理に力を入れることが目的の**「統計」は社会科学の課題解決に向いており、「機械学習」は自然科学の予測やロボットでの自動処理に向いている。**と、整理結果から私は考えるに至ったし現実はそうなっている。売上に変動する要因を洗い出せ、要因に対して売上アップの施策を考えろなんていうテーマがあればこれは影響度の整理を行う「統計」の話（社会科学の問題解決）で「機械学習」でどうこうなる話ではない。（なお、BIのAI機能として提供されている影響分析の機能があるが、これは影響しているであろう項目の指定を行うことが必要で、関連して行われる計算は「統計」のエリアだ。ECサイトのおすすめ商品表示も他の人が買ったことのある組み合わせを表示させているだけのことが多く、機械学習上の予測というよりシンプルなクエリーに近いことが多いはずだ。）一方で台風の進路予測や地震予測（まだ無理だと思うが）、画像認識や音声認識などのロボット処理は機械学習のアプローチになる。例えば台風の進路/強度予測は進路/強度さえ当たれば別に気温、海水温、ジェット気流など何が影響してようがしていまいがモデルが統計学的に綺麗であろうが嫌われようが（気温と海水温は多重共線性、multicollinearityにより相互連動するから統計モデルという意味では両方同時に使わない方が好ましいはずですが）結果さえ正しければ国民には関係ない、興味関心がない話だからだ。
**多くの事業会社はセールス、マーケティング、ファイナンス、人事といったエリアの「社会科学」に興味があるのであって「自然科学」や「ロボット」に興味がないことが多い。
（※マーケティングオートメーションは自動化を考えるわけですから、この領域はロボットと言えるかも。限定的ですが。）**

#さらに、なぜ多くの事業会社が「統計も機械学習も使えない」のか？

●**データがない。**これに尽きる。
Kaggleコンペであるような綺麗なデータセットは一般的な事業会社では持ち合わせていない。
**（１）主要因であるはずの属性情報データがない。**
例えば物やサービスを購入しているお客様の過去、最新、未来の属性情報がない。属性情報は変動しており過去の時は過去の属性、現在の時は現在の属性。例としてクレジットカード会社の例として顧客情報の最新情報が手に入る与信を自動化は比較的楽だが、10年後どうなっているかの予測はまずできない。学歴だの家族構成だの年収だの状況はコロコロ変わるが最新の属性情報をいつも正しく管理しているわけではないので、結果としてクレジットカードを利用している人が誰なのか（属性として誰なのか）クレジットカード会社は（大量に多くの属性の個人情報を持っている企業ですら）ほとんどわかっていない。一回入手したら変わらない性別、年齢といった変わらない情報の最新はいつも持っているけど顧客属性を考えるとあまりに限られた情報だ。こんな状態で過去、現在、未来の消費動向などをつなげようとするのは無理だ。

**（２）トランザクションデータとマスタデータが紐づいていない。**
マスタデータ（品番など）がコロコロ変わり過去、現在、未来がつながらない。

**（３）社内情報ですら（全ての）戦略や施策を網羅的に統計用、機械学習用にデータ化できない。**
企業戦略、施策によって（例として広告、キャンペーンなど）仕入や売上に影響するのはアタリマエの話であるのだが、統計や機械学習用にデータの受け渡しなどほぼできない。ピンポイントで施策が功を奏したか否かくらいの個別分析はできても企業全体でなんていう話は無理。でも経営者はそれを欲しがる。

#結論
●自然科学やロボット処理/処理自動化に興味関心がない人、会社は「機械学習」に入り込む多大なメリットはなさそう（各々がそちらの方面で潰しを利かすのなら別）
●分析に用いる適切なデータがなければ「統計」も「機械学習」も旗を振ったところで無意味、無駄な労力
●前提となる分析用データ整備がされていない場合は、データ入手/整備から入ることが必要
●根本、本質を理解していないデータサイエンティスト職の今後が危うい！成果出せずに結果...