OmniAICreator/Qiita-1.07M huggingface dataset:
【JavaScript】非同期処理②　コールバック関数とチェーン


#はじめに

Udemyの[【JS】ガチで学びたい人のためのJavaScriptメカニズム](https://www.udemy.com/course/javascript-essence/)の講座の振り返りです。

前回の記事

https://qiita.com/nao0725/items/ae0646a4f22e9340533a

#目的

* 非同期処理についての理解を深める

#本題
###1. タスクキューとコールスタック

タスクキューとは**実行待ち**の非同期処理の行列
→　非同期処理の**実行順**を管理

キューの仕組みをFIFO（First in First out）「先入れ先出し」という

###2.コールバック関数と非同期処理

**前提**

```js
// 関数a,bを用意
function a() {
  setTimeout(function task1() { 
    console.log('task1 done');
  });

  console.log('fn a done');
}

function b() {
  console.log('fn b done');
}

a();

b();

// それぞれfn a done, fn b done, task1 doneの順で出力される
`````

関数ｂをtask1の後に実行されるようにする

```js
// aの関数の引数に関数bを入れる
function a(b) {
  setTimeout(function task1() { 
    console.log('task1 done');
    // ここで実行することでtask1の後に関数bが実行される
    b();
  });

  console.log('fn a done');
}

function b() {
  console.log('fn b done');
}

// ブラウザ上でも順序が入れ替わっている
a(b);

// b();
`````

###3.非同期処理のチェーン

複数の非同期処理をコールバック関数を用いて連続的に繋げて処理する

**前提**

````js
// コールバック関数を1秒間後に待機したあと実行される関数を定義
function sleep(callback){
  setTimeout(function() {
    console.log("hello");
    callback();
    // helloが呼ばれた後にcallback関数が実行される
  },1000)
}

sleep(function(){
  console.log("callback done!");
})
// 1病後にhelloとcallback doneが出力される
````

上記の処理を複数つなげるとどうなるか

````js
// 引数にvalを追加し、+1加算される形でコンソールで出力されるようにする
function sleep(callback,val){
  setTimeout(function() {
    console.log(val++);
    // callbackの引数としてvalを渡す
    callback(val);
  },1000)
}

// callbackの引数として渡しているのでここにもvalを渡す
sleep(function(val){
  console.log("callback done!");
  // valは0と出力される
}, 0)

//　sleepをさらにsleepの中で実行する
sleep(function(val){
  sleep(function(val){
    // このようにすることで1秒後に0, また1秒後に1と出力される
  }, val)
}, 0)

sleep(function(val){
  sleep(function(val){
    sleep(function(val){
      sleep(function(val){
        sleep(function(val){
            // 4まで出力される
        }, val)
      }, val)
    }, val)
  }, val)
}, 0)
`````

しかし、上記のようにするとコードの可読性が下がるので、Promiseというオブジェクトを使用する。



今日はここまで！

#参考にさせて頂いた記事

* [【JS】ガチで学びたい人のためのJavaScriptメカニズム](https://www.udemy.com/course/javascript-essence/)
* [Let'sプログラミング JavaScript入門](https://www.javadrive.jp/javascript/)
おすすめのJupyter拡張機能

# おすすめのJupyter拡張機能
## (前提) JupyterLabがインストール済みであること
- JupyterLabのインストール

```
$ pip3 install --upgrade --no-cache-dir 'jupyterlab~=3.0'
```

## おすすめのJupyter拡張機能
- JupyterLabのテーマ（背景デザイン）
    - Monokai++
    - インストール方法

      ```
      $ jupyter labextension install @hokyjack/jupyterlab-monokai-plus
      ```
![スクリーンショット 2021-11-17 8.15.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95700/4ea01fdc-124f-0c2a-ea5e-ab962f063c87.png)

- 目次（Table of contents）
    - toc
    - インストール方法

      ```
      $ jupyter labextension install @jupyterlab/toc
      ```
![スクリーンショット 2021-11-17 8.19.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95700/6e7b689f-9659-9230-807d-6c693fad0a6b.png)

- コード自動整形(black)
    - jupyterlab_code_formatter
    - インストール方法

      ```
      $ pip3 install --upgrade --no-cache-dir jupyterlab_code_formatter
      $ pip3 install --upgrade --no-cache-dir black
      $ pip3 install --upgrade --no-cache-dir isort
      $ jupyter labextension install @ryantam626/jupyterlab_code_formatter
      $ jupyter serverextension enable --py jupyterlab_code_formatter
      ```
![jupyterlab_code_formatter.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/95700/ef11eba5-4cac-9a5a-f446-5aa57db728e8.gif)
Colaboratory にて pandas DataFrame を動的にする

Colab において、pandas の DataFrame を動的操作可能なテーブルにレンダリングする。
以下のコードを Colab のセル上で実行すると、レンダリングに必要な拡張機能が有効化される。

```
# 動的にテーブル操作するための拡張機能の有効化
%load_ext google.colab.data_table
```

また、以下のコードで拡張機能を無効化できる。

```
# 動的テーブル操作拡張機能の無効化
%unload_ext google.colab.data_table
```
基本情報技術者試験に96点で合格した学習フロー


昔からIT系に疎かった私がIT化が進んでいく現代に取り残されないようにと学習を始めました。

ITパスポートを取得後、【基本情報技術者試験】合格を目指して取り組んだ私の学習フローや勉強時間を公開します！

これから試験を受ける方の励ましや参考になれば幸いです。

# 基本情報技術者試験の総学習時間

私は無事1回目の挑戦で合格することができました。
勉強開始から合格するまでの学習時間を全てメモアプリで管理していたので公開したいと思います。


:::note info
合計学習時間:448時間40分
:::

学習時間を全て合わせると448時間でした。
時間は2月の試験（コロナでずれました）に向けて前年の10月から学習を始めたので約5ヶ月間の期間がかかりました。

大体1日3〜5時間学習時間を確保することで5ヶ月で448時間に達することができました。

細かい詳細は以下の通りです。


:::note info
キタミ式：64時間6分
アルゴリズム：36時間52分
アセンブラ：69時間31分
過去問道場テスト：73時間16分
過去問道場(午前/午後)：184時間55分
:::

ITパスポートを取得していたとはいえ当時はプログラミングなどやったこともなく、知識ほぼゼロの状態だったので通常より多くの時間を費やしてしまった気がします。

学習時間がもっと短い人もたくさんいたので完全初心者が合格を目指した場合として参考にしてください。

## 学習フロー
学習の流れは大体以下の通りです。

1. 午前対策:キタミ式
1. 午前対策:過去問道場
1. 午後対策:アルゴリズム
1. 午後対策:アセンブラ
1. 午後対策:過去問道場
1. 午後対策:通しのテスト（過去問道場）


各対策のおすすめ参考書はこちらにまとめておきました。良ければ参考にしてください！
[【レビュー】基本情報技術者試験のおすすめ参考書！学習フローも一緒に大公開！](https://tech.amefure.com/web-fp-pass)

### 午前対策の流れと結果

最初に午前対策からはじめました。分厚い参考書を購入しひたすらノートにまとめ、ITパスポートの時にまとめたノートとリンクさせながら学習していきました。

次に隙間時間があればひたすら過去問道場を繰り返しました。常に正解率が90%くらいになるまでやり続けました。

過去問道場の午前にある問題はほとんど制覇した気がします。

試験の結果は【87.5点】でした。

![2450498B-D181-469C-81EB-160AA9D69CA3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2264957/d4d68f5a-bd31-dfb0-b61c-9aa3e7a6df40.png)

思ったより結果が悪く少し凹みましたが合格ライン（60点）は超えたのでとりあえず一安心しました。

### 午後対策の流れと結果

午後は必須科目である【データ構造及びアルゴリズム】をまず参考書を購入し、重点的に学習しました。

過去問道場だけでは理解出来なかったので参考書がないと少し厳しい分野だと思います。

しかし参考書さえこなせば満点が取れる分野だと思うので完璧に理解するまで学習することをおすすめします。

次に選択項目である【ソフトウェア開発】です。私は中でも【アセンブラ】を選択しました。

理由は3つ
1. 学習コストが低い
1. プログラミングの基礎になる
1. 他の言語が全て未経験

アセンブラも参考書を購入し学習しました。学習を始めてから楽しくなってきてしまい試験問題のプログラムの要件を問題を見ずに作れるようになろうと自作するのにハマってしまいました。

正直ここで時間を割きすぎてしまいましたが深い理解が得られたので良かったと思い込むことにします。

おかげでアセンブラは常に100点が取れるようになりました。

残りの科目は過去問道場のみで学習しました。
私の目的は合格というよりIT系に纏わることの理解なので全項目を満遍なく繰り返していきました。

アルゴリズムとアセンブラ以外は過去問道場様のお陰で合格ラインまで学習することができると思います。


試験の結果は【96点】でした。。
1問ミス…悔やまれますが合格したのでとても嬉しかったです。
![7323CC75-403A-407E-A5F9-4ECF9C0EFDA0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2264957/ee5ae5f7-d185-e909-2aef-ee07d10b5f9e.png)

# 最後に

私はプログラミング未経験、IT知識が乏しい状態から始めたので相当な時間を消費してしまいましたが逆にこれだけの時間を割けば確実に合格はできると思います。

難易度も高く、諦めたくなる時もありましたがゆっくり自分のペースで楽しみながら学習できると一番良いと思います。

試験頑張ってください。たまには休憩も大事ですよ！

ご覧いただきありがとうございました。

あめ
Railsで子モデルの所有数ランキングを取得するスコープの書き方

個人開発で必要になったのですが、どこにも書いておらず調べるのが大変だったので残しておきます。

```ruby:app/model/parent.rb
class Parent < ApplicationRecord
  has_many :children, dependent: :destroy
  scope :how_many_children, -> { joins(:children).group("parent.name").order(count_all: :desc).limit(3).count }
  # => {"親名"=>子テーブル所有数（一位）, "親名"=>子テーブル所有数（二位）, "親名"=>子テーブル所有数（三位）}
end
```

今思えば[これ（Railsガイド）](https://railsguides.jp/active_record_querying.html#%E3%82%B0%E3%83%AB%E3%83%BC%E3%83%97%E5%8C%96%E3%81%95%E3%82%8C%E3%81%9F%E9%A0%85%E7%9B%AE%E3%81%AE%E5%90%88%E8%A8%88)の応用だったので、そこまで我流のやり方ではないと思います。

自分の場合はBEST3で十分だったのですが、limitをつけなければ親全員のデータを取得できます。
Tensor Flow エラー    InvalidArgumentError:  required broadcastable shapes　解決 2021/11/17 

<h1> 本日のエラー「 InvalidArgumentError:  required broadcastable shapes」 
![Error.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/999291/127b58d3-6ef0-fcab-84db-6de4e1e66fc9.png)

本日に UNETのモデルを実行するとき、モデルのクラスを1から11まで増して、このエラーが引き起こされてしまう。原因は、Tensroflow
このエラーの原因は、私のデータを読み込む関数で、to_categoricalがなくて、tf_parseの入力サイズも違いました。

<h3>下記はエラーを引き起こされたコード</h3>

```python
def read_mask(path):
    path = path.decode()
    x = cv2.imread(path,cv2.IMREAD_GRAYSCALE)
    x = np.expand_dims(x, axis=-1)
    x = x.astype(np.double)
    
    return x
def tf_parse(x, y):
    def _parse(x, y):
        x = read_image(x)
        y = read_mask(y)
        return x, y

    x, y = tf.numpy_function(_parse, [x, y], [tf.float64, tf.float64])
    x.set_shape([256, 256, 3])
    y.set_shape([256, 256,1])
    
    return x, y
```
上記のコードは、複数のクラスの機能がないですね。マスクの画像を読み込むと、GRAYSCALEの画像の一のクラスを仮定されています。そして、tf_parseでは、マスクのyの変数のサイズは、カラスの次元は1に設定されています。複数のクラスを使用したい場合は、この点を更新しなければなりません。
<h3>改善したコード</h3>

```python 
from tensorflow.keras.utils import to_categorical
def read_mask(path,N_CLASSES=N_CLASSES):
    path = path.decode()
    x = cv2.imread(path,cv2.IMREAD_GRAYSCALE)
    x = np.expand_dims(x, axis=-1)
    x= to_categorical(x, num_classes=N_CLASSES) #カラス化
    x = x.astype(np.double)
    
    return x


def tf_parse(x, y,N_CLASSES=N_CLASSES):
    def _parse(x, y):
        x = read_image(x)
        y = read_mask(y)
        return x, y

    x, y = tf.numpy_function(_parse, [x, y], [tf.float64, tf.float64])
    x.set_shape([256, 256, 3])
    y.set_shape([256, 256,N_CLASSES])　#正しいカラス数により次元
    
    return x, y
```
一つの注意点は、「x = x.astype(np.double)」の部分は、 「to_categorical」の後で置いていなければなりません。逆の場合は、他のエラーを引き起こされます。
![Error2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/999291/f5e3bd95-f4cb-00fd-d156-eaa161500b07.png)
Xcodeでもcommand+enterで改行したい

# 概要
今回の記事はXcodeのショートカットに関するものです。
`command + enter`でVSCodeと同じような改行を実現します。
VSCodeで`command + enter`を同時に押すと、カーソルが行の途中にあっても新しい行の先頭にカーソルが移動すると思います。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551042/3eb553ee-6037-1e16-d1ed-e1380f71c682.gif" width="500" />

# 手順
1. Xcodeキーバインディングの設定ファイルを編集する
1. Xcodeの設定からキーを割り当てる

## 設定ファイルを編集する
設定ファイルは以下のパスにあります。

```
/Applications/Xcode.app/Contents/Frameworks/IDEKit.framework/Versions/A/Resources/IDETextKeyBindingSet.plist
```

このファイルを以下のように修正します。

```xml.plist
...
<!DOCTYPE ... 
<plist version="1.0">
<dict>
...
    <key>Custom Key Bindings</key>
    <dict>
      <key>insert new line(custom)</key>
      <string>moveToEndOfLine:, insertNewline:</string>
    </dict>
</dict>
</plist>
```

## キーを割り当てる
Xcodeの設定からキーを割り当てます。
**Preferences > Key Bindings** から確認できます。
![image2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551042/1b729007-7305-9d9a-6256-2de2f34357f2.png)

この画面で`command + enter`を設定します。
他のショートカットキーとコンフリクトする場合はどちらかを別のキーに設定しましょう。

# 参考リンク

https://diamantidis.github.io/2018/12/07/xcode-shortcuts-and-custom-key-bindings
【PowerQuery】形がバラバラのDBを１つのテーブルにまとめる

## まとめたい複数DB

拾いたい要素は共通なのに形がバラバラのDBを１つのテーブルにまとめたい。

パターンは以下の３つ

### パターンA
仕様が１行にまとまって、出力が横並びになったクロス表
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281933/ecfff0f3-9641-c012-6c38-da8230269a05.png)

### パターンB
パターンAと形は同じだが検索列の値が異なる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281933/cc22b2a1-6ed4-a944-01e7-0b051b082261.png)

### パターンC
出力ごとに表が分けられているパターン
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281933/2e9b58a0-d8ab-0b69-0fd3-46b6a8767b23.png)

## 結果

### クエリでまとめたテーブル
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281933/3cefd687-fbd4-d801-f9e7-575006a1606c.png)

### ピボットテーブルで再度集約したもの
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281933/1fff346a-61c4-89e5-e754-90130b8ddee7.png)

## 作り方
### クエリ集約用に別ブックを用意する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281933/ed5371f3-42c9-05e6-0bf2-988ad669b41e.png)

### クエリ編集

- 行の削除
- フィル
- 列の追加
- 列のピボット解除
- 複製(パターンCを上下に分割)
- クエリのマージ

などで整形していく
（ここの手順まとめるの後からやるとすごい面倒...進めながらまとめればよかった...）
Relaxtoolsの十字カーソルを外から呼べるようにする

## 概要

Relaxtoolsという超有名なアドインの中に「十字カーソル」という視覚支援機能があるが、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281933/7eb02a5c-0571-1228-023d-2ef178069fbf.png)

同アドイン内のカスタマイズ機能から登録できるのは設定機能orz...
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/281933/bc0668a8-5cbb-3343-7736-41e28707a9e3.png)

なのでこれをショートカットから呼び出したり他のマクロの（例えば検索結果を表示する）に付加できるようにした。


## 作り方

xmlを見てみるとリボンで呼んでいるプロシージャがこれだとわかったのでこれをアドイン外から呼べるようにする。

``` vb 
Sub lineOnAction(control As IRibbonControl, pressed As Boolean)
```

リボンを押すたびにOn/Offが切り替わる仕組みは細かくはわからないけど`pressed`の`True`/`False`で切り替えてるっぽい。

あとはリボンのボタンから呼び出す用のおまじない`control As IRibbonControl`をリボン外から呼ぶときにエラーになるので、同じ型の変数を用意して引数にぶち込む。（リボンを自作する場合はここを`Optional`つけるとかで回避できる）

あとはおまけで`ActiveCell.EntireColumn.AutoFit`を入れておけば巨大な表相手で列名が`###`となっていてもそこだけ読めるようになる。

## コード
### メイン
``` vb
Sub 十字カーソル表示(有効化 As Boolean, 列幅AutoFit As Boolean)
  If 列幅AutoFit = True Then: ActiveCell.EntireColumn.AutoFit
  ' Relaxtoolsアドイン必要
  Dim control As IRibbonControl
  Dim pressed As Boolean
  Application.Run "RelaxTools.xlam!lineOnAction", control, 有効化
End Sub

```

### 呼び出す側：OnOff切替個別
``` vb
Sub 十字カーソルOn()
  Call 十字カーソル表示(True,True)
End Sub

Sub 十字カーソルOff()
  Call 十字カーソル表示(False, False)
End Sub
```

### 呼び出す側：実行するたびにOnOff反転する
``` vb
Sub 十字カーソルOnOff()
  Static 状態 As Boolean
  If 状態 = True Then
    Call 十字カーソル表示Off
    状態 = False
  Else
    Call 十字カーソル表示On
    状態 = True
  End If
End Sub
```

## 参考
### 他ブックのマクロを実行する
`Application.Run "ブック名!Proc名",引数1,引数2,...`

https://excel-ubara.com/excelvba1/EXCELVBA427.html

### Relaxtools

https://software.opensquare.net/relaxtools/
STM32L010のPA9に32MHzを出力する HAL (VSCのcubeide)



目的
クロックのテスト


適当にコピー
main.h
stm32l0xx_hal_conf.h
stm32l0xx_it.h

ヘッダー


https://os.mbed.com/users/caa45040/code/f303_h_p1/



![o_con101.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/26005415-43db-a33f-51fa-a39c047fecc5.jpeg)




```c++




#include"main.h"

int main() {

    //37KHzのRC発振器を起動する。
    PWR->CR |= PWR_CR_DBP;    
    RCC->CSR |= RCC_CSR_LSION; //RCC->CSR=RCC->CSR | 1; //LSION SET

    //PA9にSYSCLKを出力
    __HAL_RCC_GPIOA_CLK_ENABLE();
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    GPIO_InitStruct.Pin = GPIO_PIN_9;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    GPIO_InitStruct.Alternate = GPIO_AF0_MCO;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    HAL_RCC_MCOConfig(RCC_MCO2, RCC_MCO1SOURCE_SYSCLK, RCC_MCODIV_1);
    //HAL_RCC_MCOConfig(RCC_MCO2, RCC_MCO1SOURCE_LSI, RCC_MCODIV_16); //約2KHz
    //HAL_RCC_MCOConfig(RCC_MCO2, RCC_MCO1SOURCE_LSI, RCC_MCODIV_1);


        //32MHz
        __HAL_RCC_HSI_CONFIG(  (uint32_t)1  );
        __HAL_RCC_PLL_CONFIG(RCC_PLLSOURCE_HSI,
                             RCC_PLLMUL_4,
                             RCC_PLLDIV_2);
        __HAL_RCC_PLL_ENABLE();
        __HAL_RCC_SYSCLK_CONFIG(RCC_SYSCLKSOURCE_PLLCLK);


  //16MHz
  //__HAL_RCC_HSI_CONFIG(  (uint32_t)1  );
  //__HAL_RCC_SYSCLK_CONFIG(RCC_SYSCLKSOURCE_HSI);

  //4MHz
  //__HAL_RCC_MSI_RANGE_CONFIG(RCC_MSIRANGE_6);

}



```
Raspberry Pi のサーバーとしての活用について

国連ベクトルタイルツールキットのコンテキストで、Raspberry Pi のサーバーとしての活用について検討することがありますが、一般的な観測について共有すると、次の通り。

1. インターネットに接続するサーバーとして用いる場合にも、組織の正規のネットワークの公開セグメントに接続して用いるユースケースと、ワークフロムホーム環境を含むよりオープンなネットワークから用いるユースケースは区別して考える価値がある。おそらく後者の方が、現代のコンテキストにおいては魅力的であるように思える。
1. オフライン環境での使用については、まずオフライン環境のユースケースについてよく知る必要がある。なぜなら、我々の日常生活は常時オンラインの環境である場合が多いからである。
1. ローカルネットワークについても上記段落と同様で、ユースケースをよく知る必要がある。なお、最近、特に　Google Chrome のコンテキストで、ローカルネットワークとグローバルネットワークを混ぜて使うことを抑制する施策がとられている。ローカルネットワークを活用する場合、背景地図も含めてすべてをそのサーバでホストする提案をした方が、サービスの長期安定稼働を図れる可能性がある。
1. オフライン環境やローカルネットワークと HTTPS の関係はかなり悪いと考えたほうが話が早い。HTTPS を使えないと HTTP/2 の恩恵を享受できない。この点でも、インターネットへのアクセスを前提とできるネットワークと、ネームサーバー1つのコントロールを確保していることを仮定した問題設定の方が、性能を出しやすいだろう。この問題設定のもとで、しかしサーバーはローカルネットワークにぶら下げるというコンフィギュレーションは、安価に適切な情報管理を実現できる可能性が高いという意味で、魅力的である。
1. ラップトップPCを WiFi アクセスポイントにする方法は、その PC を使いにくくする、あるいはその PC の環境を汚すことになる。Raspberry Pi を WiFi ポイントにする方法の方が、より優れる可能性がある。
1. Raspberry Pi と端末とを Ethernet ケーブルで直接接続するユースケースは魅力的である。この場合、原理的に、接続は HTTPS ではなくて HTTP で十分である。
1. インターネットをカジュアルに活用するが、外部向けという訳ではない、というユースケースを掘り下げることも考えるべきである。この場合、認証ということをより深く考えることになる。
Error: No such file or directory @ rb_sysopen 

### 問題点
```terminal
rails server
```
でサーバーを起動すると下記のようなエラーが表示される。

```terminal
/Users/user/Github/sample_app/vendor/bundle/ruby/2.7.0/gems/webpacker-4.0.7/lib/webpacker/configuration.rb:91:in `rescue in load': Webpacker configuration file not found /Users/user/Github/sample_app/config/webpacker.yml. Please run rails webpacker:install Error: No such file or directory @ rb_sysopen - /Users/user/Github/sample_app/config/webpacker.yml (RuntimeError)
```

### 解決方法
エラー文にも載っているように

```terminal
rails webpacker:install
```

をターミナルで実行すると直る。
GASでQiitaOrganizationメンバーの新規投稿を自動で拾いChatworkに通知する

所属メンバーの投稿をチャットワークに通知するGASを以下を参考に作りました。

[GASでQiitaOrganizationメンバーの新規投稿を自動で拾いChatworkに通知する](https://qiita.com/yasuoyasuo/items/75273bf60b896c634ec2)

## RSSを追記していくスプレッドシート準備

1. Google　spreadsheetsを作成する(名前はなんでもいいです）
2. 以下をセルに設定する
3. シート名を任意の名前にする（今回はテストとしています）
3. ツール > スクリプトエディタ をクリック

|セルA1  |セルB1  |セルA3  |
|---|---|---|
|https://qiita.com/organizations/自身の組織名/activities.atom  |=A1&"?d="&C1  |=importfeed(A1, "items", false, 20)  |

## GASスクリプトを作成

ロジックをそのまま流用させていただきました。

```js
function InformNewcontets() {
  var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = spreadsheet.getSheetByName("テスト"); // 任意のシート名に変更してください

  //公開されているRSS情報を読み込む
  var response = UrlFetchApp.fetch('https://qiita.com/organizations/xxx/activities.atom');
  var xml = XmlService.parse(response.getContentText());
  var atom = XmlService.getNamespace('http://www.w3.org/2005/Atom');
  var entries = xml.getRootElement().getChildren("entry", atom);

  //最新が下にくるように
  entries.reverse();

  const FValues = sheet.getRange('D:D').getValues();
  const LastRow = FValues.filter(String).length;
  var LastPublished = sheet.getRange('C1').getValue();

  var count = 0;

  for (var i = 0; i < entries.length; i++) {
    var published = new Date(entries[i].getChild('published', atom).getValue());

    //取得したRSS情報の更新日時と、最終行の更新日時（LastPublished）と比較して新しいもののみ追加する
    if (published > LastPublished) {
      count = count + 1;
      sheet.getRange('C1').setValue(new Date());

      //最終行の下に追加する
      sheet.getRange(LastRow + count, 1).setValue(entries[i].getChild('title', atom).getValue());
      sheet.getRange(LastRow + count, 2).setValue(entries[i].getChild('link', atom).getAttribute('href').getValue());
      sheet.getRange(LastRow + count, 3).setValue(entries[i].getChild('author', atom).getChild('name', atom).getValue());
      sheet.getRange(LastRow + count, 4).setValue(Utilities.formatDate(published, "JST", "yyyy/MM/dd HH:mm:ss"));

      //チャットワークに投稿する
      var body = entries[i].getChild('title', atom).getValue() + '\n' + entries[i].getChild('link', atom).getAttribute('href').getValue();
      //メッセージは良い感じに！
      requestToChatwork("Qiitaエントリがありました！みんなで応援しましょう！ (clap)", body);
    }
  }

}

// chatworkにリクエストを送る
function requestToChatwork(subject, body) {
  if (!body) return false;


  var token = 'xxxxx';
  var roomId = xxxxx;
  var body = '[info][title]' + subject + '[/title]' + body + '[/info]';
  var payload = {
    'body': body
  }
  var headers = {
    'X-ChatWorkToken': token
  }
  var options = {
    'method': 'POST',
    'payload': payload,
    'headers': headers
  }
  var url = 'https://api.chatwork.com/v2/rooms/' + roomId + '/messages';
  UrlFetchApp.fetch(url, options);
}
```

## 実行してみる
1. InformNewcontetsを実行する
1. requestToChatworkを実行する
1. 指定したルームIDに対して通知が送られます(最新の投稿がない場合は通知をスキップします）

お好みでトリガーを設定して指定時間に通知されるようにしてみてください！
![スクリーンショット 2021-11-17 4.22.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555632/e8aaaff0-172a-12a7-2bad-f40716c3f636.png)


## 最後に

読んでいただきありがとうございます。今回の記事はいかがでしたか？
・こういう記事が読みたい
・こういうところが良かった
・こうした方が良いのではないか
などなど、率直なご意見を募集しております。
TypeScriptで定数オブジェクトを使いまわす方法

共通で使用する定数を読み取り専用・データ型として使い回したかったので作ってみました

```ts
export const HTTP_STATUS_CODES = {
  OK: 200,
  CREATED: 201,
  UNAUTHORIZED: 401,
  FORBIDDEN: 403,
  NOT_FOUND: 404,
  BAD_REQUEST: 400,
}
```

## やりかた

```ts
export const HTTP_STATUS_CODES = {
  OK: 200,
  CREATED: 201,
  UNAUTHORIZED: 401,
  FORBIDDEN: 403,
  NOT_FOUND: 404,
  BAD_REQUEST: 400,
} as const

export type HttpStatus =
  typeof HTTP_STATUS_CODES[keyof typeof HTTP_STATUS_CODES]
```

## 説明

### as constとは
> オブジェクトリテラルの末尾にas constを記述すればプロパティがreadonlyでリテラルタイプで指定した物と同等の扱いになります。

[constアサーション「as const」 (const assertion)](https://book.yyts.org/reference/values-types-variables/const-assertion)

例えば、定数オブジェクトの値を変更しようとすると、読み取り専用だから書き換えできないよ！！って怒ってくれます

constは言わずもがな、再代入、再宣言不可の概念通りの実装になるので、思わぬバグを防げます。


```ts
HTTP_STATUS_CODES.OK = 204
// Cannot assign to 'OK' because it is a read-only property.
```
![スクリーンショット 2021-11-17 3.41.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/555632/1344e8b7-56ac-e219-bdfa-1393cae6c98a.png)

### export typeとは
> オブジェクトの型を取得します

### typeof とは
> オブジェクトからデータ型を生成します

```ts
typeof HTTP_STATUS_CODES

/*
  OK: number,
  CREATED: number,
  UNAUTHORIZED: number,
  FORBIDDEN: number,
  NOT_FOUND: number,
  BAD_REQUEST: number,
*/
```

### key ofとは
> 型のプロパティ名のUnion型で返します

```ts
type HttpStatus = 200 | 201 | 401 | 403 | 404 | 400
```

### keyof typeof

> T[K]はindexed access types、またはlookup typesと呼ばれ、オブジェクトのプロパティにアクセスするような記法でプロパティの型を取得できます。

超わかりやすい！
[[Typescripttypeof] "object value" [keyof typeof "object value"] の動作を丁寧に解説してみる](https://qiita.com/saba_can00/items/bdefb28a1873658cf5d9)


HttpStatus型に存在しない値は代入することができなくなりました！

```ts
// BAD 型 '1' を型 'HttpStatus' に割り当てることはできません。ts(2322)
const hoge: HttpStatus = 1

// OK
const hoge: HttpStatus = HTTP_STATUS_CODES.BAD_REQUEST
```
「あれ？薬飲んだっけ？あ、飲んでないや！」を撲滅！IFTTTを使ってLINEにお知らせ！

##命の次に大事なもの。それは髪。

最近言われて嬉しい言葉ランキング第1位：**あれっ？髪増えた？**
最近言われてムカつく言葉ランキング第1位：**あれっ？髪減った？**

はい、そういう悩みがあります（察してくださいませ）。

AGAってやつですね。男性型脱毛症というやつですね(:_;)
三十代半ばにして気になり始めています。。。

そんな訳で、今年の春からAGAの薬を飲み始めました。
継続は力なりという言葉がありますが、継続して薬を飲むことで髪の未来が決まるらしいです。
1日でも飲み忘れたら一からやり直しと脅されています。

が、今まで薬を飲み続けるという習慣がない私には、**飲み忘れがハゲしくあります！**

ふっさふさの方にはわからない悩みかと思いますが、飲んだっけ？飲んでないや！と出先で思い出した時は、家に帰るまでそわそわしています。

そんな時に、IFTTTに出会いました。

https://ifttt.com/home
>IFTTTは、ソーシャルメディアやプラットフォームを連携させるためのWebサービスです。「IFTTT」は、「If This Then That」の頭文字で、直訳すると「もし●●をしたら、▲▲をする」という意味になります。IFTTTを使うと、あるツールで特定の動作をしたときに、別のツールで付随した動作を自動的に行うよう設定できます。
出典：[IFTTT（イフト）とは？Webサービス・SNSを連携させる便利ツール](https://yourclip.life/post/about-ifttt/)

##毎日8時半にLINEに通知
飲み忘れを防ぐことができるように、IFTTTを使って**Date & Time**と**LINE**を繋いでみました。
毎朝8時半に薬を飲んだか確認のLINEが届きます。

朝起きたら風呂に入って目を覚まして、スマホで音楽を流しながら家を出る準備をします。
音楽をかける時にスマホをいじるので**LINEが届いていれば確認できて、薬の飲み忘れを防ぐ魂胆**です。

<font color="red">**手を煩わすことなく、朝のルーティーンに組み込めるって凄い！**</font>


<img width="500" alt="薬飲んだ？" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2049267/dd9b3d6c-92aa-a910-7b6e-a7a77e7cec3f.png">

##ノーコードだからパパっと作成
IFTTTの何が凄いって、コードを書かずに<font color="red">**ノーコードで繋ぎ込みができること**</font>ですね。
慣れれば数分あれば繋ぎ込みが出来ちゃいます！

プログラミングを習い始めて1か月半のエラーと戦う日々の私には、ほんと感動ものです！


<img width="300" alt="薬飲んだ？" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2049267/d830b67c-5d88-0ab5-d902-65f678c836ac.png">

:::note info
①トリガーの設定
：トリガーとは連携の起点となる、ユーザーの動作のこと。画像の「If」にあたる部分です。
：Date & Timeを使って、毎日8時半に設定しました。

②アクションの設定
：アクションとは①トリガーによってIFTTTが自動的に行う動作のこと。画像の「Then」にあたる部分です。
：LINEに通知するという設定の部分です。

③アプレット
：アプレットはトリガーとアクションを組み合わせたもの。アプレットを作成することでサービス同士の連携が可能になります。
：毎朝8時半に、LINEに通知できるようになります。
:::


<img width="300" alt="薬飲んだ？" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2049267/84637a1c-c962-ec13-0ec0-c5040e7349d8.png">
トリガーになる時間は簡単に変更できます。

<img width="300" alt="薬飲んだ？" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2049267/b39d879c-fef8-d125-fc48-32d14a82c666.png">
通知されるテキストメッセージや画像の設定も簡単にできました。

##会社の後輩に見せびらかせてみた
こんなこと出来るようになったぜー！と自慢しに行くついでにフィードバックをもらいました。
ビックリするくらい食いついてきて、その場でやり方を教えることになりました笑

**これまさに今欲しかったものなんです。**

これが後輩君からの最初の言葉でした。
話を聞くと、最近父親の体調が優れず、薬を数種類処方されたそうです。
朝昼晩のものや朝晩のものやら色々で飲み忘れがあるようです。だからピッタリだと。

更に話を聞くと、**そもそも薬って字が小さくて見づらいし、馴染みのない長いカタカナ名が多くて覚えられない**といった悩みが発覚しました。

た、たしかに。。。

##改善点
自分にとっては飲み忘れを防ぐためのものなので、LINEに通知さえくれば事足りるものでした。

後輩君のお父さんに役立つものにするには、
飲み忘れ防止のために通知が来ることの他に、**小さい字や薬の名前を覚えなくても飲む薬がわかること**が必要でした。

教えながら作った後輩君のプロダクトには、LINEに通知が来る際に**薬の画像も一緒に通知される**ようにしました。
これで字が小さくても薬の名前を覚えていなくても<font color="red">**視覚**</font>で判断できるようになりました。

後輩君のパソコンで作成した画像を撮り忘れてしまったので、私が作成したものに画像も取り込みました。

##IFTTTを使ってみて
まずは、**ノーコードでツールとツールを繋ぐことが出来ることに感動！！**

そして、フィードバックをもらいに行った**後輩君から話をもらうことで、思いがけない役立ち方を発見**しました。
私の中だと軽い気持ちで作ったものが、感謝されるほどのものになりました。

嬉しい気持ちと自分で思いつかなかった悔しさとが混在しますが、**人に話すことによって新たな発見があるってことを発見出来たことは良かった点**でした！

こうやってプロダクトは成長していくんだ！と改めてハゲしく感じました。
ルーティングの優先度と正規表現　～真犯人は上にいる～

#目次
[1.ルーティングの優先度](#1-ルーティングの優先度)
[2.上に書かれた設定が優先的に実行される](#2-上に書かれた設定が優先的に実行される)
[3.真犯人はもっと上にいる](#3-真犯人はもっと上にいる)
[4.と見せかけて](#4-と見せかけて)

#1. ルーティングの優先度

ブログアプリを作っていく中で一つ躓いた部分があったので備忘録として残しておきます。
``web.php``でブログに関するルーティングを書いていました。

```php:routes\web.php
<?php

use Illuminate\Support\Facades\Route;

//ブログ一覧画面を表示
Route::get('/','App\Http\Controllers\BlogController@showList')->name('blogs');

//ブログ詳細画面を表示
Route::get('/blog/{id}','App\Http\Controllers\BlogController@showDetail')->name('show');

//ブログ投稿画面を表示
Route::get('/blog/create','App\Http\Controllers\BlogController@showCreate')->name('create');

//ブログ投稿
Route::post('/blog/store','App\Http\Controllers\BlogController@exeStore')->name('store');

```

ブログ一覧画面～ブログ投稿まで、追加した順にそのままコードを書いていましたが、
ブログ投稿画面を表示する ``/blog/create`` にアクセスしたところエラーが。。。
しかもそのエラー内容が、**「データがありません。」**
これは、ブログ詳細画面の ``/blog/{id}`` にアクセスしたときに、対応するブログIDがない時に出るエラーのはず。
なぜブログ投稿画面でこのエラーが出るのか。

#2. 上に書かれた設定が優先的に実行される

調べてみたところ、Laravelのルーティング設定には、**上に書かれた設定が優先的に実行される**というルールがあるらしい。
ただ僕はこれを知っても、
**「うん、それとブログ詳細画面のエラーが出ることに何の関係があるの？」**と理解できませんでした。
上に書かれた設定が優先されるだけで、順番が来たら``/blog/create``にもアクセスされるんじゃないの？と思っていました。
ただそうではなく、``/blog/create``より先に他のルーティングに反応したら、そのままそこにアクセスされて終わりなのです。

#3. 真犯人はもっと上にいる

じゃあ``/blog/create``より先に反応しているルーティングがあるはず！それはどれだ！
はい、それがブログ詳細画面を表示する``/blog/{id}``なのです。
この``{id}``の部分に``create``が代入されて、``/blog/{create}``として反応していたのです！
そしてそのままコントローラに連れていかれ、
**``{create}``というIDのブログはないよ！エラー！**
ということで先ほどの**「データがありません。」**が表示されたのです。

なるほど～！
コードなんて多少順番が違くても表示されるものは同じ！と思っていましたが大間違い！
ということで憎き詳細画面ルーティングは一番下に置いてやりました。
もう悪さするんじゃないぞ！！！


```php:routes\web.php
<?php

use Illuminate\Support\Facades\Route;

//ブログ一覧画面を表示
Route::get('/','App\Http\Controllers\BlogController@showList')->name('blogs');

//ブログ投稿画面を表示
Route::get('/blog/create','App\Http\Controllers\BlogController@showCreate')->name('create');

//ブログ投稿
Route::post('/blog/store','App\Http\Controllers\BlogController@exeStore')->name('store');

//ブログ詳細画面を表示
Route::get('/blog/{id}','App\Http\Controllers\BlogController@showDetail')->name('show');

```

#4. と見せかけて。

ただ順番を変えるという強引なやり方では、いずれルーティングが増えてきたときに限界が来るかもしれません。
そんなときのために、正規表現という方法も紹介しておきます。

```php
//ブログ詳細画面を表示
Route::get('/blog/{id}','App\Http\Controllers\BlogController@showDetail')->where('id', '[0-9]+')->name('show'); 
```


``where('id', '[0-9]+')``を追加するだけで、**IDは0~9の数字で1文字以上**という制約がかかります。
こうすれば、先ほどのような{create}が入ってきもスルーしてくれるので順番を気にする必要がなくなりますね！

プラスで、対応するコントローラの引数も ``$id`` -> ``int $id``に変えてあげると親切ですね！
テキストのグラデーションを保ちつつ縁取りするCSS

とある事情で時計ウィジェットを作っていて
テキストにグラデーションをかけつつ、テキストの縁取りをする必要が出た。
`text-shadow`で解決できず悩んだが、なんとか解決したので書いておく。

<p class="codepen" data-height="300" data-theme-id="dark" data-default-tab="html,result" data-slug-hash="jOLXPdp" data-user="mafumafuultu" style="height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/mafumafuultu/pen/jOLXPdp">
  text gradation  &amp; Text borders</a> by mafumafuultu (<a href="https://codepen.io/mafumafuultu">@mafumafuultu</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

結論から言えば `text-stroke`の使い方で解決した。

疑似要素側の`text-stroke`を`0`
要素側`text-stroke`を任意の太さにする。

疑似要素側が要素の上に重なるので、
本来であればテキストの内側にも食い込んでくるstrokeを疑似要素側のstrokeのないグラデーションのテキストを使って隠している。
React（Next.js/GraphQL）からHasuraを使ったCRUD操作 〜CRUDのU（Update）について〜

## はじめに

React（Next.js/GraphQL）からHasuraを使ったCRUD操作を何回かに分けて見ていきます。

今回は、CRUDのU（Update）について見ていきます。

## 最終的なゴール

以下のような構成のアプリを作ることです。

![スクリーンショット 2021-10-18 17.27.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14191/e8a9a2e1-2723-4fec-77ef-be3b9eefdd81.png)

### 目的

- 仕事で使っている技術のキャッチアップと復習
- 使う可能性がある技術の理解度向上

## ベースとなる記事のリンク

この記事は以下の記事がベースとなっております。

全体のコードなどはそちらに記載があります。

詳細👇

https://qiita.com/ryosuketter/items/d9106135dd81bee3c038

## Updateに関するカスタムフック

使う関数は`useMutation`です。というか、`R`以外は、`useMutation`と思っても良いかも。

```tsx:pages/hasura-crud.tsx
const [update_users_by_pk] = useMutation<UpdateUserMutation>(UPDATE_USER)
```

`useMutation`関数を使って引数`UPDATE_USER`コマンドを実行しているとわかります。

ジェネリクスしてる型は`./types/generated/graphql`から来た`UpdateUserMutation`ですね。

型定義はこんな感じ。

```ts
export type UpdateUserMutation = {
  __typename?: 'mutation_root'
  update_users_by_pk?:
    | { __typename?: 'users'; id: any; name: string; created_at: any }
    | null
    | undefined
}
```

返り値は、以下ですね。

```ts
[update_users_by_pk]
```

### キャッシュ更新部分

Updateの場合は、Apolloがキャッシュ内の各オブジェクトの __typename と id を見て、レスポンスの内容と一致するものを自動で更新してくれます。

`UPDATE_USER`の中身を見ると、

```ts:queries/queries.ts
export const UPDATE_USER = gql`
  mutation UpdateUser($id: uuid!, $name: String!) {
    update_users_by_pk(pk_columns: { id: $id }, _set: { name: $name }) {
      id
      name
      created_at
    }
  }
`
```

戻り値が以下であるとわかります。

```
id
name
created_at
```

帰ってくる時のフィールド名が`update_users_by_pk`という名前で1つのユーザー情報が返ってきます。

#### ユーザーの更新

試しに、ユーザーを更新します。

まずは、Hasura側を見てみます。

![スクリーンショット 2021-11-17 0.48.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14191/b4ece67b-0cd2-5cea-d8a1-d363a10ee4fc.png)

続いてWebの方で更新します。

![ecfb117ef48e607115cbec1ed3fc64fe (1).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14191/a98530fd-e2c8-ce77-8296-6b3aeff160f5.gif)

Hasuraからも削除できたことがわかります。

![スクリーンショット 2021-11-17 0.51.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14191/50eaf08f-5a70-4792-0a65-e74c0f7a8397.png)


Networkみると、以下のようなJsonデータが、GraphQlに送られていたことがわかります。

```json

{
    "operationName": "UpdateUser",
    "variables": {
        "id": "f6a27de5-2f26-4e14-8435-bc463aabe791",
        "name": "Paul"
    },
    "query": "mutation UpdateUser($id: uuid!, $name: String!) {\n  update_users_by_pk(pk_columns: {id: $id}, _set: {name: $name}) {\n    id\n    name\n    created_at\n    __typename\n  }\n}\n"
}

```

CRUDのUの流れはこんな感じです。

今日のところは以上です。

次回以降で、他の処理も見てきます。ありがとうございました。

## 参考

https://tech.mof-mof.co.jp/blog/apollo-with-cache-intro/

## アウトプット100本ノック実施中

https://qiita.com/ryosuketter/items/713474dbd009870e4103
GoogleDomainを使ってGoogle Compute Engine (GCE)の独自ドメインを設定

今回は、GoogleDomainで取得したドメインを、Google Compute Engine（以下GCE）の独自ドメインとして設定する方法をまとめました。（メモ程度です。）

## 準備するもの
### GCPへの登録   
まず、GoogleCloudPlatformに登録をしましょう。
[GoogleCloudのサイトへ](https://cloud.google.com/)
![GoogleCludHome.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1024959/256576a9-e87e-5182-4416-412513cae21b.jpeg)

個人の利用でも、90日間$300分の無料トライアル期間を試せるので、その期間だけは無料で利用することができます。

### Google Compute Engineの作成
GCPに登録をしたら、GCEを作成し、外部IPの割り当てを行ってください。
GCEで外部IPの割り当てができたかどうかは、
「 __VPCネットワーク__ 」の「 __外部IPアドレス__ 」から確認することができます。
そして、この外部IPアドレスは後ほど利用するので、メモを取っておいてください。
![externalIP.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1024959/c94f597d-6857-2d8c-95d3-04fad085a8fa.jpeg)

## Google Domainでドメインの取得方法
### GoogleDomainの登録
以下のサイトから、GoogleDomainの登録を行ってください。
[GoogleDomainへ](https://domains.google/intl/ja_jp/)
![GoogleDomain_HOME.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1024959/a6e3db25-7daa-17bf-3aa9-f0cadd03f7b0.png)


### ドメインの取得
HOME画面より、新しいドメインを取得をクリックします。
![GoogleDomain1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1024959/e0009839-7f8a-15fb-d9b7-2de12b1cc18b.png)

その後、取得したいドメインを検索します。  
今回は、「exsample-sample.com」というドメインを検索してみます。
![GoogleDomain2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1024959/c4762e16-79b7-27cb-21ba-8780a6f9bd54.png)


検索すると以下のような画面が表示されます。  
検索結果には、利用可能な末尾や料金などが表示されます。
![GoogleDomain3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1024959/a27e7699-f722-9fa5-f282-1f34ebe695df.png)

表示内容で良ければ、カートに入れて購入手続きを行います。
![GoogleDomain5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1024959/a6dc2050-fed3-f31c-e815-d8ebbcc4b35f.png)


購入後、HOME画面以下のような画面に切り替わります。
![GoogleDomain.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1024959/474a7e0f-4fca-1aaf-bf64-856cd057cef4.png)

GoogleDomainの独自ドメインの取得は以上です。  
次にGCPの設定に移ります。


## Google Compute Engineで外部ドメインの割り当て
### Cloud DNSの設定
まず、GCPのHOME画面の左のメニューバーより、 **ネットワークサービス** を選択し、 **Cloud DNSを**クリックします。
![CloudDNS1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1024959/e08e9c1a-24db-1704-0031-217623467b7a.png)

そして新たにゾーンを作成します。
![CloudDNS2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1024959/5d7ec0fc-0aa9-ddd5-8093-622633b40a1a.png)

ゾーンが作成し終わったら、以下のような画面が表示されるはずです。このとき、NSに４つほどルーティングポリシーが表示されていると思います。![CloudDNS４.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1024959/faf4f286-d5b6-9392-fe6f-42b8528c8787.png)


### レコードセットを追加
ここで、先ほど、メモした外部IPアドレスをIPv4の欄に記入して、作成をクリックします。
![CloudDNS3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1024959/d016d6f6-8286-7a8a-2395-c0dc4d37e2e4.png)

作成されると、新たにレコードが追加されていると思います。


続いて、GoogleDomainの設定に再び移ります。

## カスタムネームサーバーに情報を追加
先ほどGCP上で表示されていたNSのルーティングポリシー記載のドメインサーバーを、GoogleDomainのカスタムサーバーに情報を追加します。
情報を転記した後、保存を押して、取得したドメインをカスタムネームサーバーに設定し、全ての操作は完了です。
あとは、反映されるまで時間がかかるので、後ほどできているか確認する。
![GoogleDomain6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1024959/23cdcb5f-faae-6a48-2c8b-709520da611e.png)

## まとめ
今回は、GoogleDomainで取得した独自ドメインを、GoogleComputeEngineに割り当てる方法をまとめました。
何かの参考になれば幸いです。
王道なファイルとディレクトリ

**/bin**
--------------
基本的なコマンドが配置される。
このディレクトリにあるコマンドは、一般ユーザーでも実行可能。
※CentOS7以降は、/binは/usr/binのシンボリックリンク

**/sbin**
-----
システム管理に必須のコマンドが配置される。
このディレクトリにあるコマンドは、rootユーザーのみ実行が可能。
※CentOS7以降は、/sbinは/usr/sbinのシンボリックリンク

**/etc**
------
システムやアプリケーションの設定情報、スクリプトファイルなどが配置される。

**/dev**
-------
ハードディスクやDVD-ROMなどのデバイスファイルが配置される。

**/lib**
--------
共有ライブラリやカーネルモジュールが配置される。
/bin、/sbinにあるコマンドが必要とするライブラリはここに配置される。

**/media**
---------
DVD-ROMなどリムーバブルメディアのマウントポイントが配置される。

**/mnt**
-------
一時的にマウントするファイルシステムのマウントポイントが配置される。

**/opt**
-----------
パッケージ管理の仕組みを使ってプログラムがインストールされるディレクトリ。
ディレクトリビュージョンによっては配置されない。

**/proc**
---------
カーネル内部の情報にアクセスするための仮想的なファイルシステム。
つまり、このディレクトリ内のファイルはファイル見えるだけで、実際にはディスク上に存在しない。

**/root**
----------
rootユーザーのホームディレクトリ。
/homeファイルシステムがマウントできなくなった場合でも、システムのメンテナンスを行うことができるよう、/homeとは別になっている。

**/boot**
---------
起動に必要な設定やカーネルイメージが配置される。
起動時にBIOSの制限を受けないようにするために、ルートファイルシステムとは別に、ディスクの先頭付近に配置されることがある。

**/home**
--------
ユーザーごとのホームディレクトリが置かれる。独立したファイルシステムにすることにより、クォータを設定することができたり、保守性を向上させたりできる。

**/tmp**
--------
一時ファイルが置かれる。すべてのユーザーが読み書き可能。

**/var**
-------
ログファイル、メールやプリンタのスプールなど、頻繁に書き換えられるファイルが配置される。

**/var/cache**
---------
manコマンドで表示するために整形したデータなど、一時的なキャッシュファイルが配置される。

**/var/lock**
-----------
アプリケーションが排他制御に使うためにロックファイルが配置される。

**/var/log**
-------------
ログファイルが書き出される。システムのログファイルmessages、メールシステムのログファイルmaillog(mail.log)などがある。

**/var/run**
-----------
システムの状態を示すファイルが配置される。

**/var/spool**
----------------
印刷町のデータや予約されたジョブなど、処理待ちのデータが配置される。

**/usr**
-------------
コマンドやユーティリティなどが配置される。/usrディレクトリの下はさらに細分化されており、複数のディレクトリがある。

**/usr/bin**
-------------
ユーザーが一般的に使うコマンドで、緊急時のシステム保守に必須ではないコマンドはここに配置される。

**/usr/sbin**
------------
システム管理コマンドで、緊急時のシステム保守に必須ではないコマンドがここに配置される。

**/usr/lib**
-----------
プログラムに必要な共有ライブラリが配置される。

**/usr/local**
-------------
ローカルシステムで必要とされるコマンドやライブラリ、ドキュメントなどが配置される。
このディレクトリ内は、さらにbin、sbin、libなどのディレクトリが細分化される。

**/usr/share**
---------------
x86やx86-64といったシステムアーキテクチャに依存しないファイルが配置される。
たとえば、/usr/share/manにはmanコマンドで使うマニュアルが配置される。

**/usr/src**
---------------
Linuxのカーネルソースなど、ソースコードが配置される。
CLionでOpenCV

# OpenCVのダウンロード

[OpenCV-GitHub](https://github.com/opencv/opencv/releases/tag/4.5.4)のページから、`opencv-4.5.4-vc14_vc15.exe`をダウンロードし、実行し、任意の場所に展開しておきます。(ここでは`F:/opencv`とする。)

# 環境変数の設定

システム環境変数にて、次を追加しておきます。

```
F:\opencv\build\x64\vc15\bin
```


# CLionで実装！

まずはCLionでC++ Executableでプロジェクトを作成します。
![8e651bc6-47d5-400b-881b-ffe5f6001a04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1563715/43f1bc3c-0e89-4301-bf0c-a3730d7c6f17.png)

## ビルド設定

`Settings>Build,Execution,Deployment>Toolchains`を開き、Architectureにx64と記入します。(x86で出来ないのが気持ち悪いけどなんにもわからない)

![6f874a42-30b4-4633-b03b-111ea3b5c008.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1563715/f2938925-6b0c-93cc-4d25-7dcfcca53bd3.png)


## CMakeListの編集

以下のコードを追記します。

```
set(OpenCV_DIR "F:\\opencv\\build\\x64\\vc15\\lib")
find_package(OpenCV REQUIRED)
include_directories(${OpenCV_INCLUDE_DIRS})
target_link_libraries(projectName ${OpenCV_LIBS})
```
※↑`target_link_libraries`の`projectName`はCLionで作成したプロジェクト名で置き換えて下さい。

## おわり

これで.cppにopencvがincludeできるようになりました！!

![8db55990-8b58-4b2f-8cfa-2515b15e8d2b.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1563715/29e78e14-206f-4a11-c833-e6155bf7cc32.png)

# あとがき

CPP、OpenCV何にもわからない人間なので、間違ってたら指摘していただけると幸いです。
railsチュートリアル 第１３章 マイクロポストのサンプル

###マイクロポストのサンプル
####サンプルデータにマイクロポストを追加する
db/seeds.rb

```rb
# メインのサンプルユーザーを1人作成する
User.create!(name:  "Example User",
             email: "example@railstutorial.org",
             password:              "foobar",
             password_confirmation: "foobar",
             admin: true,
             activated: true,
             activated_at: Time.zone.now)
# create!は基本的にcreateメソッドと同じものですが、
#   ユーザーが無効な場合にfalseを返すのではなく例外を発生させる
# admin:trueにして管理者にする
# サーバーのタイムゾーンに応じたタイムスタンプ

# 追加のユーザーをまとめて生成する
# メイン以外のユーザー99人を作成
99.times do |n|
  name  = Faker::Name.name
  email = "example-#{n+1}@railstutorial.org"
  # 数ごとにメアドが変更される
  password = "password"
  # パスワードは変わらない
  User.create!(name:  name,
               email: email,
               password:              password,
               password_confirmation: password,
               activated: true,
               activated_at: Time.zone.now)
  # 許可された属性リストにadminが含まれていない
  # 任意のユーザーが自分自身にアプリケーションの
  #   管理者権限を与えることを防止
end

  # ユーザーの一部を対象にマイクロポストを生成する
users = User.order(:created_at).take(6)
  # takeメソッドを使って最初の6人だけに追加します。
  # テストユーザーの最初の６人
50.times do
  # 50回
  # 50回分まとめない
  content = Faker::Lorem.sentence(word_count: 5)
  users.each { |user| user.microposts.create!(content: content) }
end
```

####マイクロポスト用のCSS
app/assets/stylesheets/custom.scss

```scss
/* microposts */

.microposts {
  list-style: none;
  padding: 0;
  li {
    padding: 10px 0;
    border-top: 1px solid #e8e8e8;
  }
  .user {
    margin-top: 5em;
    padding-top: 0;
  }
  .content {
    display: block;
    margin-left: 60px;
    img {
      display: block;
      padding: 5px 0;
    }
  }
  .timestamp {
    color: $gray-light;
    display: block;
    margin-left: 60px;
  }
  .gravatar {
    float: left;
    margin-right: 10px;
    margin-top: 5px;
  }
}

aside {
  textarea {
    height: 100px;
    margin-bottom: 5px;
  }
}

span.image {
  margin-top: 10px;
  input {
    border: 0;
  }
}
```

###演習

1.
(1..10).to_a.take(6)というコードの実行結果を推測できますか? 推測した値が合っているかどうか、実際にコンソールを使って確認してみましょう。

```rb
>> (1..10).to_a.take(6)
=> [1, 2, 3, 4, 5, 6]

>> (1..10).to_a
=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
#to_aメソッドとは、ハッシュ、範囲オブジェクトなどを配列に変換するメソッド

>> (1..10).take(6)
=> [1, 2, 3, 4, 5, 6]

>> (1..10).class
=> Range
>> (1..10).to_a
=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>> (1..10).to_a.class
=> Array
```
2.
先ほどの演習にあったto_aメソッドの部分は本当に必要でしょうか? 確かめてみてください

今のところ不要

3.
Fakerはlorem ipsum以外にも、非常に多種多様の事例に対応しています。Fakerのドキュメント（英語）を眺めながら画面に出力する方法を学び、実際に架空の大学名やHipster IpsumやChuck Norris facts（参考: チャック・ノリスの真実）を画面に出力してみましょう。

ちょっとわからない。
railsチュートリアル第十四章 ユーザーをフォローする

#ユーザーをフォローする
他のユーザーをフォロー（およびフォロー解除）できるソーシャルな仕組みの追加と、
フォローしているユーザーの投稿をステータスフィードに表示する機能を追加します。

ユーザー間の関係性をどうモデリングするかについて学びます
モデリング結果に対応するWebインターフェースを実装していきます。
このとき、Webインターフェースの例としてAjaxについても紹介します。最後に、ステータスフィードの完成版を実装します。

ステータスフィード作成のためにRuby/SQLを「だます」テクニックも含まれます。

これまでよりも複雑なデータモデルを使います。
ここで学んだデータモデルは、今後自分用のWebアプリケーションを開発するときに必ず役に立ちます。

モックアップ
工業製品の設計・デザイン段階で試作される、外見を実物そっくりに似せて作られた実物大の模型のこと。

##Relationshipモデル
ユーザーをフォローする機能を実装する第一歩は、データモデルを構成することです。

```
git checkout -b following-users
```

```
ubuntu:~/environment/sample_app (following-users) $ rails generate model Relationship follower_id:integer followed_id:integer
Running via Spring preloader in process 4446
      invoke  active_record
      create    db/migrate/20211027060213_create_relationships.rb
      create    app/models/relationship.rb
      invoke    test_unit
      create      test/models/relationship_test.rb
      create      test/fixtures/relationships.yml
```

relationshipsテーブルにインデックスを追加する
db/migrate/[timestamp]_create_relationships.rb

```rb
class CreateRelationships < ActiveRecord::Migration[6.0]
  def change
    create_table :relationships do |t|
      t.integer :follower_id
      # integer : 整数 
      # tを整数型のデータにする
      # それをfollewer_idカラムの値にする
      t.integer :followed_id

      t.timestamps
    end
    
    add_index :relationships, :follower_id
    # add_index 指定したテーブルにインデックスを追加
    # followingテーブルのそれぞれの行は、
    #   followed_idで識別可能なユーザーでなければなりません
    #　　ユーザーを認識するための行
    # フォローする側
    add_index :relationships, :followed_id
    # フォローされる側
    # 
    add_index :relationships, [:follower_id, :followed_id], unique: true
    # follower_idとfollowed_idの組み合わせが必ずユニークであることを保証する仕組みです。
    # ユニーク 一意性制約（テーブル内で重複するデータを禁止する）
    #          カラムに独自性を与えます。
  end
end
```

```
rails db:migrate
```
###演習
1.
図 14.7のid=1のユーザーに対してuser.following.map(&:id)を実行すると、結果はどのようになるでしょうか? 想像してみてください。ヒント: 4.3.2で紹介したmap(&:method_name)のパターンを思い出してください。例えばuser.following.map(&:id)の場合、idの配列を返します。

配列で返しそう。

2.
図 14.7を参考にして、id=2のユーザーに対してuser.followingを実行すると、結果はどのようになるでしょうか? また、同じユーザーに対してuser.following.map(&:id)を実行すると、結果はどのようになるでしょうか? 想像してみてください。

わからない。
GridSearchCVの結果をcsvに保存する

### Grid Searchの結果の保存の仕方

```python
  results = clf.cv_results_
    params = results['params']
    print("params", params)
    param_str = list()
    for p in params:
        temp_param = ""
        for key,  value in p.items():
            temp_param += key + ':' + str(value) +'_'
        param_str.append(temp_param)
    param_str = np.array(param_str)
    mean_score = results['mean_test_score']
    stds = results['std_test_score']
    rank = results['rank_test_score']
    data = {"param name": param_str, "mean" : mean_score, "std" : stds, "rank": rank}
    import pandas as pd
    df = pd.DataFrame(data)
    df.to_csv('path/to/grid_svm_result.csv', encoding='utf-8', index=False)
```

使用したparamはstringとして、保存している。
以上
Python_is演算子

# is演算子
同じオブジェクトかどうか判定する。
Noneなどの判別によく使用する.


```
a = 1
b = 1
c = 0
d = a
print(id(a), id(b), id(c), id(d))
print(a is b)
print(a is c)
print(a is not c)
```

>94279174345344 94279174345344 94279174345312 94279174345344
True
False
True
railsチュートリアルMysql化とDocker化

今回、下記の動画を参考にしつつRailsチュートリアルのプロダクトをDocker化させてみました。

Docker超入門講座 合併版 | ゼロから実践する4時間のフルコース 
[https://www.youtube.com/watch?v=lZD1MIHwMBY&t=3538s](https://www.youtube.com/watch?v=lZD1MIHwMBY&t=3538s)

railsチュートリアルではデフォルトではpostgresqlが選択されていますが、IT企業で採用されているデータベースはMysqlが一番多いという話を聞いたので変更してみます(上記紹介動画でもmysqlが紹介されております。mysql8系で紹介されておりますが、herokuの無料プランが5系のみとの事なので5系でDBを設定します。)

ただ、M1のMacの場合はDockerでMysqlは、サポートされていないのでMariaDBにした方が良いです。(私はintelのMacとM1のMacを持っているので今回は試験的にmysqlにしてますが、恐らくこの先、新しくプロダクトを作る場合mysqlを選択するならMariaDBを選択するって言うのが主流になっていくのでは無いかと思われます。)

### **作業ディレクトリの作成**

作業ディレクトリを作成し、そのディレクトリへ移動します。

自由に名前を決めてください。（筆者の場合はrails_dockerとしました）

$_は作成したdirにcdするコマンドです。

```
$ mkdir rails_docker && cd $_
```

### **Gitの初期化**

最初にGitの初期化を行います。下記からは作成したrails_dockerディレクトリをrootとします。

```
root $ git init
```

### rootディレクトリに各ファイルを作成します

sample_appディレクトリとDockerfileとdocker-compose.ymlファイル。sample_appの下の階層にGemfileを作成

```ruby
root $ mkdir sample_app && touch {$_/Gemfile,Dockerfile,docker-compose.yml}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2005642/aa99062e-ff67-c6ab-d03b-fe6c49c0dfc6.png)


