OmniAICreator/Qiita-1.07M huggingface dataset:
非同期でも分散トーレス！ CloudTasksとCloudTraceを連携させる

## はじめに

Googleの分散トレースモニタリングのCloudTraceはOpenCensusをベースというかその元になっているので、同様に非同期処理であってもちゃんとトレーシング出来ます。

なので、CloudTasksを使って非同期処理を今回実装したのですが、マニュアルとかにやり方が書いてなくて少し嵌ったのでメモ。

## やり方

まずはCloudTasksをJavaで実行するコード。これは基本的にはチュートリアル通りです。

```java
try ( var client = CloudTasksClient.create()) {
    var queuePath = QueueName.of(projectId, locationId, queueId).toString();

    var traceparent = getTraceparent();
    var taskBuilder = Task.newBuilder()
            .setHttpRequest(HttpRequest.newBuilder()
                    .putHeaders("traceparent", traceparent)
                    .setUrl("http://locahost:9000")
                    .setHttpMethod(HttpMethod.GET)
                    .build());

    // Send create task request.
    var task = client.createTask(queuePath, taskBuilder.build());
    logger.debug("task-create", $("taskid", task.getName()));
}
```

ポイントはHTTPヘッダに`traceparent`を使っていることです。[以前の記事](https://qiita.com/koduki/items/200da6983ccc0d7cf3ca
)にも書きましたが、これでコンテキストを伝搬してやらないと、リクエスト自体は反映されるものの一連のリクエストとしてCloudTrace側で認識できません。

そのため、以下のようなコードで現在のSpanから`traceparent`を生成します。

```java
private static final Setter<Map<String, String>> setter = new Setter<Map<String, String>>() {
    @Override
    public void put(Map<String, String> carrier, String key, String value) {
        carrier.put(key, value);
    }
};

public String getTraceparent() {
    var traceContextFormat = new TraceContextFormat();

    var current = Tracing.getTracer().getCurrentSpan().getContext();
    var carrier = new LinkedHashMap<String, String>();
    traceContextFormat.inject(
            SpanContext.create(current.getTraceId(), current.getSpanId(), current.getTraceOptions(), current.getTracestate()),
            carrier,
            setter);
    var traceparent = carrier.get("traceparent");

    return traceparent;
}
```

前提として`opencensus-api`を依存に入れておく必要があります。

`traceparent`のメインは`TraceContextFormat`と`Setter<Map<String, String>>`です。こいつにSpanのトレースIDやスパンIDを渡す事で下記のフォーマットで変換してくれます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54904/cfa13097-6aac-cf47-6737-4e12a21e2611.png)

自前で、作っても良いのですが微妙にフォーマットがめんどくさいので既存のコードを使わない理由も特にないでしょう。

これで、以下のように非同期処理もちゃんとトレースされました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/54904/1ba61992-84f6-f95d-be8d-ffb70e763a90.png)


## 参考:

