OmniAICreator/Qiita-1.07M huggingface dataset:
Windowsでスクリーンショットを画像ファイルとして保存しまくる簡単なやり方

## はじめに
Qiitaやnoteを書くときに大量のスクリーンショットを撮るのて面倒ですよね。
Qiitaの場合は **Print Screen** や **Alt + Print Screen** してからエディタ画面にペーストすれば、あとは自動的にアップロードしてくれるのでまだ良いのですが、noteは画像ファイルを用意しないといけないのでひと手間増えます。
そこで、この悩みを少し和らげてくれるtipsをご紹介したいと思います。

## 対象の環境
Windows 10
(他のバージョンでは未調査です)

## デスクトップ全体のスクリーンショットをPNGファイルとして保存する
キーボードの **Windows + Print Screen**を押す。
**%USERPROFILE%\Pictures\Screenshots** [^1] 以下にPNGファイルとして保存されます。

## アクティブウィンドウのスクリーンショットをPNGファイルとして保存する
キーボードの **Windows + Alt + Print Screen** を押す。
こちらはなぜか **%USERPROFILE%\Videos\Captures** [^2]以下にPNGファイルとして保存されます。

以上、小ネタでした。

[^1]: エクスプローラー上では **ユーザー名 > ピクチャフォルダ > スクリーンショット** として表示される。
[^2]: エクスプローラー上では **ユーザー名 > ビデオ > スクリーンショット** として表示される。
laravelでのテーブル削除方法

一度消したはずのマイグレーションテーブルのファイルがあるのに、なぜかマイグレーションを実行しようとしたところ、そのファイルが存在しているとエラー画面が出てしまいます。なぜでしょうか？




 SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'goods' already exists   
  (SQL: create table `goods` (`id` int unsigned not null auto_increment primary key, `us  
  er_id` int unsigned not null, `item_name,300` varchar(191) not null, `item_code` varch  
  ar(191) not null, `item_price` int not null, `item_caption` text not null, `created_at  
  ` timestamp null, `updated_at` timestamp null) default character set utf8mb4 collate u  
  tf8mb4_unicode_ci)                                                                      
                                                                                          

In Connection.php line 458:
                                                                                         
  SQLSTATE[42S01]: Base table or view already exists: 1050 Table 'goods' already exists  
                                                                                      


+------+------------------------------------------------+
| Ran? | Migration                                      |
+------+------------------------------------------------+
| Y    | 2014_10_12_000000_create_users_table           |
| Y    | 2014_10_12_100000_create_password_resets_table |
| Y    | 2020_03_05_185507_create_wants_table           |
| Y    | 2020_03_05_185545_create_nices_table           |
| N    | 2020_03_07_095900_create_items_table           |
+------+------------------------------------------------+
【激戦】プログラミング教育の行方は

#世界で激戦のWindows vs Chorome OS
|企業名|MicroSoft|Google|Apple|
|---|---|---|---|
|PCOS|Windows|**ChoromeOS**|MacOS|
|PC多い形態|デスクトップ/ノート|ノート|ノート|
|スマホ|(WindowsMobile)→停止|Android|iOS|
|タブレット|(Windows)→人気低下中|Android|**iPadOS**|
|価格帯|**幅広い**|幅広い|高め|
|品質|様々|高い|非常に高い(ハードウェアに最適化)|
|純正高性能ソフトウェア|有料|無料(Web上)|Apple製品なら使用可能|
|オフィススイート|MS Office|Google Apps|iWork|
|メイン|ソフトウェア|ソフトウェア|ハードウェア|
|愛用|有名故|実用性|虜になる傾向が強い|

Microsoft系OS製品は設定等は非常に自由度が高い。特定の誰か(開発者や旧OS利用者や新OS利用者等)ではなく多くの人に使い勝手の良いOSになっている(そのため非常にOSのデーターサイズが大きくApple製品やGoogle系OS製品と比べて高度なことが出来るというメリットはあるが、直観性は欠けがち)
Google系OS製品は実用性が高くOSS(オープンソースソフトウェア)で色々な価格帯があり、有名になればライト層を魅了する能力がある(日米英はiOS優勢、他ではAndroid優勢。Android+ChoromeOS)。
Apple製品は使うと大人が使うと子どもにも使わせたくなる程非常に人を惹きつける魔力がある(iphone+Mac+iPadで全てそろえている強者もいる)。

#教育について
プログラミング教育としてPCに慣れさせるという名目で低価格な製品が選ばれることが多い。しかし、これに乗じて知識のない人から云万PCを云十万(intel Core i9 MacBook Proさえ買えそうな価格)で貸出する高額な詐欺をしている悪い輩(やから)もいるそうなので、注意が必要です。なお、ChoromeBook側は、Apple製品しか買わないファンが殆どのMacBookを仮想敵にせず、明らかにWindowsを仮想敵にしているそうで、ユーザーがWindowsで気になることを纏めてCMにする辺り本気なんだなって思っています(敵を限定することは戦略上重要)。
Apple(が売りたいであろうMacBook proシリーズ)は直撃せず、Windowsが直撃するだろうし。

#感想
どうなるか楽しみにしています。
Alloyでパズル (6) Halmos の握手問題

今回はAlloy本から普通にパズル、とその先に見えたこと。

# 問題
Alloy本 A.3.4 Halmos の握手問題

> あるパーティーで、Alice と Bob は４組のカップルを招いた。
互いに知り合いだった者もいれば、そうでない者もいた。礼儀正しい者もいれば、そうでない者もいた。
そのため何人かは握手をしたが、ゲストのすべての組み合わせで握手が交わされたわけではない（もちろん、自分とも自分のパートナーとも握手した者は１人もいなかった）。
Alice はパーティーの終わりに、興味本位で何人と握手したかを全員に訊いて回った。
彼女は９人から９つの異なる回答を得た。
Bob と握手したのは何人だろうか？

# リスト
書くこと自体は特に問題なかった。
ただ１点気になったのが「Alice と Bob がカップルだとは問題文に書かれていない」こと。
文脈からカップルであると仮定して、コメントを残す形とした。

```alloy
one sig Alice, Bob extends Person {}
sig Guest extends Person {}
abstract sig Person {
    partner : Person-this,
    shake: set Person-this-partner,
    shakes: #shake
}
fact {
    partner = ~partner
    shake = ~shake
    Alice.partner = Bob     // とは明言されてないけど..
}

fact disjShakes {
    #shakes[Person-Alice] = #(Person-Alice)
}
run {} for 5 int, exactly 10 Person

check {Bob.shakes=4} for 5 int, exactly 10 Person
```

# 結果

Bobの握手数は４、反例はなかった。
![shakehand.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/20005/888cacd7-bc38-1086-94f8-e1742bd144fd.png)

図を見て「全員、握手回数をパートナーと合わせると８になるようだ」と思い、確認してみた。

```alloy
check { all p:Person | add[p.shakes, p.partner.shakes] = #Guest }
 for 5 int, exactly 10 Person
```
「全員、握手回数をパートナーと合わせるとゲスト人数になる」に反例はなかった。
人数を増やしていくと反例探しにかかる時間が厳しいので数え方を変えないといけないだろう。

# 追加調査
## Alice と Bob がカップルでなかったら？
さて、気になっていた件を少し確認してみよう。
Alice と Bob がカップルではなく、握手したかもしれないと考えたらどうだろう。
少し修正して試してみると、Bob の握手数は 4,5,6,7,8,**9** の６通りになった。

まだ気になることがある。
「握手が交わされたのは Alice,Bob,ゲスト の間**だけ**」とは問題文に書かれていない。
Alice と Bob それぞれのパートナーが「招かれてはいないがホスト関係者として参加していた」なら？
パーティー参加者以外のケータリング業者と握手した者がいたら...

だんだん叙述トリックを読んでいるような気分になってきた。
「厳密に言葉通り」を追求すると解がなくなるのは確実なのでやめておこう。