### 各ファイルを**編集します。**

### **Gemfile**

```
source 'https://rubygems.org'
gem 'rails',  '6.0.3'
```

### Dockerfile

```ruby
FROM ruby:2.7.4

RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - \
  && echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list \
  && apt-get update -qq \
  && apt-get install -y nodejs yarn
WORKDIR /app
COPY ./sample_app /app
RUN bundle config --local set path 'vendor/bundle' \
  && bundle install
```

### docker-compose.yml

```ruby
version: '3'
services:
  db:
    image: mysql:5.7
    volumes:
      - ./sample_app/db/mysql_data:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: password

  web:
    build: .
    command: bundle exec rails s -p 3000 -b '0.0.0.0'
    volumes:
      - ./sample_app:/app
    ports:
      - "3000:3000"
    environment:
      RAILS_ENV: development
    depends_on:
      - db
```

上記のように設定します。

Dockerをbuildする。

```docker
root $ docker-compose build
```

rootディレクトリでrails newする。

```docker
root $ docker-compose run web rails new . --force --database=mysql
```

rails newされたら

再度imegeをbuildする

```docker
root $ docker-compose build
```

上記操作でrailsの雛形が完成。

### DBの設定をする。

### [sample_app/config/database.yml]

passwordにpasswordと入れるのとhost(dbの接続先)をdbに変更する。

