OmniAICreator/Qiita-1.07M huggingface dataset:
最新の超解像モデルReal ESRGANをiOSでつかう

#最新の超解像機械学習モデルがiOSでつかえる
320*320
<img src="https://user-images.githubusercontent.com/23278992/147282886-60da9a52-5bb1-47f1-a77b-99546bd25fc8.png">
↓
超解像
↓
<img src="https://user-images.githubusercontent.com/23278992/147282923-24fdf622-a147-450b-b6f4-9fce5dd74376.JPG">
1280*1280

小さなサイズの画像を鮮明に、大きなサイズにしてくれる超解像モデル。
2021年発表のReal ESRGANもiOSで使える。

#機械学習モデルを扱うのは難しそう？

とはいえ、最新の機械学習モデルをつかうのはたくさん手順が必要なんじゃないの？

#変換済みのCoreML Modelをつかえばかんたん

Real ESRGANも変換済みのものがあります。これをつかえばすぐにiOSで超解像ができます。

#かんたん手順

[**CoreML-Models**](https://github.com/john-rocky/CoreML-Models)からReal-ESRGANのCoreMLモデルをダウンロードします。
プロジェクトにドラッグします。
Visionで実行します。

```swift
guard let model = try? VNCoreMLModel(for: real_esrgan(configuration: MLModelConfiguration()).model) else {fatalError("model initialization failed")}
let coreMLRequest = VNCoreMLRequest(model: model)
let handler = VNImageRequestHandler(cvPixelBuffer: pixelBuffer, options: [:])
try? handler.perform([coreMLRequest])
guard let result:CVPixelBuffer = coreMLRequest.results?.first as? VNPixelBufferObservation else { return }
```
これで1280*1280のサイズに超解像された画像が取得できます。

超解像をプレビューするだけなら、ダウンロードしたmlmodelファイルを開いてお手持ちの画像をドロップすると、
プレビューができます。
<img src="https://user-images.githubusercontent.com/23278992/147302588-5ca80d4b-0b19-4b56-a479-0000e0385a48.png">


🐣
****
フリーランスエンジニアです。
お仕事のご相談こちらまで
簡単な開発内容をお書き添えの上、お気軽にご連絡ください。
rockyshikoku@gmail.com

Core MLやARKitを使ったアプリを作っています。
機械学習／AR関連の情報を発信しています。

[Twitter](https://twitter.com/JackdeS11)
[Medium](https://medium.com/@rockyshikoku)
[JavaScript] firestore の loadBundle() を使用したページをiOSのブラウザで開くとloadBundleが結果を返さない

ので

```javascript
await loadBundle(fetchedBundle);
```

とやっていると、結果が返ってこないのでそこで処理が止まります

普通はloadBundleでindexedDBにデータを突っ込んだあとに
そのデータからget()してくるので、データが取得できないまま画面はロード中になり続けます

ブラウザの進む、戻るをやるとなぜか表示されたりします
indexedDBにはデータが入っているけど完了を返さないのだろうか？

サンプル数もテスト環境も少なくて自分のコードに問題がある可能性も高いのですが、
iOSのwebkit環境(Safari, WKWebView)でだけ発現しています
Windowsではどのブラウザでも問題ありません


もしかしたらfirestoreではなく、WebKitにおけるindexedDBのバグかもしれません

https://qiita.com/nao_h/items/17cc1c858a12be9152ff



もし解決できたら教えていただけると助かります
パーソナルコーチングが楽しい

この記事は [ゆめみ Advent Calendar 2021](https://qiita.com/advent-calendar/2021/yumemi) の25日目の記事です。

# はじめに
今年の11月からゆめみでパーソナルコーチングを受け始めました。

ゆめみでは、パートナーもメンバーと区別なく、コーチングを受けることができる取り組みを行なっています。

コーチングの存在を知ったのはゆめみに関わるようになってからですが、実態としては直前まであまりよくわかっていませんでした。漠然と、コーチの字面から何かを指導するという先入観がありましたが、そうではなく、**伴走する**という言葉の方がしっくりきます。今現在、パーソナルコーチングの時間が楽しいので、その紹介記事です。

ゆめみでコーチングを受けた別の人の記事も合わせて読んでもらうとコーチングとは何なのか、よりわかりやすいと思います。

https://note.com/ddden/n/n6b52118bd22e

# やったこと
- コーチングで扱うテーマを決める
- 価値観を探る
- 振り返りを行う
- 夫婦喧嘩を扱う

## コーチングで扱うテーマを決める
はじめにお伝えした通り、コーチは何かを教えてくれたり、決めてくれるわけではなく、その場に一緒にいて、誘導するでもなく、伴走してくれる存在でした。

パーソナルコーチングは3ヶ月を目安として、2週間ごとに1時間のセッションとして進めていきます。
まずは全体通して扱うテーマを決めようということになりました。セッションごとに変わっても良いので、今この時点で気になっていることを挙げてみましょうとなりました。
直近では、家庭と仕事のバランスで悩んでいたのでそのことを扱うことにしました。

極端な考えとして、
家庭を大事に思うなら、仕事をしない方が良いとさえ思ったりもしました。
意味のない前提として、何かしらの偶然により収入の心配がないのが条件ですが。
ただ、仮にそれを前提として仕事をしない状態が自分にとって望む状態かというと、今の時点ではそうではないと気付かされました。仕事が大事かというよりは、育児に専念することは自分にとって簡単ではないと感じています。
1年半ほど前の緊急事態宣言の頃の記録ですが、同じような気持ちになってしまいそうです。

https://note.com/ykawashi7/n/n9f53a68fe522

さて、こういった気づきが得られたのは、コーチとの対話の中で、自分の中から湧いてくるものをコーチと一緒に拾っていく、一人だと取りこぼしてしまったり、深堀りできないところを、フォローしてくれる存在があるからなのだと思います。

この回では、扱うテーマを決めたという結論そのものよりも、そこに辿り着くまでのプロセスが楽しいと感じました。

## 価値観を探る
家庭と仕事のバランスを考える上で、自分が何を大事にしているのか、改めて問い直す意味と、
パーソナルコーチングでは、相性が大事で、合う合わないがあって、それを探る一環として価値観を探るゲームをしました。

https://wevox.io/valuescard

その時の自分の結果は次のようになりました。確か 60 くらいある価値観の中でこの 5つが残りました。

<img alt="kawashima-valuecard.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/31787/01a263c1-025d-80ac-eaaf-ef68ff501181.png" width="200">

遊び心を持って、発見し、思考しては挑戦し、変化していく。ここで残した変化には、次に引用されるような想いが強いです。

> この世に生き残る生き物は、最も力の強いものか。そうではない。最も頭のいいものか。そうでもない。それは、変化に対応できる生き物だ

業界柄、変化していくことが常であり、生存のための必須条件と強く意識しています。

## 振り返りを行う
この時は、自分は貢献できているのか、成長できているのか、悩んでいるという話をしました。

成長を感じるのはどんな時かという質問に対して、「振り返って、あの時成長していた、と思い至るような感覚がある」と搾り出しました。

最近までずっと振り返る習慣がなくなっていたとも話し、振り返りを行うことを決めました。
ゆめみでは習慣化を大事にしていて、習慣化の Slack チャネルもあり、そこに参加することになりました。そこでコーチが使っていたジャーナルアプリを見て、真似して使い始めたところ、自分にも相性がよく、言語化が捗るようになりました。

https://muute.jp/

このアプリの詳しい紹介はもう少し使った後に別の機会としてレビューできればと思います。

:::note info
2022年2月1日 レビュー記事へのリンクを追記しました
:::

https://zenn.dev/ykws/articles/better-journal

## 夫婦喧嘩を扱う
コーチングセッションの前に夫婦喧嘩をしていて、そういうことを扱っても良いのか相談したところ、もちろんという回答を頂きました。

ここで得た気づきは、夫婦喧嘩を勝ち負けと捉えていて、勝ちたくもないし、そうかと言って負けたくもないし、どちらも選びたくなくて、相手の言うことも素直に聞けないし、自分の思っていることも言えない状況でした。勝ちとか負けとかではなく、相手の言うことを一旦そのまま受け止める。自分の思っていることも一旦相手に預ける。そうやってただ意見を出し合って、そこからじゃあどうしようかという話をすれば夫婦でその課題に向き合える。

というようなことは、読みかけのアサーションの書籍で、頭には入っていても、いざその場の感情に左右されてうまくいっていないわけで、

https://www.kanekoshobo.co.jp/book/b208828.html

ここでも夫婦で振り返りをしてみる。その場が感情的になって難しいのなら、時間を空けて振り返ってみるのはどうだろうか、という話になりました。

これについては **カジャイル** というキーワードのアイディアだけあって、何かつながるかもしれないという期待があって、また別の機会に形にしたいです。

# 何が変わったか
- 振り返りを通して日常の気づきが増えた
- 言語化する量が増えた

気づきがあることで着実に進んでいるという実感が湧き、自信になる、というと誇張しすぎですが、何もできていないのではないか、という不安な気持ちは随分と減った気はします。気づきが増えることと言語化する量が増えたのは相関関係があり、今現時点は好循環になっていると感じます。気づきが増えて言語化する機会が増え、、言語化するから気づきが増えるという仕組みです。

# おわりに
この記事が誰かにとってのクリスマスプレゼントとなるきっかけになったら嬉しく思います。
来年以降も、パーソナルコーチングを続けていくので、この後も自分にどんな変化が起こり続けていくのか楽しみです。

:::note info
2022年3月6日 セッション6回を終えての記事へのリンクを追記しました
:::

https://zenn.dev/ykws/articles/changes-by-personal-coaching
Nuxt 3 with ESLint

# 概要

Nuxt３でESLintを設定する方法

# 手順

１. ESLintをインストール

```bash
$ yarn add -D eslint eslint-plugin-vue
$ yarn add -D typescript @typescript-eslint/eslint-plugin @typescript-eslint/parser @nuxtjs/eslint-config-typescript
```

２. ESLintを初期化

```bash
$ yarn run eslint --init

# 以下を選択
> To check syntax and find problems
> JavaScript modules (import/export)
> Vue.js
> Does your project use TypeScript? Yes
> Where does your code run? Node (※スペースキーで選択)
> What format do you want your config file to be in? JavaScript
> Would you like to install them now with npm? No
```

３. 設定ファイルを修正

```js:.eslintrc.js
module.exports = {
    "env": {
        "es2021": true,
        "node": true
    },
    "extends": [
        "eslint:recommended",
        "plugin:vue/essential",
        "plugin:@typescript-eslint/recommended",
        "@nuxtjs/eslint-config-typescript" // ここを追加
    ],
    "parserOptions": {
        "ecmaVersion": 13,
        "parser": "@typescript-eslint/parser",
        "sourceType": "module"
    },
    "plugins": [
        "vue",
        "@typescript-eslint"
    ],
    "rules": {
    }
};
```


４. スクリプトを追加

```vjavascript:package.json
"scripts": {
  "dev": "nuxi dev",
  "build": "nuxi build",
  "start": "node .output/server/index.mjs",
  "lint": "eslint --ext .ts,.js,.vue ."  // 追加
},
```

５. 実行

```bash
$ yarn lint
```

完了！！
ビット演算で権限付与の切り分けを行う方法

https://qiita.com/jerrywdlee/items/d228452e870a6f5a78c0

|項目|10進数|2進数|
|----|----|----|
|A|1|0001|
|B|2|0010|
|C|4|0100|
|D|8|1000|

###付与する権限をビットを立てることで表現できる
|権限|10進数|2進数|
|----|----|----|
|A|1|0001|
|AB|3|0011|
|BC|6|0110|
|ABCD|15|1111|
|D|8|1000|

####ポイント
例えば10進数8と6で比べた場合、8の方が数字は大きいが、権限は6の方が大きくなる


https://www.youtube.com/watch?v=pwZAqtxJl84

##電卓
windows標準搭載の電卓で2⇔10進数の計算が簡単に行える

* メニューバーから「標準」→「プログラマー」に変更する
下の例 2進数1111⇔10進数15

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/637823/6da48c83-1598-a479-f4e2-5326a1370177.png)

##シフト演算
データのビット情報の桁をずらす演算

###論理シフト
* 倍々にすれば計算できる

|項目|10進数|2進数|
|----|----|----|
|A|1|0001|
|B|2|0010|
|C|4|0100|
|D|8|1000|
[ServiceNow]ユーザーをグループで絞り込みたい

##はじめに
こんにちは！
最近、ServiceNowという物を触り始めたので、普及の為に記事書いてみようと思います。
ちなみに、始めての投稿になりますので、見苦しい点あるかもしれませんが、温かく見守ってください。

##実装環境
ServiceNow バージョン：Rome

##やりたいこと
サービスカタログでユーザーコンボをグループで絞り込みしたい。
ロールなら下記の画像のように簡単に設定できるが、グループではちょっと工夫が必要っぽいので、実装してみた。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/448204/25783e3a-1d43-8a8f-0b37-09b897364ec6.png)


#設定内容
１．まずはスクリプトインクルードを作ります。
※注意：手抜きスクリプトです。いきなりクエリを返すようなクソコードです。実際につくるならメンバーのIDを返す方がいいと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/448204/dde6623a-70d6-7b86-7ef3-d8fa9b00e2ee.png)

```GroupUtils 
var GroupUtils = Class.create();
GroupUtils.prototype = {
	initialize: function() {
	},
		getGmemberQuery: function(gname){
			var userIds = [];
			var gr = new GlideRecord('sys_user_grmember');
			gr.addQuery('group.name',gname);
			gr.query();

			while(gr.next()){
				userIds.push(gr.user.toString());
			}
			return 'sys_idIN' + userIds.toString();
		},
	type: 'GroupUtils'
};
```
　


２．カタログアイテム変数の参照修飾子に先ほど作ったスクリプトを書いてきます。引数には絞り込みたいグループ名を入れます。
これで、sys_id in(メンバー1, メンバー2・・・)みたいなクエリになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/448204/41273047-3c7c-5fa0-6de8-19b39d69ce05.png)

