OmniAICreator/Qiita-1.07M huggingface dataset:
AWS Application Composerを使ってみた

先日のre:InventでリリースされたAWS Application ComposerというAWSの新サービスを使ってみました。

## そもそもAWS Application Composerってなんぞ

AWS Application Composerはサーバーレスアプリケーションを構築できるビジュアルエディタです。
GUI上でポチポチするだけでテンプレートを生成してくれて、簡単にデプロイできるという代物。

## さっそくやってみた
### ①プロジェクトの作成
まずはコンソールトップからプロジェクトを作成します。
![AWS_Application_Composer.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/652172/6e23c03c-aa52-5f7f-1adf-0d8fbd67b6a8.png)

「Open Demo」を選ぶとAWS公式が用意したデモプロジェクトを使って作業ができます。
今回は自分でゼロから作りたかったので、「Create Project」をクリックします。

すると↓のようなモーダルが立ち上がります。
![AWS_Application_Composer.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/652172/34cde5dc-f784-eab8-6774-4df3a2931fa4.png)
すでにSAMテンプレートを持っている場合は「Load Existing Project」をクリック、今回はSAMテンプレートを持っていないので「New Blank Project」を選択

Local file system connection modeについて、「Connected」を選択すると、ローカル上のディレクトリと接続して自動で編集内容を反映してくれます。めっちゃ便利

### ②ビジュアルエディタからリソースを配置
今回はよくあるS3への画像アップロード時にリサイズをしてくれるアーキテクチャを構成します。
![AWS_Application_Composer.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/652172/d4ac3bb8-0798-42e7-ed00-db3949119dae.png)

### ③SAM CLIを使ってデプロイ
ConnectedモードにしていればローカルにSAMテンプレートが自動で構築されているはずなので、SAM CLIを使ってデプロイします。

SAM CLIの導入は公式ドキュメントを参考にしました。

https://docs.aws.amazon.com/ja_jp/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html

CLI導入後以下を実行します

```
sam build
```

```
sam deploy --guided
```

するとCloudformationを使ってリソースを構築するログが流れます。
問題なく完了すればリソースの構築が完了しています。

## 設定された内容の確認
### Lambda関数
![image-resize-app-Function-TjeX9Nx2koKD_-_Lambda.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/652172/78c203b1-5ad5-c8be-de3f-bfcda141b1af.png)

みた感じ、Lambdaのトリガーは自分で設定しないといけない感じでしょうか・・・
トリガーの設定までやってくれてたら便利そうでしたが、ApplicationComposerのコンソールにもトリガーを設定するような箇所はないので、SAMテンプレートに追記するなりLambdaコンソールから設定するなりする必要があるのかも・・・？

と思ってたところ↓の記事を参考にテンプレートを編集したところLambdaコンソール上でもトリガーが設定されていることを確認。SAMの仕様の問題ぽいね

https://qiita.com/cloud-solution/items/b7fbfd0b7672fb4fdc62

![image-resize-app-Function-TjeX9Nx2koKD_-_Lambda.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/652172/d13265f4-dd64-6e80-0924-5ce1385c53a0.png)

### S3

![S3_Management_Console.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/652172/d1e5aa48-a946-9eab-7a45-c39e1eb24891.png)

Application Composerから設定したバケットが登録されていることを確認

![image-resize-app-uploadbuc-957017051518_-_S3_bucket.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/652172/bd8cc552-2cf6-e870-b383-fd740d81391f.png)

パブリックアクセスをブロックすると画像のようなバケットポリシーが生成される

LambdaとS3を連携しているとイベント通知が設定される
![image-resize-app-uploadbuc-957017051518_-_S3_bucket.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/652172/17586e99-93f4-d2b3-2e00-2a5f497c7fc7.png)

あとはLambda関数に処理を書いて、バケットにオブジェクトをアップロードすればええ感じに使えるんじゃないかな！

## 感想
めっちゃ便利だけどSAMテンプレートを手動で書けるようになってから使った方が事故った時のデバッグとかしやすい気がするので、こういう便利ツールに頼りきりにならないようにしたい
Prologで16行でBasicインタプリタを作ってみた。

Pythonで書くと数百行かかるというような話をみて、Prologで書いたものあったよな。ないな。書いてみるかと思って書いてみました:

```prolog
a(V,G,[V|G]).
e(X,I,G,G):-member(X=I,G),!.
e(I,I)-->{integer(I)},!.
e(A+B,I)-->!,e(A,I1),e(B,I2),{I is I1+I2}.
e(X=E,V)-->!,e(E,V),a(X=V),!.
e(E1<E2,I)-->!,e(E1,I1),e(E2,I2),{I1<I2->I=1;I=0},!.
g(I:_,[I:E|Ls],[I:E|Ls]):-!.
g(I:_,[_|Ls],Rs):-!,g(I:_,Ls,Rs).
g(_:_,[],[]).
s(goto(I),_)-->{basic(P),g(I:_,P,Ls)},b(Ls).
s(X=E,Ls)-->!,e(E,V),a(X=V),b(Ls).
s(if(E,E1),Ls)-->!,e(E,V),({V=0} -> b(Ls);s(E1,Ls)).
s(print(E),Ls)-->!,e(E,V),{writeln(V)},b(Ls).
b([])-->!.
b([_:E|Ls])-->s(E,Ls).
run:- basic(P),b(P,[],_).
basic([
10:(a=0),
20:(print(a)),
30:(a=a+1),
40:(if(a<10,goto(20)))
]).
:- run.
:- halt.
```

SWI-Prologインストール、実行方法と結果
```
$ apt install swi-prolog
$ swipl a.pl
0
1
2
3
4
5
6
7
8
9
```


a/1 環境に追加
g/3 gotoの処理
s/4 文の評価
b/3 プログラムの評価
run/0 実行
basic/1 ベーシックのプログラム

最小限の機能しかないですが、これを元に拡張していけば何でも出来るようになると思います。
RubyでRot13問題

# 前提
ROT13は、暗号の一種です。
仮に文字列`test`を暗号化すると、13個先のアルファベットである`grfg`に変換されるものです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/264678/ea7d5d7a-5701-764a-c4c0-da707d963a3b.png)

# ROT13をRubyで実装
最初ソースコードを書いた際は、ROT13の変換パターンをhashでまとめて、文章の頭文字だけが大文字という条件下だったため、下記のコードのように大文字の場合だけ`capitalize`を最後当てるようにしてました。

```ruby
ALPHABET_HASH = 
  {"a"=>"n",
  "b"=>"o",
  "c"=>"p",
  "d"=>"q",
  "e"=>"r",
  "f"=>"s",
  "g"=>"t",
  "h"=>"u",
  "i"=>"v",
  "j"=>"w",
  "k"=>"x",
  "l"=>"y",
  "m"=>"z",
  "n"=>"a",
  "o"=>"b",
  "p"=>"c",
  "q"=>"d",
  "r"=>"e",
  "s"=>"f",
  "t"=>"g",
  "u"=>"h",
  "v"=>"i",
  "w"=>"j",
  "x"=>"k",
  "y"=>"l",
  "z"=>"m"}

def rot13(string)
  list = []

  strings = string.downcase.split('')
  strings.each{|s| ALPHABET_HASH.include?(s) ? list << ALPHABET_HASH[s] : list << s }

  string[0] == string.capitalize[0] ? list.join.capitalize : list.join
end
```

そもそも、hashで定義するパターンに大文字を入れれば良いことに気付いたので、修正後は結構すっきりなソースコードに

```ruby
ALPHABET_HASH =
{"a"=>"n", "b"=>"o", "c"=>"p", "d"=>"q", "e"=>"r", "f"=>"s", "g"=>"t", "h"=>"u", "i"=>"v", "j"=>"w", "k"=>"x", "l"=>"y", "m"=>"z", "n"=>"a", "o"=>"b", "p"=>"c", "q"=>"d", "r"=>"e", "s"=>"f", "t"=>"g", "u"=>"h", "v"=>"i", "w"=>"j", "x"=>"k", "y"=>"l", "z"=>"m", "A"=>"N", "B"=>"O", "C"=>"P", "D"=>"Q", "E"=>"R", "F"=>"S", "G"=>"T", "H"=>"U", "I"=>"V", "J"=>"W", "K"=>"X", "L"=>"Y", "M"=>"Z", "N"=>"A", "O"=>"B", "P"=>"C", "Q"=>"D", "R"=>"E", "S"=>"F", "T"=>"G", "U"=>"H", "V"=>"I", "W"=>"J", "X"=>"K", "Y"=>"L", "Z"=>"M"}

def rot13(string)
  strings = string.split('')
  strings.map{|s| ALPHABET_HASH.include?(s) ? ALPHABET_HASH[s] : s }.join
end
```

納得できるコードを書いた後、色々調べてみたところ`tr`メソッドを使えばこんなにシンプルにできたのか。。。

```ruby
string.tr("A-Za-z", "N-ZA-Mn-za-m")
```

# おまけ
定数のhashはこんな感じで作りました。大文字は後から追加したので別途upcase当てました。

