OmniAICreator/Qiita-1.07M huggingface dataset:
SQL上で1つのレコードを特定の値区切りに分割しレコードを複製したい

## 概要

タイトル通りなんだけど、語彙力が無さすぎて言葉で詳しく説明するのが難しかったので例で説明。

## 例

下記のようなデータがある

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603595/f62a6f15-9325-d292-9135-65b4f265cf8b.png)


これを下のように100毎に区切って分解したい。
また、余りはそのまま余りを出力したい。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/603595/372d39e0-5667-8d06-7309-cb1a059a50b2.png)


果たしてどうやるのがいいのか？


## 自分なりにたどり着いた答え

```SQL
WITH data AS (
  SELECT
    *
  FROM 
    UNNEST([STRUCT(1 AS user_id, 232 AS amount), (2, 310), (3, 100), (4, 1)])
)

SELECT
  user_id,
  amount
FROM (
  SELECT
    user_id,
    ARRAY_CONCAT(ARRAY(SELECT 100 FROM UNNEST(GENERATE_ARRAY(1, CAST(TRUNC(amount / 100) AS INT64)))), [MOD(amount, 100)]) AS amount_array
  FROM
    data
),
UNNEST(amount_array) AS amount
WHERE
  amount != 0
```

## 解説

簡単に説明すると、元になる値を分割して分割数を求めてその分割数分の要素が100の配列を作成してそれに対して、元になる値を分割した際の余りを加えてUNNEST CROSS JOINで展開している。

と言ってもよくわからないので一つずつ分解

##### 1
```SQL
GENERATE_ARRAY(1, CAST(TRUNC(amount / 100) AS INT64))
```
元になる値(amount)を分割したい数字(100)で割って小数点を切り捨てる。
例えば378だったら3が返ってくるし、1だったら０が返ってくる。
`GENERATE_ARRAY(1,n)` は1からnまでの連番の配列を作ってくれるのでここで要素数分の配列を作成する。
`378→[1,2,3]`


##### 2
```SQL
ARRAY(SELECT 100 FROM UNNEST([1,2,3,4]))
```
その配列の各要素を全て分割したい数字(100)に置き換えてしまう。
`[1,2,3] → [100,100,100]`


##### 3
```SQL
ARRAY_CONCAT([100,100,100], [MOD(amount, 100)])
```
その配列に元になる値(amount)を分割したい数字(100)で割ったときの余りを追加する
`[100,100,100]→[100,100,100,78]`

##### 4
後は配列をUNNESTしたやつと元のデータを `CROSS JOIN` してあげれば求めたかった物が出来上がる。

## まとめ

もっとスマートなやり方はあるかもしれない、というかあるきがする。
ただ、UDFを使うやり方はパフォーマンス落ちるのであまりやりたくなかった。
Macのシステム設定まとめ

新しいMacを買った時、Macをクリーンインストールした後にするシステム設定をまとめます。

## 執筆時の環境
・macOS Catalina 10.15.2
・MacBook Pro 13inch 2019
・US配列のキーボード

## 設定
### タップでクリック
1本指のタップを、クリックとして認識させます。
「システム環境設定」>「トラックパッド」>「ポイントとクリック」>「タップでクリック」

### 軌跡の速さを変更
マウスカーソルの移動速度を、やや速めに変更。
「システム環境設定」>「トラックパッド」>「ポイントとクリック」>「軌跡の速さ」

### リピート入力の速さを変更
バックスペースで文字を削除するスピードをあげるために。
「システム環境設定」>「キーボード」>「キーのリピート」と「リピート入力認識までの時間」を一番右側へ

### ~~タッチバーからSiriを削除~~
~~「システム環境設定」>「キーボード」>「Control Stripをカスタマイズ」~~

### 3本指でドラッグ
ドラッグや文字の選択を、3本指でできるように。
「システム環境設定」>「アクセシビリティ」>「ポインタコントロール」>「マウスとトラックパッド」>「トラックパッドオプション」>「ドラッグを有効にする」>「3本指のドラッグ」

### 入力ソースに日本語を追加
「システム環境設定」>「キーボード」>「入力ソース」>「+」>「日本語」

### 英語入力中に自動で大文字になったりする機能を無効化
「システム環境設定」>「キーボード」>「ユーザー辞書」>「英字入力中にスペルを自動変換」と「文頭を自動的に大文字にする」のチェックを外す