## 原典はどうだった？
探してみると、本家リポジトリにソースがあった。
　[handshake.als](https://github.com/AlloyTools/org.alloytools.alloy/blob/master/org.alloytools.alloy.extra/extra/models/examples/puzzles/handshake.als)

冒頭にコメントがあるので読むと最初の行にいきなり "Hilary and Jocelyn are married. They invite four couples who are friends for dinner." とある。
他に握手対象がいなかったかについても "When they arrive, they shake hands with each other." なので they, each other に含まれない文章外の人とは握手していない、と読める。
原文では明記されていたのだ。
（まあ Hilary と Jocelyn は arrive した１つめの they に含まれないので each other にも含まれないという解釈もできるが、冒頭の２文に現れる面々が２つめの they および each other の対象と考えるべきだろう）

かなり注意深く行われたという翻訳作業でも、日本語にした時点であいまいになってしまったようだ。

## ところで
- 「全員、握手回数をパートナーと合わせると８になる」証明も handshake.als のコメントに書かれている。
- 直々に書かれた handshake.als だが、Spouses の記述がくどいように思う。  
そこそんなにかみくだいて説明するほど大事ですかね？

# 参考

- Daniel Jackson：[抽象によるソフトウェア設計 ―Alloyではじめる形式手法](https://www.amazon.co.jp/dp/B07BKRG85J)
- [handshake.als](https://github.com/AlloyTools/org.alloytools.alloy/blob/master/org.alloytools.alloy.extra/extra/models/examples/puzzles/handshake.als)
HTML5 テンプレート

```html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<link rel="stylesheet" href="style.css">
<script src="main.js"></script>
<title></title>
</head>
<body>
</body>
</html>
```
VisualStudioCodeで、!を入力し[Enter]キーを押すと、
HTML5のテンプレートが自動で表示される
``` html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    
</body>
</html>
```

https://www.vector.co.jp/soft/screen/win95/game/se394828.html
MCP23S17の制御　覚え書き

#MCP23S17 セットアップ
SPIインタフェースで１６ビットパラレルインタフェースに接続できるMCP23S17は安価で便利なデバイスであるが、その分制御が複雑でややわかりにくい。
そこで使う上で勘所となることを記録しておくことにした。

１．パワーオンリセット
　MCP23S17には電源投入時にリセットがかかる機能があるが、あまり使えない。
　通常コントローラのSPIがその後初期化されるので各信号線が変化することがある。この変化をMCP23S17が受け取るのでその次のSPIからのパケットを正しく受け取れない。
　回避策は、MCP23S17のリセット信号をコントローラに接続し、コントローラのSPIの初期化後にリセットをかけ直すことで回避できる。

２．リセット
　データシートによるとリセット信号はレベルで動作しているように見えるが、
立ち下がりと立ち上がりの両エッジが必要なようだ（詳細は検証していない）。
　１の回避策を採用する場合は、ハイレベルにしてある（リセット解除）状態からローレベルにしてハイレベルに戻す操作を要する。

３．データ転送
３．１　デバイスの設定　
　１６ビットのパケットを送る。
３．２　読み出し、書き込み
　バイトモードとワードモードがあるが、コマンドが１６ビットなのとデバイスのポートが１６ビットなので私はワードモードを好んでいる。
　ワードモードの場合、読み出しも書き込みもパケットは３２ビット（２ワード）である。１ワード目がコマンドで、２ワード目がデータで読み出しの場合は適当な値を１ワード送信するとMISOに読み出しデータが乗ってくる。
Ubuntu 18.04 バーチャルホスト

* バージョン

Ubuntu 18.04.4 LTS
Apache/2.4.29 (Ubuntu)

---

* ホームディレクトリに、public_htmlディレクトリを作成する
mkdir /home/user/public_html
※ 例: ユーザー名は、userの例

* index.htmlファイルを作成する
vi /home/user/public_html/index.html

* index.htmlファイルに表示する内容を記述する

例

```
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset="utf-8">
</head>
<body>
テスト
</body>
</html>
```
---

* 管理者権限にする
sudo su -

* 設定ファイルのディレクトリへ移動する
cd /etc/apache2/sites-available

* 設定ファイルのテンプレートをコピーする
cp 000-default.conf test.com.conf
※ 例: test.comという名前のバーチャルホストを作成する例

* test.com.confファイルをviエディタで編集して保存する
vi test.com.conf

```
ServerName test.com
DocumentRoot /home/user/public_html/
```
※ 例: ユーザー名は、userの例

* ホームディレクトリ内に置いたファイルを Webサイトとして公開できるようにする
a2enmode userdir

* test.com.confファイルを反映する
a2ensite test.com

* アパッチを再起動する
systemctl restart apache2

---

* ブラウザで、test.comにアクセスする
ActiveAdmin の グローバルメニューの変更方法について軽く調べた

## はじめに

ActiveAdmin のヘッダーメニューのカスタマイズで、ラベルの変更方法について調べてみました。

## ヘッダーメニューのラベルの変更方法

[ActiveAdmin のドキュメント](https://activeadmin.info/2-resource-customization.html#customize-the-menu) に書いてありますが、ActiveAdmin の `register` ブロックの中で、`menu` メソッドの `label` オプションに文字列を渡すことで設定できます。

```ruby
ActiveAdmin.register User do
  menu label: 'Something'
end
```

## I18n やモデルのメソッドも指定できる

以下のように、メソッドを渡して
メソッドの戻り値は String とします。

```ruby
ActiveAdmin.register User do
  menu label: ->{ User.something_label }
end
```

## proc で渡さないと、1回レンダリングしたあとメソッドの値を更新してくれないので注意

メソッドを渡すのに、直接渡すことができないかと考える方もいるかと思います。
戻り値が String なら、以下のように指定することは可能です。

ただ、メソッドが実行されるのは最初一度のみで、以降アプリ再起動するまでその値が保持されます。

例えば以下のような設定をしていると、


```ruby
ActiveAdmin.register User do
  menu label: User.something_label
end
```

```ruby
class User < ApplicationRecord
  def self.something_label
    "#{Time.current}"
  end
end
```

ラベルは一度レンダリングした時刻、例えば `2020-03-07 09:12:32 +0900` からリロードなどをしても変わらなくなります。


## おわりに

ドキュメントふまえて色々実験すると勉強になりますね。一度レンダリングしたあと値を保持し続ける挙動についてはまた機会があれば調べてみたいと思います。

## 参考

* [Active Admin | The administration framework for Ruby on Rails](https://activeadmin.info/2-resource-customization.html#customize-the-menu)
第03回　独自開発した「ニューロ型データベースモデリング Ver.1」　縦連結したデータの表示順（ソート順）を【 サブグループ 】で管理する

###
はじめに
---
【 ニューロ型データベースモデリング Ver.1 】とは

「脳を構成する神経細胞（neuron）が繋がり合って情報を司る」
という仕組み（ネイチャーテクノロジー）に着目し
私が独自で研究・開発 してきた「データベースモデリング」です。
使用する静的テーブルは「２個(２種類)だけ」なのでシンプルな構造となり結果的に基本メンテナンスフリー の 汎用データベースモデリング が出来上がりました。

詳しくは【 [開発の歴史](https://kuhen.org/ndb/?page_id=77)：2016-03-04～05　総務省「異能vation」協力・協賛企業マッチングイベントに「ニューロ型データベースモデリング」が選定される 】をご覧下さい。

###
縦連結したデータの表示順（ソート順）を【 サブグループ 】で管理する
---
### ３つのデータを【縦連結】させただけの状態 
![15_2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567414/593c5629-a67a-83c7-9a16-9c116a57ea4f.jpeg)



####【 表示順（ソート順）】　**３列**

　　**１．<font color="Green">グループID</font>**　**２．<font color="Green">T_ID</font>**　**３．<font color="Green">ソート</font>**

| 主キー|<font color="Green">グループID</font>|<font color="Green">T_ID</font>|<font color="Green">ソート</font>|ユニット|入力項目|入力データ|
|:--:|:---:|:---:|:---|:--|:--|:---|
|7|1|<font color="Blue">1(未来)</font>|50|30|<font color="Blue">年齢</font>|<font color="Blue">58</font>|
|1|1|2(現在)|10|10|氏|小島|
|2|1|2(現在)|20|10|氏ヨミ|コジマ|
|3|1|2(現在)|30|20|名|茂|
|4|1|2(現在)|40|20|名ヨミ|シゲル|
|6|1|2(現在)|50|30|年齢|57|
|5|1|<font color="maroon">3(過去)</font>|50|30|<font color="maroon">年齢</font>|<font color="maroon">56</font>|

　　【 <font color="Green">T_ID</font> 】<font color="Blue">　　1（未来：予定）</font>　2（現在）　<font color="maroon">3:（過去：履歴化）</font>
　

### 縦連結した３つのデータを【 サブグループID 】で表示順を管理する
---
####【 表示順（ソート順）】　**４列**
**１．<font color="Green">グループID</font>**　**２．<font color="Red">サブグループID</font>**　**３．<font color="Green">T_ID</font>**　**４．<font color="Green">ソート</font>**
![17_2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567414/1908c459-735f-adf5-aaf0-301e4e2f1cb5.jpeg)

### まとめ
---
####**【 基本 】 ４つの列で【データ】表示順（ソート順）を管理する**
　**１．<font color="Green">グループID</font>**　**２．<font color="Green">サブグループID</font>**　**３．<font color="Green">T_ID</font>**　**４．<font color="Green">ソート</font>**

####「フォーム画面」で縦連結されたデータを横長に表示する時便利
![18.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/567414/2dd1bc14-8113-2356-cb7b-b65d376115a6.jpeg)


###
関連投稿記事
---
前回　[第02回　独自開発した「ニューロ型データベースモデリング Ver.1」　【学習】方法を考える](https://qiita.com/kuhen-org/items/c66dcd6c116aac88a38b)

次回　[第04回　独自開発した「ニューロ型データベースモデリング Ver.1」　既存データを【コンボボックス】として使ってみる](https://qiita.com/kuhen-org/items/05458f9210887dd00b23)
【Rails Sass】Rails でSassを変更しても反映されないとき

# Rails でSassを変更しても反映されないとき

```terminal:terminal
> rake assets:precompile
> git add -A
> git commit -m "コメント"
> git push heroku master
> heroku restart
> heroku open
```

いったん手動でコンパイルしたらなんかいけた！
強強のかた、知見がございましたらご教示ください涙

※rake assets:clean
でrake assets:precompileは代替できそう

参考：
https://qiita.com/masarufuruya/items/d6125332cc3394b5177c
AWS のビデオカンファレンスサービス Amazon Chime を使う

https://aws.amazon.com/jp/chime/

Amazon Chime は、Amazon Web Services が提供するビデオ会議です。昨年末に東京リージョンも対応しました。

- [Amazon Chime は 14 の AWS リージョンを使用して、参加者により近い場所で会議をホストできるように](https://aws.amazon.com/jp/about-aws/whats-new/2019/12/amazon-chime-can-now-host-meetings-in-14-aws-regions/) (2019/12/3)
- [Amazon Chime Meetings App for Slack アプリが利用可能に](https://aws.amazon.com/jp/about-aws/whats-new/2019/12/announcing-amazon-chime-meetings-app-for-slack/) (2019/12/4)

専用のアプリをインストールしなくても、ブラウザだけでも参加できるのが利点かと思います。画面共有も問題なくできました。
このご時世、急にリモートで仕事しなくてはならなくなったりして、でも相手にわざわざアプリをインストールしてとは言いにくい...そんな場面にも良いのではないでしょうか。

会議をホストするには1日あたり \$3、上限は \$15/月 という料金設定となっています。使わなければお金はかかりませんし、使いまくっても Zoom の [Pro](https://zoom.us/pricing) より安いくらいです。また、利用開始から30日間は無料で(時間制限もなく)ホストできます。会議に参加するだけならアカウント不要で、料金もかかりません。

Zoom と比べて機能的に遜色もないと思うのですが、あまり話題にはならないような...ちょっと分かりにくいんですよね。

## 会議に参加する

ホストされている会議に参加するには、アカウントもアプリも不要です。

主催者から教えてもらった URL リンク (https://chime.aws/XXXXXXXXXX) をブラウザで開くだけで参加できます。ネイティブアプリがインストールされていればアプリが開きますし、インストールされていなければそのままブラウザ上で参加できです。

https://chime.aws にアクセスまたはネイティブアプリを起動して直接 meeting ID を入力しても参加できます。

## ログイン、会議のホスト

会議をホストするには、[Login with Amazon](https://developer.amazon.com/apps-and-games/login-with-amazon) でのログインが必要です。
少々分かりづらいのですが、AWS でも Amazon.co.jp でもなく、Amazon.com のアカウントになります。持っていない場合は Chime のログイン画面から登録しましょう。

ログインしたら「Start a instant meeting」から、会議を開始します。
 
## 支払い

30日の無料期間を過ぎると料金が発生しますが、AWS のサービスが Amazon を認証を使っているだけであり Amazon.com に料金が発生するわけではありません。別途 AWS アカウントが必要になります。(なんということでしょう...)

AWS のアカウントに、支払い対象とする Amazon.com アカウントを追加するイメージです。

詳細の手順は [Purchasing Amazon Chime](https://docs.aws.amazon.com/chime/latest/ag/getting-started.html) ([日本語](https://docs.aws.amazon.com/ja_jp/chime/latest/ag/getting-started.html)) を参照してください。

 1. 支払いをおこなう AWS アカウントで、AWS Console から [Chime](https://chime.aws.amazon.com/) の管理画面にアクセスする。
 2. 「Account」の「New account」から、適当なアカウント名を入力してアカウントを作成する。
 3. 「Inviie users」から、Amazon.com アカウントのメールアドレスを入力する。

無料期間が残っていても直ちに料金が発生するようになってしまうみたいなので、注意です。
OculusQuestのランタイムロード

# はじめに
OculusQuestでランタイム時に端末からVRMファイルをロードし、動的に生成する方法を記述します。

# 環境など（開発環境、実行環境）
- Unity 2019.2.17f1
- UniVRM 0.55.0
- Oculus Integration 13.0
- AliciaSolid.VRM https://3d.nicovideo.jp/works/td32797

# コード
```cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using VRM;

public class LoadFile : MonoBehaviour
{
    GameObject VRM;
    string AndroidFilePath;
    string VRMDirectory = "/VRM/";
    string filename = "AliciaSolid.vrm";

    void Start()
    {
        AndroidFilePath = Application.persistentDataPath + VRMDirectory + filename;
        //Application.persistentDataPath = 
        //storage/emulated/0/Android/data/AppPackageName/files
        //AndroidFilePath =
        //storage/emulated/0/Android/data/AppPackageName/files/VRM/AliciaSolid.vrm

        var context = new VRMImporterContext();
        context.Parse(AndroidFilePath);
        context.LoadAsync(() =>
        {
            VRM = context.Root;
            context.ShowMeshes();
        });
    }
}

```

# 解説
AndroidはStreamingAssets（**Application.streamingAssetPath**で取得できる）からファイルをランタイムロードできないので、Androidの永続ファイルを格納するパスである**Application.persistentDataPath**に、事前にVRMファイルを入れておいて、ランタイムロードを実現しています。
コード中にもコメントで記載していますが、今回は、**storage/emulated/0/Android/data/AppPackageName/files以下**にVRMというディレクトリを作成し、ニコニ立体さんを入れて読み込んでいます。

# 余談というかメモのようなもの
- OculusQuestに任意のファイルを入れる方法は、以下のコマンドでできます。

adb push **任意のファイル名** /storage/emulated/0/Android/data/**PackageName**/files/

任意のファイル名は、拡張子を含むファイル名で、実行するディレクトリからの相対パスで指定します。
PackageNameは、対象のアプリのPackageNameです。（com.Company.AppName的な）

- DirectoryInfoで指定したディレクトリのファイル一覧を取得して選択することも可能です。
- Application.persistentDataPath以外に入れたディレクトリはWebRequestで一旦Application.persistentDataPathに読み込んで取得する方法があるみたいです。今度試してみます。


# 参考記事
- https://www.fast-system.jp/unity-vrm-import-demo/

VRMファイルのゲーム中での生成は上記記事を参考にしました。以前のバージョンだと生成のコードがだいぶ変わっていてうまくできなかったので、ここに明記しておきます。
SAPにUiPathで自動ログインしてテーブル項目を取得してみる

# やること
UiPathでSAPログイン、テーブル項目の取得を自動化する。

# 環境
- SAP GUI for Windows 750
- UiPath Studio 2019.7.0
- SRC Common Reusable Components for SAP® ERP 2.2.0

# 事前準備
## UiPath Connectからコンポーネントをダウンロード
[SRC Common Reusable Components for SAP® ERP](https://connect.uipath.com/ja/marketplace/components/common-reusable-components-for-sap-erp)のサンプルコードを利用します。今回は2020/03/07時点で最新の2.2.0を使っています。

コンポーネントのファイルをダウンロードし、サンプルの設定用エクセルファイルを開き、以下の項目を設定します。

テーブル項目取得サンプルの設定ファイル
Sample Files\Sample_SRC_TABLEDATA_OUTPUT_E\SetInfo\Sample_LoginSetting.xlsx

SAP GUIで接続先設定、ログイン時に入力する項目をファイルに記載しておきます。

- in_AppServer　アプリケーションサーバ
- in_Client　インスタンス番号
- in_Language　クライアント
- in_SystemNumber　ログオン言語

## BAPIパッケージインストール
UiPath StudioにBAPIを利用するためのパッケージをインストールします。
![SAP x UiPath.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149785/5f3f3463-3afe-8810-b9d9-eab4bb17133c.png)

1. UiPath Studioの「パッケージ管理」を選択
2. パッケージソースの「オフィシャル」のチェックボックスを選択
3. 検索窓に「BAPI」と入力して検索
4. 「UiPath.SAP.BAPI.Activities」をインストール

# SAPにログインしてテーブル項目を取得
準備が終わったらUiPathからサンプルを実行します。

## UiPathでサンプル実行
展開したコンポーネントの以下のファイルをUiPath Studioから開いて、実行ボタンを押します。

Sample Files\Sample_SRC_TABLEDATA_OUTPUT_E\Sample_SRC_TABLEDATA_OUTPUT_E.xaml

## 必要事項を入力
ポップアップが出てくるので必要な事項を入力します。

1. SAPのユーザを入力します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149785/11216db8-55bc-490a-b90b-560963017d53.png)

2. SAPのパスワードを入力します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149785/2ebda813-9092-0039-df9b-b8c814115964.png)

3. 出力したいデータを選択します。今回はテーブル項目を取得するのでチェックボックスで指定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149785/d96487f2-ad99-7c79-0840-af09d8605717.png)

4. 取得したいテーブル名を入力します。今回はT001(会社コード)を指定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149785/ade7a905-467b-a92e-2e71-b0c1b5937e2b.png)

5. 取得したデータをダウンロードするフォルダを指定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149785/9d95369a-010f-4fe7-a7d0-8ac001506426.png)

## テーブル項目取得
指定フォルダにDATAELEMENT_T001.xlsxというエクセルファイルが作成され、開くとテーブル項目が取得できている事が分かります。

<img width="600" alt="excel" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/149785/d6cb4d69-1f41-6c3d-1bec-f6275086b001.png">
初心者向け入門書を読んでみた 第1弾

以前執筆した「[初心者向け入門書2冊を比較してみた](https://qiita.com/Haruka_mm_0950/items/3d5cffbf2b7d621418d7)」という記事で、紹介した本それぞれについて記事を書くと言っていたのにずっと放置していたので、1冊ずつ紹介していきます。
今回は『[改訂3版 これからはじめるプログラミング 基礎の基礎](https://www.amazon.co.jp/%E6%94%B9%E8%A8%823%E7%89%88-%E3%81%93%E3%82%8C%E3%81%8B%E3%82%89%E3%81%AF%E3%81%98%E3%82%81%E3%82%8B%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0-%E5%9F%BA%E7%A4%8E%E3%81%AE%E5%9F%BA%E7%A4%8E-%E8%B0%B7%E5%B0%BB-%E3%81%8B%E3%81%8A%E3%82%8A/dp/4297101181)』を紹介します。

#どんな本？
タイトル通り「プログラミングの基礎の基礎」から学ぶ入門書です。
「コンピューターの仕組みって？」「そもそもプログラミング言語って何？」など、土台の部分を丁寧に説明してくれています。
「プログラミングを始めたものの、基本的なことがよく分からない」という初心者の方には最適な良書です。
また「新人さんに基礎を教えたいけど、どう教えたらいいか分からない」という中級以上の方にもおすすめかと思います。
ただし、**特定の言語について解説しているわけではない**ので、あくまで全体像をつかみたい方向けです。
また、丁寧に説明している分ページ数も多いので、活字が苦手な方は読むのがつらいかもしれません。

#おすすめしたい理由
この本をおすすめしたい理由は以下の3点です。

**1. 文章が分かりやすい**
**2. 実例が分かりやすい**
**3. プログラミングに必要な考え方や概念を丁寧に説明**

以下でひとつずつ説明していきます。


##文章が分かりやすい
専門用語を多用しない、読みやすい文章なので、「入門書なのに分かりづらい…」と感じることは少ないでしょう。
例えば、プログラムに関しては以下のように書かれています。

>プログラムは、コンピューターを動かすために欠かすことのできない大切なものです。その正体は、

>**コンピューターが何をすればよいのかを細かく書いた指示書**

>です。

>>p.24　第1章「コンピューターと仲良くなろう」より

他の項目についても、上記のように分かりやすく説明してくれています。


##実例が分かりやすい
この本でプログラムを作ることはできませんが、どんな考えや手順が必要なのかは知ることができます。
著書内で実例がたくさん出てきますが、個人的に印象に残っているのは、お掃除ロボットのプログラムを作る章です。
テレビのリモコンや宅配ピザのチラシが床に落ちている、畳んでない洗濯物が室内に放置、ついでに昨日着ていたスーツもソファに放置。
という状態の ~~汚部屋~~ 雑然とした部屋を片付けて、掃除まで終わらせるために、どんな指示を出したらいいかを考えます。
答えを先に言ってしまうと、**整理整頓→掃除** が主な手順となります。
この実例から、プログラミングの前に仕事内容や手順を決めるのが大事だと分かります。
プログラミングに限った話ではありませんが。
ちなみに、例題のお掃除ロボット、著書内では指示内容が90項目ありました。
実際にコード書いたら、どのくらいになるんでしょうね……


##プログラミングに必要な考え方を丁寧に説明
この本は、全12章、299ページなのですが、うち4分の1はプログラミングに必要な考え方の説明に割かれています。
他の入門書は概念の説明だけで全体の4分の1も使わないでしょうから、かなり丁寧です。
最初の第1章〜第3章までがその部分に当たるのですが、コンピューターが動く仕組みから、プログラムを作る前にやるべきことまで細かく書かれています。
ここでコンピューターの特性と、プログラミング言語が必要な理由が説明されているので、いきなりコードを打つより理解が深まるのではないでしょうか。


#まとめ
プログラミングに関する様々な概念の背景を知ることができるので、個人的には良書だと思います。
ただ、背景なんてどうでもいいから、とにかく手を動かしたいという人には不向きかもしれません。
著者は「そういう人にこそ読んでほしい」と言っていますが。
ちなみに、変数、関数、論理演算子など、全言語共通の概念についても、もちろん説明されていますよ。

#関連記事
[初心者向け入門書2冊を比較してみた](https://qiita.com/Haruka_mm_0950/items/3d5cffbf2b7d621418d7)
[初心者向け入門書を読んでみた 第2弾](https://qiita.com/Haruka_mm_0950/items/f36281fffea2ba233b31)
アセンブラからｃの関数 その２

#概要

アセンブラからｃの関数、呼び出して見た。
x64で、やって見た。

#サンプルコード

```
import subprocess
import os

def gcc():
	s_file = 'main.s'
	test_s = """
.code64
.global main
.text
main:
    call    test
    mov     $message, %rdi
    call    puts
    ret
.data   
message:
    .asciz "world!"
"""
	with open(s_file, 'w') as f:
		f.write(test_s)
	c_file = 'test.c'
	test_c = """
#include <stdio.h>	
void test()
{
	printf("hello ");
}
"""
	with open(c_file, 'w') as f:
		f.write(test_c)
	os.system("gcc -no-pie test.c main.s")
	os.system("./a.out")

if __name__ == '__main__':
    gcc()




```

#成果物

https://paiza.io/projects/agpU9LRNYR04cwQsfCU_Zg

以上。
Drush10とDrush9にダウングレードする(composer経由で)

composer経由で2020年2月にDrushを入れる事で最新版のDrush10が導入できてます

Drush10はDrupal8.4以上を対応、としている所もあり旧環境のD7やD8を触るにあたり、Drushのバージョンを落とす必要が出てきました

以前投稿したcomposer経由でDrush10のインストールを行った記事です
https://qiita.com/m_46/items/2649caa01e683bdc68d2

この状態から、Drush9にダウングレードする手順を記したのがこの記事となります

下記3ステップで構築出来ます


1.「Drush10」のcomposer経由での削除

```
composer global remove drush/drush
```

2.「Drush9」インストール

```
composer global require drush/drush:9
```

3.Drushのバージョン確認

```
drush --version
```

「composer global require」でバージョンを指定する事で選べる様ですね

最新版指定

```
composer global require drush/drush:dev-master
```

旧バージョン指定指定

```
composer global require drush/drush:9
```

といった所でしょうか

※記事寄稿時は2020/03となり、日時経過によっては環境が異なる可能性がある事をご留意下さい

ご参考まで
フロービルダーで制限に達しないようにループを使ってみた

以前商談の一括更新や行動一括作成時にループの解説を致しました。フロー上の更新・作成数が少なかったり、他のプロセスビルダーやApexなど多く使われていない場合は実用的で有効だと思っています。

しかし**ループ上で多数のコレクション変数を対象にレコードの更新・作成や他のプロセスビルダーやApexなどのシステムを多数使われている場合は制限に引っかかってエラーになる可能性**があります。またTrailheadで確認できますが、ループ中にレコードの作成・更新の要素を含むのはよくないようです。

[プロセスビルダーと Flow Builder の機能を組み合わせる](https://trailhead.salesforce.com/ja/content/learn/modules/business_process_automation/business_process_automation_combined)

>レコードの作成や更新などのアクションをループ内に追加することは避けてください。間違いなく制限に達してしまいます。

最近になってようやく納得感をもってレコード作成や更新を一括でできるようになりましたのでご紹介できればと思います。


##制限を意識したフローのループ
以前解説した[商談一括更新](https://qiita.com/DEKA_PIYO/items/51d800f79eec1cbc215b)と[行動一括作成](https://qiita.com/DEKA_PIYO/items/70aa47c4f6d651b189ff)を制限を意識して修正してみました。要素も少ないので変更部分だけのご説明で十分かと思いますがいまいちわからなかった方はそちらを一読されてもよいかと思います。

・商談一括更新(ループ修正版)
![フロービルダーの商談一括更新(ループ修正版).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510376/687ac3fb-4eea-6b93-be1f-21efaf9496b5.png)

・行動一括作成(ループ修正版)
![フロービルダーの活動一括作成(ループ修正版).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510376/dff8e1b2-de8b-f407-b85b-77ab2834a1d9.png)

ループ中のポイントをまとめると以下の通りです。

**１．割り当てで空のレコード変数に値を代入する**
**２．変更したレコード変数を新しく用意したレコードコレクション変数へ追加する**


###1.割り当てで空のレコード変数に値を代入する
既存の項目を更新する場合はそのIDと更新したい項目を指定します。**レコードの一括更新の場合はIDがないとエラー**が発生し、**レコードの一括作成の場合はIDがあるとエラー**になるので注意が必要です。商談の一括更新の場合は商談Idと最初に取得した商談のフェーズが割り当てに必要で、行動の一括作成の場合はユーザに画面へ入力してもらった項目だけ割り当てに使用します。

・商談一括更新の場合の割り当て（レコード更新の場合）
![フロー：商談一括更新の場合の割り当て.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510376/ad02fde7-63f6-55dd-073d-63a83f2e7b31.png)



・行動一括作成の割り当て（レコード作成の場合）
![フロー：行動一括作成の割り当て.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510376/0e7b5519-9856-bf7d-a5e5-95cf27dc96c7.png)




###2.変更したレコード変数を新しく用意したレコードコレクション変数へ追加する
変更したレコード変数を新しく用意したレコードコレクション変数へ追加します。
割り当てで演算子を追加とすれば、文字通りレコード変数がレコードコレクション変数へ追加されていきます。


![フロー：変更したレコード変数を空のレコードコレクション変数へ追加.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510376/67deb4ed-7c0a-cb8f-eb42-c2717b0ae1e7.png)


###レコードコレクション変数にあるレコードをまとめて更新・作成する
レコードを一度に更新する場合は「レコードまたはレコードコレクションからの ID およびすべての項目値を使用」を選択して先ほどレコード変数を追加したレコードコレクション変数を追加します。一度にレコードを作成する場合、「作成するレコード数」を「複数」としてレコード変数を追加したレコードコレクション変数を追加します。

![フロー：レコードまたはレコードコレクションからIDおよびすべての項目値を使用.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510376/a3563e53-0c32-5ae7-d6a5-34b8dc7f5dbb.png)

![フロー：作成するレコード数は複数.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510376/aa0d20dd-2518-63ee-dc9f-f52738c985d5.png)


##ちょっと便利なレコード遷移
![レコード遷移.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/510376/e1a32d44-277a-16b7-d2cd-a71071f4157e.gif)


デバッグをする際、フローにループが含まれているとレコードのIDが沢山含まれます。問題が起こった場合、レコードIDから調べることになると思いますが、classicのように末尾にレコードIDを入力するのでなく、**オブジェクトのAPIとviewの間のレコードIDを調べたいレコードIDに置き換えれば直接レコードにアクセスすることができます**。違ったオブジェクトのレコードIDでも問題なく表示されます。これは例えば**取引先のレコードを見ていてる状態でも商談のレコードIDを変えるだけで自動的にオブジェクトのAPI名も変わります**。
sqlplus: command not foundとなったときの対応方法

- 環境
    - Ubuntu Server 18.04.3 LTS 64bit(EC2インスタンス)

# 事象 : SQL*Plusをインストールしたはずなのにないと言われている
```bash
# インストールしたはずなのに
$ sudo dpkg -i oracle-instantclient12.2-basiclite_12.2.0.1.0-2_amd64.deb oracle-instantclient12.2-sqlplus_12.2.0.1.0-2_amd64.deb 
Selecting previously unselected package oracle-instantclient12.2-basiclite.
(Reading database ... 157738 files and directories currently installed.)
Preparing to unpack oracle-instantclient12.2-basiclite_12.2.0.1.0-2_amd64.deb ...
Unpacking oracle-instantclient12.2-basiclite (12.2.0.1.0-2) ...
Selecting previously unselected package oracle-instantclient12.2-sqlplus.
Preparing to unpack oracle-instantclient12.2-sqlplus_12.2.0.1.0-2_amd64.deb ...
Unpacking oracle-instantclient12.2-sqlplus (12.2.0.1.0-2) ...
Setting up oracle-instantclient12.2-basiclite (12.2.0.1.0-2) ...
Setting up oracle-instantclient12.2-sqlplus (12.2.0.1.0-2) ...
Processing triggers for libc-bin (2.27-3ubuntu1) ...

# ないと言われている
$ sqlplus -version
sqlplus: command not found
$ which sqlplus
$
```

## 原因 : 64bit用は`sqlplus`ではなく`sqlplus64`だから
> 64ビットバージョンをインストールした場合、クライアントは`sqlplus64`と呼ばれることに注意してください。
> [SqlPlusのインストール方法](https://qastack.jp/ubuntu/159939/how-to-install-sqlplus)

## 対応方法 : `sqlplus64`を使う

```bash
$ which sqlplus64
/usr/bin/sqlplus64
# まだ設定していないのでエラーになる
$ sqlplus64 -version
sqlplus64: error while loading shared libraries: libsqlplus.so: cannot open shared object file: No such file or directory
```
[VisualStudio] VS2019テストエクスプローラ上の「不明なプロジェクト」の表示を消すには

# 問題
VS2019にて開発をおこなっている際、テストエクスプローラに「< 不明なプロジェクト >」という項目が表示された。
このテスト失敗の表示は、テストがすべて成功しても消えないので、精神衛生上非常によろしくない。

# 発生した環境
Visual Studio 2019 version 16.4.5
MSTest.TestFramework v2.1.0
MSTest.TestAdapter v2.1.0

# 解決方法
1. Visual Studioを終了し
2. ソリューションが格納されているフォルダの.vs\XXXXX\v16\TestStore\0 というフォルダを削除

# ためになった情報
https://stackoverflow.com/questions/59391984/test-explorer-vs-shows-unknown-project
FormDataでデータ送信する際の"SyntaxError: Unexpected token - in JSON at position 0"というエラーへの対処方法

# はじめに
ファイルアップロードの実装の際に，HTTP通信の表題のようなエラーが出ました．今までJSON形式でデータを送信していたのですが，画像送信をする際のサンプルでFormDataを用いる方法を用いていたので通信方式が変わるらしく生じたエラーのようです．
Web系のアプリ製作の初心者であり，変なことを言っている可能性が非常に高いので，詳しい方は間違いを見つけ次第ご指摘お願いします．

# そもそもこのエラーが出る原因
JSON形式の送信ではありえない1文字目に， "-" という文字が混入していた場合に起こります．（普通は"{"であるはず）
私の場合，送信内容がJSON形式でなく，`multipart/form-data`形式で送信していたため，下記のようなデータを送信していたのでエラーが生じたようです．

```
-----------------------------54363239114604
Content-Disposition: form-data; name="user_name"

hogehoge
-----------------------------54363239114604
Content-Disposition: form-data; name="user_feature"

hagehage

… 続く
```
最初が"-"となっていることがわかると思います．

# 実行環境
Client側：Submitボタンを押した時点で，FormDataを用いてデータをまとめ，fetchによりデータをPOSTする．
Server側：app.post()を用いてデータを受信

## 最初のコードの概形
Client側

```javascript
let formData = new FormData();

formData.append("user_name", "hogehoge");
formData.append("user_feature", "hagehage");
//…続く

for (var item of formData) console.log(item);  //←  普通にformDataの内容が表示できる

fetch("http://localhostのどこかやで", {
    method: "POST",
    headers: {
        'Content-Type': 'application/json;charset=utf-8'   //←  要はここが間違い
    },
    body: formData
});
```

Server側

```javascript
app.post('送信先', (req, res) => {
    // 処理
});

```

## 修正後のコードの概形
Client側

```javascript
let formData = new FormData();

formData.append("user_name", "hogehoge");
formData.append("user_feature", "hagehage");
//…続く

for (var item of formData) console.log(item);  //←  普通にformDataの内容が表示できる

fetch("http://localhostのどこかやで", {
    method: "POST",
    //←  ★もはやHeadersを変更
    body: formData
});
```

Server側

```javascript
const multipart = require('connect-multiparty');  //←  ★npm installする必要あり
app.use(multipart());  //←  ★なんか設定しないといけないみたい

app.post('送信先', (req, res) => {
    // 処理（変化なし）
});

```

ちなみに，Headersを削除せずに`multipart/form-data`の設定を実装すると，Server側でStreamが停止するエラーが出ました．Headersを削除したらそのエラーもなくなったので，ここは実装しないほうがいいかと思います．

# おわりに
HTMLもCSSも経験したことない未熟者が，いきなりReactに手を出してできるものではありませんでした．知識がないとこれには気づけませんね．しかし，headersの設定を意図的になくすことで自動的に設定してくれたり，ライブラリを入れるだけで解決したり，javascriptは非常に便利だと最近感じ始めました．


## 参考文献
・[multipart/form-dataを用いた通信について]("https://www.yoheim.net/blog.php?q=20171201)
・[通信内容の調べ方について](https://hakuhin.jp/js/network_capture.html)
・通信内容を調べるのはOWASP ZAPというソフトでもできる可能性（自分にはまだ早かった）．
AutoLISP 関数処理関数の使い方

[関数処理関数リファレンス（公式ヘルプ）](https://help.autodesk.com/view/OARX/2020/JPN/?guid=GUID-6804DF2D-E5C4-466A-9869-3CDD7A031FAA)

## 引数のリストを指定された関数に渡す　apply
```scheme
(apply '+ '(1 2 3 4 5))
;; -> 15
(apply 'strcat '("a" "b" "c" "d" "e"))
;; -> "abcde"
(apply 'list '(1 2 3 4 5))
;; -> (1 2 3 4 5)
```

## 関数を定義する　defun
```scheme
;; 足し算をする関数を定義
(defun add (a b /)
    (+ a b)
)
(add 1 2)
;; -> 3

;; タンジェント求める関数を定義
(defun tan (x)
    (/ (sin x) (cos x))
)
(tan (/ pi 4))
;; -> 1.0
```

## AutoLISP 式として評価した結果を返す　eval
```scheme
(eval "car")
;; -> "car"
((eval car) '(1 2 3 4 5))
;; -> 1
((eval (read "car")) '(1 2 3 4 5))
;; -> 1
```

## 匿名の関数を定義する　lambda
```scheme
;; 2乗する匿名関数をシンボル(変数) f に格納
(setq f (lambda(x) (* x x)))
;; -> #<USUBR @0000029296274f48 -lambda->
(f 2)
;; -> 4
```

## 各式を順に評価して最後の式の値を返す　progn
```scheme
(if t
    (setq a '(1 2 3))
    (setq b (apply '+ a))
)
;; -> b = nil
(if t
    (progn
    	(setq a '(1 2 3))
    	(setq b (apply '+ a))
    )
)
;; -> b = 6
```
【Heroku】リリース後、アプリのアップデートをHeroku上アプリに反映させる

# リリース後、アプリのアップデートをHeroku上アプリに反映させる

# 1.変更をステージングする

```terminal:terminal
> git add -A  #-A は変更を加えた全ての変更をステージングさせる
もしくは、
> git add 特定のファイル名  
```

# 2.ステージングした変更をコミットする

```terminal:terminal
> git commit -m "コメント"
```

# 1.コミットした変更をHeroku上のアプリにPushする

```terminal:terminal
> git push heroku master # ←ブランチ名をば
```

３ステップでできる！
素晴らしい！🎉
fishシェル使用時にvirtualenvを通常のコマンドで立ち上げられない

久々にvirtualenvを使おうと思ったら謎のシェルスクリプトエラーが発生しハマったのでメモ。

## 結論
`source venv/bin/activate`

の代わりに

`source venv/bin/activate.fish`

を使う。
`venv`の部分はもちろん作成した仮想環境名。

## 参考
https://github.com/pypa/virtualenv/issues/853
TypeScript: メソッドやゲッターの計算結果をキャッシュするデコレータ

実行すると計算結果をキャッシュするデコレータがあると便利です
下記のようにかけるようになります

```ts
import { memoized } from '~/util/memoizedMethod'

class Foo {
  @memoized
  async action() {
    console.log('₍₍(ง˘ω˘)ว⁾⁾')
  }
  @memoized
  get magicNumber() {
    console.log('42')
    return 42
  }
}

const foo = new Foo()
foo.magicNumber // 42
foo.magicNumber // なにも出ない
foo.magicNumber // なにも出ない
await foo.action() // ₍₍(ง˘ω˘)ว⁾⁾
await foo.action() // なにも出ない
await foo.action() // なにも出ない
```

#### 実装

```ts
const memoized = (_target: any, _propKey: string, descriptor: PropertyDescriptor) => {
  const key =
    'function' === typeof descriptor.value ? 'value' :
    'function' === typeof descriptor.get ? 'get' :
    null
  if (!key) return
  const original = descriptor[key]
  const map = new WeakMap<any, { v: any }>()
  descriptor[key] = function() {
    const r = map.get(this)
    if (r) return r.v
    const v = Reflect.apply(original, this, arguments)
    map.set(this, { v })
    return v
  }
  if ('get' === key && 'function' === typeof descriptor.set) {
    const original = descriptor.set
    descriptor.set = function() {
      Reflect.apply(original, this, arguments)
      map.delete(this)
    }
  }
}
```

引数を持つメソッドなどに使うとうまく動かないので型エラーが出るようにしたいけど無理っぽい？


#### 関連

[TypeScript: 計算結果をキャッシュする関数](https://qiita.com/suin/items/c19a0be9c64783c03ca0)
【おっちゃんがエンジニアになるまで】@4ヶ月目〜面接の声がかかる〜(転職編)

#はじめに
**こんにちは！ばーんです。**

30歳、独学、業界未経験、既婚者、働きながら
のおっちゃんが具体的にどうやってエンジニアになれるのか？
を（ほぼ）リアルタイムで振り返り共有させてもらいます。

自身の思考整理がメインですが、これから目指す方の指標に少しでもなれれば幸いです。

3ヶ月目(前月)は[こちら](https://qiita.com/baan_nasebanaru/items/06828bab067940e7a54c)
最後は[こちら](https://qiita.com/baan_nasebanaru/items/7da95e0811cb54a49e44)

##数字振り返り

1ヶ月目　Total  76h(1日平均2.5h)
2ヶ月目　Total  91h(1日平均3.0h)
3ヶ月目　Total 102h(1日平均3.3h)
4ヶ月目　Total  83h(1日平均2.7h)

Day 91-100　26h
Day101-110　21h
Day111-120　36h

##学習内容

今回からは転職に向けたお話がメインなので、学習内容はさっくりいきます。

###Day 91-100:デザイン学習、Qiita投稿、転職サイト登録

ノンデザイナーズブックを読みましたが、めちゃくちゃ名著でした！時間みつけて、まとめ記事投稿したいと思います。
また、↑これを読んだあとにcocodaに投稿したんですが、結構良くなってました！

後は、この期間にQiitaに投稿続けて思考整理したのと、メンターのすすめで転職サイトに登録しました！これは後で詳しく書きます。

###Day101-110:案件獲得、生のJavaScript

初案件獲得できました！
メンター経由のお話ですがwまぁなにわともあれ、モチベーションあがりました。
後は、参加しているコミュニティでAtcoderに挑戦しました！これもむちゃくちゃ楽しかったですね。アルゴリズム組み立てるのめっちゃ好きみたいです。

###Day111-120:読書、contentful、Git

この週はメンターに4日間みっちりオフラインで教えてもらいました！神！
Gitの理解が深まったのが相当大きいですね。
後は、当初予定ではWordPress進める予定でしたが、contentfulに切り替えました。WordPressレッドオーシャン過ぎて、正直ちょっと躊躇してましたし...まぁいいか。

##学習まとめ

4ヶ月目の感想は、学習時間減ったということが主な感想です。ここはしっかり掘り下げて考えます。
**1.案件進めるのは意外と苦労が多い
2.複数案件の同時進行でややパンク
3.自律**

1.2.は今後気をつければ回避できるので省略しますが、3.については自分が結構ルーズだったことを思い出しました…
来月は少し自分に追い込みかけます（パンクしない程度に）
自分の性格的にもそのほうが進めるので。

##転職のお話

今回はここがメインです。行動したこと＋現状の成果？を書いておきます。

###前提条件

必ずしもすぐに転職したい！というわけではありません。良いところがあれば転職しよう。というスタンスです（家庭の事情もあるので）
2019年11月よりエンジニアリングの学習開始。HTML→CSS→JavaScriptを学習し、静的なサイト制作を行っています。2020年3月より案件を受注。フリーランスエンジニアとして開業予定。2020年4月にITパスポート取得予定。2020年10月にl基本情報処理取得予定。
月に100hほどが最大で稼働可能。副業としての参画も視野に入れています。
今年いっぱいは恐らく関西が拠点です。30歳、既婚者、業界未経験。

###転職に向けてしたこと
1.転職サイトへの登録(Green,Wantedly)
2.SNSプロフィールの修正
3.[1.2.]の項目にアドバイスを頂く
4.Twitterの募集に参加する

1.はいわゆるエンジニアに向けた転職ならとりあえず登録した方が良いのかなと思うサイトです。
####2.SNSプロフィールの修正
基本的にした方が良いと聞いたのは**「Twitter,GitHub,Codepen,Qiita,Portfolio」の相互リンクです**（勿論成果物がある場合のみですが）
大抵それぞれのプロフィール欄に設置場所があります。もし、この中から選ばないといけない場合はGitHubが良いとのことでした（エンジニアのとして見られる場合は貴重なソースなので）
残りの優先順位は自分がどれをアピールしたいか？で決めていいんじゃないかな〜とも思います。

今ふと考えるとAtcoderなども載せて良いかもしれませんね。


3.は自分の場合はメンターと第三者に見てもらいました。個人的な感覚としては、こういう場合有識者だけの偏った意見ではなく、幅広い視野が必要だと考えるので。結局それを判断するのは自身ですし。
見てもらう前よりはだいぶ良くなったと思います。
探せば有料で(と言ってもかなり安い)実施していただける方もいますし、基本的には第三者に見てもらった方が良いと思います。

【例】両方自身の実施例です
[Twitterプロフィール](https://twitter.com/baan_nasebanaru)
[転職プロフィール](https://www.wantedly.com/users/18404919)

4.基本的にこちらから能動的に転職活動は暫くしませんが、Twitterで流れているものは積極的にアタックしてます。

###得た成果

ちょうど登録してから1ヶ月ほど経過しました。成果としては
**書類よかったら送ってきてよ！的な連絡が約10件
こちらが書類送ったのが1件**

※Twitterは5件こちらから連絡して1件待機中です

です。勤務地や年収で断念するのはちょっと歯痒い気持ちですね…（魅力的に見える会社も多かったので）

来月の振り返りは選考進めた企業がどうなったか？その他の動きは？という点で振り返りたいと思います。

##さいごに

今回も最後まで見ていただきありがとうございましたm_ _m
実は記事を書いてる現在、アルゴリズム組み立てていくのがすごく楽しくなっちゃってますw
その辺りも次回触れたいなーと思います。それでは！

ばーん。
Alloyで書こう：私は彼？

Alloyでパズル(1)、(3) に解説を加筆した流れで。
ふだん言葉にしていない部分もしっかり書こうという話。
仕事を海外発注する場合に限らず、言ってない・書いてないところにバグは潜むもの。
さすがにパズルではなさすぎるので、Alloyでパズルシリーズとは別とした。

# 問題

Alloy本 A.3.1 驚くような三段論法 より
> Doris Day の歌に、次のような節がある。
　　*“Everybody loves my baby
　　 but my baby don’t love nobody but me."*
　　みんな私の彼が好き
　　でも彼は私以外好きじゃない。
David Gries が指摘したところによると、論理的に厳密な立場からすれば、これは「私は私の彼だ」を含意しているそうだ。
(中略) Doris Day が言いたかったであろう形に記述し直し、今度はアサーションが反例を持つことを示せ。

# 書いてみる

## 例1

できる限り勝手な解釈を入れずに、そのまま書くとこうなるだろう。

```alloy
sig Person {loves: set Person} { MyBaby in loves }
one sig Me in Person {}
one sig MyBaby in Person {} { no loves & Person-Me }

run {}
check { Me = MyBaby }
```
確かに言葉通りなら、彼は（彼が好き かつ 私以外好きじゃない）ので「私＝彼」でないと成り立たない。
![mybaby.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/20005/78adc9fe-dd4a-8877-2868-23611e479d94.png)

## 例2

常識的に考えると「言いたかったであろう形」はこんな感じか。

```alloy
sig Person {loves: set Person-this}     // 自己愛について話してない
one sig Me,MyBaby extends Person {}     // 私と彼は別人

pred everybodyLovesMyBaby {             // (彼以外の)みんなは彼が好き
    (Person-MyBaby) in loves.MyBaby
}
run everybodyLovesMyBaby

pred myBabyLovesNobodyButMe {
    MyBaby.loves = Me                   // 彼は私だけが好き
}
run {
    everybodyLovesMyBaby && myBabyLovesNobodyButMe
} for 5
```
![mybaby2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/20005/ca446413-6dce-f519-3e98-e4a22e3e4cdc.png)

## 例3

しばらくして思った。
いや違う、そんなにくどい解釈が言いたかったことじゃない。
こうか。

```alloy
let everybody = Girl            // "everybody" means "every girls"
sig Girl {loves: set Boy}       // loves: lone Boy の方が気持ちに合っているかも
sig Boy {loves: set Girl}
one sig Me in Girl {}
one sig MyBaby in Boy {}

fact {
    everybody in loves.MyBaby   // Everybody loves my baby
    MyBaby.loves = Me           // my baby don’t love nobody but me (He loves only me)
}

run {} for 4 but exactly 4 Girl
check { Me = MyBaby }
```
BoyとGirlという概念が現れた（今の時代なら同性愛も念頭におくかもしれないが..）
![mybaby2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/20005/47cc870e-9889-c4d0-0836-e51476162f6d.png)

## 例4

ちなみにあえて空気を読まずに「私以外好きじゃない」に戻すと

```alloy
let everybody = Girl            // "everybody" means "every girls"
sig Girl {loves: set Boy}       // loves: lone Boy の方が気持ちに合っているかも
sig Boy {loves: set Girl}
one sig Me in Girl {}
one sig MyBaby in Boy {}

fact {
    everybody in loves.MyBaby   // Everybody loves my baby
    no MyBaby.loves & (Girl-Me)　// my baby don’t love nobody but me
}

run {} for 4 but exactly 4 Girl
check { Me = MyBaby }
```
私も好かれてなかったという身もふたもない解釈が出る（私が好きとは言ってない）。
![mybaby4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/20005/5ac654c3-82a9-6ef6-258b-348ad31efded.png)


なお、例1以外では check は「左辺と右辺は＝になりえないって定義してるよね」と警告される。

```
== is redundant, because the left and right expressions are
always disjoint.
Left type = {this/Me}
Right type = {this/MyBaby}
```

# まとめ

言葉にされていない部分を仕様化・実装すると、例え意図をくみ取ろうとしてもこれだけ解釈が揺れる。
だから人に何かを頼むときは、できる限り正確で曖昧さのない仕様を書こう。
たぶんそれは、日本語や英語だけでは難しい。

# 参考

- Daniel Jackson：[抽象によるソフトウェア設計 ―Alloyではじめる形式手法](https://www.amazon.co.jp/dp/B07BKRG85J)
ASUSX205TAでLinuxMintが起動できない

　Windows8.1搭載のAsusX205TAに以前CloudReady（ChroniumOS)を入れたのですが、ドライバーの問題で色々と面倒が起きたので、しばらく放っていました。しかし、最近Macを使うことが多くなりLinuxも使ってみたいと思うようになりました。ChroniumOSでもLinuxは使えるんですが、折角ならLinuxのディストリビューションを使ってみたいと余っていたX205TAを使うことにしました。ただ、起動に悪戦苦闘したので、検索に引っかかるようにメモ書きを残しておきます。
#32bitOSでのUEFIでのブートはefiファイルが必要
　UbuntuとかCentOSとかいろいろなディストリビューションでも試したものの、下記のリンクの手順を踏まないと起動しませんでした。
[32bit-UEFI環境でLinux-MintをUSB-bootする](https://www.segmentation-fault.xyz/entry/2017/05/28/232406)

##X205TAとLinuxMintの相性
　かなり良いです。ちょっとした作業なら問題なさそうですね。
LinuxMint19.3MATEエディションをインストールしています。
各種ドライバーも問題なし。
【Docker】Error loading shared library liblzma.so.5: No such file or directory を解決する

#docker-compose upすると・・・

```
require': Error loading shared library liblzma.so.5: No such file or directory 
(needed by /usr/local/bundle/gems/nokogiri-1.10.5/lib/nokogiri/nokogiri.so) - 
/usr/local/bundle/gems/nokogiri-1.10.5/lib/nokogiri/nokogiri.so (LoadError)
```
このエラーが出ました。
ちなみにPCはMacです。
職場でMacを使用している人も同様のエラーが発生し、
ググってもジャストな解決策がなかなか出てきませんでした。
しかしとある先輩が見事解決。

#原因
xz-devというパッケージがないことが原因だそうな。

#解決策
コンテナが立ち上がらないので`docker commit`でwebコンテナに入り、
[このパッケージ](https://pkgs.alpinelinux.org/contents?branch=edge&name=xz-dev&arch=x86_64&repo=main)を`apk add xz-dev`でインストール。

してもいいのですが、dockerfileに下記のように書いて`docker-compose build`してもOK。

```
RUN apk add xz-dev
```

これで無事にwebコンテナが立ち上がるようになりました。

#あとがき
短期間で私含め3人がこの現象に立ち合いました(全員Mac)。
なのになかなか解決策が見つからずでしたが、ひとまずこれで安心。
LaravelでSlackへの通知設定してるとき、例外発生時にスタックトレースを送らないようにする

# やりたかったこと

LaravelでSlackに直接ログを通知するようにしてるとき。
例外が発生したときのSlack通知で。
スタックトレースは送らないようにしたい。
（Slackの通知用チャンネルがエライことになった）

# 実行環境

Laravel 5.7

# やったこと

logging.php に設定追加すれば完了！

```diff
        'slack' => [
            'driver' => 'slack',
            'url' => env('LOG_SLACK_WEBHOOK_URL'),
            'username' => 'Laravel Log',
            'emoji' => ':boom:',
            'level' => 'critical',
+           'context' => false,
        ],
```

# どうなるのか

こういう通知が届くようになります。
恐ろしく長いスタックトレースで流されずにすみます。
<img width="825" alt="スクリーンショット 2020-03-07 1.30.33.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108431/6967c634-5eda-c040-850d-b3d67b289473.png">

（設定ミスったままmigrateを実行した図）

## ドキュメントに載ってなかったけど、コード読んでたら見つけました。

https://github.com/laravel/framework/blob/5.7/src/Illuminate/Log/LogManager.php#L267-L283

```php:vendor/laravel/framework/src/Illuminate/Log/LogManager.php
    /**
     * Create an instance of the Slack log driver.
     *
     * @param  array  $config
     * @return \Psr\Log\LoggerInterface
     */
    protected function createSlackDriver(array $config)
    {
        return new Monolog($this->parseChannel($config), [
            $this->prepareHandler(new SlackWebhookHandler(
                $config['url'],
                $config['channel'] ?? null,
                $config['username'] ?? 'Laravel',
                $config['attachment'] ?? true,
                $config['emoji'] ?? ':boom:',
                $config['short'] ?? false,
                $config['context'] ?? true,
                $this->level($config),
                $config['bubble'] ?? true,
                $config['exclude_fields'] ?? []
            ), $config),
        ]);
    }
```

引数はこちらで
https://github.com/Seldaek/monolog/blob/master/src/Monolog/Handler/SlackWebhookHandler.php#L40-L49
Kotlin coroutine入門 ② ~ coroutine scope & jobについて~

[Kotlin coroutine入門①](https://qiita.com/ymkit/items/f0e0b2e8644e83bcace1)の続きです。
前回は、coroutineとは？から仕組み、launch、async、awaitの動きをみました。
今回は、coroutineをandoridで扱う上で知っておきたい coroutine scope & jobについて書いていきます。

# CoroutineScope &CoroutineContextとDispatchersを理解する

### CoroutineContext
CoroutineContextは、要素のセットです。 coroutineの文脈や環境の状態を表す値の集まりで、キーと値のペアとして情報を保持しています。主な要素としてはcoroutineのjobとDispatchersです。

端的に言うと Coroutineを利用するための情報が全て入っている。ここでCoroutineが実行される


### Dispatchers
Dispatcher はコルーチンをどのスレッドで実行するかといったことを決定します。
以下のような種類があります。

#### Dispatchers.Main
UIに関する処理をするメインスレッドの指定です。
##### Dispatchers.Main.immediate
UI更新を即時行いたい際に使用されます。
##### Dispatchers.Default
共有スレッドプールを使用し、CPUのコア数に従って設定される。
CPUに負荷をかけるような計算をするような処理に対して使うことが推奨されます。
##### Dispatchers.IO
その処理に必要なコルーチンの数に応じて必要な分だけ共有スレッドプールを使用する。
DBの検索等、I/Oに負荷をかけるような処理に対して使うことが推奨されます。
##### Dispatchers.Unconfined
一度中断させて再開した場合は別スレッドに切り替わっている可能性があります。

### job
任意のスレッドで行う仕事。launchなどCoroutineBuilderにて作成されたコルーチンはJobとして扱われる。

### CoroutineScope
CoroutineScope とは、コルーチンが所属する仮想的な領域です。
コルーチンはいずれかのスコープに属します。
launch や async といったコルーチンビルダーは CoroutineScope の拡張関数として定義されているため、 CoroutineScope なしではコルーチンは起動できません。
前の記事でsuspend関数がCoroutineもしくはsuspend関数からしか呼び出せないのは、このためです。



以上の関係の全体を把握するには[ここの](https://qiita.com/offwhite/items/94540e7cc3b330507c9c#%E9%96%A2%E4%BF%82%E5%9B%B3)関係図が分かりやすいです

![alt](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F318776%2Fbb89be7e-1af2-dd2d-4be1-f307f4018a41.png?ixlib=rb-1.2.2&auto=format&gif-q=60&q=75&w=1400&fit=max&s=59c92ab165b718326a2c6e307029f84d)


# まとめ
前回launchやasyncで試したコードはCoroutineScope やContext Dispatchersによって動いていることが分かりました。
次は[Kotlin coroutine入門 ③~ViewModelの中でcoroutineを扱ってみる~](https://qiita.com/ymkit/items/8738e84b58d55abfce29)
オレオレ Kotlin Extensionライブラリを作ってみた

### ライブラリ作っちゃった
ここ数ヶ月の間でフルKotlinの新規Androidアプリ開発に携わっており、ktxやExtensionの知見が貯まってきたのでライブラリ作っちゃおっかなーってことでやっちゃいました！

[common-ktx](https://github.com/sasa-nori/common-ktx)

まぁ、名前に関してはツッコミは不要ですｗ

### どんな内容なの？
よくある実装をExtensionで実装してます！

例えば、こんな感じでダブルクリック禁止のクリックリスナーをセットできたり

```Kotlin:MainActivity.kt
button.setOnSingleClickListener { 
   // run
}
```

こんな感じにSharePreferencesの値を扱えたり
_※委譲プロパティでゴニョってるよ！_

```Kotlin:MainActivity.kt
val pref = Preferences(this)
val isFirstLaunch:Boolean = pref.isFirstLaunch
```

こんな感じにRuntimePermissionのチェックが出来ちゃったり

```Kotlin:MainActivity.kt
if (hasPermission(arrayListOf(
        Manifest.permission.WRITE_EXTERNAL_STORAGE,
        Manifest.permission.READ_EXTERNAL_STORAGE
    ))) {
    // run
} else {
    // request permission
}
```

お決まりの処理をサクッと呼び出したいときに便利そうだなってことで色々用意してます！

### 入れ方

下記の感じで入れてもらえたら動きます！（はずです！）
 
```gradle:build.gradle
allprojects {
    repositories {
        google()
        jcenter()
        maven { url 'https://jitpack.io' }
    }
}

```

```gradle:app/build.gradle
dependencies {
    implementation "com.github.sasa-nori:common-ktx:$latestVersion"
}
```

最新バージョンはこちら
 [![](https://jitpack.io/v/sasa-nori/common-ktx.svg)](https://jitpack.io/#sasa-nori/common-ktx)

ライブラリの方で導入している各種ktxライブラリは `implementation` ではなく `api`で宣言しているので、そのまま同じバージョンのものが使えるようにしております

ちなみに、Android 6.0 (minSdkVersion 23) となっておりますので...ご注意を

そして国内外の方にも使っていただけるようになるべく日本縛りはない感じで作ってます！

LocaleとかJAPANにしたかったけど！！

READMEなんかもなるべく英語で書いてます！（英単語並べただけｗw

### 今後のメンテ

基本的に私が思いついたら更新していく予定ですが、皆様のissueやPRお待ちしておりますので是非コミッターになっていただけると嬉しいです！

ブランチ運用については `git flow`でいく予定です！

`develop` ブランチに対しての `feature` ブランチからPRを作成しますとDangerが実行されるようになっていますので、Lintエラーはちゃんと解決してもらってからじゃないとマージはしないです :thumbsup: 

#### AndroidのKotlin利用プロジェクトの必須ライブラリを目指して！！
[common-ktx](https://github.com/sasa-nori/common-ktx)をよろしくおねがいしますー！
paiza #コードクロニクル

|&nbsp;|URL|
|:--|:--|
|コードガールこれくしょん|https://qiita.com/cielavenir/items/ea97544089a5a3ca686f|
|コードクロニクル|https://qiita.com/cielavenir/items/3124ec862325682d381d|

ガルこれと比べると、時間制限がゆるくなったおかげで大幅にやりやすくなりました。
というかガルこれが鬼畜すぎたんです。 ~~stage17を22秒って無理ゲーでしたよ。。~~ これはもしかしたらstage17は60秒だったかもしれんが、とかく時間制限がきつい印象しか残ってないという程度に取っていただければ

あと、問題が大幅に読みやすくなったのは評価できますし、乱数関数の使い方を問う問題がなくなったのも良いです。randintって関数名が重要なのではないんだね。

## 200307

リーダー「ディニエル」(スコア7%)で51467点。

## 共通

`x == 1`と書くより`1 == x`と書いたほうがタイプ数が短いなら積極的に行きましょう。なお定数を左に書く記法をヨーダ記法と言います。

## PHP

### 変数

変数がいっぱい出てくる問題では同じ数値を打ち込んだほうが変数を打ち込むより速いと思います。$は早打ちできない。

### 型

`gettype($value)`です

## Ruby

### 型

`value.class`です

### each

each問題の意地悪な例だと`||`の中に変数を書き足さないといけない問題があります。注意。

## Python

Python3であることに留意。printは括弧必要です。

### 型

`type(value)`です

### if

ifの最後のコロン(:)を忘れずに書き足しましょう。

### 複文

セミカンマ(;)を使うと、if/for等以外は1行に連結できます。オートインデントに不安があるので有効だと思います。
collection_selectにデフォルト値で空欄を設定する方法

環境　rails 5.2.3 ,ruby 2.5.1

# 先に結論から
include_blank: true
を付ける！

## 付け方（例）
`= i.collection_select :month_id, Month.all, :id, :name, include_blank: true`

## view画面では
<img width="101" alt="スクリーンショット 2020-03-07 1.03.58.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558973/e55136eb-c109-2cff-7bc3-ae2a31975fec.png">
見事空欄が表示できた！
GASのプロジェクトを1リポジトリで管理するためのテンプレートを作りました

## なにか
- GASをTypeScriptでかける[Clasp](https://github.com/google/clasp)を1リポジトリ（1ディレクトリ内）に複数プロジェクト作成できるnpm-scriptベースのツール
- [リポジトリはこちら](https://github.com/2or3/multi_gas_project)

## どういうことか
- `npm run create --project=[Project Name] `とかやると`multi_gas_project`のディレクトリ内に`[Project Name]`の名前でディレクトリができて、その中の`dist`内の`index.ts`ファイルにTypeScriptでGASのコードがかけます
- もちろん、`push`とか`deploy`とかもできます
コンソールを使って指定のチャットワーク部屋のメッセージをすべて取得する。

# これはなに？

チャットワークの部屋のログをすべて取得できるスクリプトの紹介です。

## モチベーション

チャットワークのログをテキストデータとして取得できないかという相談がありました。

チャットワークの API だと最新100件までしか取得できないため、なんとかできないか試行錯誤しました。
https://developer.chatwork.com/ja/endpoint_rooms.html#GET-rooms-room_id-messages

同じ目的のものとして [goodbye_chatwork](https://github.com/swdyh/goodbye_chatwork) があったが、自分のログイン方法が SSO だったためか、[issue があった reCAPTCHA の影響か](https://github.com/swdyh/goodbye_chatwork/issues/29) 、直接は利用できなかった。スクリプトを参考にした。

# スクリプトは？

以下の gist に上げています。

コンソールを使って指定のチャットワーク部屋のメッセージをすべて取得する。
https://gist.github.com/junjanjon/8ce62c1cb90e817b1247de672bf93116

## 使い方

以下を書き換えればどの部屋でも利用できます。

```js
// 取得したいチャットルームのルームID。先頭のridを除いた数字のみ。
// [] を指定すると、アクセスできる全ルームの情報をダウンロードします。
var TARGET_ROOM_IDS = []
// var TARGET_ROOM_IDS = [123456789, 987654321]

// 取得したくないチャットルームのルームID。
// ログ用ルーム等のダウンロードを除外するのに利用します
var EXCEPT_ROOM_IDS = []
// var EXCEPT_ROOM_IDS = [123456789]

// 通信間隔[ミリ秒]。ダウンロードするデータの規模が大きい場合は、1000（1秒）ぐらいに指定してください。
var INTERVAL_TIME = 300;

// チャットワークのホスト. 企業用の場合は適宜修正ください
var HOST_URL = "www.chatwork.com"
// var HOST_URL = "kcw.kddi.ne.jp"
```

## どうやって使うの？

Google Chrome のデベロッパーツールの中の機能、コンソールを利用します。ほかのブラウザにも同等の機能があるので読み替えてください。

![image1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63607/3680909e-3343-fbf2-7a95-7b0adfd7867e.png)

![image2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/63607/5751f940-a166-30fd-0e4a-ecc1d4f1c527.png)

20件のメッセージごとにINTERVAL_TIME\[ms\]待ちます。

## どんな結果が来るの？

ダウンロードディレクトリに `{部屋ID}_messages.json` がダウンロードされます。

ダウンロードディレクトリに添付ファイルが `{部屋ID}_{ファイル名}` でダウンロードされます。

### `_messages.json` の内容について

最上位が配列のデータです。配列内の各要素がメッセージです。

普通のテキストメッセージの例を以下に表します。

```json
[
  ...,
  {
    "id": "123451234512345",
    # ユーザID
    "aid": 1234567,
    # メッセージ内容
    "msg": "Hello World",
    # メッセージタイプ: テキストメッセージ、部屋作成、部屋参加、アップロードなどがある
    "type": "text_message_type",
    "tm": 1234567,
    "utm": 0,
    # 部屋内のメッセージのインクリメントの値
    "index": 12,
    # リアクション: 絵文字とリアクションしたユーザIDが記録される
    "reactions": [],
    # 投稿時間
    "datetime": "2024/12/12 12:12:12",
    # ユーザ名
    "aid_name": "田中太郎"
  },
```

# 実績は？

約3万件のメッセージがある bot 部屋(ニュースを流し続けていた部屋)のログをすべて収集できました。テキストで約 60[MB] でしたが、問題なくテキストエディタへコピペできました。

# 注意

攻撃のようなリクエストにならないよう注意してください。

開発者コンソールは強力なことができてしまうため注意してください。

# 追記（2025/2/4）

この記事のコメントにさらに高機能なスクリプトを書いていただき、動作確認したため gist と記事にも反映させていただきました。
ありがとうございます！

https://qiita.com/JunkiHiroi/items/4fb577e8a8912a7ffada#comment-fd37f83676fae9543a2d