```ruby
('a'..'z').to_a
key = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
value = ["n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m"]
ary = [key, value].transpose
h = Hash[*ary.flatten]

ALPHABET_HASH = 
{"a"=>"n",
 "b"=>"o",
 "c"=>"p",
 "d"=>"q",
 "e"=>"r",
 "f"=>"s",
 "g"=>"t",
 "h"=>"u",
 "i"=>"v",
 "j"=>"w",
 "k"=>"x",
 "l"=>"y",
 "m"=>"z",
 "n"=>"a",
 "o"=>"b",
 "p"=>"c",
 "q"=>"d",
 "r"=>"e",
 "s"=>"f",
 "t"=>"g",
 "u"=>"h",
 "v"=>"i",
 "w"=>"j",
 "x"=>"k",
 "y"=>"l",
 "z"=>"m"}

 ALPHABET_HASH.to_h{|k,v| [k.upcase,v.upcase]}
```
Railsをdockerで動かす（M1）


# 概要

M1チップのMacBook側で、rails6 on Dockerを試しました。
成功時の手順を記録します。

# 前提情報

- M1MacBook

- [Docker Desktop for Apple silicon](https://matsuand.github.io/docs.docker.jp.onthefly/desktop/mac/apple-silicon/) Version 4.15.0 

- ruby-3.1.2


# 構築までのメモ

アプリケーション用のディレクトリを切る

```
mkdir railsapp
cd railsapp
```

## 基本ファイルを用意

```
touch Dockerfile
touch Gemfile
touch Gemfile.lock
touch docker-compose.yml
touch entrypoint.sh
```

./Dockerfile
```
FROM ruby:3.1.2
RUN apt-get update -qq && apt-get install -y build-essential nodejs postgresql-client libpq-dev

RUN apt-get update && apt-get install -y curl apt-transport-https wget && \
wget --quiet -O - /tmp/pubkey.gpg https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - && \
echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list && \
apt-get update && apt-get install -y yarn

# install nodejs(LTS)
RUN curl -fsSL https://deb.nodesource.com/setup_lts.x | bash - && apt-get install -y nodejs

RUN mkdir /railsapp
WORKDIR /railsapp
COPY Gemfile /railsapp/Gemfile
COPY Gemfile.lock /railsapp/Gemfile.lock
RUN bundle install
COPY . /railsapp

COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
EXPOSE 3000

CMD ["rails", "server", "-b", "0.0.0.0"]
```


./Gemfile
```
source "https://rubygems.org"
gem "rails", "~>6"
```

./docker-compose.yml
```
version: '3'
services:
  db:
    image: postgres
    volumes:
      - ./tmp/db:/var/lib/postgresql/data    
    environment:
      POSTGRES_HOST_AUTH_METHOD: 'trust'    

  web:
    build: .
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/railsapp
    ports:
      - "3000:3000"
    depends_on:
      - db
```


./entrypoint.sh
```
#!/bin/bash
set -e

rm -f /railsapp/tmp/pids/server.pid

exec "$@"
```


## Railsプロジェクトの作成

```
docker-compose run web rails new . --force --no-deps --database=postgresql --skip-bundle
```


## ビルド

```
docker-compose build
```


## DB基本情報の記載

./config/database.yml
```
default: &default
  adapter: postgresql
  encoding: unicode
  # For details on connection pooling, see Rails configuration guide
  # https://guides.rubyonrails.org/configuring.html#database-pooling
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  host: db
  username: postgres
  password: xxxxxxxx

development:
  <<: *default
  database: railsapp_development
```

※実際運用する際は、passwordはベタ書きせず、最低限
gem 'dotenv-rails'
などを使用して.env（ignoreする）にて管理し、
```
password: <%= ENV['APP_DBPASS'] %> 
```
として運用する


## DB作成
```
docker-compose run web rake db:create
```

## webpackのインストール
```
docker-compose run web rails webpacker:install
```

## upして動作確認

```
docker-compose up
```

```
http://localhost:3000/
```

# 参考記事

https://mebee.info/2021/04/01/post-27926/


# 詰まった箇所（上記には反映済）

### GPG（GNU Privacy Guard）キー部分を更新

```
gpg: no valid OpenPGP data found.
```

↓参考にして更新
https://zenn.dev/junki555/articles/2de6024a191913

### Rubyやnodejsの対応バージョンをあわせる

はじめはnokogiriエラーがあったので
以下記事を参考にトラシューしたが、結果的にrubyとnodejsのバージョン変更で解決
https://regardie.dev/post-5126

### ほか
```
gem "net-smtp"
```

を足しても良いかも
BMI測定Webアプリ①

BMIWeb測定アプリを開発しました。
以下テストで実装したコードです。
改良版は適宜記事にいたします。

```html
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>健康アプリWebアプリ</title>
  <style>
    #answer {
      width:200px;
      margin-top:20px;
      color:#000;
      background-color: #FFF;
    }
    #res {
      margin-top:40px;
      width:500px;
      color:#F00;
      background-color: #5EF;
      font-size:30px;
      font-weight:bold;
    }
    #calc {
      width:120px;
      height:40px;
      color:#3791C4;
      background-color: #F7C806;
      border-radius: 1px #000;
      margin-top:20px;

    }

  </style>
</head>
<body>
  <script>
    function setcalc(myForm){
      var w_h = Number(myForm.height.value);
      var w_w = Number(myForm.weight.value);
      var result = w_w / ((w_h / 100) * (w_h / 100));
      return result;
    }
  </script>
  <form name="weight form" id="form1">
    <label>身長を入力してください。cmで記入</label><br>
    <input type="text" name="height" id="height"><br>
    <label>体重を入力してください。kgで記入</label><br>
    <input type="text" name="weight" id="weight"><br>
    <input type="button" id="calc" name="calc" value="計算する">
  </form>
  <div id="answer">
    BMI値を表示
  </div>
  <div id="res">
    判定を表示
  </div>
  <script>
    const height = document.getElementById('height');
    const weight = document.getElementById('weight');
    const form1 = document.getElementById('form1');
    const calc = document.getElementById('calc');
    const answer = document.getElementById('answer');
    const res = document.getElementById('res');
    var value;

    calc.addEventListener('click',function(){
      value = setcalc(this.form);
      answer.textContent = Math.floor(value);
      hantei1(value);
    },false);
    

    function hantei1(value1){
      if(value1 < 18){
        res.textContent = "痩せ過ぎです";
      } else if (value1 < 25){
        res.textContent = "普通体重です";
      } else if (value1 < 30){
        res.textContent = "肥満１度です";
      } else if (value1 < 35){
        res.textContent = "肥満２度です";
      } else if (value1 >= 35){
        res.textContent = "太りすぎです";
      }
    }
  </script>

  
</body>
</html>
```
アイトラッカーでウェブサイトを比較してみた

・アイトラッカーを使って列車予約サイトの比較をしてみた
・わかりにくいサイトでは、時間がかかり、視線の移動が多い

---------------------------------------

アイ・トラッカーを使って列車予約サイト２社の違いを調べてみました。

---------------------------------------

![npr212046-fig-0002-m.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/333980/ff47f639-2059-6ec2-bdbd-7d448f7243a7.png)
<h7><a ref = "https://onlinelibrary.wiley.com/doi/full/10.1002/npr2.12046"> Reference:　Wiley Online Library </a></h7>

アイ・トラッカーとは、カメラで得られた瞳孔の画像などを使って、人がモニター上のどこを見ているかを調べる機械です。

---------------------------------------

列車の予約サイトは全国に多数ありますが、その中から、ふたつ（A社とB社）を比較しました。

おおむねの予約の流れは、以下のようになっています。
（１）出発駅、到着駅、時刻を入力
（２）列車の種類（特急など）、切符の種類（指定席、自由席、など）を指定
（３）必要に応じて座席の指定
（４）購入手続き

---------------------------------------

今回、（２）の部分について、Sさん、Tさん、Uさんの、３人の視線の様子を調べました。

（２）以外の部分は、入力の順番や、入力のオプションが、かなり異なっていて、単純に比較できなかったからです。

---------------------------------------

![スライド1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/333980/3073659e-ad50-72c3-5d49-8e24dab2bc13.png)
まず、かかった時間（秒）です。Sさん、Tさん、Uさんとも、A社サイト（オレンジ）では、B社サイト（青）に比べて、２倍くらいの時間がかかっています。

---------------------------------------

![スライド2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/333980/9a151f06-c708-d05f-5016-77078906c0c6.png)
視線の移動回数です。専門用語でサッケードと呼ばれる目の動きですが、どの人も、A社サイトではB社サイトの２倍くらい視線が移動しています。

---------------------------------------

![スライド4.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/333980/4d31c095-32eb-094a-25b7-4ebcfe3d8ded.png)
視線の移動距離は、視線が、モニター上でどれくらいの距離を移動したかを表したものです。３人とも、A社のサイトでは、B社のサイトに比べて２倍以上の距離を移動していることがわかります。

---------------------------------------

![スライド3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/333980/c4265e63-0e59-cf2d-b853-260e58fe43cc.png)
マウスクリックの回数も、A社のサイトのほうが、かなり多いですね。

---------------------------------------

感想では、A社のサイトのほうが、B社のサイトよりも使いにくいとのことでした。

特に、切符の種類を入力するところで、どうしたらいいかがわからず、困っていたようです。

---------------------------------------

今回、アイ・トラッカーを使って、ユーザ・インタフェースに対する人の反応を、数値化できることがわかりました。

大きな違いが出るのは、なぜでしょうか？

---------------------------------------

実は、A社のサイトと、B社のサイトは、見た目に大きな差があるわけではありません。

しかし、人が使ったときには、明らかな違いが出てしまいました。

A社のサイトでは、視線が上下に大きく移動したり、

わかりにくいところを何度も繰り返し見たりする様子が伺えました。

---------------------------------------

人が使いやすいように改善していくためには、

違いの原因を丁寧に調べて、分析していくことが大切ですね。

---------------------------------------
Goでエンベロープ暗号化してみた

この記事はHRBrain Advent Calendar 2022 カレンダー2の9日目の記事です。

https://qiita.com/advent-calendar/2022/hrbrain

## はじめに

株式会社HRBrainでエンジニアをやっている深谷です。
この記事ではGoでエンベロープ暗号化を実装したことについて書いていこうと思います。

## エンベロープ暗号化とは
> エンベロープ暗号化とは、暗号化された鍵、つまりデータ暗号鍵とルート鍵を使用して機密データを保護するプロセスのことです。

https://cloud.ibm.com/docs/key-protect?topic=key-protect-envelope-encryption&locale=ja

簡単に説明すると
- コンテンツ
- コンテンツを暗号化する鍵
- その鍵を暗号化する鍵


以上を使用して機密データを安全に管理しましょうってことです。

一般的な暗号化方式では平文などのデータを様々な暗号化形式によって暗号化します。
しかしデータと暗号化したときの鍵があればもともとのデータが見えてしまいます。
エンベロープ暗号化では暗号化した鍵をさらに別の鍵で暗号化します。
なので一般的な暗号化方式より安全にデータを扱うことができます。


## 今回採用したもの
暗号化形式: `XChaCha20-Poly1305`
ChaCha20-Poly1305の拡張版。
暗号化にChaCha20とPoly1305を使用している。
ChaCha20は、AESよりも安全性が高いとされる暗号化アルゴリズムです。Poly1305は、暗号文の改ざんを防ぐためのメッセージ認証符号。

データ暗号鍵: `CEK`
CEK（Content Encrypting Key）は、暗号化されたデータを復号するための鍵。
暗号化されたデータを復号して、元のデータを復元することができる。

鍵暗号鍵: `KEK`
KEK（Key Encrypting Key）は、暗号化された鍵を復号するための鍵。
KEKは、暗号化された鍵を復号するために必要な鍵。

## 実装

1: コンテンツを暗号化するためのCEKを生成。
```go
const keySize = 32
func generateCEK() ([]byte, error) {
	key := make([]byte, keySize)
	if _, err := rand.Read(key); err != nil {
		// エラー処理
	}
	return key, nil
}
```
2: CEKを暗号化するためのKEKを生成。
ほぼCEKと処理が同じなので省略。
KEKの強度を上げる場合は、saltを用意して[argon2](https://pkg.go.dev/golang.org/x/crypto/argon2)を利用するといいかもです。

`argon2`
2015年7月に開催されたパスワードハッシュ競技会で優勝した鍵導出関数で、パスワードとsaltから暗号化キーを導出するために使用できます。


3: コンテンツをCEKとKEKで暗号化する関数を用意
```go
func encryptByKey(text []byte, key []byte) ([]byte, error) {
	aead, err := chacha20poly1305.NewX(key)
	if err != nil {
		// エラー処理
	}
	nonce := make([]byte, aead.NonceSize(), aead.NonceSize()+len(text)+aead.Overhead())
	if _, err := rand.Read(nonce); err != nil {
    	// エラー処理
	}
	encryptedMsg := aead.Seal(nonce, nonce, text, nil)
	return encryptedMsg, nil
}
```
4: encryptByKeyを適宜呼び出し、暗号化する
```go
func Encrypt(contents []byte) ([]byte, []byte, error) {
	KEK, err := getKEK()
	if err != nil {
		// エラー処理
	}
	CEK, err := generateCEK()
	if err != nil {
		// エラー処理
	}
    // コンテンツをCEKで暗号化
	encryptedData, err := encryptByKey(contents, CEK)
	if err != nil {
		// エラー処理
	}
    // CEKをKEKで暗号化
	encryptedKey, err := encryptByKey(CEK, KEK)
	if err != nil {
		// エラー処理
	}
	return encryptedData, encryptedKey, nil
}
```



復号化について、詳細は省きますが
1. KEKを再生成
1. 暗号化済みのCEKをKEKを使用して復号
1. 復号したCEKを使用してコンテンツを復号

以上の流れで復号化することが可能ですのでぜひやってみてください。

## まとめ
今回はGoでエンベロープ暗号化する一連の流れを紹介しました。

ということで、そんな弊社に興味を持った方がいればぜひ下記ページからご応募ください！

https://www.hrbrain.co.jp/recruit
IBM Cloud : SafariブラウザにCOSへのアップロード用のAspera機能拡張を追加

#### はじめに

IBM Cloud Object Storageに大容量ファイルをアップロードする際にAspera クライアントをMac PCに追加したログです。


----


#### 環境

・PC : MacOS
・Webブラウザ：Safari

アップロード先：IBM Cloud Object Storage の1 バケット




----
#### 実行内容

IBM Cloud へログインし、Object Storage のバケットからファイル・アップロードを選択すると以下の画面が出ます。
ここではAsperaの転送がまだ選択できません。


<img width=20%><img width="50%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/517421/bb333510-d08e-fd8b-bba1-a12f9248ea80.png">

上記画面の"Asperaのインストール"を押し Aspera クライアントをダウンロードします。
必須ステップが出てきます。Connect のインストールを押します。


<img width=20%><img width="50%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/517421/ea934835-7607-edaf-a83c-a1f1b94ef249.png">

ダウンロードしてきた "IBM Aspera Connect Installer" を押し導入します。


<img width=20%><img width="50%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/517421/164bb323-37f2-5c94-b0c7-3140647e93b2.png">

「開く」を押します

<img width=20%><img width="50%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/517421/bf57a4d6-91b0-aff3-b0e3-ff612ab7a977.png">

「開始」を押します。

<img width=20%><img width="50%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/517421/bb7a9e3f-9f80-677c-c8ec-6ad5782ca468.png">

<img width=20%><img width="50%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/517421/d1098fa3-33db-e371-d70b-3514a70a33dc.png">

インストールが完了後、ブラウザを立ち上げ直して再度Asperaインストールから必須ステップに移動します。
ステップ2の”機能拡張"を実行します。

<img width=20%><img width="50%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/517421/049b2efe-ab55-6f77-30d0-9c4e2057c74e.png">

Mac PC 側の許可設定が必要となりました。


<img width=20%><img width="50%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/517421/b1e8a4d7-48b2-0571-daf5-0fcd25e5eafc.png">

機能拡張をオンにします。

<img width=20%><img width="50%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/517421/d28397dc-3fc7-4dd5-0b4e-0e31e31deaf4.png">

<img width=20%><img width="50%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/517421/d6057336-0dfb-8279-a1b8-439a413fe7e7.png">

再度ブラウザを立ち上げ直し、IBM Cloud にログイン、対象のCOSバケットに移動、ファイルのアップロードを実行します。

Aspera が選択できるようになりました。

<img width=20%><img width="50%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/517421/76044018-7ff9-f109-7abc-77fafeef943e.png">

ようやく目的のファイルをアップロードできます。

<img width=20%><img width="50%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/517421/edc2b6f1-1e07-1f66-86db-8dec97033f11.png">



---

#### おわりに

参考情報：

API を使用してPython でCOSにAspera転送したい場合は以下が参考になるかもしれません。

https://github.com/ibm-cloud-docs/cloud-object-storage/blob/master/basics/aspera.md


以上です。
H2DB 予約後に関連するエラー

apiテストでh2ので以下のエラーが出た
```
org.h2.jdbc.JdbcSQLSyntaxErrorException: SQLステートメントに文法エラーがあります
```
原因 offsetがh2の予約語になっている。
```
create文..., OFFSET[*] NUMBER(5)
```

対応方法
該当の予約後をダブルクォーテーションで囲む

以下のリンクが非常に分かりやすいです。
[参考: h2.jdbc.JdbcSQLSyntaxErrorException:SQLステートメントに文法エラーがあります
](https://zenn.dev/rstliz/articles/69c1fd6c7401eb)
Oracleで正規表現検索

# やり方

```sql
SELECT * 
FROM テーブル名
WHERE REGEXP_LIKE(カラム名, '正規表現パターン')
```

# 空文字に注意

下記SQLの場合『自己紹介』カラムの **値が空文字のレコード** は結果に **上がってきません** 。

```sql
SELECT * 
FROM 従業員
WHERE NOT REGEXP_LIKE(自己紹介, '^私の戦闘力は[0-9]{8}です')
```

「値が空文字のレコードは正規表現にマッチしないから、検索結果に上がってくるだろう」
と思いこみで作らないように注意。

Oracleは『空文字をNULLとして扱う』という動作になっているので、値がNULLの場合も同様。

# バージョン

Oracle Database 11g Release 11.2.0.1.0 - 64bit Production
前職でのやらかしと教訓

前職で実際にやってしまったことやヒヤリハットについて色々経験し自分の中で教訓になっていることを紹介します。

# ファイルアップ時のヒヤリハット
前職ではサーバーにファイルをアップロードするのにFTPクライアントのFileZillaを使用していました。ドラッグアンドドロップでファイルをアップロードでき、とても操作しやすく便利なものでした。
ヒヤリハットが起きたときも特に変わった使用方法などせず普通に使用していました。
がしかしディレクトリを移動しようとフォルダのアイコンをダブルクリックしようとした際にマウスが動いていたせいか、フォルダアイコンの真下のファイルがドラッグアンドドロップでフォルダを移動させてしまったのです。
幸いなことに移動先のフォルダには同名のファイルが存在せず上書き等も行われずそのままファイルをもとの場所に戻して事なきを得ました。
もしファイルの上書きをしてしまいさらに対象のファイルのバックアップをもっていなかったらディレクトリの場所次第ですが大きな損害になっていたと思うと恐ろしいです。

操作が簡単だからと言って気を抜いて作業するのは絶対によくないです。サービスの運用にかかわるものを触るときは慎重に作業しましょう。あとバックアップはすごく大切です。

# フォームのチェックボックス（大惨事）
フォームの最後に注意事項を記載したスクロールできるボックスとその注意事項をちゃんと確認し同意しますか？というチェックボックスを実装したときの話です。
実装内容としては注意事項を最後までスクロールしてからでないとチェックボックスをチェックできないようにするというものでした。特に難しい実装もなく実装の内容としては、
注意事項の書かれた要素の高さを取得してその高さ分スクロールしたかをscrollイベントで取得して比較するような実装をしていました。
実装の確認もMac：Google、Safari、Firefox、Windows：Google、Edge、IE、Firefox、iPhone：Safari、Googleで確認しました。Androidのみ実機を所持していなかったのですが特にデバイスに依存するような実装じゃないので大丈夫だと思ってテストアップの報告をしました。
ディレクターからも問題ないというフィードバックを受け、本番に反映し、いざ応募を開始したところAndroidのユーザーからチェックボックスをチェックできなくて応募できませんとの報告を受けました。
もう応募を開始してしまっているため急いで修正するためチェックボックスをスクロールせずにチェックできるようにしディレクターに確認してもらいすぐ本番に反映しました。
できるだけ早く修正しましたがクライアントがとても大きいため短時間でも応募できなかったユーザーはどれだけいたのかわからず謝罪を行うような事態になってしまったのです。
確認するべきブラウザやOSについては契約の内容に含まれるものすべてで確認が必要なのにAndroidでの確認を疎かにしてしまったことで謝罪を行うような事態になってしまいました。
この件のあとから社内の確認フローにAndroidでの確認を必ずするようにと全体周知を行うようになりました。
自分はこの件のあとからブラウザ確認をしっかりするようになったことと、スクロールによる比較にはずれることがあるかもしれないと思い、できるだけスクロールの比較をするような実装をしなくなりました。
具体的にはwindow.addEventListener('scroll')をほとんど使用せずInterSectionObserverを使用するようになりました。
余談ですがscroll系の実装はGSAPかInterSectionObserverの使用をおすすめします。

# まとめ
- 簡単な作業でも動いているサービスを扱う場合は一つのミスが大きな損害になり得るので絶対にミスをしないように集中して作業を行う。
- 確認作業はしすぎるくらいにしよう。対応端末やOS、ブラウザについても確認しておきましょう。

短くなってしまいましたが前職のやらかしと教訓についてでした。
やらかしてしまうとずっと引きずってしまうことになるのでできるだけやらかさないように気を付けましょう。
JavaScript 基礎編 (通信と非同期処理)

# この記事の内容について
　フロントエンドの第一歩としてJavaScriptの基礎学習を始めました。アウトプットとして、JavaScriptのオブジェクトやDOM操作などをまとめていこうと思います！
　私はまだエンジニア歴1年未満の初学者なので、間違い等があればご指摘いただけると幸いです。

# JavaScript 基礎編
* [ブラウザオブジェクト / DOM](https://qiita.com/Nao52/items/c6b7531b85a5e4a6c8dc)
* [イベント](https://qiita.com/Nao52/items/6705eeca68a77b3f280a)
* [通信と非同期処理](https://qiita.com/Nao52/items/3ae127867cee0f838643)
* [ミニアプリの開発](https://qiita.com/Nao52/items/ed9f64a9b1c1da91abc0)

# JavaScript 応用編
* [モダンなJavaScriptの機能](https://qiita.com/Nao52/items/5ee9c2af96b4e9dfd278)

# 効率的なページ遷移
### 通常のWebサイト
1. ブラウザからサーバーへURLをリクエストする
1. サーバーは必要な情報をブラウザへ渡す
1. ブラウザはファイルを受け取って画面にページを描写する

　ページ自体が全く異なるものであれば問題ないが、大部分は同じで一部分だけが異なるページへ遷移する場合は、全てのファイルを読み込み直すのは**とても非効率**であり、異なる部分だけをサーバーから受け取れば効率的である。
　その問題を解決するため、JavaScriptから必要なデータのみを取得し、ページを部分的に書き換える手法を **Ajax(エイジャックス)** と呼ぶ。

### データ形式JSONについて
　JSONは人間に読み書きがしやすいデータ形式で、JavaScriptの記法をベースにしているため親和性が高く、よく使用されている。
#### JSONの記法例
```
{
"name" : "tarou",
"languages" : ["JavaScript", "PHP", "Phython"]
}
```
　全体を波括弧({})で囲み、その中にコロン　(:) で区切られたキーと値の組み合わせを並べるのが基本的な型である。キーと値の組み合わせは、末尾のカンマ (,) で区切りがつけられている。キーと値に使える文字に制限はないため、日本語でも構わないが基本的には英字で統一した方がコードが書きやすい。
　また、キー名はダブルクオーテーション (") で囲む必要がある点は注意だ。

# 非同期処理
### 同期と非同期
　一般的にプログラムは書いたコードの順番通りに上から下に実行される。一番最初のコードが完了するのを待ってから、下の行に移動し次のコードを実行していく。これを**同期処理**と呼ぶ。それに対して、コードの完了を待たずに次のコードを実行することを**非同期処理**と呼ぶ。

```javascript:同期処理を再現する
// アラートが表示され、OKを押して閉じると、コンソールに「ログを出力」が表示される。
function syncAlert() {
  alert('アラートを表示');
  console.log('ログを出力');
}
syncAlert();
```

```javascript:非同期処理を再現する
// アラートが表示されたときに、コンソールに「ログを出力」と表示される。
function asyncAlert() {
  setTimeout(function () {
    alert('アラートを表示');
  }, 0);
  console.log('ログを出力');
}
asyncAlert();
```

# 非同期通信 
### fetch（)通信の書き方
```javascript
fetch(通信したいURL).then(function(response) {
    return response.json();
}).then(function (json) {
    // 任意の処理
    console.log(json);
})
```
```html:JSONファイルから文字列を受け取るWebページ
<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8">
</head>

<body>
  <div class="result"></div>

  <script>
    fetch('http://127.0.0.1:5500/15/sample.json').then(function (result) {
      return result.json();
    }).then(function (json) {
      const result = document.querySelector('.result');
      result.textContent = json.text;
    })

  </script>
</body>

</html>
```
### async(アシンク) / await(アウェイト)で非同期処理を簡単に書く
```html:async / awaitで書き換える
<!DOCTYPE html>
<html>

<head>
  <meta charset="UTF-8">
</head>

<body>
  <div class="result"></div>

  <script>
    // async / awaitを使わない書き方
    fetch('http://127.0.0.1:5500/15/sample.json').then(function (result) {
      return result.json();
    }).then(function (json) {
      const result = document.querySelector('.result');
      result.textContent = json.text;
    })
    // async / awaitを使用した書き方
    async function showJsonText() {
      const response = await fetch('http://127.0.0.1:5500/15/sample.json');
      const resultBox = document.querySelector('.result');
      resultBox.textContent = json.text();
    }
    showJsonText();

  </script>
</body>

</html>
```
NetBSD/armの割り込み

armは割り込みは実際使うのは1本でそれをプログラマーブルインターラプトコントローラ(PIC)で複数にします。

armv7(?)でPICが標準化されていますが、それ以前はSOC個別のPICでした。

armv5tなRT1310の割り込みは以下のようになっています。

![arm_intr.png](https://qiita-image-store.s3.amazonaws.com/0/104066/3012765f-cec8-4667-21f3-478132f748b0.png)

CPU側の割り込みのON/OFFとPICの割り込みマスクを使って制御します。

mipsでは5本(+タイマー)あってそのどれかにPICをつけたり、一つの割り込みで複数受け付けて5つでまにあわせるケースもありました。

デバイスがCPUに割り込みをあげると、決められた物理アドレスの命令に実行が強制的に移ります。その後ごにょごにょして、仮想アドレスのハンドラを呼び出して処理を行い、処理が終ったら強制的に移ったところに戻ります。

FreeBSDは割り込みは全アーキテクチャ共通で、実際の割り込みでの処理と、スレッドでの処理の二つに分けることができます。リアルタイムで処理しなくていいも物はスレッドで処理するようになっています。実際はどちらかしか使っていないケースが多いです。割り込みはCPU資源が大きいのでそうしているようです。このような構成からFreeBSDでは多重割り込みはサポートしてないと思います。

NetBSDではアーキテクチャ別に割り込み処理がありarmでは二つには分けていなくて、一つの処理として実行されるようです。また優先度の設定があるようです。この優先度によって多重割り込みを許可しているようです。

まず割り込みコントローラーのデバイスは最初にattachするように調整します。

デバイス側は、以下のように割り込みルーチンを登録します。

```
intr_establish(sc->sc_irq, IPL_SCHED, IST_LEVEL, sc->irq_handler, NULL);
```

この関数の実態は、sys/arch/arm/pic/pic.cにあります。

カーネルのビルドオプションでARM_INTR_IMPLでヘッダーファイルを指定して、その中でARM_IRQ_HANDLERで大本のハンドラの関数を指定します。

デバイスのハンドラの呼び出しはpic_dispatch()を使ったもの(apple,cortex,imx)と
pic_do_pending_ints()を使ったもの(apple,broadcom,cortex,gemini,imx,marvell,sunxi,ti)がありました。これより前はpicはなく独自実装だったようです。

ブート後に割り込みが有効になるのはarch/evbarm/autoconf.cのcpu_configure()の最後です。

NetBSDのコードがいけてないと思うのは以下のようなところです。

```c:pic.c
void
pic_do_pending_ints(register_t psw, int newipl, void *frame)
{
        struct cpu_info * const ci = curcpu();
        if (__predict_false(newipl == IPL_HIGH)) {
                KASSERTMSG(ci->ci_cpl == IPL_HIGH, "cpl %d", ci->ci_cpl);
                return;
        }
#if defined(__HAVE_PIC_PENDING_INTRS)
```

pic_do_pending_ints()の中で#if defined(__HAVE_PIC_PENDING_INTRS)とか、なにをしたいのか、よく分からないです。

この割り込み処理は必要以上に複雑になってよくないと思います。最近の高速化したCPUにおいては出来るだけ割り込み処理は軽くするのがOSのセオリーなのに時代に逆行した実装にも見えます。

Comcertoの対応を実装していて、このSOCのPICには割り込み優先度の機能があり、ソフトでやる必要はなさそうです。

理想としてはプレーンな実装をまずつくり、必要なら優先度の処理がオプションで使えるようにするのでしょうか。

多重割り込みが必要になるのは、そもそもシステム設計の時点で問題があります。

BSD小僧さんも調べられていました。

http://www.tokuda.net/diary/0832

uart割り込みとかは複雑なので、割り込み処理はタイマーで確認するのが分かりやすいです。

タイマー割り込みがちゃんと動くと、ブーとログの時間の表示が更新されるようになります。適当な値でタイマーを動かして確認し、値は後から直すのがいいです。

~~もちろんプライオリティを無視してハンドラを実装する事もできます。ターゲットによってはその方が良いケースもありそうです。~~ 動く事もあるのですが、おかしな動きをすることもあるようなので、他と合わせたほうが無難なようです。

多重割り込みはプライオリティを元に処理しているようです。以下のようなことをやってると思われます。

他の割り込みがなければそのままハンドラは処理をして終了

割り込み中に割り込みが発生したが、プライオリティの低い割り込みの場合 -> 割り込みは処理をせず抜けて、元の処理を続行して完了後、多重割り込みした割り込み処理を行う。

複数段多重割り込みが発生した場合は、プライオリティで整理。

割り込み中にプライオリティの高い割り込みが発生 -> そのまま処理して終ったら元の割り込みにもどる。

この仕組みがいけてないと思うのは以下のようなことです。

* 割り込みはキャッシュを破壊するので、キャッシュを元にパフォーマンスを向上させてる近代のCPUに不向き
* ハードウエアでもプライオリティ処理があることがおおいので、わざわざソフトでやることはない
* 割り込みのようなクリティカルな処理は複雑にすべきではない
* 参照実装がないし、かなりばらばらに実装されてちゃんと動くのか疑問

RT1310のポートをしていて、多重割り込み禁止で実装したところsoftintrとuartの受信割り込みまわりで、暴走してしまい正常に動かなかったので、標準の実装方法にしました。
無料で使えるAPIを紹介

皆さんこんにちは。

今日はフロントエンドで使えそうな、ポートフォリオのプロジェクトで使えそうな無料のAPIを紹介します。

真面目なものから、ふざけたものまで色々集めたので是非、使ってみてください。

良かったら自分でホスティングしているサイトとYouTubeがあるので他の記事も見てみてください。
[<img src="https://asameshicode.com/wp-content/uploads/2022/12/asameshiLogo.jpg">](https://asameshicode.com/)

https://www.youtube.com/channel/UCiVt4Mcnog4KBEOALesuu1g

## **NASAの宇宙API**

ユーザー登録が必要です。

日替わりの宇宙画像とかがあるそうです。

[https://api.nasa.gov/index.html](https://api.nasa.gov/index.html)


## **天気予報API**

天気情報のAPIは誰しもが使うマストなAPIですね。簡単な天気アプリとかに使えそうです。

これもユーザー登録が必要になります。

[https://openweathermap.org/api](https://openweathermap.org/api)


## **米国株式のAPI**

Polygon.ioというところが提供しているAPIです。GitHubで登録してAPIキーを手に入れた後にAPIにアクセスできるようです。


---


## **ユーザー登録なしで使えるAPI**

ここから、ユーザー登録が不要ですぐに使えるAPIを紹介します。


## **ポケモンAPI**

みんなの大好きなポケモンのデータがAPIになりました。

[https://pokeapi.co/](https://pokeapi.co/)

参考URL:　[https://pokeapi.co/api/v2/pokemon/charizard](https://pokeapi.co/api/v2/pokemon/charizard)


## **カクテルAPI**

カクテルのレシピがAPIになってます。

[https://www.thecocktaildb.com/api.php](https://www.thecocktaildb.com/api.php)

サンプルURL:[https://www.thecocktaildb.com/api/json/v1/1/search.php?s=margarita](https://www.thecocktaildb.com/api/json/v1/1/search.php?s=margarita)


## **ビットコインAPI**

クリプトのAPIです。CoinBaseが提供しています。

[https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-users#data-endpoints](https://docs.cloud.coinbase.com/sign-in-with-coinbase/docs/api-users#data-endpoints)

サンプルURL:[https://api.coinbase.com/v2/currencies](https://api.coinbase.com/v2/currencies)


## **為替API**

為替のレートのAPIです。

[https://www.coingecko.com/en/api](https://www.coingecko.com/en/api)

サンプルURL:[https://api.coingecko.com/api/v3/exchange_rates](https://api.coingecko.com/api/v3/exchange_rates)


## **アメリカの統計**

アメリカの人口や統計がデータになったAPIです。

[https://datausa.io/about/api/](https://datausa.io/about/api/)

サンプルURL:　[https://datausa.io/api/data?drilldowns=Nation&measures=Population](https://datausa.io/api/data?drilldowns=Nation&measures=Population)


## **犬の画像**

ランダムで犬の画像が表示されます。

[https://dog.ceo/dog-api/](https://dog.ceo/dog-api/)

サンプルURL:[https://dog.ceo/api/breeds/image/random](https://dog.ceo/api/breeds/image/random)


## **アニメAPI**

アメリカで有名なMyAnimeListの非公式のAPIです。

[https://jikan.moe/](https://jikan.moe/)

サンプルURL:　[https://api.jikan.moe/v4/anime?q=naruto&sfw](https://api.jikan.moe/v4/anime?q=naruto&sfw)


## **本のAPI**

OpenLibraryという組織で提供している本のAPIです。

[https://openlibrary.org/developers/api](https://openlibrary.org/developers/api)

サンプルURL:　[http://openlibrary.org/api/volumes/brief/isbn/9780525440987.json](https://openlibrary.org/api/volumes/brief/isbn/9780525440987.json)


## **ランダムユーザーAPI**

自動でユーザーを生成してくれるAPIです。

[https://randomuser.me/](https://randomuser.me/)

サンプルURL:　[https://randomuser.me/api/](https://randomuser.me/api/)

とりあえず、これだけあれば次のプロジェクトの参考になるのではないでしょうか？

お疲れ様でした。
nodeのバージョンを下げる

Error: Node Sass does not yet support your current environment: OS X 64-bit with Unsupported runtime (111)
For more information on which environments are supported please see:
https://github.com/sass/node-sass/releases/tag/v4.14.1

こういうエラーでた

↓


brew unlink node
brew install node@14
brew link --overwrite node@14
npm rebuild node-sass
お名前.com SDレンタルサーバーでWordPressインストール手順

# 基本環境
お名前.com SDレンタルサーバー
ドメインをお名前.comで取得済み

# お名前.com Naviにログイン

https://navi.onamae.com/top

# ドメインネームサーバー設定

 上部メニュー「ネームサーバーの設定」　＞　「ネームサーバーの設定」

設定するドメインの左にチェックマーク

「お名前.com各サービスを利用」タブを選択

「レンタルサーバー SDプラン、お名前メールのネームサーバーを使う」右横の「設定する」ボタンをクリック

「ドメインプロテクションでセキュリティ強化しませんか？」　＞　「申し込まない」

「ネームサーバー情報」
１）dns01.gmoserver.jp
２）dns02.gmoserver.jp
「設定する」をクリック

# ドメインをレンタルサーバーに紐付け

 上部メニュー「レンタルサーバー」　＞　「利用レンタルサーバー一覧」

紐付けしたいサーバーの「ドメイン追加」をクリック

「お名前.comで契約済みのドメイン」ラジオボタンを選択し「次へ」

紐付けしたいドメインにチェック→「ネームサーバーを変更しない」ラジオボタンを選択→「確認」

「確定」をクリック

# SSL設定

コントロールパネルにログイン（お名前.com Naviとは別ページ）

https://cp.rentalserver.jp/Login.aspx

「SSL設定」を選択

設定したいドメインをプルダウンで選択→「新規作成」

「確認画面へ進む」

「決定」

反映までしばらく時間がかかります

# データベース作成

コントロールパネル「MySql」

「新規作成」

作成後以下を保存

・データベース名
・ユーザー名
・パスワード
・ホスト名

# ディレクトリ作成

WordPressをインストールするディレクトリ/隠しディレクトリをFTPかSSHで作成

```:例
example.com/hide
```

# WordPressファイルダウンロード＆アップロード

https://ja.wordpress.org/download/

FTPでexample.com/hideへアップロード

「hide」「wp-content」以下のファイルパーミッションを705に変更

# ブラウザでアクセス

https://example.com/hide/
（WordPressをアップロードしたディレクトリ）

以下を入力
・データベース名
・ユーザー名
・パスワード
・ホスト名

「インストール実行」

新規設定する
Magento2 日本語化の元データ


カスタムテーマを作成して、日本語訳の微調整を行いたいとき、もともとの（日本語ロケールの）翻訳元文章と翻訳結果が分かっていると便利です。そのファイルは

```
/path/to/magento/vendor/magentoj/language-ja_jp/ja_JP.csv
```
に存在しています。ただしこのファイルを直接修正するのはMagento2の設計思想上NGです。カスタムの日本語訳を行いたいときはカスタムテーマを作成して、そのうえで行いましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/56044/4fd4257a-69d1-4ab3-e587-72a65f8fa29e.png)

参考文献 
- [Magento2:テーマコンポーネントから日本語表示調整](https://magento.szmake.net/page-adjustment-tips/creating-original-theme-ja_jp-file/)
Sudachi辞書の紹介 Part 3　-分割モードおよび分割情報-

『Sudachi辞書の紹介』の続きです。


これまで、[第1回の記事](https://qiita.com/sakamoto_mi/items/4b55898aa221c290f411)、[第2回の記事](https://qiita.com/sakamoto_mi/items/c1787973dd1a591c9957)で、登録単位や品詞について概観し、small辞書に比べ、core辞書やfull辞書は、複合語が多く登録されていること、さらにfull辞書には固有名詞が多く登録されていることなどを見てきました。
第3回では、Sudachiの分割モードおよび分割情報について紹介します。


## 3つの分割モード

Sudachiには、[A, B, C, 3つの分割モード](https://github.com/WorksApplications/Sudachi)があり、辞書登録されている複合語を、短い単位に分割することができます。

それぞれの分割モードの違いをざっくり言うと、
* Aモードでは最も短い単位に分割します。（以降これを"A単位"と呼称します）
* Bモードでは接辞付き相当の長さに分割します。（以降これを"B単位"と呼称します）
* Cモードでは分割しません。登録されている長さのまま出力します。（以降これを"C単位"と呼称します）

例）
|登録単位|Aモード|Bモード|Cモード|
|:-------|:-----|:-------|:-----|
|東京国立博物館|東京|東京|東京国立博物館|
||国立|国立||
||博物|博物館||
||館|||


さて、Sudachi辞書における"最も短い単位"（A単位）とは、どういう長さのことでしょうか。
UniDicの短単位とどう違うのでしょうか。
また、3つの分割モードによって得られる単位（A単位、B単位、C単位）は、どういう方針で設計されているのでしょうか。
これらについて見ていきたいと思います。


## UniDicの短単位

まず、UniDicの短単位についてポイントを確認しておきましょう。

UniDicの短単位とは、
「BCCWJからの用例収集を目的として」(*1)、「言語の形態論的側面に着目し、下で述べる最小単位を基に斉一性を重視して規定された言語単位（単位語）」(*1)
です。
最小単位による短単位の認定規則は、

>和語・漢語は、２最小単位の１次結合体を１短単位とする。 ｜母=親｜ ｜食べ=歩く｜ ｜言=語｜資=源｜ ｜研=究｜所｜ ｜本=箱｜作り｜
>外来語は、１最小単位を１短単位とする。 ｜コール｜センター｜ ｜オレンジ｜色｜

となっています。
＜図１＞『短単位 - 短単位の認定規定』の図から引用(*1)
![unidic_tantani.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2513630/a61d6231-bee7-633f-fff2-fbfc10d01b7e.png)

(*1)https://clrd.ninjal.ac.jp/unidic/glossary.html#suw

UniDicの開発目的はコーパスに基づく用例収集や語彙調査、そのために重視されているのが、形態論的斉一性です。


## Sudachi辞書の開発方針

Sudachiは、「既存の形態素解析器に不足する柔軟性や精度を兼ね備えた商用利用に耐えうる形態素解析器」(*2)を目指して開発をスタートしました。
(*2)https://www.worksap.co.jp/news/2022/1007/
商用利用として最も重視しているのは検索エンジンです。

### A単位

検索では、常に、検索漏れとノイズの問題がつきまといますが、UniDicの斉一な短単位では、不向きなものがあります。
例えば、和語は、漢語と異なり最小単位が自立語として使用されることが多いため、最小単位で形態素認定した方が検索漏れが少なくなる場合があります。
そのため、SudachiのA単位には、UniDicの短単位をさらに短くしたものがあります。

例）
|UiDic短単位|A単位|
|:-----|:-------|
|子クジラ|子|
||クジラ|
|うがい薬|うがい|
||薬|
|仮住まい|仮|
||住まい|
|右ふくらはぎ|右|
||ふくらはぎ|
|梅雨時|梅雨|
||時|
|錆び付く|錆び|
||付く|


逆に、UniDicの単位が短すぎて、検索ノイズが発生するものがあります。それらは一塊でA単位としています。

例）
|UiDic短単位|A単位|
|:-----|:-------|
|自転|自転車
|車||
|太平|太平洋|
|洋||
|スマート|スマートフォン|
|フォン||


つまり、Sudachi辞書における"最も短い単位"であるA単位は、検索での利用を強く意識したものです。


### B単位

B単位は、A単位に接辞相当の語が付いた長さです。
これは、『広辞苑』など、国語辞典の見出しの長さに近いものと位置付けています。

例）
|A単位|B単位|
|:-----|:---|
|光熱|光熱費|
|費||
|総|総決算|
|決算||
|駆け|駆け回る|
|回る||


### C単位

C単位は、Sudachi辞書に登録されている語の長さです。単独の語、複合語、略語、慣用句…等、すべてを含みます。


:::note info
A単位は、検索用の短い単位、B単位は、国語辞典の見出しに近い日本語として自然な単位、C単位は、Sudachi辞書に登録している語の長さそのもの、となります。
:::


UniDicに見られるような明確な形態論的斉一性は、Sudachi辞書にはありません。代わりに、専門の辞書開発者によりチューニングされた3種類の辞書と分割モードを提供しています。
では、斉一性が必要とされるコーパスからの用例収集や語彙調査を行いたいときはどうすればよいのでしょうか。
その場合は、「small辞書 + Cモード」を使えば、UniDic相当の解析結果が得られます。


## 分割情報

分割モードに関わる情報は、分割情報としてSudachi辞書に格納されています。
分割情報とは、見出しを"A単位"または"B単位"に分割するための内部構造を記述したものです。

例）
|見出し|A単位分割情報|B単位分割情報|
|:-----|:---|:---|
|東京国立博物館|東京/国立/博物/館|東京/国立/博物館|
|東京|--|--|
|国立|--|--|
|博物館|博物/館|--|

※"/" は、構成語の境界

「東京国立博物館」は、Aモードでは、「東京」「国立」「博物」「館」のA単位に分割されます。Bモードでは、「東京」「国立」「博物館」に分割されます。
分割情報を持たない「東京」「国立」は、A,B,Cどの分割モードでも分割されません。つまり、A単位、B単位、C単位がすべて同じ長さとなります。
「博物館」は、A単位分割情報のみ持っていますので、Aモードでは、「博物」「館」に分割されます。Bモード、Cモードでは分割されません。



今回は、Sudachiの分割モードおよび分割情報の概要を紹介しました。
次回は、分割情報について、もう少し具体例を上げて、紹介したいと思います。
Amazon Connect の予測、キャパシティプランニング、スケジューリング機能が一般提供(GA)されました！！

**この記事は株式会社ナレッジコミュニケーションが運営する [クラウドAI by ナレコム Advent Calendar 2022](https://qiita.com/advent-calendar/2022/knowcom-cloudai) の9日目にあたる記事になります。**

# はじめに
AWS re:Invent 2022にて、Amazon Connect の予測、キャパシティプランニング、スケジューリング機能が一般提供開始(GA)されると発表されました。

※現在、米国東部 (バージニア北部)、米国西部 (オレゴン)、アジアパシフィック (シドニー)、欧州 (ロンドン) リージョンで利用できます。
東京リージョンは未対応です。

[公式ブログ](https://aws.amazon.com/jp/blogs/aws/amazon-connect-new-ml-powered-capabilities-for-forecasting-capacity-planning-scheduling-and-agent-empowerment/)

# Amazon Connect とは？
Amazon ConnectとはAmazon Web Services 社の提供する簡単にコールセンターを開設できるサービスです。

本サービスについて、私が過去に書いた記事がありますので、ご紹介します。
[Amazon Connectの使い方[丁寧に解説してみた]](https://qiita.com/mottie/items/5d94c7d2f94beeb9c342)
[Amazon Connect Voice ID とAmazon Connect Wisdom がプレビュー公開されました！！](https://qiita.com/mottie/items/407ed6ba7ab54e9f200c)
[【通話要約】Contact Lens for Amazon Connect の新機能が発表されました](https://qiita.com/mottie/items/cefc9e6ea126ee9ce2c8)

# re:Invent 2022 で発表された新機能について
## 予測
予測機能では過去の履歴データ(通話履歴)をもとに、問い合わせ量と平均処理時間を予測することができます。
![connect-forecast-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578416/6f601d53-00d0-11a0-b311-0a0d0179a89f.png)

## キャパシティプランニング
キャパシティプランニング機能では、各時間帯によってエージェント(業務従事者)が何人必要かを予測します。
![connect-capacity-plan.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578416/c4f8a230-75b8-d674-6c8a-e11aa2e38dc3.png)

## スケジューリング
スケジューリング機能ではエージェントのサービスレベル、回答に対する平均速度を踏まえて、最適化されたスケジュールが作成されます。
![connect-ot.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/578416/7aa7dbd4-41c5-594e-7f89-d32c60563cc7.png)

# おわりに
本機能を利用することで、顧客からの需要を予測して適切に人員配置することができますので、さらなるカスタマーサクセスにつながるのではないでしょうか。
cron で 全データに対し、1日1回処理をする

cronを使って以下の処理を行いたいときがある

・ランダムな時間
・全データに関して1日1回は処理をしたい
・しかし、DBから100件取り出しても 15件しない時とかある

上記の処理をするアルゴリズムが複雑すぎたのでまとめて書いておく。


```User.php

    public static function cronRand($syori,$day_fun)
    {
//        $syori = 100;//一度に処理するレコード数
//        $day_fun = 1440;//1日の分数(2日に一回なら2880とする)

//        ランダムにIDを取得
        $rand_ids = User::query()//単数形 User
        ->select('id')
            ->inRandomOrder()
            ->take($syori)
            ->pluck('id')->toArray();//リスト形式で取得

        $user = User::query()//単数形 User
            ->whereIn('id',$rand_ids)
            ->paginate($syori);//take でなく、ここに直接1ページに表示するカウントを指定


        $record = User::query()//単数形 User
            ->paginate($syori);//take でなく、ここに直接1ページに表示するカウントを指定



        $all_record = $record->total();

        $page = $record->lastPage();//レコード数(何ページあるかを調べるか)

        $tmp = $day_fun/$page;
        $wariai = ceil($tmp);//1日1回に足りない程度
        $jikkou_flag = mt_rand(1,$wariai);//jikkou_flag が 1のときに実行すれば良い


        //オブジェクトを配列に
        $tmp = json_decode(json_encode($user), true);
        $data = $tmp['data'];

        //テスト配列をカットしてみる
        $data = array_splice($data, 0,3);

        $dummy = $data[0];
        $dummy['id'] = 0;

        //7個たりないので配列を埋める
        $tarinai = $syori-count($data);
        $data += array_fill(count($data), $tarinai, $dummy);

//        foreach ($data as $v) {
//            echo $v['id']." : ".$v['name']." <br>";
//        }
//
//        echo "all_record : " . $all_record . "<br>";
//        echo "処理ペース : " . $wariai . " 回 に 1回<br>";
//        echo "実行フラグ : " . $jikkou_flag . " が1のとき実行<br>";
//        echo "総ページ数 " . $page . "";

        if($jikkou_flag == 1){
//            pd("処理実行");
            return $data;
        } else {
            return false;
        }



    }

```


ここでデータが帰ってきた場合のみ、処理を実行すればOK

```HogesController.php

//        100件を一気に読み出し、1440分（1日） に 1回の割合で処理
        $res = User::cronRand(100,1440);
        print_r($res);

```
Azure Administrator(AZ-104)：Azure管理者向けの前提条件「パラメーターと変数(Bicep)」

Microsoft Learnを用いたMicrosoft Azure Administrator(AZ-104)の試験内容をまとめる投稿です。
この投稿ではMicrosoft Learnで学ぶ内容をできるだけ簡潔にまとめております。
Azureの勉強を一から始め、AZ-900取得後の資格としてAZ-104取得を目指している方の参考になれば幸いです。
※AZ-900の内容は本投稿では省略しております。再度復習したい方は下記をご参照ください。
[Azure Fundamentals(AZ-900)：試験合格に向けた学習内容のまとめ](https://qiita.com/fsd-jume/items/e4ec76959adb547ac5e8)

## 今回の学習内容
**◆「パラメーターと変数(Bicep)」**
◇対応するMicrosoft Learn ラーニングパス
[AZ-104:Azure 管理者向けの前提条件](https://learn.microsoft.com/ja-jp/training/paths/az-104-administrator-prerequisites/)
◇まとめとリソース
[Azure Resource Manager テンプレートを使用してリソースを構成する](https://learn.microsoft.com/ja-jp/training/modules/configure-resources-arm-templates/8-summary-resources)
◇対応するモジュール
    [パラメーターと変数を使用して柔軟性を高める](https://learn.microsoft.com/ja-jp/training/modules/build-first-bicep-template/5-add-flexibility-parameters-variables)

※前回の投稿は下記から確認できます。
[Azure Administrator(AZ-104)：Azure管理者向けの前提条件「リソースの定義(Bicep)」](https://qiita.com/fsd-jume/items/d143ca65bb8082f9cc2a)

## パラメーターと変数(Bicep)
### パラメーター
**デプロイごとに変わる内容でパラメーターの使用を推奨**
・一意である必要があるリソース名
・リソースのデプロイ先のリージョン
・SKU、価格レベル、インスタンス数などの価格に関わる設定
・テンプレートで記載されていない他システムにアクセスするための資格情報

**◆パラメーター定義のコード例**
・「toy-product-launch-1」という名前のApp Serviceアプリを作成する場合
```:Bicep
param appServiceAppName string = 'toy-product-launch-1'

resource appServiceApp 'Microsoft.Web/sites@2021-03-01' = {
  name: appServiceAppName
  location: 'westus3'
  properties: {
    serverFarmId: appServicePlan.id
    httpsOnly: true
  }
}
```
**※コードの意味**
**・param `パラメーター名` `データ型` (`= 既定値`)**
パラメーターを定義していることをBicepに通知
　-既定値：既定値を指定した場合、パラメーターを指定しなかったときに既定値が使用される
　-今回の場合はデプロイ時に「appServiceAppName」の値を指定しなかった場合
　　⇒リソース名が既定値の「toy-product-launch-1」になる
**・name: appServiceAppName**
定義したパラメーター「appServiceAppName」を使用

### 変数
**変数を使用することでBicepファイルの開発の簡略化が可能**
例)複雑な式を含む変数を定義することでBicepファイル全体で複雑な式を繰り返す必要がなくなる

**◆変数使用の推奨例**
・デプロイごとに同じ値を使用するが、テンプレート内で値を再利用できるようにする場合
・式を使用して複雑な値を作成する場合
・一意な名前を必要としないリソースの名前を定義する場合

**◆変数定義のコード例**
・App Serviceプランの名前を「toy-product-launch-plan」と定義する場合
```:Bicep
var appServicePlanName = 'toy-product-launch-plan'
```
**※コードの意味**
**・var `変数名` `= 変数の値`**
変数を定義していることをBicepに通知
　-変数の値：パラメーターと異なり値の指定が必要
　-データ型は指定の必要なし(指定した値から自動で型を認識)

## 次の学習内容
**◆パラメーターと変数を用いた式(Bicep)**

https://qiita.com/fsd-jume/items/c5619673af9540a60a25

## 学習内容をまとめたページの一覧

https://qiita.com/fsd-jume/items/6eda24728c9c03c36bc3
ValueObjectについてまとめてみた

案件の中で、Value Objectを使用している箇所がいくつかあったのでまとめました。

**Value Object(バリューオブジェクト) とは、**

- 値をクラスにすること
- 値を変更したくなったら、バリューオブジェクトごと置き換えること
- どの箇所からでも再利用できること(バリューオブジェクト内のデータを使うので、データの値を担保できる)

と自分は認識しています。

例として、Userモデルを挙げます。
| Userモデル | 
| ---------- | 
| id         | 
| name       | 
| tel        | 

`name`はその人の名前を表すものなので、バリューオブジェクトにする必要はないと思います。
下記あたりが、バリューオブジェクトにしやすいものと思います。

- CRUDするときに、変な値で登録させたくないもの
- typeが存在するもの(性別や、血液型など)

例として、Userモデルの中の、`tel`をバリューオブジェクトにしてみます。

```php
<?php

class Tel
{
    const DEFAULT_TEL = '00000000000';

    /** @var string */
    private $tel;

    /** @param string $tel */
    public function __construct(string $tel)
    {
        // 数字以外の入力だったらエラー出すとか、文字数制限とか
        if(xxxx){
           // throw Exception 
        }
        $this->tel = $tel;
    }

    /* @return string */
    public function getValue(): string
    {
        return $this->tel;
    }
}
```


このようになりました。**telをクラス化**しています。

値をクラス化することによって、Telをインスタンス化した時に、**意図しない値が入るのを防ぐことができます。**
意図しない値が入った場合例外を投げるので、エラー原因の特定につながります。

## 使い方

### CRUD処理時など
```php
User::register(
    'test_name',
    new Tel('090xxxxxxxx'),
    ....
)
```
これにより、`new Tel('aaaaaa')`と 意図しない値が入ってもエラーで弾くことができます。

### 引数として使うときなど
```php
public function findFirstByTel(Tel $tel)
{
return User::where('tel', $tel->getValue())
    ->get()
    ->first();
}
```

### バリューオブジェクトを呼び出すとき

`(new Tel('00000000000'))->getValue();`

コレだとピンとこないので、

例えばUserモデルをモデリングしてみます(言葉合ってるかわからないです)
```php
class UserEntity
{
    private ?int $id;
    private string $name;
    private Tel $tel;

    public function __construct(
        $id,
        $name,
        $tel
    ) {
        $this->id = $id;
        $this->name = $name;
        $this->tel = new Tel($tel);
    }

    public function getId(): ?int
    {
        return $this->id;
    }

    public function getName(): string
    {
        return $this->name;
    }

    public function getTel(): Tel
    {
        return $this->tel;
    }
}

$entity = new UserEntity(null,'test_name','09012345678');

var_dump($entity->getTel()->getValue());

--> 09012345678
```



のような形で値を取ることができます。

この辺、DDDとも絡んでる気がするのですが、解釈人それぞれなのでこれ以上は追求しないです。(個人の感想です)

## 参考資料
- https://kzkohashi.hatenablog.com/entry/2018/03/05/170525
- https://qiita.com/t2-kob/items/9d9dd038fe7497756dbf
コミュニケーションがもたらすもの


# はじめに

みなさんこんにちは！
AIQVE ONE Advent Calender 5日目を担当します@NAKAMeです。
この記事では、私がこれまでに感じてきたクライアントさんとのコミュニケーションが
もたらすものについて、お話できればと思います。

# 未経験からマネージャーへ

前職ではECサイトのCS(カスタマーサポート)として働いており、品質管理にはあまり縁のない日常を送っていました。
1年ほど働いた後、先のキャリアプランを考えた時に、自分の好きなエンタメに関与できる
お仕事をしたいと転職し、未経験テスターとして現AIQVE ONEに入社をしました。

JSTQBなどの知識もない状態からのスタートであり、現場叩き上げでスキルを身に着けようと
はや2年、今ではテストマネージャーとして、テスト業務も行いながらテスト管理も行っており、
業務を兼任しながら日々を過ごしています。

# テスターからマネージャーになって

現在はマネージャーとしてQAに関わっている立場上、テスターとして働いている時に比べて、
テスト実行を行うよりもメンバーやクライアントさんとコミュニケーションをとる時間の
比率が大きくなってきています。
そんな日々を送っている中で、コミュニケーションがもたらすものについてふと目を向けることがありました。

元々CSに従事していたこともあり、お客様（ビジネスモデル風にいえば、B to 〇の〇部分）
とのコミュニケーションに重きを置くことに特に理由も考えていませんでした。
ただ、Advent Calenderで執筆するにあたって、所謂当たり前に考えていたものを言語化
してみるのもよいと思い、拙いながら書いてみようと思います。

# コミュニケーションをとることで...

### 信頼を得やすい

お仕事をする上で信頼を得るというのはとても大切なことです。
どなたであっても、理解できる人や安心できる人にお仕事を任せたいと思うでしょう。
お仕事相手（もしくはお客さん/クライアントさん）と親密になる、お仕事を円滑にこなす、
いくつか手段や過程はありますが、コミュニケーションにおいては特に元手も必要なく
行うことができるので、これだけでも試して損はありません。
信頼を得ることでより円滑に進む業務やプロジェクトも必ずあるので、大きなメリットになります。

### 情報更新が早くなる

コミュニケーションをとるということは、少なからずお相手との会話も増えていきます。
QAに関わらずではありますが、クライアントさんやお客さんと話しているとこんなことがあったりします。
「え、今の内容仕様書に記載ないじゃん！」とか、
「その内訳、マイルストーンやらスケジュールやらには一文字もないやん！」とか。
もちろん、提示されている資料やデータに最初から記載いただくに越したことはないのですが、
見えてこない情報をキャッチアップしに行けるというのはメリットです。
結果として、円滑にゴールを迎えるためのマイルストーンを引きやすくなったりもします。

### 認識齟齬がおきづらくなる

情報更新に関連するところではありますが、コミュニケーションを活発にとれている環境では
進捗確認のチェックポイントを多く設定しやすくなります。
認識のすり合わせなど細かく行うことで、成果物のクオリティアップにつながり、
完成間近や完成後のロールバックなどの手間コスト増を防ぐこともできます。
結果として評価にも繋がりますし、より信頼の獲得にもつながる好循環を生み出せるかもしれません。


# 最後に

エンジニアリングに近い業務であることも相まって、報連相など意識することはあっても
コミュニケーション自体に重きをおけていない方、一定数いるんじゃないかと思っていたりします。

コミュニケーションにメリットしかないかと言われればそうではなく、
先にあげたコミュニケーションがもたらすものは、逆に自らのプレッシャーやミスに
時につながるものでもあります。
「成果を出せずに信頼に比例した評価をされた...」「情報をキャッチアップできていたのに活かせなかった...」など。

ただ、自分の業務への責任感をより強くもつきっかけやポテンシャルにもつながりますので、
今の立場にこだわらず、できる限りでコミュニケーションの充足を目指していただき、
プロジェクトのクオリティアップを目指していければと考えています。
【SQL EXISTS句】利用した全てのECモールで1ヶ月当たりに使用される金額が5000円以上のユーザーを調べる

# まずは、テーブルを用意

それぞれのユーザーが利用したECモールで1ヶ月当たりに使用した金額を表す`ec_malls`テーブルを用意します

・**[風土jp](https://www.hoodo.jp)**
・A
・R

3つのECモールがあるとして、それぞれ利用した場合の金額が格納されます

```
SELECT * FROM ec_malls;
 user_id | mall_name | amount_spent_per_month
---------+-----------+----------------------
       1 | 風土jp    |                30000
       1 | A         |                 8000
       1 | R         |                 1000
       2 | 風土jp    |                 5000
       2 | A         |                 5000
       3 | 風土jp    |                10000
       3 | R         |                 3000
       4 | 風土jp    |                25000
```

# 全てのECモールで5000円以上利用したユーザーを表現するには?

「全ての〜〜」をSQLで簡単に表現できれば良いのですが、
SQLには、全称量化子に対応する述語が存在しないみたいです。

なので、**二重否定文**へ変更することでSQLでは表現出来るようです

> 全てのECモールで5000円以上利用したユーザー
↓
全てのECモールで5000未満の利用のユーザーが存在しない

# 実際のSQL

```sql
SELECT DISTINCT user_id
FROM ec_malls ecm1
WHERE NOT EXISTS (
    SELECT *
    FROM ec_malls ecm2
    WHERE ecm1.user_id = ecm2.user_id AND ecm2.amount_spent_per_month < 5000
);
```

```
 user_id
---------
       4
       2
```

今回欲しいのはuser_idだけで、`DISTINCT`で重複行を除きます

`WHERE NOT EXISTS()`：1行ずつ評価していきますが、条件を満たさない行が見つかった時点で処理は止まります

## HAVING句を使用した書き方でも書ける

```sql
SELECT DISTINCT user_id
FROM ec_malls
GROUP BY user_id
HAVING SUM(
    CASE WHEN amount_spent_per_month >= 5000
         THEN 1
         ELSE 0
    END
) = COUNT(user_id);
```

user_id 毎にグループ化したものに対して、それぞれ条件指定しています

`COUNT(user_id)`はGROUPごとのレコード数の合計を表しています。そのため、`amount_spent_per_month >= 5000`の条件を全て満たしていれば`SUM() = COUNT(user_id)`は成立します

これは、`EXISTS`とは違って全ての行をなめる必要があります

そのため、**パフォーマンスの観点で言うと`EXISTS`が勝るようです**

# 今度は、[風土jp](https://www.hoodo.jp)で12000円以上、Rで5000円以下利用したユーザーを調べる

今度はモールを`風土jp と R`に絞ったクエリを考えてみます

```sql
SELECT DISTINCT user_id
FROM ec_malls ecm1
WHERE mall_name in ('風土jp', 'R') AND NOT EXISTS (
    SELECT *
    FROM ec_malls ecm2
    WHERE ecm1.user_id = ecm2.user_id AND 1 =
        CASE WHEN mall_name = '風土jp' AND amount_spent_per_month < 12000 THEN 1
             WHEN mall_name = 'R' AND amount_spent_per_month > 5000 THEN 1
             ELSE 0
        END
);
```

```
 user_id
---------
       1
       4
```

`WHERE mall_name in ('風土jp', 'R')`でまず絞ります

そして、今回の条件である、「風土jpで12000円以上、Rで5000円以下利用した」は
>風土jpで12000円以上、Rで5000円以下利用した
↓
風土jpで12000円未満、Rで5000円より大きい額の利用を満たさない

で表すことが出来ます

ここでは、CASE式を利用して条件を満たす場合は1、満たさない場合は0として比較します

## 風土jpもしくはRが存在しない場合は除外する

`GROUP BY user_id HAVING count(mall_name) = 2`を追加します

ユーザごとに、絞った2つのモールが存在しない場合は除外しています

```sql
SELECT user_id
FROM ec_malls ecm1
WHERE mall_name in ('風土jp', 'R') AND NOT EXISTS (
    SELECT *
    FROM ec_malls ecm2
    WHERE ecm1.user_id = ecm2.user_id AND 1 =
        CASE WHEN mall_name = '風土jp' AND amount_spent_per_month < 12000 THEN 1
             WHEN mall_name = 'R' AND amount_spent_per_month > 5000 THEN 1
             ELSE 0
        END
)
GROUP BY user_id
HAVING count(mall_name) = 2;
```

```
 user_id
---------
       1
```

# 終わりに

帆立がたべたい
[pc]
https://www.hoodo.jp/pc/store/katsumaru/02300020

[スマホ]
https://www.hoodo.jp/sp/store/katsumaru/02300020