```
javascript:'active=true^'+new GroupUtils().getGmemberQuery('テストグループ')
```
　

３．動作検証！
「テストグループ」には下記の5名を入れています。
彼らが出れば成功です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/448204/b9565673-df96-6f17-7936-7856f4df4f72.png)


やったね！たえちゃん！！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/448204/6519948b-d1a6-7a08-c7aa-69addaa0b8ae.png)


##おわりに
今回はカタログアイテムでグループでフィルタリングする方法について記載してみました。
これからも定期的に役に立ちそうなもの書いていけたらと思います！
Cloudflare の DNS Record を Pulumi (TypeScript) で管理する


## はじめに

Cloudflare で管理していた DNS Record を Pulumi (TypeScript) で管理する方法を記載します。
この記事では、すでに Cloudflare で作成済みの DNS Record を import していきます。

Pulumi の Project で Cloudflare のリソースを管理できるように設定されていることを前提に記載します。
設定が終わっていない方は以下記事を参考に設定を行ってください

https://qiita.com/mziyut/items/84212b8847eb5702dc60

https://qiita.com/mziyut/items/fd81f8b81d61c9578bd2

## DNS Record の import を行う

今回は Cloudflare 上で管理する mziyut.com の DNS Record を import します。
新規で DNS Record を追加する場合は、「DNS Record 情報をファイルに追記する」まで読み飛ばしてください。

Pulumi に Cloudflare の DNS Record を import するコマンドは以下となります。

今回、 import するドメインは `CNAME` で定義されている `mziyut.com` を使用します
`xxxxxx/yyyyyy` の `xxxxxx` は Zone ID を指定し、 `yyyyyy` は Record ID を指定してください

```zsh
pulumi import cloudflare:index/record:Record record_mziyut_com xxxxxx/yyyyyy
```

Zone ID や Record ID は Cloudflare の API から参照することができます

https://api.cloudflare.com/#dns-records-for-a-zone-list-dns-records

^ の import コマンドを実行すると pulumi up など実行したときと同様に
state の変更状況を出力した後、index.ts などに追記すべきサンプルコードを出力してくれます。

```console
Please copy the following code into your Pulumi application. Not doing so
will cause Pulumi to report that an update will happen on the next update command.

Please note that the imported resources are marked as protected. To destroy them
you will need to remove the `protect` option and run `pulumi update` *before*
the destroy will take effect.

import * as pulumi from "@pulumi/pulumi";
import * as cloudflare from "@pulumi/cloudflare";

const record_mziyut_com = new cloudflare.Record("record_mziyut_com", {
    allowOverwrite: false,
    name: "mziyut.com",
    proxied: true,
    type: "CNAME",
    zoneId: "YOUR_RESOURCE_NAME",
}, {
    protect: true,
});
```

## DNS Record 情報をファイルに追記する

Import 時に出力されたコードを index.ts に追記します。
出力されているコードはあくまでサンプルと考え、適切なオプションを付与してください。

今回は以下記事で Zone Resource を import しているためその情報と併せて index.ts に記載します。

https://qiita.com/mziyut/items/fd81f8b81d61c9578bd2

```ts:index.ts
import * as pulumi from "@pulumi/pulumi"
import * as cloudflare from "@pulumi/cloudflare"

const zoneMziyutCom = new cloudflare.Zone("mziyut_com", {
	zone: "mziyut.com",
	plan: "xxxx",
	type: "full",
}, {
    protect: true,
})

const record_mziyut_com = new cloudflare.Record("record_mziyut_com", {
    allowOverwrite: false,
    name: "mziyut.com",
    proxied: true,
    type: "CNAME",
    zoneId: mziyut_com.id,
}, {
    protect: true,
})
```

ファイルに追記したら `pulumi preview` を実行し取り込んだ state に差分が生じないことを確認してください

## Reference

https://www.pulumi.com/registry/packages/cloudflare/api-docs/record/
【Python】Tkinterを使って✜マークを記述

PythonとTkinterを使って✜マークを記述するコード。

## 実装コード

```python
from tkinter import *

window = Tk()
window.geometry ("600x600")
window.attributes("-topmost",True)
window.title("sample window")

c = Canvas(window,width=600,height=600,background="green")

size = 3
for n in range(size):
 for m in range(size):
  if (n+m) % 2 == 1:
    c.create_rectangle(50+m*32,50+n*32,80+m*32,80+n*32,outline="",fill="black")
c.pack()
mainloop()
```

## 実行結果

![スクリーンショット 2021-12-24 1.36.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/522445/1129cfb4-f9af-1896-7ff9-5f91fe1eef2d.png)
＊わかりやすいように背景を緑色にしています。

https://docs.python.org/ja/3/library/tkinter.html

## Pythonのお役立ち情報

https://wagtechblog.com/programing/python-school

https://wagtechblog.com/programing/ai-develop-school
【Python】turtleを使って⌘(command)マークを記述

Pythonとturtleを使って⌘(command)マークを記述するコード。

## 実装コード

```python
from turtle import *
speed(0)
step = 2
for m in range(4):
	for n in range(0,270,step):
		forward(2)
		right(step)
	forward(200)
done()
```

## 実行結果![スクリーンショット 2021-12-24 1.31.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/522445/5f8af3cb-dbb3-f109-f4b3-0d5eacc39f58.png)

https://docs.python.org/ja/3/library/turtle.html

## Pythonのお役立ち情報

https://wagtechblog.com/programing/python-school

https://wagtechblog.com/programing/ai-develop-school
Udemy「最新版：Python + Django3 Djangoを基礎から応用まで、アプリケーション開発マスターpython付き」を受けてみた！おじさんは動画時間を甘く見ていた。

