OmniAICreator/Qiita-1.07M huggingface dataset:
redoc-cliのDocker Imageを作成してDockerHubに登録する

OpenAPI v3を試すために、環境を用意するところから始めたかったが、redoc-cliは公式でdocker imageがなさそうだったので作って登録しておいた。

cliでチマチマ作業するのは好きではないので、intelliJを使いました。
本記事は、その作業の備忘録です。

# 用意したもの
- githubアカウント
- DockerHubアカウント
- intteliJ
- Docker Desktop for Mac

# 作業
### githubにリポジトリを作成する
https://github.com/hidekingerz/redoc-cli

### Docker Hubにリポジトリを作成する
https://hub.docker.com/r/exthirix/redoc-cli
とりあえず作るだけ。自動ビルド設定は後回し。

### intelliJ で Dockerfile を作成する
https://github.com/hidekingerz/redoc-cli/blob/master/Dockerfile
master ブランチ に push しておく。

### intelliJ で Dockerfile から Image をビルドする。
Run/Debug Configurations でぽちぽちするだけ。
設定したら Run してイメージを作っておく。
![dockerfile.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/125552/0f3ea8af-e9ce-a850-66b2-215743a68976.png)

### イメージからコンテナを作成する
Run/Debug Configurations でぽちぽちするだけ。
コンテナができるので動作確認する。

![container.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/125552/525d9082-766b-7b4e-40be-ba3ac05431da.png)

### Docker Hub に push する
InterlliJ から DockerHub にpushできるので、ぽちぽちするだけ。
Pushには少し時間が書かかるので待ちましょう。
![push.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/125552/a08c6b98-8dd0-9dfb-4810-cb199215a2ea.png)

### Docker Hub で Dockerfile を公開するために github と連動させる
Automated Buildを設定すれば良い。設定したら、Save and Build を実行すると、しばらく立ってから build されて公開される。

![dockerHubManage.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/125552/05080820-a784-d077-e4e1-babe2c104d71.png)
多対多のテーブルで関連付けたテーブルの情報を取得する方法

#この記事でわかる事
多対多の関係になるようにアソシエーションを組み、
関連づけたテーブルの情報取得をする方法。
※詳しい状態は前提に記載。


###前提
言語：Ruby
　　
私の作成中のアプリを例にします。
私はCDとそこに収録された曲を多対多でアソシエーションを組みました。
多対多の理由：CDには複数の曲が入っている。
　　　　　　　曲は複数のCDに入っていることもある。

![visualMusic-Page-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/661441/8bbe5625-633d-6b4e-5661-6723bb8c71e0.png)

![visualMusic-Page-3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/661441/7725255a-cbd8-f183-d9f1-15221636e4ae.png)

