OmniAICreator/Qiita-1.07M huggingface dataset:
【メモ】VSCodeでUnity C#の自動整形環境を自前で用意する（C# FixFormatなし）

**注意！**
**.NET 5 の頃の情報です。.NET 6 からは、フォーマッタが本体に同梱されたりしていろいろ仕様が変わりました。**

いろんなドキュメントには、C#の自動整形をしたいなら、
[「C# FixFormat」](https://marketplace.visualstudio.com/items?itemName=Leopotam.csharpfixformat)という拡張を使えばいいよ！って書いているんだが、
2020年12月24日現在、マーケットプレイス上で非公開になっており、
拡張機能のインストールができないという状態になっている。
詰んだじゃねえか・・・。

しかし俺は、なんとしてもVSCodeでC#の自動整形を使いたい。
というわけで、なんとかしてみたのでここにメモを残す。

なお、筆者は.NETもC#も、ほとんど素人に近いので、
間違いとかあってもご愛敬。
もっと楽な方法あったらコメントで教えてください。

## 動作環境
- Windows 10
- `dotnet`コマンドが使える環境
  - Chocolatey で手っ取り早く入れるなら `cinst -y dotnet-sdk`

## 必要なもの
- VSCode
- [dotnet-format](https://github.com/dotnet/format)
- [VSCode拡張: Run on Save](https://marketplace.visualstudio.com/items?itemName=emeraldwalk.runonsave)
- Unityプロジェクト

また、自動整形させたいC#ファイルは、
`./Assets/Scripts/**/*.cs` に置いておく。

## やり方

まず dotnet-format をインストールする。
これはコマンドライン上からC#の自動整形を行うことができる
.NETのツールらしい。

```shell
dotnet tool install -g dotnet-format
```

次にUnityのプロジェクトをVSCodeで開いたら、
クイックメニューで以下のコマンドを打ち込んで、
必要な拡張をインストールする。

```shell
ext install emeraldwalk.runonsave
```

そしたら今度は
クイックメニューから`Preferences: Open Settings (JSON)` を選び、
開いた設定ファイルに以下の設定データを書き加える。

```json
  "emeraldwalk.runonsave": {
    "commands": [
      {
        "match": "\\\\Assets\\\\Scripts\\\\.*?\\.cs$",
        "cmd": "dotnet format -f ./Assets/Scripts"
      }
    ]
  }
```

これで完了。

多少のタイムラグはあるものの、`./Assets/Scripts/` の中にある
C#ファイルは、保存をトリガーに自動整形が働くようになる。
Google workspace(カスタムドメイン)でGmail利用する場合のMXレコード

## 背景
Google workspace(独自ドメイン)を利用する際、MXレコードに下記を設定するとGmailを利用できます。

## 設定値
▼表の通りの設定で問題ありませんが、`値`と`レコードタイプ`以外は適宜変更できます。

|ホスト|TTL|レコードタイプ|優先値|値|
|---|---|---|---|---|
|@|3,600|MX|1|ASPMX.L.GOOGLE.COM|
|@|3,600|MX|5|ALT1.ASPMX.L.GOOGLE.COM|
|@|3,600|MX|5|ALT2.ASPMX.L.GOOGLE.COM|
|@|3,600|MX|10|ALT3.ASPMX.L.GOOGLE.COM|
|@|3,600|MX|10|ALT4.ASPMX.L.GOOGLE.COM|

設定はGoogle workspace 管理コンソールのドメイン管理から実施できます。

私の記事に不備などありましたらご指摘いただけると幸いです。
Apache GuacamoleでRed Hat OpenShift on IBM Cloudに踏み台サーバを構築する（SSH編）

# 目的

前回の[記事](https://qiita.com/teruq/items/cb9172fa4424329ae187)でRed Hat OpenShift on IBM Cloud上にApache Guacamoleをデプロイしました。今回はSSHを使った踏み台を検証してみます。

# 手順

## 接続設定

管理者でログインし、設定→接続を選び、接続の追加をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241424/e1aa6b54-d031-c747-8279-995bf510771a.png)

名前を決め、プロトコルはSSHとします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241424/420f6be9-e513-245e-2b71-7817c04aeac6.png)

接続先のホスト名（アドレス）、ポートを指定し、認証に必要な情報を入力します。この例では公開鍵認証をしていますので、あらかじめ公開鍵をホスト側の~/.ssh/authorized_keysに登録している必要があります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241424/8e880097-8ab1-ad79-7e11-aa4ab2f34801.png)

タイプスクリプト（テキストの記録）を設定すると、SSHセッション中の操作を記録することができます。ログはguacdコンテナ内に出力されます。真面目にやるときは永続ボリュームをマウントしてそこに出力するようにしてください。今回は面倒なのでコンテナ内のそのまま出力してしまいます。ディレクトリ名、ファイル名は変数を利用できます。この例では次のように設定しています。

* タイプスクリプトの保存ディレクトリ: /tmp/\${GUAC_DATE}
* タイプスクリプト名: \${GUAC_USERNAME}-\${GUAC_DATE}-\${GUAC_TIME}.log

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241424/d4d74488-0690-e2f4-b4cd-3179d61ae563.png)

SFTPも有効化しておきます。ブラウザからファイル転送ができるようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241424/4243e7d1-ed2f-7acb-7b62-9d9e8bf81e6b.png)

設定を保存したらホーム画面に移動します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241424/68c1d531-4a4f-25a6-b5aa-0cb7e5a6fbd5.png)

## 接続

接続先を選びます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241424/ed719119-b8b0-55eb-ba85-1850e1805d1f.png)

設定に問題がなければブラウザ内にターミナルが表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241424/56c9b295-4745-cf5a-7149-a69713ea2977.png)

日本語も大丈夫です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241424/04afa32d-10db-1750-14dc-629b65bc310d.png)

## ファイル転送

先ほど有効にしたSFTPを使用するには、Ctrl + Shift + Altを同時押しします。するとサイドメニューが表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241424/912f184e-46e8-a1cb-f9fb-6a3a5c49597d.png)

デバイスをクリックするとホスト側のディレクトリツリーが表示されますので、これを使ってファイルのアップロードやダウンロードが可能です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241424/f2f654cb-af55-c380-5a12-d3c26ce22950.png)

ターミナルからexitコマンド等でログアウトすると、ホームに戻るか、再接続するか、Guacamole自体からログアウトすることができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241424/108ff917-e220-c1e1-01bb-30937c5b2b71.png)

## スクリーンログの確認

guacdのコンテナ内に侵入してみます。

```
$ oc get pods | grep guacd
guacd-1-deploy       0/1     Completed   0          50m
guacd-1-zj8d4        1/1     Running     0          50m
$ oc rsh guacd-1-cdp4r bash
```

ログが出力されています。

```
1000620000@guacd-1-cdp4r:/$ find /tmp/20201223/
/tmp/20201223/
/tmp/20201223/guacadmin-20201223-155628.log.timing
/tmp/20201223/guacadmin-20201223-155628.log
```

.logは入出力が記録されていますのでそのままテキストとして読めます。.timingはコマンドの実行タイミングを記録しています。操作を再生する場合はscriptreplayコマンドを使用します。

```
1000620000@guacd-1-cdp4r:/tmp/20201223$ scriptreplay guacadmin-20201223-155628.log.timing guacadmin-20201223-155628.log
```

次回はWindowsサーバにRDP接続してみます。
GlideAppでCRUDのお試し

GlideAppで簡単にアプリを作れて面白そう！と思ったので、試してみました。
都合により、RCUDの順でお届けします。