### 入力切替方法を変更
左のcommandボタンで英字、右のcommandボタンで日本語入力に切替えられるようにします。US配列なので、、
(参考)
[Mac用 Apple英字配列(US)キーボードにおける日本語入力切替のおすすめ：Commandキーのみで実現](https://qiita.com/daichi87gi/items/ded35e9d9a54c8fcb9d6)

### ctrlとcapslockを入れ替える
「システム環境設定」>「キーボード」>「キーボードショートカット」>「修飾キー」

### キーボードが光らないようにする
「システム環境設定」>「キーボード」>「環境光が暗い場合にキーボードの輝度を調整」をオフ
タッチバーで輝度を修正。

### バッテリー残量をパーセントで表示
デフォルトだと図が表示されるだけなので、
~~「画面上のバッテリー残量ボタン？をクリック」> 「割合(%)を表示」~~
「システム環境設定」>「コントロールセンター」>「バッテリー」>「割合(%)を表示」

### ~~日付を表示~~
~~デフォルトだと曜日と時間しか表示されないので、~~
~~「システム環境設定」>「日付と時刻」>「時計」>「日付を表示」~~

### メニューバーにBluetoothを表示
~~「システム環境設定」>「Bluetooth」>「メニューバーにBluetoothを表示」~~
「システム環境設定」>「コントロールセンター」>「Bluetooth」>「メニューバーに表示」

### Touch IDに指を追加
右手の人差し指、中指を登録します。
「システム環境設定」>「Touch ID」>「指紋を追加」

### Night Shift
「システム環境設定」>「ディスプレイ」>「Night Shift」

### マルチデスクトップの並び順を固定
~~「システム環境設定」>「Mission Control」>「最新の使用状況に基づいて操作スペースを自動的に並べ替える」をOFF~~
「システム環境設定」>「デスクトップとDock」>「Mission Control」>「最新の使用状況に基づいて操作スペースを自動的に並べ替える」をOFF

~~### Spotlight検索のショートカットキーを無効化~~
~~「システム環境設定」>「Spotlight」>「キーボードショートカット」~~

### 拡張子を表示
「Finder」>「環境設定」>「詳細」>「すべてのファイルの拡張子を表示」

### Finderの初期画面を設定
「Finder」>「環境設定」>「一般」>「Finder新規ウィンドウで次を表示」

### スクリーンショットの保存先、ファイル名を設定
`~/SS`というディレクトリ、名前を撮影日時にして保存

```terminal
$ cd ~
$ mkdir SS
$ defaults write com.apple.screencapture location ~/SS/
$ defaults write com.apple.screencapture name ""
$ killall SystemUIServer
```
NVIDIAのGPUでWineのゲームやSteamが使えない場合の対処方法

## 環境と問題
Wineでオトメドメインを起動しようとしたり、Steamを起動しようとしたりすると以下のエラーが出力される場合が有ります。
私はLTSカーネルを常用しているので既に`nvidia-lts`はインストールしていました。

```
libGL error: No matching fbConfigs or visuals found
libGL error: failed to load driver: swrast
X Error of failed request:  GLXBadContext
```


## 解決方法
[こちらのスレッド](https://bbs.archlinux.org/viewtopic.php?id=155058)で見つけました。

```bash
sudo pacman -S lib32-nvidia-libgl lib32-nvidia-utils nvidia-libgl 
```
HTML/CSSの基礎知識

# HTML/CSSについて
1.HTMLとは
・ハイパーテキスト・マークアップ・ランゲージ（ HyperText  Markup Language）の略。
・ウェブページを作成する為の言語。
・ハイパーテキストに目印をつける言語。

①ハイパーテキストとは？
・ハイパーリンクを埋め込むことができる高性能なテキスト。

②ハイパーリンクとは？
ウェブページで下線の付いたテキストなどをクリックすると別のリンクへ移動するリンクのこと。

③マークアップとは？
・文書の各部分がどのような役割を持っているか分かるように示すこと。
（各部分→elementと呼ぶ。）

<メリット>
・マークアップにより、その部分がどのような役割なのかを明確にすることで、コンピューターがその文書構造を理解できるようになる。

2.CSSとは？　
・カスケーティング・スタイル・シートの略。
・ウェブページのスタイルを指定する為の言語でHTMLと組み合わせて使用する。
・スクリーンに表示される際の色、サイズ、レイアウトなどの表示、プリンタで印刷される際の出力スタイル、音声で読みあげられる際の再生スタイルなど、どのようなスタイルで表示、出力、再生するかについて指定することができる。

①スタイルシートとは？
・文書のスタイルを指定する技術全般のこと。

②スタイルシートが必要な理由は？
・HTMLでもCSSのようにウェブページをスタイリングできないことはないが、それだと文書構造がでたらめになってしまう。
・HTMLの要素をどのように表示するかはブラウザによって異なるので、HTMLタグを駆使してある閲覧環境では綺麗にレイアウトされたとしても、他の閲覧環境では全く意図しないレイアウトになってしまうことがある。

<メリット>
・文書の構築とスタイルを分離して管理できるようになる。
・文書の構造に影響を与えずにスタイルを制御できるようになる。
・スタイル指定のせいで文書構造が分からなくなることがなくなる。
・スタイルを一括管理できる。
・複数の文書でスタイルを共有できる為、メンテナンス性が向上する。
・検索エンジンに正しく解釈されるウェブページになる。
・文書から余分なマークアップを排除して、スタイルに関する記述を一箇所にまとめる事でウェブページを軽量化できる。
・様々なメディアごとに適用するスタイルを指定し分けることができる。
・将来的に特定のメディアに依存することなく、それぞれのメディアに合ったスタイルでウェブページを表示、再生、出力させることができる。
Dockerを使った既存のRailsアプリの環境構築に苦労したので、メモを残してみた

#1.はじめに
　2020年3月からDockerの勉強を始め、基礎を終えた後、Railsの環境構築に挑戦してみようと思ったが、思いの外、上手くいかなかったので、ここにメモを残すことにしました。誰かの参考になれば幸いです。
#2.教材
・[入門 Docker](https://y-ohgi.com/introduction-docker/)
・Docker/Kubernetes 実践コンテナ開発入門(書籍)
・Docker Hubの公式イメージ
#3.開発環境
・[Play with Docker](https://labs.play-with-docker.com/)
(事前にDockerHubのアカウントが必要です。)
・Ruby:2.5.3
・Ruby on rails:5.2.2
・MySQL
#4.手順
###4-1 クローンを取得
まずは、GitHubからgit cloneでアプリをクローンしておいてください。

```
git clone 'クローンしたいアプリのURL(GitHub参照)'
```

これで、作成済みのアプリをローカルディレクトリに取り込むことができました。
###4-2 Dockerfileとdocker-compose.ymlの作成
Dockerfileとdocker-compose.ymlを以下の配置になるように作成してください。
(作成済みのアプリをSampleAppと名付けています。)

```
SampleApp---|--app
            |--bin
            |--config
            |--db
            |--lib
            |--log
            |--public
            |--storage
            |--tmp
            |--vendor
            |--.gitignore
            |--.ruby-version
            |--Dockerfile   (これを追加)
            |--Gemfile
            |--Gemfile.lock
            |--README.md
            |--Rakefile
            |--config.ru
            |--docker-compose.yml  (これを追加)
            |--package.json
```

また、Dockerfileとdocker-compose.ymlの中身は以下のようになります。

```Docker:Dockerfile
FROM ruby:2.5.3

RUN apt-get update -qq && apt-get install -y build-essential libpq-dev node.js 

RUN mkdir /myapp
WORKDIR /myapp 

COPY Gemfile /myapp/Gemfile 
COPY Gemfile.lock /myapp/Gemfile.lock 

RUN bundle install

COPY . /myapp
```

```Docker:docker-compose.yml
version: '3'

services: 
  db: 
    image: mysql 
    environment: 
      MYSQL_ROOT_PASSWORD: password 
      MYSQL_DATABASE: root
    command: --default-authentication-plugin=mysql_native_password 

  web: 
    build: . 
    command: bundle exec rails s -p 3000 -b '0.0.0.0'
    volumes: 
      - .:/myapp 
    ports:
      - "3000:3000" 
    depends_on: 
       - db 
```

これで、実行する準備は完了です。
###4-3 実行
アプリのディレクトリ内で以下のコマンドを実行してください。

```
$ docker-compose build

$ docker-compose up -d

$ docker-compose run web rake db:create

$ docker-compose run web rake db:migrate
```

完了です。

#5. 最後に
何か間違えているところがあれば、ご指摘ください。

#6. 参考記事
[既存のRailsアプリにDockerを導入する手順](https://qiita.com/kenzoukenzou104809/items/b9e716204e0cd0cea447)
[railsの環境構築 その1](https://qiita.com/hb5kz/items/0cd9340812c4b1513f71)
[プログラム好き大学生のDocker+Ruby on rails5で環境構築とgitの設定（初心者向け）](https://qiita.com/mtaku29/items/e1bafcd6511d44e93c8a)
(Django) django-extra-viewsのUpdateWithInlinesViewで、条件によってInline Formを変える

Djangoでインラインフォームを簡単に実装できる[django-extra-views](https://django-extra-views.readthedocs.io/en/latest/index.html)。

ただたインラインフォームを使うだけだったら、view.pyに

```python
from extra_views import UpdateWithInlinesView, InlineFormSetFactory

class PostUpdateInlineFormSet(InlineFormSetFactory):
	model = Author
	fields = ('name',)
	factory_kwargs = {'extra': 0,'can_order': False, 'can_delete': False}

class PostUpdate(UpdateWithInlinesView):
	model = Post
	fields = ('title',)
	template_name = 'post/post_detail.html'
	success_url = reverse_lazy('post:home')
```

を書くだけで実装できてしまう。

また、インラインフォームクラスを複数作って、条件によって使うインラインフォームを変えたい時はget_inlines()をオーバーライドすれば可能になる。

```python
class PostUpdate(UpdateWithInlinesView):
	model = Post
	fields = ('title',)
	template_name = 'post/post_detail.html'
	success_url = reverse_lazy('post:home')
        #ここではユーザーのタイプによって出し分け
        def get_inlines(self, **kwargs):
		inlines = super().get_inlines(**kwargs)
		user = self.request.user
		if user.user_type == 'admin':
			inlines = [AdminUpdateInlineFormSet, ]
		elif user.user_type == 'member':
			inlines = [PostUpdateInlineFormSet, ]
		return inlines
```
AWS BackupのDefault vaultのリカバリーポイントをまとめて削除する。

#概要
大分前にテストしていたAWS BackupでDefault vaultに大量のAMIとSnapshotがあり、
邪魔だったので消そうとしたところ、EC2のコンパネからはまとめて削除ができない。

AWS Backupのコンパネからだと1個ずつしか消せず、vaultごと削除しようとしたところ
**Defaultのvaultは削除できない**ことが判明。

引用元:
[AWS Backupを使い始める前に覚えておきたいこと]
(https://qiita.com/hayao_k/items/a4f18d030e0e58063f64)

#解決策
50個程度のAMIとSnapshotなら1個1個手で消してもいいかもしれないが、どうせ同じ時間をかけるならまとめて削除できる方法を考えたい。
**じゃあAWS CLIで一気にやってしまおう。**

#環境
Amazon Linux2
aws-cli/1.16.300 Python/2.7.16 Linux/4.14.171-136.231.amzn2.x86_64 botocore/1.13.36

#組んだshell
```budel.sh
#!/bin/bash
##一覧作成CLI用変数
LIST="list-recovery-points-by-backup-vault --backup-vault-name"

##AWSBackupにやらせたいCLI用変数
CMD="delete-recovery-point --backup-vault-name"

##引数省略用
RPA="--recovery-point-arn"

##引っ張ってくる値
VAL="RecoveryPointArn"

##VAULTからリカバリーポイント一覧を取得＆整理
aws backup $LIST $1 | grep $VAL | sed -e "s/[\"]//g" | awk '{print $2}' | awk -F ',' '{print $1}' | cat > vault.txt

##出力したファイルから一行ずつコマンド処理
while read line
do
  aws backup $CMD $1 $RPA $line
done < ./vault.txt

##立つ鳥跡を濁さず
rm -f vault.txt
```
#結果
. budel.sh ＜vault名＞で叩いてあげると、そのvault内にあるリカバリーポイント(EC2ならAMIとSnapshot)が全て消える。
**※間違って他のvaultで削除しないように**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/536700/5d625eaf-38fd-b4bc-17c6-3b3d056bed03.png)

CMDをlist-recovery-points-by-resource --resource-arnにして、
VALをResourceArnとかにすると、ResourceArn毎のリカバリーポイントの値を
リストで出してくれるので、そっちから試した方が良い（自分はそうした）

まだ全部見てないけど、CLIによっては他にもっと便利な動きしてくれるかな。
[AWS Backup CLI一覧](!https://docs.aws.amazon.com/cli/latest/reference/backup/index.html#cli-aws-backup)

#悩み事(解決_20200319)
~~あと、vault一覧取得のところでどうしても以下じゃないと出力が出来なくて、~~
~~awkを二回挟んでるんだけど、どうにかならんものか。~~
~~`awk '{print $2}' | awk -F ',' '{print $1}' `~~

~~こうすると何も出力されない。~~
~~`awk -F ',' '{print $2}'`~~

有志により、grep後のsedを以下に変更すると良いとのこと。
```sed -r "s/\"|,//g```

さらに出力したものを一回一回ファイルにしていたのを、変数に入れて処理するように変更。
(変数lines=の後に半角スペースが入っていると上手く動かず若干ハマる)

#修正したshell
```awsdel.sh                                                                                          
 #!/bin/bash
 ##一覧作成用変数
 LIST="list-recovery-points-by-backup-vault --backup-vault-name"
 
 ##AWSBackupにやらせたいこと用変数
 CMD="delete-recovery-point --backup-vault-name"
 
 ##引数省略用
 RPA="--recovery-point-arn"
 
 ##引っ張ってくる値
 VAL="RecoveryPointArn"
 
 ##VAULT一覧を取得＆整理し、変数に格納
 lines=`aws backup $LIST $1 | grep $VAL | sed -r "s/\"|,//g" | awk '{print $2}'`
 
 ##出力した結果から一行ずつコマンド処理
 for line in $lines
 do
   aws backup $CMD $1 $RPA $line
 done
```

very smart!!
Railsアプリが開けない...エラーへの対処法


アプリケーションファイルを作成してプレビューしようとしたところ、
**ActiveRecord::ConnectionNotEstablished**
とエラーが表示され、進められないといった事態が起こりました...

あるエンジニアさんに質問したところ、原因と解決方法を教えていただけたので簡単に紹介します。かなり端的です。
言語と環境は以下の通りです。
・Ruby 2.6.3
・Rails 6.0.2.1
・AWS Cloud9

##原因１：RailsのVer.がうまく指定できていない
[解決方法]
RailsのVer.が6だったので、
ターミナルで、

```
$ gem install rails -v 5
$ rails _5_ new sample-app(←アプリ名の例)
```

をそれぞれ入力する。
→Ver.を5に落として指定することで解決

##原因２：RailsがSQLite3 1.4.2(最新Ver.)に対応していない
[解決方法]
作成したアプリファイルの中の[Gemfile]を開くと、

```Rails:Gemfile
gem 'sqlite3'
```

と書いてあります。
このままだと最新Ver.なので、その後ろに、

```Rails:Gemfile
gem 'sqlite3','~> 1.3.6'
```

といったように書き足し、(「,」を書き忘れずに！)
ターミナルで、

```
$ bundle update
```

と入力し、変更を保存する。

→Ver.を1.3.6に落として指定することで解決

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

その後、ターミナルで、

```
$ rails s -b $IP -p $PORT
```

と入力すると…起動させることに成功しました！

最終的に、
・Ruby 2.6.3 → 変更なし
・Rails 6.0.2.1 → 5.0.7.2
・sqlite3 1.4.2 → 1.3.6
となりました:thumbsup:
Perl で学ぶ逆元の３ ABC 151 E が解けた！

# はじめに
逆元問題が好きになってきたので、調子に乗って *[E - Max-Min Sums](https://atcoder.jp/contests/abc151/tasks/abc151_e)* に挑戦したが、難易度水色だったため簡単に解けるはずもなく気持ちが <font color='LightBlue'>Light Blue</font> になりながらも、何とか乗り切った話。
# E - Max-Min Sums
*[AtCoder Beginner Contest 151 E - Max-Min Sums](https://atcoder.jp/contests/abc151/tasks/abc151_e)*
答えは非常に大きくなる可能性があるので、

```math
mod\ 10^9 +7
```
で出力してください。
この時点で、テンションは **Max** だった。

# 嵌ったところ
```before1.pl
  $ans += $a[$n-$i-1] * $c;
  $ans %= $MOD;
  $ans += ($MOD - $a[$i]) * $c;
  $ans %= $MOD;
```
足し算なのでそのまま加えていましたが、加える変数 **\$a** が負の場合、<font color='orange'>WA</font> となるケースが考えられます。

```after1.pl
  $ans += ($MOD + $a[$n-$i-1]) * $c; # 負にならない様、法を加算
  $ans %= $MOD;
  $ans += ($MOD - $a[$i]) * $c;
  $ans %= $MOD;
```

```before2.pl
use Math::BigInt; # perl の bigint は圧倒的に遅い

my $modinv = sub {
  my $a = shift;
  Math::BigInt->new($a)->bmodinv($MOD); # BigInt メソッド
};
```
[この投稿](https://qiita.com/superrino130/items/a65eaa417f7da80971e7) で、**Math::BigInt** の味を占めたので使用しましたが、*[perl の bigint は圧倒的に遅い](https://mametter.hatenablog.com/entry/20080116/p1)* に気付かず <font color='orange'>TLE</font> の山。

```after2.pl
my $modinv = sub {
  my $a = shift;
  $modpow->($a, $MOD - 2); # 自作関数
};
```
# 解けたところ
```ABC151E.pl
use v5.18; # strict say state
use warnings;

my ($n, $k) = split / /, <STDIN>;
my @a = split / /, <STDIN>;
@a = sort { $a <=> $b } @a;
my $MOD = 1e9 + 7;
my $modpow = sub {
  my ($a, $n) = @_;
  my $r = 1;
  while ($n > 0) {
    $r = $r * $a % $ MOD if $n & 1;
    $a = $a * $a % $MOD;
    $n >>= 1;
  }
  return $r;
};
my $modinv = sub {
  my $a = shift;
  $modpow->($a, $MOD - 2);
};
my (@fac, @finv);
$fac[0] = 1;
$finv[0] = 1;
for my $i (1..$n) {
  $fac[$i] = $fac[$i-1] * $i % $MOD;
  $finv[$i] = $modinv->($fac[$i]);
}
my $combi = sub {
  my ($n, $k) = @_;
  $fac[$n] * ($finv[$n-$k] * $finv[$k] % $MOD) % $MOD;
};
my $ans = 0;
for (my $i=0; $i<=$n-$k; $i++) {
  my $c = $combi->($n-$i-1, $k-1);
  $ans += ($MOD + $a[$n-$i-1]) * $c;
  $ans %= $MOD;
  $ans += ($MOD - $a[$i]) * $c;
  $ans %= $MOD;
}
say $ans;
```
|<font color="LimeGreen">AC</font>|
|:-----:|
どやっ
# まとめ
+ 水色は骨のあるやつだった

参照したサイト

+ [多倍長整数演算の速度比較](https://mametter.hatenablog.com/entry/20080116/p1)
+ [Perl で学ぶ逆元の２ + パナソニックプログラミングコンテスト2020 C で嵌った話](https://qiita.com/superrino130/items/a65eaa417f7da80971e7)
+ [Perl で学ぶ剰余計算](https://qiita.com/superrino130/items/c72da0b8eb4d987f1488)

# 追記
**BigInt** を使用すると**100倍遅い**ことが分かりました
*[Perl AtCoderでベンチマーク](https://qiita.com/superrino130/items/251e10c5dabee7febca1)*
【Salesforce】Apexでファイルをライブラリ経由して公開方法

#Apexでファイルをライブラリ経由して公開方法
##概要図
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/480807/45b41811-cc29-f581-4613-83c658a35950.png)

---
#ファイルの登録
　ContentDocument直接書き込みできないので、ContentVersionにレコードを登録して、ContentDocumentにデータを自動登録できる。

```java:getAlertDescriptionFile
    public static ContentVersion getAlertDescriptionFile() {
        ContentVersion contentVersion_1 = new ContentVersion(
            Title = "Test",
            PathOnClient = 'Penguins.jpg',
            VersionData = Blob.valueOf('Test Content'),
            IsMajorVersion = true
        );
        return contentVersion_1;
    }
```
---
##ライブラリを作成

```java:getContentworkspace
    public static Contentworkspace getContentworkspace() {

        return new Contentworkspace(
            name='test for share file with library'
        );
    }
```
---
##ファイルをライブラリに格納
```java:getContentWorkspaceDoc
    public static ContentWorkspaceDoc getContentWorkspaceDoc(ContentDocument cd, ContentWorkspace cws) {

        return new ContentWorkspaceDoc(
            contentdocumentId = cd.id,
            ContentWorkspaceId = cws.id
        );
    }
```
---
##ライブラリ権限の作成

```java:getContentWorkspacePermission
    public static ContentWorkspacePermission getContentWorkspacePermission() {

        return new ContentWorkspacePermission(
            Name='test view',
            PermissionsAddContent = true,
            PermissionsTagContent = true
        );
    }
```
---
##ライブラリと権限とユーザに割り当て
```java:getContentWorkspaceMember
    public static ContentWorkspaceMember getContentWorkspaceMember(ContentWorkspace cws, ContentWorkspacePermission cwsp, User usr) {

        return new ContentWorkspaceMember(
            ContentWorkspaceId = cws.id,
            ContentWorkspacePermissionId = cwsp.id,
            MemberId = usr.id
        );
    }
```
【CI】GitHubActionsを使ってみた。「1.ワークフローを起動する」での詰まり&解決策

先日参加したPHPerKaigi2020で「GitHub Actions」に関するトークセッションがあり、スライドで丁寧な解説がされていたので参考にしてやってみました。本記事では、「準備からリポジトリへpushした際にプログラムが動作するまで」をやった際に詰まった部分＆答えが書いてあります。

#■詰まり1: .github/workflowsってどこに作るんだ？
**答え：リポジトリの最上部（.gitファイルがあるディレクトリ)**

この`.github/workflows`を作るのはgithubでリポジトリを表示した時に表示される階層に作成します。
僕は初っ端、どの階層に作れば良いか分からずに詰まりました。

<img width="1392" alt="githubactions_1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/250884/25c4e89e-01f8-c98a-8d2e-fca96126345c.png">

ちなみに、`.github`ディレクトリを作っていない状態で「Actions」タブを見ると、github上でディレクトリの作成から設定ファイルの作成までやってくれます。特に理由がないのであれば、ここから作成するのが良いかもしれないですね。

<img width="1434" alt="github_actionstab.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/250884/86a97b48-3e64-1658-1984-95082fc30fd4.png">

#■詰まり2: ワークフローはどのタイミングで起動する？
**答え： `.github`のあるブランチへフックになっているイベントが実行された時。**

CIはブランチごとに実行することができるようです。
始め、masterブランチにのみ`.github`を作成して実行すると思っていたのですが、別のブランチに設定ファイルを作成してイベントを実行したところ、ワークフローが起動しました。

設定ファイル「.yml」内の`name`に記載した名前がActionsタブで一覧に表示される名前になります。`master`ブランチに作成したファイルのnameが「Laravel」、`addgithubActions`ブランチに作成したファイルのnameが「CI」です。

<img width="1440" alt="ci_一覧.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/250884/e839ef52-857b-47c8-2c92-0d6dd90cada0.png">

#■次はActionsを使ってみる
これで実行する準備ができました。
次はstepsで実行することができる処理のまとまりである「Actions」を使ってみたいと思います。
それでは！

#■URL
参考：「GitHub Actionsで始めるPHPアプリケーションのCI実践入門」
https://speakerdeck.com/fortkle/ga-phperkaigi2020

PHPer Kaigi2020
https://phperkaigi.jp/2020/
【OZV全社発表LT】Agileで落ちやすい罠

オズビジョン全社発表会のLTの発表資料となります。

---

# Agileのお話し

--- 

### 以前見た、ブログの内容で、個人的に面白かったことろを引用して、Agileのお話しをしようと思います。

---

### これから話す内容は正解とは言えないものです。色んな人と自分の主観も交じっているので、参考までにお聞きいただければ幸いです。

---

# 問

--- 

#### 1) Agile is [①Low cost / ②High Cost]

#### 2) Agile is [①High Speed / ②Low Speed]

#### 3) Agileの主体は「？」ではない。「？」を主体として考えること。

--- 

# 答

--- 

1) Agile is [①Low cost / ②High Cost]
▶ **どっちもあり得る。**

2) Agile is [①High Speed / ②Low Speed]
▶ **どっちもあり得る。**

3) Agileの主体は「**人**」ではない。「**プロダクト**」を主体として考えること。

---

# （本題）<br> Agileで落ちやすい罠

---
# （引用）<br> 制作プロセス

---

# プロセス１

---
#### プロセス１：車の制作プロセス

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/436887/575c750d-7b43-f846-dc1d-28751ceac7fd.png)

---
#### プロセス１：車の制作プロセス

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/436887/99950ac6-bbfc-bbb1-7e71-88ff1273b477.png)


---

# プロセス２

---

#### プロセス２：Agile? （車の制作プロセス）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/436887/c8be643d-9aff-49e3-29b2-46e191cf1410.png)

---

#### プロセス２：~~Agile~~　**Waterfall**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/436887/4ac89feb-a5f4-3efe-ed20-2227622b9fb8.png)


---
# Agileと呼べる事例は？

---

# プロセス３

---

#### プロセス３：Agile （車？？の制作プロセス）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/436887/0b103f9f-1aef-fcff-438f-d8b21e5bae30.png)

---
#### プロセス3：Agile

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/436887/5798d30e-d05a-88ba-51b5-8e6c2f93a22d.png)

---

# 一番大事な違いは？

---
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/436887/804001ad-9436-879d-e642-69bb3d335b31.png)

> 顧客に提供する「**価値**」と「**プロダクト**」の設定

---

#### １．顧客に提供するプロダクト（価値）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/436887/3713fd6d-839e-9fe7-f620-3ea3028b7051.png)

---
#### １．顧客に提供するプロダクト（価値）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/436887/8bd1a2fa-d421-ee22-d482-95ad9351b472.png)

---

#（再び）<br>答 / 一番大事な違いは？

---

#### 1) Agile is [①Low cost / ②High Cost]

▶ どっちもあり得る。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/436887/94edcd25-31e3-4fbc-4127-4d7e718eb00a.png)

---

#### 1) Agile is [①Low cost / ②High Cost]

▶ どっちもあり得る。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/436887/67c57d71-cc6e-8dc0-ff36-19cf62f7c3c4.png)

---
#### 1) Agile is [①Low cost / ②High Cost]
▶ どっちもあり得る。


提供価値と、プロダクトの設定によって、
**「Low Costもなれるし、High Costにも」**
なれる。

---
#### 2) Agile is [①High Speed / ②Low Speed]
  ▶ どっちもあり得る。

提供価値と、プロダクトの設定によって、
**「High Speedもなれるし、Low Speedにも」**
なれる。

---
#### 3) Agileの主体は「人」ではない。「プロダクト」を主体として考えること。

- Agileは、**人**が素早い開発手法**ではない**。
- Agileは、**価値提供**が素早いのが理想的
- Agileは、**提供価値**と市場状況、顧客ニーズに反応しながら、**プロダクトを設定していく**のが理想的
- Agileは、顧客が満足させるために必要な物を**探索する過程を含む**プロセス。

---
# 一番大事な違いは？

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/436887/546ecd78-22f6-f1f2-192f-db4ac76b6e2b.png)


**提供価値の設定**
**プロダクトの探索・設定**

---
# ご清聴ありがとうございました。<br>「終わり」
pythonでgithub apiを呼び出してPull Request 情報を取得する

# 背景
データ基盤のデータソースとなるサービスのレポジトリのスキーマ変更があった場合に自動で通知がくるような機能を作りたい。github api で Pull Request 情報を引っ張ってきて作ったのでその時のメモ。
認証は、個人アクセストークンを使用する↓

##### [コマンドライン用の個人アクセストークンを作成する](https://help.github.com/ja/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line)


# 実装

```python

import requests

# closeされたPRのみ取得
URL = 'https://api.github.com/repos/owner/repo_name/pulls?&state=closed'
headers = {'Authorization': 'token xxxxx'} # 取得したアクセストークン
r = requests.get(URL.format(repo), headers=headers)
return r.json()
```

# 参考
- [Github API 公式](https://developer.github.com/v3/)
- [how to use github api token in python for requesting
](https://stackoverflow.com/questions/17622439/how-to-use-github-api-token-in-python-for-requesting)
  - 公式ドキュメントだとtokenのheader定義方法がわかりづらかったので参考になった
シニアエンジニアに聞いたvue関連ライブラリの選定方法

同僚の @kubotak さんに聞いたライブラリ選定基準をまとめます。今回は特にフロントエンド領域でvueに絞って書きます。


# 1. 公式がまとめているライブラリリストをみる
まずはともあれ、vuejsが公式でまとめているライブラリリストを参照する。

https://github.com/vuejs/awesome-vue

ここにやりたいことにマッチしそうなライブラリを全部一通り見てみる。


# 2. star数を確認する
あまりにも使っている人が少ないと、コミュニティがないことが想定される

# 3. 新規 issue を確認して、それがPRに反映されているか
issue が無いのはユーザが少ないか、すでに枯れている（安定してバグなども少ない）ライブラリ。

issue が多いのにPRが作られていない、またはマージされていないライブラリはメンテナが居なくなっているので避けるのが吉。

# 4. 最終リリースタグとnpmのページを確認する
githubでreleasesをみると最後にいつリリースされているかわかる。ただしnpmの場合にはrelease tagが切られていなくてもnpm packageとしてリリースされていることがあるのでそちらも確認する。
あまりに古いのだと新しいvueバージョンに追従できない可能性などを考慮した方が良い。

# 5. readme がきちんと書かれているか
有用な情報が書かれていないと導入は辛くなります。

# 6. 動作例が書かれているか
あれば何ができるかよりイメージがつきやすくなります。無い場合には自分で動かさないといけないのでややハードルは上がる。

# 7. ファイルサイズは大きすぎないか
あまりに便利すぎるライブラリは全部入りでファイルサイズが大きくなりがちです。
nuxtなどフレームワークで適切に配信されるものが分割される場合にはそこまでシビアにならなくても良い。

# 8. 2個くらいまで絞り込めたら実際に使ってみる
何個かまで絞れて迷うところまできたら、導入しやすそうか使いやすそうかを実際に使ってみて確かめる。
AWS SES のSMTPエンドポイント を使って YAMAHA RTXルーターからメール通知

# 概要
- YAMAHA RTXルーターからメール通知を設定したい
- 専用のメールサーバを立てたり契約したりするのは面倒くさいので避けたい
- AWS SESで、SMTPエンドポイントを使って送信できないか？を試行錯誤

# 前提
- 独自ドメインを保有している。
- AWSアカウントを保有している。
- 今回試した環境は YAMAHA RTX1210

# 1. SESのセッティングを行う
- SMTPエンドポイントを利用して、IAMのAPIキーでメール送信可能になるまでSES環境をセットアップする。
- SESのセットアップ方法は世にたくさん記事があるのでここでは割愛。
- ポイントは`DNSでDKIM・SPFレコードの設定`、`サンドボックス解除の緩和申請を行う`

### 参考にした記事
- https://www.slideshare.net/AmazonWebServicesJapan/aws-30934799
- https://docs.aws.amazon.com/ja_jp/ses/latest/DeveloperGuide/Welcome.html
- https://dev.classmethod.jp/cloud/aws/sendmail-from-ses-smtpendpoint/
- http://blog.serverworks.co.jp/tech/2020/02/08/ses-smtp-interface/

# 2. ルーター上でメールサーバ設定を行う
- SMTPエンドポイントでメール送信する時にいくつか接続要件があるので従う
- https://docs.aws.amazon.com/ja_jp/ses/latest/DeveloperGuide/smtp-connect.html
- ポイントは `SMTPS(ポート465、TLS）を利用`+ `SMTP-AUTHはPLAINで送信でよい`

## CLIの場合
- マニュアル: http://www.rtpro.yamaha.co.jp/RT/manual/rt-common/mail_notify_trigger/mail_server_smtp.html

```
mail server smtp <<設定番号>> <<SMTPエンドポイントのFQDN>> port=465 smtp-auth <<APIキー>> <<Secret>> smtps
```

## WEB GUIで設定する場合

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/75076/fa036070-be18-b780-c469-e7baa63184b2.png)

# 設定後
- 設定完了後にメール通知テンプレートを設定。
- WEB GUIから`今すぐ通知`機能などで送信テスト。
- ダッシュボードの　Syslogで`MAIL` でフィルタすると送信状況を確認できる。
- SESのセットアップで独自ドメインのSPF設定が漏れていると受信先で迷惑メールに分類されるので注意したい
まだStoryboardの多言語対応で消耗してるの？ローカライズの最強ベストプラクティス対応法

こんにちは。もぐめっとです。

Qiita初投稿です。

先日、大先輩の[fmtonakai](https://qiita.com/fmtonakai)大師匠からすごい目からウロコのstoryboardのローカライズ対応について教えてもらいました。
普段は[自分のブログ](https://blog.mogmet.com)に書いているのですが、あまりにも目からウロコ過ぎたのでQiitaで共有しておきます。

## storyboardにローカライズのキーを指定できるようにする

```UILabel+Extension.swift
extension UILabel {
    @IBInspectable
    private var localizedKey: String? {
        get { fatalError("only set this value") }
        set {
            if let newValue = newValue {
                text = newValue.localized()
            }
        }
    }
}
```
```String+Extension.swift
extension String {
    func localized() -> String? {
        return NSLocalizedString(self, comment: "")
    }
}
```

こう書いておくだけで、Android Studioのようにstoryboardからキーを設定してローカライズすることができるようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42234/a759f4b1-f28e-61fe-0c5e-6f2ffe9fa9e7.png)

すごい！画期的！！

## ローカライズのキーtypoを防ぐ その１

このままだと、typoとかしたときにローカライズのキーがそのまま表示されてしまうのでローカライズ漏れに気づけるように改良してみました。

```String+Extension.swift
extension String {
    private static let localizedEmptyKey = "##not exists##"
    func localized() -> String {
        let string = NSLocalizedString(self, tableName: nil, bundle: Bundle.main, value: String.localizedEmptyKey, comment: "")
        if string == String.localizedEmptyKey {
            fatalError("not exists localized key")
        }
        return string
    }
}
```
キーが無かった場合には強制的にアプリを落としてしまうことによってキーの漏れに気づけるようになりました。

## ローカライズのキーtypoを防ぐ その2

その1の対応だと、画面を表示したときでないとtypoに気づけません。

そこで、ビルド時にキーのチェックをしてtypoに気づけるようにさらに改良してみました。

Build Phasesに下記スクリプトを追加するだけ！

```RunScript.sh
#!/bin/bash

for file in `\find . -name \*.storyboard`; do
    IFS=$'\n'
    for xmlKey in `\grep 'keyPath="localizedKey"' ${file}`; do
        localizedKey=`echo $xmlKey | sed -e 's/.* keyPath="localizedKey" value="\([0-9a-zA-Z_-]*\)".*/\1/g'`
        for localizedStringFile in `\find ${SRCROOT} -name Localizable.strings`; do
            grep "\"${localizedKey}\" =" $localizedStringFile > /dev/null 2>&1
            if [ $? != 0 ]; then
                echo "not exists key '${localizedKey}' in ${localizedStringFile}"
                exit 1
            fi
        done
    done
done
```
storyboardで設定されているlocalizedKeyをひっぱてきてLocalizable.stringsのファイルと突き合わせて存在しなければエラーを吐き出します。

## まとめ

Android Studioに比べるとxcodeで至らぬところというのはまだまだありますが、今回の対応でLocalizable.stringsに文言を集約することができるようになり、よりローカライズがしやすくなってとってもウロコな方法でした。

storyboardでのローカライズはこの方法でやって、コードでの動的なローカライズについてはR.swiftやswiftgenなどで対応していって適材適所に使ってローカライズしていけるといいと思います。

今回の検証コードは[こちら](https://github.com/mogmet/LocalizedStoryboard)においてあります。

Special Thanks [fmtonakai](https://qiita.com/fmtonakai)
【Microsoft Graph API & Powershell】Connect-MSGraphでのログインをCUI化

# 前提
Connect-MSGraphでのサインインをCUI化する方法を書いています。
通常Connect-MSGraphコマンドだけを単体で実行するとブラウザ経由で管理者権限でのGUIサインインの入力を求められます。その手順をCUIで実現することが目的です。

Connect-MSGraphは動作が不安定で、同じ環境で複数回実行しても成功することと失敗することがあります。そのため、ログインが成功するまでwhileでループさせて、try-catch文でエラーをキャッチした場合はリトライし、成功するまでサインインを繰り返す方式を取っています。

Microsoft側のサーバー負荷やAPI回数制限のことを考慮して再接続を試すまでに3秒インターバルを置いています。

また、パスワードをコード内にベタ書きするのはセキュリティ的に望ましくないため、暗号化パスワードファイルをあらかじめ生成しておいて、ログインの際にそのファイルの中身を取得する方法をとっています。

Connect-MSGraphがIntune-PowerShell-SDKのメソッドなので当然ですが、Intune-PowerShell-SDKが実行PCにインストールされていないと動きません。

また、本記事はIntuneSDKのConnect-MSGraphメソッドについてのものですが、Connect-AzureADなどでも流用できるかと思います。

開発歴一年くらいの人間が書いてるのでツッコミ歓迎します。

■参考資料

・microsoft / Intune-PowerShell-SDK（公式ドキュメント）
https://github.com/microsoft/Intune-PowerShell-SDK
　IntuneSDKのGitHubです。SDKのインストール手順も記載されています。
　※インストールがエラーになる場合、Powershellの実行ポリシーが変更されてるかもチェックしてください。

・パスワードをスクリプトに埋め込むなんてありえない！Tableau ServerのTSMコマンド用スクリプトへ移行する方法
　Graph APIに関する記事ではありませんが、Powershellでのパスワード暗号化ファイルの作成手順として流用しています。
https://dev.classmethod.jp/business/bigdata/20181017-tableau-server-migrate-tsm-command-for-regacy-scripts/

・Microsoft Graph 調整ガイド（公式ドキュメント）
　APIリクエストの回数制限について記載されています。
https://docs.microsoft.com/ja-jp/graph/throttling


# 事前準備
### 暗号化パスワードファイルの作成
$FilePathはパスワードファイルを生成したいパスに変更してください。

```$FilePath = "C:\Users\administrator\Desktop\password.sec"
$Credential = Get-Credential
$Credential.Password | ConvertFrom-SecureString | Set-Content $FilePath```

上記を実行するとアカウントとパスワードが生成されるので、Graph APIで使用するアカウントとパスワードを入力してください。
サインイン後、指定したパスに暗号化されたパスワードファイルが生成されます。

※他のPCで作成したパスワードファイルは流用できないようなので、
　Powershellの実行PCが変わったときはパスワードファイルの再作成が必要です。

# サインイン

```
# サインイン用アカウントを指定
$adminUPN = "test@xxxx.co.jp"
# パスワードファイルのパスを指定
$adminPwd = Get-Content "C:\Users\administrator\Desktop\password.sec" | ConvertTo-SecureString

$creds = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList ($adminUPN, $adminPwd)
	while($true){
		try {
		# 3秒待つ
		Start-Sleep -s 3
		Connect-MSGraph -PSCredential $creds
		return;
     		}
		catch
		{}
	}
```
成功後、Invoke-MSGraphRequestメソッドが使えるようになります。




以上
Springの配列の環境変数を外から投入する

## 環境変数でconfを上書きする

やり方次第だとは思いますが、spring batchでバッチをつくった際、ジョブスケジューラ側で変数をハンドリングした方が楽なケースもあると思います。
[Springの説明](https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-external-config-application-property-files) 記載の通り、```spring.config.name```を、```SPRING_CONFIG_NAME```で書き換えられるのです。
（設定ファイルから環境変数を参照するのではなく、上書きです）

が、配列をどういれるのかわからなかったので、メモしておきます。

```application.yml

hoge:
  fuga:
    - a
    - b
    - c
```

これを上書きするには、

```exec.sh
export HOGE_FUGA_0=a
export HOGE_FUGA_1=b
export HOGE_FUGA_2=c
``` 

なるほど。。。
tomcat9 エラー 「HTTP メソッド名に不正な文字が含まれています。」を解決 

# 概要
tomcat9 の環境で「HTTP メソッド名に不正な文字が含まれています。」のエラー発生。
server.xml の redirectPort に書いてあるポートを、別のhttpdプロセスが利用していた。
redirectPortの番号を書き換えて解決。

# tomcat の エラー
```catalina.xxxx-xx-xx.log
17-Mar-2020 xx:xx:xx.xxx 情報 [http-nio-8090-exec-xx] org.apache.coyote.http11.Http11Processor.service HTTP リクエストヘッダーを解釈できませんでした。注：HTTPリクエスト構文解析エラーがさらに発生すると、DEBUGレベルでログに記録されます。
	java.lang.IllegalArgumentException: HTTP メソッド名に不正な文字が含まれています。HTTP メソッド名は決められたトークンでなければなりません。
		at org.apache.coyote.http11.Http11InputBuffer.parseRequestLine(Http11InputBuffer.java:415)
		at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:294)
		at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
		at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:853)
		at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1587)
		at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
		at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
		at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
		at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
		at java.lang.Thread.run(Thread.java:748)
```

# 設定
```server.xml
...
    <Service name="Tomcat-Standalone">
        <Connector port="8090" connectionTimeout="20000" redirectPort="8443"
                   maxThreads="48" minSpareThreads="10"
                   enableLookups="false" acceptCount="10" debug="0" URIEncoding="UTF-8"
                   protocol="org.apache.coyote.http11.Http11NioProtocol"/>
```

# 調査結果
無関係なhttpdサーバがポート8443を使っていた。
にも係わらず、server.xml で redirectPort に ポート8443が設定されていた。
redirectPort を該当サーバではどのプロセスも使用していないポート番号に設定し、tomcat を再起動したところ、エラーが解消
[Ktor]rest-assuredでList<Any>を取得してAnyを利用する

Ktorのテストコードでrest-assuredを用いてAPI呼び出しをする際の話。

List<Any>形式で受け取りたい場合に、Extractでto\<List\<Any>>()を使用した後に
アサーションのために値を利用しようとすると、Jacksonのデシリアライズに失敗してClassCastExceptionとなってしまうので、その対策。

今回はrest-assuredのkotlin拡張を利用していますが、利用しなくても特に問題はありません。

## Gradle
``` gradle
    testImplementation "org.assertj:assertj-core:3.14.0"
    testImplementation "io.rest-assured:rest-assured:4.1.2"
    testImplementation group: 'io.rest-assured', name: 'kotlin-extensions', version: '4.1.2'
```

## Test
```kotlin
@Test
fun testGetHoge() {
    var hoges = mutableListOf<Hoge>()
    transaction {
        hoges.add(Hoge.new { name = "taro" })
        hoges.add(Hoge.new { name = "jiro" })
    }

    val results = Given {
        contentType(ContentType.JSON)
    } When {
        get("/hoge")
    } Then {
        statusCode(200)
    } Extract {
        // resultsの型は、(Mutable)List<HogeData>!になる
        body().jsonPath().getList(".", HogeData::class.java)
    }

    assertEquals(hoges.size, results.size())
    // to<List<HogeData>>()だと、results[0].nameに失敗する
    assertEquals(hoges[0].name, results[0].name)
    assertEquals(hoges[1].name, results[1].name)
}
```

## 関連記事とか
java - java.lang.ClassCastException:java.util.LinkedHashMapをcom.testing.models.Accountにキャストできません
https://ja.coder.work/so/java/67788

java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to com.testing.models.Account
https://stackoverflow.com/questions/28821715/java-lang-classcastexception-java-util-linkedhashmap-cannot-be-cast-to-com-test
さくらのVPSに無料SSL証明書 Let’Encryptを導入

参考にしたリンクとか、メモとか。。。

## さくらのVPSに無料SSL証明書 Let’s Encryptを導入

参考：
https://knowledge.sakura.ad.jp/10534/

## 詰まったとこ。
「仮想ポートを設定してください」というエラー

参考：
https://hacknote.jp/archives/48748/

## Please choose whether or not to redirect HTTP traffic to HTTPS, removing HTTP access.って聞かれた

１を選んだ。

参考：
https://jonkara.net/2017/10/12/ssl_lets_encrypt/


・・・これで導入できたよね。
composerコマンドメモ

composerでコマンド触るときによく忘れるのでメモ

## Composer自体のバージョンを確認
``composer -v``

## Composerによってインストール済みのパッケージ一覧を表示
``composer show``

## インストールされているパッケージが、ローカルで変更していないか(変更があったパッケージをリストアップ)
``composer status``

## packageの更新を行う際に、何が更新されるか更新対象を事前にチェックする
``composer update --dry-run``
※dry-runオプションをつけると、何が更新されるかを確認するだけで実際の変更は行われない。

## オプション
オプションで``-vvv``をつけると詳細のログが確認できる
AWSのCloudFormationのテンプレートを作成中に依存循環のエラーが発生した。

cloudFormationを使っていたところ、依存循環のエラーが発生し少しハマってしまった。
AWS初学者です。エンジニアとして一年目なので、そこを考慮して見ていただけると幸いです。間違っている点などありましたら、教えてください。。

# 環境
Amzon Linux2

# エラーの内容
cloudformationのテンプレート作成中に以下のエラーが発生。調べると、依存循環のエラーとのことらしい。

```
[cfn-lint] E3004: Circular Dependencies for resource Ec2InstanceServer.  Circular dependency with [WpLaunchTemplate, Ec2InstanceServer]
```

以下、エラーが出たコード部分です。

```
---省略---
Parameters:
  DBPassword:
    NoEcho: true
    Description: The database admin account password
    Type: String
    MinLength: 8
    MaxLength: 41
    AllowedPattern: '[a-zA-Z0-9]*'
    ConstraintDescription: must contain only alphanumeric characters.

---省略---

Resources:
 WpLaunchTemplate:
  Type: AWS::EC2::LaunchTemplate
  Properties:
   LaunchTemplateName: wp-launch-template
   LaunchTemplateData:
    UserData:
      Fn::Base64: !Sub
        - |
          #!/bin/bash
---省略---
          echo 'grant all on wpdb.* to wpadmin@${Ec2Ipaddress} identified by '${DBPassword}'' | mysql --defaults-extra-file=/etc/my.cnf.d/client.cnf
        - {
           Ec2Ipaddress: !GetAtt Ec2InstanceServer.PrivateIp,
          }

---省略---
```

EC2のUserDataの中で自リソースを!GetAttで参照していたことがエラーの原因とのこと。
CloudFormationでは、組込関数(!Refや!GetAttなど)を使用すると、依存関係が自動的に作られる。
Aリソース内に!RefでBリソースを参照した場合、リソースが作成される順番は
　Bリソース　→　Aリソース

依存循環のエラーになる場合
Aリソース内に!RefでBリソースを参照しかつ、Bリソース内でも!Refなどの組込関数でAリソースを参照した時。
　Bリソース　⇄　Aリソース
上のような状態になり、どちらから作成していいのか判断できなくなる。

# 解決
EC2のパブリックIpアドレスをシェルスクリプト内で使用したかっただけなので、以下のようにコマンドを修正し、!GetAttを削除。
grant all on wpdb.* to 'wpadmin'@'`hostname -i`' identified by '${DBPassword}';
元々、シェルスクリプトやコマンドについての知識不足で、この書き方に気づけなかった。


## ちなみに複数のIPアドレスが振られている場合は以下のようにした。
```
// eth0
$ hostname -I | cut -f1 -d' '
// eth1
$ hostname -I | cut -f2 -d' '
```

### 各コマンドについて
①cutコマンドについて
cut -f 項目数 -d 区切り文字 ファイル名
ex)
`cut -f 2 -d ":" sample.txt`
ファイルsample.txtを「:」の文字で区切り、その２項目目を表示するコマンド

②hostnameコマンドについて
`hostname -i`
ホストのIPアドレスを表示するコマンド

# 参考
組込関数について
https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference.html
循環依存について
https://note.com/amakata/n/n914e5b87fbcd
cut・hosnameのコマンドについて
https://moomindani.wordpress.com/2014/09/17/linux-command-ip-address/
GAS版Moment.jsメモ

タイトルの通り、GAS版Moment.jsを使ってみて分かった事まとめです。
使用バージョンは9です（執筆時点での最新Ver.）

## 追記：Moment.jsはレガシープロジェクトになりました
Moment.js for Apps ScriptのおおもとであるJSのMoment.jsは2020年9月をもって新機能などの開発は廃止となりました。 詳しくは[こちら](https://momentjs.com/docs/#/-project-status/)
今後新規開発するときはあまりMoment.jsを使わない方がいいかもしれません。

JSとしては[Luxon](https://moment.github.io/luxon/)というのが後継となるそうです。
Luxon for Apps Scriptとかできるといいですね！

## Moment.jsとは
momentオブジェクトの各要素を使って、

- 日付をフォーマットして出力
- 日付の計算・比較

などといった事ができる便利ライブラリ

## ライブラリのインポート
スクリプトエディタで[リソース] > [ライブラリ]を押下。
表示されるダイアログのAdd a libraryの所に"MHMchiX6c1bwSqGM1PZiW_PxhMjh3Sh48"を入力すると使えるようになります。

## 使い方
とりあえず実行例をもくもくと挙げていきます。

今回の比較では'days'しか挙げませんが、'years','months','days','hours','minutes','seconds'とかが使えるはずです(確認してません)

※Logger.log()を省略してます

```javascript

Moment.moment('2020/03/03'); //momentオブジェクト生成
Moment.moment('2020/03/03').format('YYYY年MM月DD日'); //'2020年03月03日'
Moment.moment('2020/03/10').startOf('month').format(); //月のはじめ2020-03-01T00:00:00+09:00
Moment.moment('2020/03/10').endOf('month').format(); //月のおわり
Moment.moment('2020/03/10').month(); //何月か 3
Moment.moment('2020/03/10').date(); //何日か 10

var start = Moment.moment('2020/03/01');
var end = Moment.moment('2020/03/08');
end.diff(start, "days"); //日付差 7.0

//以下Ver.8で動かない可能性あり
end.isBefore(start, "days"); //指定した日より前かどうか。つまりif(end < start) 結果はfalse
end.isAfter(start,"days"); //if(end > start) true
end.isSame(start,"days"); //同じ日かどうか
```

## 本家Moment.jsでは使えるけどGAS版では使えないもの

以下は使えませんでした。

- isSameOrBefore
- isSameOrAfter
PyGithubを使って、GitHubの情報を取得する

こんにちは、[@yshr10ic](https://twitter.com/yshr_10ic)です。

最近、アウトプットの目標として、GitHubに1日1コミット以上することを心掛けています。（もちろん、コミットすることが目的ではいけないことは重々承知しています。）

せっかく毎日コミットするのだから、どれくらいコミットしたのか可視化したいと思いました。そこで、GitHubのコミットログを取得する方法を調べていたところ、[PyGithub](https://github.com/PyGithub/PyGithub)の存在を知りました。

本記事では、PyGithubの使い方を簡単にまとめたいと思います。

# PyGithubとは

> PyGitHub is a Python library to access the GitHub API v3 and Github Enterprise API v3. This library enables you to manage GitHub resources such as repositories, user profiles, and organizations in your Python applications.

`GitHub API v3`および`Github Enterprise API v3`にアクセスするためのライブラリ。リポジトリやユーザプロファイル、組織のようなGitHubのリソースをあなたのPythonアプリケーションで管理することができるようになります。

# PyGithubのインストール

```
$ pip install PyGithub
```

私の環境では、バージョンは`1.47`です。

# PyGithubの使い方

[PyGithub - Examples](https://pygithub.readthedocs.io/en/latest/examples.html)から一部抜粋。

## GitHubインスタンスの作成

```python:create_instance.py
from github import Github

# ユーザ名、パスワードによるインスタンス生成
g = GitHub('username', 'password')

# アクセストークンによるインスタンス生成
g = Github('access_token')

# カスタムホストによるGitHubエンタープライズのインスタンス生成
g = Github(base_url='https://{hostname}/api/v3', login_or_token='access_token')
```

## リポジトリ一覧の取得

```python:get_repos.py
for repo in g.get_user().get_repos():
    print(repo)
```

出力

```
Repository(full_name="yshr10ic/deep-learning-from-scratch")
Repository(full_name="yshr10ic/deep-learning-from-scratch-2")
...
```

## スター数の取得

```python:get_count_of_stars.py
repo = g.get_repo('yshr10ic/deep-learning-from-scratch-2')
print(repo.stargazers_count)
```

出力

```
1
```

## ブランチ一覧の取得

```python:get_branches.py
repo = g.get_repo('yshr10ic/deep-learning-from-scratch-2')
for branch in repo.get_branches():
    print(branch)
```

出力

```
Branch(name="images")
Branch(name="master")
```

## コミットしたファイル一覧の取得

```python:get_committed_files.py
repo = g.get_repo('yshr10ic/sample')
for commit in repo.get_commits():
    print(commit.files)
```

出力

```
[File(sha="xxx", filename="django/djangorestframework/tutorial/tutorial/urls.py")]
[File(sha="yyy", filename="django/djangorestframework/tutorial/tutorial/quickstart/views.py")]
[File(sha="zzz", filename="django/djangorestframework/tutorial/tutorial/quickstart/serializers.py")]
...
```

# まとめ

今回は、既にあるGitHubリポジトリの情報を取得するだけでしたが、実際にはファイルの作成や、プルリク、イシューの作成などもできます。

GitHubインスタンスの生成から各種情報の取得までをやってみましたが、非常に簡単に情報を取得できて良かったですね。ただ、「どれくらいコミットしたのか可視化したい」という当初の目的を達成するには、コミットログを時間で検索できないといけません。PyGithubだと時間による検索ができそうもないので、他の手段も検討してみます。
リンク時にsonameを無視(できなかった)



```c:func.c
int op(int x,int y){return x+y;}
```

```c:gateway.c
int op(int x,int y);
int gateway(){return op(123,456);}
```

```c:main.c
#include <stdio.h>
int gateway();
int main(){
    printf("%d\n",gateway());
}
```

```sh:main.sh
mkdir -p mul
cat func.c | gcc -O2 -s -shared -Wl,-soname,func.so -o func.so -xc -
cat func.c | sed 's/+/*/' | gcc -O2 -s -shared -Wl,-soname,func.so -o mul/func.so -xc -
#patchelf --set-soname '' mul/func.so
gcc -O2 -s -shared -o gateway.so gateway.c $PWD/mul/func.so
#patchelf --replace-needed func.so $PWD/mul/func.so gateway.so
gcc -O2 -s main.c gateway.so
./a.out
```

このような状況で、a.outに(579ではなく)56088を出力させたい。 **ただしfunc.soのコンパイルオプションは変更できないものとする。**

試行錯誤してみたが、どうしてもpatchelfを使う(2箇所あるpatchelfのうち片方をコメントアウトする)必要があった。
【Salesforce】開発者コンソールのリセット方法

#状況
　開発者コンソールはエラー状態に続ける。https\://YOURORGANISATINO.my.salesforce.com/_ui/common/apex/debug/ApexCSIPageを使って別のタブで開いても解決できない。

#対策
　上記状況の場合、開発者コンソールをリセットしなければならない。次はリセット手順（ブラウザはchromeです）を紹介します。

#リセット手順

1. IDEWorkspace IDの取得

　　1-1. 開発者コンソール画面を開いてる状況のままで、DevToolsを開きます。
　　1-2. 「Network」タブをクリックして、「Filter」に「IDEWorkspace」を入力して、必要なリクエストしか絞り込みように設定します。
　　1-3. 開発者コンソール画面を再読み込んで、絞り込んだリクエストに18桁のIDをメモします。これはIDEWorkspace IDです。
2. 開発者コンソール状況確認（必要なら）

　　2-1. 下記コードを任意なApexカスタマイズコントローラに貼り付けます。コード中のIDEWorkspace IDを1-3で取得したIDEWorkspace IDに入り替えて

```java:
    system.debug('session id: ' + userinfo.getSessionId());
    Http h = new Http();
    HttpRequest req = new HttpRequest();
    req.setEndpoint(Url.getOrgDomainUrl().toExternalForm() + \'/services/data/v48.0/tooling/sobjects/IDEWorkspace/IDEWorkspace ID\');
    req.setMethod('GET');
    req.setHeader('Authorization', 'Bearer ' + UserInfo.getSessionId());
    HttpResponse res = h.send(req);
    System.debug(res.getStatusCode());
    System.debug(res);
```

　　2-2、該当コードを所有しているApexを正常の方法（画面上のボタンをクリックするなど）で実行すれば、ログ中に情報を出力できます。
3. 開発者コンソールのリセット

　　2の開発者コンソール状況確認と同じフローで実施して、なお2-1のコード中の「<font color="red"><B>GET</B></font>」を「<font color="red"><B>DELETE</B></font>」

```java:
    system.debug('session id: ' + userinfo.getSessionId());
    Http h = new Http();
    HttpRequest req = new HttpRequest();
    req.setEndpoint(Url.getOrgDomainUrl().toExternalForm() + \'/services/data/v48.0/tooling/sobjects/IDEWorkspace/IDEWorkspace ID\');
    req.setMethod('DELETE');
    req.setHeader('Authorization', 'Bearer ' + UserInfo.getSessionId());
    HttpResponse res = h.send(req);
    System.debug(res.getStatusCode());
    System.debug(res);
   
```
LaravelのQueryBuilderのfirst()で結果が無かった時の処理と空判定

## はじめに: LaravelのQuerybuilderのfirst()がどんな動きをしているか確認
書きの記事を参考にしてLaravelのQuerybuilderのfirst()がどんな動きをしているか確認します。
[QueryBuilderのfirst()の動きを調べてみた](https://qiita.com/gomaaa/items/69d963c24f60960cfc94)

## 結果が無い場合の返り値

>結果が無かったら
5.1ではnull
5.3から collect([])が返ってくるようです

バージョンによって少し異なるようですがLaraevl6.4でlogger（）で吐かせたところ
Objectの`{}`が返却されていました。

## isEmpty()とかempty()で判定したい

colectionでもarrayでも無いのでできません。
さえ、どうしましょう。。。

```php
if (!$res->count()) {
  // coentが0の場合の処理
}
```

今回はこんな感じにしました。
時間が無いので検証などできませんでしたが、今度時間がある時にもう少し理解を深めたいと思います。
すべてのファイルをBase64エンコードして、別々のファイルにリダイレクトする

テストのために多量の画像ファイルをBase64エンコードしなくちゃいけなくなったので、そのためのワンライナーを記録しておきます。


## コード

カレントディレクトリ直下の`img`ディレクトリ内にあるpngファイルをすべてbase64エンコードして、元ファイル名の末尾に.txtを付けたテキストファイルに書き出します。

```bash
find ./img -name '*.png' -type f -print0 | xargs -0 -i{} sh -c 'base64 {} > {}.txt'
```

ファイル名に`{}`が含まれる場合は上手くいかないと思います。


## 解説

`find`と`xargs`の組み合わせは非常に強力で、多くのファイル操作を自動化してくれます。


```
find [dir] -name [pattern] -type f -print0
```

ディレクトリ`[dir]`内の`[pattern]`にマッチするファイルのファイル名の一覧を出力します。

`-print0`オプションは、出力結果の区切り文字を空白文字からNull文字に置換します。これは、ファイル名に空白文字を含むファイルがあったときにも、適切に動作させるためのものです。


```
xargs -0 -i[replace-str] [command]
```

`[command]`の引数に、標準入力を渡します。

`-0`オプションをつけると、Null文字を引数の区切り文字とします（このオプションがないと、空白文字が区切り文字になります）。`find`の`-print0`オプションと合わせて、ファイル名に空白文字を含む場合も適切に動作するようになります。このオプションを省略し、たとえば、`a b.png`が標準入力に渡された場合、`[command] a b.png`（`$1`が`a`、`$2`が`b.png`）が実行されることになってしまいます。

`-i[replace text]`オプションは、`[command]`内の`[replace text]`を、標準入力の値に置換します。
なお、本来`xargs`は、標準入力に複数の入力が与えられた場合、それらすべてを一度にコマンドの引数に渡しますが、このオプションが指定された場合は、標準入力を1つずつ渡します。
つまり、`1.png 2.png`が標準入力に渡された場合、通常は`[command] 1.png 2.png`が実行されるところを、`[command] 1.png`と`[command] 2.png`が実行されることになります。
ちなみに、`xargs`には`-n`オプションがあり、一度にコマンドに渡す引数の数を指定できます。


```
sh -c [expression]
```

`[expression]`を実行します。


## 補足

一応補足しておきますが、上記のコマンドはOSコマンドインジェクションの脆弱性がありますので、本番稼働しているシステムに組み込んだりすることは、お止め下さい。


以上です。
誤り等ございましたらご指摘下さい。
GCP Cloud AutoML Vision を使った鼓膜画像分類

#概要
普段は耳鼻咽喉科の開業医をしています。

以前Microsoft Custom Vision Service を使用して鼓膜画像の分類モデルを作成してみました。
以前の記事はこちら
[Microsoft Custom Vision Service を使用した鼓膜画像認識](https://qiita.com/doikatsuyuki/items/bbed5e902577d68fb8a9)
[Microsoft Custom Vision Serviceによる中耳炎画像認識LINE Botの作成](https://qiita.com/doikatsuyuki/items/61f0a8a6eb523da58947)
[鼓膜の画像を送り質問に返答すれば、自動で中耳炎の診断や治療方針が返されるLINE Botを作成（ヒーローズ・リーグ2019 LINEテーマ賞）](https://qiita.com/doikatsuyuki/items/216e9f954f9a09b834d6)

今回Google Cloud Platformが提供する機械学習サービスの１つであり、画像分類を行うことが出来るAutoML Visionを使って鼓膜画像分類モデルを作成してみました。


[AutoML Vison](https://cloud.google.com/vision/automl/docs/?hl=ja)


#作成方法
**1.鼓膜データ収集**

使用した鼓膜画像は画像認識技術開発のために使用することに同意いただいたものを匿名化し使わせて頂きました。train dataとして急性中耳炎103枚、正常鼓膜102枚、滲出性中耳炎101枚を用意しました。
（最適なモデルを作成するには、各ラベルに少なくとも 100 個の画像を含める必要があると書かれています。）

**2.画像のインポート**

Google Cloud Platformのコンソール画面左上のハンバーガーメニューから『Vison』を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/453374/8490efe1-6852-bff7-2d06-e73a44b8f9dd.png)
AutoML Vision　『使ってみる』を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/453374/5c26fa18-ded3-28a8-4487-9d80a9903bab.png)
『データセット名』を適当に付けて、今回の場合は『単一ラベル分類』を選び、『データセットを作成』を選びます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/453374/1f087cc2-9a56-1554-54aa-761a7b041f32.png)
今回はパソコンから画像をアップロードします。
『BROWSE』を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/453374/6baad8b6-8bff-2f8a-5421-229571dea344.png)
バケットを作成します。名前を適当に付け、他は初期設定のまま作成しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/453374/2e54b345-8c8f-bda9-f697-80b83b798396.png)
今回は急性中耳炎・滲出性中耳炎・正常鼓膜の各ファイルが入ったzipファイル（train.zip）をパソコンから選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/453374/795089a1-d924-cab5-2244-9cb188be1773.png)
画像がインポートされました。
ファイル毎に分類されています（aom:急性中耳炎、normal:正常鼓膜、ome:滲出性中耳炎）。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/453374/89e19e5d-5f28-2ee6-1c84-f8e53d797c2a.png)

**3.トレーニング**

『トレーニング開始』を選択します。
今回トレーニングが終わるまで2時間ほどかかりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/453374/6e4f54ad-d93a-e048-51a3-31709aeb6d33.png)

鼓膜画像分類モデルができました。
平均適合率は98％です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/453374/a2e02ac6-d9fe-b4aa-e98e-0e66494a29c5.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/453374/8b883da1-bf47-f68e-a7c4-b8c70b805eaa.png)
滲出性中耳炎（ome）の判別が難しく、急性中耳炎（aom）に間違えやすいようです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/453374/fbe5244e-f5b1-f54b-e10e-d50a618a82c6.png)

#考察
AutoML Visionを使いノンコーディングで簡単に高精度の鼓膜画像分類モデルを構築することが出来ました。Microsoft Custom Vision Serviceに比べるとトレーニングにかかる時間がかなり長いようです。今度は構築したモデルをAPI経由でアプリやWebサービスから利用してみたいと思います。