# 伝えたい事：Udemyはお得。やってみる価値ある。初めての人は動画時間を見て無理なく実施出来るコースを選びましょう！


## 問題（現状とあるべき姿のギャップ）
おじさんは、「若いうちに勉強すべき」とか言う。
しかし、若者は、おじさんの昔話ではなく、「今」を見ている！
今勉強していないと説得力ないでしょ。


## 課題（ギャップをうめるためにやるべきこと）
技術でも英語でも、新しいことを学んでいる姿を見せる。
こっそりやってるなんてもったいない！
おじさんもチャレンジしている姿を見せ続ける！


## コース
最新版：Python + Django3 Djangoを基礎から応用まで、アプリケーション開発マスターpython付き
https://www.udemy.com/course/python-django-web/
37.5時間のオンデマンドビデオ
※学習期間の制限なし

## はじめに
私自身は昔ちょっとだけ、人のプログラムを流用してシェル等を触ったことがある程度の初心者。


## 受講の感想
動画37.5時間は甘くない！
自分でも手を動かすことを考えると倍くらいの時間がかかる！
間違い探しだけでも時間はかかる。

まずはオンデマンドの時間の倍程度の時間がかかることを想定し、計画的に実施する。

私はQiita投稿期限のために、有給とって動画をみる時間を捻出しました。




## 本コースの内容について
Pythonの基本的な文法
　⇒ここが大変！いやここが手厚い！
　　途中途中に「後ほど説明」というフレーズが結構あり、忘れた頃にやってくる！

Djangoを用いたアプリケーションの開発ができるようになること
Webフレームワークのアーキテクチャについて基本的な内容
アプリケーション開発の流れと、テーブル設計、セキュリティ



## 最後に
これを受講したからといって、すらすらpythonを使える訳ではない！そんなに人生甘くない！
あくまでも触りが分かる程度。

ただ、この「触りが分かる」は「分からない」と比べたら雲泥の差です！

また個別の言語だけでなく、派生でAnacondaやVScode等の開発環境を主体的に触れることが出来たのは何より良かった。
手を動かすことが少なくなったおじさんにはとても良い！

そして初めてのUdemy。初めての経験をくれた周りのメンバー皆に感謝！
データ分析初学者がFBProhetについてまとめてみた

##はじめに
データドリブンで事業を加速させることが、当たり前となってきた現代では
「商品の需要予測」「在庫の最適化」などのAIプロジェクトに取り組まれている企業様は多いのではないでしょうか。
上記のような、いわゆる「時系列予測」は非常にハードルが高いように感じることもあると思います。

特に私はデータ分析初学者（文系出身）なので、時系列予測に必要な統計学を勉強するとなるとものすごく高い壁に感じてしまいます、、、、
それでも統計学はいつかは勉強しないといけません。。。
どうにか便利なものないかなーと探していたら、時系列予測をサポートしてくれるライブラリーを見つけました！
その名も「FBprophet」！

今回はデータ分析の際に使われるライブラリー FBprophet について紹介していきます。

* FBProhetとは何か？
* どんなシーンで使われるか？

等について触れる記事になりますので、具体的な使用方法を知りたい方にはおススメできません。

目次は以下になります。

##目次
+ FBProhet とは
+ FBProhetユースケース（事例）
+ 終わりに

##FBProhet とは

FBProhetとは、Facebook社が開発した時系列予測をするためのライブラリーになります。
データ分析はビジネスにおいて無くてはならない物になりましたが、

+ 「高度なスキルが必要（統計モデル理解、ドメイン知識等）」
+ 「高い精度の予測をしたい」

等の観点から非常にハードルが高く感じるのが正直なところです。
特に時系列データは様々な分野において多岐に使用をしますが、統計への知識が欠かせません。

そこで有効なのが、FBProhetになります。
FBProhetでは「年周期」「週周期」「日周期」という３つの時系列データの周期性を利用して分析したり、予測することができます。
使用できる言語は、Rまたはpythonから選ぶことができるので、得意な方をチョイスできるのも嬉しい点です。

ちなみに、「Prohet」は日本語で預言者という意味なので、誰でも簡単に時系列の預言者になる事ができます。

###FBProhetにおけるメリット（特徴）
FBProhetを使用するメリットは3つあると思っております。

+ 統計学の知識が無くても予測が行える
時系列データの予測では、統計学の知識とドメイン知識が欠かせません。
FBProhetではこのうちの統計学の知識を補填してくれるので、非統計者でも簡単に予測モデルを作成することができます。
逆をいうと、ドメイン知識（業界への知見：イベント、季節など）を強化することでより高い精度の分析を行うことができるので、ドメイン知識を増やすことに集中できますね。

+ 自動化
手動で行っていたパラメーターの取得など、面倒な業務を自動化することができます。

+ 早くて正確
これからご紹介する事例の会社も含め、多くのアプリケーションやMLにおいて、正確性が求められる予測などにも使用されております。


##FBProhetユースケース（事例）
実際のFBProhetを活用した事例を紹介します。

###需要予測（スターバックス）
スターバックスは「3rdプレイス」をコンセプトにカフェ事業を展開する小売業です。
3万店以上ある店舗に加え、膨大なアイテム数を持つスターバックスでは、適切な量の在庫を仕入れなければ多大な損失を生み出すことになります。

上記のような背景も踏まえ、スターバックスでは商品の需要予測を行っております。

しかし、上述したように膨大なデータ量（ペタバイト級）が存在するスターバックス社では、細かい分析を行うためにデータの一元管理とスピーディな分析ができる環境が必要でした。
そこでスターバックスは膨大なデータを分析する基盤として、Databricksを採用いたしました。

> Databricks は AI /機械学習をはじめとするビッグデータを扱うためのデータ基盤です。2020年ガートナー「マジッククアドラント」データサイエンスおよび機械学習プラットフォーム部門でリーダーとして位置づけされており、この分野において現在最も注目を集めているサービスです。特にデータ分析環境の統合と大規模データ処理に強みがあり、パブリッククラウド環境/BI製品との親和性が高いことも大きな特徴です。

https://www.knowledgecommunication.jp/product/databricks.html

DatabricksのNotebook上でFBProhetを使用することで、

+ 個別の店舗
+ 個別の商品

等の細かい分析を高精度で行うことができるようになりました。
分析でのアウトプットは企業全体における在庫管理の改善や、新たな製品・サービスのイノベーションに役立てています。

##終わりに

いかがだったでしょうか。
データの活用が重要なカギとなっている現代では、時系列予測を行いたい企業様も多いと思います。
Databricks では、製品の需要予測を瞬時に行うことができるサンプルNotebook（モデル構築済み）が公開されているのでぜひ活用してみてください。

▽サンプルNotobookはこちら
https://pages.databricks.com/rs/094-YMS-629/images/Fine-Grained-Time-Series-Forecasting.html
SwitchbotとRaspberry Piを繋ぐ



昨年のアドベントカレンダーで[Switchbotの温湿度計をenebular-agent](https://qiita.com/jksoft/items/5175d6c0b49928c2b214)に繋ぐというのを試してみましたが、SwitchbotのセンサーやBotは様々な種類が販売されているので、他にも試してみました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109992/88ce5243-210b-c640-c9b7-88b2aa534512.png)
SwitchBotの人感センサーとドア開閉センサー、スイッチを押すためのボット、スマート加湿器です。Raspberry PiとBluetoothで接続することができます。

# 準備

まず、準備としてBluetoothをPythonで扱うためのモジュールをインストールします。

```shell
$ sudo apt install -y python3-pip
$ sudo apt install -y python-dev libbluetooth3-dev
$ sudo pip3 install pybluez
$ sudo apt install -y libglib2.0 libboost-python-dev libboost-thread-dev
$ sudo pip3 install gattlib
$ sudo pip3 install bluepy
```

人感センサーとドア開閉センサーは以下のPythonプログラムで値を取得します。引数でBLEの固有アドレスを指定します。Switchbotのセンサーは事前にスマホアプリから設定を行い、BLEの固有アドレスを取得しておきます。

```python
import sys
import binascii
from bluepy.btle import Scanner, DefaultDelegate

macaddr = ''

class ScanDelegate( DefaultDelegate ):
  def __init__( self ):
    DefaultDelegate.__init__( self )

  def handleDiscovery( self, dev, isNewDev, isNewData ):
    if dev.addr == macaddr:
      data = dev.getScanData()
      for item in data:
        if(item[0] == 22):
          door = "false"
          light = "false"
          pir = "false"
          bytedata = binascii.unhexlify( item[2] )
          if( bytedata[3] & 0x40 ): pir = "true"
          if( bytedata[5] & 0x02 ): door = "true"
          if( bytedata[5] & 0x01 ): light = "true"

          print( '{ "pir": ' + str( pir ) + ', "door": ' + str( door ) + ', "light": ' + str( light ) + ' }' )
          exit()

macaddr = sys.argv[1]
scanner = Scanner().withDelegate( ScanDelegate() )
scanner.scan( 0 )
```

人感センサーもドア開閉センサーも光センサーが内蔵されていて、その値も取得できます。出力はJSONで出力するようにしています。

次にSwitchbotのボットを動かすプログラムを用意します。こちらは、Switchbotオフィシャルが用意しているプログラムを使用しました。

```
$ sudo apt install -y git
$ git clone https://github.com/OpenWonderLabs/python-host.git
```

上記を実施し、引数にBLEの固有アドレスと動作を指定すると動きました。

```
$ sudo python3 switchbot_py3.py --device XX:XX:XX:xx:xx:xx Press
```

# enebular-agentで動作させる
簡単に値を取得するフローを作って確認してみました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109992/5946f198-29d8-aba3-e053-b98dbd5c3a3e.png)

debugノードでセンサーから取得された値が確認できました。

（本記事は、書き途中です。動作確認しながら書き上げていきます。）
Java ストリーム

