OmniAICreator/Qiita-1.07M huggingface dataset:
Railsで短縮URL

## はじめに
今回は短縮URLをRailsで作っていきたいと思います。
他の記事ではBitlyが使われていたりするのですが、今回はGemの[shortener](https://github.com/jpmcgrath/shortener/)を使っていきたいと思います。
では早速始めていきましょう！！！
（すごく便利です。)
## どんな感じ？

```
http://localhost:3000/s/jsbei
```
こんな感じになります。localhostの部分がドメインになるかと思います。なので、Bitlyに比べてサイトがわかるので、信頼性が高いと思います。
## インストール
早速インストールしていきましょう。
まずGemfileに以下のように追記してください！！！

``` Gemfile
gem 'shortener'
```
そして、以下をターミナルで実行しください。

```
rails generate shortener
rails db:migrate
```
これで、インストールは完了しました。
##ルートの設定
ここまで来たら、もう少しです。
ルートの設定をしていきましょう。

``` ruby
get '/:id' => "shortener/shortened_urls#show"
```
これを追加するだけです。
これが追加できたら、

``` erb
<%= short_url("https://qiita.com/") %>
```
ヘルパーが提供されているので、上のようにすっきりと短縮URLを発行することができると思います。
## おまけ
自分が今アクセスしている、URLの短縮URLを発行する場合の実装をやっていきたいと思います。
### 自分のいまアクセスしているURLは？
以下のように呼び出せます！！！シンプル！！！

``` ruby
request.url
```
なので、合わせ技で