- [TraceContextFormat.java](https://github.com/census-instrumentation/opencensus-java/blob/e5e9d9224a1c9c5ee981981cf29e86662aef08c6/impl_core/src/main/java/io/opencensus/implcore/trace/propagation/TraceContextFormat.java)
- [TraceContextFormatTest.java](https://github.com/census-instrumentation/opencensus-java/blob/e5e9d9224a1c9c5ee981981cf29e86662aef08c6/impl_core/src/test/java/io/opencensus/implcore/trace/propagation/TraceContextFormatTest.java)
フリマアプリにて桁区切りの実装

## フリマアプリ開発にて実装した桁区切りのまとめを記載していきます。

ruby"2.5.1"
Rails"5.2.4.3"

価格が大きくなってくると金額が分かりにくくなるため、下記の３ページの商品価格について桁区切りを実装していきます。
今回はdelimitedというヘルパーメソッドを使用します。

## ＜変更前＞
- 修正前のトップページ画面
<img width="1440" alt="スクリーンショット 2020-08-14 10.48.27.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/657964/784ebabd-c832-160c-494f-5b5092ca28fe.png">

- 修正前の商品詳細ページ画面
<img width="1440" alt="スクリーンショット 2020-08-14 10.49.04.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/657964/848a7b0f-15a0-8084-7479-17d83b6ea6de.png">

- 修正前の商品購入ページ画面
<img width="1440" alt="スクリーンショット 2020-08-14 10.49.34.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/657964/025c3611-4966-1e72-2381-22584d051110.png">


## ＜手順＞
##### ①「helpers/products_helper.rb」に下記の通りにヘルパーメソッドを定義
　（※商品詳細・購入ページ用）

```ruby:products_helper.rb
     module ProductsHelper
       def converting_to_jpy(price)
    	 "#{price.to_s(:delimited, delimiter: ',')}円"
       end
     end
```

##### ②「helpers/tops_helper.rb」に下記の通りにヘルパーメソッドを定義
　（※トップページ用）

```ruby:tops_helper.rb
     module TopsHelper
       def converting_to_jpy_top(price)
         "#{price.to_s(:delimited, delimiter: ',')}"
       end
     end
```

##### ③「products/show.html.haml」のpriceの箇所の表記を変更

```ruby:show.html.haml
     .show__main__product__content__information__price
       %span
         = converting_to_jpy(@product.price)
```

##### ④ 「products/purchase.html.haml」のpriceの箇所の表記を変更

```ruby:purchase.html.haml
     %p.purchase__main__product-info__inner__content__detail__price
       %span
       　= converting_to_jpy(@product.price)
```

##### ⑤「_item-preview.html.haml」のpriceの箇所の表記を変更

```ruby:_item-preview.html.haml
     .item__caption__details__price
       = converting_to_jpy_top(product.price)
```
※productと分けるために`converting_to_jpy_top`としています。

これで各ページの変更は完了。

## ＜変更後＞
- 修正後のトップページ
![スクリーンショット 2020-08-14 15.18.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/657964/f30c7dac-c10f-5335-b15b-039813818d69.png)

- 修正後の商品詳細ページ
![スクリーンショット 2020-08-14 15.19.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/657964/27c90347-effd-75c4-d81f-a2f6935c1ad7.png)

- 修正後の商品購入ページ
![スクリーンショット 2020-08-14 15.19.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/657964/72b0c52f-4b0c-6bd0-9ff0-2ce01b118891.png)

桁区切りを導入したことで、多少ページに締まりが出てきたかなと思いました。

以上です。
[初心者向け]Railsのコンソールでjbuilderの中身を確認した話

### やったこと
JsonをRailsのアプリで扱いたく、jbuilderで値を生成しました。
ただ、使う前に欲しいデータが手に入るのか確認したく、コンソールで確認してみました。
その手続きの話です。

### そもそも、Jbuilderとは？
Railsの機能としてある、**Builderテンプレート**の中の1種で、[Railsガイドの説明](https://railsguides.jp/action_view_overview.html#builder%E3%83%86%E3%83%B3%E3%83%97%E3%83%AC%E3%83%BC%E3%83%88)は以下の通りです。

> BuilderテンプレートはERBの代わりに使用できる、よりプログラミング向きな記法です。これは特にXMLコンテンツの生成を得意とします。

**Jbuilder**もBuilderテンプレートの一種であり、また、RailsのGemの一つでもあるそうです。JbuilderはRailsのGemfileにデフォルトで含まれています。なので、削除をしていない限り特に何もインストールせずに使えます。

### 使い方
[Railsガイド](https://railsguides.jp/action_view_overview.html#jbuilder)によると、Jbuilderの具体的な使い方は下記の通り。

> .jbuilderという拡張子を持つテンプレートでは、jsonという名前のJbuilderオブジェクトが自動的に利用できるようになります。

```ruby:some_file_name.json.jbuilder
json.name("Alex")
json.email("alex@example.com")
#=> { "name": "Alex", "email": "alex@example.com" }
```

その他の実際に利用する際の具体的な使い方は、[公式ドキュメント](https://github.com/rails/jbuilder#jbuilder)や以下の記事が詳しかったです。

- [Railsのjbuilderの書き方と便利なイディオムやメソッド](https://qiita.com/ryouzi/items/06cb0d4aa7b6527b3645)

### 実際にどんなコードが生成されるのか確認してみた
では本題です。実際にJsonデータを使うのはviewなのですが、その前に、きちんとJsonデータが作られているか確認したく、コンソールで確認してみることにしました。

```
$ rails c
```
で、コンソールを立ち上げて

```
[1] pry(main)> @categories = Category.all
```
インスタンス一覧を`@categories`に代入します。
そして、コンソールで順番に下記を実行します。

```ruby
[2] pry(main)> Jbuilder.encode do |json|
[2] pry(main)*   json.array! @categories, :code, :name
[2] pry(main)* end
#=> "[{"code":100, "name":"カテゴリー1"},{"code":200, "name":"カテゴリー2"},{"code":300, "name":"カテゴリー3"}]
```

無事、欲しいjsonデータが出力されていました＾＾
`json.array! @categories, :code, :name`の部分は、先にあげた下記の記事を参考に作成したものです。

- [Railsのjbuilderの書き方と便利なイディオムやメソッド](https://qiita.com/ryouzi/items/06cb0d4aa7b6527b3645)

引き続き、Jbuilderテンプレートを使って、生成したデータを利用していこうと思います＾＾
英字配列の日本語切替を楽にしたい

# 日本人にとってITの勉強は面倒かもしれない
私は、一応エンジニアですので、心に余裕があるときには、ITの勉強をします。
その際、知識的な内容に関しては、紙とペン(万年筆)を使用してメモをとるのですが、実践的なもの(実際にプログラムを書くもの)に関しては、Markdownを使用してメモをとります。
そうすると、見た目は綺麗ですが、非常に日本語と英語の切替が面倒なんですよね。
プログラムを書いているだけであれば良いのですが、インフラ系の場合コマンドなんかをメモするときの日本語<->英語切替はすごく面倒です。
ブログやドキュメントを書いているときなんかも、日本人は特にこの問題に遭遇するかもしれません。

イメージ1

```
# Docker-composeのコマンド
- Dockerの起動
    - `docker-compose up`
    - `-d`オプションをつけるとバックグラウンドで実行
- Dockerの停止
    - `docker-compose down`
```

イメージ2

```
# TypeScriptのはじめ方
TypeScriptのプロジェクトを作成することにより、複数の`.ts`のコンパイルや管理、設定が簡単に行うことができる。

- 初期化
  - `tsc --init`
    - `tsconfig.json`が生成
- コンパイル
  - `tsc`
  - `tsc -w`
    - プロジェクト上の全`.ts`ファイルがコンパイルされる
```

この中で何回日本語<->英語切替をすることか...
全て英語で書ける外国の人は羨ましいです。
なので、私なりに試した切替方法を紹介していきます。
## 環境
- 仕事
    - 日本語配列外付けキーボード
        - Dell(適当にあったもの)
- 自宅
    - 英字配列外付けキーボード
        - REALFORCE 87UB

最近は、テレワークが多い為、自宅の英字配列キーボードを使う機会が非常に多いです。
なので、たまに会社に戻ると混乱しますね。
あと、シンクラ環境を使用していると、キーが無かったりします。

### 切替方法
英語配列のキーボードで日本語切替を行う方法は以下の方法があります。
感想も添えて書くとこのような形です。

- Windows
    - Alt + ~ (半角/全角)
        - 2ボタン同時押しの中では程よく距離も離れ押し易い気がする
- Mac
    - Command + Space(Ctr + Space)
        - (確か)OSによって仕様が異なるので混乱する
            - 自宅MacMini、自宅MacBook、前使っていたMacBookでキーが違うのが辛い...
        - キーの距離が近すぎて個人的に押し難い
            - Alt + ~ くらいがベスト
    - Ctr + Shift + j
        - 3ボタンなのでまず面倒
        - 結構`j`を探す
        - 英語に切り替えるときなぜ`Ctr + Shift + ;`なのか未だに知らない
    - 右Command(Karabiner-Elements使用)
        - 日本語への切替はし易い
            - 右手は十字キーへの移動が多い為真下のキーを押すのに慣れている
        - 英語への切替が近すぎて遅にくい
            - 左手は固定で動かさない為、真下のキーは押し辛い
    - Caps Lock
        - Macの設定を変更
            - 日本語の環境設定->CapsLockの動作->"オンのとき「英字」を入力"に設定
        - 左手から非常に近く、今のところ一番押し易い
        - ただ、色々なアプリをはしごしているとCapsLockが光ってるのに日本語入力になるタイミングがある

今のところは、Winは`Alt + ~`、Macは`CaspLock`を使用して日本語英語を切り替えています。
CaspLockが便利だと感じる場面は、たまに書くシェルやサーバーの環境変数の設定とかくらいなので、そのときはShiftで頑張ればいいかと思っています。

## 最後に
個人的には、CaspLockによる切替に落ち着いています。
皆さんのやり易い切替方法があれば、是非コメントお願いします!!
雑メモ

### Docker入門
https://y-ohgi.com/introduction-docker/

---

### Dockerfile のベストプラクティス
http://docs.docker.jp/develop/develop-images/dockerfile_best-practices.html

---

### CircleCI チュートリアル
https://circleci.com/docs/ja/2.0/tutorials/

---

### Ruby メンター
https://menta.work/plan/729

---

### Rails → Docker 切り替え
https://ryo10leo.hatenablog.com/entry/2020/01/31/210520

---
電子書籍サービスのシステム処理方式設計－午後

平成31年春期 午後問題4

ファイル：2019h31h_ap_pm_qs.pdf

**１、「新システムの構成の検討」について、図２にa,b,c入れる適切な字句を答えよ。**

aは、WebサーバーのCPU負荷を軽減するための専用の機器ですね。
具体的に、WebサーバーのCPU負荷が高い理由は、WebコンテンツをTLSによって暗号化する機能を兼ねているのためです。そうすると、aは暗号化専用機器ですね。
Webコンテンツの暗号化専用機器
→TLSアクセラレータ

・SSLアクセラレータ  【 SSL accelerator 】 
SSLアクセラレータとは、通信を暗号化するSSL/TLSを利用する際に、暗号化や復号を専門に行う機器やソフトウェアのこと。Webサーバなどが行う暗号化などの処理を肩代わりして負荷を軽減することができる。

bは、単純にこれを考えると難しいかもしれませんね。
ただ、表２に認証AP書いている、「利用者の認証を行うWeb　APIを提供する。Web APIはフロントAP又は、バックAPからWebサーバを介して呼び出される」により、フロントAP or　バックAPにアクセスするときに、最初は、利用者の認証を行うだろう。

リクエスト処理
→
利用者の認証

cは、「現状のシステム構成と稼働状況」に書いている、RDBはディスクの読込み負荷が常に高いのことですね。

読込み負荷
→
読込み負荷


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591618/7b3e6139-be68-d841-3e3e-de77928de7c0.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591618/831b087d-3778-b209-9393-bf29c5f4830e.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591618/e6c6551c-479a-0215-c84d-cbcccfcfb7b3.png)


**２、システム稼働率**
（１）図１のシステム全体の稼働率は？

・知識として、システム全体の稼働率は下記となります。
・直列
R　×　R

・並列
１－（１－R)　×　（１－R)

・現状のシステム稼働率
Webサーバは並列、APサーバも並列ですね。RDSは一つだけがあるので、直列ですね。
(1-(1-w)^2)(1-(1-a)^2)r　が答えですね。

・新システムの稼働率
Webサーバは並列のまま、フロントAPは並列※１、バックAPも並列、KVSが並列になりますね。
※１　並列とは、いずれか通れるのこと

なので、新システムの稼働率は、
(1-(1-w)^2)(1-(1-f)^2)(1-(1-b)^2)(1-(1-k)^3)　ですね。

ただ、設問には、スマホアプリを用いた場合のシステムの稼働率ので、フロントを通りませんので、(1-(1-w)^2)(1-(1-b)^2)(1-(1-k)^3)　になりますね。

緊張な試験中、間違いしやすいでしょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591618/819001c0-00b6-0aae-fec3-c6151b51b3a2.png)

**３、本文中の下線①にあるフロントAPとバックAPの台数はそれぞれどのように変化するか。**
スマホアプリはフロントAPを通りませんので、フロントAPは少なくなれますね。
ただ、スマホアプリを利用するユーザが増えることで、バックAPはどうなりますか？増えるのは必要でしょうか。
システム全体へのリクエスト数は、変わらないとの条件があります。
そもそも、フロントAPもバックAPをアクセスするので、一部利用者がスマホアプリの利用に移行するだけで、バックAPの負荷は増えないですね。なので、変わらないが答えです。

**４、本文中の下線②はどのような処理か。４０字以内で述べよ。**
同様のデータ処理とは、将来的に、Webブラウザー機能が向上で、フロントAPで行っている、「Webブラウザの種類に応じたWebコンテンツの変換」はWebブラウザに任せるとのことですね。

生コンテンツを呼出端での変換と表示処理
→
バックAPから電子書籍データを取得しWebコンテンツに変換する処理

**５、本文中の下線③の問題を回避するためには、表２中の機器の機器に変更を加える必要がある。**
対象となる機器を表２から選び、加える変更について、３０字以内で述べよ。

利用者にポイントを定期的に付与するバッチ処理を実行すると、Webブラウザからのリクエストに対する応答待ちが極端に長くなってしまうのことですね。

新システムでも、軽減できていません。
回避策としては、バッチ実行は利用者がない又は少ない時間帯でやればいいではないか。
参考答えは、既にバックAPは２台あるので、バッチ専用として、機能を分けるとの策です。

ポイントを付与するバッチの実行は利用者が少ない時間帯で行う
→
バッチ処理とその他の処理が実行される機器を分ける

多分、私の考えと参考答えを結合したら一番よいかもしれませんね。
「利用者が少ない時間帯で、１台がバッチ処理専用機器とする」になりますね。

緊張な試験中、綿密に答えられないだろうね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591618/66e552d3-e8bc-982a-33dc-da57980dff66.png)



参照：

SSLアクセラレータ  【 SSL accelerator 】 
http://e-words.jp/w/SSL%E3%82%A2%E3%82%AF%E3%82%BB%E3%83%A9%E3%83%AC%E3%83%BC%E3%82%BF.html


システム全体の稼働率
https://qiita.com/lymansouka2017/items/4e1ad6954db51d573975
BitBoard を利用してリバーシの反転処理を実装する

リバーシを BitBoard で実装します。今回は反転処理を実装します。
（簡単のために 4x4 の例で説明しますが、実装は 8x8 です。W: 白石、B: 黒石、x: 石がない、をそれぞれ表します。）

```
xxxx
xWBx
xBWx
xxxx
```

この盤面を BitBoard では黒石の配置

```
0000
0010
0100
0000
```
と白石の配置

```
0000
0100
0010
0000
```
の二つの bit列で表現します。

黒番の着手 `move` :

```
0000
0000
0001
0000
```

に対して、反転する石の配置 `flipped` :

```
0000
0000
0010
0000
```
を求めると、白番の反転処理は `opponent_board ^= flipped` つまり白石の配置は

```
0000   0000   0000
0100 ^ 0000 = 0100
0010   0010   0000
0000   0000   0000
```

また黒石の配置は `self_board ^= flipped | move` または `self_board |= flippled | move` から得られます。

```
0000   0000   0000
0010 ^ 0000 = 0010
0100   0011   0111
0000   0000   0000
```

ここからは 反転する白石`flipped` を求めることに注力します。
反転する白石は必ず、着手`move` の上下左右斜め8方向のいずれかにあります。そのうち、まず左方向の探索から考えます。
左方向の反転は以下の二つのパターンのいずれかに該当します。

```
BWo
BWWo
```
（W: 白石、B: 黒石、o: 黒番の着手、をそれぞれ表します。）

着手`move` を左にシフトして、白番の配置と積をとります。結果をさらに左にシフトして、白番の配置と積をとることで `flipped` を得ます。（8x8 では合計6回シフトすると `flipped` を得ます。）ただし、演算の前に左方向に反転できる白石があることを確かめておく必要があります。これは[合法手を見つける方法](https://qiita.com/torajiro1220/items/e891355327a368a5f189)と同じです。

```python
class Board:
    BLACK, WHITE = True, False

    def __init__(self, black=0x000008100000, white=0x000010080000):
        self.board = {Board.BLACK: black, Board.WHITE: white}

    def flipped(self, player, move):
        """ returns flipped stones """
        flipped = 0b0
        player_board = self.board[player]
        opponent_board = self.board[not player]
        blank_board = ~(player_board | opponent_board)

        masked_opponent_board = opponent_board & 0x7e7e7e7e7e7e7e7e

        # 左方向に反転できる白石があることを確かめる
        temp = player_board << 1 & masked_opponent_board
        temp |= temp << 1 & masked_opponent_board
        temp |= temp << 1 & masked_opponent_board
        temp |= temp << 1 & masked_opponent_board
        temp |= temp << 1 & masked_opponent_board
        temp |= temp << 1 & masked_opponent_board
        legal_moves = temp << 1 & blank_board

        # move & legal_moves は move か 0b0 になる
        temp = (move & legal_moves) >> 1 & opponent_board
        temp |= temp >> 1 & opponent_board
        temp |= temp >> 1 & opponent_board
        temp |= temp >> 1 & opponent_board
        temp |= temp >> 1 & opponent_board
        temp |= temp >> 1 & opponent_board
        flipped |= temp

        return flipped
```
Visual Studio C++のプロジェクトフォルダの容量を抑える

# 自己紹介
画像解析系の研究をしている大学院生です。QtでGUIを作ったり、Visual Studioを使って解析コードを書いて過ごしています。
「誰でもわかる」を目指しつつ、自分の備忘録としてちょっとしたことを記載しています。

# 記事を書いたモチベーション
新型コロナウィルスの影響で在宅ワークをする機会が増えているわけですが、それにつれて家で使っているPCと出先で使うPCの情報を同期したいことも増えてきました。

僕はBox Driveの無料版を使用させていただいてPC間でファイル共有を行っており、使い勝手がよく大変満足しています。また、どのPCでも作成したプロジェクトを**<font color="Indigo">シームレスに</font>**編集できるように、**<font color="Indigo">Visual StudioのデフォルトディレクトリをBox Drive上に配置</font>**しています。

Box Driveを使用し始めて1か月ほど経ったある日のこと、いつものようにVisual Studioでコードを書いていたところ、「Box Driveの容量を使い果たしました」というメッセージが出てアップロードが拒否されてしまいました。

Box Driveの無料版は10 GBまで使用できるらしいのですが、プロジェクトは20個ほどだったので、「そんな使ってなくない？ぴえん。」って感じでびっくりでした。

Visual Studioのプロジェクト以外にもミーティング資料などを同期していたので、そっちが多すぎたかとも思ったのですが、少し気になってプロジェクトをまとめているフォルダの容量を確認してみると、18個のプロジェクトで4 GB以上も使用していることがわかりました。

| ![](https://i.imgur.com/6BUJIHZ.png) | ![](https://i.imgur.com/6lkwrNJ.png) |
| ---- | ---- |
そもそも、Visual Studioで書いているコードはフォルダ整理や、あちこちに散らばった解析データを一つのファイルにまとめる程度の簡単なもので、ライブラリもあまり使っていないので、1プロジェクトあたり200 MBは多くない？と疑問に思い、詳しく見てみると、**<font color="Indigo">プロジェクトフォルダが大きくなっている原因は、隠しフォルダ(.vs)の中にある*"Browse.VC.db"*と*"(cppファイル名).ipch"*でした(それぞれ容量は50 MB, 100 MB程度)</font>**。

そこで、これらのファイルをどうにかできないかと思い、調べてみると、これらのファイルはVisual Studioに搭載されているIntelliSense(自動補完システム)に関係するファイルのようでした(Stack Overflow: https://stackoverflow.com/questions/36407386/what-is-the-vc-db-file-in-visual-studio-projects より)。

また、これらのファイルを生成する場所を変更できるとのことなので、肥大化したプロジェクトファイルの容量を減らし、共有ドライブをより効率よく使えるのではないかと考えました。
少々導入が長くなってしまいましたが、本記事では**<font color="Indigo">IntelliSenseに関するファイルの出力場所を変更する方法</font>**を記載していきたいと思います。

# 手順
※私のVisual Studio環境は英語で設定しているので、日本語で設定している方とは少々異なる部分があることをご承知おきください<font color="Blue">（一応青色で日本語版の説明も加えてはいます）</font>。
また、Visual Studioのバージョンによっても多少異なる部分があるかもしれません(私は2019年版を使っています)。
###1. 適当なプロジェクトを開き、Visual StudioのTools → Options...を選択する
<font color="Blue">日本語版ではツール → オプション。</font>
![Imgur](https://i.imgur.com/BGBW98Y.png)
###2. Text Editor → C/C++ → Advancedを選択する
<font color="Blue">日本語版ではテキスト エディター → C/C++ → 詳細設定。</font>
###3. Browsing Database FallbackにあるAlways Use Fallback LocationをTrueにする
<font color="Blue">日本語版では「フォールバック位置」にある「常にフォールバック位置を使用」をTrueにしてください。</font>
Always Use Fallback LocationをTrueにするとIntelliSenseに関するファイルの出力場所を変更できるようになります。手順4で出力場所を指定します。
![Imgur](https://i.imgur.com/w6ljf8E.png)
###4. Browsing Database FallbackにあるFallback Locationに好きなフォルダのパスを入力する
<font color="Blue">日本語版では「フォールバック位置」にある同じ名前の「フォールバック位置」に好きなフォルダのパスを入力してください。</font>
僕はBox Driveではないローカルな場所を指定しました（パスは隠しています）。
![Imgur](https://i.imgur.com/x7V96ew.png)
###5. OKを押す
これでBrowse.VC.dbなどの容量が大きいファイルの生成場所が変更されます。ただし、当然すでに作られたファイルは消えないので、この後にすべてのプロジェクトの.vsフォルダを手動で消去しました。
その結果、Box Driveの容量を5分の1以下(4.36 GB→774 MB)に抑えることができました。

|![](https://i.imgur.com/6lkwrNJ.png)|![](https://i.imgur.com/8HqnRv9.png)|
|---|---|

ちなみに、.vsフォルダは削除した後に再度プロジェクトを開くとまた自動で作られます。が、中身のBrowse.VC.dbなどの重いファイルは設定したFallback Location<font color="Blue">（フォールバック位置）</font>に移動しているはずです。

また、これらの設定を終えた後にプロジェクトを開くと以下のようなメッセージが出現しますが、OKを押して問題ないと思います。毎回出現するのが嫌なので、Do not prompt me againにチェックをつけてOKをしたら出なくなりました(メッセージ中のパスは見えないようにしています)。
![Imgur](https://i.imgur.com/iBsvrtG.png)

これで、Visual Studioのプロジェクトを共有する際に、IntelliSenseの機能を維持した状態で共有ドライブの容量を抑えることができました。
jQueryでパララックスを自作する

jQueryでパララックスを自作する事が良くあるのだけど、基本的にはいつも同じ作業をしているが、毎回作るのが面倒なのでコピペが出来るように記事にする事にしました。

設計としては、
# 目標：クラス名を付けるだけでパララックスする。
class名：prlx

## １、スクロール位置とステージサイズから対象が画面内に表示されているかどうかを判別する。

```js:test.js
setInterval(function(){
		for(var i = 0 ; i < $(".prlx").length ; i++){
			if($(".prlx").eq(i).offset().top < $(window).scrollTop() + $(window).height()*0.9){
				$(".prlx").eq(i).addClass("-show")
				break;
			}
		}
	},100);
```

※画面の下から10%の位置に対象が来た場合に実行をする。
※スクロールイベントで実行もできるが、画面リサイズなども含めて考えてsetIntervalを利用する。
※表示されるアニメーションはクラスを付けてcssで管理する。

## ２、一度のイベントにつき、反応する対象を１つにする（横並びの対象に対しても時間差をつける）

```js:test.js
var level = 0;
setInterval(function(){
		for(var i = 0 ; i < $(".prlx").length ; i++){
			if($(".prlx").eq(i).offset().top < $(window).scrollTop() + $(window).height()*0.9 && level == i){
				$(".prlx").eq(i).addClass("-show")
				level = i+1;
				break;
			}
		}
	},200);
```

※ずれは0.2秒づつにしてる。

## ３、他とバッティングしないようにオブジェクト化する。

```js:test.js
var PRRX = {
	init:function(){
		var level = 0;
		setInterval(function(){
			for(var i = 0 ; i < $(".prlx").length ; i++){
				if($(".prlx").eq(i).offset().top < $(window).scrollTop() + $(window).height()*0.9 && level == i){
					$(".prlx").eq(i).addClass("-show")
					level = i+1;
					break;
				}
			}
		},200);
	}
}
```

使い方：

```js:test.js
$(function(){
	PRRX.init();
});
```

## ４、クラスを設定する。

```css:test.css
.prlx{
	transform:translate(0,100px);
	opacity:0;
	transition:all 0.6s ease-out,opacity 0.6s linear;
	&.-show{
		transform:translate(0,0);
		opacity:1;
	}
}
```

※0.6秒かけてフェードインしながら、100px上に上がってくる。アニメーション。

これで、クラスを変更すればお好みにパララックスが出来る。
いつも作ってたので、今後はコピペをするようにしています。

何かオススメの方法などあればご教授してくれると嬉しいです。
ubuntuでusbブータブルなディスクを作成する

毎回忘れるのでメモ

USBメモリはFATでフォーマットしておきます。

~~~~
sudo add-apt-repository ppa:gezakovacs/ppa
sudo apt-get update
sudo apt-get install unetbootin
sudo QT_X11_NO_MITSHM=1 /usr/bin/unetbootin
~~~~
【Python】データサイエンス100本ノック（構造化データ加工編） 028 解説

- データサイエンス100本ノックをやりきる会を作りました🎉
- こちらの[Slack招待URL](https://join.slack.com/t/data-science-100nocks/shared_invite/zt-gfncg9vm-8W8b3UrDg8R~TKaqUkQpgw)からご参加ください！！
- ぜひ一緒に励まし合いながら、データサイエンス100本ノックをやり切りたいと思っています！

##Youtube
[動画解説](https://youtu.be/wnMkN9XNaHg)もしています。

##問題
P-028: レシート明細データフレーム（df_receipt）に対し、店舗コード（store_cd）ごとに売上金額（amount）の中央値を計算し、降順でTOP5を表示せよ。

##解答
```:コード
df_receipt.groupby('store_cd').amount.median().reset_index().sort_values('amount', ascending=False).head(5)
```

##出力
|  | store_cd | amount |
|--:|:--|--:|
| 28 | S13052 | 190 |
| 30 | S14010 | 188 |
| 51 | S14050 | 185 |
| 44 | S14040 | 180 |
| 7 | S13003 | 180 |

##解説
・PandasのDataFrame/Seriesです。
・同じ値を持つデータをまとめて処理し、同じ値を持つデータの合計や平均などを確認したい時に使用します。
・**'groupby'は、同じ値や文字列を持つデータをまとめて、それぞれの同じ値や文字列に対して、共通の操作（合計や平均など）を行いたい時に使います。**
・**'.amount.median()'は、amount の中央値を表示させます。**
・**'.reset_index()'は、'groupby'によってバラバラになったインデックス番号を0始まりの連番に振り直す操作を行いたい時に使います。**
・**'.sort_values('amount', ascending=False)'で'amount'を降順に表示しています。**

※こちらのコードでも同様の結果を出力します  

```:コード
df_receipt.groupby('store_cd').agg({'amount':'median'}).reset_index().sort_values('amount', ascending=False).head(5)
```
Web Storage の使い方

こちらのページを参考にしました。
[HTML5 Web Storage の使い方](https://www.keicode.com/script/html5-webstorage.php)

```html:web_storage.html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta http-equiv="CONTENT-TYPE" content="text/html; charset=utf-8" />
<script src="http://code.jquery.com/jquery-3.5.1.min.js"></script>
<script src="web_storage.js"></script>
<title>Web Storage</title>
</head>
<body>
<h1>Web Storage</h1>

<h2>保存</h2>
<div>
<input type="text" id="text1">
<button type="button" id="saveButton">Save</button>
</div>

<h2>読込み</h2>
<div>
<button type="button" id="readButton">Read</button>
</div>

<p />
<div class="message">
</div>
<p />
Aug/15/2020<p />
</body>
</html>
```

```js:web_storage.js
// ---------------------------------------------------------------
//	test.js
//
//					Aug/15/2020
//
// ---------------------------------------------------------------
jQuery(function()
{
	jQuery('#saveButton').click(function(){

		if(window.localStorage){
			var ss = jQuery('#text1').val()
			localStorage.setItem("key1", ss)
			jQuery('#text1').val("")
		}

	})

	jQuery('#readButton').click(function(){

		if(window.localStorage){
			value = localStorage.getItem("key1")
			jQuery(".message").text(value)
//			alert( localStorage.getItem("key1") );
		}

	})
})

// ---------------------------------------------------------------
```

1) ペーにアクセス
![web_storage_aa.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/225c16b6-4da1-b716-ee9f-10991b028fb9.png)

2) 保存
![web_storage_bb.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/a174d77c-722d-bc41-85c8-5a4a8aec5034.png)

3) 読み込み
![web_storage_cc.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/4db339ff-a9ec-d12d-5761-87d521d7eade.png)
[UE4] ソースコードをビルドした際にエラー D8049 が発生した際の対処法

# はじめに

検証環境は UE4.25.3 です。

# 謎のエラー「D8049」
Github から落としてきた UE4 のソースコードを 4.25.3 にアップデートした後、既存のソースコードに関数を追加してビルドしてみたところ、以下のようなエラーが発生しました。

> cl : コマンドライン エラー D8049 : 'C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\bin\HostX64\x64\c1xx.dl' が実行できません : デバッグ レコードに対してコマンド ラインが長すぎます

どうやら何かのパス名などが長すぎることが原因のようです。関数を追加する前は発生しなかったのですが……。

# .vs フォルダを消してみたら…？
いろいろ調べたり、試したりしてみたところ、以下の手順でビルドできるようになりました。

1. UE4.sln と同階層にある .vs フォルダを削除。
2. GenerateProjectFiles.bat でプロジェクトを再生成する。
3. UE4 プロジェクトをビルドし直す。

他にも原因があるかもしれませんが、もし同様の問題が発生した時は試してみても良いかもしれません。
【Laravel】複数条件の絞り込み検索機能

## やりたいこと
Laravelでusersテーブルに対して複数の条件で絞り込み検索機能を実装します。今回は、「名前」「性別」を検索できるようにします。

## 前提

- PHP7.2
- Laravel6.1
- MySQL5.7

■usesテーブル

| カラム | 型 | コメント |
| :--- | :--- | :--- |
| sei | VARCHAR | 性 |
| mei | VARCHAR | 名 |
| family_name | VARCHAR | 性（カナ） |
| last_name | VARCHAR | 名（カナ） |
| sex | INT | 性別（1:男, 2:女） |

## ビュー

![スクリーンショット 2020-08-15 14.27.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264073/4eeb3d08-bec9-ca3f-330c-5522b07c095a.png)


```user/index.blade.php
<?php
 $sex = ['男' => 1, '女' => 2];
?>

<form>
  <input name="keyword" type="text" placeholder="キーワードを入力" value="{{ $params['keyword'] ?? null }}">
  <select class="form-control" name="gender">
    <option selected="selected" value="">選択してください</option>
    @foreach($sex as $key => $value)
      <option value="{{ $value }}" {{ isset($params['sex']) && $params['sex'] == $value ? 'selected': null }}>
        {{ $key }}
      </option>
    @endforeach
  <button type="submit">検索する</button>
</form>
```

## モデル

今回はLaravelの[クエリスコープ](https://readouble.com/laravel/6.x/ja/eloquent.html)を活用します。

```User.php
/**
 * 絞り込み・キーワード検索
 * @param \Illuminate\Database\Eloquent\Builder
 * @param array
 * @return \Illuminate\Database\Eloquent\Builder
 */
public function scopeSerach(Builder $query, array $params): Builder
{
    // 性別絞り込み
    if (!empty($params['gender'])) $query->where('gender', $params['gender']);

    // キーワード検索
    if (!empty($params['keyword'])) {
        $query->where(function ($query) use ($params) {
            $query->where('sei', 'like', '%' . $params['keyword'] . '%')
                ->orWhere('mei', 'like', '%' . $params['keyword'] . '%')
                ->orWhere('family_name', 'like', '%' . $params['keyword'] . '%')
                ->orWhere('last_name', 'like', '%' . $params['keyword'] . '%');
        });
    }

    return $query;
}

```

## コントローラ

```UserController.php
namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\User;

public function index(Request $request)
{
    $params = $request->query();

    $users = User::serach($params)->get();

    return view('admin.user.index')->with([
        'users' => $users,
        'params' => $params,
    ]);
}

```

## 参考
- https://github.com/yuuta1988/shussekikun
- https://readouble.com/laravel/6.x/ja/eloquent.html
- https://qiita.com/namaozi/items/11b65ccb6b7ecaefc23e
Ruby: クッキーの使い方

こちらと同じことを、PHP で行いました。
[jquery-cookie の使い方](https://qiita.com/ekzemplaro/items/95706b030581cd7a63c5)
[Perl: クッキーの使い方](https://qiita.com/ekzemplaro/items/cbe00d47275db0f49ba0)
[PHP: クッキーの使い方](https://qiita.com/ekzemplaro/items/71843c6685025d215d49)
[Python3: クッキーの使い方](https://qiita.com/ekzemplaro/items/f65f447e16f94fb474a1)

クッキーを送る

```rb:cookie_put.rb
#! /usr/bin/ruby
#
#	cookie_put.rb
#
#
puts "Set-Cookie: message='Good Morning';\n"
puts "Set-Cookie: aa='おはようございます。';\n"
puts "Set-Cookie: bb='今日は晴れています。';\n"
puts "Set-Cookie: cc='こんにちは';\n"
puts 'Content-Type: text/html',"\n"
puts "\n"

puts "<!DOCTYPE html>"
puts "<html lang=\"ja\">"
puts "<head>"
puts "<title>cookie put</title>"
puts "</head>"
puts "<body>"
puts "cookie_put.rb<p />"
puts "Aug/15/2020<p/>"
puts "</body>"
puts "</html>"
```

クッキーを確認

```rb:cookie_get.rb
#! /usr/bin/ruby
#
#	cookie_get.rb
#
cookie = Hash.new
ENV['HTTP_COOKIE'].split(/;\s/).each do |bo|
  mo = bo.split(/=/)
  cookie[mo[0]] = mo[1]
end

puts "Content-type: text/html\n\n"
puts "<!DOCTYPE html>"
puts "<html lang=\"ja\">"
puts "<head>"
puts "<meta http-equiv=\"CONTENT-TYPE\" content=\"text/html; charset=utf-8\" />"
puts "<title>Cookie Test</title></head>"
puts "<body>"

puts "Cookie Test<p />"
# puts cookie
cookie.each {|key, value|
	puts key,":",value,"<p />"
	}
puts "</body></html>"
```
electron+Vue.jsで内容をテキストファイルに書き出す方法

##やりたいこと
やりたいことは２点
・メモ帳アプリをelectron+Vue.jsで作成する。
・入力された内容をテキストで吐き出せるようにする。

##テキスト出力方法
ざっくり言うと２つの機能を使います。
・保存ダイアログ表示 → electron
・ファイル保存 → Node.js

以下サンプル。

```vue:top.vue
<template>
    <div>
　　　　 <!-- 書き出しボタン表示。 -->
        <headerVue 
            @out="out"
        />
　　　　 <!-- 入力画面表示。ここに表示されている内容を出力。 -->
        <div class="mainArea">
            <sideBarVue :list="memoList" />
            <textarea
                placeholder="本文を入力してください。"
                rows="20"
                v-model="message"
                class="textArea"
            />
        </div>
    </div>
</template>

<script>
import sideBarVue from "../components/sideBar.vue";
import headerVue from "../components/header.vue";
import { remote } from "electron";
import * as fs from "fs";

export default {
  methods: {
    //書きだしボタン押下
    out: function() {
      //保存ダイアログを表示
      //第一引数：表示するダイアログ。基本的には固定で良い。
      //第二引数：保存形式と画面表示する名称を指定。
      //第三引数：取得したファイル名を指定して、保存やキャンセルボタンを押下した際の処理を記載。
      remote.dialog.showSaveDialog(
        remote.getCurrentWindow(),
        {
          filters: [{ name: "Text File", extensions: ["txt"]},
                    { name: "All Files", extensions: ["*"]}],
        },
        (filename) => {
          if (filename) {
            //ファイルに保存
            //第一引数：保存する際のファイル名。
            //第二引数：保存する内容
            //第三引数：エラー内容を取得して、エラーが発生した際の処理を記載。
            fs.writeFile(filename, this.message, (err) => {
              if (err) {
                alert(err);
              }
            });
          }
        }
      );
    }

```
Ping-tでLPIC1合格しました

以前個人ブログに書いた記事の移植になります(2019/4/21)

LPICはLinuxの資格で、似たようなものでLinuCがあり宗派があるようです。
会社よりWeb系移るならまずはコレとのことで、取り掛かりました。
LPIC1を取るには101,102の両方に合格する必要があります。

## 前提知識
* 高専の頃にLinuxで自宅サーバ(Web,ファイル,録画)構築経験あり(オールコピペ)
* 基本情報技術者
* 高専の情報科卒業　C言語の授業はLinux、Linuxサーバ構築の授業もあったような気がする
* DBの業務経験有り
* NW業務経験有り
* Linuxの業務経験無し

## 学習期間
* 小豆本読み始め2019/2月〜、本格的には3月〜
* 101は4/4,102は4/15に受かりました。

## 学習方法
* 小豆本　後半使わなかった
* Ping-t(eラーニング的なやつ
    - 効率よくやるなら、小分類毎に銅→銀、中分類で銀→金もしくは模擬試験、コマ問をちょこちょこやるといった感じです。
* (2020/8 追記 LPIC系はまだUdemyよりPing-tのほうが良さそうです) 
本来VMでLinux触るべきでしたが、触らず。Macありましたが、あまりコマンド叩きませんでした。

### 取得ポリシー
短期取得最優先。出費は惜しまない。ガンガンいこうぜ

## 反省点
効率良い勉強方法見つけるまでがとても非効率だった…小豆本を読むだけだったり、闇雲にPing-tの問題解いたり。結局分野絞って数解いて暗記していくのが資格試験においては最適なんだなと。

## 費用
* 受験料 およそ1.5万*3(一度落ちた)
* Ping-t有料会員 6ヶ月分で5千円くらいだったような

## 資格取ってみて
未経験ですが、やらなかったよりかはLinuxの業務に入りやすくなったかなと思います。
SESの案件決めに置いても一押できるし、受かったという自信がどんと来いという気持ちにさせてくれます。
また、気持ち的に追い込みながら勉強して合格を手にするのは一つの成功体験だなと。去年(2018)の応用情報はだらだらと中途半端な勉強で落ちてますし。。。

資格は既にスキルがあってやりたい仕事に従事できていれば不要ですが、私みたいにスキルチェンジ狙うなら取ったほうがスッと入れると思います。

→2019/6よりLPIC取得後無事にLinux触る業務に参画しました
twitterのapiで401

#プロローグ
twitterのAPIを使ってみようかな~

#ツイートするとエラー
APIを使ってツイートしようとすると「401」!!
ググってみると、401が出る場合は原因が何パターンかあるらしい。
(https://qiita.com/hirokishirai/items/5a43977a38ecd922bfb9)

>アプリの設定画面のCallbackURLに何も入力されていない
API KEY（CONSUMER KEY）とAPI SECRET（CONSUMER SECRET）の設定が間違っている
コンピュータの時刻が狂っている（記事下部のコメントも参照してください）
アプリがTwitterからSuspendされてる

しかし、どれも問題なし。

ん...

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/538462/2df7b56b-3e11-ec0b-a2b0-2322daec6a81.png)



#​​​​​​​​「り、りーどおんりーになっとるやないかーーい！！」（完）

PS.
App permissionを変更した後にAccess Token & SecretのRegenerateが必要でした。
RailsAdminで表示順を気軽に変えられるようにしたい

## はじめに

CSVインポート機能の追加くらいで、ほぼ素のままのrails_adminを今まで使ってきていました。
それを最近しみじみ見て、大事そうでもない情報が上の方にあったり、使いそうもないリレーションがところどころに挟まっていたり…使いにくく感じました。
順番を変えるだけでも運用でミスが減るだろうと思い、少しやってみました。

### ソース
- https://github.com/ken1flan/rails_admin_sample
  - 変更のプルリクエスト https://github.com/ken1flan/rails_admin_sample/pull/1

## やっていないこと

項目の非表示はしていません。
rails_adminをどのように運用で使っているのかわからないので、項目の非表示などをして混乱させてもよくないと思ったためでした。
また、表示するものを減らしたい、というような要求が出てきたときには、rails_adminで創意工夫を凝らすより、素直に編集画面を作るようにしようと思っています。

## こんなふうになります

↓のように、`body`、`title`、`user_id`の順で定義された`Article`モデルがあるとします。

```ruby:db/schema.rb
ActiveRecord::Schema.define(version: 2020_08_15_021803) do

  create_table "articles", force: :cascade do |t|
    t.text "body"
    t.string "title"
    t.integer "user_id", null: false
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
    t.index ["user_id"], name: "index_articles_on_user_id"
  end

  # :
  # : （省略）
```

これをrails_adminで見ると↓のように`body`、`title`、`user`の順で表示されます。

![localhost_3000_admin_article_1(PC).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14380/54d95efe-a1b0-ded6-b211-4b7b40b3a8f1.png)

↓のような設定ファイルによって…

```yaml:config/initializers/rails_admin.yml
preffered_fields:
  article:
    - user
    - title
```

`user`、`title`、`body`の順で表示できるようにします。

![localhost_3000_admin_article_1(PC) (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14380/9dfeb653-fef9-bdef-8bce-afa7fdbea886.png)


## やったこと

上の方に置きたいフィールドを`おきにいり`ということにして、同一ディレクトリ内に置いたYAMLファイルから読みます。おきにいりフィールドを`#field`を使って設定し、残りは`#include_all_fields`でまとめて設定しています。

```ruby:config/initializers/rails_admin.rb
RailsAdmin.config do |config|

  # :
  # : （省略）
  # :

  # モデルの表示順制御
  settings = YAML.load_file(Rails.root.join('config/initializers/rails_admin.yml'))
  settings['preffered_fields'].each do |model_name, preffered_fields|
    config.model model_name do
      preffered_fields.each do |field_name|
        field field_name.to_sym
      end
      include_all_fields
    end
  end

  # :
  # : （省略）
  # :

end
```

## おわりに

rails_adminをマジマジとみて、かなり使いやすいのと、置き換えでrails_admin相当の便利な入力・編集フォームを作ろうとすると、結構大変だぞ…と思いました。
直近の不便を解消する程度のことはしてもよいと思いましたが、あれこれがんばって工夫する前に、工夫をしたくなったところから徐々に自前で作ったフォームに置き換えていきたいと思っています…。
SwitchBotの温湿度計の値をNode.js（BLE）を使って取得する

## 環境構築
balenaを使ってしまっていますが、debian環境なので `install_packages` はそのまま `apt install` 等で置き換えてください。

またNode.jsでBLEを扱うためのnobleというライブラリを今回は使いますが、本家よりも `@abandonware/noble` の方がメンテされているので、今回はこちらを使います。

```Dockerfile:Dockerfile
FROM balenalib/%%BALENA_MACHINE_NAME%%-node:12-buster-build as build
RUN install_packages bluetooth bluez libbluetooth-dev libudev-dev
RUN npm install @abandonware/noble rxjs

FROM balenalib/%%BALENA_MACHINE_NAME%%-node:12-buster-run
WORKDIR /work
COPY --from=build ./node_modules ./node_modules
COPY app.js .
CMD ["node", "app.js"]
```

## ソースコード

SwitchBotの温湿度計のMACアドレスを予め取得しておいてください。わからない場合は、まずfilterせずにScanしてみて、それっぽいのをしぼります（filterの記述はソースコードのコメントを参照）。

まず冒頭のRxを準備するソースコード。

```js:app.js
const noble = require('@abandonware/noble');
const SWITCHBOT_MAC_ADDR = process.env.SWITCHBOT_MAC_ADDR || 'aa:bb:cc:dd:ee:ff'; // コロンあり小文字で

const {
  fromEvent,
  forkJoin,
  interval,
  empty,
} = require('rxjs');

const {
  filter,
  map,
  mergeMap,
  take,
} = require('rxjs/operators');


// BLEのデバイスがスタンバイ状態になるのを待つストリーム
const blePowerdOn = fromEvent(
  noble,
  'stateChange'
).pipe(
  filter((state) => {
    console.log(state);
    return state === 'poweredOn';
  }),
  map(() => console.log('[ble]poweredOn')),
  take(1)
);

// ペリフェラルを発見したらペリフェラルを流すストリーム
// MACアドレスが不明な場合はfilterの記述を削除
// bleDevices = fromEvent(noble, 'discover')
bleDevices = fromEvent(noble, 'discover').pipe(
  filter((peripheral) => {
    return peripheral.address === SWITCHBOT_MAC_ADDR;
  })
);

```

アドバタイズのデータから温度と湿度とバッテリー残量を取得する処理。
参考: https://qiita.com/c60evaporator/items/7c3156a6bbb7c6c59052#%E3%82%BB%E3%83%B3%E3%82%B5%E5%80%A4%E5%8F%96%E5%BE%97%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%97%E3%83%88%E3%81%AE%E4%BD%9C%E6%88%90

```js:app.js
const decodeSensorData = (data) => {
  const batt = data[2] & 0b01111111;
  const isTemperatureAboveFreezing = data[4] & 0b10000000;
  let temp = (data[3] & 0b00001111) / 10 + (data[4] & 0b01111111);
  if (isTemperatureAboveFreezing < 0) temp = -temp;
  const humid = data[5] & 0b01111111;
  return {
    'SensorType': 'SwitchBot',
    'Temperature': temp,
    'Humidity': humid,
    'BatteryVoltage': batt
  };
};

```

最後に実際に動かす部分。

```js:app.js
forkJoin({
  ble: blePowerdOn
}).pipe(
  mergeMap(() => {
    console.log('[ble]scanning...');
    noble.startScanning([]);

    // 10秒ごとにスキャンする（この中でやる必要はなさそう）
    interval(10 * 1000).subscribe(() => {
      noble.stopScanning();
      noble.startScanning([]);
    });

    return bleDevices;
  }),
).subscribe((peripheral) => {
  // 取得したセンサー情報を出力する
  console.log(decodeSensorData(peripheral.advertisement.serviceData[0].data));
});

```

## 出力

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4194/dc93a29b-3734-179b-4f39-7108264831ee.png)

このように値を出力できました。あとは、好きなクラウドにアップロードしたり、画面に出力したりして楽しんでください。
metaタグの使い方

#プログラミングの勉強日記
2020年8月15日　Progate Lv.226

#metaタグとは
　metaタグはmeta要素ともいう。Webページの情報を検索エンジンやブラウザに伝えるために用いる。metaタグはHTMLのheadの部分に記述し、ブラウザに対して文字コードを指定の役割も果たしている。

#charset属性
　charset属性を使うことで、ブラウザでどの文字コードを設定できる。charsetはcontent属性を必要としないので、そのまま文字コードを設定すればいい。
　一般的にはutf-8を使用するが、システムによって設定する文字コードは異なる。

```html
<head>
  <meta charset="urf-8">
</head>
```

#ettp-equive属性
　ettp-equive属性はブラウザに対して指示ができる。このサイトはHTMLで作られてることをブラウザに宣言することやブラウザの更新、一定時間経過したら遷移するといったことを指示できる。
　ettp-equive属性はcontent属性と合わせて使う。

```html
<head>
  <!--content-typeでファイルの種類や文字円コードを指示する-->
  <meta ettp-equiv=”content-type” content=”text/html; charset=’utf-8’”>

  <!--デフォルトで読み込むCSSファイルの指定-->
  <meta http-equiv=”default-style” content=”(CSSのURL)”>

  <!--ページの更新(content属性に更新する秒数を指定 URLを指定でそのページに遷移させる)-->
  <meta http-equiv=”refresh” content=”30; url=’ページのURL’”>
</head>
```

#name属性
　サイトの説明を記述できる。

##description
　このdescription属性の値に書いた説明文はGoogleの検索結果一覧に表示されることが多い。以下の画像のように検索結果のタイトルの下に表示される。
![0815.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/642821/f80b4780-84c1-6f3e-1f40-59550769ab06.png)

```html
<head>
  <meta name=”description” content=”このサイトの説明”>
</head>
```

##keywords
　Webページの内容を表すキーワードを半角カンマ`,`区切りで複数指定できる。ユーザには見れないので、システムのためのタグである。titleタグや本文に書かれたキーワードで特に重要だと思われるキーワードを記述する。

```html
<head>
  <meta name="keywords" content="キーワード1,キーワード2">
</head>
```

##robots
 検索エンジンのWeb上の文章や画像を周期的に取得して、自動的にデータベース化するプログラムであるクローラの動作を制御することができる。
　content属性の値を`”noindex,nofollow”`にすることで、検索エンジンがこのmetaタグを設定したページを巡回するのを防げる。

```html
<head>
  <meta name=”robots” content=”noindex,nofollow”>
</head>
```

#スマホの画面表示を制御をする
　スマホの画面表示を制御するmetaタグも存在する。name属性にviewportを設定して、content属性にそれぞれの設定したい値を記述する。viewportでは読み込まれる長さや高さ、拡大縮小可能かどうかを設定できる。

〇initial-scale
　画面の拡大縮小率を設定。0から10の間で指定する。(初期値は0.25)
〇width, height
　表示する幅、高さを幅は200pxから10000pxの間で、高さは223~10000pxの間で指定する。
〇user-scalable
　ユーザに画面の拡大縮小を許すかをyesかnoで指定する。
〇minimum-scale, maximum-scale
　拡大縮小を許可した場合に最小値と最大値を指定できる。拡大率を指定し、値は0から10の間で指定する。（初期値は最小値で0.25、最大値で1.6）

```html
<head>
  <meta name=”viewport” content=”initial-scale=1.0”>
</head>
```

#参考文献
　[【初心者向け】metaタグとは？](https://www.genius-web.co.jp/blog/website-operation/what-is-the-meta-tag-for-beginners.html#:~:text=meta%E3%82%BF%E3%82%B0%E3%81%AE%E6%84%8F%E5%91%B3,%E4%BC%9D%E3%81%88%E3%82%8B%E3%82%BF%E3%82%B0%E3%81%AE%E3%81%93%E3%81%A8%E3%81%A7%E3%81%99%E3%80%82&text=%E3%81%93%E3%81%A1%E3%82%89%E3%81%AFHTML%E3%81%AEhead,%E3%81%AB%E6%9B%B8%E3%81%8B%E3%82%8C%E3%81%A6%E3%81%84%E3%81%BE%E3%81%99%E3%80%82)
　[【HTML初心者入門】metaタグってどんな意味があるの？使い方も解説！](https://web-camp.io/magazine/archives/12455)
Google Books APIの使い方~その３~

[前回](https://qiita.com/stella0270/items/7a19dea8a4f47d97570b)からの続きです。

今回は「Googleブックスで使用されるID」についてです。

本記事はGoogle Books APIの[開発者向けサイト](https://developers.google.com/books)を翻訳して簡潔にまとめたものです。

# Google Books IDs
特定のAPIメソッド呼び出しではIDフィールドを指定します。 
IDには3つのタイプがあります。

***Volume IDs***
ボリュームを識別するための一意の文字列

APIを使用してVolumeリソースを返すリクエストを行うことで、Volume IDを取得できます。
Volume IDはidフィールドで確認できます。

***Bookshelf IDs***
ユーザーのライブラリの本棚を識別するための数値 

あらかじめ用意されている本棚には以下の数値が割り当てられています。

- Favorites: 0
- Purchased: 1
- To Read: 2
- Reading Now: 3
- Have Read: 4
- Reviewed: 5
- Recently Viewed: 6
- My eBooks: 7
- Books For You: 8

Bookshelf IDはユーザーごとに一意です。
APIを使用してBookshelfリソースを返すリクエストを行うことで、Bookshelf IDを取得できます。
Bookshelf IDはidフィールドで確認できます。

***User IDs***
各ユーザーに割り当てられた一意の数値

APIおよびGoogleブックスを介して、他のユーザーのUser IDを取得することはできません。

#GoogleブックスのID
APIで使用するIDは、Googleブックスサイトで使用されるIDと同じです。

***Volume ID***
Googleブックスでボリュームを表示すると以下のようなURLが表示されます。
>https://books.google.com/ebooks?id=buc0AAAAMAAJ&dq=holmes&as_brr=4&source=webstore_bookcard

idパラメータに入っているのがVolume IDです。

***Bookshelf ID***
Googleブックスで特定の本棚を表示すると以下のようなURLが表示されます。
>https://books.google.com/books?hl=en&as_coll=0&num=10&uid=11122233344455566778&source=gbs_slider_cls_metadata_0_mylibrary

as_collパラメータに入っているのがBookshelf IDです。

***User ID***
Googleブックスでライブラリを表示すると以下のようなURLが表示されます。
>https://books.google.com/books?uid=11122233344455566778&source=gbs_lp_bookshelf_list

uidパラメータに入っているのがUser Idです。

#最後に
以上、「Googleブックスで使用されるID」でした。

次回は「[リソースの操作とクエリパラメータ](https://qiita.com/stella0270/items/8fdd2efcdd9db96a5c4d)」です。
railsにおけるマイグレーションについて理解する


<h2>はじめに</h2>
Ruby on Railsを勉強していく中で、データ操作に関する色々な言葉や概念がわからなくなってしまったので、覚書として整理します。

<h2>マイグレーションへの疑問</h2>
自分がRailsを勉強していく中で、感じた疑問は以下の通りです。

<b>
その１　そもそもマイグレーション、モデル、マイグレーションファイルってなに？
その２　マイグレーションはどのタイミングで行うの？
その３　マイグレーションファイルは何ごとに作るの？</b>

それぞれについて整理しながら考えていきます。

<h2>その１　そもそもマイグレーション、モデル、マイグレーションファイルってなに？</h2>
Railsでデータを操作する場合に、出てくるのが「マイグレーション」「モデル」「マイグレーションファイル」という用語。用語の意味への理解ができていない状態で勉強をすすめていくと、かならずどこかで「あれ、これどういう意味？」というのにぶち当たると思います。（私もそうでした）
なので、一度改めて用語への理解を深めることにしました。

一言で表すとこんな感じです。

<b>● モデル
　データを操作するクラス。各テーブルごとに定義する</b>
<b>● マイグレーション
　テーブルの設計書を書き換えること</b>
<b>● マイグレーションファイル
　設計書を書き換え方を記載したもの</b>

すこしだけ詳しく見ていきます。

<h3>● モデル</h3>
RailsはMVCというデザインパターンを採用しています。イメージは画像のような形です。
![rails_モデル理解.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/176783/431b7bd3-67fb-8d51-741e-98cc58cab6ab.png)

各コンポーネントがそれぞれの役割を担っている中で、モデル(Model）の役割はデータとビジネスロジックです。特にデータベース操作の際に用いられます。操作のためのロジックをもっているのが、ここです。railsでは、クラスという形でモデルが定義されています。
モデルは、テーブルごとに作成され各モデルを通じてテーブルの作成・削除などの操作を行います。（紫色の吹き出し内のようなイメージ）

<h3>● マイグレーション</h3>
マイグレーションという言葉は、英語で「移行」という意味。
そして、Railsにおいての「マイグレーション」とは、「テーブルのスキーマの変更すること」を意味します。
ちなみに、スキーマは「テーブルの大枠を決める設計書のこと」なので、もっとざっくり言うと、マイグレーションは、<b>「テーブルの設計書を変更すること」</b>ということになります。

<h3>● マイグレーションファイル</h3>
Railsでは、マイグレーションをする際に「マイグレーションファイル」というものを用います。
ファイル内で、スキーマをどのように変更するかを定義し、このファイルを元に変更を行います。



<h2>その２　マイグレーションはどのタイミングで行うの？</h2>
その１で整理した用語の意味から、マイグレーションを行うタイミングというのは、「テーブルの設計書を変更する際」ということがわかります。
具体的には、テーブルの作成や、カラムの追加などです。
レコードの追加・編集・削除は「設計書自体の書き換え」にはならないということを念頭に置いておいてください。ですので、このような操作はマイグレーションにあたりません。

<h2>その３　マイグレーションファイルは何ごとに作るの？</h2>
単刀直入にいえば、「マイグレーションを行うタイミング＝テーブルの設計書を変更するタイミング」に作成します。


<h2>さいごに</h2>
概念のみ説明してきましたが、実際にはRailsでの操作を含め実際に動かしてみないことには感覚が掴みづらいかもしれません。私自身も理解ができているか微妙なところです・・・引き続き勉強していきたいと思います。
【Flutter】GridViewを使って簡単に要素を横に羅列させよう【gridview】

#この記事を読んで習得できること
FlutterでGridViewを使って、要素をこんな感じに横に並べることが出来るようになる

![Simulator Screen Shot - iPhone SE (2nd generation) - 2020-08-15 at 14.14.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/389553/e8c23166-f67d-2c44-15df-772188abf8ad.png)



#結論
こんな感じで書く


```main.dart

...略

            child: GridView.count(
              padding: EdgeInsets.all(10), // 割と重要！ここでGridViewの位置を調整する
              crossAxisCount: 4, // 一列に要素をいくつまで置けるかを指定
              children: List.generate(
                4, // 要素をいくつ並べるか
                (index) {
                  return Container( 
                    margin: EdgeInsets.all(10), // 要素間の幅を作る
                    child: RaisedButton( // childは今回はRaisedButtonを使用
                      onPressed: () {
                        print("tap");
                      },
                      color: Colors.grey,
                      child: Text(index.toString(), style: TextStyle(fontSize: 16)),
                    ),
                  );
                },
              ),
            ),
```

####ポイント
・`GridView.count`の直下で`padding`を使用する
　　→デフォルト値が大きく設定されているので、ほとんどのケースで設定し直さないといけないと思う

・`crossAxisCount`で一列あたりの要素数を決定する
　　→固定値でいいと思う

・`List.generate`内で全要素数を指定する
　　→ここでは固定値を入れたが、実際は配列の要素数（こんな感じ→`array.length`）を入れるようにするはず

#要素間のスペースはどう開ける？

今回は、`margin: EdgeInsets.all(10)`で開けたのだが、
公式ではGridView配下で`crossAxisSpacing: 10`みたいな方法があったので、
多分こっちの方がいいと思う。

#公式を見たい方はこちら
https://flutter.ctrnost.com/basic/layout/gridview/

要素数が無限な場合のケースはこちらから。
要素間のスペースの開け方もいろいろあるようで、詳しくはこちらから！

#ソース
https://github.com/taichi6930/flutterstudyapp/tree/develop
Twitterに投稿されたツイートをMattermostへ投稿

# 背景

技術やサービスのリリース情報を追う際にTwitterをよく利用しています。
また、Webサービスなどに障害があった際も公式アナウンスよりも早くTLがざわめき出す為、
早い段階で心構えができたり、確認作業に入る事ができます。

Twitterで気になる情報を弊社で利用しているMattermostに手作業でコピペを行っていましたが、
たまたま見つけた+手作業という非効率さが気になり自動化できないかと考えました。(~~実際は資格取得に向けた勉強からの現実逃避~~)

# ふんわりした構成(未採用)
AWSを使った業務を行っている為、以下の構成を考えました。

Amazon EventBridge(Cron) -> Lambda(Twitter API実行) -> webhooks -> Mattermost


定期的にLambdaで検索かけるのもリアルタイム性がなく、コードを書かなくては行けないのでもっと手軽な方法がないかを調べることにしました。

# 結果

[IFTTT](https://ifttt.com/)なるサービスを見つけました。
Webサービスの連携をしてくれるらしく、特定のキーワードに該当したらwebhooksに転送してくれる機能がありました。
もうこのサービスだけでやりたいことができます。

IFTTT -> webhooks -> Mattermost
↓↑
Twitter


# 設定

1. Twitterアカウント作成
    - Twitterの検索を自身のアカウント経由で行う為、Twitterのアカウントが必要になります。
2. Mattermostの内向きwebhooksを作成
   1. 投稿する予定のチャンネル作成
      1. 公開チャンネル or 非公開チャンネル右にある＋を押す
      2. 名前(任意)を入力し、チャンネルを作成を選択
   2. 統合機能　-> 内向きウェブフック -> 内向きウェブフックを追加する
   3. 追加
      1. タイトル(任意)
      2. チャンネル(上記で作成したものを選択)
      3. 保存を選択
      4. 発行されたURLを控える
3. IFTTTのアカウント作成
4. IFTTTの設定
   1. TOPページのCreateを選択
   2. IF This Then ThatのThisを選択
   3. Twitterを検索し選択
   4. if new tweet from searchを選択
   5. Search forの項目に[Twitterの検索ルール](https://help.twitter.com/ja/using-twitter/twitter-advanced-search)にならって検索ワードを入力
        - 例1: ```"from:アカウントID リリース"```
        - 例2: ```"**** 障害"```
   6. IF This Then ThatのThatを選択
   7. webhooksを検索し、選択
   8. Make a web requestを選択
   9. Complete action fields
      - URL
         - Mattermostの内向きWebhooksのURL
      - Method
         - POST
      - Content Type
         - application/json
      - Body (optional)
         - 以下の形式で入力します。

            ```json
            {"text": "投稿したい内容"}
            ```  
        - Add ingredientを押すと変数がでてくるので、お好みで選んでください。
          - 例: 
          
            ```json
            {"text": "{{Text}}"}
            ```
   10. Create action -> Finishを選択し完了です。
   11. 検索が実行される間隔はまだつかめてませんが、テストのタイミングだと2分は連携に時間がかかりました。
   
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316662/8cd824ec-d047-4812-5b98-f7a1599fe98c.png)


# 感想
思い立ってから完成するまで約1時間でした。
Twitterのツイートを他のWebサービスに投稿というケースが沢山あり大変参考になりました。
Mattermostの例がほぼない状況でしたが、公式サイトを確認し対応できています。
https://docs.Mattermost.com/developer/webhooks-incoming.html

どなたかの参考になれば幸いです。
Firebaseでサイトを公開する

前提:Fire baseでプロジェクト作成済み

###firebasetoolsをインストール
```powershell.
  npm install -g firebase-tools
```
------------------------------------------------------------------------

###firebaseにログイン
```powershell.
  firebase login
```
------------------------------------------------------------------------
###プロジェクトリストを表示

project ID をコピーしておく
 
```powershell.公開するフォルダ
  firebase project:list
```
------------------------------------------------------------------------
###フォルダを初期化する

コピーしたproject IDでフォルダを初期化する
途中で色々聞かれるけどデフォルトでOK
（デフォルトではpublicフォルダが公開される）


```powershell.公開するフォルダ
  firebase init --project=myportfolioproject-11e3a
```

------------------------------------------------------------------------
###ファイルを公開する
```powershell.公開するフォルダ
  firebase deploy

=== Deploying to 'myportfolioproject-11e3a'...

i  deploying hosting
i  hosting[myportfolioproject-11e3a]: beginning deploy...
i  hosting[myportfolioproject-11e3a]: found 6 files in public
+  hosting[myportfolioproject-11e3a]: file upload complete
i  hosting[myportfolioproject-11e3a]: finalizing version...
+  hosting[myportfolioproject-11e3a]: version finalized
i  hosting[myportfolioproject-11e3a]: releasing new version...
+  hosting[myportfolioproject-11e3a]: release complete

+  Deploy complete!

Project Console: https://console.firebase.google.com/project/myportfolioproject-11e3a/overview
Hosting URL: https://myportfolioproject-11e3a.web.app

```

ホスティングurlが発行される`Hosting URL: https://myportfolioproject-11e3a.web.app`

------------------------------------------------------------------------
**終了**