# 準備
- 初めに、[GlideApp](https://www.glideapps.com/)のアカウントを作っておきます。
- 次に、スプレッドシートを作ります。
![スクリーンショット 2020-12-24 0.49.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/74969/0dbea484-f21b-3be3-d6cd-f414d4c0659b.png)
- Glideから読み込みます
    - ＋マークを押して、SpreadSheetから読み込み
    - Googleログイン
    - 先ほどのSpreadSheetを選択します。 
![スクリーンショット 2020-12-24 0.47.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/74969/bbcad655-f353-291f-509c-c3bcbcddfb4a.png)

# Read
- なんとすでにRead（Multiple）画面ができています（感動）
![スクリーンショット 2020-12-24 0.47.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/74969/3c3e8a27-0537-ac7c-dce9-828cdbefb15e.png)
-  行を押してみると、なんとRead（Single）もできています（感動）
![スクリーンショット 2020-12-24 0.48.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/74969/cc155956-c17b-1a5e-4a8d-69e8e7643d53.png)

# Create
- Createですが、Read(Multiple）の画面の右の方に「Add」がありますので押してみます。
- 「Allow users to add items」があるので押してみると、、、、できました。（感動）
![スクリーンショット 2020-12-24 0.48.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/74969/9af65d2a-ee0d-3a16-95a4-ecaf89f16033.png)

# Update
- Updateですが、Read(Single）の画面の右の方に「Edit」がありますので押してみます。
- 「Allow users to edit items」があるので押してみると、、、、できました（感動）
![スクリーンショット 2020-12-24 0.48.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/74969/1f6f5b51-daaa-8942-f2f5-2401f25158ff.png)

# Delete
- 最後にDeleteです。Updateの時に押した、「Allow users to edit」のしたに、「Allow users to delete」がありますので押してみると、、、、、できました（感動）
![スクリーンショット 2020-12-24 1.00.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/74969/e5bdb75f-893d-5e04-51ba-d933d6b41ed9.png)

# デプロイ
- あおい「Share」ボタンを押すだけ！（感動）
APIGateway BlackBelt に物申す！ ～RESTとWebSocketの理解を深めよう～

#REST-APIとWebsocket
AWSのサーバレスアーキテクチャを構築する上で欠かせないAPIGatewayのBlackBeltを読んで、APIGatewayの2大主要機能であるREST APIとWebsocketについて理解を深めてみようと思う。APIGatewayのBlackBeltを読んで「REST」と「Websocket」が2つ比較で並べられて説明されており、少し違和感を覚えたので、ちょっと記事を書いている。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/409437/582d7624-dfc1-9087-f670-2919b41223c8.png)
###:shamrock:REST-APIとは？
APIGatewayは「REST API」を作成することできる。REST-APIとは、**Restfulな設計原則に基づいている**APIだよ！ということだ。Restfulって何って話だが、下記を満たす設計原則のことだ。プログラムを書くときにリターンコードに無意識に200としたりしていないだろうか？それはRestfulな設計原則が身についているからかも？

・アドレス指定可能なURIで表現できること
・インターフェース(HTTPメソッドの利用)の統一がされていること
・ステートレスであること:sparkles:
・情報の内部に、別の情報や(その情報の別の)状態へのリンクを含めることができること

####:snowman2:ステートレスって？
ステートレスとは、状態に関わらず同じリクエストであれば同じ応答をするということだ。Webページの閲覧（HTTPプロトコルでGetする）はいつも同じ応答なので、ステートレスだ。セッションなどの状態管理を行わない。HTTPリクエストとHTTPレスポンスでやり取りされる情報はそれ自体で完結して解釈することができる。なお、CookieやSessionStorageで応答が変わるというのは、HTTPプロトコルで定義されているものではないので、HTTPプロトコルとその他の機能を利用してステートフルな仕組みを実現している。

###:shamrock:WebSocketとは？
Websocketが使われているのは、チャットアプリなどだ。他の人の発言がリクエストしていないにも関わらず表示されるのは、クライアントとサーバ間で通信が一定時間確保された状態にあり、1リクエストに対して1つレスポンスを返すのではなく、双方向の通信ができる。強調したいのは、**Websocketは通信プロトコル**ということだ。チャットアプリを開く（リクエスト）たびに、別の人が発言をしたり、毎回応答が変わる。状態によって応答が変わる「**ステートフル**」だ。

REST-APIは、HTTPプロトコルを利用して「ステートレス」な通信を行う、Websocketは、Websocketプロトコルを利用して「ステートフル」な通信を行うという意味では対比できるものかもしれないが、RESTとWebsocketという言葉自体は対比するものではない。

WebsocketはTCP/IPに適合するプロトコルだ。というのは、TCPというのは、3ハンドシェイクという相手が通信できるか確認してから通信を始めるプロトコルであるため、Websocketの双方向通信と相性よさそう！ってのは何となくイメージできる。BlackBeltに「HTTP上」でクライアント間と双方向通信が可能とあるが、その表現はちょっと違うんじゃないかなと思っている。ブラウザがHTTPプロトコルに対応しているので、HTTPと同じ形式でリクエストして、Websocket使える？って聞いてるのだ（たぶん。間違ってたら教えてください）

そんな便利なWebsocketAPIをAWSのAPIGatewayではサーバレスで構築することができる。下記のソースを利用してCloudFormarionでAPIGatewayとLambdaをデプロイすると、Websocket通信を簡単に体感できるので、ぜひ試してみてほしい:snowman:
[chat-app-sample](https://github.com/aws-samples/simple-websockets-chat-app)


####参考文献
1.  [APIGateway BlackBelt](https://aws.amazon.com/jp/blogs/news/webinar-bb-amazon-api-gateway-2019/)
2.  [WebSocket](https://docs.microsoft.com/ja-jp/archive/msdn-magazine/2012/december/windows-8-networking-windows-8-and-the-websocket-protocol)
【UiPath】Advent of UiPath 2020 #6（多重ループ）

この記事は、UiPath Forum で行われている [**Advent of UiPath 2020**](https://forum.uipath.com/t/advent-of-uipath-2020/273299) の [Advent Challenge #6](https://forum.uipath.com/t/advent-challenge-6/275140) の紹介記事です。

:christmas_tree: 過去の投稿

- [Advent of UiPath 2020 #1（APIからデータを取得）](https://qiita.com/miya_g/items/4021ba90aab84984cb3c)
- [Advent of UiPath 2020 #2（正規表現で文字列を抽出）](https://qiita.com/miya_g/items/087a9d5d29145ae3e33e)
- [Advent of UiPath 2020 #3（ファイルをダウンロードしてメール送信）](https://qiita.com/miya_g/items/b774ef61150330ba0ee0)
- [Advent of UiPath 2020 #4（画像をbase64デコードしてOCRで画像認識）](https://qiita.com/miya_g/items/489e81d876ba504986f2)
- [Advent of UiPath 2020 #5（2つのエクセルを比較、重複行マージ）](https://qiita.com/miya_g/items/2a67e274a5edae65c25e)

# “Advent of UiPath 2020” とは何か？

- 英語版のフォーラムで投稿されています。
- RPA challenge です（＝お題を出て、みんなでRPA化してみる）
- 誰でも回答できます（フォーラムのアカウントがあれば）
- 3日おきに出題され、計8回（xmasイブまで）あります
- 回答して上位に選ばれれば、フォーラム上でスターがもらえます。
- フォーラムのスタッフが開催しているっぽいです。

# チャレンジ6：多重ループ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154139/0830bbdd-f092-5a44-c087-5722a4e820cd.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154139/8a79aadf-d22c-8962-ae8d-248a1004b843.png)

サンタは、何匹人かのトナカイが再び逃げ出したと言っています。今回は名前を呼んでもトナカイは戻ってきませんでした。彼はトナカイについての絶対的な専門家であるクレアに相談しました。

クレア：「サンタさん、あなたを助けるために9頭のトナカイを追加します。新人3匹、中堅3匹、熟練3匹で構成されますが、各グループから1人のメンバーを選び、一緒にテストランさせる必要があります。」

### 初心者用チャレンジ
以下のメンバーでテストランをさせてください。
　初心者: Rebecca, Robert, Ricky
　中堅: Lucas, Lili, Lars
　熟練: Emily, Ed, Eryk


### 上級者向けチャレンジ

初心者向けのルーツに加えて「チームは熟練１、中堅１、初心者２」で構成してください

# 感想

多重ループをどうやって書くか？というお題でした。

業務でよくあるのは、「複数ファイル X　複数行」の２重ループですが、
追加チェックか何かで３重ループになることもよくあります。

コードで言えば
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154139/37592560-03d6-7c59-4659-823a6e3d7b04.png)
となりますが、Uipathだと
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154139/0857b5cd-9675-7b54-ad4f-3c5221a0fa08.png)
となりあう。

ちょっとみづらいですね。みんな同じ回答でした。
ネストが下がったら、枠の色が自動で変わるとかだったら良いんですけど。
[Flutter]画面にキーボードが開ける時にScaffoldエラーやUI崩れる場合の解決

こんにちは。
この半年は勉強して来たFlutterを思いっきり実務で利用できる時間でした。
先日、無事にアプリをリリースできたので、色んな課題を乗り越えながら積み重ねて来たノートをそろそろ整理してアウトプットしようと思います。
どうぞよろしくお願いします。

# 概要
スマホアプリを作る時は、様々な機種のデバイスサイズ、横モードと縦モード、キーボード登場など、色んな画面サイズに対応しないと行けません。
レスポンスデザインで色んな画面サイズを対応することが一番素敵ですが、画面のWidgetが複雑になればなるほどリソース不足などでそこまで対応しない場合がありますね。
しかし、アプリを公開して不特定多数が利用する場合は何も対応しないと結局UI崩れやOverflowsエラーなどが発生されます。
今回はその対応の中でキーボードを開くことによって対応の話をします。

# 対応内容
Flutterのデフォルトではキーボードを開くと同じレイヤーで開けるためUIが上に押されます。
簡単なUIではありがたい仕様ですが、Widgetを複雑に配置する場合は問題が出てしまいます。
Expandedなどで相対的にサイズを決めてくれる実装した場合はUI崩れて、固定サイズになった場合はOverflowsエラーが出ます。

適当に例の画面を作りましたが、例えば以下のようなOverflowsエラーが発生されるとします。
![aaa.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108364/dc113d06-559f-96ad-9b9a-6a8eb8ed29ef.gif)

レスポンスデザインで対応せず解決するためには2つの対応が必要です。

#### 対応1. キーボードを同じレイヤーではなく上端のレイヤーに乗せる設定をします。
この対応はScaffoldのオプションを調整することで簡単に対応できます。

```dart
    return Scaffold(
      resizeToAvoidBottomInset: false,
```

#### 対応2. キーボードのレイヤーに隠されるところを表示させます。
上の対応1だけでは、キーボードのレイヤーに下端のところが隠されて使えなくなります。
そのため、画面の最下端にキーボードのサイズ分の空白を入れて、画面がサイズを超えたらスクロールが入るようにします。
もちろん、その空白はキーボードが開いた時だけにします。

```dart
    body: SafeArea(
      child: SingleChildScrollView(

     //...省略

     SizedBox(
       height: MediaQuery.of(context).viewInsets.bottom,
     ),
```

上のように対応すると様々なWidgetサイズをレスポンス的に対応せず、簡単に解決できます。
![bbb.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108364/8db3819f-c758-d693-b9ca-d38b85c98884.gif)
【Rails】閲覧しているファイルのインスタンス変数、ローカル変数を確認する

# 結論
```ruby
Rails.logger.info(self.instance_variables)
Rails.logger.info(binding.eval("local_variables"))
```
上記のコードで、インスタンス変数とローカル変数をINFOログとして出力できる。
はじめて見るプロジェクトで、全体像や使える変数を確認したい時に。

# 解説
Railsのcontrollerにしろ、viewファイルにしろ、
self.instance_variablesの値をインスタンス変数@varの形で利用できる。
bindingオブジェクトは[こちら](https://uxmilk.jp/33886#:~:text=Binding%20%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%81%A8%E3%81%AF%E3%80%81%E5%A4%89%E6%95%B0,%E6%83%85%E5%A0%B1%E3%82%92%E8%A1%A8%E3%81%99%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%81%A7%E3%81%99%E3%80%82&text=%E4%BE%8B%E3%81%88%E3%81%B0%E3%80%81%E3%81%82%E3%82%8B%E3%83%A1%E3%82%BD%E3%83%83%E3%83%89%E5%86%85%E3%81%AE,%E3%81%A8%E3%81%84%E3%81%A3%E3%81%9F%E4%BD%BF%E3%81%84%E6%96%B9%E3%82%92%E3%81%97%E3%81%BE%E3%81%99%E3%80%82)によると
> 変数・メソッドなどの環境情報を表すオブジェクト

との事。
evalメソッドで"local_variables"を引数にとるとローカル変数を取得可能。


# 参考サイト
[ruby-lang.org：Objectの項](https://docs.ruby-lang.org/ja/latest/class/Object.html)
[ruby-lang.org：bindingの項](https://docs.ruby-lang.org/ja/latest/class/Binding.html)
[UK MILK：bindingについての解説](https://uxmilk.jp/33886#:~:text=Binding%20%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%81%A8%E3%81%AF%E3%80%81%E5%A4%89%E6%95%B0,%E6%83%85%E5%A0%B1%E3%82%92%E8%A1%A8%E3%81%99%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%81%A7%E3%81%99%E3%80%82&text=%E4%BE%8B%E3%81%88%E3%81%B0%E3%80%81%E3%81%82%E3%82%8B%E3%83%A1%E3%82%BD%E3%83%83%E3%83%89%E5%86%85%E3%81%AE,%E3%81%A8%E3%81%84%E3%81%A3%E3%81%9F%E4%BD%BF%E3%81%84%E6%96%B9%E3%82%92%E3%81%97%E3%81%BE%E3%81%99%E3%80%82)
AADユーザー(カスタムドメイン)でWindowsにログインしてSaaSにSSOするまで

## 背景
検証環境(無料)を作成し、下記を実施したので、実施するまでに調べた内容をまとめます。
① 独自ドメインのAzureテナントを作成する
② AADユーザーでWindowsにログインする
③ AADをIDPとしてSSOする(ゲストユーザー含め)

ちなみにIDPにAADを採用した理由は下記3点です。
・ガートナー マジッククアドラント2020で一番右上にいる
・無料(50000 objectまで)
・資料が多い
IDPはAADかokta がよさげだと感じました。

AADをIDPとした際の、SSO対象SaaSに必要な料金プランも載せます。(投稿時点)

## 独自ドメインのAzureテナントを作成する
① 独自ドメインを取得します。
お名前ドットコムでもなんでも大丈夫です。
googleのドメイン`.page`は1年間無料なのでこれを使いました。
ついでにgoogle work spaceのトライアル(2週間)も利用しました。

② AADの左側「カスタムドメイン」セクションで①の独自ドメインを登録します。
独自ドメインが利用可能であればTXTレコードが表示されるので、これを独自ドメインに追加し、ドメインの所有権を証明します。
私の場合はAADで表示されたTXTレコードをgoogle domainsのカスタムリソースレコードから`MS=hoge`という形で入力しました。

③ テナントを作成します。
テナントに初期ドメインを設定後、独自ドメインを追加できます。

## AADユーザーでWindowsにログインする
前提として、Windows Pro以上のエディションじゃないとできません。

① AADテナントでユーザー作成します。

② Windows設定(歯車) -> アカウント -> 職場または学校にアクセスする -> 接続 -> このデバイスを Azure Active Directory に参加させる -> ①で作成したユーザーを入力 -> 次へ．．．

で設定ができます。設定ができたらWindowsのユーザー切り替えで上記のユーザーとしてログインできるようになります。

## AADをIDPとしてSSOする(ゲストユーザー含め)
▼Microsoft公式チュートリアルで丁寧に解説されています。
[SaaS アプリケーションと Azure Active Directory の統合に関するチュートリアル](https://docs.microsoft.com/ja-jp/azure/active-directory/saas-apps/tutorial-list)

エンタープライズアプリケーションのAzureADギャラリーに専用のsamlアプリがないSaaSにSSOしたい場合は、下記手順でアプリを作成します。
① AAD左側「エンタープライズアプリケーション」セクション -> 独自アプリケーションの作成 -> アプリ名を任意で入力 -> ラジオボタン「ギャラリーに見つからないその他のアプリケーションを統合します」選択 -> 作成

② 「ユーザーとグループの割り当て」「シングル サインオンの設定」を設定

以上でAzureADギャラリーに専用のsamlアプリがあるSaaSと同じようにアプリを用意できます。
また、サインイン対象のSaaSによりますが、ゲストユーザーをSSOさせることもできます。
ゲストユーザーをSSOさせる場合は、「ユーザーとグループの割り当て」でゲストユーザーを選択します。

## AADをIDPとしたSSO対象の必要料金プラン(投稿時点)
調べた範囲で載せます。

|SaaS名|必要プラン|トライアル期間|
|---|---|---|
|GitHub|Enterprise以上(ユーザー/$21)|45日|
|Zoom|ビジネスプラン以上(ID/¥2,000)|1月|
|Slack|プラスプラン以上(ユーザー/¥1,600)|30日|
|jira|atlassian Accessが必要|30日|
|AWS|無料(IAM)|-|
|Google workspace|無料|-|

Slackはトライアル開始に問い合わせが必要ですが、
フォーム入力後にチャットですぐに返信が来て、すぐに利用開始できました。

Google workspaceはSSOするために追加料金はいりませんが、そもそも有料です 。トライアルは2週間あります。

## 蛇足
私の記事に不備などありましたらご指摘いただけると幸いです。
上司からハンマードリルでコンクリートに穴を開けろと言われた時の話

はじめに、私は8月に社内SEとして入社したばかりの新米エンジニアである。
普段は社内PCやサーバの環境構成から簡単な社内ツールのデベロッパーとして活躍しております。

それがある日のことです・・・。
（こっから軽い寸劇、実在する登場人物をかなり歪めてお送りします）

##　寸劇

「俺くん、ちょっといいか？」

「なんでしょ？」

「この前地震あったやろ？その時におもったんよねー。この会社にサーバー機器などの耐震対策がないことを」

「はぁ、まぁー大型の地震あったときに倒れて怪我でも起こったら困りますからね」

「そこで手始めに、入り口手前のメタルラックを耐震対策してくれへん？」

「入り口のメタルラックって、これですか？」
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/516317/e9842a75-4cfa-8f51-211d-15b9b3081852.jpeg" width="400">

「せや、この前大型キャビネットの場所確保したせいで下の板外したから、もうラックがグラグラやで」

「でもこのメタルラックの下、キャスターなんで上から挟み込むような器材付けれないですよ」

「そうなんよねー。で、考えた結果ワイヤーで固定しようと思ってん」

「ワイヤーで他のラックとかと連結させるんですか？」

「それもいいけど、素直に壁に取り付けたらいいやん」

「え？壁コンクリートですよ？ドリルでもない限り・・・」

「あるねん、ドリル」

デデン、コンクリート用のハンマードリルです。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/516317/52ac907e-50c2-63e6-a03c-4d42dd1e1b94.jpeg" width="400">

「あ、でもコンクリート用のネジとかいるんじゃないですか？」

「あるねん、コンクリート用のネジ」

ご丁寧にコンクリートのみならず、木造などのネジやら全て揃っている。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/516317/de5a345b-0a42-2031-902e-29803df4e77f.jpeg" width="400">


「そんな壁に穴とかコンクリート開けたことないですよ？」

「上司もやったことあるから大丈夫できる」

お、おう・・・。

そう、我社は何事に置いてもできることは自前で行うShafooなのです。。。


## 必要な道具

とりあえず、コンクリートの開け方を検索してみると必要な道具としては

・　コンクリート壁用のハンマードリル
<img src="https://images-na.ssl-images-amazon.com/images/I/61TcK3mMSQL._AC_SL1372_.jpg" width="200">

・　コンクリート用のドリル（細めと太め）※ただしネジよりは小さい口径が必要
<img src="https://images-na.ssl-images-amazon.com/images/I/71jVEvSNYBL._AC_SL1500_.jpg" width="200">

・　プラスドライバー用のドライバービット
<img src="https://images-na.ssl-images-amazon.com/images/I/61AhtU9ffFL._AC_SL1500_.jpg" width="200">

・　コンクリート用のネジ
<img src="https://images-na.ssl-images-amazon.com/images/I/61O%2BMUjfNjL._AC_SL1000_.jpg" width="200">

・　ネジ用ワッシャー
<img src="https://images-na.ssl-images-amazon.com/images/I/71y5d1ghnAL._SL1200_.jpg" width="200">

・　取り付けたい金具
<img src="https://images-na.ssl-images-amazon.com/images/I/61iGK1fw3SL._AC_SL1000_.jpg" width="200">

取り付けたい金具とチェーン以外はすべて揃っていたので、金具とチェーンはすぐさまamazonで取り寄せました。
チェーンと繋ぐため金具にはフックがあるものにしました。


## 工程

工程は以下の通り（比較的簡単）

1. 開ける箇所の下にゴミ袋を敷く（あとで掃除しやすい用にする工夫）
1. 金具の穴に合わせてマーキング（黒の油性ペンではマーキングできない場合は、ホワイトマーカーがあるとよい）
1. マーキングした箇所に、細いドリルで掘る。
1. ネジの長さと同じぐらいの深さまで掘れたら太いドリルに変えて再び掘る！（ギガ・ドリル・ブレイクゥゥゥ！）
1. ワッシャーとネジを取り付ける。（ネジだけだと金具が抜けてしまうため）
1. (1〜5)の工程を4回行う
1. 何本かチェーンを止めて耐震対策完了

とまぁ工程をかいている時点でお気づきかもしれないが、コンクリートに金具を取り付けたあとに、
「あ、これqiitaの記事にしたら面白いんじゃない」と気づいたので、工程の写真がまるまる抜けてしまいました。
ただ、やる前とやったあとの画像だけは載せれるので、載せておきます。

## beffor
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/516317/e9842a75-4cfa-8f51-211d-15b9b3081852.jpeg" width="400">

## after
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/516317/ee4f89a1-d213-4eaf-9a7b-f932f066ca44.jpeg" width="400">

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/516317/96817708-5ed4-1fb8-ce23-98a950cabb78.jpeg" width="400">

かなり頑丈に取り付けれました。
ちなみに試しに私の体重（72Kg弱）を支えることもできたので、メタルラックぐらい倒れるのは屁でもない安定感でした。

##ドリルでコンクリートに穴を開けてみた感想
意外と簡単。
ただ、ドリルで穴を開ける際のコンクリートの粉塵は凶器、マスクとメガネもしくはゴーグル、あとイヤーマフがあれば最高death。

ああ、SEとしての実体験と同じぐらい簡単な日曜大工の知識がつけられるいい職場です。
正直こんなことできるようになるとは、1年前の自分は想像できなかったなぁと思っております。

### いや、日曜大工の知識以上に本業のデベロッパーとしての知識もっとつけたいですよ？
ではでは、明日もコードが書けることを信じて仕事がんばります。
Dartのコードメモ

ただの自分用のメモです。Qiitaも初投稿となります。


```
class Person{
  String name ='Max';
  int age = 0;
}

double addNumbers(double num1, double num2){
  return num1 + num2;
}

void main(){
  var p1= Person();
  var p2 = Person();
  p2.name = 'John';
  print(p1.name);
  print(p2.name);
  
  
  var firstResult =   addNumbers(1,2);
  firstResult = addNumbers(2.3,4.5);
  print(firstResult+3);
}

----結果↓----
Max
John
9.8
```
* classの中の変数はプロパティ
* classの中の関数はメソッド

```
//Hello!だけが出るアプリ。

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Text('Hello!'),
    );
  }
}
```
メモ：`はshift + @
fishシェルでMySQL5.7のパスを通す

現在開発しているアプリケーションがMySQL8.0よりも5.7と互換性が良かったので、最新版ではなく、brewでMySQL5.7のインストールして、パスを通すまでのことを紹介しようと思います。

#開発環境
Macbookpro Catalina ver10.15.7
メモリ16GB
Terminal: fishシェルを使用

##実際のコマンド
まずはMySQLをインストールするところからです
```brew install mysql@5.7```
↑をコマンドで入力するとbrewによってMySQL5.7がインストールされます。

コマンドが上手く実行されるとその途中で下記のようなことが表示されて、インストールが成功されたことが記されます。

```
mysql@5.7 is keg-only, which means it was not symlinked into /usr/local,
because this is an alternate version of another formula.

If you need to have mysql@5.7 first in your PATH run:
  echo 'set -g fish_user_paths "/usr/local/opt/mysql@5.7/bin" $fish_user_paths' >> ~/.config/fish/config.fish
```
↑これはパスを通さないと、MySQLというコマンドは使用できないよということを示しています。
`echo 'set -g fish_user_paths "/usr/local/opt/mysql@5.7/bin" $fish_user_paths'
`この記述があるファイルを　`>>`の階層のなかに用意しなさいということです。

```
 vi ~/.config/fish/conf.d/MySQL@5.7.fish
```
そのため、`vi`コマンドを用いでfish内にパスを通すファイルを作りました。ちなみに`.config/fish`のなかであれば良いので、その下に`conf.d`というディレクトリを作り、その下に各種ソフトウェアのパスを通すファイルの用意をしているので、このような命名、構造をしています。

```
 exec $SHELL -l
```
シェルを再起動します。

```
cat ~/.config/fish/conf.d/MySQL@5.7.fish
```
`cat`コマンドで中身を確認します。

```
echo 'set -g fish_user_paths "/usr/local/opt/mysql@5.7/bin" $fish_user_paths'

```
上記の通りに中身は指示された記述がなされていました。そうすると、問題なく、`MySQL`というコマンドが自由に使えるようになります。
JupyterLabお勧めExtension（拡張機能）

## jupyterlab-lsp
自動補完ツール。jupyterLab自体にもTab補完は存在するが、あれを超える便利さ。
PycharmやIDLE
というぬるま湯環境
に慣れきった筆者にとって必須機能。
ググる回数が激減するので時間効率もUPする。
タイプ数も減るので腱鞘炎予防にもなるかも？
[jupyterlab-lsp](https://github.com/krassowski/jupyterlab-lsp)

![Extent12.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315665/e4b0cc56-0cec-7058-f56c-a9de8d4c53c2.png)

ちなみに、Extensionを導入しただけでは起動しませんでした。
以下のcondaパッケージが必要です。

python-language-server
nodejs(パッケージだけでなく、nodejsライブラリそのものが必要です。[ダウンロード](https://nodejs.org/ja/))

#### 随時足していきます
dockerfileの書き方

アドベンドカレンダー初投稿！
この記事は、Phone Appli Advent Calendar の24日目です。
よろしくお願いします！

# なぜ、Docker？
- 何度かイライラさせられたのが、「Docker」だったから・・・・・
- 「イメージ」「コンテナ」などの用語が理解できなかったので・・・
- 本やサイトでよく見るから・・・・・

要は、業務中や他の勉強中にdockerでイライラする事を少なくするための「備忘録」的な記事です。はい・・・・

早速、やってみよう〜〜〜〜

## 前提条件

| ツール | 説明 |
|:-:|:-:|
| docker  |  インストール済み |
| VScode  |  プラグインとかあるので |

## そもそも、Dockerとは？
- コンテナ型の仮想環境を作成・実行などをする事ができるプラットフォーム

### コンテナとは？
- 仮想環境の一つである。（Linuxカーネルに実装された「namespace」という技術を使っている）
- ホストOS上（自分のPCのOS上）で,コンテナと呼ばれる仮想環境を作り、アプリ開発に必要なライブラリなどを一つにまとめて運用する事ができる
- 一つのホストOSで複数のアプリケーションを動かす事ができる（そのため、マイクロサービスとの親和性が高い　とされている）


# 実装
## 今回のゴール
- コンテナ内で、指定にでファイル（/sample/test.md)で「vim」が起動できる

特に、vimに対する強いこだわりはないが、コンテナで何か作業する事で、
ホスト（自分のPC）との違うがわかるはず・・・

## Dockerfileに記載する事

```docker
FROM ubuntu:latest　
RUN apt-get update && apt-get install -y \
    vim
RUN mkdir sample
WORKDIR /sample
RUN touch test.md
WORKDIR /
CMD ["ls"]
```
これを実行して、コンテナ内で指定ディレクトリに進み、vimを起動する事ができる

### 中身の説明

```
FROM ubuntu:latest
```
`FROM` は、基本的にOSを指定する事が多い（今回はLinuxから派生した初心者に優しいとされるubuntuを指定）

- docker imageの基礎となるので、あまり大きなサイズにしたくない

```
RUN apt-get update && apt-get install -y \
    vim
RUN mkdir sample
WORKDIR /sample
RUN touch test.md
WORKDIR /
```

`RUN`は、**実行コマンド**

- ubuntu用の`apt-get` コマンドで `update`と`install`を実行する

 
`WORKDIR`は、**ディレクトリ移動**

- 二回移動していますね・・・・（もっと良いやり方があるはず・・・）

```
CMD ["ls"]
```
`CMD`は、コンテナを起動したときに最初に行うコマンドである。ポート番号を指定したい時などに使う

- 今回は、`ls`コマンドを実行して、ディレクトリの一覧を表示する

## ターミナル・コマンドプロンプトで、コマンドを実行

```
docker build -t "自分が付けたいイメージの名前" .  //-> イメージが作成される
docker images //-> "sample"というイメージが作成されている
docker run イメージ名 //-> コンテナを生成・起動して、コンテナ内でlsコマンドが実行される。すぐにコンテナが終了してしまうけど・・・
docker ps -a //-> `COMMAND`欄に`ls`コマンドをした履歴が残っているはず・・・
```

さて、dockerfile作成 -> image作成 -> コンテナ生成・起動 -> コンテナ内でコマンドを実行したけど、

- コンテナ内で立ち止まって、自分でコマンドを叩く事ができない**（ゴールを達成できない）**

## オプションに`-it`と`bash`を付け加える事で解決

```
docker run -it イメージ名 bash  //-> 「-it　イメージ名 bash」 でコンテナ内のubuntuOS上でコマンドを叩く事が可能となる
```
`-it`は、`-i` と `-t`で分ける事も可能（どちらかだけで実行しても良いが、標準入力ができなかったり、表示がきれいでなかったりする）
`bash`は、コンテナ内を立ち上げるシェルコマンドである

あとは、以下のコマンドを順番に叩いて、**ゴールとなる**

```
cd sample
vim test.md
```

# お疲れ様でした！

本来は、pythonやkotlinなどのWeb開発の環境構築・データ分析基盤のためにDockerを使う事が多いです。
なので、今回の実装だけで使うイメージができないかも知れないですが:fearful:、
参考書やサイトに出てくる「コンテナ内で・・・・・」や「イメージを作成して・・・・」などでイライラする事が多少、減るかも知れないです。
今回の記事で、dockerに対するイライラが減るエンジニアが増えると、幸いです。

ではでは・・・・
ローカルにブランチを作らずにリモートブランチを確認する

# 概要
ローカルにブランチを作成せずにリモートブランチを確認するコマンド

## 用途
コードレビューや軽く動作確認したい時などブランチを作成するほどでもないけど、リモートブランチの内容を確認したいとき

## コマンド
```
git checkout origin/リモートブランチ名
例) git checkout origin/development
```

Gitのバージョンが2.23以降

```
git switch -d origin/リモートブランチ名
例) git switch -d  origin/development
```
PRML 8.18解答(標準)

<a id="eq:1.152"></a>
##はじめに
本記事は, 機械学習の教科書の決定版ともいえる, Christopher Bishop先生による『Pattern Recognition and Machine Learning （パターン認識と機械学習）』, 通称PRMLの演習問題のうち, 私が解いた問題の解答を記したものです

今回は演習問題8.18の解説です
<a id="eq:1.152"></a>

##問題
1.有向木によって表現される分布が、対応する無効木上の等価な分布によって表現されることを示せ

2.無向木で表現される分布が、クリープポテンシャルを適切に規格化することにより有向木で実現可能であることを示せ

3.ある与えられた無向木から構築できる異なる有向木の数を計算せよ

##解答1


一般的な有向グラフィカルの変数にわたる同時確率分布モデルは（8.5）で与えられます。

```math
p(\mathbf{x})=\prod_{k=1}^{K} p\left(x_{k} \mid \mathrm{pa}_{k}\right)
```

ツリーの特定のケースでは、各ノードには単一の親があり、Pakは、空となるルートノードを除いて、各ノードkのシングルトンになります。
したがって、有効木の同時確率分布は、無効木と同様になります。

##解答2

チェーン全体の確率分布において、有向グラフを表す8.44式

```math

p(\mathbf{x})=p\left(x_{1}\right) p\left(x_{2} \mid x_{1}\right) p\left(x_{3} \mid x_{2}\right) \cdots p\left(x_{N} \mid x_{N-1}\right)
```
同じ変数がいくつかの条件付き確率で条件付けバーの右側に発生する可能性があります。つまり条件には1つだけではなく、分布（つまり、各ノードは1人の親、複数の子を持つことができます）

よってこれは無向グラフの8.45式により置き換え可能です


```math
p(\mathbf{x})=\frac{1}{Z} \psi_{1,2}\left(x_{1}, x_{2}\right) \psi_{2,3}\left(x_{2}, x_{3}\right) \cdots \psi_{N-1, N}\left(x_{N-1}, x_{N}\right)
```

（8.44）は（8.45）として書き直され、確率分布にも適用できます。
つまり無向木で表現される分布が、有向木で実現可能であることが示されます


##解答3

以上の議論より、無向グラフでは、ノードをルートとして任意に選択します。ルートから始まり、外側に向かって進みます。
つまり無向ツリー内のノードのすべてのペア間に一意のパスがあるため、一度ルートノードを選択すると、結果の有向ツリーの残りが表示されます。
したがって、N個のノードを持つ無向ツリーから、N個の異なる有向ツリーを構築できます。





参考
[PRML公式解答(Solutions to Exercises Web-Edition)](https://www.microsoft.com/en-us/research/wp-content/uploads/2016/05/prml-web-sol-2009-09-08.pdf)
Djangoにstaticファイルだけを配置してWebサーバっぽく使う方法

# はじめに
Djangoでテスト用にちょっとしたhtmlファイルを置きたかったのだが、そのものずばりな単純なやり方だけを書いてる記事を見つけられず、すごく簡単なことをやりたかっただけなのにかなり時間を食ってしまった。
そのため最短手順をここに書き記しておこうと思う。


# 作成方法
とりあえずやり方だけ記載。解説は後程。

## 環境
以下の環境で確認。

|  |  |
|:-:|:-:|
| H/W  |  AWS EC2(t2.micro) |
|  OS | Ubuntu 20.04  |

以下、インスタンス起動直後のさらっぴんな状態から説明する。

```.sh
$ pwd
/home/ubuntu
```

## djangoインストール
まずはapt updateしたあとdjangoをインストールする。

```.sh
$ sudo apt update && sudo apt upgrade -y
$ sudo apt install -y python3-django
```

## プロジェクトの作成
「testprj」という名のプロジェクトを作成する。

```.sh
$ mkdir testprj
$ cd testprj
$ django-admin startproject testprj .
```

## staticファイルの置き場所設定(settings.py)
さっきの手順でプロジェクトに必要なファイル一式が作成されたのでstaticファイルの配置場所(つまりはLinux上のディレクトリ)をsettings.pyに追記する。ここでは「static_files」ディレクトリとした。

```.sh
$ cat <<EOF >> testprj/settings.py
> STATICFILES_DIRS = [
>     os.path.join(BASE_DIR, 'static_files'),
> ]
> EOF
```

BASE_DIRはプロジェクトのベースディレクトリ=/home/ubuntu/testprj/ なので、STATICFILES_FIRSは/home/ubuntu/testprj/static_files/ となる。

## htmlファイルの配置
先ほど作成したstatic_filesディレクトリに適当なhtmlファイルを作成する。

```.sh
$ mkdir static_files
$ echo "This is test html." > static_files/test.html
```

htmlと謳ってるが中身はタグもないただのテキストである。


## HTTPサーバ起動
ここまでで準備完了なのでサーバ起動して動作確認する。

```.sh
$ python3 manage.py runserver 127.0.0.1:8000
```

## HTTPアクセス
端末をもう一つ立ち上げ、curlで下記URLにアクセスしたらtest.hhtmlが取得できた。

```.sh
$ curl http://localhost:8000/static/test.html
This is test html.
```


# 解説
上記手順の中でsetting.pyに設定を追記したが、改めて中身を確認すると以下のようになっている。

```testproj/settings.py
STATIC_URL = '/static/'
STATICFILES_DIRS = [
    os.path.join(BASE_DIR, 'static_files'),
]
```

STATIC_URLはデフォルトで設定されているもので、今回追加したのはSTATICFILES_DIRSである。
os.path.join()は第一引数と第二引数のパスをつなぎ合わせる関数。
この設定の意味するところは、「STATICFILES_DIRSディレクトリにあるstaticファイルをSTATIC_URLで指定したパス以下で取得する」ということになる。
整理すると以下の関係ということだ。

|  |  |  |
|:-:|:-:|:-:|
| URL  | http://127.0.0.1:8000/<font color="red">static</font>/test.html  | 赤字が<font color="red">STATIC_URL</font> |
|  ディレクトリ | /home/ubuntu/testprj/<font color="blue">static_files</font>/test.html  | 青字が<font color="blue">STATICFILES_DIRS</font> |


# 参考
[Managing static files (e.g. images, JavaScript, CSS)](https://docs.djangoproject.com/en/3.1/howto/static-files/)
【アプリ開発】こども向けアプリのペアレンタルゲートの設置

個人開発で、こども向けアプリ内にAppStoreのレビュー画面に遷移する機能を追加しいた際に、ペアレンタルゲートの存在を初めて知り、色々苦労したため、残しておきます。

#経緯
私は、甥っ子のために計算練習と復習ができる計算アプリの開発をし、iOSアプリでリリースをしておりました。
軽微な修正を行っている中、せっかくならユーザにレビューをいただけるよう、AppStoreのレビュー画面に遷移する機能を構築しました。

#審査
却下。。
こども向けアプリ（リリースする際に設定）では、外部リンクへ遷移する際は、子供だけの判断で遷移できないよう、ペアレンタルゲートを設ける必要があると。

なにそれ？
Google先生に聞いてみると、Appleの公式でも普通に書いてありました。勉強不足。。

+ 子ども向けのAppを開発する 
https://developer.apple.com/jp/app-store/kids-apps/

#修正
初回リリース時も、子供向けアプリで広告は入れちゃダメとリジェクトされていたため、実は、今回のリリースでは子供向けのチェックを外していたのですが、もうダウンロードしている人は子供向けの認識になっているから、後で変えてもダメというやりとりもありました。。
できるだけ簡単にペアレンタルゲートを設置する方法を、調べ下記案にたどりつきました。

####遷移ボタンをワンタップではなく、長押しで遷移。

ボタン押下のアクションを、下記の通り、「onTap」から「onLongPress」に変更するだけなので、なんて楽なんだと思い、実装、審査へすぐ出しました。

```
 onTap: 
　　↓
 onLongPress:
```

#再審査
却下。。。。
なんで！？
確かに、「こんなのこどもでもできちゃうだろうから意味あるの？」とは思っていましたが、そういうアプリもあるらしいからいけるだろうと思ってたのに。
しかも、Appleからのメッセージに、埒が明かないから電話する！ときてました。（実際はこんな強くはきてないですよ。もちろん。）

まさか、「英語ペラペラの外国人から連絡くるの？」と思って、困っていたら、ある方に日本語しか喋れないとメッセージしておけば、日本語喋れる方から連絡くるから大丈夫よと言われたので、速攻 「I can only speak Japanese.」とメッセージしておきました。

#Appleからの電話
１回目仕事中で出れなかったので、着信があったのみた時には「カリフォルニア」から連絡が来てたので怯えていたのですが、留守電には日本人の声があったので一安心。
後日、再度電話が来て、丁寧にペアレントゲートについて、教えてくれました。

####ペアレンタルゲートを設定はしてくれたけど長押しは、簡単すぎるから他の方法で設定してね。

そうですよね。。

####年齢を入れてもらって、問題ない年齢だったら遷移するようなもので良いよ！

なるほど、それならできそう！
ということで、後日こんな感じで年齢入れるような仕組みに変えてみました。

![スクリーンショット 2020-12-23 23.51.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/944428/f9a12924-fec3-e163-b22d-a078d6f39820.png)

何歳からなのいいの？という疑問が湧くと思いますが、僕もそう思ったので、聞いてみました。
ただ、それは開発者さんの判断でと。
このため、僕は適当に18才以上ならレビューへいけるよう設定しておきました。

#再再審査
４度目の正直！！

###無事通過しました:relaxed:
手抜きをしすぎるなということを身に染みて感じました。

#まとめ
ペアレンタルゲートの設置で簡単な方法は、年齢入力するような機能を追加し、対象年齢以上であれば外部リンクへ遷移できるようにするだと思います。
もし、皆さんもこのようなことに遭遇し、簡単に作成したいなと思ったら試してみてください。

僕は、これを受けて、子ども向けアプリをまだ作れるかもと思いました。
VSCODEのVIM操作のインサート(挿入)モードの中でカーソル移動する際の設定(コピペ可)

vscodeのvim操作におけるインサートモード時にカーソル移動をしたかったので記載。



```setting.json
"vim.insertModeKeyBindings": [
      {
        "before": ["<C-p>"],
        "after": ["<Up>"]
      },
      {
        "before": ["<C-n>"],
        "after": ["<Down>" ]
      },
      {
        "before": ["<C-b>"],
        "after":  ["<Left>"]
      },{
        "before": ["<C-f>"],
        "after":  ["<Right>"]
      },
    ] 
```
とある会社に転職したエンジニアが、訳わからんDBを理解しようとして作ったツール

# あらすじ
とある会社に転職した、ぺちぱーのぺーさんは、まず最初に担当するWebアプリケーションについて
ざっくりとした説明の後、ドキュメントを教えてもらいました。
しかし、いざドキュメントを見てみると開発環境の作り方しか書いていなく、
しかも陳腐化しているため信憑性が微妙なものでした。
「さて困ったぞ」
しかし、エンジニアなので、なんとかしようとするもの。
何とかしようとしたぺーさんの最初に作ったツールのお話です。
※この話は数年前にあった実話を元にしたフィクションです。

#最初の仕事で壁に当たる
研修を終え、会社のビジネスを知ったぺーさんは、まず簡単な機能開発をする事になりました。
内容は都道府県別のリストで出しているものをグルーピングして表示すると言った内容です。
(この←の部分です）
![first_job.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224753/4b099d4f-2ca9-f3a8-9da3-7c16020e69a5.png)

こんなのすぐできる、そう思った数分が僕にもありました。
意外な所で時間がかかってしまうのです。

## このデータはどう作成しているのだろう
こういう時、view側でDOMの個数を計算するなんて事はあまりしないと思います。
まあ普通に考えてこの表示になるようにするのはviewにfetchしている変数があるはずなので
その変数を作成する時に一緒に変数を作っちゃえって思いました。
なのでController側を見てデータを抜き出している所までざーっと追ってみました。
しかし、ここでなんとかのパラドックスに出会います。

## 謎のwhere句に翻弄される
データを取得しているのは、hoge_containersというテーブルと言うのがわかったので、そのクエリを参照します。

```sql
SELECT id, name FROM hoge_blocks WHERE pref IN ('愛媛県', '香川県', '徳島県', '高知県') AND hoge_block_type_id = 1 AND deleted IS NULL;
```

なるほど、``hoge_blocks``を見ればいいのか。
よしよし、databaseを見てみよう。うん。こうとってきているので、戻り値に``pref``をつけてあげて、それでグルーピングしてあげればいいね。
ところでこの``hoge_block_type_id=1``ってなんだろう？？
まあとりあえず``hoge_block_types``ってテーブルを見ればわかるか。見てみよう！

```bash
mysql> select * from hoge_block_types;
ERROR 1146 (42S02): Table 'm9(^Д^).hoge_block_types' doesn't exist
```
ない・・・？どういう事だろう・・・？idだよな・・・？

## 常識が通用しないパターンに出会う
結局、この後ソースコードに記載を見つけるのですが、結局こう言う話でした。

```php
const JAPAN_HOGE_BLOCK_TYPE   = 1; // 日本のhoge block type
const ANOTHER_HOGE_BLOCK_TYPE = 2; // 日本以外のhoge block type
```
なるほど・・・。ソースコードにしかないのか・・・。

# DBの中身を調べなきゃ。
結局この後も似たようなケースで、どこにどんなデータが入っているのかよくわからない状態が続きます。
これはあかん。無理や。テーブルの構造が想定外のものが多い。
なぜなら、この時1つのdatabaseに200以上のテーブルがあり、何がどのように関わっているのかわからないからです。

DBの中を見るツールはいっぱいあっても、どこに設定されているかって案外わかんないですよね。
(ER図あれば楽なんですけどねー。)

## CREATE文検索ツールを作ったら
CREATE文出してくれる便利なアプリないかなーってドラクエ3で言う所の、とうぞくのカギを手に入れるくらいの時間探したけど見つからない・・・。
桃鉄で言う所の最初の急行カードを使うくらいの時間悩み、作る事を決意。
適当なCSSと適当なDB接続を使い、パパッとDB検索ツールを作成しました。
![スクリーンショット 2020-12-24 0.21.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224753/1b6285c9-b147-c4d8-34a5-6f575a958ff2.png)
こんな感じ。で、ここに検索したい文字入れると、
![スクリーンショット 2020-12-24 0.27.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224753/7b065ddd-55d1-7e0f-2630-287b52fa461e.png)
こんな感じにこの単語に引っかかるテーブルを教えてくれる。
![スクリーンショット 2020-12-24 0.28.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/224753/28276bf2-6c43-86b7-b0e7-58729430f19c.png)
一応びよーんって伸びてCreate文を教えてくれます。。

お粗末なローカルでしか動かないWEBアプリケーションですが、
これを作って少しだけ楽になりました。

# その後
訳わからんDBを理解する事は未だに出来てはいませんが、こうやって少し調べながらなんとかやっています。
こういうツール作ると捗るものもありますよね。
ただ、もう使ってないや。
Windows上のファイルをLinuxコマンドで整理する　- WSLを用いて -

##当記事の目的
　・「Linuxコマンドを試したいが、仮想環境の構築までは面倒だと考えている」方
　・「勉強のために練習ディレクトリを作成するのではなく、実際に生きたファイルを使いたい」方
　・「とりあえずWindows上のファイルを効率的に整理したい方」

　上記の方々に**WSL**を用いて、
　**Windows上のファイルをLinuxコマンドを用いて操作(整理)が出来るようになる事**が目的です。

　※環境構築は簡単で、**30分前後**でWindows上でLinuxコマンドが実行出来るようになります！

#####WSLとは
　・「Windows Subsystem for Linux」の略です。
　・Windows OS上でLinuxの実行環境を実現するサブシステムです。

##WSLを用いたLinux環境の構築方法
　今回は「Windows10」ユーザ向けに箇条書きで記載していきます。

　1. WSLの有効化
　　WSLを利用するには、WSL機能を有効化する必要があります。
　 「スタート」→「設定」の順で移動し、「Windows の機能の有効化または無効化」タブを開く。
　　下記のように、「Linux 用 Windows サブシステム」をチェックし、PCを再起動をします。
　　![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402537/7f19c537-8a6f-6943-680b-818c09a3e434.png)


　2. Ubuntuのインストール
　　WSLを利用するには、Linuxディストリビューションが必要です。
　　下記のように、「Microsoft Store」でUbuntuと検索し、一番上に出てくる「Ubuntu」を
　　インストールします。
　  ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402537/2dddc6c2-ebbb-5b3f-6e95-5be65f68070a.png)
　　インストール完了したら、スタートメニューから「Ubuntu」を検索して起動をします。
　　![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/402537/2088b188-a560-f9c7-1196-02d4c26e932c.png)

　3. WSLとWindows間のファイル連携方法
　　下記の方法で、WSLとWindowsのそれぞれのファイルを参照出来ます。

```ruby:WSLからWindowsファイルシステムへのアクセス（Ubuntuで入力）
'cd /mnt/{ドライブ名}'
```

```ruby:WindowsからWSLファイルシステムへのアクセス（エクスプローラで入力）
'\\wsl$'
```
 
##最後に

Linux環境の構築には、主に以下の2つの方法があり、それぞれにメリット・デメリットがあります。
それらを認識したうえで、Linuxコマンドの学習とファイルの整理を効率的に行っていきましょう！

`WSL`
　メリット　：ホストのファイルを直接参照するので、セキュリティ面に不安が残る。
　デメリット：別のOSはインストールしないので、手軽にLinuxのCUI環境を利用できる。
`仮想化`
　メリット　：別のOSをインストールするので、ホストに影響を与えない分離した環境の構築。
　デメリット：マシンのリソースを利用するので、パフォーマンスがスペック依存になる。
【UiPath】Advent of UiPath 2020 #5（2つのエクセルを比較、重複行マージ）

この記事は、UiPath Forum で行われている [**Advent of UiPath 2020**](https://forum.uipath.com/t/advent-of-uipath-2020/273299) の [Advent Challenge #5](https://forum.uipath.com/t/advent-challenge-5/276298/27) の紹介記事です。

:christmas_tree: 過去の投稿

- [Advent of UiPath 2020 #1（APIからデータを取得）](https://qiita.com/miya_g/items/4021ba90aab84984cb3c)
- [Advent of UiPath 2020 #2（正規表現で文字列を抽出）](https://qiita.com/miya_g/items/087a9d5d29145ae3e33e)
- [Advent of UiPath 2020 #3（ファイルをダウンロードしてメール送信）](https://qiita.com/miya_g/items/b774ef61150330ba0ee0)
- [Advent of UiPath 2020 #4（画像をbase64デコードしてOCRで画像認識）](https://qiita.com/miya_g/items/489e81d876ba504986f2)

# “Advent of UiPath 2020” とは何か？

- 英語版のフォーラムで投稿されています。
- RPA challenge です（＝お題を出て、みんなでRPA化してみる）
- 誰でも回答できます（フォーラムのアカウントがあれば）
- 3日おきに出題され、計8回（xmasイブまで）あります
- 回答して上位に選ばれれば、フォーラム上でスターがもらえます。
- フォーラムのスタッフが開催しているっぽいです。

# チャレンジ5：2つのエクセルをマージ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154139/b3b1d39a-5809-8aa2-4d1e-2c3282720607.png)

サンタのアシスタント「ジングルベル」は、バージョン管理について聞いたことがないため、ひどい間違いを犯しました。サンタは願い事をした子供の名前をExcelシートに保存していましたが、ジングルベルが突然新しいバージョンを作成し始め、内容がわからなくなってしましました。
Santa Inc.には、同じ子供に2回配達するためのリソースがなく、サンタもプロとして「同じ人に2回配達する」のは到底できません。

### 初心者用チャレンジ
サンタはあなたがUipathのエキスパートだとは思っていません。両方のファイルの作成日を読み取り、最後に作成されたファイルを削除するワークフローを作成してください。

### 上級者向けチャレンジ
添付された2つのExcelシートを比較するUiPathワークフローを作成し、名前の重複を削除した一意の名前のファイルを作成してください

# 感想

今回は「ファイルの比較」というお題でした。
実際の業務でも良くあります。

初心者向けは、

・ファイルの一覧を取得 -> ループしながらファイルの情報を取得し、最も古いファイルを特定する

上級者向けは

・ファイルをデータテーブルに読み込み -> 比較し重複行を削除

という対応です。「データテーブルをマージ」アクティビティと「重複行の削除」アクティビティを使えば簡単です。

面白い回答は

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154139/3aa36b73-adef-deda-11f7-86b20251484a.png)
フォームアクティビティで見栄え良く見せる

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154139/d7a0a0ca-21a8-341a-3a70-a4b4a5d6d038.png)
やっぱり「ザ・ロック」が登場（好きな人がいるんだな）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154139/0c557c07-e259-65dc-f297-0d6205382855.png)
やっぱりダッシュボードに表示したいらしい。

でした。

ちなみに重複を削除した「サンタへのお願い」リストは

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154139/83d42820-3cfe-a9d2-cbcd-fc13ed206910.png)

みたいです。ゲーマーマウス欲しいですね。
rails heroku エラー録

久しぶりにHerokuにpushしようとしたらエラーが、、

```
...
remote: -----> Preparing app for Rails asset pipeline
remote:        Running: rake assets:precompile
remote:        rake aborted!
remote:        ActiveSupport::MessageEncryptor::InvalidMessage: ActiveSupport::MessageEncryptor::InvalidMessage
...
remote:        
remote:        Caused by:
remote:        OpenSSL::Cipher::CipherError: 

```

`ActiveSupport::MessageEncryptor::InvalidMessage`
これはrailsのmaster.keyが原因のエラーぽい

Herokuに登録しなければいけないぽいので

```
heroku config:set RAILS_MASTER_KEY=`cat config/master.key`
Setting RAILS_MASTER_KEY and restarting ⬢ tunagu-natto... done, v475
RAILS_MASTER_KEY: 72ddbs9f8c905e836e4e8dbf72a8b
```
FactoryBotで外部キーの値はどうやって作り出すんだ〜（泣

#はじめに
　先日投稿した、テストコードに関するエラーで少し進展したので、記録しておきます。

先日の投稿↓
「[RSpecを使ってテストコードを書いているが、うまくいきません](https://qiita.com/TerToEer_sho/items/8967b4cd04737602b0e9)」

##検証結果
仮説２はおそらく関係がないことがわかりました。
ヘルパーメソッドを
`number_field`から`text_field`に変えても、課題の解決には繋がりませんでした。依然として、うまく保存ができないため、仮説１の外部キーに関わる部分でエラーが発生していると考えられます。
モデルで外部キーであることをバリデーションしていることで、単にIDを入力するだけでは、主キーを見つけられないことが原因だと考えられます。

##最後に
　引き続きテストコードがうまくいくように検証を続けて行きます。
[devise] ストロングパラメーター

# 前提
・deviseを導入
・ユーザー新規登録機能の実装が目的

# devise基礎知識
新規登録時に入力する情報はパラメーターとしてサーバーに送信されます。
不適切な情報の侵入を防ぐため
Controllerにストロングパラメーターを設定する必要がありますが、
deviseControllerはGem内に記述されているため、`編集することができません。`

よってapplication_controller.rbにストロングパラメーターを設定し、
deviseControllerのみに適用させます。

# :devise_controller?
:devise_controller?は`deviseのヘルパーメソッドです。`
もしdeviseに関するControllerの処理であれば、そのときだけconfigure_permitted_parametersメソッドを実行するように設定しています。

before_actionのifオプションを使用して
値にメソッド名を指定することで、その戻り値がtrueであったときにのみ処理を実行するよう設定します。

```application_controller.rb
class ApplicationController < ActionController::Base
  before_action :configure_permitted_parameters, if: :devise_controller?

end
```

# devise_parameter_sanitizer
devise_parameter_sanitizerメソッドは、`deviseにおけるparamsのようなメソッドです。`
deviseのUserモデルに関わる「ログイン」「新規登録」などのリクエストからパラメーターを取得できます。

普通のストロングパラメーターと同じく、新たに定義するPrivateメソッドの中で使用します。

```application_controller.rb
private
def configure_permitted_parameters  # メソッド名は慣習
  # deviseのUserモデルにパラメーターを許可
  devise_parameter_sanitizer.permit(:deviseの処理名, keys: [:許可するキー])
end
```
|処理名	         | 用途
|----------------|-------------------------------
|:sign_in	 | サインイン（ログイン）の処理を行うとき
|:sign_up	 | サインアップ（新規登録）の処理を行うとき
|:account_update | アカウント情報更新の処理を行うとき

例えば下記のようにすると
ニックネームの値が保存可能になります。

```application_controller.rb
private
def configure_permitted_parameters
  devise_parameter_sanitizer.permit(:sign_up, keys: [:nickname])
end
```
---
因みにこれは「deviseに定義されているpermitメソッド」であり、Railsではじめから使用できたpermitメソッドとは異なります。

```_controller.rb
# paramsのpermitメソッド
params.require(:モデル名).permit(:許可するキー)

# devise_parameter_sanitizerのpermitメソッド
devise_parameter_sanitizer.permit(:deviseの処理名, keys: [:許可するキー])
```
[Python] 区間スケジューリング　ABC103D

#[ABC103D](https://atcoder.jp/contests/abc103/tasks/abc103_d)
下図のようにすべて串刺しにするには、最小何本必要か、という問題である。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/568274/a0c53ee8-da62-5930-bfc4-85097bff1ca1.png)
区間スケジューリング問題とは以下のような問題である:

>M 個の区間が与えられ、どの 2 つの区間も時間帯を共有しないように最大個数の区間を選べ

蟻本の Greedy の章の最初にも載っている有名問題で、区間の終端でソートして Greedy にとっていけばよい。

実は今回の問題の答えは、区間スケジューリング問題の最適解と同じになる:

* まず区間スケジューリング問題の答えが k 個だった場合、その k 個は時間帯を共有しないので、それらを全部刺すには最低でも k 本の串が必要である (**弱双対性**)

逆に k 本の串があれば十分であることは、区間スケジューリング問題に対する貪欲法の動きを注意深く追うと理解することができる。具体的には、

* 区間スケジューリング問題で選ぶ k 個の区間に対して、その右端から串を刺していけば、ちょうど k 本の串ですべての区間を串刺しにできる (**強双対性**)

```python:サンプルコード
from operator import itemgetter

n, m = map(int, input().split())

# 区間の終端でソート
ab = sorted([tuple(map(int, input().split())) for i in range(m)], key=itemgetter(1))
# 前回除いた橋
removed = -1
ans = 0

for a, b in ab:
    # a が removed より大きい = まだ取り除いてない
    if a > removed:
        removed = b - 1
        ans += 1

print(ans)
```
[Ruby on Rails] kaminariの使い方

#kaminariとは？
rubyのgemの一つで、ページネーションを作るためのものです。

#kaminariのインストール

以下を `Gemfile` に追加します。

```
gem 'kaminari'
```

ターミナルでインストールします。

```
$ bundle install
```
#コントローラーにページネーションのコードを追加

```

class PostsController < ApplicationController

def index
  @posts = Post.all
  @posts = Post.page(params[:page]).per(15)
end

end
```

`page(params[:page]).per(15)` の部分でページあたりいくつ表示させるかを設定します。
ページネーションが表示されるのは、表示される数が設定した数より多い場合です。

#ビューファイルにページネーションのコードを追加
ビューでページネーションを表示させる場所に追加します。


```
    <%= paginate @posts %>
```

#kaminariを日本語化する
kaminariの表示はデフォルトだと英語です。
日本語化する場合は、 `config/locales` に `kaminari_ja.yml` というファイルを作成すると管理しやすいです。
`kaminari_ja.yml` に以下を追記します。

```
ja:
  views:
    pagination:
      first: "&laquo; 最初"
      last: "最後 &raquo;"
      previous: "&lsaquo; 前"
      next: "次 &rsaquo;"
      truncate: "..."
  helpers:
    page_entries_info:
      one_page:
        display_entries:
          zero: ""
          one: "<strong>1-1</strong>/1件中"
          other: "<strong>1-%{count}</strong>/%{count}件中"
      more_pages:
        display_entries: "<strong>%{first}-%{last}</strong>/%{total}件中"
```
Proxy経由でゲームがしたいとき

この記事はProxyとの戦いに勝利した[Proxyを華麗にスルーしてWi-Fiを飛ばすには - Qiita](https://qiita.com/yangniao23/items/be9eaf95ed87b1084bac)の後日談です。
環境などは上の記事に準じておりますので，是非ご一読の上こちらの記事をお読みください。

## Proxy経由だとなぜゲームができない？
ゲームではウェルノウンポート以外のポートを多用するためです。
つまり，ゲーム側がウェルノウンポート以外でTLS通信をしている場合は，Squid側で設定してあげることで正常に通信ができるようになります。

## 具体的にどう設定したの(追加するポートを4432番とします)。
```conf:/etc/squid/squid.conf
- acl SSL_ports port 443
+ acl SSL_ports port 443 4432

+ acl Safe_ports port 4432
```

SSL_portsとSafe_portsに追加したいポートを加えるだけです。

## 参考文献
443以外のSSLポートを使用するプロキシサーバ（Squid）の設定 : https://minory.org/proxy-squid-403-error.html
【初心者でもわかる】CSSで立体文字を再現する方法

# どうも7noteです。CSSで3Dの文字を再現するには。

基本的にwebサイトは平面ですが、立体感のある表現をしたい時にちょっと無理やりですが文字を立体にさせることができます。

**見本**
![sample.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/661092/1e54c3c0-921f-7d6f-0929-9e5578acfe83.png)


## 立体文字の書き方

```index.html
<div class="text">777</div>
```

```style.css
.text {
  font-size: 30px;    /* 文字サイズを30pxにする */
  font-weight: bold;  /* 太文字にする */
  text-shadow: 1px 1px 0 #666,2px 2px 0 #666,3px 3px 0 #666;  /* 影を3重に指定 */
}
```

正確には立体ではなく、あくまでも立体に見せかけているだけですが、パッと見はそれほど気にならないと思います。
影を3重にして、左上に伸びているような立体感を再現しています。

背景色を使うとこんなかんじの立体感も再現することができます。

![sample2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/661092/3945d189-cead-86c7-a53b-e4e08e060804.png)


```style.css
.text {
  color: #99f;
  font-size: 30px;
  font-weight: bold;
  text-shadow: 1px 1px 0 #fff,2px 2px 0 #fff,-1px -1px 0 #fff;
  background: #99f;
  padding: 5px;
}
```

## まとめ

グラデーションをつけたり、さらに立体化を求めるなら画像にするしか今は方法がないかもしれませんね。

#### おそまつ！
~ Qiitaで毎日投稿中!! ~
[【初心者向け】WEB制作のちょいテク詰め合わせ](https://qiita.com/7note)
Selenium と Headless Chrome を Heroku で動かしてみたらハマった

この記事は [YAMAP エンジニア Advent Calendar 2020](https://qiita.com/advent-calendar/2020/yamap-engginers) の 23日目の記事となります。

# ダイジェスト

Selenium をサーバで定期実行しようと思ったら、日本語化や長時間処理などでハマったので晒します。
興味のある方は続きをお読みいただければと思います。

※実施したときからかなりの時間が経過しており、記憶があいまいな部分は記載を省略しております。予めご了承ください。

# 動機

ヤボ用で、とあるWebページを定期的にスクレイピングしてゴニョゴニョしたいなと思い立ちまして、Selenium でサクッとやってサーバで定期実行したら良いだろうと軽い気持ちでやってみました。


# まずはローカルで動かしてみる

今回はサンプルなので Yahoo! JAPAN のトップニュース見出しを取得してみます。
本来はあれしたり、これしたりと色々なことをやっています。


![スクリーンショット 2020-12-23 22.38.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/100097/c7fe0f85-faee-ff0d-64a9-86e379aa02ff.png)


試しに赤丸部分を取得します

```
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

options = Options()
options.add_argument("--disable-extensions")
options.add_argument("--disable-dev-shm-usage")

driver = webdriver.Chrome(executable_path="./chromedriver", options=options)
driver.get("https://www.yahoo.co.jp/")
news = driver.find_element_by_xpath("//*[@id=\"tabpanelTopics1\"]/div/div[1]/ul/li[1]/article/a/div/div/h1/span").text
print(news)
driver.close()
```

```
> python3 sample.py
イベント 上限再び5千人に
```
取得できました。

# Heroku上で実行する

詳しい説明は割愛しますが、ポイントは Selenium のオプション設定で headless を指定して executable_path を変更します。

```
options = Options()
options.add_argument("--disable-gpu")
options.add_argument("--disable-extensions")
options.add_argument("--disable-dev-shm-usage")  
options.add_argument("--headless")

driver = webdriver.Chrome(executable_path="/app/.chromedriver/bin/chromedriver", options=options)
```

# ハマリポイント1: スクショ取ってみたら日本語が文字化け

つい出来心で、スクリーンショットを取って外部ストレージに保存したりすると便利なんじゃないかと思ってやってみました。
すると、あろうことか日本語が文字化けしてしまいます。。
Heroku で動かす場合は .fonts フォルダに日本語フォントの tts ファイルを置いておかないといけないようです。
今回はIPAフォントを置いたら正常に表示されました。

# ハマりポイント2: Webアプリケーションが30秒でタイムアウトしてしまう

Selenium でいろんなページを処理するようにしていたらタイムアウトエラーになってしまいました。
どうやら heroku は 30 秒を超えるとタイムアウトエラーになり、30秒という設定は変更できないようです。(基本的なことらしいですが知りませんでした。)

バックグラウンド処理での実装を検討して、 Heroku Redis と RQ で何とか実装できました。
こちらを参考にしました。
https://python-rq.org/patterns/

# 最後に
ここまで Heroku の無料の範囲内で実装できました。いろいろとハマりましたが、何とかやりたいことを実現できました。
また、自動で Selenium の定期実行ができるようになり、スクリーンショットの外部ストレージ保存もできたので、次は自作Webアプリケーションの定期テストを自動化してみようと思います
Google Spread Sheetで日本の祝日情報を取得する方法

業務上で必要となったので、Googleスプレッドシートで日本の祝日情報を取得する方法をGoogle Apps Scriptで作ってみました。

# スクリプトの内容

1. メニューに「祝日情報取得」という名称のメニューボタンを追加し、祝日情報取得関数(getHolidayData)を実行できるようにする。
2. 祝日情報取得関数(getHolidayData)が呼び出されると、内閣府が用意している祝日CSVを取得し、シートに書き込む。(URL: https://www8.cao.go.jp/chosei/shukujitsu/syukujitsu.csv)

# スクリプト

```js
function onOpen() {
  // メニュー追加
  SpreadsheetApp
    .getActiveSpreadsheet()
    .addMenu('祝日情報取得',[
      {name: '情報取得', functionName: 'getHolidayData'}
    ]);
}

function getHolidayData() {
  var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = spreadsheet.getSheetByName('祝日一覧');

  // 祝日一覧のシートのF3セルに内閣府祝日データCSVのURLを記載してあります。
  var url = sheet.getRange('F3').getValue().toString();
  var charset = 'Shift_JIS';
  var response = UrlFetchApp.fetch(url);
  var holidayCSV = response.getContentText(charset);

  var ary = Utilities.parseCsv(holidayCSV);
  sheet.getRange(1,1,ary.length,ary[0].length).setValues(ary);

}

```

* ※スクリプトを登録した際は、onOpen()を実行して、権限を許可しておいてください。

* スクリプト参考記事
    * CSVの読み込みは次の記事を参考にしました。
        * [スプレッドシート:csvファイル読み込み](https://maki1.hatenablog.com/entry/2019/09/12/214820)
    * メニュー追加機能は次の記事を参考にしました。
        * [スプレッドシートにカスタムメニューを追加して、拡張機能を実装する方法](https://qiita.com/tanabee/items/dea49d7ab2df17a05b07)

# 動作

* メニューにある「祝日情報取得」を実行します。(権限を求められたときは許可して、再度実行してください。)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108558/3d84c63e-d1ef-8952-7a22-0ba8a7dc77df.png)

* 実行すると、下の様にA:Bセルにデータが挿入されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108558/e162fec8-96c1-eb0c-3370-559bf089609b.png)


# ちなみに

他にも方法はあります。 Googleカレンダーの祝日カレンダーから取得する方法があります。
(多分正攻法はこっちな気がします…)

* 参考記事
    * [GoogleAppsScriptで日本の祝日をスプレッドシートに出力する方法](https://qiita.com/cazimayaa/items/28b2dd351712ea807d6f)
    * [google spread sheetに自動更新される日本の祝日シートを作る](https://qiita.com/ik-fib/items/6c35640954c2b04a9287)
ドローンシュミレーター

ドローンを体験したい、練習する場所がない、実機の購入は・・・
などなど様々な悩みが発生するドローン環境

そこで、今回紹介するのは、ドローンシュミレータ「Veloc Droen」です

（利点）
　・初期投資最小限（パソコンがあれば）
　・実機ドローンと差が少ない為、実機ドローンに移行しやすい
　・ゲーム感覚で練習できる
　・ドローンセットアップが学べる
　・オリジナルコースが作れる
　・オンライン訓練ができる
　・何より安全！！
　
（必要な物）
　・パソコン
　・ネット環境
　・Veloc Droen
　・USBゲームコントローラー（理想は実機プロポが良い）
　　※プロポ使用の場合、専用のUSBケーブルが必要になります


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542485/bf96fa49-10c6-302d-86a2-9ed994d292f1.png)

推奨されているPCスペックです
因みに私が使用してるPCスペックは　Win１０  CORE I3　２.５GHz　RAM１６GB　拡張グラフィックボードなし
レース思考でない限り十分に動きます

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542485/acf2858e-a68b-442b-536b-ff5b1c4aebc4.png)

【シュミレーター導入の流れ】

（動作確認）
　・Veloc Droenシミュレータ体験版ダウンロードします
　・お持ちのpcで起動する事を確認します　多少スペックが悪くても動作します
　・USBコントローラー（アナログスティック付き）をパソコンに接続し動作する事を確認します

（セットアップ）
　・シュミレーターを起動し、USBコントローラーのチャンネル設定をします
　・使用するドローン機体を選択します　体験版は固定だった気がします
　・選択したドローン機体の飛行パラメーター設定をします

（テスト飛行）
　・飛行するマップを選びます
　・選択後、スタートすると飛行開始です

　　【確認ポイント】
　　　・飛行中画面の動きがカクカクする？
　　　・操作と動作のタイムラグはあるか？
　　　・画面更新が遅い？
　　　・表示されない部分がある？

　　　上記の現象を感じた場合、パソコンスペック問題により厳しいかもしれません
　　　動作に問題を感じなかった場合、正式版を購入しましょう！！