``` erb
<%= short_url(request.url) %>
```
このようになると思います。
## まとめ
Bitlyなどを使った短縮URLの実装より随分簡単だったと思います。
ここでは紹介しなかったこと以外にも[公式ドキュメント](https://github.com/jpmcgrath/shortener/)にはいろいろ書かれているので、公式ドキュメントも活用してみてください！！！！
【VSCode】既存の拡張機能はカスタマイズして、独自仕様にできます。【勉強用にも】

# 手順のまとめ

1. [Visual Studio Marketplace](https://marketplace.visualstudio.com/)（拡張機能がここで公開されています。）で手頃な拡張機能を探す。
2. GitHubからソースを入手する。（GitHubへのリンクがあります。※拡張機能によってはリンクがないこともあります。）
3. 中身を修正してカスタマイズする。
4. `vsce package`を実行してVSIXを作成
5. VSCode上からコマンドパレットで`Extensions: Install from VSIX...`を実行、VSIXを選択して拡張機能をインストール

これだけで理解できる方は以下の解説は不要です。

# はじめに

前回の投稿で、独自の拡張機能を作る方法を解説しました。
[【拡張機能の作り方】Visual Studio Code（VSCode）のスニペット作成が面倒だったので、自作の拡張機能をインストールした。 \- Qiita](https://qiita.com/sfp_waterwalker/items/b2cbdbe1119ea46ab25e)

上記では、「yo code」というコマンドで拡張機能の雛形を作る方法を紹介しています。
ただ、すでに多くの拡張機能が**ソースを含めて公開されています**。
このソースをカスタマイズして独自仕様にすることもできるので今回はその手順を解説します。

# 手順

## Visual Studio Marketplaceで手頃な拡張機能を探す

[Visual Studio Marketplace](https://marketplace.visualstudio.com/)では、拡張機能が公開されています。
今回はWorkbenchという拡張機能を使ってみます。

[Workbench \- Visual Studio Marketplace](https://marketplace.visualstudio.com/items?itemName=andrew-lis.workbench)

## GitHubからソースを入手

VSCode拡張昨日は、ソースがGitHubで公開されているものも多くあります。
GitHubからZipをダウンロードしてみます。

<img width="1177" alt="スクリーンショット 2020-01-27 4.26.06.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27902/24b7df8c-8a37-34b6-18c2-5992d22a4e31.png">

<img width="1502" alt="スクリーンショット 2020-01-27 4.26.32.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/27902/eed06146-c3c5-4142-d2a5-b289de920c24.png">

[andrew\-lis/Workbench: Workbench \- the VSCode Extension](https://github.com/andrew-lis/Workbench)

## 中身を修正してカスタマイズ

中身は当然動くソースなので、イメージもつかんでいけると思います。
たいてい、`package.json`と`src/extensions.ts`に調整をかけていくことになると思います。
（Workbenchは、`src/extensions.ts`から`src/commands.ts`、`src/models.ts`が読み込まれているのでこれらもカスタマイズ対象でしょう。）

## VSIXを作成

ひととおりの調整が終わったら、`vsce package`を実行してVSIXを生成します。

## VSCodeで拡張機能をインストール

VSCode上からコマンドパレットで`Extensions: Install from VSIX...`を実行、VSIXを選択して拡張機能をインストールします。
これでカスタマイズした拡張機能を使うことができます。
JavaScript, PHPなど、これらの違い

#JavaScriptとPHPの違いとは？！
２つともプログラミング言語で
Webブラウザで動作するのは間違いないんですが…
一体何が違うのだろうか？
ということで調査してみた。


#JavaScriptとPHPの共通点
スクリプト言語。
コンピューターにソースコードを置いて直接実行できる。
コンピューターが機械語に変換しながら実行する。
コンパイル不要。

##　コンパイラ言語
C言語やJavaなど。
プログラムを実行するには、ソースコードを機械語に変換して「実行ファイル」を作成しておく必要がある。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/516313/9c0dd351-cd98-81c6-299d-1a8c451edd3e.png)


#JavaScriptとは
クライアントサイドスクリプト。
青文字の流れ。

私たちのパソコンの中で実行している。
Webサイトのリンクをクリックすると、サーバーにアクセスして
「見たいHTML、CSS、JavaScriptなどのソースコード、画像・音楽・動画ファイルなどなどをください」とお願いする。
そしてサーバーからダウンロードします。ダウンロードしたファイルをブラウザが実行する。
#PHPとは
サーバーサイドスクリプト。
赤文字の流れ。
Webサイトのリンクをクリックするとサーバーにアクセスする。
このWebサイトのデータが保存されているサーバー側で動作するのがPHP。
データベースにアクセスしてその都度必要なHTMLファイルを生成し直す。
動的計画法を分けるやつ

DPを分けると計算量が落ちることがあります。やってみよう。

##例えば何を分けるのか
例えば、次の遷移を考えます。数列 $a$ が与えられて、

$dp_{x+1}=a_x+\sum_{k=1}^{x}dp_k$
$dp_{0}=1$

と表せるdpがあったとします。愚直に組んでみましょう。

```python:python_de_kakuyo.py
dp[0] = 1
for i in range(N):
  dp[i + 1] = a[i]
  for j in range(i + 1):
    dp[i + 1] += dp[j]
```

二重ループを使うので計算量は $O(N^2)$ です。遅いですね。

ここで、dpを次のようにdpとdp'に分けようと思います。
$dp_{x+1}=a_x+dp_x'$
$dp_{x+1}'=dp_x'+dp_{x+1}$
$dp_{0}=1$

次式が成り立つことがお分かりいただけると思います。
$dp_{x}'=\sum_{k=1}^{x}dp_k$

```python:python_de_kaitayo.py
dp1[0] = 1
for i in range(N):
  dp1[i + 1] = a[i] + dp2[i]
  dp2[i + 1] = dp2[i] + dp[i + 1]
```

dp'がdpの累積和として活躍し、計算量は $O(N)$ になりました。

このように、dpの遷移式が何かの和で表されている時にそれぞれを別の遷移として考えることで計算量が削減できる可能性があります。それだけです。

##ナップザックDPとの関連性
ナップザックDPの遷移は初心者クラッシャーとして有名ですが、dpを分けることで理解が進みます。（たぶんね:thinking:）あとpythonの定数倍高速化に使えます。

容量$W$のナップザックに荷物を詰めまくって詰めた荷物の価値の総和を最大化せよという「ナップザック問題」というのがあります。制約によって色々解き方が変わりますが、とりあえず次の遷移を考えます。

$dp_{x+1,y+w}=max(dp_{x+1,y+w} , dp_{x,y}+v)$
$dp_{x+1,y}=max(dp_{x+1,y} , dp_{x,y})$

境界条件を処理していないざっくり遷移ですが、上のような遷移でナップザックDPは進みます。ただし、x番目の荷物までをみていて、詰め込んだ荷物の重みの総和がyであるときの価値の総和の最大値を$dp_{x,y}$とおきました。wとvはそれぞれ荷物の重みと価値です。

dpを分けます。時間計算量は残念ながら変わりません。

$dp_{y+w}=max(dp_{y+w} , dp_{y}'+v)$
$dp_{y}'=max(dp_{y} , dp_{y}')$

荷物の重みの総和がyの時の価値の最大値が$dp_y$
dpを累積したのがdp'です。

ナップザックDPはこのように「それまでの状態を累積したdp'」と「更新していく最新のdp」の２つで表現可能で、この２つに分離させることで空間計算量を削減できます。


##どんな記事にも終わりはある

演習問題です。
ARC043: B - 難易度
https://atcoder.jp/contests/arc043/tasks/arc043_b

どうでしたか。これといって新しいテクニックではないですが、書いちゃいました。コードや遷移は何の動作確認もしていません。なにか間違っていたら言ってくださいね。:hugging:
Unity2D備忘録

<h1 class="article_heading" itemprop="headline">Unity2Dに関する私用の備忘録</h1>
<h2 id="説明">説明</h2>
制作で引っかかった点をまた同じミスをしたときに無駄な時間を過ごさないための記事
ものすごい、初歩的なミスをなくすための物。
<h2 id="衝突判定について">衝突判定について</h2>
voidの名前に2Dが入ってない、2Dではこれがないとダメ
（例）void OnCollisionEnter2D(Collision2D col)
メモリ使用が激しすぎる言語はゲームに向かない

ゲームによく使われる言語としてC,C++,C#,lua,Python,(JavaScript,Java,アセンブリ)等がありますが、メモリ使用量の多い言語とゲームに使われていない言語が物凄い強い相関関係があります。
一番メモリを使うであろうScalaはJavaの2~3倍(※要出典),F#はC#の1.5倍(※要出典),JavaはC#の2倍程(※要出典)メモリを食うと風の噂で聞いたことがあります(VMはメモリ消費が激しい傾向にある)。Pythonやluaはメモリ消費量比較的多いと言われるスクリプト言語の中ではメモリを殆ど消費しないC/C++より数倍程度で、ゲームのスクリプトや簡易処理に多用されます。C#はUnityで使われている。JavaやF#は2Dとかなら普通に使われている。他の言語は(特にメモリ使用量が多ければ多いほど)マイナー。

- 大体のメモリ使用量目安(比較/ネット記事より参照)
 - Scala **459,000**  ≪＝ヤバスギィ
 - Java 170,000
 - F# 127,500
 - C# 80,000
 - PHP 60,000
 - JavaScript 58,000
 - Python(Python3) 22,000
 - lua(lua/luajit) 20,000
 - C++ 5,000
 - C 2,000

#感想
以上を見て如何に**メモリの重要性**を思い知ることができた。5年くらい前まではよく組み込みとかでC++は**メモリを多く使うから駄目**とか言われていたらしいが(今では**開発の高速化要求**から少しずつ普及しているらしい),やはりメモリは資源の中でも重要なんだなと改めて知った。特にコンシューマーとかスマホやバックエンドなんかは1ソフト当たりの**メモリ,CPU資源が限られている**ので如何にCPUやメモリを使わずコードを見やすく書くかが肝であるのだと思います。それにしてもC言語の**約230倍**,Pythonの**約20倍**とかScalaのメモリ使用量はヤバイな...(はて、何個スマホがいるのやら...)どうやら、CとかMozillaの**Rust**(C++のライクなモダンな言語)とか(C++とか)はメモリ使用量が少ないらしい。

#速度については
C <= Rust < C++ <= Java <= C# <= VB.net <= F# << JavaScript = LuaJit < Lua < Ruby < Python <= PHP <= Perl << ShellScript = PowerShell の順らしいですが、メモリ使用量がさらに重要なのかJavaよりC#,JavaScriptよりPythonが使われる傾向がある。Rustは例外でどちらもC並みの優秀さがありますが、新しい言語のためライブラリーが揃ってないらしく、今からなのかなって思います。Rustのデフォルトイミュータブルやスコープの概念、型安全などはunsafeなコードから解放される優秀な機能なので、将来的には使われるのかな？って思います(MSも認めたし)。if式だったりは[C系の可読性を損なう演算子](https://qiita.com/raccy/items/0b25b2f106e2a813828b)から解放されたり、演算子と違って、else if で2つ以上の条件が調べられる点も優秀です。Rust早く普及してくれないかなぁ。
転職日記８日目

全くこちらを更新しなくて、個人的に少し申し訳なくおもってます。

というのも今月末までに何としてもポートフォリオを完成させたく

そちらの方ばかりやっていました。

そのせいか、寝る時間は、am1:00からam3:00にして、そこからプログラミングをはじめて、出社するという生活サイクル

筋トレをして、食生活を気をつければこんな睡眠時間でもきっちりやれてしまう気がするのです、

ポートフォリオに関して、こちらで報告できるように頑張ります。
ネットワークの基礎知識

#ネットワークとは

複数のパソコンなどコンピューターを接続して相互に通信できる状態。

#ネットワークの種類

- LAN(Local Area Network)

ランと読む。
狭いエリア（ひとつの建物内）のネットワーク。

- WAN(Wide Area Network)

ワンと読む。
LANで接続しきれない遠隔地のLAN同士を結ぶネットワーク。

#IPアドレス

PCなどの通信機器の所在を表すもの。
所在が分からないと通信できないため必ず必要。

- IPv4

現在広く利用されているIPアドレス方式。
8bit（8桁の2進数）× 4 = 32bit
ただし、32bitを8bitずつ「.」で分割して、その数値を10進数で表記する。
（例）
11000000　10101000　000000000　1100100（わざとスペースで区切っている）は
192.168.0.100となる。

- IPv6

IPv4のアドレス数を補うために構成されたIPアドレス。
16bit ×　8 = 128bitで構成されている。

- プライベートIPアドレス

LAN上で通信可能なIPアドレス。

- グローバルIPアドレス

世界に1つしかないIPアドレス。
インターネットに接続するには、必ずグローバルIPアドレスが必要。

#ドメイン
世界にひとつしかないネットワーク上の所在地情報。
ネットワーク上の住所にあたるIPアドレスは数字の羅列。
しかし、それでは扱いにくいので
数字（IPアドレス）を文字列（ドメイン）に変換する。

- DNS(Domain Name System)

IPアドレスとドメインの関連付けを管理するシステム。
通常のクラスからラムダ式に変形していく

#導入
こんにちは。けちょんです。
**皆さん、ラムダ式使ってますか？**
私はこれから初めて使います。ガチ素人です。

#以降、変形させていく

##クラス度100%
まず、Ruunableインターフェースを実装したクラスは以下ですね。

```
class lambda implements Runnable {
	@Override
	public void run() {
		System.out.print("OK");
	}
}
```
インターフェース通りに、runメソッドを実装して終了です。

##クラス度60%,ラムダ度40%
```
Runnable runner = new Runnable() {
	@Override
	public void run() {
		System.out.print("OKっぽい");
	}
}; // OKっぽい
```
ここでクラスが匿名化され、インスタンス化と同じ場所で定義されています。
最後の";"は省略するとコンパイルエラーになります。誰か教えてください。

##クラス度40%,ラムダ度60%
型推論等により、冗長な部分を削除していきます。
※ここからしばらくコンパイル通りません。

```
Runnable runner = {
	@Override
	public void run() {
		System.out.print("OKっぽい");
	}
}; // OKっぽい
```

```new Runnable()``` は左辺から型を推測できますね。

##クラス度20%,ラムダ度80%

```
Runnable runner = {
		{
		System.out.print("OKっぽい");
}; // OKっぽい
```

```public void run() ```はRunnableインターフェースがrunメソッドしか持たないことから、わざわざ指定する必要はありませんね。

##ラムダ度100%

```
Runnable runner = () -> System.out.print("OKっぽい");// OKっぽい
```

引数を表す```()->```を追加して、{}を省略して、ラムダ式の完成です。

#まとめ
JSみたいに書けるってことかな？？？
CloudformationでEC2を作った話

# はじめに
CloudformationでEC2の構築＋ユーザデータでM/W導入を自動化しようと思いました。
結論から言うとユーザデータ関連のテンプレートフォーマットエラーが解消できず、ただ単にCloudformationでEC2を作るだけの平凡な結果に終わってしまいました。

それでもCLoudformationについて多少勉強になったのでまとめます。
（今後解決策が見つかったら更新します）

# やろうとしたこと
- EC2インスタンスを作成
- テンプレートを修正せずに最新バージョンのAmazon Linux 2のAMIで起動させる
- ユーザデータでterraformをインストール【失敗】

# terraform導入
まずはユーザデータ作成のためEC2上で普通に導入しました。
特に理由はありませんが、何となくrootのプロファイルにPATHを追加する手順も入れました。

    $ sudo yum install wget unzip
    $ wget https://releases.hashicorp.com/terraform/0.12.20/terraform_0.12.20_linux_amd64.zip
    $ sudo unzip terraform_0.12.20_linux_amd64.zip -d /usr/local/bin/
    $ sudo sed 's|^PATH=\$PATH:\$HOME/bin|PATH=\$PATH:\$HOME/bin:/usr/local/bin|g' /root/.bash_profile > /tmp/bash_profile_tmp
    $ sudo chown root.root /tmp/bash_profile_tmp
    $ sudo mv /tmp/bash_profile_tmp /root/.bash_profile

※補足
・sedは通常「sed 's/～/～/g'」のように書かれることが多いですが、「/」の部分は別の記号に置き換え可能で、今回のようにディレクトリパスを記載する場合は「/」以外にすると便利です。
・terraformのダウンロードURLは[公式ページ](https://www.terraform.io/downloads.html)を参照下さい。

# Cloudformationテンプレート
最終的にうまく行ったVersionを載せます。
（デザイナーでガワだけ作成し、残りは公式ページ他を見ながら記載）

    AWSTemplateFormatVersion: 2010-09-09
    Metadata:
      'AWS::CloudFormation::Designer':
        389e90b9-2b30-43fa-a312-411827e53a79:
          size:
            width: 60
            height: 60
          position:
            x: 375
            'y': 125
          z: 0

    Parameters:
        Ec2ImageId:
            Type: AWS::SSM::Parameter::Value<String>
            Default: /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp
        Ec2InstanceType:
            Type: String
            Default: t2.micro

    Resources:
      EC2I4K5C4:
        Type: 'AWS::EC2::Instance'
        Properties: 
            ImageId: !Ref Ec2ImageId
            InstanceType: !Ref Ec2InstanceType
        Metadata:
          'AWS::CloudFormation::Designer':
            id: 389e90b9-2b30-43fa-a312-411827e53a79

※補足
・AMIのイメージはSSMのパラメータ経由で指定すると常に最新版を取得できます。
（SOAの試験でも出たような気がします）
・本当はこれに「KeyName（キーペア名）」と「UserData（ユーザデータ）」を入れたかったのですが、フォーマットエラーを解消できずに断念。

# スタック作成時の注意点
テンプレートを試す際はスタック作成失敗時にロールバックを無効にしておきましょう。
（でないと、失敗しても何のエラーも出さず、デバッグが何もできなくなります）

![image2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319027/2b6e67bc-e054-9a53-cec2-1e5638fdef8b.png)
Vue.jsとDjango-Rest-Frameworkで神経衰弱アプリを作ってみる【その1】~Djangoのセットアップ編~

[その2 >>](https://qiita.com/Butterthon/items/8d986e16bd6f3e540a7e)

# バージョン情報
OS：MacOS X
node：v12.14.1
npm：6.13.4
@vue/cli：4.1.2
python：3.9.0
Django：3.2.2
djangorestframework：3.12.4

# Pythonの仮想環境作成
### 事前準備
[ここ参照して、以下を行えるようにしておくこと。](https://qiita.com/fabeee-developer/items/4a0e2d738b33650fa819)
・pyenvが使える
・pyenv-virtualenvでPythonの仮想環境を作成できること

### 仮想環境作成
python3.9.0の仮想環境を作成します。
神経衰弱を作るので、名称は「concentratio」とでもしておきます。

```
butterthon$ pyenv virtualenv 3.9.0 concentratio
```
仮想環境の作成は以上です。


# Djangoプロジェクトを作成
### 事前準備
プロジェクトルートディレクトリを作成して、仮想環境を適用する。

```
butterthon$ mkdir workspace # ワークスペースを用意
butterthon$ cd workspace
workspace$ mkdir concentratio # ワークスペースの中にアプリケーションルートディレクトリ作成（名称は任意）
workspace$ cd concentratio
concentratio $ pyenv local concentratio
(concentratio)concentratio$ python -V
Python 3.9.0
```

### プロジェクト作成

```
concentratio$ django-admin startproject config .
```

以下のような構成になります。

```
concentratio # プロジェクトルートディレクトリ
├── config # 設定ファイルがconfig配下にまとまる
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
└── manage.py
```

# Djangoの起動画面を確認する。
｀python3 manage.py runserver｀でDjangoサーバを起動して[http://localhost:8000](http://localhost:8000)にアクセスする。

```
(concentratio)concentratio$ python3 manage.py runserver # Djangoサーバ起動


Watching for file changes with StatReloader
Performing system checks...

System check identified no issues (0 silenced).

You have 17 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions.
Run 'python manage.py migrate' to apply them.

January 08, 2020 - 15:35:47
Django version 2.2.6, using settings 'config.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
```
　
ロケットが発射している画面が表示されればOKです！！！

# Django Rest Frameworkをインストールする
```
(concentratio)concentratio$ pip install django-rest-framework
```

インストールできたら設定ファイルに追記する。

```config/settings.py
.
..
...
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework', # 追加
]
...
..
.
```

APIのエンドポイントを記載

```config/urls.py
.
..
...
from django.contrib import admin
from django.urls import path
from django.conf.urls import include, url # 追加
from rest_framework import routers # 追加

ROUTER = routers.DefaultRouter() # 追加

urlpatterns = [
    path('admin/', admin.site.urls),
    url('api/', include(ROUTER.urls)), # 追加
]
```

Django Rest Frameworkが正しく起動できるか[http://localhost:8000/api](http://localhost:8000/api)にアクセスして確認
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/357470/55717a51-93e7-28fb-94bf-7b7bf95a0b65.png)

[その2 >>](https://qiita.com/Butterthon/items/8d986e16bd6f3e540a7e)
【Swift】【Xcode】adMobの広告を入れるためのコード

#SwiftでのadMobの広告の入れ方(方法)

すべてを端折ってadMobの広告を入れる際に必要なコードだけにした備忘録

💡注意💡
コード内にも記載しているがID系はGitにpushする際に記載したままpushしちゃわないように！
載せちゃうと、、、アカウントがキンキンになる

```admob.swift
import GoogleMobileAds

class mapMapViewController: GADBannerViewDelegate {
    // GADBannerViewDelegate をプロトコルとして入れる

    // AdMob ID を入れる  
    let AdMobID = ""
    let TEST_DEVICE_ID = "xxxxxxxxxxxxxxxxxxxxxxx"
    //ID系はgitにpushする際載せないように注意！
    
    let AdMobTest:Bool = true      
    let SimulatorTest:Bool = true    
    //testのときはtrueにしておく
    //実機or審査に提出の際はfalseにする

override func viewDidLoad() {
        super.viewDidLoad()
        
        showAdBanner()
       //広告を表示する関数
    }

 //広告を表示する
    func showAdBanner(){
        
        var admobView = GADBannerView()
        admobView = GADBannerView(adSize:kGADAdSizeBanner)
        admobView.frame.origin = CGPoint(x:0, y:self.view.frame.size.height - admobView.frame.height - 45)
        
        admobView.frame.size = CGSize(width:self.view.frame.width, height:admobView.frame.height)
        admobView.adUnitID = AdMobID
        admobView.delegate = self
        admobView.rootViewController = self
        
        let admobRequest = GADRequest()
        
        if(AdMobTest){
            // simulator テスト
            if SimulatorTest {
                admobRequest.testDevices = [kGADSimulatorID]
                print("simulator")
            }
                // 実機テスト
            else {
                admobRequest.testDevices = [TEST_DEVICE_ID]
                print("device")
            }
        }
            // 本番
            admobView.load(admobRequest)
        
        self.view.addSubview(admobView)
    }
    
      override func viewWillAppear(_ animated: Bool) {
        read()
    }
    
}

```
背景画像を一定の時間ごとにランダムで表示切り替えする方法

### 概要

とってもニッチな議題なのであまりニーズはなさそうですが、備忘録もかねてかきます。
完成イメージはこんな感じです。
[![Image from Gyazo](https://i.gyazo.com/cf58dc1bd8a85b78cee3cc4cf570739c.gif)](https://gyazo.com/cf58dc1bd8a85b78cee3cc4cf570739c)

コードは以下です。

```HTML:html
<body>
<div id="randomImg"></div>
</body>
```
```CSS:css
#randomImg {
  width: 100vw;
  height: 100vh;
  background-image: url(/image01.jpg); //背景画像の初期値
  background-position: center center;
  background-size: cover;
}
```
```javascript:javascript
    var images = [ 'url(/image01.jpg)', 'url(/image02.jpg)', 'url(/image03.jpg)' ];  // ランダム表示させたい画像のパス

    $(function(){
      var backgroundRandom = function(){
        var number = Math.floor(Math.random() * images.length); // 0~3の数値を算出 
        var selectedImg = images[number]; // 算出された数値を元に、1行目の配列から取り出す
        $('#randomImg').css('background-image',selectedImg); // cssにランダムに選ばれた画像を背景設定する
      };
      setInterval(backgroundRandom, 1000);  // 1000msごとにランダム切り替えを繰り返す
    });
```
### 使用シーン
スライドショーではないもので、キービジュアル部分を切り替えたいなーというときに使えるかもしれません。
setIntervalの数値をいじればゆっくり表示することもできますし、
cssでゆっくり拡大したりとアニメーションをつけても面白いと思います。

### 注意点
- ランダムなので、同じ画像が続くこともあります。
- 画像ファイルが重いと、読み込みに時間がかかります。画像点数はファイル数と相談して適度に保ちましょう。

### つまづいた点
途中、setIntervalが1度しか動かず、解決に数時間費やしてしまいました。
原因はスコープの範囲を間違っていたという初歩的なことでしたが、その過程で見つけた記事も参考になりそうなのでこちらに紹介しておきます。
https://qiita.com/AK092/items/a8cdde07b55df355ed08
https://taccuma.com/timer-javascript/

以上です。
改善点や間違っている点がありましたら是非ご指摘おねがいします！
基本情報15週目(01/27週)

# 目標と結果
### 目標
- 参考書をみる。
- [基本情報技術者試験ドットコム](https://www.fe-siken.com/)を使う。
- 午後で通用する様に内容を理解する。
    - アルゴリズムとプログラミングの勉強をする。
    - 午後問題で重視する分野を見つける。
- 大学の諸々を片付ける。
- 2、3月の予定を立てる。
    - 改めて午後試験の概要を把握する(おさらい)。

### 結果
- 卒論は終わりました！
- 3つ目の午後対策講座に申込みました。
    - Pythonとセキュリティ。

- 午後問題の概要
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/514786/dbfefb23-85dd-e7a4-59dd-ca3c1e2995d4.png)
出典(https://www.ipa.go.jp/about/press/20190124.html)

###確実にやる必要があるもの(高配点)
- 情報セキュリティ(問1)
- データ構造およびアルゴリズム(問6)
- アセンブラ、表計算、Pythonのどれか
    - 対策講座で解説されるのでそれで決めたい

###選択問題、合わせて2問解答、計30点
- 5分野中3分野出題
    - ソフト、ハードウェア
    - データベース
    - ネットワーク
    - ソフトウェア設計
    - データベース
- 4分野中1分野出題
    - プロジェクトマネジメント
    - サービスマネジメント
    - システム戦略
    - 経営戦略、法務


# 振り返り
### Keep
- なし

### Problem
- なし

### Try
- 午後問題に取り組む。
ラズパイでNeoPixel（マイコン内蔵RGB LED）を手軽に激しくLチカする方法

![LED_ws281x.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/81919/9f4b638d-188c-4d40-6730-e88c246ec4a6.jpeg)

# ラズパイでNeoPixelを激しくLチカ
　ラズパイで派手にLEDを光らせたいときありますよね。私はあります。

　意外にもやったことなかったので、手順をメモします。

　使用したのは、以下のLEDテープです。買ったまま放置していました。

https://www.switch-science.com/catalog/1399/

# ハードウェア準備
　用意したのは以下です。

- ラズパイ4
- ICクリップ
- LEDテープ

　LEDテープはとりあえず3つくらいに切っておきます。使用するLEDは電流を考慮して決めましょう（ここでは説明は省略します）。

　接続は、以下のサイトを参考にして下さい。

http://jellyware.jp/kurage/raspi/led_stick.html

# ソフトウェア
　以下２つのサイトが参考になりました。

[ラズパイでLEDスティック点灯](http://jellyware.jp/kurage/raspi/led_stick.html)

[ラズベリーパイでNeoPixelを使う](https://qiita.com/m_take/items/e80735e860ce235c1a74)

　ほとんど上記のサイトのままですが、自分の環境に合わせて少し変えたりしたので、まとめておきます。詳細は、上記のサイトの方を参照して下さい。

　そのうちスクリプト化するかもです。

## rpi_ws281xライブラリのセットアップ
　まずは、以下コマンドでrpi_ws281xライブラリをビルドします。sconsというのがmakeの代わりらしいです。

```sh
$ sudo apt-get install scons
$ cd && git clone https://github.com/jgarff/rpi_ws281x.git
$ cd rpi_ws281x
$ sudo scons
```

## rpi_ws281xのpythonラッパープログラムセットアップ
　続いて、ラッパープログラムをインストールして、サンプルをダウンロードします。

```sh
$ sudo pip3 install rpi_ws281x
$ cd && git clone https://github.com/rpi-ws281x/rpi-ws281x-python
```

## サンプルを動かす
　以下でサンプルを動かすと、LEDが綺麗にピカピカします。

```sh
$ cd ~/rpi-ws281x-python/examples
$ sudo python3 standtest.py
```

　ただし、このままだと`CTRL+C`でプログラムを終了してもLEDが眩しいです。プログラム終了時にLEDをOFFしたい場合は、以下のように`-c`オプションをつけましょう。これで終了するとLEDがオフするようになります。

```sh
$ sudo python3 standtest.py -c
```

　使用するピンを変えたいときは、standtest.pyの`LED_PIN = 18`を編集すれば簡単に変えられます。18pinだと、アナログオーディオが死んでしまうので、オーディオ使いたいときは別のピンにしましょう（私はとりあえず参考にしたサイトに従い、21pinにしました）。

# もっと長いLEDテープでLビカ（LEDビカビカ）する場合
　ラズパイ4で以下のように繋げます。

![IMG_4217.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/81919/ff84e9d1-3a64-ea4d-ae7b-11696657631c.jpeg)

![IMG_4218.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/81919/a41f05a7-b24d-65d4-7e08-9eb9b3c157b2.jpeg)

![IMG_4219.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/81919/4d790e5c-fc94-8d39-3232-432e4e55994d.jpeg)

　サンプルプログラムでビカビカ。LEDの個数のパラメータは調整しておきましょう。

https://twitter.com/karaage0703/status/1662011780288380932

　ラズパイ3だと電源回路の過電流保護にひっかかってしまうかもしれません。

https://twitter.com/mnlt18/status/1662031932975378432

　直接ピンヘッダの5Vに給電するか、5Vは根本で分けたほうが良いかもですね（電流次第）。

# まとめ
　ラズパイで激しくLチカしました。楽しいですね。

# 関連記事
https://karaage.hatenadiary.jp/entry/2022/11/25/073000

https://zenn.dev/karaage0703/articles/18be273e8fc147

# 変更履歴
- 2023/05/27 Lビカやサンプルプログラムの注記を追記
メモ　GSuiteのユーザ管理

# はじめに
GSuiteのユーザ管理についてどのような運用方法がいいか、調査している中でのメモ。
動作保証などはないためご容赦願いたい。

# 目的
GSuiteにはゲストアカウントがないため開発会社等の協力会社をプロジェクトに参加する場合は
アカウントを発行することとなる。
先方がGsuiteを利用していれば連携はグループを使って簡単にできる面もあるが
自社だけで完結させる場合のプラクティスを模索中。
管理方法的には将来的にGCPの管理にも使えると思っている。

# GSuiteでいうユーザ
利用しているGSuiteのサービスを利用できる（Basic,Business,Enterpriseによってかわる）
メールアドレスでログイン。
ユーザ作成時に組織に属することができる。
その他のGoogleサービスも利用可能。

# 組織とグループについて
グループわけとして、グループと組織がある。
## グループ
エイリアスのメールアドレスが発行される。
共有するアイテム、共有ドライブはグループあてに可能。
アプリの制限のほか、サービスの制限（Photo,GCP,Youtube,Domainsなど）ができる。
1つのユーザは複数のグループに所属可能。
**グループは階層化できない（グループ内グループというのができるっぽいが未検証**

## 組織
メールアドレスは発行されない。
共有相手としては選択できない。
アプリの制限のほか、サービスの制限（Photo,GCP,Youtube,Domainsなど）ができる。
1つのユーザは1つの組織のみ所属可能
**組織を階層化できる。組織のアプリ利用の制限を継承可能。**


# どのような使い分けがいいのか
参考
https://support.google.com/a/answer/9050643
https://support.google.com/a/answer/4352075?hl=ja
わかりやすい図がありました。上記URLより引用。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/541506/3dd51e28-1117-30f8-c966-51195ee0afb6.png)

目的としては外部の会社用のアカウントとする場合、
組織をわけてそこに所属、目的にアプリやサービスだけを有効にするのがよさそう。
そうすれば勝手にメールを使われたりもしない。

# サブドメインの利用方法
自社の組織と別にする場合、プライマリドメインとは別にサブドメインを追加し、
ユーザアカウントもそのサブドメインにするのがよさそう。


# 利用設計
## サブドメインの追加
外部の協力会社ようのサブドメインを追加
例）vender.yourdomain.com
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/541506/fe800bc9-e80e-83c7-cc88-430fc3c6cff7.png)

## 組織を追加
協力会社という組織を作り、その下に実際の会社を配置。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/541506/b9b51a81-3dbb-d55c-a165-a30bd95a3756.png)


## 利用可能なアプリケーション
協力会社の組織でON/OFFをわける。
この例はGdrive関係のみオン
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/541506/c30ad1de-1326-266b-a8b0-4369d2b91ff5.png)

## グループの作成
サブドメインでグループを作成する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/541506/c5e5807b-1712-ecdf-135b-30a14fd930b0.png)

## ユーザの作成
サブドメインでユーザを作成し、組織部門に所属させる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/541506/fedbb25e-039a-8b6a-f143-ad1eab70bf80.png)

グループへの追加だけはユーザ追加後に設定

## 例
実際に作ったユーザでGdriveにアクセス。
共有ドライブのみが表示（事前に所属グループに対し権限を付与）
右側にあるアプリへのショートカットが表示されない
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/541506/7545d0d5-7847-ce8d-c8ae-205488dc47fd.png)


### 許可されてないアプリへのアクセス
メール
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/541506/68fb350b-7ca9-abb5-bcd0-9b360967ad42.png)
カレンダー
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/541506/2700db8b-02a4-8937-6a62-f718a8ca59d2.png)


必要なアプリだけが利用できる外部用ユーザができたと思う
GatsbyjsをGitLabのCI/CDで自動でレンタルサーバーにデプロイしてみた設定

**私は初心者です。ググりながら動かして見た設定ですので注意してください**

参考：[GitLabにコミットしたら、FTPでサーバにアップロードする自動化を１分で行う方法。-『Git』 | webmanab.html／ウェブまなぶ](https://webmanab-html.com/tip/gitlabci-ftp/)

# プロジェクト作成

```bash
$ npx -p gatsby-cli gatsby new hoge-site
$ cd hoge-site
$ npx gatsby develop
```

http://localhost:8000/ でサイトが立ち上がったので、これをGitLabのCI/CDでレンタルサーバーにftp転送してみます

<img width="917" alt="Screen Shot 2020-01-27 at 0.32.06.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142910/a6fed9e3-6f2b-9f59-87f2-f291f6bca6ea.png">

# ftp接続情報を設定

GitLabの左メニューの「Settings」＞「CI/CD」＞「Variables」を選択し、`Key`と`Value`にftp接続情報を設定し、「Save variables」をクリック


|  |   |  |
|---|---|---|
| HOST | "hogefugaxxx.sakura.ne.jp" |  |
| USERNAME | "yourName" |  |
| PASSWORD | "yourPass" |  |
| LOCAL | "./public" | ローカルのデプロイしたいフォルダを指定 |
| SERVER | "/home/hogefugaxxx/www/site/path" | デプロイしたいレンタルサーバー内のパス |

<img width="1217" alt="Screen Shot 2020-01-27 at 0.51.33.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142910/6942e704-9ab4-571e-ecf8-bd142722dc83.png">

# `.gitlab-ci.yml` を設定

`.gitlab-ci.yml`をプロジェクト直下に作成する

```.gitlab-ci.yml
image: node

before_script:
  - npm install
  - npm run build

build:
  script:
    - apt-get update -qq && apt-get install -y -qq lftp
    - lftp -c "set ftp:ssl-allow no; open -u $USERNAME,$PASSWORD $HOST; mirror -R $LOCAL $SERVER --parallel=10"
  only:
    - master
```

`.gitlab-ci.yml`をコミットに含めた状態で、masterにpushやmergeなどすると、自動でgatsbyjsをビルドし、`public`フォルダをレンタルサーバーにデプロイしてくれました

<img width="1017" alt="Screen Shot 2020-01-27 at 1.12.32.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/142910/180ab7db-ac8d-4b69-5fe6-299b89a8b2a5.png">

---

さくらのレンタルサーバーで行ったのですが、デフォルトで国外IPアドレスからのftpアクセスを制限しているようなので、そこも外さないとダメでした

https://help.sakura.ad.jp/206054272/

---

また、`.ftpaccess`を設置している場合も設定によってはgitlabのciからのftpアクセスができないので、そこも気をつけると良いと思いました。

---

見ていただいてありがとうございましたm(_ _)m
プログラム初心者がrasberry pi 3 model3 でリアルタイム画像認識できたよ。

#はじめに
初心者の私がまず始めたのは、ドットインストールでした。
2ケ月ほどHTML/CSS→PHP→pythonと無料の範囲でやってみましたが、
いまいち、グッと来るものがありませんでした。
そこで、とりあえずラズベリーパイに挑戦してみました。
![images.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560969/35e86ed4-9a46-b704-e677-d01fd3655840.jpeg)

##やってみたこと

"Raspberry Pi3でTensorflowのObject Detection APIを使えるようにしてみる”
[投稿元](https://qiita.com/kobayuta/items/59c7b84caf8994071357#comment-fee655c26fa64e909b86)

↓今回できた画像認識（カメラが逆さまになっています、ご了承ください。）
![IMG_3958.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560969/1f05df94-bdfd-f5d2-f2f7-50b6b6feef8a.jpeg)
そうこれこれ、私はこういう事がしたかった。
フレームで囲まれて、画像認識した名称表示とパーセントが出ている。
プログラマーになる気はないし、その能力もなさそうだけど
今の仕事である機械・電気の延長線上にはきっとAIや画像認識が
近い将来、必要になると思っています。

###つまずいたこと
一番は、投稿元さんの手順通りにインストールしても
エラーが出て前に進めなくなったことです。
私が投稿元さんのOSバージョンをきちんと理解していなくて
最新のBUSTERというOSを入れていたのが原因でした。

途中、ImportError:No module named 'matplotlib'というエラーメッセージがでたので、
”matplotlibのインストール”というサイトでインポートしました。
[投稿元](https://teratail.com/questions/157875)
↓今回のエラー
![2無題.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560969/b73e1abd-4995-da64-874c-19fe8391c070.png)


　細かいところでは、一番最初にSDカードの相性が悪いのか
FAT32にフォーマットしましたが、全く動作しませんでした。
ちなみにSanDiskのULTRA　64GBです。
　そこで、動作確認済みのシリコンパワー製16GBを買いましたが、
その当時は、先ほど記載したOSバージョンの不具合で
何度も色んな方法を試していて16GBの容量がいっぱいになってしましました。
　今度は、産業用のMicron MTSD32AHC65MS-1WT　平均故障時間200万時間と
いうものを購入して、一つ前のOSでRaspbian Stretch with desktop 2019-04-08を
再インストールしました。

####追加で必要なもの
冬なので必要がないと思いましたが
作動中は熱くなったので、銅製ヒートシンク×2ケと冷却ファンを買いました。

#####追加でやったこと

必要かどうかわかりませんが、スワップサイズを100→2048に変更しました。
”Raspberry Pi のスワップ領域拡張”
[投稿元](https://qiita.com/nyas/items/f4d0675061ee8cdcc3e7)

######最後に
OSを入れ直しも含めて2日で出来ました。
何度かエラーっぽい表示が出ましたが、
再度、コマンド入力してみました。
それまでの苦労はなんだったのか？と思うほど上手く行きました。
ただし、画像認識の作動は重たいのでカクカクしています、
過度な期待はしないでください。
これに気を良くして、ラズパイ４を買ってきましたが、
電源ケーブル端子がUSB　-A　→　-Cになっているのを知りませんでした。
（HDMI出力　→　MINI　HIMIになっているので注意ください。）
今度は変換ピンを購入して、ラズパイ４で試してみます。

とにかく、今回の件で少し自信が持てましたし、
ネットで色んな情報や皆様から協力を頂けるありがたさを
身に染みて感じました。:relaxed:
ラズパイを触ってみた(DHT11編)

#エアコンによる乾燥 vs 加湿機　ﾌｧｲｯ!!!!!!!!!!!!
乾燥が辛い。
ただでさえ喉が弱いのに...さらにやられてまう...
ところで今って湿度どれくらいあるんやろう？
加湿器ってどれくらい効果でとんやろ？
ということで、測ってみた！

#いろんなwebページをみながらやってみたがなかなかうまくいかなかった。
参考にしたページ
https://yuki-no-yabo.com/measure-temp-usingdht11/

##動かなかった理由
一言で言うとpinの読み間違え
***BCM***の方をみないといけなかったのに
![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513179/07af6840-9242-d844-1406-e6004798c5eb.jpeg)

***wiring Pi***の方を見ていた
![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513179/de993475-657c-9924-4d36-7159e3889e6e.jpeg)
参考にさせていただいたページはこちら
https://iot.keicode.com/raspberry-pi/pinout.php
>GPIO の番号は BCM ピン番号で割り当てられており、通常プログラミング時には BCM 番号を使います。

ということらしい。


##配線イメージ

使ったDHT11。スターターキットに入っていたもの
 ![DHT11](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513179/bb023a0c-1534-0c5b-7b57-df8425c96593.jpeg)

![IMG_3380 (1).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513179/e4c66b9a-86d8-f92b-4f7c-09933a05916c.jpeg)

使用したコード
https://github.com/szazo/DHT11_Python.git
上記ではpin=14で設定されているのでGPIOを14に接続

| DHT11側| ラズパイ側| 
|:--------|:-----------|
| GND |6 |
| DATA | 8 (GPIO 14) |
| VCC |1 (3.3v)|


ジャンプワイヤはオスオスとオスメスを両方使ってみたかったから使ってみた
![IMG_3381 (1).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513179/fe64a287-4ee1-5c21-e539-dde0cfb6ec48.jpeg)

で、無事にデータを取れました。（記念写真)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513179/c01573e3-32dc-24ee-8e92-b8498235413c.png)



ちょっと触ってみただけだけど...ラズパイって...楽しい！！！
【Django】ExcelやCSV形式でDBテーブルのインポート、エクスポートを行う

# 実装するもの
1. 管理者画面に以下のボタンを追加する。
    - インポート
    - エクスポート
2. DBテーブルの権限で表示を制御する。
    - インポート　：書き込み権限が必要
    - エクスポート：だれでもOK

これらを、`django-import-export`というライブラリで実現します。
django-import-exportの使い方（導入方法）まとめ記事です。

# 権限アカウント
今回は以下の権限を持つアカウントを作成した。

  - admin: 全権限
  - guest: 閲覧権限のみ

# 画面表示
## adminでログインした場合
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/384142/64211547-655b-8852-a5e7-6d484c85322c.png)←このボタンが追加される
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/384142/6d950120-cee3-4634-3f07-0e65d54a52e3.png)

## guestでログインした場合
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/384142/f8e71208-375f-63d7-e609-465e2a07386b.png)←このボタンが追加される

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/384142/77f1615d-3281-0d7c-d7f0-34f97285e2e4.png)

## インポート画面
形式は下記の通り。豊富。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/384142/4d223902-2b40-20c8-2166-b7578b92bc9c.png)


## エクスポート画面
形式は下記の通り。インポートよりさらに豊富。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/384142/c8eaf077-2395-50f7-1c97-fbd545ceb74e.png)


# 実装
## インストール
django-import-export
https://django-import-export.readthedocs.io/en/latest/

```
pip install django-import-export
```

## setting.pyに書く
```python:setting.py
# インストールアプリ
INSTALLED_APPS = (
    ...
    'import_export',
)

# 管理サイトでのインポート機能は権限が必要と設定する
IMPORT_EXPORT_IMPORT_PERMISSION_CODE = 'change'

```

## スタティックファイル書き出し
```
python manage.py collectstatic
```


## admin.pyに書く

`model.py`に`Book`という名のテーブルがあることを想定

```python:admin.py
from django.contrib import admin
from import_export import resources
from import_export.admin import ImportExportModelAdmin
from .models import *


# リソース
class BookResource(resources.ModelResource):
    class Meta:
        model = Book

# 管理
class BookAdmin(ImportExportModelAdmin):
    resource_class = BookResource

# 登録
admin.site.register(Book, BookAdmin)
```

# ひとこと
シンプルで高機能！素晴らしい。
今回は、全ファイルのエクスポートだったが、フィルタもできるらしい。
挑戦してみたい。
Simulink API (6) 2種類のブロックプロパティとSimulinkモデルの動き その2

## はじめに
[前回](https://qiita.com/stozaki/items/ecc2fd157ea7c97a50d1)、Simulink APIに触れつつ「Simulinkってシミュレーション実行できる」という非常に重要な事をしれっと記載しました。今回はもう少し深堀りしてみます。

### 軽く前回の復習
Simulinkブロックには様々なプロパティ設定があります。
一例としてInportブロックの設定ダイアログを記載します。
![qiita200126_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/324583/150a851f-474e-d164-2f12-0602daf958f2.png)

ブロックによってはタブが幾つもあり、設定自体に四苦八苦するものもあります。
しかし、Simulinkブロックは[前回説明](https://qiita.com/stozaki/items/ecc2fd157ea7c97a50d1)したように、シミュレーション時にプロパティ値がResolveされるコンパイル型と、そうでない静的なプロパティに分類できます。そこで今回は設定ダイアログ上の設定値からどの様に反映されるのか？を見ていきたいと思います。

### 継承とは
ブロックプロパティ値には 「inherit ・・・」とか「-1」という値を設定できるものがあります。これは、Simulinkのような信号・ブロック線図の[幾何的・循環的特徴](https://qiita.com/stozaki/items/bad07d0e6e1c571dfc47)を活かした設定と言えると思います。これらの設定はモデルのコンパイル時に各々の属性がResolveされます。
端的に言うと、次のようなステップを繰り返しながら、入力信号を処理しながら出力信号を生成するモデリングで利用します。(信号ドリブンモデルという方もいます)
![qiita200126_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/324583/4350b63c-2264-d433-f9ec-6f9b3583f867.png)


### 非継承(明示的なプロパティ設定)
とはいえ、信号源は明示的にプロパティ値を設定しなければなりませんし、ブロックの演算種別によっては、ブロックの入出力で属性を変化させる必要となる場合もあります。

### 信号伝播を担保するには
実際のモデリングでは継承設定と非継承設定を組合せて、どの様に正しい信号伝播を担保するか?ということを踏まえる必要があります。これが守られないと正しいシミュレーション結果を得られない場合が出てきてしまうからです。
それって、具体的に何をすればいいの??

Aさん 「ブロックの設定なんて、一つに決めておけばよくね??」
Bさん 「設計者が要求を理解して、一つ一つ明示的に設定しないと駄目なのでは??」
Cさん 「Aさんや、Bさんみたいに意見が分かれるので、レビューで回収するしかないね。。」

Aさん、Bさん、Cさんも以下の様に読み替えると正解だと思いますし、この様な意見を集約し、形式的な文章としたものが「モデリングガイドライン」として世に出回っているものだと思います。

Aさん : プリセット 
Bさん : ポストセット 
Cさん : 設計後の自動チェック 

何れもSimulink APIで自動的に処理が可能です。

#### モデリングガイドラインルール例
では、試しに「信号伝播を担保する」ルールを一つ紹介します。

[na_0002: 基本的な論理演算と数値演算の適切な実装](https://jp.mathworks.com/help/simulink/mdl_gd/maab/na_0002appropriateimplementationoffundamentallogicalandnumericaloperations.html) 

このルールの骨子は、制御ロジックと数値演算は分割してモデル化しましょう。その際、データ型を混在させるような処理は避けることが望ましい。ということを[形式的](https://jp.mathworks.com/help/slcheck/ref/mathworks-automotive-advisory-board-checks.html#mw_783da046-c828-41eb-a55e-3b3e7a28f86f)にチェックプログラム化しています。(ツールで機械的に検査できます)

## まとめ
他の人が描いたモデルにおいて、ブロック設定が何故inheritや-1になっているのか?何故、明示的な設定値となっているのか?を読み解きその成否判断のスキルと、
逆に自分が描いたモデルにおいて、何故このブロックはinheritとしたのか? 何故明示的に設定しなければならなかったのか?を説明出来ることがモデリングスキルに大事な一つだと思います。

##### 余談
MathWorksさんのWebサイトに[MATLAB Anser](https://jp.mathworks.com/matlabcentral/answers/?language=ja%2Cen&sort=asked+desc) というユーザー同士のコミュニティがあります。ここでは、ユーザー同士でMathWorks製品のQ&Aを行ったりすることができます。
Simulinkのエラー関連の質問を見ていると、継承設定になっているプロパティ値と明示的に設定したプロパティ値が整合しないためにエラーとなっているケースをよく見かけます。
例えば「次元が一致しません」「データ型の不整合が・・・」のような感じのものです。
既定値のinheritや-1が何をしているのか? 一方自分はそのブロックをどう動かしたいのか?を考えながらモデリングの実施を心がけていればその様なエラーには遭遇しなくなります。

あー文章力上げたい。。。
docker-compose + realizeでライブリロードする環境構築


goで開発しているとコード変更のたびにビルドするのが面倒くさいので
[realize](https://github.com/oxequa/realize)を使ってライブリロードしてサクサクコーディングできるように環境構築した時の設定をメモっておいてます。

## パッケージ構造
```
.
├── api/
│   └── main.go
├── .realize.yaml
├── docker-compose.yml
└── Dockerfile
```


## 設定ファイル
### Dockerfile
`go get`で`realize`を取得しておきます。
またCMDには`realize`の起動コマンドを設定しておきます。

```
FROM golang:1.13

RUN go get github.com/oxequa/realize

EXPOSE 8080

CMD [ "realize", "start", "--run" ]
```

### docker-compose.yml
`.realize.yaml`が配置されているディレクトリを`working_dir`に設定しておきます。
今回は`docker-compose.yml`と同じディレクトリに配置したので、volumesに設定したディレクトと同じ場所を指定しています。

```yaml
version: "3"

services:
  go:
    build: .
    ports:
      - 8080:8080
    volumes:
      - ./:/app
    working_dir: /app
```

### .realize.yaml
`realize`の設定ファイルです。
**拡張子は`yml`じゃなくて`yaml`です！**

ググると出てくるこちらの記事 → [Realize が Go 1.11 の Modules で使えない](https://qiita.com/enta0701/items/0d0592abb18a333b3268) に書いてありますが
realizeはGo Modulesに対応していないようで、issueの[解決策](https://github.com/oxequa/realize/issues/217#issuecomment-459198990)にあるように`command`にちょっと設定が必要になります。


```yaml
settings:
  legacy:
    force: false
    interval: 0s
schema:
  - name: api
    path: api
    commands:
      build:
        status: true
        method: go build -o /go/bin/api
      run:
        status: true
        method: /go/bin/api
    watcher:
      extensions:
        - go
      paths:
        - /
      ignored_paths:
        - .git
        - .realize
```


## 動作確認
### テスト用のコード
`api/main.go`は以下のようなSampleを出力するだけのAPIを用意します。

```go
package main

import (
	"fmt"
	"net/http"
)

func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "Sample")
	})
	http.ListenAndServe(":8080", nil)
}
```

### 確認①
起動すると以下のようなログが出ます

```
$ docker-compose up
〜〜〜 略 〜〜〜

go_1  | [15:11:08][API] : Watching 1 file/s 1 folder/s
go_1  | [15:11:08][API] : Build started
go_1  | [15:11:10][API] : Build completed in 2.703 s
go_1  | [15:11:10][API] : Running..
```

この状態でlocalhost:8080を叩くと`Sample`が出力されます

```
$ curl http://localhost:8080
Sample
```

とりあえずAPIが動いていることが確認できました。

### 確認②
続けてテスト用のコードを編集して保存してみます。
（`fmt.Fprintf()`をSample -> HogeHogeに変更しただけ）

```go
package main

import (
	"fmt"
	"net/http"
)

func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintf(w, "HogeHoge")
	})
	http.ListenAndServe(":8080", nil)
}
```

保存すると以下のようにログが出力されます。
変更されたファイルが表示され、自動でビルドされているのがわかります。

```
go_1  | [15:16:18][API] : GO changed /app/api/main.go
go_1  | [15:16:18][API] : Build started
go_1  | [15:16:19][API] : Build completed in 1.777 s
go_1  | [15:16:19][API] : Running..
```

この状態でlocalhost:8080を叩くと変更後の`HogeHoge`が出力されました。

```
$ curl http://localhost:8080
HogeHoge
```
Cloud Run + Pub/Sub で NestJSアプリを動かす


## 前提知識

* Cloud RunとPub/Subについてどんなものか知っていると理解しやすいです。
* [bull](https://docs.nestjs.com/techniques/queues)と[schedule](https://docs.nestjs.com/techniques/task-scheduling)についても知ってるといいかも。

## サーバーレスに移行したい

NestJSやってると、タスクキューは[bull](https://docs.nestjs.com/techniques/queues)や[schedule](https://docs.nestjs.com/techniques/task-scheduling)なのですが、インスタンス立ち上げっぱなしな制約を受けてしまうため、なかなかサーバーレスな環境に移行するのが難しいものがあります。

今回、サーバーレスな環境に移行しようという状況が出てきました。「どうにかしてbullとscheduleの使用をやめよう」と作業をしていて、代替えの技術となったのがCloud RunとCloud Pub/Subの組み合わせでした。

Pub/Sub経由でHTTPリクエストをしてもらい、NestJSを起動し、リクエスト内容によって処理（Provider）を分けることがゴールになります。

その手助けをしてくれるライブラリを[@anchan828/nest-cloud-run-pubsub](https://github.com/anchan828/nest-cloud-run-pubsub)として作りました。
![](https://repository-images.githubusercontent.com/233642584/f7bba780-3c42-11ea-82b4-15ddc2651db8)

### PublisherとSubscriberの2つのアプリを作成する

意味合い的にはメッセージを発行するためのパブリッシャー、受け取り側のサブスクライバーが存在します。なので2つのアプリケーションを作らないといけないですが、コード的には1つのアプリ（Cloud Runなので１つのDockerイメージ）で問題ないです。Cloud Runサービスを2つ作ればいいだけです。たぶん１つのサービスでも行けると思いますがやったことがない...

### 受け手側のWorkerを作成する

イメージしやすいように、先にリクエストの受け取り側サブスクライバーの説明をします。

@anchan828/nest-cloud-run-pubsubは、リクエスト内容（リクエストボディ）によって呼び出すProviderを決めます。なのでPub/Subのトピックに送るメッセージ内容で呼び出すWorkerが変わります。これにより、[bull](https://docs.nestjs.com/techniques/queues)のようなProcessorの書き方ができます。

```ts
@CloudRunPubSubWorker("ワーカー名")
class Worker {
  
  @CloudRunPubSubWorkerProcess()
  public async process(message: string): Promise<void> {
    console.log("メッセージ内容: " + message);
  }
}
```

### メッセージを送信する

次にデータの送信側です。CloudRunPubSubServiceという@google-cloud/pubsubのラッパーサービスを用意していて、publish関数で指定のワーカーとメッセージをトピックに送信します。あとはワーカーが動いているCloud Runのサービスに向けてHTTPリクエストを投げるようにサブスクリプションをセットアップするだけです。

```ts
export class Service {
  constructor(private readonly pubsubService: CloudRunPubSubService) {}

  public async sendMessage(): Promise<void> {
    await this.pubsubService.publish({
      name: "ワーカー名",
      data: "メッセージ",
    });
  }
}
```

### まとめ

これで対応終わりです。
...NestJS側の対応は簡単なのですが、初めてセットアップをやるとき、Cloud Runの設定やPub/Subのサービスアカウント周りの権限など躓くところが多いと思います。そこさえクリアできれば、快適な環境が作れると思いますので、GCPを使ってるNestJSユーザーは、ぜひ Cloud Run + Pub/Sub の組み合わせを検討してみてください。
不要なpackageを削除する

先日goにてプロジェクト開発をしていた際に指摘されたので、modulesについて簡単にまとめていきます。

# 要約
不要なpackageを削除するために、`go mod tidy`をする

# modとは？？
go1.11から使えるようになった依存管理ツールだそうです。
使い方については参照記事がわかりやすくまとまっていますので、そちらを御覧ください。

# 参照
https://blog.mmmcorp.co.jp/blog/2019/10/10/go-mod/
顧客サポートのプロフィット化

# コストセンターとプロフィットセンターそれぞれの最適化とは
## コストセンター

カスタマーサクセスのサポートには属さない。
お問合せ対応をコストとして、最適化を図る。
その為、お問合せ1回あたりにかけるの時間の最小化、サービス提供の同一性などを重視する。
どれだけコストを抑えて運用可能かを設計する。

## プロフィットセンター
カスタマーサクセスのサポートに属す。
お問合せをした顧客のディスロイヤルを可能な限り0にする事を目的にする。

また、お問い合わせ対応を通して以下の分析を行う。

* 顧客の課題発生起因、問題解決に不足している情報、傾向の定量分析
* 顧客心理を読み取り定性分析

上記をプロダクトへフィードバックをする事でエフォートレスプロダクトを推進する。
同時に、セルフサービスの充当を行う。

その結果、顧客ロイヤリティ、チャーンの抑止などに繋がり、カスタマーサクセスの一部を担う言葉通りのプロフィットセンターになる。

# プロフィットセンター化したサポートセンターの活動

サポート対応から顧客の課題を吸い上げ以下を行う。

* セルフサービス機能の充当
* VOC分析
* プロダクトへのフィールドバック

## セルフサービス機能の充当
顧客自身で問題解決できるようにする機能のグロース。
例えば、FAQ、チャットボット等のコンテンツ最適化を行う。
お問い合わせ内容からFAQに、チャットボットなど反映する事で顧客のセルフサービス機能の充当を行う。

### 効果測定
役に立った/役にたたなかったボタンを設置し、ボタンのクリック、PV数からコンバージョンレートを測定する。
類似問い合わせの減少。
CESの最大化。

## VOC分析
顧客対応を通し顧客の心理を分析し、エフォートレスプロダクトの企画を立案。
お問合せ対応を通して実際のユーザー行動フローのファクトを確認
運用の最適化

### 効果測定
類似問い合わせの減少。
CESの最大化。

## プロダクトへのフィードバック
VOC分析で得た知見から、エフォートレスプロダクトの為のフィールドバックを行う。
合わせてプロダクトの運用設計を行う。

### 効果測定
お問い合わせ数。
CSAT、NPS、CESの最大化。
-> 成長に比例してお問い合わせが増える(要望は増えても良い)運用設計に問題があるか、顧客が求めているプロダクトを提供できていないと考えるべきだと思います。
iPhoneでYOLOを動かしてみたい

#はじめに
初めまして、普段はFPGAや組み込みソフト関係の仕事をしている社会人３年目です。
ずっとQiitaで記事を書こうと思いながら半年が過ぎてしまいました。
ついにやる気が起きたので、自分の学習用にこれから投稿を継続していこうと思います。
業務や自分の趣味で機械学習やフロント系のスキルも身に付いていきたいです。
#今回は
勉強の息抜きをしたいなーと思って、お手軽にリアルタイム物体認識の実装とアウトプットできる題材はないかな思い周りを見渡すと、
~~「そう、iPhoneならね。」と聞こえてきた気がして、~~丁度よくiPhoneがあったのでYOLOを実装してみようと思いました。
とは言っても、iosは全くの初心者で何もわからないため、[先人の知恵](https://github.com/hollance/YOLO-CoreML-MPSNNGraph"先人の知恵")を借りながらXcodeでiPhoneへデプロイする流れをなぞっていきます。
具体的にはgit hubで公開されている、Tiny-YOLO v2のswiftプロジェクトを手持ちのiPhoneで実行します。
#Xcodeのインストール
Xcodeはすでにインストールしてあったのですが放置していたため、アップデートする必要がありました。（今回のプロジェクトはversion:9以降が必要でした。）
未インストールの場合はApp Storeからインストールをすれば良いと思います。
アップデートの場合、App Storeからがうまくいかなかったら一度Xcodeをアンインストールしてから、[Mac developer](https://developer.apple.com/download/more/)から直接アーカイブをダウンロードするのが早いと思います。
僕はうまくいかずにこの方法で再インストールしました。
#プロジェクトのセットアップ
まず、適当なディレクトリへプロジェクトをクローンします。

```shell:ターミナル
git clone https://github.com/hollance/YOLO-CoreML-MPSNNGraph.git
```

TinyYOLO-CoreMLフォルダ内のTinyYOLO-CoreML.xcodeprojをダブルクリックして開きます。

続いてiPhoneで実機でバッグを行う為のセットアップを行います。
Apple IDが必要になりますが、ここでは趣味程度なので自分のIDのまま進めます。

1.Xcodeから「Preferences...」を開き
<img width="309" alt="スクリーンショット 2020-01-26 22.53.44.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/447500/7d392d84-6406-533f-8053-0834d25d14aa.png">
<img width="808" alt="スクリーンショット 2020-01-26 23.06.08.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/447500/b751cdf4-90b8-164b-4a44-19dbf45b8d71.png">
Accountsタブの「＋」を押して「Apple ID」を選択します。
Apple IDとパスワードを求められるので、普段使用している物を入力するとApple IDが追加されると思います。
2.「Manage Certificates...」を開き、
<img width="804" alt="スクリーンショット 2020-01-26 23.15.45.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/447500/647f524a-dc31-e41c-5428-be2545060e63.png">
「＋」タブを開き「iOS Development」を選択してDoneを押し、証明書を作成します。
3.プロジェクトを選択した状態で
<img width="947" alt="スクリーンショット 2020-01-26 23.26.03.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/447500/ed93620f-56aa-3ab9-255d-d02775e9c684.png">
「Signing & Capabilities」からTermを、登録したApple IDへ変更します。
これでセットアップは終了ですが、画面にまだエラーがでている場合は「Bundle Identifier」を「jp.primetheory.プロジェクト名＋適当な文字列」に変更するとエラーがなくなるようです。
例）jp.primetheory.TinyYOLO-CoreML20200123

#実機確認
やっと準備ができたので、ついにiPhoneで実機確認をします。
MacへiPhoneを繋ぎ
<img width="384" alt="スクリーンショット 2020-01-26 23.40.11.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/447500/c031ee7c-f119-4ae0-674f-d3f1b9b7f1e5.png">
上部で手持ちのiPhoneを選択して、▶︎でビルドと実行を行います。

![CF41D48D-8A69-436A-9409-E233ED260F99_1_105_cのコピー.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/447500/94a55b93-7e06-f170-30e9-2a0894f6d440.jpeg)

アプリがインストールされています。

実行してみましょう。
![62B1A445-F4D1-4239-856E-7A46EFFACA00_1_201_aのコピー.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/447500/846f5e82-2b09-25fc-c293-42d132a97a3c.jpeg)

ちゃんと認識されていますね！！
認識速度も20FPSと中々の速度でした。
#おわり
Xcodeのセットアップにかなり手間取りました。
YOLOの実装を自分でしたわけではないので、作り込んだぞーという感覚は得られないですが、お手軽に物体認識で遊ぶことができ息抜きになりました。
swiftに触れたことがないので、一通りやってみると興味がでてきますね。コード読んでみようかな。
Google Earth

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254888/f00e2c6a-a9b4-9bd4-56af-d833f1a19388.png" width=100%>

## 【前文】
公式フォーラムで見かけ興味が湧きアクセスしてみた。
[Google earth now runs on Pi4](https://www.raspberrypi.org/forums/viewtopic.php?f=63&t=262331&p=1597554&hilit=google+earth#p1597554 "Google earth now runs on Pi4 - Raspberry Pi Forums")

## 【Google Earth】
RPi4 で Chrome を開き、以下アクセス。
[Google Earth](https://earth.google.com/web/@10.48436129,-65.33731306,-3595.50635944a,18942085.43675423d,35y,0h,0t,0r?beta=1 "Google Earth ")

「LAUNCH WASM SINGLE THREADED」クリック。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254888/2e27b888-3f33-71e3-e78e-12b952623321.png" width=100%>
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254888/f00e2c6a-a9b4-9bd4-56af-d833f1a19388.png" width=100%>
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254888/68609e6b-106b-6024-eafc-03a4d4d3f118.png" width=100%>
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254888/17986701-c108-3431-ed13-14d7d88da538.png" width=100%>
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254888/6dd3726f-4439-51af-47d0-d138bb82db90.png" width=100%>
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254888/7bb4e522-66f4-e410-cbb7-51ebe83e5b9b.png" width=100%>
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254888/8f298bee-e2c7-cd2d-49a9-60034de3dd57.png" width=100%>

ちょっと触ってみただけだけど、RPi4 でもそこそこ動くみたい。
いい時代になったね。
Re:ゼロから始める競技プログラミング生活　第1章2『涙のPython』

#第2の敵
今回は前回より難しいB問題を解いていきます！！
では早速、問題どーん！！
<img width="1042" alt="ce1c5b58d8be6c42b4e39bd7d61f140b.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570839/1d6dda61-bb6d-c7ae-4641-448d9e5b7e4d.png">

...何じゃこれ
難易度一気に上げ過ぎではないでしょうかねぇ...
とりあえず図を描いて何を求めていけば良いのかを整理してみます。
![image0.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/570839/55c0c0c9-3eac-dcd0-a23f-6f8b1381dc20.jpeg)

なるほど、この小学生でもまだマシなものを描きそうなこの図を見ると、Lの回数に最初の1回を加えたものがこの問題の解答になると言うことですね。意外と簡単だった！！
では早速、C++で書いていきたと...

Python「(´･ω･`)」

OT「どうしたPython！？」

Python「もう僕は使わないの？(´・ω・)」

OT「だってPython、君を使ってコードを書くスキルが自分にはないんだ...ないんだよ.....」

Python「じゃあ僕はいらない子なの？(´°̥̥̥̥̥̥̥̥ω°̥̥̥̥̥̥̥̥｀)」

OT「そんな悲しい顔しないでくれパイソぉおおおおおおおおおん」

...

...

...はい、と言う訳で今回はPythonでコードを書いていきます。


```python

N, X = map(int, input().split())
L = list(map(int, input().split()))
distance = 0
bounds = 1
```

とりあえず、使う変数を全て宣言！！

N,X,Lは前回いただいたコメント等を参考に記述、ここさえクリアできればなんとかなるはず！！
boundsはボールが跳ねる回数で、最初から座標D0の文の1回を入れています。
deistanceはボールが跳ねて進んだ距離です。


```python

for i in range(n): 
    distance += l[i]
    if distance <= x:
      bounds += 1
    else:
      break
print(bounds)
```

この繰り返し文でdistanceがXを超えるまでboundsが加算されるようにします。
これでなんとかACいただきました！！

#最後に
今回は前回より早く解けましたが、前回のコメントの力がかなり大きかったです。
コメントしてくださった方、ありがとうございますm(_ _)m
これでもうPythonの泣き顔を見る日はやってこないであろう...
問題Cからはなんか無理めな予感がするぜ...

ご拝読いただき、ありがとうございました。
OpenID Connect Certification の Conformance Test をローカルで実施する

# 概要
- OpenID Connect Certification を取得するためには、 Conformance Test という Web で実施できるテストを実施して、結果を提出します
- ただ、 Web で公開されているテストだと、テスト対象の OP も Web に公開する必要があり、実装途中だったり仕様の理解が正確でないと、結構辛いです
- テストツールも含めて、すべてローカルに立ち上げてテストする方法をまとめています
- OP （OpenID Connect Provider） のテストを前提とした記事です

# Conformance Test とは
- OpenID Connect の標準仕様にそった実装ができているかどうかを確認することができるツールです
- Web 上で実施でき、[ここ](https://op.certification.openid.net:60000/)からいつでも誰でもテストを実施できます
- 実施方法の詳細は、[公式サイト](https://openid.net/certification/testing/) を参照してください

# ローカルで立ち上げた OP のテストはできない
- [Web で公開されているテスト](https://op.certification.openid.net:60000/) では、ローカルで立ち上げた OP のテストができません
    - このテストは、対象の OP に対して、 テスト用の RP (Relying Party) を立ち上げて、 OpenID Connect のプロトコルに沿った認証・認可までできるかどうかをチェックするものです
    - `Authorization Code Flow` のように、サーバ間通信を必要とするフローの場合、テスト時に立ち上がる RP (https://op.certification.openid.net:620xx/) から OP へアクセスできる必要があります
- OP が実装途中の場合、わざわざインターネットアクセスできるところに公開しないとテストができないので、テスト/デバッグ/修正がめちゃくちゃ辛いです

# テストツールの Docker がある！
- [Github](https://github.com/openid-certification/oidctest) に公開されていて、テストツール自体は簡単にローカルで起動できます

# テストツールをローカルで起動する
(Readme に書いてある通りですが）

- checkout して `docker-compose up` 

```sh
$ git checkout stable-release-1.2.x
$ docker-compose -f docker/docker-compose.yml up
```

- `/etc/host` を書き換え

```
$ sudo vi /etc/hosts
---
+ 127.0.0.1 op-test op rp-test
```

- `http://op-test:60000` にアクセス
    - https://op.certification.openid.net:60000 と同じ画面が表示されます

# テスト対象の OP をローカルで起動する
- `http://localshot` で起動しているとします

# テストツールでテストを新規作成する
- [テスト新規作成画面](http://op-test:60000/new) を開く
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/65416/87679c0c-8745-6920-3d39-d049aae56467.png)

- issuer に `http://host.docker.internal` を指定する (Docker for Mac を使っている場合）
    - `http://localhost` を指定すると、テストで起動する RP はテストツールの Docker コンテナ上にいるため、Docker ホスト上の localhost ではなく、 Docker コンテナ上の localhost を見に行ってしまいます
    - Docker コンテナから Docker ホスト上のプロセスを指定する必要があります
        - [Dockerのコンテナの中からホストOS上のプロセスと通信する方法](https://qiita.com/Iju/items/badde64d530e6bade382#%E3%81%9D%E3%81%AE5hostdockerinternal-%E3%82%92%E4%BD%BF%E3%81%86-20190916%E8%BF%BD%E8%A8%98)

# RP 側のログを見る
- テスト中にスタックトレースが表示されるようなエラーが起きた時に、実際に RP <-> OP の間でどういうリクエストとレスポンスがあったのかを見に行ったほうが早いです

```
$ cd ${conformance-test-root-dir}
$ cd ./docker
$ docker-compose exec op-test /bin/bash
# ここからコンテナ内操作
/usr/local/src/oidf/oidc_op# less server_log/rp_6000x.log
```