ということで、
対対多のテーブルを作成。
中間テーブルも同時に作成。
※idやカラムはもっとありますが省略
![visualMusic-Page-4 (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/661441/cea0f5bc-6b91-0583-9a0d-188304420e75.png)
ここまでが前提で出来ていて、
同じように多対多でアソシエーションを組んだ方はこの記事が参考になるはずです。


#実装したいこと
このdiscsテーブルを元に、
各CDの詳細ページを作りたいということでViwe(show.haml.html)を用意。

(URL▶︎localhost:3000/discs/1)
＜例①：disc_idが1の場合＞
取得・表示したい情報：CD-Aに紐づいた曲（song-A,song-B,song-C）

＜例②：disc_idが2の場合＞
取得・表示したい情報：CD-Bに紐づいた曲（song-A,song-D,song-E）
　
　
:point_right_tone1:関連したテーブルからも情報を取得したい！というのが今回の目標です。
  
  
####例①のテーブルの図
![visualMusic-Page-4 (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/661441/bc9443e5-f044-abac-a324-80e2fde98ee4.png)
関連するピンクの曲名も同じページに表示されれば成功です。
何となくやりたいことは理解いただけたでしょうか？
　
　　
# 実際のコード
ここでURLで表示されていたidを取得してきます。
例だとdisc_id:1ですね。ユーザーがid:1のCDの情報が欲しいと指示できる訳です。

```ruby:discs_controller.rb
class DiscsController < ApplicationController
#省略

  def show
    @disc = Disc.find(params[:id])
  end

#省略
end
```

```ruby:show.html.haml（show.html.erbの場合はhamlをhtmlに変換してください。）

- @disc.songs.each do |song|
    = song.name
```
ルーティングは「resources :discs,only: [:show]」という感じで:showを入れてます。


#ポイント
テーブルを跨いじゃう時の記述がポイントかと思います。

```ruby:show.html.haml（show.html.erbの場合はhamlをhtmlに変換してください。）

- (params[:id]を取得した変数).(所得したい関連テーブル名).each do |(以下で使う変数)|
    =(上記で指定した変数).(所得したテーブル内で表示したいカラム名)
```
説明がクドイと思いましたが詳しく書いてみました。

　　
　　
以上で表示出来たかと思います。
お疲れ様でした！
　
　　
#ひとことMemo
自身は正直本当に初心者で
現在、アソシエーションを組むメリット、
親子関係にするメリットなども理解が追いついていません。
ただ、今回、多対多にすることで単体のテーブルに紐づいたビューでも他のテーブル情報がとって来られることがわかりました。
クライアントから受け取れるURLからの情報は「/discs/1」とか「/discs/1/song」とか「discs/new」とかこうしたものからなのだと気づいたり。
また、ルーティングではメインとなる情報元のテーブルの指示を受け、表示されるviwe情報を受け取ってたり、コントローラーでテーブルから取ってくる情報が記述出来たり、気付きばかり。

同じように基礎部分で悩んでいる方がこれで何かヒントを掴んでくださったなら、
自分がここで躓いたことに意味があるはず！と思い、
未来にまた同じところで躓く自分への記事としてここに記録しました。
　　
　　
最後まで読んでくださって、ありがとうございました:relaxed:
ではまた:wave:
VBSファイルコピー例


#フォルダチェック
```VBS:Folde_chk.vbs

Option Explicit
Dim strDstFolder
Dim FSO

strDstFolder = "C:\Dst"

Set FSO = CreateObject("Scripting.FileSystemObject")

If FSO.FolderExists(strDstFolder) Then

    WScript.Echo "フォルダが存在します"

End If

Set FSO = Nothing

```

#フォルダ内ファイル一覧

```VBS:file_list.vbs
Option Explicit
Dim strSrcFolder
Dim FSO
Dim objSrcFolder

strSrcFolder = "C:\Src"

Set FSO = CreateObject("Scripting.FileSystemObject")

Set objSrcFolder = FSO.GetFolder(strSrcFolder)

for each file in objSrcFolder.files

    WScript.Echo filename

next

Set FSO = Nothing


```

#ファイル一覧から一つずつコピーして、成功なら削除

```VBS:file_Copy.vbs
Option Explicit
On Error Resume Next



Dim SaveFile

Dim strSrcFolder
Dim strDstFolder

Dim FSO
Dim objSrcFolder

Dim strDate

Dim WF '#保存ファイルオブジェクト

Const ForReading = 1, ForWriting = 2, ForAppending = 8

strSrcFolder = "C:\Src"
strDstFolder = "C:\Dst"

Set FSO = CreateObject("Scripting.FileSystemObject")


'###################################################
'# エラーログ記述開始
'###################################################


'###################################################
'# 引数チェック
'###################################################

Dim CorpID,Type

If WScript.Arguments.Count >< 2 then

   '#エラーログへ記述

End if

CorpID = WScript.Arguments(0)
Type = WScript.Arguments(1)


'###################################################
'# 日時取得
'###################################################
 
'yyyy/mm/dd hh:mm:ss 形式
strDate = Now()
 
'yyyy/mm/dd hh:mm:ss から /,:,半角スペースを削除

strDate = Replace(strDate, "/", "")
strDate = Replace(strDate, ":", "")
strDate = Replace(strDate, " ", "")

'###################################################
'# 日付ファイルの作成
'###################################################

SaveFile = FSO.BuildPath(strSrcFolder,strDate & ".csv")

Set WF = FSO.OpenTextFile(SaveFile, ForWriting, true)

WF.WriteLine(strDate)
WF.Close

Set WF = Nothing

'###################################################
'# 保存先フォルダの存在チェック
'###################################################

If Not FSO.FolderExists(strDstFolder) Then

　'# エラーログ出力の上、抜けるなどの処理

End If

'###################################################
'# 保存済みファイルのループ処理
'###################################################

Set objSrcFolder = FSO.GetFolder(strSrcFolder)

For each file in objSrcFolder.files

 Err.clear 'エラーリセット
 FSO.Copy(file.path,FSO.BuildPath(strDstFolder,file.name))

 If( Err.number = 0 ) Then

   '#ファイルコピーが成功の時のみコピー元ファイルを削除する。
   FSO.DeleteFile file.path, True

   if( Err.number >< 0 ) Then

     'ログに削除失敗を記述
   
   End if

 Else

  'ログにコピー失敗を記述

 End if

Next

'###################################################
'# 終了処理
'###################################################

Set FSO = Nothing


```
Fargate PV 1.4でGitHub Packagesを使用するとCannotPullContainerErrorが発生する

## タスク起動時のエラーメッセージ
```
CannotPullContainerError: httpReaderSeeker: failed open: content at https://docker.pkg.github.com/v2/<username>/<reponame>/<image>/manifests/sha256:1840562644708320d81c1852b65a297d5ccf890e4a822a8aaca01axxxxxxxxxx not found: not found
```

## 原因
Open Container Initiative (OCI) によって定義されている コンテナイメージ配布の
標準仕様である [HTTP API V2](https://github.com/opencontainers/distribution-spec/blob/master/spec.md) を GitHub Packages が一部満たしていないことに起因し、
コンテナランタイムが Containerd の場合に、イメージの pull に失敗します。

## 回避策
プラットフォームバージョン 1.3 以下を利用するか、その他のレジストリサービスを使用する必要があります。

**2020/9/2 追記**
パブリックベータとして発表された GitHub Container Registry では上記の問題が解決されています。
https://github.blog/2020-09-01-introducing-github-container-registry/

## 補足
Fargate に限らず、Conitainerd で動作する環境全てで Github Pakcages から
イメージの pull ができません。
Fargate については プラットフォームバージョン 1.4 以降、 コンテナランタイムが 
Docker Engine から Containerd に置き換わっため、上記不具合の影響を受けます。

**詳細: Fargate データプレーン**
https://aws.amazon.com/jp/blogs/news/under-the-hood-fargate-data-plane/

プラットフォームバージョン 1.3 以下は Docker Engine で実行するため
この問題の影響を受けません。

Containerd の GitHub レポジトリにこの問題の issue があがっています。
2019年5月に起票され、~~2020年8月時点で解決されていませんが、
Github Packages 側の修正は進んでおり、近日中に動きがありそうな状況は確認できます。~~

GitHub Container Registry の使用により事象が解消される旨記載され、issue もクローズになりました。

**containerd can't pull image from Github Docker Package Registry #3291**
https://github.com/containerd/containerd/issues/3291

簡単ですが、以上です。
参考になれば幸いです。
OpenCC で中国語変換だけしたい！

# OpenCC とは？

npm の漢字変換もづーる。

https://github.com/BYVoid/OpenCC

# インストール

パッケージに入れたいわけじゃない、そもそもパッケージがない、リソースに追加したいだけなので、グローバルインストール。
`npm i opencc -g`

そして、 node.js でさっさとオブジェクトをいい具合にしたいだけなので、 require に必要なフルパスを探す。

`find $HOME/.nvm/ -name opencc`

以下、
`$userdir` は `$HOME`
`$version` は `node -v` の結果
で読み替えてください。

```OpenCC-sample.js

const OpenCC = require( '/home/$userdir/.nvm/versions/node/$version/lib/node_modules/opencc' );
const t2s = new OpenCC( 't2s.json' );

/*
 * 英語,日本語,繁体字中国語 でリソース組んだけど OpenCC を入れ込むの
 * 重たいし、リソースの後ろにくっつけたいです。っていう感じのオブジェクト。
 */
const l = {
  displayLanguage: [ 'Language', '表示言語', '顯示語言' ],
  english: [ 'English', '英語', '英文' ],
  japanese: [ 'Japanese', '日本語', '日文' ],
  tradChinese: [ 'Traditional Chinese', '繁体字中国語', '繁體中文' ],
  simpleChinese: [ 'Simplified Chinese', '簡体字中国語', '簡體中文' ],
}

// キーごとの繁体字中国語を簡体字中国語に変換して、配列のケツにぶっこむ。
// foreach 書き方忘れたからこれでいいや
Object.keys( l ).map( key => {
  let terms = l[ key ], sc = t2s.convertSync( terms[ 2 ] ); terms.push( sc );
} );

# > l
{
  displayLanguage: [ 'Language', '表示言語', '顯示語言', '显示语言' ],
  english: [ 'English', '英語', '英文', '英文' ],
  japanese: [ 'Japanese', '日本語', '日文', '日文' ],
  tradChinese: [ 'Traditional Chinese', '繁体字中国語', '繁體中文', '繁体中文' ],
  simpleChinese: [ 'Simplified Chinese', '簡体字中国語', '簡體中文', '简体中文' ],
}

// あとはコレをコピペしてリソースにしちゃえばオッケーオッケー。
```
平面上における2点間の距離と角度の求め方

# 概要

XY座標の2点間の角度と距離の求め方をまとめる。
言語はJava

# 距離の求め方

```
// 2点の座標
double x = 0;
double y = 0;
double x2 = 1;
double y2 = 1;

// 2点の座標から距離を求める
double distance = Math.sqrt((x2 - x) * (x2 - x) + (y2 - y) * (y2 - y));
```

# 角度の求め方

```
// 2点の座標
double x = 0;
double y = 0;
double x2 = 1;
double y2 = 1;

// 2点の座標からラジアンを求める
doble radian = Math.atan2(y2 - y, x2 - x);

// ラジアンから度を求める
double degree = radian * 180 / Math.PI;
```
DockerでMysqlを使いたい

Dockerを初めてまだ日数が立っておらず、ハマったので、備忘録としてターミナルでMysqlに接続し、弄る方法を記述していく。

始めに、

```
docker ps
```

で、MysqlのコンテナIDを確認。

```
name@mbp APP_NAME % docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
2acfbade0963        app_name_web       "rails s -p 3000 -b …"   2 days ago          Up 2 days           0.0.0.0:3000->3000/tcp   app_name
c71b0bf50f29        mysql:5.6.47        "docker-entrypoint.s…"   2 days ago          Up 2 days           0.0.0.0:3306->3306/tcp   app_name
```

こんな感じで出るので、今回は"c71b0bf50f29"をコピーしておく。

次に、

```
docker exec -it コンテナID mysql -u root -p
```
でMysqlに接続する。

今回は今コピーした”c71b0bf50f29 ”をペーストする。

パスワードは、database.ymlに記述したのでOK

#おまけ

そこからテーブルを弄りたい場合、

```
show databases;
```

で、データベースをコピーし、

```
use 今コピーしたDB名
```

テーブル内確認

```
select * from テーブル名;
```

テーブル内を全削除

```
DELETE FROM テーブル名;
```
SQLアンチパターン　ラウンディングエラー

# ラウンディングエラー

floatやdoubleのような実数を表すデータ型を使用する際、小数値の値を使用すると丸めが発生して正確な数が格納できない。
floatは実数を２進数形式でエンコードする。

10進数で記述できる全ての値を、2進数で格納できるわけではない。

# 丸めが避けられない

3分の1のような有理数は0.3333…のような循環小数で表す場合、正確な値は少数では表現できない。
桁数とは数の精度であり、循環小数では無限精度が必要になる。
　
妥協策は可能な限りオリジナルに近い値、例えば0.333などの有限精度の値を使用すること。
しかしこの妥協策は丸めの振る舞いによる誤差を生み出します。

1/3 + 1/3 + 1/3 = 1
0.333 + 0.333 + 0.333 = 0.999

3分の1の近似値である0.333の精度を上げてから３倍しても真値である1.0にはならない。
これが循環小数を持つ数を表すために止むを得ず有限精度を使用するという妥協策である。

0.333333 + 0.333333 + 0.333333 = 0.999999 ←有限精度を使うと1.0にはならない

# SQLでのFLOATの使用

SQLのFLOATデータ型は、IEEE754標準にしたがって実数を2進数形式でエンコードする。
IEEE754では、浮動小数点数を2進数形式で表現する。

2進数形式で無限精度が必要な値は、10進数で表現される値とは異なる。
10進数では有限精度で表せる値として59.95を例として説明する。

FLOAT型では無限精度を扱うことができないため2進数形式で格納できる近似値を使用する。
その近似値を10進数で表現すると「59.950000762939」となる。

## この小さな誤差が.....

浮動小数点の誤差累積の影響は和ではなく積を計算する場合にさらに大きくなる。
元々の誤差は小さく見えるが計算によってみるみる大きくなる。

とある値Aがあったとする。

値Aに1.0を何回掛けようと値Aの結果は変わらない。
値Aにかける値が0.999だった場合は誤差が大きくなっていく。

値Aに0.999を1000回かけると誤差は約0.3677となる。
計算回数がさらに増えるとさらに誤差が大きくなる。

一つ値にかけ算を何回も繰り返し行う典型的な例は金融システムにおける利子の複利計算などがある。
初めは小さな誤差だが計算を繰り返すうちに誤差はどんどん大きくなる。

金融系に限った話ではないが正確な値を使うことは重要である。

# アンチパターンの見つけ方

FLOAT、REAL、DOUBLE、PRECISIONなどのデータ型をもちいると「完全に正確な値」は期待できない可能性が高い。
そのため上記のデータ型を用いている場合、アンチパターンを用いている可能性が高いと言える。

# 解決策

NUMERIC型、DECIMAL型を使用する。

上記のデータ型では有理数を丸めこむことなく格納できるためその値を正確に格納され信頼できる値となる。
しかし上記の型を用いても３分の１のような無限精度が必要な値を格納することができない。

正確な値が必要な場合はNUMERIC型、DECIMAL型を使用。
FLOAT型など丸めこみが発生する型の場合は概数として扱うべきである。

# まとめ

できる限り、FLOAT型は使わないようにしましょう。

文字ばかりの記事ですみません.....

# 次回

サーティワンフレーバー

# 参考文献

[SQLアンチパターン](
https://www.amazon.co.jp/SQL%E3%82%A2%E3%83%B3%E3%83%81%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3-Bill-Karwin/dp/4873115892/ref=sr_1_1?adgrpid=104444684056&dchild=1&gclid=CjwKCAjw4_H6BRALEiwAvgfzqy-f83NTsyQkauo7gn6ysgAPmJvKyvuI5FaXFnxFmhVfCzCRRACsaBoCY-oQAvD_BwE&hvadid=447984765572&hvdev=c&hvlocphy=1009332&hvnetw=g&hvqmt=e&hvrand=13417269104929133208&hvtargid=kwd-335484809678&hydadcr=27264_11561110&jp-ad-ap=0&keywords=sql%E3%82%A2%E3%83%B3%E3%83%81%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3&qid=1599934568&sr=8-1&tag=googhydr-22)

![参考文献.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/257405/b46d45ab-75ec-a620-eeb2-a422f6b1e659.jpeg)
PHPでの三項演算子(if文に?(はてな)があるコード)について

#プログラミングの勉強日記
2020年8月28日
`?`(はてなマーク)の後に`:`がある式についてまとめる。`?`と`:`は、条件分岐の式を記述できる三項演算子(条件演算子)となる。記号は２つ使うが、演算子としては１つの演算子となる。

#書き方
　三項演算子では、演算の対象である被演算子を３つとり、`?`と`:`を以下のように書く。

```:書き方
(条件式)? <真式> : <偽式>
```

```php:具体例
$num = 13;
echo ($num%2==0) ? '真' : '偽';

// 上記は以下と同じ
if ($num%2==0) {
   echo '真';
} else {
   echo '偽';
}
```

#??マークとは(番外編)
　`??`は<font color=orange>null合体演算子</font>と呼ばれている。これはnullかどうかを確認することができる。

#参考文献
[【PHP】?（ハテナマーク）と : （コロン）条件演算子｜条件分岐を一行で記述](https://blog-and-destroy.com/7118)
[3項演算子（if文に「?（はてな）」があるやつの見方）](http://harumemo.hatenablog.com/entry/2016/04/28/164916)
[【PHP】？？（クエスチョンマーク二つ）って何・・・？](https://tektektech.com/php-double-question/)
Self-XSS防止 [Chrome Developer Tools]

まず、Googleのあるサイトが実施しているSelf-XSS防止の実例を示します。
![self-xss-warning.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/699050/21c3bf5a-49b5-070e-eade-6c57e0a21213.png)

そうです。Consoleに警告を表示する！です。
以上です。
# 簡単な説明
Developer ToolsのConsoleではJavaScriptを直接実行できるため、もし被害者が攻撃者に誘導され悪意あるコードを直接実行した場合はCSRF TokenやSession IDなどが攻撃者に盗まれ最終的にアカウントが乗っ取られる可能性があったりします。他にもJavaScriptが実行できるのでいろいろとできるかもしれません。

これを防止するために...
Consoleに警告を表示する！です。

Self-XSSに関しては他にもアドレスバーにjavascript:alert(1);などを入力するやExtensionsなどで実行することができますが、本記事の対応で気持ち程度はセキュリティリスクを軽減することができると思います。
C++ std::transform関数(map関数にあたる)

C++におけるmap関数にあたるのはstd::transform関数

```cpp
// 使用例
vector<int> vec {1, 2, 3, 4, 5};
vector<int> output(vec.size());
auto f = [](int x){ 
  return 2 * x; 
};
transform(vec.begin(), vec.end(), output.begin(), f);
// またはもとのvectorを変更することも可能
transform(vec.begin(), vec.end(), vec.begin(), f);
```

他の言語と名前が違うのでややこしい。

https://en.wikipedia.org/wiki/Map_(higher-order_function)
GCP Workflowsを試す

# Workflows

https://cloud.google.com/workflows

httpベースのAPIのワークフローをyamlで定義して実行できるくんっぽい、最近betaが出たっぽい

# とりあえずquick startをやる

https://cloud.google.com/workflows/docs/quickstart-gcloud

公式ドキュメント通りにyaml書いて、gcloudコマンドでデプロイする。
それからgcloudコマンドで実行する。

と思ったら普通に失敗した。
公式ドキュメント中のyamlだと http://worldclockapi.com という時間情報を取得するAPIを使うのだが、そのまま叩くと403が返ってくる。これはちょっと……。
ということで代わりになりそうな http://worldtimeapi.org/ というのを見つけたのでこれを使ってみる。

# 少し修正したquick start

以下の様なファイルを作成

```myFirstWorkflow.yaml
- getCurrentTime:
    call: http.get
    args:
        url: http://worldtimeapi.org/api/timezone/Asia/Tokyo # ここを修正
    result: currentTime
- readWikipedia:
    call: http.get
    args:
        url: https://en.wikipedia.org/w/api.php
        query:
            action: opensearch
            search: ${currentTime.body.day_of_week} # レスポンスのフォーマットが異なるためここも修正
    result: wikiResult
- returnResult:
    return: ${wikiResult.body[1]}
```

以下コマンドでワークフローをデプロイする
公式だとサービスアカウントを指定していたが、無しでも可能ではある模様
`gcloud beta workflows deploy myFirstWorkflow --source=myFirstWorkflow.yaml`

以下コマンドでワークフローを実行する
非同期で実行されるため、以下コマンド実行後に表示されるコマンドを叩くか、gcp console画面を見れば実行結果の確認が可能
`gcloud beta workflows execute myFirstWorkflow`

これで成功したら完了、作成したワークフローをもう使わないのであれば削除しておく
なお5,000 steps以上から課金が発生するため注意

# 感想

+ 良さそうなとこ
    + 機能しぼってるのか、まだbetaだからなのかわからないけど簡単
    + 単一のyamlにワークフローをまとめることができるので、どういう順序でジョブが実行されるかの確認がしやすい
    + 画面からワークフロー単位でエラー詳細、ログが見れる
    + gcloudコマンド、API経由でワークフローを実行できるのでGAE, GCEとか色んなところから呼べそう
+ 不満なとこ
    + 途中で失敗したらそれで終わり、リトライ機構とか、途中から再開は無さそう？
    + ワークフローのどこまで完了したか、的なグラフィカルなUIは無い、yamlしか見れない
    + 定期実行する場合は単体では無理で、Cloud Schedulerとか組み合わせないとダメそう
    + エミュレータは無く、ローカルでの動作確認とかは出来無さそう

# まとめ

簡易的、小規模のプロジェクトなら試しに使ってみても良いかもだけど、ちゃんとやるなら他のワークフローツール使った方が良さそうな感じに見えました （他をそんなに知らない）
今後に期待
初心者がRuby on Railsでポートフォリオを作成しました

# はじめに

初心者がRuby on RailsでWebアプリを開発しました。
アプリや本記事についてアドバイスありましたらよろしくお願いします。

# 開発環境

- Ruby 2.6.3
- Rails 5.2.3
- DB：PostgreSQL 12.3
- AWS/EC2/S3
- Route53,ACM,ALBでSSL

# 背景

私は大学時代に落語研究会に所属しており、そこで知り会った人たちが現在、お笑い芸人をやっております。
私自身お笑いが好きということもあり、知り合いのライブをよく見に行くのですが、毎度同じネタをやったり、練習不足などが目に見えることが何度かありました。
そこで知り合いの芸人に現在の状況を聞いてみたところ、芸人として使える時間が少ないことが原因と判明しました。
そのため以下のような課題があると考えました。

##### ・ライブのチケットが売れずに給料が低いため、バイトをしており芸を磨けていない
売れていないお笑い芸人は生活をするために、日々バイトをしております。
また自分が出演するライブのチケットの販売ノルマを課せられ達成できない場合、給料から天引きされる仕組みになっています。
減給されると、本来するべきである芸を磨くということに時間を使えなくなり、バイト三昧と負のループに陥ってしまいます。

そこで自身が出演するライブのチケットを売り切ることで収入が安定し、
芸を磨くことに当てる時間が増えるため芸人として売れる確率も上がると考えました。

##### ・ライブの情報がまとまっていない
芸人の方々もSNSを駆使してライブの情報やチケット販売の広報をしておりますが、
1つのプラットフォームにまとまっていないため、検索がしづらく、既に芸人を知っている方はライブの情報を収集することができますが、新規のお客様を獲得することが難しくなっています。
また芸人も数々のライブに参加するため、スケジュール管理が大変になっているとお聞きしました。

そこで今回「OWARAIMOVE」というアプリを作成しました。
#### https://www.owaraimove.net/

# アプリ概要

- 芸人が販売している置きチケ販売や参加するライブの管理を助ける
- 芸人のライブを見てみたいけど探し方や選び方がわからない人を助ける
そのようなにライブチケットを購入頂きたい芸人とライブに参加したいユーザーをマッチングするアプリです。

# 何ができるか？（機能）

OWARAIMOVEは、以下のことができます。

### ・ユーザー登録/編集/退会機能
![新規登録画面.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/509302/f2f3df71-e958-4765-c152-593bf800ed23.png)
deviseを使用して作成しております。（以前、Session&Cookieの概要を学ぶために１からログイン機能作成済）

### ・簡単ログイン機能（テストログイン）
![簡単ログイン機能.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/509302/f9b061dd-369c-7ae4-7ade-4ce2a4f97c96.png)

簡単ログイン機能を実装しました。
ボタン一つでログインできれば、選考の際に見てもらいやすくなるのではないかと考え実装に至りました。

### ・芸人の作成/編集/削除
アプリに登録する際に芸人かどうかチェックする部分があります。(ユーザー登録参照)
芸人にチェックした場合、自動的に芸人作成画面に遷移し項目を入力いただき芸人情報を作成することができます。
編集や削除は下の画像の赤丸部分のようにプロフィールより操作することが可能です。
![芸人詳細画面.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/509302/6955fdf5-6d1a-911b-3510-6bdfd6632e00.png)

### ・ライブの作成/編集/削除
![ライブ作成](https://user-images.githubusercontent.com/50095754/91462280-fb906600-e8c4-11ea-8d02-b5ee80a16899.gif)
芸人として登録している場合は、ライブ作成から作成することができます。
編集や削除は作成したライブをクリックして操作可能です。（下の画像の赤丸部分を参照）
![ライブ詳細画面.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/509302/c1d93665-22d6-bb7e-b01f-88188728a490.png)

### ・ライブの参加/キャンセル
ユーザーまたはライブに出演していない芸人の場合、ライブに参加することができます。
下の画像の赤丸部分をクリックすることでライブに参加することができます。
![ライブ参加・出演機能.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/509302/a81f46c9-f556-68ef-cb3d-2edc0606b5bd.png)

### ・ライブの出演/キャンセル
現在表示されているライブに参加/出演していない芸人はライブに出演することができます。（操作画面は上記参照）

### ・レスポンシブ対応
![レスポンシブ対応](https://user-images.githubusercontent.com/50095754/91453865-368d9c00-e8bb-11ea-8f50-8db1723cb105.gif)
スマートフォンが主流なので、そちらでも使いやすくするためにレスポンシブ対応にしました。

## 課題＆追加したい機能
- ライブのアンケート機能
- ライブチケット販売

## 最後に

本記事を読んでいただきありがとうございました。
また機能を追加次第、更新していきたいと思います。
PythonとOpenCVでいのちを輝かせる

# まずは背景の白色画像

```python
import numpy as np
import matplotlib.pyplot as plt
import cv2

# back groud
back = np.ones((512, 512, 3), np.uint8) * 255

plt.imshow(back)
plt.show();
```
![download.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323251/c7bbe813-532c-af5b-a72c-50c52a1ff89a.png)

# 次にいのち本体

```python
# red circle
cv2.circle(back, (80, 160), 53, (231, 0, 18), -1)
cv2.circle(back, (160, 186), 47, (231, 0, 18), -1)
cv2.circle(back, (162, 115), 47, (231, 0, 18), -1)
cv2.circle(back, (225, 60), 50, (231, 0, 18), -1)
cv2.circle(back, (330, 90), 65, (231, 0, 18), -1)
cv2.ellipse(back, (380, 170), (76, 36), 0, 0, 360, (231, 0, 18), -1)
cv2.ellipse(back, (370, 250), (45, 55), 0, 0, 360, (231, 0, 18), -1)
cv2.ellipse(back, (352, 350), (70, 65), 0, 0, 360, (231, 0, 18), -1)
cv2.circle(back, (262, 422), 66, (231, 0, 18), -1)
cv2.circle(back, (170, 408), 46, (231, 0, 18), -1)
cv2.ellipse(back, (128, 340), (30, 54), 0, 0, 360, (231, 0, 18), -1)
cv2.circle(back, (95, 258), 60, (231, 0, 18), -1)

plt.imshow(back)
plt.show();
```
![download-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323251/402501a4-3265-2d2a-b2f5-620abd8a7162.png)

# 最後に目！

```python
# eyes
cv2.circle(back, (68, 152), 28, (255, 255, 255), -1)
cv2.circle(back, (56, 144), 13, (29, 143, 255), -1)

cv2.circle(back, (350, 70), 28, (255, 255, 255), -1)
cv2.circle(back, (360, 60), 13, (29, 143, 255), -1)

cv2.circle(back, (350, 70), 28, (255, 255, 255), -1)
cv2.circle(back, (360, 60), 13, (29, 143, 255), -1)

cv2.ellipse(back, (378, 355), (33, 30), 0, 0, 360, (255, 255, 255), -1)
cv2.circle(back, (392, 350), 15, (29, 143, 255), -1)

cv2.circle(back, (253, 442), 25, (255, 255, 255), -1)
cv2.circle(back, (253, 454), 10, (29, 143, 255), -1)

cv2.circle(back, (253, 442), 25, (255, 255, 255), -1)
cv2.circle(back, (253, 454), 10, (29, 143, 255), -1)

cv2.circle(back, (105, 275), 26, (255, 255, 255), -1)
cv2.circle(back, (103, 263), 12, (29, 143, 255), -1)

plt.imshow(back)
plt.show();
```
![download-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323251/6074ecae-d4fc-980c-bdf2-05a20b710763.png)

見事に輝くいのちの誕生です！祝大阪万博 :qiitan-cry:

# 追記（2021/09/27）
　[プロ野球データの可視化サイト](https://npb-visualization.com) を作りました。まだまだクオリティは低いですが、今後少しずつバージョンアップさせていく予定です。野球好きの方は是非遊びに来てください⚾️

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/323251/ee131f5d-4ddd-8ecc-efa3-91ca5e483a02.png)
はじめての App Clip【実装編-Part1】



前回の概要編に続き今回は既存のプロジェクトに App Clip を作っていきます。また、サーバの対応や App Store Connect での設定などはまた別の記事で書こうかと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/292456/440becfd-4c55-e22f-487a-4a8a6e9cfc29.png)

### 作業開始 👨‍💻

AppClip の開発には Xcode12 以上が必要なので、インストールが完了していない場合は[こちら](https://developer.apple.com/download/)からダウンロードしてください。

今回は以前作った [Gyotaku](https://apps.apple.com/us/app/gyotaku-%E9%87%A3%E3%81%A3%E3%81%9F%E9%AD%9A%E3%82%92%E5%86%99%E7%9C%9F%E3%81%A7%E6%92%AE%E3%81%A3%E3%81%A6%E7%B0%A1%E5%8D%98%E3%83%87%E3%82%B8%E3%82%BF%E3%83%AB%E9%AD%9A%E6%8B%93/id1523300209?ign-mpt=uo%3D2) というアプリに AppClip を追加していきたいと思います。まずは File > New > Target で `App Clip` を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/292456/c0754fe3-6977-42d3-5cb3-f2a9a9aeb09a.png)


そして、プロダクト名を `GyotakuClip` 見たいな感じにしてインターフェース・ライフサイクを決めます。基本的に App Clip の実装では SwiftUI と UIKit の両方をサポートしているので好きな方で問題ないかと思います。現状では、シンプルなアプリ構築には SwiftUI を、複雑なレイアウトが必要な場合などには UIKit を見たいな感じで判断してやっています👀 
ただ、次回以降では SwiftUI のキャッチアップも含めて SwiftUI で実装していきたいと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/292456/49f8f45b-5489-2869-f244-fd38c73e8d9f.png)



ターゲットが追加されたので、実際に少し触って見ます。今回は `Gyotaku` App のすでに存在する Class などを使用してみたいので、Button がタップされたら画像に BlurEffect がかかる見たいなアプリ作って見たいと思います。

まずは、`GyotakuClip` で Class が使用できるようにするため必要なファイルの `Target Membership` に `GyotakuClip` を追加します。

![image.png](https://cdn-ak.f.st-hatena.com/images/fotolife/y/yum_fishing/20200819/20200819215614.png)

![image.png](https://cdn-ak.f.st-hatena.com/images/fotolife/y/yum_fishing/20200819/20200819215252.png)


すると、上記が画像のように `Module が見つからないよ` と Error がでています。解決方法として、`GyotakuClip` にも Rx 関連のライブラリを追加という手もありますが、バイナリサイズが 10MB と制限されているので、不用意にライブラリを追加するのはよくなさそうです。App Clip には Swift Complier で使用できる `APPCLIP` というフラグがあるので、これを使用して App Clip 以外で使用する場合にのみ必要な Framework 及びコンポーネントをインポートするようにします。

下記のようにして、それぞれのコンパイル環境(ここでは Debug, Release)で `APPCLIP` フラグが使えるようにします。

![image.png](https://cdn-ak.f.st-hatena.com/images/fotolife/y/yum_fishing/20200819/20200819220329.png)



追加できたら、下記のように追加して `APPCLIP` 以外でインポートするように設定すると Error が消えます🎉

![image.png](https://cdn-ak.f.st-hatena.com/images/fotolife/y/yum_fishing/20200819/20200819220632.png)


では、UIKit でお馴染みのように UI を作成していきます。

```swift
import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var contentBaseView: UIView!
    let effectImageView = BlurEffectImageView.loadFromNib()

    override func viewDidLoad() {
        super.viewDidLoad()
        contentBaseView.addSubview(effectImageView)
        effectImageView.setConstraintsToFill()
    }

    @IBAction func buttonDidTap(_ sender: Any) {
        effectImageView.set(type: .effectBlur, originalImage: UIImage(named: "icon")!)
    }
}
```
Typescript + Puppeteer やってみた

# 概要
PuppeteerをTypescriptで動かしたい!
知識をつけたいので, いろいろ試していこうと思いました!!

# リポジトリ
数年ぶりに作った....!
https://github.com/KawamotoShuji/ts_puppeteer_sandbox

# 構成(WIP)
```
.
├── crawler
│   ├── base_crawler.ts
│   ├── index.ts
│   └── test_crawler.ts
├── package-lock.json
├── package.json
└── tsconfig.json
```

# とりあえず動かすためにやったこと
## package.json作成
```:package.json

{
  "name": "testtscrawler",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "build": "tsc",
    "lint": "eslint 'crawler/**/*.ts'",
    "lint:fix": "eslint 'crawler/**/*.ts' --fix"
  },
  "author": "KawamotoShuji",
  "license": "ISC",
  "dependencies": {
    "axios": "^0.19.2",
    "dotenv": "^8.2.0",
    "puppeteer": "^5.2.1",
    "ts-node": "^8.10.2",
    "typescript": "^3.9.7",
    "yargs": "^15.4.1"
  },
  "devDependencies": {
    "@types/chai": "^4.2.12",
    "@types/dotenv": "^8.2.0",
    "@types/mocha": "^8.0.1",
    "@types/puppeteer": "^3.0.1",
    "@types/yargs": "^15.0.5",
    "@typescript-eslint/eslint-plugin": "^3.9.1",
    "@typescript-eslint/parser": "^3.9.1",
    "chai": "^4.2.0",
    "eslint": "^7.7.0",
    "eslint-config-prettier": "^6.11.0",
    "eslint-plugin-prettier": "^3.1.4",
    "mocha": "^8.1.1",
    "prettier": "^2.0.5"
  }
}
```

## tsconfig.json作成
```
{
    "compilerOptions": {
        "target": "es2018",
        "module": "commonjs",
        "outDir": "./target/",
        "removeComments": true,
        "strict": true,
        "noUnusedLocals": true,
        "noUnusedParameters": true,
        "noImplicitReturns": true,
        "noFallthroughCasesInSwitch": true,
        "esModuleInterop": true
    },
    "include": [
        "crawler",
        "node_modules/@types/puppeteer/index.d.ts"
    ]
}
```

## npm i
NodeModuleがごりっと出来上がる.

## crawlerディレクトリ作って, 中にTSファイル配置
index.ts で処理をキックするようにした.

```ts:index.ts
import TestCrawler from './test_crawler';

(async () => {
    const crawler = new TestCrawler();
    await crawler.run();
})();
```

ベースとなるクローラーのTSファイルを作った.
ヘッドフル大好きなので, デフォルトをヘッドフルにした.

```ts:base_crawler.ts
import puppeteer, { Browser } from 'puppeteer';
import { Page } from 'puppeteer';

export interface Crawler {
    run(): Promise<void>;
}

export abstract class BaseCrawler implements Crawler {
    async run(): Promise<void> {
        const browser = await puppeteer.launch(
            { 
                headless: false
            }
        );
        const _page = await browser.newPage();
        await this.crawl(browser, _page);
        await browser.close();
    }

    protected abstract crawl(browser: Browser, page: Page): any;
}
```

クローリングする実体のクローラーを作った.
うるるに行くようにした.

```ts:test_crawler.ts
import { Browser } from 'puppeteer';
import { Page } from 'puppeteer';
import { BaseCrawler } from './base_crawler';

export default class TestCrawler extends BaseCrawler {
    protected async crawl(_: Browser, page: Page) {
        await page
            .goto('https://www.uluru.biz/')
            .then(() => page.waitFor(1000));
    }
}
```

## npm run build
`./target/` にコンパイルされたJSファイルが出力される.
こいつらを実行しまくる.

## クローラー実行
直下で, 
`node target/index.js`
実行.

うるるにいける.
自宅ラボへのVPN接続


<h1>【はじめに】</h1> 
とりあえず、自宅にESXが準備できた。
あとは、おしゃれなカフェでコーヒーでも飲みながら、ESXにつないで検証できるようにしておきたい。

<h1>【目的】</h1>
・ESX上にVPNサーバを構築
・外部NWを経由してVPN接続
・SSH,デスクトップ操作を行う

イメージはこんな感じ↓
![f78a4133-s.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/639874/2a8bb2c4-d183-f8b3-2d81-d509fd41e578.jpeg)



<h1>【方法】</h1>
普段、情報収集もかねて活用させてもらっているサイトを参照しました。
<a href="https://www.server-world.info/">・Server World - ネットワークサーバ構築</a>
<a href="https://www.server-world.info/query?os=CentOS_7&p=openvpn&f=1">┗ OpenVPN</a>


また、今回はグローバルIPを発行していないので、ルータにポートフォワーディングを設定しました。
自宅で使用しているルータ（自宅では無線LAN）にログインして設定しました。
ルータに対して特定のポート宛て(図ではポート：1194)のアクセスが来た時、ESX上のVPNシステム（例. 192.168.2.253）にルーティングする設定を追加しておきます。
![002.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/639874/45eab9f2-6c7c-5697-2600-65746a9336b1.jpeg)


※<a href="https://www.idcf.jp/words/port-forwarding.html">ポートフォワーディングとは | クラウド・データセンター用語集／IDCフロンティア</a>



<h1>【結果】</h1>
無事、外部NWを経由してVPN接続することができました。
今回の構築でVPN、ポートフォワーディングについて再学習できました。
Gradle依存ファイルをcacheしてdocker buildを高速化する


# 要旨

- Gradle関係ファイルのみ `COPY` した状態で `gradlew build` を行うことで、依存ファイルをダウンロードしたキャッシュ用レイヤを作る
- Docker imageのビルド時間を約70%削減した（※環境・プロジェクトにより差はあります。）

# 動機

Spring BootアプリケーションのDocker imageのビルド時間が5分以上掛かっていました。
このため、検品環境へのビルド・デプロイに時間がかかってしまい、
検品環境でしかできない試行錯誤に時間がかかるという課題がありました。

# Sample Dockerfile

```Docker
FROM openjdk:11.0.8-jre-slim as builder

WORKDIR /app

# build.gradleに依存するファイルのみを追加し、
# gradle buildを空回しして依存ファイルをキャッシュする
COPY *.gradle gradle.* gradlew /app/
COPY gradle/ /app/gradle/
RUN ./gradlew build -x test --parallel --continue > /dev/null 2>&1 || true

# 以下の行以降でコードの変更を取り込みビルドする
COPY . /app
RUN ./gradlew build -x test --parallel

FROM openjdk:11.0.8-jre-slim

COPY --from=builder /app/build/libs/app.jar /app/app.jar
CMD ["java", "-jar", "/app/app.jar"]
```
Tips: multi-stage builds を利用し、ビルド用コンテナと実行用コンテナを分けています。

# 詳解
## 一般的なDockerfile例

よくあるGradle buildをするDockerfileは下記の様になると思います。

```Dockerfile
FROM openjdk:11.0.8-jre-slim as builder
WORKDIR /app
COPY . /app
RUN ./gradlew build -x test --parallel
```

このDockerfileの課題としては、ビルドのたびにgradleのバイナリや依存ファイルのダウンロードが行われるため、ビルドに時間がかかってしまいます。
今回はこのgradleのバイナリと依存ファイルのダウンロードをイメージのレイヤにキャッシュすることで高速化を行います。

## Gradleに依存ファイルをダウンロードするコマンドは無い
残念ながらGradleのコマンドにはバイナリや依存ファイルのダウンロードのみを実行するコマンドはありません。
しかしながらダウンロードはビルド実行時の冒頭で行われます。
そこでビルドが失敗する状態でもビルドを空回しすることで事前ダウンロードを行います。

```sh
$ ./gradlew build --continue > /dev/null 2>&1 || true
```

`--continue` のオプションを付けることで複数プロジェクトがあるビルドでも最後まで実行し、依存ファイルをダウンロードをすることができます。

## `COPY` コマンドのキャッシュ特性
`COPY`コマンドではファイルのチェックサムを元にキャッシュ利用の可否を検査します。
（※最終更新日やアクセス日時ではありません）
そこで gradle buildに最低限必要なファイルを `COPY` し、 buildを空回しすることで依存ファイルをダウンロードしたレイヤを作ることができます。
`build.gradle` 等は変更されることが少ないため、多くのビルド時にキャッシュを利用することができビルド時間の削減が見込めます。

```Docker
COPY *.gradle gradle.* gradlew /app/
COPY gradle/ /app/gradle/
```

# 削減効果
以上のGradle依存ファイルのキャッシュ利用をすることでDockerのイメージビルド時間を削減できると思います。
削減効果に関して、環境やJavaプロジェクトによって異なりますが、私の適用結果を共有しておきます。

適用前: `4min 56sec`
適用後: `1min 42sec`

今回の手法の適用によって約70％のビルド時間を削減することができました。

# 最後に

以上の手法で、少しでも世界のGradleを利用したDockerのイメージビルド時間が削減されれば幸いです。記述に間違い等がありましたら、コメントにてお知らせください。
IEEE829から学ぶテストドキュメント～⑤テスト項目移管レポート編～

#1．概要

計画、設計、ケース、手順書と続き、次は「テスト項目移管レポート」の説明になります。

ただ、この「テスト項目移管レポート」は現実的にほとんど作成されないドキュメントになります。
（私のこれまでの経験でも、現場で一度も見たことがありません…）

そのため、今回はIEEE829の「テスト項目移管レポート」の項目を説明しながら、なぜこのドキュメントが作成されないのか解説したいと思います。


#2．IEEE829のテスト項目移管レポートについて

移管という言葉を辞書で引くと、以下のような説明になっています。

- 移管　⇒管理を他に移すこと。管轄をかえること

また、参考書等を確認するとテスト項目移管レポートは「テスト対象ソフトウェア構成品のテスト環境への移管報告書」と記載されていたり、「リリースノート」と記載されていたりします。

まとめると、テスト項目移管レポートは以下2つの意味を持つドキュメントとなります。


- **テスト開始前**にテストする対象のソフトウェア管理を、検証担当者に移管するためのドキュメント
- **テスト完了後**にテストした対象のソフトウェア管理を、保守担当者に移管するためのドキュメント

そのため、IEEE829のテスト項目移管レポートは以下の項目を記載することになっています。

- 移管レポート識別番号
- 移管項目　⇒ドキュメント名やモジュール名等を記載
- 場所　　　⇒保管先のフォルダ名やチケット番号等を記載
- 状態：移管される項目の状態を記述　⇒検証済みなのか開発中なのか、担当者が誰から誰に変わるのか記載
- 承認
 

#3．現場で使われていない理由

現場で「テスト項目移管レポート」が作成されない理由は、恐らく以下であると考えています。

- ①担当者が変わらないので移管する必要がない
- ②別のツールで管理しているので、ドキュメント化する必要がない

###①担当者が変わらないので移管する必要がない

多くの場合、開発は開発、検証は検証と担当者がきちんと分けられ、責任者が決められています。そのため、開発工程が進む中で**移管するものがほとんどなく**、結果として作成する必要がなくなります。


###②別のツールで管理しているので、ドキュメント化する必要がない

一番作成されない理由は、ここだと思っております。

ソフトウェア開発では、エクセル等で管理せずに、GitだったりRedmine等の管理ツールを利用する場合が多いと思います。

そのため、**チケット等に移管担当者や移管項目が記載できるようになっている**ので、わざわざドキュメント化する必要がなくなります。


#4．まとめ

「テスト項目移管レポート」の内容は、おおよそ開発フローのどこかに含まれているので、ドキュメント化する必要がないものでもあります。

ただ、開発⇒検証⇒保守と工程が変わるごとに責任者が変わることがあるので、**責任者を
きちんとわかるようにしておくこと**、が重要な要素となります。
Andorid studio 外部からダウンロードしたファイルを使用時

外部からの画像ファイルを使用する時は
プロパティから画像使用を許可するように設定を行う。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211236/6a007be8-9140-d16f-3aa4-bd957e85ccdc.png)

そのあとに、ファイルをコピーして
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211236/69e766d1-75d2-60ee-9b31-3eb02fbd2ffa.png)
src/main/res/drawable のパスに貼り付けをして、いろいろ設定したら、アプリ作成用のフォルダ内に認識されるようになる。この時に、画像ファイル名に大文字の英語を使ってはいけない。
（この仕様が謎だ......名前の付け方はアンダーバーを利用するのが望ましい。）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211236/df842b52-639f-6db4-d820-e31477504063.png)
Geeksalon

８月からGeeksalonという学生限定のプログラミングサロンに入会することになりました。以前から、独学をしておりましたが、それでは厳しいことを実感し、入会することを決意いたしました。
教材は既におわり、もうすぐポートフォリオ作成に入りますが、自分の納得のいく成果物が作れるように精一杯努めて参ります。サロンに入ったことを後悔しないように、日々勉学に励む所存です。
クラウドの利用モデルの種類

クラウド環境を`「誰が」`、`「どこに構築し運用するか」`でクラウドの呼び方が変わってくる。

#パブリッククラウド
- `クラウド事業者がシステムを構築し、インターネット網などのネットワークを介して不特定多数の企業や個人にサービスを提供する形態`のこと。

- 事業者のポリシーに従わなくてはならないが、低コストで利用でき、運用管理の負担が少ない。

#プライベートクラウド
- クラウドサービスのユーザー側または事業者側のデータセンターに、`クラウド関連技術を活用した自社専用の環境を構築`して、コンピューティングリソースを柔軟に利用できる形態のこと。

#コミュニティクラウド
- `共通の目的を持った特定企業間でクラウドのシステムを形成し`、データセンターで共同運用する形態のこと。

#ハイブリッドクラウド
- パブリッククラウドとプライベートクラウド、コミュニティクラウドなどの各クラウドやオンプレミスシステムを連携させて活用するシステム／サービスのこと。
【初心者でもわかる】cssで文字を等間隔（均等割り付け）にしたり、数行の文章の右端がキッチリ揃う方法

#どうも7noteです。文字を等間隔にしたり、文章の右端を揃える方法です。

どうも7noteです。
この記事は以下へ引っ越しました。

https://naruweb.com/coding/equal-allocation/
stripeエンドポイント作成 php

stripe custom webhook
ダッシュボードがトリガー


```php:webhook.php
<?php
ストライプキー挿入
//
// Webhook の署名を確認する
// https://stripe.com/docs/webhooks/signatures#verify-official-libraries
//
$endpoint_secret = 'えんどポイントダッシュボードのエンドポイントにて';


$payload = @file_get_contents('php://input');
$sig_header = $_SERVER['HTTP_STRIPE_SIGNATURE'];
$event = null;

try {
    $event = \Stripe\Webhook::constructEvent(
        $payload, $sig_header, $endpoint_secret
    );
} catch(\UnexpectedValueException $e) {
    // Invalid payload
    http_response_code(400); // PHP 5.4 or greater
    exit();
} catch(\Stripe\Error\SignatureVerification $e) {
    // Invalid signature
    http_response_code(400); // PHP 5.4 or greater
    exit();
}

//
// $eventに対しての処理を行う
//
$event_json = json_decode($payload);
// $event_json = json_decode($payload);
//　ダッシュボードのテストでは0だからうまく行かない　ここら辺の
// $event_id = $event_json->id;
// try {
//     $event = \Stripe\Event::retrieve($event_id);
// } catch(\Stripe\Error\InvalidRequest $e) {
//     // Invalid payload
//     http_response_code(400);
//     exit();
// } catch(\Stripe\Error $e) {
//     // Invalid payload
//     http_response_code(400);
//     exit();
// }

if ($event->type == 'customer.created') {
}
if ($event->type == 'account.updated') {
  $account = $event->data->object;
  handleAccountUpdate($account);
  // var_dump($event_json);
}

//ここにうまくいったときと処理
if ($event->type == 'checkout.session.completed') {
dbやらメールなど
      var_dump($event_json);　



      
}

if ($event->type == 'customer.subscription.deleted') {
}

if ($event->type == 'customer.subscription.updated') {
}

if ($event->type == 'invoice.payment_succeeded') {
}

http_response_code(200);

function handleAccountUpdate($account) {
  // Fulfill the purchase.
  echo $account;
};
?>
```


Q.ユーザーが、アカウント作成の際にstripe様に運転免許等のIDを提出すると思うのですが、stripe様がそのIDを許可または許可しなかった行為を行われた際に、account.updatedのイベントが発生しwebhookで受け付けることは可能でしょうか？

A.はい、account.updated 、person.updated （Person API 使用の場合）で可能です。
身分証明書のカラースキャンまたは写真が Stripe のチェックを通ると、書類の要件が requirements[currently_due] から削除されます。その人物または企業のすべての確認要件を満たすと verification[status] フィールドは更新されて verified になります。また確認プロセスの完了時に account.updated Webhook 通知が届きます。

また、確認が失敗するとステータスは unverified となり details フィールドに理由を伝えるメッセージが表示されます。このメッセージは「提供された画像が読み取れません」のようにユーザに表示して問題ないものです。さらにこの応答には scan_not_readable のような details_code 値が含まれます。
失敗すると requirements[currently_due] が新しい身分証明書のアップロードが必要であることを示します。確認の期日が迫っている場合は、requirements[current_deadline] に日付が入力されている場合があります。また account.updated Webhook 通知が送信されます。

Q.また、https://stripe.com/docs/connect/identity-verification-api こちらを参照すた際に主にエラーが発生するのはユーザーのアカウント作成が主となっているようなのですが、銀行口座アカウント(external account)でもアカウント作成のようなエラーが発生し、エラーを解除しなければ送金ができないということは起こりうるのでしょうか？

A,連結されたアカウントでの入金アクティビティはすべて、Webhook を使用して追跡できます。入金固有の以下のイベントが発生します。
payout.created
payout.updated
payout.paid
payout.failed

入金を完了できない場合は、payout.failed イベントが発生します。このイベントの failure_code プロパティは理由を示します。また、入金に関与する銀行口座が無効になります。銀行口座が無効になるとaccount.external_account.updated 通知が起動します。プラットフォームが連結されたアカウントの銀行口座情報を更新するまで、自動入金も手動入金も完了できませんことご留意ください。
RefineryCMSの導入【Ruby on Rails】

https://www.farend.co.jp/blog/2019/01/refinerycms/
をほぼパクった自分用メモ。OSはMacです。
[Refinery公式](https://www.refinerycms.com/guides/installation-prerequisites)のガイドを見ながらすると簡単。
# 実行環境
Rails 5.1.6.1
refinerycms 4.0

[Refinery公式](https://www.refinerycms.com/guides/installation-prerequisites)のガイドを見て自分の環境を確認してください。

## インストール・プロジェクト作成
### gemのインストール
$ gem install refinerycms

### プロジェクト作成

#### ターミナル

    $ rails _5.1.6.1_ new プロジェクト名 -m https://www.refinerycms.com/t/4.0.0
RailsのVerを指定して作成

    $ cd プロジェクト名
    $ bundle exec rails db:create
    $ bundle exec rails db:migrate
    $ bundle exec rails db:seed
サーバー起動して確認。

    $ bundle exec rails s
公開画面
http://localhost:3000

管理画面
http://localhost:3000/refinery

## 設定
初期設定の変更をしていく。
#### サイト名の変更
config/initializers/refinery/core.rb

    # Site name
    - # config.site_name = "Company Name"
    + config.site_name = "自分のサイト名"

#### 日本語化

config/initializers/refinery/i18n.rb

    - # config.default_locale = :en
    + config.default_locale = :ja
    - # config.current_locale = :en
    + config.current_locale = :ja
    - # config.default_frontend_locale = :en
    + config.default_frontend_locale = :ja
    - # config.frontend_locales = [:en]
    + config.frontend_locales = [:ja]

さらに、seeds.rbの行頭にlocaleの設定を追加します。（これをしないとトップページの初期データが日本語化せず、編集できなくなります。） と書いてあるので変更する。

db/seeds.rb

    + I18n.locale = ::Refinery::I18n.default_locale
の後に

    $ bundle exec rails db:migrate:reset

    $ bundle exec rails db:seed
（http://localhost:3000/refinery） 日本語になっていたら完了。

## デザインテンプレートの作成
   
    #レイアウト
    $ bundle exec rails refinery:override view=layouts/application.html
    #ヘッダー
    $ bundle exec rails refinery:override view=refinery/_header.html
    #フッター
    $ bundle exec rails refinery:override view=refinery/_footer.html
    #Showページ
    $ bundle exec rails refinery:override view=refinery/pages/show
    #トップページ
    $ bundle exec rails refinery:override view=refinery/pages/home

デフォルトの状態では、turbolinksが有効になりますので、必要ない場合は、読み込みを削除します。
らしいので変更します。
app/assets/javascripts/application.js

    //= require rails-ujs
    - //= require turbolinks  ←これを消す。
    //= require_tree .

これで導入できました。
# 参照サイト
https://www.refinerycms.com/guides/installation-prerequisites
https://www.farend.co.jp/blog/2019/01/refinerycms/
pythonでinputを使って見よう

#記事の対象者
・inputを使って見たい人
・使い方でエラーが出て困っている人
※googlecolaboratoryでスクリプトを実行します。
#inputの使い方を知る
コードを先に書いてから解説します。

```python
age = input("年齢を入力してください")
typle(age)

# 実行結果
年齢を入力してください50

str
```

まず始めにinputの入力を保管する変数(ここではageを使っている)を作り=を使って入力結果を変数に代入しています。後はカッコ内に""で囲った入力を促すメッセージを入力したら完成です。しかしinputで帰って来る引数は全てstr型(文字列を格納する型)になっているのでそのままでは、数値を入力してその数値を元に計算する事が出来ないので、次のようなコードを打って見てくだいさい

```python
age = float(input("年齢を入力してください"))
type(age)

if age >= 20:
  print("大人だよーん！！")
else:
  print("子供だよーん！！")

# 実行結果
年齢を入力してください10
子供だよーん！！
```
inputの出力をfloat型で囲ってやる事で数値として扱う事ができるようになりました。最後にグラフを使って遊んで見ます。![スクリーンショット 2020-08-27 23.22.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/581846/a780a2d1-f664-640f-a024-1d44e4e4b9d7.png)
コードです貼り付けて実行して見て下さい。

```python
    import numpy as np
    import matplotlib.pyplot as plt

    # 変数を決める
    a = float(input("a * x - b to 'a'"))
    b = float(input("a * x - b to 'b'"))

    x = np.arange(-10, 10)
    y = a * x - b
    plt.ylim([-10, 10])
    plt.grid()
    plt.plot(x, y) 
```
スプレッド構文とRestパラメータを理解する

ES6で加わったSpread Operatorと Rest parametersがとても便利だと思ったので、記事にします。

日本語だと、
Spread Operatorはスプレッド構文
Rest parametersは残余引数（？）だそうです。
ちょっと後者は英語で覚えた方がなんかしっくりきます。

では書き方と機能について見ていきます。

##Spread Operator（スプレッド構文）

まずES５では、関数を呼び出して配列を引数に渡す際は、`apply()`メソッドを使ってました。

`apply(thisの参照先, 渡したい配列)`

```Javascript
function expenses (a, b, c, d) {
  return a + b + c + d;
}

var cost = [1000, 2500, 500, 3000];
var totalCost = expenses.apply(null, cost);
console.log(totalCost + '円'); //結果:7000円
```

これをES６のスプレッド構文で書くとシンプルです↓

```Javascript
function expenses (a, b, c, d) {
  return a + b + c + d;
}

var cost = [1000, 2500, 500, 3000];
var totalCost = expenses(...cost); 
console.log(totalCost + '円'); //結果:7000円
```

__関数(...配列の変数名)__と書くだけです。
applyでnullとか書かなくていいので、とても簡単になりました。
<br>

__『配列同士をマージしたい』__ という時も使えます。

```Javascript
const teamA = ['Mary', 'Mike', 'Jim'];
const teamB = ['Emily', 'Tony', 'John'];
const bigTeam = [...teamA, ...teamB, 'Taro'];
console.log(bigTeam);
//結果: ["Mary", "Mike", "Jim", "Emily", "Tony", "John", "Taro"]
```
最後に"Taro"を追加してますが、このように普通に追加も可能です。
<br>
__『配列をコピーしたい』__ という時も使えます。

```Javascript
const color1 = ['blue', 'red', 'yellow'];
const color2 = [...color1]
```
全く同じ内容になります。※コピーなのでcolor1は変更されません。
<br>

__『オブジェクト』__にも使えます。

```Javascript
const teamA = {mary: 'manager', john: 'player' }
const teamB = {mike: 'manager', will: 'player' }
const bigTeam = {...teamA, ...teamB}
console.log(bigTeam)
//結果：{mary: "manager", john: "player", mike: "manager", will: "player"}
```
ストーリーは意味不明ですが、マージできました。

<br>

##Rest Parameters（残余引数）

スプレッド構文とRestパラメータは同じように「...」を使うので見た目がそっくりです。
しかし働きは逆になります。

[MDN：スプレッド構文](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Spread_syntax)より引用してみると、以下の通り。

>こちらはスプレッド構文とは逆の働きといえます。スプレッド構文が要素を展開するのに対して、残余構文は複数の要素を集約して 1 つのオブジェクトに「濃縮」します。[残余引数](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Functions/rest_parameters)を参照してください。

ちょっと難しいですね。
あとで違いをまとめに書きますが、Rest Parametersのコードがこちら↓

```Javascript
function workYears (...joinYear) {
  joinYear.forEach(cur => 
    console.log((2020 - cur) >= 10))
}
workYears(1990,2000,1995,2015);
//結果：true,true,true,false
```

ここでは10年以上働いたかの結果をBoolean（true/false）で表示してます。
最後だけはfalseになってますね。

ES5で書くと、オブジェクトをループ(`forEach`や`for of`)で計算する時、配列に変換する作業が必要です。
※`for in`などは使えます。

しかし、Restパラメータを使うと自動で配列に変換してくれます！非常に楽ですね。

次の例↓

```JavaScript
const myObject = ({ name: Username, ...rest }) => {
  console.log(Username);
  console.log(rest);
}

myObject({name: 'Mike', age: 30, job: 'engineer'});
//結果: Mike
//結果: {age: 30, job: "engineer"}
```
こちらは引数にオブジェクトを渡してるんですが、`Username`以外は`...`restにして一つにまとめてます。
今回の場合`...rest`としてますが、`rest`部分の名前は何でもOKです。
でも引数に渡す場合はrestを使うのが慣例ぽいですね。

##まとめ

それぞれES5に比べてとてもシンプルに書けるので、是非使っていきたいです。
スプレッド構文とRestパラメーターの違いは、

__「場所」と「要素の扱い」が違う！__　ということでした。（以下詳細）

【場所】
スプレッド構文: functionを呼び出す時に
Restパラメーター: function宣言の時に

【value(要素)の扱い】
スプレッド構文: 配列から一つ一つvalueを変換する
Restパラメーター: 不特定数のvalueを受け取り、一つの配列に変換
JavaScriptで実装した自作ゲームをモニタでプレーする

# 本題について
折角作った自作ゲーム。それをパソコン楽しむだけでは勿体無いなと思い、
外付けモニタ・コントローラーを用いて、設定方法、実際に遊んだ感想を記載します。
※自作ゲームとは、自身がJavaScriptで実装したシューティングゲームです。

## 構成図
![Screen Shot 2020-08-27 at 23.04.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130301/c3280288-f638-8397-ce61-ed3bb2d5d102.png)
※ブラウザはChromeです。


## コントローラーの購入
[8BitDo® Zero 2](https://www.8bitdo.com/zero2/)を購入しました。
[マニュアル](https://download.8bitdo.com/Manual/Controller/Zero2/Zero2_Manual.pdf)は英語と中国語のみです。
初めてなので高機能ではなく、手軽に利用したい目的でした。

実際に購入した画像です。AirPods Proを側に置いてみました。
想定よりもかなり小さかったです。

![IMG_2584.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130301/62b4cf32-2e92-d105-dd5f-38e82bd81968.jpeg)



## コントローラーをBluetoothで接続
いくつかペアリング方法があります。([参考サイト](https://www.nukopuni.net/toa/8bitdo-zero-2のペアリングの仕方%E3%80%80%E3%80%80最小最強の補助デバ/))
以下5つのうち1つを選びます。
1. Switch
2. Windows「X-input」
3. Android
4. ｍacOS
5. キーボードモード 

ここでは5. キーボードモードを選択しました。

[ペアリングの接続設定]
1. [M]ボタン＋[START]ボタンを長押しする→点滅します
2. [SELECT]ボタンを3秒長押しする→点滅がさらに速くなります
3. [8BitDo Zero 2 gamepad]に接続する

![Bluetooth 2020-08-26 22-09-07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130301/51fd7086-18c9-7bea-eda4-0ee1a8f554b5.png)

今後、ペアリング開始・解除するときは以下になります。

[ペアリング開始]
1. [START]ボタンを押すとペアリングします

[ペアリング解除]
1. [SELECT]ボタン長押しでペアリング解除します

## Karabiner-Elementsアプリをインストール
ここの[サイト](https://karabiner-elements.pqrs.org)へアクセスして、アプリをダウンロード。
起動して、以下画面のようにキーボードとのマッピングを設定しました。
※キーボード側は自作ゲームの仕様にあわせてます。

![Karabiner-Elements Preferences 2020-08-26 22-25-31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130301/b52094ea-07a6-8112-844b-f01e883ba337.png)

## モニタに接続
MacBookからAppleTVへAirPlayでアクセス。
AppleTVからはBluetooth経由でSoundLink® Mini Bluetooth® speaker IIにつないでいます。
[BOSE製品へのリンク（私が持ってるのは旧モデルかと思います)](https://www.boss.co.jp/ja_jp/products/speakers/portable_speakers/soundlink_mini_ii_special.html#v=soundlink_mini_ii_special_triple_black)  

Chromeをモニターに持ってきて、コントローラーからアクセスできることを確認しました。

## 実際に自作ゲームをプレーしてみての感想

![IMG_2585.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/130301/da799442-b0eb-330e-bd5f-b645ad9ded22.png)

写真の感じで、実際にプレーしてみました。
Bluetooth接続のせいで 若干の遅延はしますが、普通にプレーできました。
BOSEスピーカーで迫力ある音を聴けて良かったです。

今回は22インチのモニタでしたが、もう少し大きいモニタも楽しんでみたいです。
あと、コントローラーはやはり小さすぎて、操作しづらかったでした・・・。笑。

### 追記

- 2020/09/25  
  macOS Catalina 10.15.7へアップデート  
  Karabiner-Elementsと、コントローラー共に動作確認済。
ノーコードツール「Glide」で飲食店アプリを圧倒的短時間で作ってみた

#サンプル
![一○堂 · ホーム · Made with Glide - Google Chrome 2020_08_27 15_50_12 (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/620192/36b619bf-f12b-a4f1-b5dd-5688dc274b6e.png)

今回私はGlideというノーコードツールで飲食店アプリを作成しました。
Glideで作成した飲食店アプリは、下記のURLから閲覧が可能です。是非ご覧ください。
https://deadpan-laborer-6969.glideapp.io/

このアプリはラーメン界で有名な一風堂をモデルに作成しています。


ちなみに制作時間は、実装以外に、設計、情報元サイトからのデータ取得等の作業を含めたらトータルで4時間から5時間です。

##なぜGlideでアプリを作成したのか

まず私は、大前提としてプログラミング歴が浅く、ましてやアプリ開発なんてしたことがないです。そんな私でもアプリを作ることできないか調べたところ、**Glide**というノーコードツールがありました。

Glideというノーコードツールは、
**スプレッドシートがデータベースの役割を果たしてくれて**、スプレッドシートに
**データを入力するだけでアプリを作ることができます.**

私はGlideを利用してアプリを3つほど作りましたが、断言できるのが,

**まったく開発経験の無い人間でもアプリを作る事が出来る。**
ということです。

今回は開発経験0の私がノーコードツールGlideを利用してみて、
・良かった点
・悪かった点
について、率直にレビューしていきたいと思います。

#そもそもノーコードツールGlideとは
簡単にglideのアプリの作成方法について説明すると、
①**googlespreadsheetに必要な項目を入力**
②記入したデータを基に**好きなパーツを選び、クリック操作で画面を作成**
これだけです！

この表現を見たら、簡単すぎないか？と思うかもしれませんが、本当にその通りで簡単にアプリが作れてしまいます。もちろん、構成やパーツについての知見は必要ですが。

そんなGlideですが、ノーコード界では少しずつ盛り上がりを見せています。

・コロナ渦の中、5000ダウンロードを突破して地域の飲食店を再起させた「いなぎお弁当マップ」
https://inagiobento.glideapp.io/

・高校生が中心となって災害情報についてまとめた　「災害情報　九州」
https://whether-info-kyusyu.glideapp.io/

など様々な事例があります。

#Glideの良い点
**1. 圧倒的短時間でアプリが作れる**
時間を掛けずに、短時間でアプリを作成できることは最大のメリットなのではないかと考えます。

スプレッドシートにアプリで必要なデータを丁寧に記入していけば、後は自動でスプレッドシートを読み込んでくれて、アプリの形は出来上がってしまいます。

そこから自分がイメージした構造をGlide内にあるコンポーネントを利用して作っていきます。

**2. コンポーネントが多種多様にある**
基本的なメールアドレス、電話番号、画像設置のためのコンポーネントはもちろんあるのですが、

その他にも、MAP、動画、コメント記入ボタン、購入ボタン、日付ボタンなど自分がこの実装したいなと思ったコンポーネントはだいたい揃っています。

画像をクリックしたら、外部のサイトに飛ばすことが出来たり、その項目の詳細を見れたりと、自分のアイデアを実現することが容易となります。

#Glideの気になった点

**1.オリジナルでデザインが加えられない**

先ほど私が取り上げた良い点で、コンポーネントが多種多様にあることを述べましたが、そのコンポーネントもオリジナルで改造して実装できません。別の言い方をすると、Glide内で作るアプリはデザインが同じような物になってしまうということです。

例えば、コンポーネントの中からボタンを選ぶとします。そのボタンというのも、押した後にサイトを飛んだり、詳細を見ることはできるのですが、
ボタンの形、大きさを変えることはできません。
(色に関しては、show as という項目から似たようなデザインに変更することは可能です。)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/620192/9623e31c-157d-32dd-6e9a-6acd99f80bc6.png)


１つ１つのパーツやページのデザインに、オリジナリティをもっと出したいのであれば、Bubbleのような自分で一から作り上げるツールを触れてみるのも１つの方法です。



**2.Map内の住所のピンがずれてしまうことがある。**

googlespreadsheetに住所を書き込めば、Map表示をするときに住所をピンで設置することができるのですが、住所が表示されなかったり、住所を指定したところに設置されないことが多々あります。

その解決策として、挙げられるのが緯度経度から住所を指定するという方法です。spreadsheetに住所と同じ緯度経度を記入することで、住所が表示されなかったり、ピンずれがなくなりました。
こちらで住所を検索すれば、緯度経度を取得できます。
https://www.geocoding.jp/




**3. spreadsheetに書き込んだ内容がGlideに反映されない場合がある**
下の画像を見て頂ければ分かるのですが、spreadsheetに追加した項目がGlide内のDataタブに反映されていなかったりします。。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/620192/260be32b-1bb0-72df-cf30-9d49183ef6a9.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/620192/a0a6aca5-6447-fb2b-8c5c-667a95985267.png)

時間が経てば、追加されるだろうと私も最初は思ってたのですが、結局アプリ作成終盤になっても更新されることはありませんでした。。

しかも１回だけ反映されていないというわけではなかったので、アプリを作る際は面倒ではありますが、既存のシートに反映されなかった項目を追加で書く等対策しなければなりませんね。

#終わりに
今回Glideで飲食店アプリを作ってみて、気になった点もありましたが、総合的には非常に良いノーコードツールだなと感じました。

スプレッドシートに記入するだけで短時間でアプリを作れることはとても便利でしたし、飲食店アプリ以外にも日常生活をより便利にするアプリも作ってみようと思います。

他にもアプリを作るためのノーコードツールや自動化や効率化ができるノーコードツールもあるので、そちらも実践を踏まえた上でQiitaに書いて行ければ良いなと思います。