[Javaのカレンダー | Advent Calendar 2021](https://qiita.com/advent-calendar/2021/java)の15日目の記事です

※　少し呑んでます

# 概要

Java の Stream と List(等) で1000件くらいのオブジェクトを扱ったときのヒープ(メモリ)の使用量がどのように変わるかを確認しました

結果は、Stream の方が List よりも　1/4 のヒープで動いてそうです。これだけでも、Stream を使うメリットを感じられるのではないでしょうか？

:::note warn
大量のデータを扱うようなシーンでは、Stream API よりも Spring Batch などの専用のフレームワークを利用すべしとあるので、あくまでも比較的件数が限られているものの用途に向いてそうです
:::


# 比較したコード

コードは適当なオブジェクトを 1000回分生成してリストに詰める(Stream から List に変換)するものです。

## Stream を使う場合

```java
    void useStream() {
        IntStream.range(0, 1000).parallel().mapToObj(i -> create()).collect(Collectors.toList());
    }
```

:::note alert
parallel() があってこそのこの結果で、parallel() がないと、 List の場合とほぼ変わらない、もしくはちょっと大きい結果になりました m(_ _)m
:::


## List を使う場合

```java
    void useList() {
        List<Parson> l = new ArrayList<>();
        for (int i = 0; i < 1000; i++) {
            l.add(create());
        }
    }
```

# 測定結果

測定には、以前の記事　[Javaでヒープサイズ測定 JUnit5編](https://qiita.com/gosshys/items/e6aa2fe12762cf29e9c0)　で使用した、[quickperf](https://github.com/quick-perf/quickperf) を使いました

## Stream を使う場合

```
[QUICK PERF] Measured heap allocation (test method thread): 137.34 Kilo bytes (140 640 bytes)
```

## List を使う場合

```
[QUICK PERF] Measured heap allocation (test method thread): 510.02 Kilo bytes (522 264 bytes)
```


# 付録

## テストコード全体

```java
@QuickPerfTest
public class StreamVsListTest {

    @MeasureHeapAllocation
    @Test
    void useStream() {
        IntStream.range(0, 1000).parallel().mapToObj(i -> create()).collect(Collectors.toList());
    }

    @MeasureHeapAllocation
    @Test
    void useList() {
        List<Parson> l = new ArrayList<>();
        for (int i = 0; i < 1000; i++) {
            l.add(create());
        }
    }

    @AllArgsConstructor
    @Data
    class Parson {
        private String name;
        private int age;
        private String addr;
        private String addr2;
    }

    Parson create() {
        return new Parson(RandomStringUtils.randomAlphabetic(10), new Random().nextInt(), RandomStringUtils.randomAlphabetic(20), RandomStringUtils.randomAlphabetic(20));
    }

}
```
もう悲しい思いはさせない！幼稚園からの連絡メールの見逃しを LINE Notify で解決した話

## キッカケ

ある週の後半にサツマイモ掘りの日がありました。
サツマイモ掘りの日は、体操服＋長靴で登園です。

しかし、天気予報を見ると週の後半は雨の予報で、雨で延期になっちゃうかな～などと親子で話をしていました。

その週の前半、いつも通り幼稚園へ送り、家で一息付くと iPhone の通知履歴の中から保育内容変更のメール通知が目に入りました。

> **📧 週後半に予定しておりましたサツマイモ堀りですが、雨天予報の為、明日に変更致します。**

そうです。前日に、サツマイモ掘りの日程変更のメールが来ていたのです。

メールは自分と妻の両方に届くようになっていますが、2人共メールが埋もれてしまって見逃していました。
子どもは、普通の靴で体操服無しで登園してしまいました。

## 概要

フィルタ等でラベルを分けても埋もれがちなメールを Google Apps Script で定期的に検索し、LINE Notify で LINE グループに転送し、二重で通知を受け取るようにしました。ほとんど見ることのない大量に来るメールよりも LINE の方が目付きやすいからです。

## システム構成

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/53393/d122c688-a318-b8c3-0884-bdc67c221fa3.png)

## LINE Notify

https://notify-bot.line.me/ja/ からログインして、
マイページで通知を送りたい LINE グループ向けのトークンを発行します。

![20211223221337.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/53393/408439b5-eb18-e8e6-9a22-3a08a8713e7f.png)
![20211223221843.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/53393/5d41f506-96d3-4e53-9dca-85c493bf0f42.png)

## Google Apps Script

https://script.google.com からログインして、新規スクリプトを作成します。

![20211223222308.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/53393/b9a8495b-30ef-3524-e7b8-bd916cdec070.png)

```js:コード.gs
const FROM_EMAIL_ADDRESS = '${検索対象のメールアドレス}'
const ENDPOINT = 'https://notify-api.line.me/api/notify'
const ACCESS_TOKEN = '${先程取得した LINE Notify のトークン}'

/**
 * LINE Notify で通知を送る
 */
function postLineNotify(messages) {
  return UrlFetchApp.fetch(ENDPOINT, {
    method: 'post',
    headers: {
      Authorization: 'Bearer ' + ACCESS_TOKEN
    },
    payload: {
      message: [''].concat(messages).join('\n')
    }
  })
}

/**
 * エントリポイント
 */
function myFunction() {
  // 時々メールが来るくらいなので最新5件のみを処理する
  const threads = GmailApp.search(`from: ${FROM_EMAIL_ADDRESS}`, 0, 5)

  threads.forEach(thread => {
    const messages = thread.getMessages()

    // 古い順に処理するので配列をリバースする.
    messages.reverse().forEach(message => {
      if (!message.isUnread()) {
        // 既読であればスキップする.
        return
      }
      const res = postLineNotify([
        message.getDate().toLocaleString(),
        message.getSubject(),
        '',
        message.getBody()
      ])

      if (res.getResponseCode() === 200) {
        // 通知を送ったら既読にする
        message.markRead();
      }
    })
  })
}
```

### タイマートリガーの設定

Google Apps Script はトリガーを設定できます。
朝に気付ければ良いので、朝7時頃に通知を受け取るようにしています。
また、当日準備に慌てる可能性もあるので、夕方や夜にも通知を受け取るように何個かタイマーを設定しています。

## 結果

<img alt="20211223223346.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/53393/80d9379b-3158-4850-4290-c9616075d09b.png" width="512px">

※テスト用に直接 LINE Notify を受け取るようになっていますが、
※実際は LINE グループに LINE Notify をメンバー追加して使用しています。

## 工夫したところ

- メール数はそんなに多くないので、検索個数を絞って無駄な処理をしないようにしました。
- 既読フラグを使って通知済みかどうかを判定し、無駄な通知は行わないようにしました。

## まとめ

- LINE Notify は、手軽に LINE 通知が行えてとても使いやすい
- 見逃しが減った！
- 妻にも久々に喜ばれた！

## 参考リファレンス

https://notify-bot.line.me/doc/ja/
https://developers.google.com/apps-script/reference/gmail/gmail-app?hl=en
https://developers.google.com/apps-script/reference/url-fetch/url-fetch-app?hl=en
デザイン関連おすすめブックマークリスト

[Qiita株式会社 Advent Calendar 2021](https://qiita.com/advent-calendar/2021/qiita)（2）の19日目の担当は、CX向上グループの@xrxoxcxoxです！

https://qiita.com/advent-calendar/2021/qiita

## この記事の概要

自分のブックマークを整理していて、せっかくだったらまとめてみたら他の人の役に立つかもしれないと思って記事にしました。

制作する上でブックマークしておくと捗るかもしれません。

## ガイドライン等

https://developer.apple.com/design/human-interface-guidelines/

Appleの出しているUIのガイドライン。読まない理由がない。

https://material.io/

Googleの出しているUIのガイドライン。読まない理由がない。

https://www.sociomedia.co.jp/category/shig

ソシオメディアさんがまとめているインターフェースのガイドライン。読みやすく、立ち返りやすい。

https://modelessdesign.com/modelessandmodal/

OOUIを学ぶにあたって非常に参考になる。

https://docs.google.com/viewer?a=v&pid=sites&srcid=ZGVmYXVsdGRvbWFpbnxoY2R2YWx1ZXxneDo2NWIxZTQwMTdjYTU1YTNm

UXの原典みたいなもの。

## 参考になるサイトやアプリ探し

https://www.pinterest.jp/

言わずと知れたサイト。

https://www.behance.net/

Adobeが運営している。

https://dribbble.com/

↑尖りすぎてるものもあるので「こんなんどうやって実装するんだ？？？」となる場合もある笑

https://www.designspiration.com/

上3つと比べると知名度は低いかもしれない？自分は割とよく見ている。

https://io3000.com/

https://bookma.torch.blue/

https://mobbin.design/

## ダミーコンテンツ

https://lipsum.sugutsukaeru.jp/

日本語のダミーテキストを生成してくれる。

https://picsum.photos/

ダミー用に画像を挿入できる。

https://hogehoge.tk/personal/generator/

擬似的に名前や住所などを生成してくれる。リアルなので若干怖い。

## 色関連

https://colorbase.app/

オールインワン感。そして国産。

https://color.review/

色のコントラストをチェックできる。

https://geenes.app/

1色指定するとグラデーションパレットを生成してくれる。

https://meyerweb.com/eric/tools/color-blend/

指定したカラーコードの中間の色を返してくれる。

https://chir.ag/projects/name-that-color/

カラーコードを入れると色名を返してくれる。あまりにコードが似ていると名前が被るのでそこだけ注意。

https://coolors.co/

スペースキーを連打すると良い感じのカラーパレットをひたすら生成してくれる。

## 写真、イラスト、動画など

https://unsplash.com/

https://undraw.co/illustrations

https://storyset.com/

https://loosedrawing.com/

https://tyoudoii-illust.com/

https://mixkit.co/

https://cleanmock.com/
アダルトサイト開発はカーテンの向こう側

この記事は [驚異のFANZA女優検索](https://fanza-actress-bust-search.azurewebsites.net/) Advent Calendar 2021 の 24日目の記事です。

# アダルトサイトを作ったとてすぐに人が溢れるかというとそんなことは全然ない
アダルトサイトを作ってみて思ったことは普通のサイト制作よりも結構大変なことがある。正直アダルトサイトを作れば、すぐに人がわんさか来て、収益もバンバン上がってという想像をしていたが、[サイトの収益について](https://qiita.com/fabsabsfabsabs/items/219f739d29ad24dd2bb0)に書いたとおり全然そんなことはない。

# アダルトサイトを運営すると実は使えないものが結構多い
[似た顔のFANZA女優を顔写真から検索出来るサンプルを用意するのに苦労した](https://qiita.com/fabsabsfabsabs/items/0c8248a8f86970b38c76)にも書いたが、アダルトサイトは思っていた以上に制限が多い。例えばフリー素材の画像を使おうと思っても、サイトの規約を読むとアダルトサイトはNGと書いてあるケースは本当に多い。フリーを含めた素材が一切使えないのはかなり厳しい制限だと思う。そういえば、サーバーもアダルトコンテンツを置く時点でNGな所もあるし、なかなかに厳しい。

# アダルトサイト開発は自宅ではやりにくい
自宅で特に家庭を持っているとアダルトサイトの開発は難しい。特に隠しているわけでもないが、わざわざ言う事でもないと思って作っている宣言はしていない。そうなると、パソコンの前から離れる時や、後ろに回られそうになった時は画面が見られないようにしている。そのためもあってFirefoxを開発専用のブラウザにしているので、Alt+Tabでchromeを先頭に持ってくるスキルはガンマン並みに速くなっていると思う。

# アダルトサイト開発は後ろめたさがある
そもそも、やはりアダルトサイトを作っていると、特に悪いことしていなくても、ある日このようなサイトは止めてくださいという注意が何処かから来たり、突然Twitterのアカウントが凍結されるんじゃないかと思ったりする。さらに心のどこかでそういう理不尽な事があっても、「え、そんな馬鹿な！」とは思えず「あ、やっぱりな」と思ってしまう。そういうのもあって[2つの名前の管理の仕方](https://qiita.com/fabsabsfabsabs/items/b903697676fa7f115bbc)で書いたがアカウントを分けた。普通に開発をしているだけではこういう思考にはならないと思うので、こういう後ろめたさを感じてしまっている事こそが、アダルトサイト開発のもっとも大きな制限かもしれない。

# アダルトサイト開発はカーテンの向こう側
そもそも自分の性的思考なんてものは、本来日の当たる場所に晒すことではないと思うし、それを前面に押し出すのは下品な事だと思う。上品なアダルトサイトなんて、清純派セクシー女優ぐらい矛盾に満ちた表現な気もするが、つまるところ自分はダサいのが嫌なのだ。[アダルトサイトの相互リンクに自分のサイトも乗っかろうとして止めた](https://qiita.com/fabsabsfabsabs/items/ecacdea7d07956c112ab)のもほぼ同じ理由だ。別の言い方をするとアダルトサイト開発はカーテンの向こう側なんだと思う。この表現、もう令和では通じなくなるだろうなー。
ワイ「Juliaってなんぞや？」

##ワイ「突然やがDeep Learning勉強するで！」
ワイ「早速ググるで^^」
記事「機械学習とDeep Learningの違いは～MLはニューラルネットが～」
ワイ「全部おんなじような内容の記事しかないやんけ　お前それしか言えんのかよ、、」
ワイ「もっと違う情報くれや、、」
記事「`Julia`なんて言語がDeep Learning出来るで」
ワイ「Julia..?知らん情報ktkr！これいうのを求めてたんや！！」

##ワイ「Juliaってなんや？」
![Julia_Programming_Language_Logo.svg.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/379533/3ccdde18-992d-ac3d-7bc0-7ece43f55adf.png)

記事「`Julia`っていうのはPython/C/MATLAB/R/Perl/Rubyのいいとこどりをした言語やで」
ワイ「めちゃくちゃ色んな言語からとってきてるやんけ」
ワイ「欲張りさんやな」
記事「一番の特徴はその処理速度の速さやで　例えばforの速度比較なんかは**100倍**ほどやで[(参考記事)](https://qiita.com/nandymak/items/05c950ce36964439bf51)」
ワイ「なるほどな　処理速度が速いから機械学習にも使用されるんやな」
ワイ「Pythonは**重い言語**として有名やからなぁ、、」
記事「おまけに**Jupyter Notebook**にも対応してるし、**並列処理**がやりやすいで」
ワイ「聞けば聞くほどいい言語やな」

##ワイ「Juliaの記法について勉強するで！」
記事「Juliaは高級言語だからPythonと記法はほぼ一緒やで」

```jl:test.jl  
a = 1.0
b = a + 2.0
println(b)#3.0
```
ワイ「型推論までしてくれるのはええな」
ワイ「高級言語ｻﾏｻﾏやで」
記事「しかもJuliaはこんな書き方も出来るで」

```jl:test.jl
c = 2a + b
println(c)#5.0
α = π
ほげ = 4im#4i
```
ワイ「わざわざ```2*a```って書かんでええのは滅茶苦茶便利やな」
ワイ「しかもギリシャ文字も日本語なんかも使えるんか」 
ワイ「珍しい言語やなぁ」
記事「**三角関数や行列**の機能も充実してるで！」
ワイ「ええやん 気に入ったわ」

##記事「JuliaとPythonの関係についてお話します」
記事「JuliaとPythonの**相性は抜群**なんや」
ワイ「まあ記法は似てるからな　Pythonにコード移行しやすいとかそんなんか？」
記事「**Pythonのコードをそのままimportできるで**」
ワイ「相性抜群というかほぼ一心同体やんけ、、」
記事「例えばJuliaでNumpyを使いたいときはこんな感じやで」

```jl:test.jl
using Pkg
Pkg.add("PyCall")
using PyCall

np = pyimport("numpy")
x = np.array([1,2])
#-------something do---------
```
ワイ「ホンマに原文ママ使えるんやな、、びっくりやで、、」

##ワイ「Juliaのデメリットとかはないんか？」
ワイ「いいとこばっかり聞いてるけど**デメリット**ももちろんあるんやろ？」
記事「そもそもPythonよりは**使用人口が少ない**から**情報収集がしにくい**で」
ワイ「もはや逆にPythonがデカすぎるんやろ、、」
ワイ「**公式リファレンス読む練習**にはなりそうやな（ポジティブ」
記事「あとは使用できる**ライブラリがまだ少ない**で」
ワイ「ここはPythonとの大きな違いやな」
ワイ「まあでもPythonのライブラリそのままimport出来るならそこまで問題でもないかもしれんな」

##ワイ「まとめやで^^」
ワイ「Juliaについて色々知ることが出来たわ（小並感」
ワイ「取り合えずJuliaは**処理速度**が速くて**Pythonとの連携**が素晴らしいんやな！」
ワイ「今後はJuliaで最適化問題とかモデル予測制御とか挑戦したいﾝｺﾞね」
ワイ「ほなまた:wave:」

##参考文献
- [「Julia」とはどんな言語？メリット・デメリットやPythonとの違いを解説(Tech Camp)](https://tech-camp.in/note/technology/103566/)
- [Juliaで数値計算　その1：コードサンプル〜基本的計算編〜(Qiita)](https://qiita.com/cometscome_phys/items/31d0b811345a3e12fcef)
- [ワイ「いうても型なんて面倒くさいだけやろ？」(Qiita)](https://qiita.com/Yametaro/items/2eaa6fd75255c8c2a2bb)
buttonタグのsubmitした値がPOSTされなかった話



# クリックしたボタンによって処理を分ける

formでpostする際において複数のボタンを設置している場合、クリックしたボタンの値を受け取って処理を分岐できる。
例えばメールフォームなどで、確認画面から入力画面に戻るか、送信するかという場合、以下のような処理で実現できる。

```html
<form action="post.php" method="post">
    <button type="submit" name="action" value="back">戻る</button>
    <button type="submit" name="action" value="send">送信</button>
</form>
```

```php
$action = (string)filter_input(INPUT_POST, 'action');

if ($action === 'back') {
    // 入力画面に戻る処理
    // リダイレクトとか
}

// 送信処理
```

なんてことない、よくある実装だ。

# buttonの値が送信されない

上記のようなフォームを実装して、実際に動かしてみたところどちらのボタンをクリックしても、送信処理だけが実行されてていた。`$action`のチェックがすり抜けているようだ。

`$_POST`をダンプすると、actionの値そのものが送信されていない。

# 原因

しばらく原因がわからず、さまざまな検証をしたが、JavaScriptでこのようなコードを記述していた。

```javascript
$(function($) {
  $('form').submit(function() {
    $('.submit', this).prop('disabled', true);
  });
});
```

disabled…？
このコードを削除すると、buttonタグの値が送信された。

# これなに？

いわゆる多重送信を防ぐために、サブミット後にボタンを無効化する処理。

> [さいきょうの二重サブミット対策 - Qiita](https://qiita.com/syobochim/items/120109315f671918f28d#-2-javascript%E3%81%A7%E3%81%AE%E3%82%B5%E3%83%96%E3%83%9F%E3%83%83%E3%83%88%E3%83%9C%E3%82%BF%E3%83%B3%E3%81%AEdisable%E5%8C%96)

disabledの要素の値が送信されないことは承知だが、submit後に変更してもダメなのか？
と、この記事を書いている途中に以下の記事を見つけた。

[Chromeの場合、submitボタン押下時にボタンをdisabledにすると、フォームデータが送信されない。 - Qiita](https://qiita.com/neko_the_shadow/items/1e828a05621aaa3539b1)

なるほど…、Chrome特有の問題なのか？
しかし、改善後の内容と現在の記述は（私はjQueryだが）同じものと思われる。

# 結論（未解決）

記述を変更したが、二重送信防止のためのdisabed処理を実装している場合、Chromeでは値が送信されなかった。
二重送信については、これにおいては直接の問題にはならないので、該当コードを削除して対応した。

# 解決済み（2022.02.16 追記）

コメントにて@rfr67183様にご提示いただきました。以下に引用させていただきます。

```javascript
document.querySelector('form').addEventListener('click', e => {
  const t = e.target;
  if(t.tagName !== 'BUTTON' || t.type !== 'submit') return;
  setTimeout(() => t.disabled = true);
});
```

この内容で、Chromeでもbuttonの値が送信されることを確認しました。

# ググって出てきた参考リンク（忘備録）

- [Google Chromeでsubmitボタンの多重送信防止対策に対する対策【JavaScript】 ](https://pgm.peace-machine.net/2020/08/04/google-chrome-submit/)
- [JQueryでsubmitボタン連打禁止](https://www.codelab.jp/blog/?p=2330)
- [送信ボタンの二重クリック防止を目的とするボタン無効化の推奨される対応方法について](https://wynes.info/techblog/archives/5318)
Java13〜17 振り返り

アドベントカレンダーに18日に予定入れていたのだが、ダラダラして遅くなってしまった（汗）
以前[この記事](https://qiita.com/yk0807/items/ea2d4b54545c7af37a89)でJava8〜12までの流れをものすごくざっくりと紹介していたので、それから2年9ヶ月の間にJavaがどのように進化していったかを思いっきりざっくりと書き連ねてみる。
ちなみに、Java9からはずっと半年ごとにバージョンが更新されています。

2019年9月　Java13　テキストブロック、switch式など
2020年3月　Java14　Recordクラスなど
2020年9月　Java15　Sealedクラスなど
2021年3月　Java16　VectorAPIなど
2021年9月　Java17(**LTS**)　switchのパターンマッチングなど、Javaアプレット廃止

この中だと、Recordクラス、Sealedクラスはうまく使えばプログラミングの幅が広がりそうですね。後、Javaのswitch文は若干使いづらいと感じていたので、これで使いやすくなるかなという期待はあります。
後は、時代の流れもあって最近は使われることも少なくなったとはいえ、昔はアプレットを使っていろいろ遊んだこともあったので、アプレット廃止は仕方ないとはいえ少し寂しかったり。
未経験からITインフラ業界に入って約3年経ったまとめ

Plannning-Venue Advent Calendar 2021の13日目です。

https://adventar.org/calendars/7174

タイトル通り、未経験者が何とか振り落とされずに食らいついてきたまとめです。
ラフに書いていくのでお酒でも飲みながらまったり読んでいただければ幸いです。

いきなりですが、IT未経験者がこの業界に就職するためのお役立ち知識はほぼ出てこないです。すみません。
そもそもこの業界に入った、というか入れたのはそこで働いていた友人の紹介でした。この時点でもう参考にならないです。
会社で試験的に「未経験者を入れて育ててみよう」という潮流があったようで、その波にたまたま乗れていきなり正社員になれたといった感じです。ただのラッキーです。
※人生の転機を与えてくれたその友人には今でも感謝しています。本当にありがとう。

私と同じく現在30代の方がこれからこの業界に参入して **生き抜いていく** ことはかなりハードルが高いと思います。が、無理では無いと私は思います。
事実私は“まだ”何とか食らいついています。根気よく行きましょう。

AWS資格については以前記事にしたものがあるので参考になるかもしれません。

https://qiita.com/instant_baby/items/cf39b67c044417d611b4

しかし、必ずしも資格持っている=就活に有利に働くとは限りません。
紹介で入った私が言うのもおこがましい話ですが、資格取る時間があるならアプリ作ったり何なりで形になるものを提出したほうが強そうに思います。
特にIT系の資格は士業と違って資格を持っていないと就けない仕事ではないので。
とりあえず就活用にAWS資格を取るのであればクラウドプラクティショナーだけで十分だと思います。余裕があればSAAくらい。

結局の所 **料理が好きだから料理人なる=プログラムが好きだからプログラマーになる** です。
お前は何を言っているんだ状態ですが、好きこそものの上手なれってことです。

例えば「リモーワークがしたい」「ITだと稼げそう」みたいな理由で志すのも動機としては大いに結構ですが、それだけだと長続きしないと友人に100回は言われました。
当時はピンときていませんでしたが今なら理解できます。
何故ならIT業界は学生時代から趣味で何年も業界に携わってきたようなモンスター達が蔓延る魔界。

**君は、生き延びることができるか？**

まぁそんな感じで、年下だけど超絶経験者で自分より年収が倍以上あるような人がいて当然の実力主義な世界です。年上系妹キャラみたいな状況が多発します、皆サイコガンダムMk-Ⅱに乗っているのです。
もちろん会社にもよると思いますが、私が入社した会社は完全実力主義の会社でした。
幸いなことに私は元々年齢や学歴、勤続年数などといった時間で人を測るモノサシに微塵も関心がなかったのでこの辺はすんなり受け入れられました。入社当時の先輩は6歳下でしたがなんとも思いませんでした。何故なら彼に実力があって私には実力がないから、です。当然です。

この辺を気にされる方は正直長続きしないかもしれないです。結構辛いと感じるのではないでしょうか。それが嫌なら(嫌でなくても)他の人の2倍、3倍の努力が必要です。怠けないウサギさんばかりですから。
ということで、振り落とされないために入社してから1年位は勤務時間以外もほぼほぼ勉強に当ててました。2年目くらいになってからはそれが習慣づいて、だんだんインフラが面白く感じるようになってきました。

そしてついに **好きこそものの上手なれ** のターンが私にもやってきました。

まぁ1年以上も日常業務をこなしつつ毎日アホみたいに勉強していれば否が応にも知識がついてくる訳です。
そしたら今度は仕事で触らないところにも興味が湧いてきます。

多分ここが分水嶺なんだと、今この記事を書いてて思いました。
業務でやることだけをやれればいい、だと多分いつか淘汰される気がします。

確かAWS認定資格のアソシエイト3種をとった後くらいだったかと思います。
業務で触らない範疇の技術を自発的に触ってみたいと思うようになった時期が。
今となってはうろ覚えですが確かそれがteraformだったと思います。
幸い社内に検証用のアカウントがあったので、上長の許可を貰って環境構築、それをまとめて履歴や所感と言った報告をするようになりました。

AWSをガチャガチャ触ってたら今度はオンプレに興味が湧いてきました。
そもそもクラウド触ってるのにオンプレ触ったことがないのはいかがなものかと。
ここでも幸いなことに、自宅にサーバーラックを持ってるレベルの友人が身近にいました。
その友人に相談し、ルーター(IX2105)とスイッチ(C2960)を格安で譲っていただきオンプレの世界に飛び込んでみました。

まだ趣味と言えるほど触ることは出来ていませんが、導入当時はCONSOLEポートにケーブルを繋ぐだけで緊張してました。
そして初めて1人でルーターのconfigを書き換えたときのドキドキは今でも覚えています。
オンプレでキャッキャした次はプログラミングです。何かしら書いてみたいなってことでHTMLを書き始めました(現在進行系)、今はbootstrapを使ってみようとして頭を抱えています。ナニモワカラナイ
<br>
<br>
そんなこんなで初めは何も知らずわからずの状態で入ったこの業界で、何とか振り落とされずに丸3年が経とうとしてます。自発的に色々触ってみることが出来るようになればとりあえず3年位は業界に居ることが出来ることがわかりました。

最後に、アラサー未経験でITインフラ業界を目指す方へ。
**めっっっっっっっちゃ大変！でもめっっっっっっっっっっっっっっちゃ楽しいよ！！**
以上、ここまで読んで頂きありがとうございました。

いよいよ明日はこのアドベントカレンダーの大トリ「Vultr触ってみた。手軽に激安クラウドでサーバーを建ててみる」です！

https://adventar.org/calendars/7174
WindowsユーザーがMacに移行した時に最初にやったこと

# 主旨
長年Windowsを使ってきた筆者が、Macに移行するにあたって
WinではアレできたけどMacで同じことやろうとしたらどうすりゃいいの？と思って手順を調べて対応したことをまとめて記載します。
同じような状況の人の参考になれば幸いです

### キーボードショートカット関連

キーボードから手を離さず、極力マウスを使わずに操作を完結させたいので、Macに乗り換えるにあたって、Mac固有のキーボードショートカットを覚える作業は真っ先に行いました

#### ウィンドウ操作のショートカット

https://free-method.co.jp/mac/mac-shortcut-split-screen/

#### メニューをフォーカスしてキーボード操作する

メニューバー（下図の Chrome ファイル 編集 ...のところ）にフォーカスするには`Ctrl + F2`を押す

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/81499/47d8c1bb-614e-d281-b222-871ad34c1603.png)

メニューバーにフォーカスが当たったら、方向キーでメニューを選択できます。

### 画面録画
QuickTimePlayer>ファイル>新規画面収録

「収録」をクリック

<!--
これ、うまくいってない↓
※ Mac内部で鳴らしている音(イヤホンなどへの出力含む）も収録したい場合
オプション↓
をクリックして「Background Music」を音声元にする
-->

画面収録を停止するには、メニューバーの「収録を停止」ボタン  をクリックします（または、Touch Barを使用します）。

https://support.apple.com/ja-jp/guide/quicktime-player/qtp97b08e666/mac

## Finder
### Finder の右クリックメニューをカスタマイズする

https://qiita.com/hiroyuki7/items/a3fcdf943c313473ecee

### Finderで開いているフォルダをカレントディレクトリとしてターミナルを開く

https://daeudaeu.com/finder-terminal/#google_vignette

### 隠しファイル・フォルダを常に表示
Finderだとデフォルトで隠しファイル・隠しフォルダは表示されない
`⌘ + Shift + .`で表示されるのだが毎回コマンド打つのも面倒くさいという問題への対処法
https://qiita.com/y_otake/items/cc9e2461c62eb6f9c53a

## Chrome
### ブックマークツールバーにフォーカスを移すためのキーボードショートカット
既定ではできないっぽいのでこの拡張機能を入れて

https://chrome.google.com/webstore/detail/holmes/gokficnebmomagijbakglkcmhdbchbhn

`shift + option + H`を押すことで代替とした

## ファイル圧縮

ZIPコマンドを使えばよい。パスワードつきZIPの作り方は下記記事参照。

https://qiita.com/Hikery/items/642b80cc498a280da64f

上記記事には載ってないけど、ディレクトリごと圧縮したい場合は`-r`オプションを使えば良いです

```sh
$ zip -er zipped.zip pre-zipped/
# =>  pre-zippedディレクトリが zipped.zip というパスワードつきファイルに圧縮される
```

## 関連記事
自分と似たようなことをしている方がいらしたのでこちらも参考にどうぞ

https://qiita.com/d-dai/items/3304a40798d6c2c69a17
【React】React does not recognize the `textPrimary` prop on a DOM element.の対処方法

<h2>症状</h2>
ReactでMaterialUIのAppbarを使用したとき、以下のwarnが発生しました。
翻訳すると、「ReactはDOM要素の `textPrimary`プロップを認識しません。意図的にカスタム属性としてDOMに表示する場合は、代わりに小文字の `textprimary`と入力してください。親コンポーネントから誤って渡した場合は、DOM要素から削除してください。」でした。

```terminal:warm
Warning: React does not recognize the `textPrimary` prop on a DOM element. If you intentionally want it to appear in the DOM as a custom attribute, spell it as lowercase `textprimary` instead. If you accidentally passed it from a parent component, remove it from the DOM element.
```

エラーをたどって、warnが発生している箇所を発見。抜粋しました。

```react:Appbar.js
<Typography className={classes.title} variant="h5" noWrap textPrimary={"#000"}>
  {HOME_TEXT.HOME_TITLE}
</Typography>
```

<h2>解決策</h2>
エラーの指示に従ってtextPrimaryをすべて小文字にしたら、解決しました。

```react:Appbar.js
<Typography className={classes.title} variant="h5" noWrap textprimary={"#000"}>
  {HOME_TEXT.HOME_TITLE}
</Typography>
```

<h2>参考</h2>

https://mui.com/components/app-bar/
〜超初心者編 HTMLの基礎〜

#目次
[1.目的](#1目的)
[2.HTMLとは](#2htmlとは)
[3.HTMLの基本構成](#3htmlの基本構成)
　ー[HTMLの要素](#htmlの要素)
　ー[HTMLの書き方](#htmlの書き方)
[4.終わりに](#4終わりに)

#1.目的
HTML言語を全く触ったことがないような超初心者に向けて、まずHTMLとはどういったものなのかからHTMLの基本的な書き方まで一緒に学んでいきます。

#2.HTMLとは
まずHTMLとは「<strong>H</strong>yper<strong>t</strong>ext <strong>M</strong>arkup <strong>L</strong>angage」の略で、「Hypertext」とは複数の文書を相互に関連づける仕組みのことであり主な例として「<strong>URL</strong>」があります。次に「Markup」とはテキスト中に書体などの標識情報を埋め込むことであり、一般的にタグ付けと同じようなものです。
つまり、HTMLとは「文書にタグ付けすることで色々な機能を持たせ、Web上などでさまざまな文書と共有可能にする言語」ということです。

#3.HTMLの基本構成
さて、HTML言語がどういうことをする言語なのかわかってきたところで、HTML言語の基本的な書き方を説明していきます。

###HTMLの要素
まずはHTMLの最も重要なところである、要素について見ていきます。

>`<p>タグの中身だよ</p>`

・上記の`< >`で囲んだ中身が<strong>要素の名前</strong>です。上記での場合は`p`が要素の名前となります。この要素の名前を指定することで、テキストに与える効果を設定することができます。

・要素の名前を`< >`で囲むと<strong>タグ</strong>となります。タグの中で、`<p>`のような形を<strong>開始タグ</strong>と言い、どこから要素が始まるのかを表しています。また、`</p>`のような形を<strong>終了タグ</strong>と言い、要素が適用される範囲の終わりを表しています。

・タグで囲まれた中身を<strong>コンテンツ</strong>と言います。今回の場合、`タグの中身だよ`の部分がコンテンツにあたり、要素の効果が適用される内容のことです。

・タグとコンテンツを合わせて<strong>要素</strong>と呼びます。今回の場合、`<p>タグの中身だよ</p>`が要素にあたります。

>`<a href="リンク先URL"> タグの中身 </a>`

また、特定のタグに関しては要素の追加情報である<strong>属性</strong>を入れることができる。上記では、`href="リンク先URL"`が属性であり、開始タグの中の要素の名前の後ろに入れます。`<a>~</a>`自体はリンクを作る要素だが、属性でリンク先を指定することができ、`<a>~</a>`で作ったリンクから属性で指定したリンク先に飛ぶことができる。

:::note warn
要素の名前と属性の間に「半角スペース」
:::

###HTMLの書き方
ようやくHTMLの基本的な書き方について学んでいきます。

```HTML:test.html
<!DOCTYPE html>
<html>
<head>
   <title>Charme</title>
</head>
<body>
   <h1>HTMLの超入門編</h1>
   <p>HTMLについて</p>
</body>
</html>
```

・`<!DOCTYPE html>`はこれがHTML文書であることを表すもので、おまじないとしてHTML文書の初めに必ず書きます。

・`<html> </html>`はこのタグの中身がHTMLで書かれたコードであることを表しています。HTMLのコードを書く際は必ず書きます。

・`<head> </head>`はWebページを作成した際に、そのWebページに訪問してきた人が直接見ることはあまりなく、検索エンジンに対して与える情報をこのタグの中に入れます。例えば、headタグ内にあるtitleタグの場合、検索結果となる、タイトルを与えることができ、これは検索エンジンに対して検索結果という情報を与えているということです。

・`<body> </body>`は訪問者が直接見ることになる部分で、画面内に表示されるのはこの部分となります。大見出しを表す`<h1> </h1>`や、段落を表す`<p> </p>`が中に入ります。

#4.終わりに
まずはHTMLの基本中の基本を勉強してみました。これでHTMLがどういった言語なのか少しわかったかと思います。
次回は、HTMLでよく使う基本的な要素について勉強していこうと思います。
「@kazuo_reve, AUTOSARのClassic PlatformとAdaptive PlatformにおけるDiagnosticsの違いを整理」で慌てて

@kazuo_reve AUTOSARのClassic PlatformとAdaptive PlatformにおけるDiagnosticsの違いを整理
https://qiita.com/kazuo_reve/items/05c179d705c69286b94a

を拝見して慌てて、引用元の記事に書き足しています。

# Foundation
AUTOSAR R21-11(1) Glossary
https://qiita.com/kaizen_nagoya/items/9eaf0c2a82a39c356f92

にいろいろ書き足す予定。

AUTOSAR R21-11(3) Requirements on Diagnostics
https://qiita.com/kaizen_nagoya/items/fce079cfd7ce9f6ee4ca

には、少し書き足した。
# Diagnostics
AUTOSARと国際規格
https://qiita.com/kaizen_nagoya/items/4ddba03efb942969b125

DIAG関連規格の改装図を転記予定。

# セキュリティと安全
自動運転を想定したセキュリティとDiagnosticsは対になって運用するかもしれない。

自動車アセスメント、テストコースでの実車の実動試験を含めた仕様整理が大事かも。

堀場製作所がMIRAを、ContinentalがElektrobitを買収したのも、
自動運転、テストコース関連という逸話をお聞きしたことがある（伝聞）。

セキュリティと安全について、Diagnosticsの視点で整理する予定。

SOTIF(ISO/PAS 21448:2019
Road vehicles — Safety of the intended functionality), サイバーセキュリティ(ISO/SAE 21434:2021 Road vehicles — Cybersecurity engineering)、FTA, FMEA, HAZOP,ETA(IEC 62502 2010, Analysis techniques for dependability – Event tree analysis (ETA))

名工大のいくつかの研究室に声をかけるかもしれない。
# Reference
物理記事　上位100
https://qiita.com/kaizen_nagoya/items/66e90fe31fbe3facc6ff

数学関連記事１００
https://qiita.com/kaizen_nagoya/items/d8dadb49a6397e854c6d

言語・文学記事　１００
https://qiita.com/kaizen_nagoya/items/42d58d5ef7fb53c407d6

医工連携関連記事一覧
https://qiita.com/kaizen_nagoya/items/6ab51c12ba51bc260a82

通信記事１００
https://qiita.com/kaizen_nagoya/items/1d67de5e1cd207b05ef7

自動車　記事　１００
https://qiita.com/kaizen_nagoya/items/f7f0b9ab36569ad409c5

小川清最終講義、小川清最終講義（再）計画, Ethernet(100) 英語(100) 安全(100)
https://qiita.com/kaizen_nagoya/items/e2df642e3951e35e6a53

＜この記事は個人の過去の経験に基づく個人の感想です。現在所属する組織、業務とは関係がありません。＞
### 文書履歴(document history)
ver. 0.01 初稿 　 20221223
ver. 0.02 ありがとう追記 　 20230529
### 最後までおよみいただきありがとうございました。
いいね　💚、フォローをお願いします。
####  Thank you very much for reading to the last sentence.
Please press the like icon 💚　and follow me for your happy life.
【必読】笠松競馬場 12/30(木) 第3レース完全攻略マニュアル決定版【water】

## はじめに
ウマも馬もやらんけど笠松競馬場 12/30(木) 第3レースに絶対勝ちたい…！
せや！人気順にかけたら必ず勝てるんちゃうか？？？

## なにをするの
人気順にウェイトがかかるようにランダムで3連単を選ぶ。
みんな重たいのが好き。

## python
~~~python
import csv
import random
import numpy as np


# List形式で格納
tmpUmaList = list()
with open('./TEST_UMA.csv', encoding = 'shift_jis', newline='') as f:
    reader = csv.reader(f)
    for row in reader:
        tmpUmaList.append(row)

# ヘッダ削除
umaList = np.delete(tmpUmaList, 0, 0).tolist()

# 行数カウント
umaCount = len(umaList)
print(str(umaCount)+'頭立て')



# Weightを付与(総数-人気、weightは必ず1以上なので+1)
for n in umaList:
    weight = umaCount-int(n[2])+1
    n.append(str(weight))

# weightで昇順ソート
sortedUmaList = sorted(umaList, reverse = True,key=lambda x:x[3])

# getWeight
ninkiWeight = []
for n in sortedUmaList:
    ninkiWeight.append(float(n[3]))

# getNo&辞書登録
umaNo = []
umaTachi = {}
for n in sortedUmaList:
    umaNo.append(n[0])
    tempUma = {n[0]:n[1]} 
    umaTachi.update(tempUma)

# result
result = []
choice1 = random.choices(umaNo,ninkiWeight,k = 1 )
while True:
    choice2= random.choices(umaNo,ninkiWeight,k = 1 )
    if choice1 != choice2:
        break
while True:
    choice3 = random.choices(umaNo,ninkiWeight,k = 1 )
    if choice1 != choice3 and choice2 != choice3:
        break
result = choice1 + choice2 + choice3

print(f'{result[0]}-{result[1]}-{result[2]}')
print(f'{umaTachi[result[0]]}-{umaTachi[result[1]]}-{umaTachi[result[2]]}')
~~~


## データリスト
|番号|名前|人気|
|---|---|---|
|1|矢澤にこ|1|
|7|西木野真姫|3|
|3|小泉 花陽|2|
|8|東條 希|5|
|9|星空 凛|9|
|2|園田 海未|7|
|6|南 ことり|4|
|4|絢瀬 絵里|6|
|5|高坂 穂乃果|8|

csvで保存する。


## 実行結果
~~~console
$ python3 yazawa.py
9頭立て
7-3-1
西木野真姫-小泉 花陽-矢澤にこ
~~~


## ほんとうに
ウェイトかかってるんか？？？

~~~python
# 計測
sample = random.choices(umaNo,ninkiWeight,k = 1000 )
n=1
while n<=9:
    print(n,':',sample.count(str(n)))
    n+=1
~~~

jikkou

~~~console
1 : 191
2 : 56
3 : 197
4 : 94
5 : 47
6 : 129
7 : 157
8 : 101
9 : 28
~~~
かかっとるやんパンダだかパンツとかで棒グラフ出すの面倒だからいいや。

## これから
詳しく知らんけど”人気”以外にもオッズとか馬場状態？？とかからウェイトの解像度上げていけば当たる確率は上がるはず(儲かるとは言っていない)
なんでも重いやつが勝つんやな。

## TODO
CSVじゃなくてどっかからデータを自動で抜いてくる。
GASでTwitter APIのOAuth2.0 Bearer Tokenの認証をする

公式ドキュメントに書いてあることをやるだけです

# 公式ドキュメント

https://developer.twitter.com/en/docs/authentication/oauth-2-0/application-only

# 必要なもの
Twitter Developperアカウント
それで得られるConsumer Keys(API Key, API Secret)

ここでは解説しないので以下のサイトとか各自検索したりしてください

https://blog.palettecms.jp/article/20103

https://qiita.com/hatt_takumi/items/b142378809f56f81352b

# やり方
上記に書いた通り公式ドキュメントに書いてあることをやるだけです

```js
function twitterOauth2(){
  const encodedKey = encodeURIComponent(TWITTER_API_KEY)
  const encodedSecret = encodeURIComponent(TWITTER_API_SECRET)

  const bearerTokenCredentials = Utilities.base64Encode(encodedKey + ':'+ encodedSecret)

  const option = {
    headers: {
      'Accept-Encoding': 'gzip',
      Authorization: 'Basic '+ bearerTokenCredentials ,
      
    },
    'contentType': 'application/x-www-form-urlencoded;charset=UTF-8',
    method: 'POST',
    payload: 'grant_type=client_credentials'
  }
  const res = UrlFetchApp.fetch('https://api.twitter.com/oauth2/token', option)
  Logger.log(res.getContentText())

}
```

## Consumer Keysのエンコード, 証明書の生成

```js
const encodedKey = encodeURIComponent(TWITTER_API_KEY)
const encodedSecret = encodeURIComponent(TWITTER_API_SECRET)
```


まずそれぞれのkeyをURLエンコード(RFC 1738)します．keyのエンコードに関しては`encodeURI`の方でも問題ないけど`encodeURI`はRFC 2396なのでちょっと仕様が違う[^encodeURL]．そもそも「現状の仕様だとこのエンコードに意味はないよ．でも仕様変わるかもしれないから一応やってね」って書いてある．
>URL encode the consumer key and consumer secret according to RFC 1738. Note that at the time of writing, this will not actually change the consumer key and secret, but this step should still be performed in case the format of those values changes in the future.

```js
const bearerTokenCredentials = Utilities.base64Encode(encodedKey + ':'+ encodedSecret)
```

エンコードしたkeyを`:`でくっつけた後にbase64にエンコードしたら証明書の完成です．

## Bearer Tokenの取得

```js
const option = {
  headers: {
    'Accept-Encoding': 'gzip',
    Authorization: 'Basic '+ bearerTokenCredentials ,
    
  },
  'contentType': 'application/x-www-form-urlencoded;charset=UTF-8',
  method: 'POST',
  payload: 'grant_type=client_credentials'
}

const res = UrlFetchApp.fetch('https://api.twitter.com/oauth2/token', option)
Logger.log(res.getContentText())
```

`UrlFetchApp.fetch()`仕様の`option`は上記の感じ．ここまで何も間違ってなければログにBearer Tokenが表示されるのでメモって環境変数にでも設定しておきましょう．

# 使い方
おまけです．`query`はエンコードしなくても大丈夫です．

https://developer.twitter.com/en/docs/twitter-api/tweets/search/quick-start/recent-search

```js
function searchTwitter(){
  const url = 'https://api.twitter.com/2/tweets/search/recent?max_results=10&expansions=author_id&tweet.fields=attachments&query='

  const query = encodeURIComponent('from:yuzukichococh url:twitter.com/i/spaces')

  const option = {
    method: 'get',
    contentType: 'application/json',
    muteHttpExceptions: true,
    headers:{
      Authorization: 'Bearer '+ TWITTER_BEARER_Oauth2
    },
  }

  const res = JSON.parse(UrlFetchApp.fetch(url+query, option))
  Logger.log(res)
}
```
`query`で`list:`検索できないのが残念．streamで使いたかった...



[^encodeURL]: https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/encodeURI#encodeuri_vs_encodeuricomponent
ALBの認証機能でお手軽SSOを実現する

ALBには認証機能が備わっています。これを利用することで、簡単にシングルサインオン を実現できます。

https://aws.amazon.com/jp/blogs/news/built-in-authentication-in-alb/

https://docs.aws.amazon.com/ja_jp/elasticloadbalancing/latest/application/listener-authenticate-users.html


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/9038/447180a1-a6a2-75ef-4235-12741eb474ab.png)

選択可能な認証方式は2つです。

1. Amazon Cognitoとの連携
  - SAML連携などの企業ID連携や、FaceBook、GoogleなどのソーシャルIdPもCognitoのユーザプールを経由すれば可能
2. OpenID Connect (OIDC) に準拠する ID プロバイダー (IdP) と直接連携

今回は2を利用して、AzureADと連携してみます。


# AzureAD
## 1. アカウント作成
以下の無料アカウントを使ってAzureADを構築します。

https://azure.microsoft.com/ja-jp/free/

## 2. アプリの登録
AzureADにはテナント単位でアプリを登録でき、これを介してOIDC連携が可能となります。
下記画面でアプリを登録します。

また、設定画面の「リダイレクトURL」は以下とします。

* https://{ALBのドメイン}/oauth2/idpresponse

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/9038/99a6e81a-5141-369a-e350-1c9b99ad5799.png)
![スクリーンショット 2021-12-23 22.05.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/9038/4b01eb49-5d98-ed58-92a5-881e27c28d27.png)

## 3. シークレットの登録
シークレット情報を登録します。ALBのルール作成時に必要となるので値は控えておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/9038/cb3398ab-a7cf-dea7-06f5-e98b8a09fa45.png)

## 4. エンドポイントの確認
作成したアプリのエンドポイントを確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/9038/3c0f5f4c-d8fd-68df-a7bd-7a50a018c1cd.png)

# ALB
## 5. リスナー設定
3のエンドポイント情報を元にALBのリスナールール設定をします。
発行者、ユーザ情報エンドポイントは以下を参考にしてください。
https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration


![スクリーンショット 2021-12-23 23.31.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/9038/5c9dee80-5919-087a-67ce-290b85e62470.png)


## 6. 確認
ALBのドメインにアクセスしてみましょう。
MSサインイン画面が表示され、AzureADのテナントユーザでログインできるようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/9038/035f32ec-18a1-2dc4-9e2c-3c1b4182459f.png)


## ALBのバックエンドには何が渡されるのか？
HTTPヘッダー `x-amzn-oidc*`にjwt形式でユーザクレームが渡され、検証および情報利用が可能になります。
以下を参考にしてください。
https://docs.aws.amazon.com/ja_jp/elasticloadbalancing/latest/application/listener-authenticate-users.html#user-claims-encoding


## まとめ
ALBの認証機能を利用すると、お手軽にOIDCを利用したSSOが実現できます。
自前で実装する必要がなくなるので、活用してみてください。