```docker
default: &default
  adapter: mysql2
  encoding: utf8mb4
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password: password  #追加
  host: db　　　　　　　　#追加 
```

### 設定が完了したらDBを下記コマンドで作成

```docker
root $ docker-compose run web rails db:create
```

DBの作成が完了した。


### 下記コマンドでコンテナを立ち上げると問題なく動作します。

```ruby
root $ docker-compose up
```

以上でローカルの環境の設定は完了です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2005642/029aff91-3974-84cc-bc18-3c5ee679f207.png)



###感想
本番環境のデプロイ方法は参照動画でも紹介して下さっておりますがrailsチュートリアルを進めていくと、ローカル環境では問題ないのにheroku側ではApplication errorになってしまいます。heroku logs --tailコマンドでログを辿り、色々やったら直りましたが、無料枠でherokuを本番環境にする場合には、mysqlよりpostgresqlが一番フィットするのかもなって印象を受けました。
CKAN APIを操作する種類を作る

　[data.go.jp](https://data.go.jp/)はCKAN APIを提供しており，データセットの検索が可能になっている。これを使いやすくするための種類を作成した。

```プロデル
CKANとは
	ベースURIを持つ
	バージョン3は，×。
	自分で［パラメタ］を［API］に送りつける手順
		【URI】
		もしバージョン3なら
			URIは，ベースURI＆「api/3/action/」＆API。
		でないなら
			URIは，ベースURI＆「api/action/」＆API。
		もし終わり
		もしパラメタが無なら
			HTTPでURIを取得したものを返す。
		でないなら
			HTTPでURIへパラメタを送信したものを返す。
		もし終わり
	終わり
終わり
```

　ベースとなるURIを持っておく変数と，APIのバージョンを指定する変数を宣言している。`HTTPで【アドレス】へ【パラメータ:辞書】を〈【ヘッダ:辞書】にて〉〈【文字コード】として〉送信する`手順は，パラメータを辞書で渡せば良い感じに投げてくれるので，そのまま辞書で渡せるように`自分で［パラメタ］を［API］に送りつける`手順も引数に辞書を渡せるようにしている。

　このCKAN種類に[CKANのAPIドキュメント](http://docs.ckan.org/en/latest/api/)に従って手順を足していく。

　例えば，`ckan.logic.action.get.site_read`であれば，こう。

```プロデル
自分がサイトを読み込む手順
	【API】
	【パラメタ】は，無。
	APIは，「site_read」
	自分でパラメタをAPIに送りつけたものをJSON形式として読み取ったものを返す。
終わり
```

　`ckan.logic.action.get.package_search`の場合はこう。

```プロデル
自分が〈［パラメタ］で〉パッケージを検索する手順
	【API】
	APIは，「package_search」
	自分でパラメタをAPIに送りつけたものをJSON形式として読み取ったものを返す。
終わり
```

　APIはJSON形式でデータを返してくるので，これを`JSON形式として読み取る`手順で辞書に変換して返すようにしている。

　次のコードで実行してみる。

```プロデル
APIというCKANを作る。
APIのベースURIは，「https://www.data.go.jp/data/」。
APIが｛q＝「res_format:XLSX」，rows＝5｝でパッケージを検索する。
それを報告せよ。
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150160/75ff27b7-9169-a0d3-4216-35db1d1f357b.png)
Arduinoの勉強　第4弾：アナログ入力

# #アナログ入力
##はじめに
ハードウェアの勉強のためにArduinoを復習も兼ねて参考教材に沿って，勉強する．細かな部分の理解までして，自在に扱えるようになることが目的である．その第4弾として，「アナログ入力」を扱う．

## デジタルデータ化
![slide1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/951300/1f67be29-14c1-680e-2b85-bcd66b4add67.png)


## 感想
A/Dコンバータという存在と役割は知っていたが，仕組みは知らなかった．分解能がビットごとに存在することを学び，デジタルデータ化のイメージを知る良い機会となった．

## 参考文献
- 電子部品ごとの制御を学べる！Arduino電子工作実践講座 改訂第2版 福田和宏 著 ソーテック社
【簡単】react-map-glを日本語表示にする方法

#はじめに
react-map-glを導入した際は、英語表記となっています。
これを日本語表示にしてみましたので、まとめてみます。
![スクリーンショット 2021-11-16 23.44.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2161074/e342b463-6287-fca4-a75b-e2d1d5e27869.png)

 
#方法
いろいろ調べると以下の方法で変更できそうでした。
・MapBoxStudioで表示言語を日本語にして、StyleURLを取得する方法
 
#MapBoxStudioで表示言語を日本語にして、StyleURLを取得する方法
MapBoxへログインをして、MapBoxStudioへ入ります。
左側タブの各要素の言語表示をjapaneseへ変更します。
（Natural features,Place labels,Point of interest labels,Road network、transit,
Walking,cycling,etc）

![スクリーンショット 2021-11-16 23.35.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2161074/5ab2c760-c749-de1d-8fc8-e47e2972a734.png)
 
<br>
 
左上からカスタマイズしたstyleのURLを取得します。

![スクリーンショット 2021-11-16 23.38.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2161074/b4480d38-3528-3ba4-6ec7-be1717df3852.png)

 
 
<br>
 
MapGLのmapStyleの中に先程取得したURLを入れます。。
 
```react:map.js
<MapGL
   ref={mapRef}
   {...viewport}
   width= "100%"
   height= "450px"
   mapStyle="さきほど取得したURLをいれる"
   onViewportChange={setViewport}
   mapboxApiAccessToken={TOKEN}
>
 
```
 
<br>
 
日本語で表示することができました。
![スクリーンショット 2021-11-16 23.48.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2161074/e8088a5d-1a8f-651e-7388-ed0dd423d3ed.png)

 
 
##まとめ
今回はmap-react-glを日本語表示する方法をまとめてみました。
参考になれば幸いです。
Typeエイリアスを使って複雑な型定義を扱う【TypeScript】

TypeScriptを勉強しているため備忘録として残しておく。

## Typeエイリアスを使用する
```typescript
let capSize: 'big' | 'small' = 'samll'
```
このような型定義、型注釈を変数があったとする。
この型を定義した部分をTypeエイリアスで定義しておくことができるらしい。

### こんな感じ
```typescript
type CapSize = 'big' | 'small'
```
上記のように定義して、実際使用する時は以下のように使用する。

```typescript
type CapSize = 'big' | 'small'
let capSize: CpaSize = 'small'
```
こうしてtypeエイリアスとして定義しておくと、他のオブジェクトや変数などの至るところでtypeで定めた型を使用することができる。
wanddb setup（メモ）


通常のセットアップをして、loginをすると、/.netrcというファイルが生成される。
これをローカルに保存しておけば、下記スクリプトでloginコマンド無しでログイン可能。

```shell:

export LANG=C.UTF-8
pip install wandb
#wandb login

cp wandbkey ~/.netrc
chmod 600 ~/.netrc

```