OmniAICreator/Qiita-1.07M huggingface dataset:
CI/CDツールを調査してみました

<a id="org5614777"></a>

# 初めに

CI(Continuous Integration : 継続的インテグレーション)、CD(Continuous Delivery / Deployment:継続的なデリバリ/デプロイ)の学習のために、CI/CDを実現するツールを調査しました。


<a id="org7adccd2"></a>

# ツールと特徴

ほぼ利用しないで、インターネットの情報だけで勝手に特徴をまとめています。(Jenkinsは昔からあるツールなので少し触ったことはあります)

他にもツールは多数ありますが、私が小耳に挟んだものをピックアップしています。

以下は、私の思い込み及び勝手な感想です。

-   Jenkins(<https://www.jenkins.io/>)
    -   オープンソースのCI/CDツール
    -   様々な環境(オンプレ/クラウド)、プラットフォーム(Linux/Mac/Windows...)で動作する
    -   汎用性が高く、プラグインも多数公開されてている。
    -   WARファイル1個で実行できる。!!
    -   K8sに特化した　Jenkins X プロジェクトもある。

-   Tekton(<https://tekton.dev/>)
    -   オープンソースのCI/CDツール
    -   Kubernates Native
    -   ビルド・テスト・デプロイもK8sのPod上で実行
    -   Katakondaで動作するチュートリアル有(Tektonのページから「Get started with interactive tutorials」)
    -   Open Shift Piplelineとして利用

-   CircleCI(<https://circleci.com/ja/>)
    -   SaaSでサービスとして利用、有料ツール。ただし、無料プランあり
    -   Mac/Windowsのビルド環境も構築可能
    -   オンプレでも利用可能
    -   コードリポジトリはGitHub または Bitbucket
    -   マニュアル・サンプルが豊富


<a id="orgf870f26"></a>

# サマリー

クラスター環境を最大限に利用したい場合は、Tekton、過去のしがらみがなければ導入が用意で学習コストが低い CircleCI、汎用性を求める場合は Jenkinsが良いと考えます。私はクラスター環境でのCI/CDを試してみたいので、Tekton を学習しようと思います。

| 名前     | 特徴                                 | クラスタ | 汎用性 | 学習コスト |
|-------- |------------------------------------ |---- |--- |----- |
| Tekton   | K8sクラスタで利用にに特化、シームレス | ○   | △  | △    |
| CircleCI | SaaS提供で直ちに利用可能、Windows/Mac向けソースのビルド可 | △   | △  | ○    |
| Jenkins  | 様々な環境・フラットフォームに対応、汎用性、プラグイン多数 | △   | ○  | △    |
Airflowでタスクのarray同士の依存関係を扱う場合のメモ

# 背景

Airflowでタスクのarray同士の依存関係を定義したい場合がある。
例えば、 [op1, op2, op3] が終了したら、 [op4, op5, op6] を実行したいなど。
直感的に

```
[op1, op2, op3] >> [op4, op5, op6]
```

などと依存関係をDAGで定義しようとすると 

```
unsupported operand type(s) for >>: 'list' and 'list'
```

というエラーになる。list同士は >> で依存関係は定義できない模様。



[Airflowのドキュメント](https://airflow.apache.org/docs/apache-airflow/stable/concepts.html#relationship-builders)を眺めてみると、`cross_downstream` という関数が定義されている。

```
cross_downstream([op1, op2, op3], [op4, op5, op6])
``` 

と定義すると

```
[op1, op2, op3] >> op4
[op1, op2, op3] >> op5
[op1, op2, op3] >> op6
```

となる。

これは便利なのだが、3つ以上のarrayの依存関係を持たせようとするとややこしくなる。例えば以下のようにしたい場合。

```
[op1, op2, op3] >> [op4, op5, op6] >> [op7, op8, op9] >> ....
```
cross_downstream使って定義するのもしんどい。

# 3つ以上のarrayタスク郡の依存性の定義方法

DummyOperatorを使った方法が良さそう。
直感的に定義できるし、簡単。
他にいい方法があれば教えて欲しい。


```py:sample.dag
from airflow import DAG
from airflow.operators.bash_operator import BashOperator
from airflow.operators.dummy_operator import DummyOperator
from datetime import datetime

default_args = {"owner": "airflow", "start_date": datetime(2020, 12, 7, 0, 0, 0)}

dag = DAG("array_tasks_test", default_args=default_args, schedule_interval=None)

op1 = BashOperator(task_id='op1', bash_command='echo "op1"', dag=dag)
op2 = BashOperator(task_id='op2', bash_command='echo "op2"', dag=dag)
#...略
op9 = BashOperator(task_id='op9', bash_command='echo "op9"', dag=dag)

dummy1 = DummyOperator(task_id="dummy1", dag=dag)
dummy2 = DummyOperator(task_id="dummy2", dag=dag)
dummy3 = DummyOperator(task_id="dummy3", dag=dag)

[op1, op2, op3] >> dummy1 >> [op4, op5, op6] >> dummy2 >> [op7, op8, op9]

```

Tree Viewはやや複雑になる。

![スクリーンショット 2020-12-08 10.24.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/20307/42243b7b-85e3-73d2-f160-30b22e9bd163.png)
iOS開発でのCombine導入の戦略について考えてみた

# はじめに
- iOSのバージョンアップに伴いフレームワークも進化してきました。SwiftUI, Combineの登場によって、UIの構築方法の変化、アーキテクチャの変化が必要な時期になってきました。しかし、既存のプロダクトを全て書き換えるのはすぐにはできないです。今回は新しいフレームワークに徐々に移行していくための戦略に追加考えてみました。

# CombineとSwiftUI
- 新しく登場したSwiftUIですがいきなり複雑なUIをSwiftUIで実装するにはハードルが高いと思います。なぜなら、SwiftUIが登場して、2年ほどしか立っておらず、フレームワークの進化の途中であり、iOSのバージョンで使えるAPIの差分が大きいと感じます。
- Combineに関して、すでにRxSwiftなどのReactive Programmingで実装する土壌がある程度整っていて、UIKitとSwiftUIどちらでも対応可能です。
さらにRxSwiftなどをすでに使っていれば、学習コストが低く、既存のものから置き換えやすいと考えられます。
- 以上の結果からCombineの導入で話を進めます。 


# Combine導入
### Target versionをiOS13に変更する
#### ⭕️
- サポートバージョンをiOS13にすれば問題なく使えることができます。

#### ❌
- 運用中のサービスであると関係者の了解をとらないといけないです

### OpenCombineを入れる
- [OpenCombine/OpenCombine](https://github.com/OpenCombine/OpenCombine)


#### ⭕️
- 導入が容易
- iOS13以下でも動作する
- Combineと実装は同じような実装はできる

#### ❌
- ライブラリとして追加するのでバイナリサイズが余計に増え
- メンテナンスが継続的にされるかわからない


### 必要なところだけ自作してみる

#### ⭕️
- 自作することで内部実装まで理解することが容易になります。
- OpenCombineを使うより、影響範囲を自分でコントロールできる

#### ❌
- 自作するので実証者によっては学習コストがかかる

# Combine導入後
- アーキテクチャや実装方針を決める
    - 書き方をある決めておくとコードのメンテがしやすくなる
        - [SwiftUIとCombineを使ったMVVMの実装](https://tech.toreta.in/entry/2019/12/24/104612) 
    - githubに多くのサンプルがあるのでとても参考になります
        - [CombineCommunity/awesome-combine](https://github.com/CombineCommunity/awesome-combine)


## 参考リンク
- https://github.com/CombineCommunity/awesome-combine
- https://github.com/OpenCombine/OpenCombine
- https://tech.toreta.in/entry/2019/12/24/104612
Formクラス作る時は、ActiveModelが便利　

以前、「[Virtusが便利](https://qiita.com/yusuke-matsuda/items/683a0518ff7fec0074ed)」というタイトルでFormクラスを作る記事を書かせていただきました。
この時は、Virtusを利用していたのですが、Rails5.2以降であれば、`ActiveModel`だけで済みます
正確には、ActiveModel::Attributesを使います

```ruby
class ConstructionsSearchForm
  include ActiveModel::Model
  include ActiveModel::Attributes

  attribute :building_name,    :string
  attribute :sales_staff_id,   :integer
  attribute :department_id,    :integer
  
  ....(略）

  def search
    Construction.ransack(
      building_name_cont: building_name,
      sales_staff_id_eq: sales_staff_id,
      sales_staff_department_id_eq: department_id,
    ).result
  end 
end
```

上記のようにFormクラスを作って、controllerで

```ruby
@constructions = ConstructionsSearchForm.new(search_params).search
```

呼び出すだけ。
簡単ですね！！

validation等を追加したい時も前回と同様、`ActiveModel::Model`をincludeしているので、

```ruby
  attribute :building_name,    :string
  attribute :sales_staff_id,   :integer
  attribute :department_id,    :integer

  validate :building_name, presence: true
```

ActiveRecordと同じ用に書いて、`.valid?`で検証するだけです。
ActiveModel::Attributesで指定できる型は、[こちら](https://github.com/rails/rails/blob/master/activemodel/lib/active_model/type.rb)に書いてあります。
【Docker】MySQLとの接続

# 概要
- ホストとコンテナの標準出力を結びつける


# 標準出力の結びつけ
- psオプションでCONTAINER ID または NAMESを確認する

```
% docker ps
CONTAINER ID   IMAGE               COMMAND                  CREATED      STATUS         PORTS                    NAMES
```

- itオプションで標準出力を結びつける
    - -i:ホストの標準入出力をコンテナに結びつける
    - -t:コンテナの標準入出力をコンテナに結びつける

```
% docker exec -it [CONTAINER ID または NAMES] bash
```

- mysqlにログイン(passはdatabase.ymlで確認)
    - -u:ユーザーの指定
    - -p:パスワード使用

```
% mysql -u root -p
```

以上
アナログ回路

# 概要

circuit sandboxをplunkerでホスティングした。
アナログ回路をシュミレーションで、説明してみる。

# 使用したライブラリィ

https://github.com/willymcallister/circuit-sandbox

# 写真

![無題.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/58c9791e-387e-8906-4a8e-692bc40d0866.jpeg)

# 説明

直流電源を設置、５Vとする。
抵抗を設置、１ｋオームとする。
メニューバーのDCをクリックすると、直流特性を表示する。
電流は、電圧÷抵抗です。

# 成果物

https://embed.plnkr.co/plunk/ipxw2jGZsV5klnv9

以上。
[ViveProEye]アイトラッキングのキャリブレーションをスクリプトから実行する

#はじめに
HTC社から販売されているHMD「**ViveProEye**」は視線をトラッキングしてその情報をゲームなどで使用することができます。
しかし、目の位置や動きには個人差があるため, 事前に**キャリブレーション（校正）**をおこなう必要があります。

これは基本的にはViveのメニュー上からおこなうのですが、スクリプトでもこれを開始することができるのでその方法を紹介します。

#実行環境
* Unity 2019.4.4f1
* SteamVRPlugin 2.6.1 (sdk 1.13.10)
* ViveEyeTrackingSDK(SRanipal) v1.3.1.0

#実装方法
以下のスクリプトのコンポーネントを任意のオブジェクトに追加します。
スペースキーを押したらキャリブレーションが始まるようにしています。

```csharp:EyeCalibrator.cs
using System;
using UnityEngine;
using ViveSR.anipal.Eye;

public class EyeCalibrator : MonoBehaviour
{
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            SRanipal_Eye_API.LaunchEyeCalibration(IntPtr.Zero);
        }
    }
}
```

HTC社が配布しているEyeTracking対応デバイスのためのSDK「[**ViveEyeTrackingSDK(SRanipal)**](https://developer.vive.com/resources/vive-sense/sdk/vive-eye-tracking-sdk-sranipal/)」が提供する
`SRanipal_Eye_API.LaunchEyeCalibration(IntPtr.Zero)`を使用します。

これを使用することでViveのメニュー上から実行するのと同じ画面に切り替わり、キャリブレーションをおこなうことができます。

詳しくはSDKに同封されているリファレンスを確認してみてください
（バージョンによっては仕様が変わっている可能性があります。）
【UFT入門】キャプチャリプレイでスクリプトを作成する

# はじめに

この記事はUFT Oneを初めて触ってみる方に向けて書いた記事になります。(いわゆるUFT入門）
そのためできるだけ丁寧に書いていくことを心がけています。
UFT Oneを試しに使ってみたいけど、スクリプトをどう書けばよいかわからない
という方はまずキャプチャリプレイからやってみると良いかと思いますので、ぜひ参考にしてみてください。

## 環境
下記の環境で説明をします。
UFT OneはすでにWindowsにインストール済みとします。
今回はWebサイトを操作していきます。

|             | Version     | 
|:------------|:-----------:|
| UFT One     | 15.0.1      |
| Windows     | 10          |
|使用するサイト|https://hotel.testplanisphere.dev/ja/|


## キャプチャリプレイとは

UFT Oneでの自動テストスクリプトの実装方法は3種類あります。
  
1. キャプチャリプレイ
2. キーワード駆動
3. コーディング

そして、その中でもキャプチャリプレイは最も簡単な方法になります。
ユーザが実施した動作を記録（キャプチャ）し、
実行する（リプレイ）
これがキャプチャリプレイになります。

## キャプチャリプレイの準備

キャプチャリプレイまでの準備は下記の通りです。
1. UFTを起動する
2. テストの作成をする
3. 記録と実行環境設定を確認する

### 1. UFT Oneを起動する

起動の際にはアドインを選択してください。

- Javaアプリケーションを操作する場合は、Javaに
- Webを操作する場合には、Webに

チェックを付けておく必要があります。
もし必要なアドインが出ない場合は下記を参照してみてください。
[UFT Oneのインストールする機能を変更したい](https://qiita.com/YamaAri/items/4ccf846c8013e0334952)

今回のアドイン選択画面は下記画面の通りです。
選択
![UFT_アドインマネージャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/121319/e4993dce-658d-5625-b4ec-6c2a99b47c3c.png)

※小ネタ
ここのアドインはいくつでも選択できます。
が、公式の推奨は３つ。
全部選択すると少し重たくなるので、使うものだけを選択してください。


### 2. テストの作成をする

ファイル > 新規 > テストからテストを作成していきます。
今回はデフォルトのままで作成していきます。

![UFT_新規.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/121319/959736ba-8bad-9a86-4152-b83410336e79.png)

### 3. 記録と実行環境設定を確認する
Action1を開いたら、記録 > 記録とと実行環境設定を選択してください。
設定はどのようにしていてもOKです。
今回は下記の通りで行きます。
※設定を変更した場合は、適用→OKを実施してください。
![UFT_記録.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/121319/8277bfd2-7aeb-7856-bcc1-0239761fbb4b.png)

## キャプチャリプレイを行う

準備が出来たら、キャプチャリプレイを実施していきましょう。

### キャプチャする
キャプチャを開始するには「記録」を選択してください。
![記録.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/121319/9255b09a-3b87-3f04-36fe-86ae9eb248e6.png)

今回の設定では記録を開始するとブラウザが立ち上がり、指定したサイトが立ち上がります。
また別に下記のようなものも立ち上がります。
記録の横にある（）の中は操作するごとに増えていきます。
![UFT_記録用.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/121319/cd5b5582-9ca8-e8aa-0309-c6ce83e43b01.png)

今回は下記の操作を行いました。

1. 宿泊予約に移動する
2. お得な特典付きプランのこのプランで予約を押下
3. 宿泊日をセット
4. 宿泊日数は1泊のまま
5. 人数は2人
6. 朝食バイキングにチェック
7. 氏名に山本をセット
8. 確認のご連絡には希望しないをセット
9. 予約内容を確認するを押下
10. この内容で予約するを押下

操作を行った後、先程の画像の■（停止ボタン）を押下すると、記録が終了します。
記録が終了するとAction1にはコードが生成されています。
![UFT_ko-do.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/121319/17714c30-89fc-97a2-abbc-70e3f8a3af92.png)

これで記録は完了です。

### リプレイする

こちらは記録ボタンの右横にある、実行ボタンを押下し、再度実行を押せば可能です。
実行が開始されると先程記録した動作が再生されます。
リプレイはこれだけです。

以上がキャプチャリプレイでスクリプトを作成する方法です。
簡単ですね！
WordPressのウィジェットを有効化する方法

WordPressウィジェットは必ず使うと思うので

テーマを開発する時は有効にしておくと良いです。

##WordPressウィジェットを有効化する方法

```php:function.php
/* ---------------------------------------
ウィジェットの有効化
--------------------------------------- */
function my_theme_widgets() {
    register_sidebar(array(
         'name' => 'サイド',
         'id' => 'side_widget' ,
         'before_widget' => '<div class="side-widget">',
         'after_widget' => '</div>',
         'before_title' => '<h2 class="widget-side-title">',
         'after_title' => '</h2>'
    ));
    register_sidebar(array(
         'name' => 'フッター',
         'id' => 'footer_widget' ,
         'before_widget' => '<div class="footer-widget">',
         'after_widget' => '</div>',
         'before_title' => '<h2 class="widget-footer-title">',
         'after_title' => '</h2>'
    ));
    }
    add_action( 'widgets_init', 'my_theme_widgets' );
```

サイド用とフッター用を設置してみました。

あとは使いたいページのphpファイルに下記のようにかく！！

```php:php
//サイド
<?php dynamic_sidebar('side_widget'); ?>
```

```php:php
//フッター
<?php dynamic_sidebar('footer_widget'); ?>
```
##さいご
以上！！
ではまた！！！
GitHubにpushせよ

#はじめに
本当にいつもいつも忘れるので戒めのメモです。

#結論
いろんなやり方があると思うのですが、ぼくはこれが基本です。
作業中のブランチ名は｀master-cron｀とします。


```
#作業中のブランチを確認
git branch
* master-cron
  master

#ステータスを確認
git status

#addする
git add ｀*｀とか｀意図したファイル名｀

#ステータスを確認してaddされているか確認する
git status

#commitする
git commit -m "modify ファイル名"

#ステータスを確認してcommitされたことを確認する
git status

#作業中のブランチを改めて確認
git branch
* master-cron
  master

#pushする
git push origin master-cron

```

#おまけ
日常的に使ってないとcloneまで忘れる。。

```
#ブランチをローカルに保存する
git clone リポジトリのURL

#ブランチを切る
git branch ブランチ名

#ブランチの切り替え
git checkout ブランチ名

```

コンフリクトとかしたら調べて都度対応する感じですね！

簡単ですが以上です。
初投稿　【Herokuを更新する】



## 初めに
初投稿はRails チュートリアルのに関して投稿していきます


なんとかherokuにデプロイして、その後変更内容を更新させていきたいと思います


applicationに変更を加え、保存後下記手順で更新していきました。


##コード

```ruby:qiita.rb
$ git add .
$ git commit -m "Update application"
$ git push heroku master
```

##終わりに
Herokuへのアップロードは祈るばかりですが、失敗しても検索力が磨かれている気がします。。。
Athena engine version 2を試してみた【神アップデート】

# 概要
東京リージョンにも、[Athena engine version 2](https://docs.aws.amazon.com/athena/latest/ug/engine-versions-reference.html#engine-versions-reference-0002)が来ました。
様々な機能追加や改善が書かれていますが、やはり一番気になるのが「Performance Improvements」ですよね。輝いてます。

一覧を見ていても

- DISTINCT
- JOIN and AGGREGATE operations
- LIKE
- ORDER BY and LIMIT 

を始め山ほど列挙されており、かつ期待が高まる項目ばかりで、それもう要するに「ぜんぶ凄く速くなった！」ってことですよね？？？

と言う訳で、自社で運用しているAthenaのクエリで早速試してみました。

# 設定方法
既存のワークグループであれば、ワークグループの編集項目に「Query engine version」と言う項目が増えていますので、「Manually choose an engine version now.」→「Athena engine version 2 (recommended)」を選択することでバージョンアップ可能です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/68734/36afbc93-7c68-2c2d-29d2-ebdd34e7827d.png)

そう、激熱ポイントとして

**1. ワークグループ単位での設定が可能**
**2. （今は）バージョン1に戻せる**

という移行および検証のしやすさがあります。これは滅茶苦茶嬉しいです。

# 利用したデータセット
[こちらの記事](https://qiita.com/yuji_saito/items/dc41797bab29beec9d63)と同様のものをベースに複雑なクエリとなったものを利用しまましたが、Athenaを始めこの手のパフォーマンスの話は、ケースバイケースの要素が強いと考えており、参考程度でご覧ください。

使われた履歴の中から、

- order by limit xxx なしのクエリ
- order by limit xxx ありのクエリ
- パフォーマンスが遅くなりがちな難儀なテーブルを含むクエリ

という軸で実行時間を見て適当にピックアップし、バージョン1とバージョン2でそれぞれ設定されたワークグループに対して検証をしてみました。
規模としては、だいたい1億～2億レコードをスキャンすることになるテーブルをいくつかJOINしたりもしています。


# 結論サマリ
・スキャン量が減るケースが散見（これも嬉しい）
・order by / limit なしのクエリは今回のデータセットでは、速度は変化なし
・order by / limit ありのクエリは目に見えて速くなった
・一番難儀だったテーブルを含むクエリに非常に高い効果が出た（30秒強→20秒弱と、実に倍速近い結果に）

総じて「**複雑で無茶をしていたクエリが少し安く、かなり速くなった**」という **そんなことが許されるのですか...** という結果となりました。神か。



# 結果一覧集
突然のExcelですが、平均実行時間、は少ないですが3回の実行結果を取っています。
なのでバージョン2が遅くなっているように見えるものは、単に試行回数によるものと思われます。また、パーセンテージにしちゃったので見辛いですが、order by limit なしはほぼ結果変わっておらず、ありはどれも数秒以上速くなってます。
ケース10～12の改善具合がえぐいですね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/68734/1a93488b-49e9-9307-c8eb-3771c0bb5f60.png)



# 感想
実運用への適用に向けて、互換性のチェックはしていかないといけないのですが、性能面においては「逆に遅くなる」などの懸念が無い感触で、アップデートに向けて期待はあるがデメリットの無い、すなわちそれは神アップデートと言えるのではないでしょうか。
re:Invent 2020でもFINRAでAthenaを超活用している事例が紹介されておりましたが、更にAthenaが盛り上がっていけば良いな！と思いました。
非エンジニアに読んでほしい、iOSアプリクラッシュレポートの話

この記事はプロジェクトマネージャーなど、非iOSエンジニアの方に知って欲しい

- アプリのクラッシュとは？
- アプリがクラッシュしたことを知るには？
- その仕組みを利用する上で知っておくべきことは？

これらのことを書きます。


# アプリのクラッシュとは
アプリを操作中に突然ホーム画面に移動してしまう現象です。
アプリが継続不可となり強制終了する状態です。
ユーザー体験を大きく損なうため避けるべきエラーです。

# アプリがクラッシュしたことを知るには？
サーバーサイドのエラーであればログを手に入れることは可能ですが、アプリユーザーにログ提出を依頼するのは現実的ではありません。
Appleが提供している仕組みでクラッシュレポート (アプリがクラッシュしたこと、及びクラッシュした経緯) を収集することは可能ではありますが
**全てのクラッシュを知ることはできません。**

※補足
https://support.apple.com/ja-jp/HT202100

### Firebase Crashlytics
Appleが提供する仕組みでは全てのクラッシュレポートを取得できないため、サードバーティの仕組みを利用することが一般的です。
Firebase Crashlyticsはその代表と言える、広く利用されているサービスです。
クラッシュレポートの収集に関しては無料で利用可能です。

# Firebase Crashlyticsを利用する上で知っておくべきことは？
### プライバシーポリシーや利用規約
アプリのプライバシーポリシーや利用規約に「Crashlyticsを利用して情報を収集する」旨を記述するか検討する必要があります。
(ほとんどのアプリは明記されています)
AppleのアプリReviewガイドラインにも個人情報収集に関する記載があります。
法務担当とよく相談しておくべき事項です。

### dSYMファイルをFirebaseに送信しなければならない
AppStoreを経由したアプリの配信時は、dSYMというファイルをAppStoreConnectからダウンロードしFirebaseへ送信する必要があります。
この操作は新しいバージョンをリリースするたびに毎回必要な作業になります。
**この操作を忘れるとクラッシュレポートは収集できません。**
コマンドラインツールの利用などが必要なため、エンジニアに相談しましょう。
※補足
ENABLE_BITCODEがデフォルト値のままtrueになっている前提です

### それでも検出できないクラッシュがある
アプリがクラッシュレポートを送信するタイミングはクラッシュ後、つぎにアプリを起動したときです。
よって、クラッシュ後もう2度とアプリを起動しなかった場合はクラッシュレポートが収集できません。
また、起動直後に繰り返しクラッシュするような状況でもクラッシュレポートは収集できません。 (ある程度アプリの実装に左右されます)

# 最後に
アプリのクラッシュは避けるべきですが、完全になくすことは困難です。
クラッシュが起こったことを知り、修正していくことは重要です。
この記事に書いたクラッシュレポート収集に関する事柄を、予めプロジェクト計画に組み込んでおく必要があると私は考えます。
未経験で大学を休学したエンジニアが2020年に学んだこと

CAMPFIRE Communityでエンジニアをしております。Matsuiです。

趣味はスポーツ観戦、旅行などです。
2020年はプロ野球、UEFAチャンピオンズリーグ、F1&F2が個人的に盛り上がりました。好きなドライバーはMax Verstappenです。(誰にも伝わらないと思いますが、Daniel Ricciardoとの[コンビのシーン](https://www.youtube.com/results?search_query=daniel+ricciardo+max+verstappen)がすごく好きです。)

2020年は大学を休学し未経験からエンジニアに挑戦をした一年でした。このアドベントカレンダーを利用して2020年に私が経験したこと、学んだこと、意識したことをまとめます。

###エンジニアにチャレンジする前（2020/1時点）のスペック
```
- プログラミング経験はほぼゼロ。（SQLのみ若干経験あり）
- コンピュータやインターネットには比較的馴染みがある。（作る側ではなく、利用する側として。）
- 国立大学文系学部に通っている。
```

#やったこと

###2020年1~2月
- 初めて `rails new` をする。
- [Railsガイド](https://railsguides.jp/getting_started.html)のチュートリアル?をやる。

###2~3月
- CAMPFIREのコードを読むようになる。
- 社内でデータ取得用のカラム追加とタスクに日時挿入の処理を追加する。

###4~6月
- [サポートサービス](https://note.com/camp_community_/n/n8cf18f844f02)のコード分離とサービス追加。
    - 密結合状態にあったコードをコントローラーレベルで切り分け、コードの分離を行いました。
    - またクラウドファンディングとコミュニティではサービスの性質が異なる部分もあるため、コミュニティ独自のサポートサービスを追加しました。


###7~8月
- [コミュニティページのデザイン変更](https://note.com/camp_community_/n/nd80f9ea72b88)に合わせて必要になったバックエンドの開発。
- 密結合状態のコードの分離を行いました。

###9~11月
- [サポートサービス](https://note.com/camp_community_/n/n8cf18f844f02)をDBで管理の上、社内の管理画面から追加、編集などをできるようにしました。
    - これまでは追加、編集のためにデプロイをエンジニアに依頼する必要がありましたが、エンジニアなしで追加、編集できるようにしました。

###11~12月
- 社内で使用する管理画面の機能改修、脱ライブラリ化。
    - CAMPFIRE全体で社内で使用する管理画面を脱ライブラリ化し、独自のシステムを構築し移行する流れがあったのでそれに合わせて、主にコミュニティに関する機能の移行を担当しました。（しています。現在も進行中です。）


#意識したこと、学び
※個人の意見です
####組織をどうしたいか、プロダクトをどうしたいかは一旦考えるのをやめた。
- 組織のことを考えることも大事ですが、自分の実力が不足している状態だったのでとにかく自分のことに集中しました。自分のことに集中することが組織のためくらい割り切っていました。

####一通り業務がこなせるようになるまでは、情報もシャットアウト。
- 技術は進歩も早く常に新しい情報が流れてくるのでできるだけキャッチアップしたほうが良いですが、基礎が無いままキャッチアップをしても効率も低いままですし、アウトプットにつながらないのでまずは基礎固めに集中しました。（特に初期は。）

####GitHubのPR,issue,Slackの議論やレビューなどはできる限り目を通す。
- どこに学びが転がっているか分からないのでGitHubのPR,issue,Slackの議論やレビューなどは自分に関係ないことでも、意識して積極的に目を通すようにしていました。（そして実装の際は徹底的に~~パクり~~参考にしました。他人の思考や脳は外部ライブラリだと思っています。）

####分からない、困ったは一定時間たったら詳しい人に質問するべき。
- ありきたりですが、初期はこれが出来ず聞いたら迷惑なのでは、自分で突き詰めて考えた方が良いのではと思っていました。しかし、わからないことは一定時間（1時間など）以上悩んでも大体解決しないのでスパッと聞いたほうが良いと考えるようになりました。聞くことは迷惑でもないですし、迷惑だったとしても他のところで取り返せば良いくらいに開き直るようになりました。


#さいごに

足りない部分、課題はありすぎて書ききれない、認識しているものが全てでないので省略します。

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

質問、ご意見、アドバイスなどあればコメントまでお願いします。

大学は卒業する予定です。おわり。
aws cli s3 syncコマンドで差分を操る

# 更新していないのに毎回アップロードされてしまう時

```shell
# ローカルの`dist`ディレクトリからs3の`bucket-name`バケットへファイルサイズを見てシンク
$ aws s3 sync --size-only dist s3://bucket-name
```

# タイムスタンプが違っていたらアップロードしたい時

```shell
# ローカルの`dist`ディレクトリからs3の`bucket-name`バケットへタイムスタンプを見てシンク
$ aws s3 sync --exact-timestamps dist s3://bucket-name
```

# 参照
[s3コマンドでsyncした時、更新していないのに毎回アップロードされてしまう](https://blog.kozakana.net/2017/11/s3_sync_size-only_option/)
公式Reactチュートリアルの解説vol.1

**※React関連の記事は引っ越しました**
VTeacherの「サブスク加入者のページ」から閲覧できます。
https://apps.apple.com/app/vteacher/id1435002381

単元
- 公式Reactチュートリアルとは
-「これから作るもの」の解説
- 「React とは？」の解説
-「スターターコードの中身を確認する」の解説
RubyonRails(RoR)でHTMLを埋め込みレンダリングする

#経緯
DBからHTMLを取ってきてそのままモーダルでHTMLレンダリングする作業が発生したので備忘録

#どうやるのか

コントローラ側で取ってきたHTMLをテンプレにアサインし、テンプレ側でpreserveするだけ。

例）

controller側

```ruby
#view側で使っているpreserveは改行を&#x000A;に変換してしまったので、
#JSがあった場合、変なところに&#x000A;が入って動かなくなる場合があるため置換
@contents = html_contents.gsub(/\r\n|\r|\n/, "") 
```

view側(hamlの抜粋)

```ruby
%body
  = preserve(@contents)
```

#今回の場合

たまたま動画埋め込みようのJSの相性なのか、動画を表示するJSがキレイに動かず、２回同じモーダルを表示しないと動画が見れなかった。
使い物にならないため別ページとしてHTMLをレンダリングすることにした。。。
Laravelで簡易的にBasic認証

LaravelでBasic認証をやる方法はいくつかありますが、ライブラリを入れたりせず、データベース使ったりせず、簡易的にに実現する方法です。

- ミドルウェアを作成する(1ファイル)
- ミドルウェアをKernelに記述する
- routes/web.php で認証の対象のページを記述する

の３ステップで実現できます。

## ミドルウェアを作成する

今回のサンプルでは、BasicAuthMiddlewareという名前でミドルウェアを作成します。


```powershell
php artisan make:middleware BasicAuthMiddleware
```


作成したミドルウェアのhandleメソッドを、以下のように実装します。
ユーザー名とパスワードは、ここに直接書いてます。


```php:App\Http\Middleware\BasicAuthMiddleware.php
    public function handle(Request $request, Closure $next)
    {
        $username = $request->getUser();
        $password = $request->getPassword();

        if ($username == 'sample' && $password == 'sample') {
            return $next($request);
        }

        abort(401, "Enter username and password.", [
            header('WWW-Authenticate: Basic realm="Sample Private Page"'),
            header('Content-Type: text/plain; charset=utf-8')
        ]);
    }
```

## ミドルウェアをKernelに登録

app/Http/Kernel.php の $routeMiddleware に、作成したミドルウェアを記述。
今回は、'basicauth'という名前で登録

```php:app/Http/Kernel.php
// Laravel9
'basicauth' => [
    \App\Http\Middleware\BasicAuthMiddleware::class,
],

// Laravel8以下
'basicauth' => \App\Http\Middleware\BasicAuthMiddleware::class,
```

バージョン5くらいのLaravelだと、下記の書き方になります。

`'basicauth' => 'App\Http\Middleware\BasicAuthMiddleware',`

## routes/web.php で認証の対象のページを記述する

登録した名前のミドルウェアで、対象のページをグループ化する

```php:routes/web.php
Route::group(['middleware' => 'basicauth'], function() {
    // ここに対象のページを記述
    // 例）
    Route::get('/', [App\Http\Controllers\TopController::class, 'index'])->name('top');
});
```

以上で完了です。
第3回　AWSに自動でテスト/デプロイしてくれるインフラの設定・構築（Nginx・MySQL編）

# 本シリーズ集
|  | タイトル |
|:-:|:-:|
| 0 | [目標・やりたいこと](https://qiita.com/drafts/c59c0df9eaf5e6b10111/edit) |
| 1 | [AWS編](https://qiita.com/Dadadada-TT/items/86e0a578f934e6578c04)|
| 2 | [rails開発環境構築編](https://qiita.com/Dadadada-TT/items/f4ce8d997cc0bb3e0aca)|
| 3 | __Nginx・MySQL編__ |
| 4 | [Capistrano編](https://qiita.com/Dadadada-TT/items/79e33659eacda1cd0510) |
| 5 | [CircleCI編](https://qiita.com/Dadadada-TT/items/a9530630782c6f4c7cbc) |
| 6 | [総集編](https://qiita.com/Dadadada-TT/items/3d1fa7854d562ae1db1b) |
#はじめに
　Nginx・MySQLを分けると、短くなってしまうため、本記事では二つをまとめる。
　まずはNginxから。

#Nginxとは
　Webサーバ用ソフトウェアの一つ。
　Webサーバといえば、__Nginx__ と __Apache__ の二代巨頭なイメージ（がないですか？）。
　今回は、このNginxをDockerfileを用いて構築する。

#ディレクトリ構成

```
/nginx
├ public
|  ├ 404.html
|  ├ 422.html
|  └ 500.html
├ nginx.conf
└ Dockerfile
```

　publicディレクトリ配下は、`rails new`コマンドにより生成されたファイル群の一部抜粋したものである。(この`404.html`とかのファイルは特別いるわけでもないが、rails側と通信できなかった時にエラーページを表示するためのものである。


###Dockerfileの中身

```Dockerfile:Dockerfile
FROM nginx:latest
RUN rm -f /etc/nginx/conf.d/*

COPY ./public /public
COPY nginx.conf /etc/nginx/conf.d/nginx.conf
# /conf.d/ディレクトリ配下の設定ファイルを読み込む設定になっているので、（元を確認してないので、もしかしたら0かもしれない。）
# それらを一度全部削除して、新たに作成したファイルを入れる 
CMD nginx -g 'daemon off;' -c /etc/nginx/nginx.conf
```

###nginx.conf ファイルの中身

```.conf:nginx.conf
server {
  listen 80;
  # ドキュメントルートの指定
  root /public;
  error_page 404             /404.html;
  error_page 505 502 503 504 /500.html;
  location / {
    try_files $uri @app;
  }

  # # リバースプロキシ関連の設定
  location @app {
    proxy_pass http://xx.xx.xx.xx:3000; 
    # 対象APサーバを持つEC2インスタンスの、プライベートIPアドレスとポートを指定する

  }
}
```

これで、準備OK。

# Webサーバを起動してみる。
　EC2インスタンスに、`sftp`コマンドにより、ファイル群をアップロードした後、`ssh`コマンドでEC2にアクセスし、

```
# docker build -t test-nginx .
# docker run -p 80:80 test-nginx
（このまま見た目は止まる）
```

とすると、起動する（見た目では分かりにくいけど）。

# ローカルブラウザから、アクセスしてみる
　ローカルブラウザで、`http://IPアドレス/`とうち、アクセスしてみると、
![スクリーンショット 2020-11-17 18.23.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/557656/4bc6043e-aef8-9ad5-473c-81ccb996a1a3.png)
と出るので、きちんとWebサーバが立っていることがわかる。


# MySQL
　MySQLのDockerfileはない。`docker pull`コマンドで`MySQL:5.7`をpullし、それをrunコマンドで走らせて終了。

### sshキーでアクセスし、各種コマンドを打つ。


```
$ ssh -i 【鍵のPATH】 ec2-user@xx.xx.xx.xx
[ec2-user@ip-xx-xx-xx-xx ~]$ sudo service docker start
[ec2-user@ip-xx-xx-xx-xx ~]$ docker pull mysql:5.7
[ec2-user@ip-xx-xx-xx-xx ~]$ docker run -p 3306:3306 -e MYSQL_ROOT_PASSWORD=root --rm mysql:5.7
...
...
Version: '5.7.32'  socket: '/var/run/mysqld/mysqld.sock'  port: 3306  MySQL Community Server (GPL)
```


これでおしまい！


# まとめ
　さら〜っとこんな感じでやればできます〜って感じで書いてますけど、実際には（主にWeb-AP間の連携の部分で）この作業周りでまる1日かかった笑。
　特に最後の画像のエラーがどうしても修正できなくて、めちゃくちゃ迷いました。なんでMySQL5.7を使用しているかも含めて、また後日この話は別の記事であげたいと思います。
Googleフォントが反映されない

こんにちは。[niina](https://twitter.com/niina_design)です。

今回は***Googleフォントのリンクを貼ったのに、ブラウザに反映されなかった***ときの自分のミスを残しておきたいと思います。

#Google Fontsとは#
私たちが目にするWebサイトは、Webフォントやデバイスフォントを利用して文字を表示するようになっていますが、使用する端末によってフォントが変わってしまうと意図したデザインと違ってしまったりととても不便ですよね。

そこで**どんな端末で見ても同じフォントで表示させてくれるのがGoogle Fonts**です。
様々な言語のフォントにも対応しており、基本的に無料で利用することができます。

Google Fontsを利用すると、ネットワーク上でフォントデータを読み込み、サイトに反映してくれるので、どんな端末で見ても同じフォントで表示されるのです。


#Google Fontsの使い方#

Googlefontsのおおまかな使い方は次の通りです。

１．Google Fontsのページから利用したいフォントを選ぶ。
２．利用したいフォントのスタイルを選ぶ。
３．生成されたコードをhtmlファイルにコピペ。

###まずはGoogle Fontsを開く###

![googlefonts.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/687925/d67e9db1-0b5b-79d6-ace7-d499e5d1968d.png)

[Google fonts](https://fonts.google.com/)のページを開きます。
ページの上部にある検索システムを使って、利用したいフォントを検索します。
あらかじめフォント名がわかっている場合は、検索窓に直接フォント名を打って、検索。
まだフォントが決まっていない場合は、LanguagesやCategoriesなどを利用して検索していきます。

###利用したいスタイルを決める###

![googlefonts2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/687925/940c2cfd-86ad-ef44-f9b7-e3cf2539d31f.png)


利用したいフォントを選んだ次は、利用したいスタイルを決めます。
細いものから太いものまで、たくさんのスタイルが用意されているので、右側にある「+select this style」をクリックして、使いたいスタイルをどんどん選んでいきます。
（Webページで使いたいスタイルのみ選択するようにしましょう。）
やっぱりこのスタイルはキャンセルしたいという時は、「-remove this style」をクリックするとすぐに削除できます。

###生成されたコードをhtmlファイルにコピペする###

![googlefonts3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/687925/2f2ccde2-8296-0dd2-5a46-9cf94e00868d.png)

「+select this style」をクリックすると、右側に「selected family」という小窓が現れ、自分が選んだスタイル名や、htmlに貼り付けるためのlinkコードが表示されます。
そのlinkコードをhtmlファイルのheadに貼り付けたら完了です。

※CSSで指示するfont-familyも、linkコードのすぐ下にある「CSS rules to specify families」を参考に書いてください。
![googlefonts4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/687925/22aa12c2-9681-e2ec-acb8-0eee763e992d.png)


#Google Fontsが反映されないときに確認すべきこと#

さて、ここまで完了したのになぜかGoogleフォントが反映されないという方は、html内に書いたlinkをもう一度確認してみましょう。

***htmlファイルは上から書いていった順に読み込まれていくので<link>を書く順序がとても重要になります。***

<head>内に書く<link>といえば、フォント以外にもreset.cssやstyle.css、jQuery本体や、jQuery、プラグインのcssなどいろいろあります。

この順番を間違えるとブラウザに正しく反映されなくなるのです。

私の場合は、reset.cssの前にGoogle fontsのリンクを貼ってしまったが故、reset.cssに上書きされてしまい、Googleフォントが反映されないという事態になってしまいました。

フォントが反映されないという方の参考なれば。
vue.js google adsense

vue.js で adsense を使いたい。

参考
https://www.ketancho.net/entry/2018/05/22/080000

#インスコ

```

npm install vue-adsense --save

```

#コード改変

これをやらないとエラーが出る

`vim node_modules/vue-adsense/main.js` をして、
以下の内容に変更

```node_modules/vue-adsense/main.js

import VueAdsense from './VueAdsense.vue'
export default VueAdsense

```


#app.js に追記

```app.js

import VueAdsense from 'vue-adsense'
// Google Adsense 用
Vue.component('adsense', VueAdsense)

```

# コード挿入

使いたいコードに以下を追記して完了。
それぞれ、adsenseから拾ったデータを入れること。

```hoge.vue

<adsense
        ad-client="ca-pub-xxx"
        ad-slot="2061149xxxx"
        ad-format="auto"
        full-width-responsive="true">
</adsense>


```
Matlab画像処理「平均化フィルタ」

2本目です。

画像の平均化フィルタをMatlab内で関数化したので投稿します。

levelに奇数を入れると、その数分の周囲のピクセル正方形から平均を取ります。
例) level = 3

1 1 1
2 2 3
3 4 4

平均化フィルタ処理後、中央画素は9ピクセルの平均値2.33になります。

下記のコードでは、周囲のピクセルが存在しない端にはフィルタ処理されないのでご注意ください。

level=7で平均化された猫チャンが右です。（よく見ると周囲のピクセルが明瞭なまま）


![ave.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/923577/32442759-9d4e-515a-77ae-8a3f7948730b.jpeg)

```
%%%読み込み%%%
test = imread("C:\hogehoge\test.jpg");

%%%処理%%%
test2 = AVEfilter(test,5);

%%%出力%%%
subplot(1,2,1)
imshow(test)
subplot(1,2,2)
imshow(test2)
imwrite(test2,"C:\hogehoge\test2.jpg")


%%%ここから下コピペ%%%
function [pic2] = AVEfilter(pic1,level) 
sz1 = size(pic1,1);
sz2 = size(pic1,2);
sz3 = size(pic1,3);

lv = (level-1)/2;
pic2 = zeros(sz1,sz2,sz3);

for k = 1:sz3
for  j=1+lv:sz2-lv
    for i = 1+lv:sz1-lv
        kernel = pic1(i-lv:i+lv,j-lv:j+lv,k);
        pic2(i,j,k)=mean(kernel,'all');
    end
end
end
pic2=pic2/255;
end
```






いや、Pythonでよくね…？
参考　西住工房様【Python/OpenCV】平均値フィルタでぼかし・平滑化
https://algorithm.joho.info/programming/python/opencv-averaging-filter-py/
LINE WORKSのJWT認証をPHPで通してみる

ちょっと仕事でLINE WORKSの認証を通す必要があったのですが、
composerでjwtライブラリを入れて認証するものが多かったのでピュアPHPで入れるとこうなるって
ものを書いてみた

```php
<?php
/**
 * @property strign rsa_key プライベートキー（実際はセキュアな場所におかないとだめ）
 */
$rsa_key = "-----BEGIN PRIVATE KEY-----
[ここは発行されたプライベートキーを入れる]
-----END PRIVATE KEY-----";

/**
 * @property strign server_id サーバーID
 */
$server_id = "[ここも発行されているサーバーIDを入れる]";

//Header作成
$header = '{"alg":"RS256","typ":"JWT"}';
$header = base64_encode($header);
//URLSafeな形で置換
$header = str_replace(array('+', '/', '='), array('-', '_', ''), $header);

//body作成 issはサーバーID
$body = '{"iss":"%s","iat":%s,"exp":%s}';
//生成は現在時刻、満了は30分後に設定
$body = sprintf($body, $server_id, time(), time() + 1800);
$body = base64_encode($body);
$body = str_replace(array('+', '/', '='), array('-', '_', ''), $body);

//headerとbodyをつなげたもの
$sha_hash = $header . "." . $body;

//電子認証を行うアルゴリズムはSHA256にしないといけない
openssl_sign($sha_hash, $encrypted, $rsa_key, OPENSSL_ALGO_SHA256);
$signature = base64_encode($encrypted);
$signature = str_replace(array('+', '/', '='), array('-', '_', ''), $signature);

//JWT生成
echo $header . "." . $body . "." . $signature;
```

このJWTを使ってPOSTmanで認証通してみると
![Postman_と_Qiita.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42874/e6b3fe37-849d-e2b9-ed85-02c304e60a2d.png)

こんな感じで200OKが帰ってきて成功する
本来はライブラリでやるんでしょうけど、それが諸々の理由でできない人はこんな感じで認証できるよという話でした
PHP授業(php01〜php05まで）

<h2>入力フォーム、送信ボタンを作る</h2>

フォームに入力されたものは、"namae"という名前になる。
POSTは送る！って意味かな

```php:
<form action="./php02.php" method="POST">
your name:<input type="text" name="namae" size="20">
<input type="submit" value="send!">
</form>
```

↓上のコードでこれができるよ
![スクリーンショット 2020-12-15 10.49.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654246/8f33d75d-fed6-0657-86d5-645b285cd698.png)




<h2>入力された値を呼び出す。データの受け渡し①
</h2>

namaeを表示させる。

```php:
<?php echo htmlspecialchars($_POST['namae']); ?>
```




htmlspecialcharsってのは、文字化けしないように、セキュリティーのためのものらしい。

<h2>入力された値を呼び出す。データの受け渡し②</h2>
もし、"namae"にisset（セット）されていたら、こうしてください。

```php:
<?php
if (isset($_POST['namae'])){
echo 'Hello, ' . htmlspecialchars($_POST['namae']);
}
?>
```
結果
![スクリーンショット 2020-12-15 11.01.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654246/c1e8f0d3-56be-e4e8-1beb-70be86d7cd44.png)


<h2>入力された値を呼び出す。データの受け渡し③</h2>
※ここからはフォームも変わるよ
txt→さっきのnamaeの部分。textを示す
no→numberを示す

```php:
<form action="./php04.php" method="POST">
text:<input type="text" name="txt" size="20"><br>
number: <input type="text" size="3" value="10" name="no">
<input type="submit" value="send!">
</form>
<?php
if (isset($_POST['txt']) && isset($_POST['no']) && (int)$_POST['no']>0){
  for($i=0;$i<(int)$_POST['no'];$i++){
    echo htmlspecialchars($_POST['txt'] . ' ');
  }
}
?>
```
訳：
txtとnoが入力されていて、かつnoの数字が0より大きい時、noに入力された数字のぶん、textを出力させる。ってやつ。

<h2>入力された値を呼び出す。データの受け渡し④</h2>

```php:
<form action="./php05.php" method="POST">
URL:<input type="text" name="url" size="20">
<input type="submit" value="memo">
</form>
<?php
if (isset($_POST['url'])){
$url=$_POST['url'] . "\n";
$fp = fopen("php05.dat", "a");
fwrite($fp, $url);
fclose($fp);
}
if (file_exists('./php05.dat')){
$fp = fopen("php05.dat", "r");
while ($line = fgets($fp)) {
echo "$line<br />";
}
fclose($fp);
}
else {
echo 'File not found.';
}
?>
```

まずはこの部分！

```php:
if (isset($_POST['url'])){
$url=$_POST['url'] . "\n";
$fp = fopen("php05.dat", "a");
fwrite($fp, $url);
fclose($fp);
}
```

訳：
urlという名前の値をもったら、出力。→変数urlとする。
fopenは「file open」の意味。php05.datというファイルを開く→変数fpとする
feriteは書く。つまり、ファイルに書いてけってこと！最後はファイルを閉じる。


次！

```php:
if (file_exists('./php05.dat')){
$fp = fopen("php05.dat", "r");
while ($line = fgets($fp)) {
echo "$line<br />";
}
fclose($fp);
}
else {
echo 'File not found.';
}
?>
```

訳：もしphp05.datがあって
書いてあったら、追加して書いてください。何も書いてなければfile not foundで。
ファイルにどんどんデータが追加されていく。php05.datは自動で作成されて自動でデータが更新されていくイメージ。

↓結果
![スクリーンショット 2020-12-15 11.50.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654246/70a58fa8-7b6c-0732-895f-d2a08ef1c447.png)
iOSのCoroutineについて(Async/Await)

## Abstract
現在iOSの非同期処理は一般的にGCDを使うのです、closure或いはdelegateでコールバックして、処理を追うんだが。関係性がある複数の非同期処理を実行する場合、コールバック地獄になる。

例えば、以下の画像処理のコードがある。

```swift

func fetchImage(url: String, completeHandler: @escaping (UIImage) -> ()) {
    ...
    completeHandler(image)
}
    
func imageDetectFace(image: UIImage, completeHandler: @escaping (UIImage) -> ()) {
    ...
    completeHandler(image)
}
    
func imageAddFilter(image: UIImage, completeHandler: @escaping (UIImage) -> ()) {
    ...
    completeHandler(image)
}
```

使う時は以下のようになる。

```swift

fetchImage(url: "hoge/url") { (originImage) in
    imageDetectFace(image: originImage) { (faceImage) in
        imageAddFilter(image: faceImage) { (filterImage) in
            imageView.image = filterImage
        }
    }
}
```
処理を増えると、可読性とメンテナンス性がどんどん下がる。

## Introduction

上記の問題の解決策として、RxSwiftとCombineなどのライブラリを使って、リアクティブプログラミングでコールバックを撲滅するのが一番多いですが。リアクティブプログラミングのデメリットとして、debugが大変なので。
今回はcoobjcというライブラリを使って、Coroutine風に非同期処理してみる。

### Coobjc
Coobjcは中国のアリババグループがOSSしたiOS用のCoroutineライブラリです。このライブラリはアセンブリとCで開発して、Objc-CとSwiftをサポートしている。このライブラリを通して、kotlin、JavaScriptやPythonなどみたいに、Coroutine風でプログラミングできる。
Github: https://github.com/alibaba/coobjc

## Usage

coobjcはAsync/AwiatとGeneratorとActorなどのCoroutine機能をサポートしている。今回はAsync/Awiatだけ使ってみる。

#### Async/Awiat
上記のコールバック地獄のコードを、Async/Awiatを使ってCoroutine風に書き直すと、↓になる。

```swift

func fetchImage(url: String) -> Promise<UIImage> {
    return Promise(on: DispatchQueue.global()) { (fullFill, reject) in
        fullFill(UIImage())
    }
}

func imageDetectFace(image: UIImage) -> Promise<UIImage> {
    return Promise(on: DispatchQueue.global()) { (fullFill, reject) in
        fullFill(UIImage())
    }
}

func imageAddFilter(image: UIImage) -> Promise<UIImage> {
    return Promise(on: DispatchQueue.global()) { (fullFill, reject) in
        fullFill(UIImage())
    }
}
```
使う時は以下のようになる。

```swift
co_launch(queue: DispatchQueue.main) {
    var image: UIImage = UIImage()
    let imgResult = try await(promise: self.fetchImage(url: "url"))
    if case .fulfilled(let fetchedImg) = imgResult {
        image = fetchedImg
    } else {
        return
    }
    
    let faceResult = try await(promise: self.imageDetectFace(image: image))
    if case .fulfilled(let faceImg) = faceResult {
        image = faceImg
    } else {
        return
    }
    
    let filterResult = try await(promise: self.imageAddFilter(image: image))
    if case .fulfilled(let filterImg) = filterResult {
        imageView.image = filterImg
    }
}

```
これで非同期処理が終わったらMainThreadに戻り、imageViewを更新する。GCDとコールバックもすっきりになりました。

## Conclusion
もしiOSで、Coroutine風にプログラミングしたい場合は、Coobjcが結構役に立てると思いますけど、プロジェクトへの侵入性がちょっと強くて、やめたい時は面倒になる。
MacOS Big Surアップグレード後VirtualboxのGUIが動かなくなった際の対処

# いきなり対処法（結論）から

下記を実行する。

1. VirtualBox（とそのExtension）をアンインストールする
2. MacOSをCmd + Rを押し続けながら再起動する（Recovery modeへ入ります）
3. Recovery modeでTerminalを開く
4. 下記のコマンドを実行する

```bash

csrutil clear
reboot
```

この後VirtualBoxをHomebrewなりインストーラを起動するなりでインストールする。
必要に応じてSecurity & PrivacyのGeneralタブからOracle Extensionを許可する。

# 経緯

MacOS Big SurでVirtualBoxが正常に動作しない問題は現在（2020年12月15日）[こちら](https://www.virtualbox.org/ticket/19795#)のチケットで進行中。
Qiitaでも色々な方が対処法を記載して頂いているようです。

- [MacOS Big SurにしたらVritualBoxとVagrantが動かなくなったので動かすまでやったこと！](https://qiita.com/syota_19910612bscplog/items/ee7e06cd23603fa529dd)
- [【macOSアップデート】vagrant upできない時に一通り試すと良いかもしれない方法](https://qiita.com/akane_kato/items/c103332729e3d0ac39e6)
- [Vagrant up でエラーが出た(macOSをBig Surにアップデートしたとき)](https://qiita.com/masa9436/items/81473c1008dfcb32b20f)

ただ私の環境だとこれらの対処法では解決せず、VagrantのBackendにVirtualBoxを使っている関係上
かなり困っていました。
4,5時間程度色々な対処法を検索しては試しを繰り返していたのですが、ようやく[こちら](https://forums.virtualbox.org/viewtopic.php?f=39&t=98763&sid=7541dfcace7a86fdb5bc8a281296ad94&start=75#p488555)の手順で解決できました。
どうにも許可設定周りがバグってる感じで、リセットしたくてVirtualBoxに付属のアンインストールスクリプトを実行したり再起動したりしていましたが、
いずれも解決には至りませんでした。

同様に困っている人の助けになれば幸いです。
GoogleのOCRを使って書籍をセルフ電子化する①

こんにちは。みなさん、英語の書籍を読むことはありますか。

フランス語の読解を先輩とやっていて、日本国内ではそんなに出回っていないテキストを二人で読もう、ということになりました。
著作権的に、いいのかかなり怪しいところだけれど、僕がもっているテキストを二人で読むために、Google Driveで共有することにしました。

画像でもいいんだけれど、なんかコメントとかできた方が便利かなと思って、テキストにしたい。と思ったときに、GoogleのOCRは便利やで〜という記事を見たので、使ってみるとあら便利。画像で保存したファイルを、右クリックして「Documentで開く」とするだけで、OCR（光学文字認識）してくれて文字にしてくれる。

しかも精度もほとんど間違いなし。頑張って手直しできる範囲です。

最初は一つ一つ画像を手でDocumentで開いていましたが、フォントを直したり、一枚のファイルにまとめたりするのに、やはりGASを使った方がいいのでは…？ということになり頑張って作ってみました。

```js:コード.gs
function main() {
  getFolder('myFolder'); // フォルダ名を入れます
}

function getFolder(name) {
  const folder = DriveApp.getFoldersByName(name).next().getFoldersByName('Images').next();
  const images = folder.getFiles();

  while(images.hasNext()) {
    const image = images.next();
    const resource = { title: image.getName(), mimeType: 'image/jpeg' };
    const blob = image.getBlob();
    
    // 画像ファイルをDocumentで開く
    const doc = Drive.Files.insert(resource, blob, { ocr: true });

    const destinationFolder = DriveApp.getFolderById("********************");
    DriveApp.getFileById(doc.id).moveTo(destinationFolder);
  }
}

function deleteImages() {
  const files = DriveApp.getFolderById("************").getFiles();
  while(files.hasNext()) {
    const file = files.next();
    const id = file.getId();
    const body = DocumentApp.openById(id).getBody();

    //　イメージを削除
    // body.getImages()[0].removeFromParent();
  }
}

/* Sets Font size and Font family */
function setTextStyle() {
  const files = DriveApp.getFolderById("************").getFiles();
  while(files.hasNext()) {
    const file = files.next();
    const id = file.getId();
    if(id == "************") {continue;}
    const body = DocumentApp.openById(id).getBody();

    const attributes = {};
    const attr = DocumentApp.Attribute;
    attributes[attr.FONT_FAMILY] = 'Calibri';
    attributes[attr.FONT_SIZE] = 13;
    body.setAttributes(attributes);
  }
}

function collectTextIntoOneFile() {
  const files = DriveApp.getFolderById("************").getFiles();
  const docs = [];
  while(files.hasNext()) {
    let file = files.next();
    let title = file.getName();
    let id = file.getId();
    if (title != "whole_text") { docs.push({ title: title, id: id }); }
  }
  
  // メモリ上のファイルを名前順に整理
  docs.sort(function(a, b) {
    let titleA = a.title.toUpperCase();
    let titleB = b.title.toUpperCase();
    
    if( titleA < titleB ) { return -1; }
    if( titleA > titleB ) { return  1; }

    return 0;
  })
  
  // 実行
  const destination = DocumentApp.openById('************');
  docs.forEach(function(doc) {
    const text = DocumentApp.openById(doc.id).getBody().getText();
    destination.getBody().appendParagraph(text);
  })
}

function props() {
  console.log(PropertiesService.getScriptProperties().getProperty('*****'))
}
```


## Step2. フォントサイズの確認

## Step3. Kindleに送信
ECR Public をDockerHubの代わりに使ってみた（DockerHubのDownload Rate Limit対策）

# あらまし

CodeBuildでDockerのビルド中にDockerHubにひっかかりました。AWSの新サービスECR Publicを使って簡単に回避できました。


# 事象

CodeBuildで`ubuntu` をbaseイメージとしたDockerコンテナをビルドしようとしたところ、以下のエラーが発生しました。

```
error pulling image configuration: toomanyrequests: Too Many Requests. Please see https://docs.docker.com/docker-hub/download-rate-limit/
```

# 調査

DockerHubが最近ダウンロード数に制限をかける事になった。ダウンロード数はグローバルIP/アカウント（ログインすれば）ごとに制限がかかるとの事。
クラスメソッドさんの記事が詳しい。
[“Too Many Requests.” でビルドが失敗する…。AWS CodeBuild で IP ガチャを回避するために Docker Hub ログインしよう！という話](https://dev.classmethod.jp/articles/codebuild-has-to-use-dockerhub-login-to-avoid-ip-gacha/)


# 対応

（DockerHubの認証めんどくさいな、、、、と思ってたところ）ちょうど、AWSがDockerHubの代替となるサービス `ECR Public`を提供し始めたので、こちらを利用する事にしました。

[［速報］AWS、Docker Hubの代替を狙う「Amazon Elastic Container Registry Public」提供開始。AWS re:Invent 2020](https://www.publickey1.jp/blog/20/awsdocker_hubamazon_elastic_container_registry_publicaws_reinvent_2021.html)
[AWSがDocker Hubの代替サービスを発表予告。パブリックにコンテナイメージを公開可能で50GBまで無料、AWSからなら何度でもプルし放題に](https://www.publickey1.jp/blog/20/awsdocker_hub50gbaws.html)

DockerHubに認証を入れるパターンと比較して、

- 簡単
- 無料枠の幅が大きい
- AWSサービスで使うならRateLimit気にしなくて良い

というメリットがあると判断しました。

[ECR Public](https://gallery.ecr.aws/)にアクセスすると、主要な公式イメージは登録されてる模様です。（全て確認したわけではないです）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32169/d72dfce8-3871-fae6-60f0-7dff4cc970d2.png)

ImageURIがあるので（tagの構成はDockerHubと同じ）、DockerFileのfromを書き換えるだけです。

```Docker
FROM public.ecr.aws/ubuntu/ubuntu:bionic
```

どうやらDockerHubと全く同じものがhostingされているらしく（同じhashでしたし、Dockerのcacheも効きました）、単純に書き換えるだけですんなり動きました。

nginxのDocker用リポジトリを見たら、[自動でECRPublicにpushするようなスクリプト](https://github.com/nginxinc/docker-nginx/blob/master/sync-awsecr.sh)がありました。


# まとめ

少し使ってみただけですが、公式イメージの取得元として、DockerHubの代替としてECR Publicは使えそうです。
特にAWS環境を使っている場合は、特に制限も無いので特に有用だと思われます。
【Docker】コンテナ作成までの操作#2

<h1>本投稿の目的</h1>

・Dockerの操作についての議事録です。

---
<h1>学習に使った教材</h1>
Udemyの ["米国AI開発者がゼロから教えるDocker講座"](https://www.udemy.com/course/aidocker/) を教材として使用しました。

---
<h1>○container作成 (2.image作成する場合)</h1>

<h3>○build contextの作成</h3>

```
mkdir <build context名>
```

・build context とは,docker image を作成する際のimage元となるフォルダ

<h3>○build contextへ移動</h3>

```
cd <build context名>
```

・カレントディレクトリが build context の状態にする

<h3>○Dockerfileの作成,編集</h3>

```
touch Dockerfile
```

・build context 内にDockerfileというテキストファイルを作成 (これは naming convention *命名規則)
・この中に書いたコマンド実行されてimageが作成される (編集方法は別途記事を書くので割愛)

<h3>○imageの作成</h3>

```
docker build .
```

・ "." はカレントディレクトリを意味する (カレントディレクトリうちのDockerfileを使てimage作成が実行される)
・名前とTAGを指定してないので "none" というimageが作成される
・dangling image とよばれる

**【Dockerfileを明示的に指定する場合】**

```
docker build -f docker -f <Dockerfileのpath/名前>
```

・-f はDockerfileを明示的に指定するためのオプション
・<Dockerfileのpath/名前> の部分には適切なpathとファイル名を記述する

**【名前とTAGを指定して作成する場合】**

```
docker build -t <image名>:<TAG> .
```

・-t は名前を付けてimageを作成するためのオプション
・<TAG> の部分は,通常はlatestと書く

<h3>○containerの作成</h3>

```
docker run <image名>
```

・作成したいcontainerの素となるimage名を指定してrunを実行
・#1で説明したとおり,これではデフォルトコマンドを実行後にexitしてcontainerから抜けてしまう

**【run後のデフォルトコマンドを上書きして実行】**

```
docker run <image名> <上書きコマンド>
```

・デフォルトコマンドの代わりに上書きコマンドを実行
・これでは上書きコマンドを実行後にexitしてcontainerから抜けてしまう
・デフォルトコマンドはrun実行後に docker ps -a のCommandから確認可能
・上書きするとここに指定したCommandが表示される

**【run後にcontainerに残るための記述】**

```
docker run -it <image名> bash
```

・これでcontainer起動後にexitせずにcontainerの中にとどまる
・そのため,ターミナルの実行前の記述が以下のように変化する

```
root@xxxxxxxxxxx:/#
```
・これはContainer上のOSにbashを通してアクセスする状態になったことを意味する
・デフォルトではコンテナ起動後はrootユーザーになる
・Continaerからexitで抜ける処理は実行されていない
・container から抜けるときは以下を実行するとHostのターミナル状態に戻る

```
exit
```

<h1>○-itとは?</h1>

```
docker run -it <image名> bash
```

・run後にcontainerに残るための記述に使用することが多いコマンド
・-iと-tを重ねて-it
・それぞれには以下の意味がある

**○-i**
・インプット可能
・HOSTからコンテナへのSTDIN(入力ch)を繋ぐコマンド
・繋がないとHostにしか入力が伝わらないため,コンテナへ指示が届かない

【chとは】
・ "STDIN" "STDOUT" "STDERR" の3つがある
・STDIN : キーボードの入力をプログラムへ繋ぐためのch
・STDOUT,STDERR : プログラム結果をモニタへ出力するためのch

**○-t**
・ターミナル表示が綺麗になる (pretyにする)
・コマンド保管も使用可能になる 

---
ELBでのHTTPSへのリダイレクト

AWSのロードバランサー(ELB)でHTTPからHTTPSにリダイレクトさせる実装をしたので、備忘録的にこの記事を残す。

# 作業

html直下の.htaccessに下記の記述を追加する。

```.htaccess
RewriteEngine On
RewriteCond %{HTTP:X-Forwarded-Proto} !https [NC]
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
```
ubuntuでreactの環境構築諦めた件

ubuntuでreactを使う。

プロジェクトディレクトリに移動して
```
npx create-react-app todoapp
```
を実行したら
```not foundram Files/nodejs/npx```と返ってきた。

恐らくubuntuにnode.jsを入れてないからである。

[このサイト](https://www.digitalocean.com/community/tutorials/how-to-install-node-js-on-ubuntu-20-04-ja)のステップ1の通りにいれた。

しかしまた同じエラーが返ってきた。

すいません。無理です。コマンドラインと仲良くなれません。
諦めました、、、(笑)
ノートPCを閉じた状態でリモート接続する方法

#はじめに
本記事ではノートPCを閉じた状態でリモート接続する方法を解説します。

#背景
ノートPCを閉じた状態ではリモート接続することが不可。そのため、ノートPCへのリモート接続方法は2つ。

 ■対応方法
　 ①ノートPCを開きっぱなしにする。
 　②外部モニターと連動させる。

①も②も場所を取って、結局すっきりしない感じ。なんかいい方法はないものかねと模索中、おっっっっっっっっっ！！これはいい解決策という商品が出ていたので紹介。

#解決方法
HDMIエミュレータを取り付ける。

HDMIエミュレータとは、ディスプレイ出力を偽装する物。
簡単に言えば、②の状態をモニター無しで作り出している状態。

うーん、、、、なかなか思いつかなかったけど、アイディア商品だなと関心。
サイズも1cm四方でかなり小さいので場所を取ることもありません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/599049/cadfa470-1d79-52c9-0880-6c5a4891ec34.png)

商品は下記URLに貼っておくので、ご参考に。

#他にもこんなメリット
 ・解像度の向上。
  　リモート先の端末の解像度が悪いと、画面がボヤけてしまう。
　　HDMIシミュレータで4K出力を偽造し、鮮明な画面を提供できる。

商品URL
www.amazon.co.jp/dp/B071D2N54Q
【個人アプリ作成】情報管理アプリ制作14日目

また、時間が空いてしまいました。。継続性の難しさを痛感します。
今日までやってきたことをまとめたいと思います。

#実装できてきたこと

>・マイページのレイアウト修正<br>・顧客データの要件定義<br>・顧客データ詳細画面<br>・ログイン画面の修正<br>・情報の取得<br>・プルダウンの実装


#マイページ

![スクリーンショット 2020-12-15 11.45.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/759485/13ed6741-132f-934b-8f0d-a246af8bdbd8.png)

少しヘッダーを整理してレイアウトをすっきりさせました。
今後はヘッダーのユーザーのところにJSで装飾を施したり、検索機能の実装を行う予定です。

今のところ、顧客情報は社名だけといった感じですが、かなり寂しいので「何の情報を開示できると有益なのか」をもう少し要件定義した方が良さそうです。
実装はruby on railsで、Seeds.rbにデータを入れて取得させています。


#顧客データ詳細画面

![スクリーンショット 2020-12-15 11.42.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/759485/cfdf8580-9c29-3526-ade3-3cb4d0fa6c4d.png)

基本情報の部分は一通り必要な情報を印字させて、先方関係者やグループ会社、トラブル・クレームは履歴データで持たせたいので、テーブルを分けアソシエーションで対応したいと思います。

まだ、顧客データの登録機能や、情報編集機能には着手できていないのでこれから実装していきたいと思います。


#これまでやってきた感想

かなり進捗が悪く、原因を追求してみました。

>・本業の仕事がかなり忙しい（いい意味で）。<br>→夜遅くなるのが日常茶飯事なので時間調整をして20時や21時にはこちらに着手できるようにする<br>・ある意味、色々やりすぎていた。特に実績もないのにPFを頑張って作ろうとしていたのはまずかった。今はアプリ開発とQiita、Githubに力を入れる。協業は随時進める。<br>・プライベートの慌ただしさ。<br>こればっかりは結婚だの同棲だの異動だので不可避なのでありきで考える。これまで考えられていなかった。

想定される工数の見積もりが甘いのとあらためて仕事は影響の出ない範囲で調整をかけていくようにしたい。
railsのArrayでnilと空白文字列の配列を除去して連結して表示する

色々なメソッドの結果を1つの文字列として出したかったが、メソッドの返り値には `nil` のケースと `""` のケースの2種類が存在していた。
railsのArrayの `#compact` は `nil` しか省いていくれない。
`reject` を使って省いた。

```
pry(main)> ["メソッドA", nil, "", "メソッドB", "メソッドC"].reject { |e| e.to_s.empty? }.join('、')
=> "メソッドA、メソッドB、メソッドC"
```
他人のノードを信頼する方法

**私が夢見るブロックチェーンが実装された社会、
それはSymbolがローンチされた、まだはるか向こう側にあります。**

Symbolをはじめ、NEMにはREST API機能が実装されています。同じようにAPI機能を提供する他のブロックチェーンもいくつかあるかもしれませんが、Symbolの提供するREST APIは、**街中に点在するATMや公衆電話のように、それを必要とする不特定多数が扱える**ように設計されています。

ところで、ブロックチェーンは改ざんに強い設計だと言われます。しかし、それはトランザクションの作成（署名）や実行についてのみです。**ブロックチェーン内に保存された情報の提供について、耐改ざん性を保証するものではありません。**

それを十分承知の上か、ブロックチェーンが保存する情報の提供については第三者（サードパーティ：例 infura社）に丸投げしているブロックチェーンもあります。NEMについても同じです。REST API機能がパワフルだったとしても**自分がノードだと思っていた情報取得先が実はただのスタティックにJSONテキストを応答するだけのサーバだった**というような、なりすましのハッキングが今後発生するかもしれません。

これを防ぐ手っ取り早い方法は「自分（検証者：Verifier）がノードを建てること」です。しかしこれでは、NEMがせっかくREST APIを提供していても、公衆電話のように不特定多数がアクセスできるメリットをあまり享受できません。他人のノードにアクセスしつつ、確実にデータを信頼する方法はないでしょうか？極論を言ってしまえば、ブロックチェーンがありふれた未来では**アクセス先のエンドポイントがノードであるかどうかを知る必要なく、提供されたデータを検証できる方法**が必要です。

残高の証明は少しややこしいので（~~まだ検証してない~~ 検証しました。[すべての人にマークルパトリシアツリーの力を](https://qiita.com/nem_takanobu/items/31ea4dfb6d8e38256e95)）、今回はブロックチェーンから取得したトランザクション情報の証明を考えてみることにします。トランザクションが誰によって署名されたかの検証は簡単です。しかし、これだけで済むような話ならそもそもブロックチェーンを使用せず電子署名で十分でしょう。ブロックチェーンを使うメリットは、その電子署名がブロックチェーンによって承認されたかものであるかどうか、つまり、**残高（余剰資産）やマルチシグなど様々な条件をクリアした署名であるかどうかが簡単に検証できる**点にあります。ですので、トランザクションがブロックに含まれていることを検証しなければいけません。これも実は簡単でマークルパスを用いることでトランザクションがブロックヘッダーに含まれていることを検証することができます。しかし、ここで安心してはいけません。**他人が提供したノードはブロックヘッダーまで偽造されている**可能性があるからです。ブロックの偽造といってもすべてが悪意のあるものではありません。フォークしたことに気が付かず、閉ざされた環境で自分は正しいとブロックを伸ばし続けているチェーンかもしれません。悪意のある偽造はすぐにばれるので、この思い込みの激しい分岐チェーンの場合を考えてみます。

この、分岐したチェーンも見る人によれば正しいチェーンです。ただ多数決すれば負けるというだけです。つまり、自分が評価したいトランザクションを含んだブロックが、ブロックチェーンに載っているかどうかというのは、みんながメインチェーンと評価しているブロックチェーンに乗っているかどうかということになります。その検証が成功すれば、そのトランザクションは**将来的にマージに負けて消えることも困難になりますし、今後新しく同期に参加してくるノードもすべて自分の記録を取り込んでくれる**ということになります。

では、メインチェーンとみなす方法ですが、残念ながら完璧な方法はありません。しかしながら、以下のような方法を取れば検証したいトランザクションがメインチェーン上にあると考えることができます。

- ルート（ジェネシスのような自明のブロック）から派生したチェーン上に存在していることを確認する
- ファイナライズされたブロックよりも以前のブロックに存在していることを確認する

前者は**誰もが自明に存在確認のできるジェネシスブロックから追える**メリットがありますが、それがメインチェーンである保証はありません。後者はファイナライズされたブロックからトランザクションの存在を確実に追うことができますが、**ファイナライズ情報は他の信頼できるノードから取得する**必要があります。この2つの検証の組み合わせや妥協点を探ることにより、情報取得先が厳密なブロックチェーンノードではなかったとしても、**ルートからトランザクションまでの明確な再現手順が上書きが不可能な状態で記録されている**ことが確認できます。

こんなことを考えながら、今年一年を過ごしていました。
来年もどうぞよろしくお願いします。
【Ruby】HTTPリクエストでJSONが返る外部APIを使う

# やりたいこと
HTTPリクエストをしてJSONが返る外部APIをRubyで使いたい。
JSONからRubyで使えるハッシュを取得したい。


#　結論
```ruby
#各種ライブラリを読み込む
require 'net/http'
require 'json'
require 'uri'

#uriライブラリ>URIモジュール
#該当するインスタンスを生成して返す
uri = URI.parse('http://hoge.com')
# => #<URI::HTTP http://hoge.com>

#net/httpライブラリ>Net::HTTPクラス
#URL先にGETリクエストを送り、そのボディを"文字列"として返す。
json = Net::HTTP.get(uri)

#josonライブラリ>JSONモジュール
#取得したJSON形式の文字列を、Rubyオブジェクトに変換して返す
JSON.parse(json)

```
以上で、URLにGETリクエストを送り、JSON形式のデータをRubyで使えるハッシュを取得できる。

### 公式リファレンス
[URIモジュール]("https://docs.ruby-lang.org/ja/latest/class/URI.html")
[Net::HTTPクラス]("https://docs.ruby-lang.org/ja/latest/class/Net=3a=3aHTTP.html#S_GET")
[JSONモジュール]("https://docs.rubylang.org/ja/latest/method/JSON/m/parse.html")



# JSONとは

>JavaScript Object Notation（JSON、ジェイソン）はデータ記述言語の1つである。軽量なテキストベースのデータ交換用フォーマットでありプログラミング言語を問わず利用できる[1]。名称と構文はJavaScriptにおけるオブジェクトの表記法に由来する。
https://ja.wikipedia.org/wiki/JavaScript_Object_Notation



>JavaScript だけではなく、Java, PHP, Ruby, Python など、様々な言語間のデータ交換、特に Ajax や REST API などで使用されています。
これまでは、共通データ定義言語として XML が利用されてきましたが、現在では、簡易的な JSON が利用されるケースが増えてきています。
http://www.tohoho-web.com/ex/json.html

異なる言語間でデータをやり取りするための記述形式で、記法はJavaScriptに由来する。
以前は、データをやり取りする時はXMLが使われおり、今はJSONが主流となっている。

###JSONのルール
キーと値にコロンがつく。
文字列は`""`ダブルクォーテーションで囲む。
`{ "hoge": "fuga" }`

シングルクォーテーションは使用できない。
❌`{ 'hoge': 'fuga' }`


カンマを使うことで、複数のキーと値を指定することができる
`{ "hoge": "fuga", "foo": 123 }`

配列や値のみでもOK！
`["hoge","fuga"]
"hoge"
123`

#まとめ
APIからJSONを取得し、Rubyで使うやり方とJSONについて、簡単にまとめました。