OmniAICreator/Qiita-1.07M huggingface dataset:
【デイトラ】初級ノートDAY2〜DAY4

## ◆悩んだとこ、後から気づいたとこをシェアしていきます。

デイトラをはじめました。
現在中級に入ったところですが、つまずくようになってきたので
初めて復習をしています。

復習にあたって、VSCodeでmarkdownを使ってノートをとるようにしました。
せっかくなので、同じ悩みの方に向けて投稿していきます。

単元を学習した後に読むのが良いと思います。

**わたしも同様に初学者です。内容の正確性を保証することはできません。**
**訂正やより良い情報があればご教授お願いします。**

### ✔この記事で解決できること

- 講義内容と課題の中でわからないことが解決できるかもしれない。
- 調べる時間を短縮できるかもしれない。
- 学習の仕方を効率化できるかもしれない。

## ◆DAY2 HTML を書いてみよう

### ✔ ブロック要素、インライン要素

ここはよく確認したほうが良いです。
私は曖昧にしたまま進んだので、
毎回a、ul、inputの中央揃えなどで頭を捻りました。

| 違い | ブロック | インライン |
| -------- | ----------- | ------------ |
| 改行 | 要素の前後 | 入らない |
| 幅、高さ | 指定できる | 指定できない |
| margin | 上下左右 | 左右のみ |
| タグ | div,h1,p,ul | a,span,input |

## ◆DAY3 CSS を書いてみよう

### ✔ セレクタ、プロパティ、バリュー

セレクタ {
プロパティ: バリュー;
}

HTMLは、要素=開始タグ＋属性＋属性値＋内容＋終了タグ
のようです。
私は混乱したのできをつけて。

### ✔ 子孫セレクタの要点

忘れやすいです。
複数のセレクタはカンマ,を使う。
これと次の 2 つで十分そう。
いまのところは。

1. .contents 以下の p をすべてを指定する記述
 .contents p {}
1. .contents 直下の p すべてを指定する記述
 .contents > p {}

```html
<div class="contents">
 <p>1と2が適用される</p>
 <p>1と2が適用される</p>
 <div>
 <p>1が適用される</p>
 <p>1が適用される</p>
 </div>
</div>
```

### ✔ ボックスレイアウトの注意点

![boxlayout.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/622998/4d141d9f-9a6d-46c9-1ee2-192109fb2f0d.png)

必須です。
当初は、次のことが理解できていませんでしたし、
この観点で教えてくれる教材はなかなか見当たりませんでした。

- border はコンテンツエリアを囲う線の太さのこと。上図では、黄色帯のことです。
殆どの図で、borderの外枠だけが太く描かれているのでわかりにくい。
- width と height はコンテンツエリアを指定する。次のborder-boxで変わります。
- border-box は width と height の指定範囲をコンテンツエリア、padding、border にする。
コンテンツエリアを縮小して調整される。
### ✔px、em、rem の違い
今はpxとemで良さそう。
- px 絶対値 長さの単位
- em 相対値 親要素に対する割合 0.5em = 50%
- rem 相対値 html タグに対する割合 r は root　
- 
+参考サイト
https://qiita.com/39_isao/items/e8242901ba1aadb75676

### ✔ 背景
初級が終わった後でも知らなかったもの。
今は流しても良いかも。
- background-size: contain;
 コンテンツエリアを埋めるように画像を繰り返す
- background-repeat: no-repeat, repeat-Y;
 画像を繰り返さない、縦方向に繰り返す
- background-attachment: fixed, scroll;
 背景を固定する、スクロールできるようにする

### ✔float

flexboxがあるので、もしかしたら実務であまり使わないのかもしれないが、
理解だけはしたほうが良いのかも。
浮く、回り込むといった抽象的な表現で説明している教材が多いので、
仕組みを調べてみた。
以下はリンク先をわたしなりに補足したものです。

> box（ブロック） の高さは、指定がない場合コンテンツエリアの中身で決まる。
しかし、float を設定すると親の box から浮いてしまう。なので、
親 box のコンテンツエリアに float の box は存在しなくなる。
その分親 box の高さがなくなる。
float が設定された box の次に clear を設定すると
float の box + clear の box までが親 box のコンテンツエリアに収納され、
親 box が高さを持つ。

+参考サイト
https://60pablog.com/css-clear/

### ✔flexbox

重要。
並べたい要素の親に display:flex;を記述し、
並べ方のプロパティも一緒に記述するのを忘れない。
最初は、並べたい要素に直接下記を書いて困ってました。

display:flex;
justify-content:center;

+参考サイト
https://www.webcreatorbox.com/tech/css-flexbox-cheat-sheet
https://pakupakumukku.com/2020/03/22/post-1629/
https://flexboxfroggy.com/#ja

### ✔position

曖昧にしないほうが良いです。
流して教わることの多いabsoluteの仕組みを知っておくと
コードが一歩読みやすくなると思います。

- static デフォルト
- fixed ブラウザを起点に位置固定
- relative 本来表示される場所を起点にずらす
- **absolute 親に static 以外が指定されていると親を起点にずらす**

+参考サイト
https://www.asobou.co.jp/blog/web/css-position

### ✔z-index

値が大きいと手前に表示
案外使わない分忘れやすかった。

## ◆DAY4 環境設定

HTMLhint は、中級で入れるプラグインの EasySass と
不具合を起こすので、中級に入る時にアンインストールしたほうがいい。

最近デイトラのslackで流れてきましたが、当時めちゃくちゃ困りました。
slackの質問スレはナレッジになるので、困ったときは検索してみてください。
私は数時間悩んだ後にslackの過去ログを見ることを思いつきました。
【Auth0】Universal Loginの新規登録を無効化する

# はじめに
[前回の記事](https://qiita.com/smesh/items/ea5100f570211ffe7890)でAPIを利用したAuth0のユーザー登録をやってみましたが
ユーザー登録は ManagementAPIで行い、ログイン画面はUniversal Loginを利用する場合はUniversal Loginから新規登録をできないように設定しておきたいかと思います。

今回はUniversal Loginから新規登録ができないように設定をしてみました。

# Database Connections設定
新規登録をできないようにするにはUniversal Loginの設定ではなくデータベースの設定を変更する必要があります。

Auth0の管理画面を開いてデータベースの設定を開きます。

![スクリーンショット 2020-09-29 14.53.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653972/5014199d-175c-398a-066a-e1240dc5df5b.png)

データベース設定の中の`Disable Sign Ups`を以下のようにONにします。

![スクリーンショット 2020-09-29 14.58.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653972/850711f8-9ea8-a128-ffd0-204014a17e27.png)
この設定だけでUniversal LoginからSignUpの選択肢が消えます。

Classicの場合は以下のようにLogin、SignUpのタブが消え、ログインのみが可能になります。
![スクリーンショット 2020-09-29 15.04.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653972/bbb7916e-1a56-bab9-5dc4-9384280a7047.png)

Newの場合は下のほうに表示されていたSingUpのリンクが消えます。
![スクリーンショット 2020-09-29 15.09.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653972/b835b211-418f-35d8-0983-f79685e80409.png)

# ソーシャルログインによる新規登録の無効化
ここまでの手順でAuth0のデータベースに対する新規登録は無効化することができましたが
これだけだとソーシャルログインによるユーザーの登録を防ぐことはできません。
ソーシャルログインしてきたユーザーがデータベースに存在しない場合はユーザーが作成されてしまいます。

ソーシャルログインを利用しつつ、ソーシャルログインによる新規登録は防ぎたい場合はRulesを使って制御します。
Rulesのテンプレートの中から`Disable social signups`を選択してRulesを追加します。
![スクリーンショット 2020-09-29 15.15.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653972/e6313856-6833-b195-fdc9-13ad7585573e.png)

このRulesを追加した状態でソーシャルログインによる新規登録を行うとエラーが返却されるので
アプリケーション側でエラーハンドリングをしてください。（エラーの詳細は`Disable social signups`のコードを参照してください。）

# ソーシャルログインによる新規登録を無効化するときの注意点
ソーシャルログインによる新規登録の無効化のほうはRulesを使った制御になっているので
データベース設定での新規登録の無効化とは違い、実はデータベース上にユーザーが作成されてしまいます。

Rulesの中でソーシャルログインによる新規登録が行われたユーザーは`app_metadata`に`is_signup`というプロパティが追加されており、これが`true`に場合にログインエラーとしているだけです。
![スクリーンショット 2020-09-29 15.27.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/653972/21bddc5a-c856-626b-639b-19ade1790820.png)

もしも`Disable social signups`のRulesでエラーとなっているユーザーのログインを許可したい場合は
`app_metadata`の`is_signup`プロパティを削除してください。

# おわりに
ユーザー登録をManagementAPIや管理画面からの操作だけでやりたい場合は
Universal Loginからの新規登録の無効化もぜひ一緒にやってみてください。
RailsにおけるCRUD機能とMVC

## はじめに
初学者のアウトプット用記事です。
ご指摘していただけると幸いです。

## CRUD機能とは？
システムに必要な4つの主要機能である「Create（生成）」「Read（読み取り）」「Update（更新）」「Delete（削除）」の頭文字を並べた用語

データを操作する際に必要な最低限の機能

CRUDはWEBアプリ制作する上で基本的な考え方になります。

・生成機能（Create）
・読み込み機能（Read）
・更新機能（Update）
・削除機能（Delete）


## MVCとは？
UI（ユーザーインターフェース)を持つアプリケーションソフトウェアを実装するためのデザインパターンの一つ。
簡単に説明すると、自分が指定したページ（URL）はブラウザに表示されるまでに、ルーティング→コントローラー（C）→モデル（M）→ビュー（V）という順で処理が行われている。モデルは必要な時にだけ処理がされるため、必要でない時はとばす。
＊Model(データ) View(画面) Controller(操作)

## MVCなぜできた？
アプリを色々処理する中で画面(UI)の部分とデータを処理する部分で性質が違うのでその2つを一緒にコードを書いてしまうと複雑になってしまうので`見た目を担当するView`,`アプリ固有のデータの処理を行うModel`,`ViewとModelをコントロールするController`の役割を3つに分ける事によって管理しやすくしようという理由でMVCというフレームワークが作られた


### M：Model
####データベースを操作する仕組み
Controllerからデータの追加や変更・削除の指示を受け実行します。
データベースのテーブルごとにModelが用意されている。
データベースのテーブルはモデルクラスとモデルクラスから生成されたインスタンスによって作られている。

### V：View
#### ユーザ-に見せるインターフェイスのデザイン（ページの見た目）
app/views （アプリケーションのメインフォルダのビューフォルダに置かれる）
Viewは通常複数用意されていて、それぞれHTMLのような形になっている。そこにはRubyのコードが埋め込んであり、要求されたアクションに応じて該当のHTMLにControllerがModelから受け取ったデータを反映し、HTMLを生成する。

### C：Controller
#### ユーザーリクエストをModelやViewと連携させる仕組み
app/controllers （アプリケーションのメインフォルダのコントローラフォルダに置かれる）
ユーザーからのリクエストを受けModelから必要な情報を受け取り、Viewによって生成されたHTMLを画面に反映させる。
ModelとViewに指示を出す司令塔のような役割。
Viewと同じく複数用意されていて、さらに1つのControllerの中に複数のアクションが用意されている。

コントローラーの中のメソッドを「アクション」と呼ぶ。
ユーザーからのリクエストに対して具体的な処理を実行するためのメソッド。


### ルーティング
#### URLとアプリケーションを結びつける仕組み
config/routes.rb （コンフィグフォルダのルーツファイルに置かれる）
ユーザーがブラウザを経由してアクセスしたURLとコントローラーのアクションを結びつける（＝処理を割り振っている）役割。
自然言語処理と関連する技術（忘備録用）

# はじめに
現在、自然言語処理についての勉強をしており、今回は自分の試したいことに関連する知識をまとめています。
ほぼ忘備録＆目的再認識なので、記事へのリンクのオンパレードになります、ご了承ください。

# なんで自然言語処理なの？
自分たちが日々の生活の中で**文字**の情報が圧倒的に多いと思います。メール、SNS、Webサイトなど様々です。
この溢れに溢れている**文字**を使って機械学習も勉強できるんじゃないか？というのが自然言語処理をやろうとしたきっかけです。
また、近年では自然言語処理に欠かせない技術の精度が上がっており、かつ、手軽に試すことができることも自然言語処理を始める後押しにもなりました。

 - 形態素解析器（Mecabとか）
 - Word2Vec
 - Pythonのgensim　

などなど、一例ですが、今後自分が使用するであろう技術たち

# 自然言語処理で欠かせない「単語の分散表現」について
文字そのままでは計算機が認識できないため、単語を数学的なベクトルで表現しようという試み。
単純に単語一つに対して一つの次元を割り当てると、効率が悪いため、**ある一定の範囲での次元で表現する**ことで、ある程度の精度が得られる。
次の記事がわかりやすい。

 - [なぜ自然言語処理にとって単語の分散表現は重要なのか？](https://qiita.com/Hironsan/items/a58636f946dd51f670b0)

分散表現にも課題はあるが、**自然言語処理の精度を上げる**ために自分ができることは

 - 質の良いテキストデータを集めること（実際に試したいことに関連する単語が多く含まれる記事など）
 - [テキストデータに対しての前処理](https://qiita.com/you_gin/items/03b6e5dc02892131cb9b)

くらい。

# 使うであろうWord2Vec
単語をベクトル化する手法の1つ。Pythonとの相性も良いし、Word2Vecに関する記事も多いので採用すると思う。
Word2Vecの基本的な活用方法として、

- 類義語の予測
- 文章間の類似度の予測

ができる。
使うとしたら、Word2Vecの結果を利用したレコメンドシステムに近いかも。
詳しい概念や使い方は以下の記事を参照。

 - [Word2Vec：発明した本人も驚く単語ベクトルの驚異的な力](https://deepage.net/bigdata/machine_learning/2016/09/02/word2vec_power_of_word_vector.html)
 - [【Python】Word2Vecの使い方](https://qiita.com/kenta1984/items/93b64768494f971edf86)
 - [絵で理解するWord2Vecの仕組み](https://qiita.com/Hironsan/items/11b388575a058dc8a46a)

Word2Vecの仕組みを紹介している記事は勉強しがいがある内容

Word2Vecに似た手法としては、**Doc2Vec**、**text2vec**、**fastText**がある。

 - [[翻訳] text2vec vignette: text2vecパッケージによるテキスト分析](https://qiita.com/nakamichi/items/1bf2ee393cb407d9fb74)
 - [FacebookのfastTextでFastに単語の分散表現を獲得する](https://qiita.com/icoxfog417/items/42a95b279c0b7ad26589)
 - [pythonでfasttextを使って文書分類してみた
](https://qiita.com/ezmscrap/items/b8124324189fc46d9512)
 - [Doc2Vecについてまとめる](https://qiita.com/g-k/items/5ea94c13281f675302ca)

# TF-IDFを使用した類似度計算
文章の特徴となる単語の抽出に使う手法。
概要としては、

 - TF値（文章内の単語の出現頻度）
 - IDF値（ある単語の文書出現頻度の逆数）

となる。
理解しやすい記事→[TF-IDF](https://qiita.com/AwaJ/items/5937665d5a4152cc24cf)

TF-IDFを使って単語の特徴量を算出して、**コサイン類似度**で文章間の類似を求めるのが多いと思う。
コサイン類似度→[[Python] 2つの文書間のcos類似度を計算](https://qiita.com/yonedaco/items/ef6fd0db2773f62b0f72)
TF-IDFについては大学時代に勉強していたので、復習みたいな感じ。
しかし、**Okapi BM25**というTFIDFに似た手法もあった。精度もTFIDFより出る可能性があるとのこと。

 - [【技術解説】単語の重要度を測る？TF-IDFとOkapi BM25の計算方法とは](https://mieruca-ai.com/ai/tf-idf_okapi-bm25/#toc_2)
 - [[自然言語処理/NLP] Okapi BM25についてざっくりまとめ (理論編)](https://dev.classmethod.jp/articles/mrmo-ml-20200422/)

# 実際にできること
今回紹介した技術、手法を使うことで様々なことができる。その可能性は無限大
個人的に興味深かった記事

 - [【Python】🍜ラーメンガチ勢によるガチ勢のためのWord2vec（食べログ口コミコーパスの威力を検証してみた）🍜](https://qiita.com/toshiyuki_tsutsui/items/19590b464f15f845efcd)
 - [【Python】🍜機械学習で「隠れた名店」を探してみた。（そして実際に行ってみた）🍜](https://qiita.com/toshiyuki_tsutsui/items/b3ac8fd1b300c3404508)
 - [【転職会議】クチコミをword2vecで自然言語処理して会社を分類してみる](https://qiita.com/naotaka1128/items/2c4551abfd40e43b0146)
 - [【word2vec】会社のクチコミを自然言語処理した結果を可視化してみる](https://qiita.com/naotaka1128/items/e617f63907fed035408a)
apiにgo言語、フロントをreactの最小構成作った

よくフロントをreact、apiをgo言語でアプリケーションを書くので最小構成のリポジトリ作った

https://github.com/kosukeKK/simple-react-golang-app

構成

```
├docker-compose.yml
├Web/
│ ├Dockerfile
│ └app/
└api/
  ├Dockerfile
  └main.go
```

```
$ docker-compose up
```
cloud9でRuby on Rails開発環境構築"part2"[view層とSlim]

前回: [cloud9でRuby on Rails開発環境構築](https://qiita.com/T_KEIICHI/items/15a64de9912259dea884 "Qiita")の続き

とはいえ、現段階では、ここに書く内容を実行したら、その後エラー出ます。なので、一旦メモがわり。


##ビュー層を効率よく書く為にSlimを使えるようにする。
何ですかビュー層って。そのうちわかるのかな・・

```text
ビュー は、アプリケーションの見た目（プレゼンテーション）を制御します。Railsでは、index.html.erbといった名前のHTML用のテンプレートがこれに当たります。
```
~~って書いてるサイトがあったのでとりあえずコレで納得して先に進みます💦~~
~~※理解できたら戻って来て完成させます。~~
**わかりやすいサイト見つけました！**
納得:[Rails,Laravelを使う前に知っておきたいMVCアーキテクチャ](https://web-nari.net/2018/08/26/post-1463/ "MVC")

RailsにはデフォルトでERBと言うテンプレートエンジンが入ってるけど、現場で多く使われているのは**Haml**か**Slim**らしいです。
なので、今回はSlimを使っていきます。
##Slimを利用する為に２つのgemをアプリケーションに追加

1. Slimジェネレーターを提供してくれる**slim-rails**と言うgem
2. ERB形式のファイルをSlim形式に変換してくれる**erb2slim**コマンドを提供してくれる**html2slim**と言うgem。

###アプリケーションが利用するgemはGemfileに定義
```text

gem 'tzinfo-data', platoforms: [:mingw, :mswin, :x64_mingw, :jruby]

#⬇️ここに
gem 'slim-rails'
gem 'html2slim'
```
bundleコマンドを実行して**Gemfile**に書かれたgemをすべてインストールされた状態にします。

```terminal
$ bundle
```
OK

ついでに、（ここは後ほど追記）

```terminal
$ bundle exec erb2slim app/views/layouts/ --delete
```

次回:[cloud9でRuby on Rails開発環境構築"part3"[Bootstrap/Sass/エラー日本語]](https://qiita.com/T_KEIICHI/items/ad89a672ee0c37c6c63b "part3")
PHP [コンストラクタ　クラスの継承]

# コンストラクタ
![スクリーンショット 2020-09-29 22.05.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/663122/9e784407-fc02-fcd8-3f4e-a97fb9ee250c.png)

__construct($text, $likes)
__construct($text, $likes)
newをした時にこちらの$textと$likesは下記から代入されています。
$posts[0] = new Post('hello', 0);
$posts[1] = new Post('hello again', 0);

# public private
publicは、クラスの中でも外でも使用する事ができる。
privateは、クラス内でしか使用できなくする。
こういうpublic privateはアクセス修飾子と呼ばれる。

# declare
declareとは、declare(strict_types=1);と最初に記述する事で、厳密に型をチェックしてくれます。

## クラスの継承
![スクリーンショット 2020-09-30 12.44.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/663122/5770bfe0-9a6c-a9a5-c201-cf5570542bda.png)
上記の画像の様に、
class 新しいクラス名　<font color="Red">extends</font> 親クラス名
とする事で、親クラスの中を引き継げる。
ちなみに、
class Post　親クラス　又は　superクラス
class SponsoredPost extends Post　子クラス　又は　subクラスと呼びます。　
# override
親クラスと同じメソッド定義する事をoverrideという。
### protected
overrideする時にプロパティのアクセス修飾子がprivateになっているとエラーが出てしまう。
そこで、privateを<font color="Red">protected</font>とする事で、そのクラスと継承したクラスしか使えなくなる。
また、<font color="Red">override</font>をうっかりして欲しくない時に、<font color="Red">override</font>して欲しくない方のアクセス修飾子の前に、<font color="Red">final</font>をつけます。
FCM の onDeletedMessages() は呼ばれるのか？


## 最初に

FCM の Android 版にはメッセージがデバイスが１ケ月以上オフラインだったり、接続されたときに未読メッセージが100件を超えてる場合は **onDeletedMessages() が呼ばれることがある** とあります。


**[onDeletedMessages のオーバーライド](https://firebase.google.com/docs/cloud-messaging/android/receive?hl=en#ondeletedmessages-)**

```
状況によっては、FCM からメッセージが配信されないことがあります。
これは、特定のデバイスが接続されたときにそのデバイスにまだ配信されていないアプリのメッセージが多すぎる（100 件を超えている）場合や、
デバイスが 1 か月以上 FCM に接続されていない場合に起こります。

このような場合、FirebaseMessagingService.onDeletedMessages() へのコールバックを受け取ることがあります。
アプリ インスタンスがこのコールバックを受け取った場合は、
アプリサーバーとの完全な同期を実行する必要があります。

過去 4 週間以内にそのデバイスのアプリにメッセージを送信していない場合、onDeletedMessages() は呼び出されません。
```


### 実験してみた
端末を機内モードに設定しインターネットに接続できない状況で、
**110 件** のプッシュ通知を送信してみました。

```
{
  "priority" : "high",
  "data" : {
     "title" : "{val}",
     "message" : "hello",
  }
}

条件：
・10秒毎に１件送信
・カスタムペイロードで送信
※{val} には「送信件数」が入るようにしています
送信内容が完全同一の場合に１通にまとめられる可能性を（念の為に）潰してます
```

機内モードを解除し、インターネット接続ができるように戻します。
結果、、、

##### 何度やっても onDeleteMessages() が呼ばれません。

### なぜ？

これはおかしいと思い、翻訳が間違ってるのかなと思い原文を読み直しました。

```
In some situations, FCM may not deliver a message.
This occurs when there are too many messages (>100) pending for your app on a particular device 
at the time it connects or if the device hasn't connected to FCM in more than one month. In these cases, you may receive a callback to FirebaseMessagingService.onDeletedMessages()
When the app instance receives this callback, it should perform a full sync with your app server.

If you haven't sent a message to the app on that device within the last 4 weeks, FCM won't call onDeletedMessages(). 
```
条件として
・特定のデバイスでアプリに対して保留中のメッセージが多すぎる（> 100）場合
・接続時、またはデバイスが1か月以上FCMに接続されていない場合

とあり And 条件ではなく OR と書かれています。
ただ「必ず呼ばれる」とは書かれておらず may と表現されてるので、呼ばれないケースも普通にあるということですね。。

### やり方を変えてみた
機内モードにするのと「端末の電源オフ」では内部事情が違うのではと思い、
**電源を切ってる状態で110件送ることにしました。**

その結果、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/486398/a196b4a3-7d62-50d7-c8f3-4d9af38f997a.png)

##### アプリを起動後１０秒ほど経過後に onDeletedMessages() がコールされました！

呼ばれないだろと思ってただけにちょっと感動しました。

### 結論
**onDeleteMessages() は実際にテストする事ができます。**
なお今回の検証では FCM バージョンは v20.2.4 を利用ました。


なお [stackオーバーフロー](https://stackoverflow.com/questions/45244521/firebase-cloud-messaging-ondeletedmessages-not-called) に **2つの条件が重なったときに呼ばれる** と記載してる方もいますが、
原文ではそのように記載されおらず、片方の条件だけでも呼ばれることが確認できました。
新卒が郵便番号の扱いに困った話

新卒エンジニアの@yhorikawaです。
新卒で入社してからこれまで郵便番号を扱うことが多かったのですが、郵便番号の仕様を知らず困った個所が複数あったのでまとめようと思います。
また、日本郵政のcsvに関してもいくつかまとめます。

## 郵便番号から住所は一意に決まらない
郵便番号から住所を検索する際に郵便番号から住所が一意に決まると思っていましたが、実際には1つの郵便番号で複数の住所を持つ場合がありました。
例えば080-1189の場合
北海道河東郡士幌町共豊
北海道河東郡士幌町士幌（南一区１８号～２１号南）
北海道河東郡士幌町東台
北海道河東郡士幌町富秋
北海道河東郡士幌町中士幌
北海道河東郡士幌町中士幌勝和
北海道河東郡士幌町中士幌北
北海道河東郡士幌町中士幌北団地
北海道河東郡士幌町中士幌共進
北海道河東郡士幌町中士幌新東団地
北海道河東郡士幌町中士幌新南
北海道河東郡士幌町中士幌西
北海道河東郡士幌町中士幌東団地
北海道河東郡士幌町中士幌文化
北海道河東郡士幌町中士幌豊進
北海道河東郡士幌町中士幌南
北海道河東郡士幌町中士幌明生
のように17件存在しています。
私のように一意に決まると思い込んでいると意図した検索結果にならないので気を付ける必要があります。

## 同じ郵便番号でも別の都道府県の場合がある
郵便番号から住所は一意に決まらないが県は一意に決まるだろうと思っていましたが、3つ郵便番号が同じでも都道府県が違う郵便番号があるそうです。

```
498-0000 愛知県弥富市, 三重県桑名郡木曽岬町
618-0000 京都府乙訓郡大山崎町, 大阪府三島郡島本町
871-0000 福岡県築上郡吉富町大分県 中津市
```

## 階数が多い建物は階ごとに郵便番号が振られている場合がある
階数が多い大きな建物の場合郵便番号がその建物の階ごとに割り振られている場合があります。

## 日本郵政のCSVを使用する場合に気を付けること
日本郵政が配布している[郵便番号データ](https://www.post.japanpost.jp/zipcode/download.html)を使用する場合に気を付けることです。
### 1. レコードが複数の行に分割されている
1つのレコードが複数行に分割されてはいっている場合があります。
例えば京都府の住所ですが

```
26102,"602  ","6028368","ｷﾖｳﾄﾌ","ｷﾖｳﾄｼｶﾐｷﾞﾖｳｸ","ｷﾀﾏﾁ","京都府","京都市上京区","北町（上の下立売通天神道西入上る、上の下立売通御前西入、上",0,0,0,0,0,0
26102,"602  ","6028368","ｷﾖｳﾄﾌ","ｷﾖｳﾄｼｶﾐｷﾞﾖｳｸ","ｷﾀﾏﾁ","京都府","京都市上京区","の下立売通御前西入上る、上の下立売通御前西入２丁目、上の下立売通御前西入",0,0,0,0,0,0
26102,"602  ","6028368","ｷﾖｳﾄﾌ","ｷﾖｳﾄｼｶﾐｷﾞﾖｳｸ","ｷﾀﾏﾁ","京都府","京都市上京区","２筋目、下長者町通御前西入、天神道上の下立売上る、天神道仁和寺街道下る、",0,0,0,0,0,0
26102,"602  ","6028368","ｷﾖｳﾄﾌ","ｷﾖｳﾄｼｶﾐｷﾞﾖｳｸ","ｷﾀﾏﾁ","京都府","京都市上京区","天神道下立売上る、天神道妙心寺道上る、天神道妙心寺道上る西入、仁和寺街",0,0,0,0,0,0
26102,"602  ","6028368","ｷﾖｳﾄﾌ","ｷﾖｳﾄｼｶﾐｷﾞﾖｳｸ","ｷﾀﾏﾁ","京都府","京都市上京区","道天神道西入下る、仁和寺街道天神道東入下る、御前通上の下立売上る、御前通",0,0,0,0,0,0
26102,"602  ","6028368","ｷﾖｳﾄﾌ","ｷﾖｳﾄｼｶﾐｷﾞﾖｳｸ","ｷﾀﾏﾁ","京都府","京都市上京区","上の下立売上る西入、御前通下立売上る、御前通下長者町上る西入、御前通仁",0,0,0,0,0,0
26102,"602  ","6028368","ｷﾖｳﾄﾌ","ｷﾖｳﾄｼｶﾐｷﾞﾖｳｸ","ｷﾀﾏﾁ","京都府","京都市上京区","和寺街道下る西入、御前通妙心寺道上る西入、御前通西裏上の下立売上る、御前",0,0,0,0,0,0
26102,"602  ","6028368","ｷﾖｳﾄﾌ","ｷﾖｳﾄｼｶﾐｷﾞﾖｳｸ","ｷﾀﾏﾁ","京都府","京都市上京区","通西裏下立売上る）",0,0,0,0,0,0
```

これで一つの住所になっています。
csvの中では複数レコードに分かれて入っているため、一行ずつ取り出すような操作をする際は気を付けなければいけません。

### 2. ()に様々な情報が書かれている
上の京都の例の場合は()の中に通りの名前が書かれていますが、それ以外にも()の中に様々な情報が書かれています。

```
453-0002 愛知県名古屋市中村区名駅（１－１－８、１－１－１２、１－１－１３、１－１－１４、１－３－４、１－３－７）
450-0002 愛知県名古屋市中村区名駅（その他）
```

のように()の中に条件が入っている場合があるので注意する必要があります。

### 3. 「以下に記載がない場合」の存在
010-0000等のように以下に記載がない場合といった文言が入っているレコードがあります。
この以下とはそのレコード以下のことを表すのですが、これも1行ずつ取り出して保存する処理などの場合にそのまま保存すると困る場合があるので注意が必要です。

## 最後に
今回は実際に自分自身が業務で郵便番号を扱う中で困った個所についてまとめました。
これ以外にも知らないと困る箇所はあるのかなと思います。
これらが改善されたデータが配布されたらいいなと思いました、、、

## 参考にした記事
https://qiita.com/_takwat/items/3a121656425fac7bb820
SwiftUIのViewModifierを使ってViewをカスタマイズする

## はじめに
SwiftUIには`ViewModifier`というViewへのカスタムModifierを作成することが可能です。
`ViewModifier`を使うことで、SwiftUIのViewを汎用的にカスタマイズすることができます。
今回はそんな`ViewModifier`についてまとめていきます。

## ViewModifierについて
Viewに対して適用させることで、Viewをカスタマイズして返却する機能を実装するための`protocol`です。
`ViewModifier protocol`に定義されている関数は下記です。

```swift
func body(content: Self.Content) -> Self.Body
```
本関数の中でViewの更新、または変換処理を行い返却を行います。
`content` は修飾する対象のViewのプロキシです。
`Self.Body`は`associatedtype`で定義されており、Viewの変換処理に返すViewの型をここに記述します。

## ViewModifierを使用する
単純なViewをカード型のViewに変換するためのカスタムModifierを作成してみます。
やることは単純で、カスタムModifierの構造体を作成し、`body(content:)`の引数である`content`に対して値を適用して返却するようにします。
あとは、適用したいViewに対してを使って作成したModifierを適用します。

```swift
struct CardModifier: ViewModifier {
    func body(content: Content) -> some View {
        content
            .padding(16)
            .background(Color.white)
            .cornerRadius(10)
            .shadow(radius: 5)
    }
}

struct ContentView: View {
    var body: some View {
        VStack {
            // .modifier(_:)、 ModifiedContent(content:modifier:)のどちらでも適用可能です。
            Text("Hello, world!")
                .modifier(CardModifier())
            ModifiedContent(content: Text("Hello, world!"),
                            modifier: CardModifier())
        }
    }
}
```
上記により、該当のViewはカスタムModifierに記載された変更が下記のように適用されます。
![スクリーンショット 2020-09-30 21.45.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/556106/1111cd03-968e-5cf8-9328-00636834d38c.png)

## おわりに
`ViewModifier`を使うことで、複数のViewに適用するレイアウトなどを汎用的に定義することができると思います。
SwiftUIはメソッドチェインでレイアウトを記載していくため、同じレイアウトを定義する際に全てベタ書きで複数同じ処理が並んでしまうと可読性が悪くなってしまいます。
綺麗なコードを保っていくにも、同じレイアウトのViewについてはカスタムModifierでまとめていくのが良いかと思います。

## 参考文献
- [ViewModifier | Apple Developer Documentation](https://developer.apple.com/documentation/swiftui/viewmodifier)
魚眼レンズの歪みを画像に付加させてみる

びぼうろく
http://www.sanko-shoko.net/note.php?id=wvb7

```python

import numpy as np
import open3d as o3d
import cv2
import math

# 一つあたりの格子の長さ
CONST_IMG_PER_WIDTH = 10
CONST_IMG_PER_HEIGHT = 10

# 格子の数
CONST_IMG_NUM_WIDTH = 100
CONST_IMG_NUM_HEIGHT = 100

RGB_WHITE = [255,255,255]
RGB_BLACK = [0,0,0]

def write_point_cloud(path,pcl):
    assert o3d.io.write_point_cloud(path, pcl),"error : fail to write pointcloud  = " + path

def exportPLYfromNumpy(nplist, colorList, outputPath):
    pcd = o3d.geometry.PointCloud()
    pcd.points = o3d.utility.Vector3dVector(nplist)
    pcd.colors = o3d.utility.Vector3dVector(colorList)
    write_point_cloud(outputPath, pcd)
    return pcd

def TransformPointI2C(uv,depth,K):
    X = float(float(uv[0] - K[0][2]) * depth / K[0][0])
    Y = float(float(uv[1] - K[1][2]) * depth / K[1][1])
    Z = depth
    CameraPos3D = np.array([[X], [Y], [Z]])
    return CameraPos3D

width_whole = (CONST_IMG_PER_WIDTH+1)*(CONST_IMG_NUM_WIDTH)+1
img_parallel_grid = []
img_parallel_grid.append([RGB_BLACK] * width_whole)
hrange = range((CONST_IMG_PER_HEIGHT+1)*(CONST_IMG_NUM_HEIGHT))

h_cnt=0
for h in hrange:
    h_cnt += 1
    if h_cnt == CONST_IMG_PER_HEIGHT+1:
        tmpimg = [RGB_BLACK] * width_whole
        h_cnt=0
    else:
        tmpimg = [RGB_WHITE] * width_whole

    for w in range(width_whole):
        if CONST_IMG_PER_WIDTH*w+w < len(tmpimg):
            tmpimg[CONST_IMG_PER_WIDTH*w+w] = RGB_BLACK
    img_parallel_grid.append(tmpimg)

img_parallel_grid=np.array(img_parallel_grid)
print(img_parallel_grid.shape)

print(img_parallel_grid)
cv2.imwrite('grid_img.png', img_parallel_grid)

print(img_parallel_grid.shape)
img_height = img_parallel_grid.shape[0]
img_width = img_parallel_grid.shape[1]
f = 10
ch = img_height/2
cw = img_width/2
K = np.array([[f,0,ch],
              [0,f,cw],
              [0,0,1]])

depth = 10 # 固定値
pointcloud=[]
colorList=[]
for h in range(img_height):
    for w in range(img_width):
        if img_parallel_grid[h][w].tolist() == RGB_BLACK:
            XYZ = TransformPointI2C([h,w], depth , K)
            pointcloud.append(XYZ.tolist())
            colorList.append(RGB_BLACK)
pcd = exportPLYfromNumpy(pointcloud, colorList, 'grid_pcl.ply')

# http://www.sanko-shoko.net/note.php?id=wvb7
points = pcd.points
k1 = 0.0
k2 = 0.0
k3 = 0.0
k4 = 0.0

# 真っ白な空のイメージ用意
img_disto = np.full(img_parallel_grid.shape,255)

pointcloud=[]
colorList=[]
for point in points:
    X = point[0]
    Y = point[1]
    Z = point[2]

    a = float(X/Z)
    b = float(Y/Z)
    r = math.sqrt(a**2 + b**2)
    tht = np.arctan(r)
    tht2 = tht**2
    tht4 = tht**4
    tht6 = tht**6
    tht8 = tht**8
    theta_d = tht * (1 + k1*tht2 + k2*tht4 + k3*tht6 + k4*tht8)

    u_d = (a*theta_d)/r
    v_d = (b*theta_d)/r

    u = (u_d-ch)/f
    v = (v_d-cw)/f

    pointcloud.append([u,v,f])
    colorList.append(RGB_BLACK)
pcd = exportPLYfromNumpy(pointcloud, colorList, 'disto_pcl.ply')

#
#     img_disto[u_d][v_d]=np.array(RGB_BLACK)
# cv2.imwrite('disto_img.png', img_disto)


```
【新人注目】マジックナンバーは使わないで・・・。

## マジックナンバーとは
実際に僕が書いたコード・・・

``` ruby
 prefectures = Prefecture.where(area_id: 3)
 cities = City.where(prefecture_id: 13)
```
こんなコード。
ようするに`自分以外の人が見たら何の数字のことかわからない番号`のこと。

自分の頭の中では,,,
``area_idの3は``関東
``prefecture_idの13は``東京都
という感じで当たり前のようにコードを書いていた。


## 変更後のコード
``` ruby
  kantou = Area.find_by(name: '関東')
  prefectures = Prefecture.where(area_id: kantou)
  tokyo = Prefecture.find_by(name: '東京都')
  cities = City.where(prefecture_id: tokyo)
```

番号を使うのではなく、誰が見てもすぐにわかる変数に格納した。
Djangoでformから読み込んだPIL形式の画像をbase64形式に変換する

# はじめに
メモ程度なので、Djangoの細かい設定は省きます。
プロジェクトはimage_pred, アプリ名はmyappとしています。
設定は公式ページの最初の部分にあるような基本的なところしかやっておりません。
#プログラム
index.htmlから、フォームを使って画像を送ります。

```index.html
{% load static %}
<!doctype html>
<html lang="ja">
<head>
 <meta charset="utf-8">
 <title>title</title>
</head>
<body>
   <div id = "input_form">
      <form action="{% url 'index' %}" method="POST" enctype="multipart/form-data">
         {% csrf_token %}
         {{ form }}
         <input type="submit" value="送信" />
      </form>
   </div>
   <!--<div id = "prevent"><img src="{{question_id}}"></div>-->
   <div id = "predict">{{urls}}</div>
</body>
</html>
```

```python:forms.py
from django import forms

class PhotoForm(forms.Form):
    image = forms.ImageField(label='画像を選択してください')
```

```python:views.py
from django.shortcuts import render, redirect
from django.http import HttpResponse
from django.views.generic import TemplateView
from .forms import PhotoForm

class MyappView(TemplateView):
    def __init__(self):
        self.params={'form': PhotoForm()}
        
    def get(self, req):
        return render(req, 'index.html', self.params)

    def post(self, req):
        form = PhotoForm(req.POST, req.FILES)
        if not form.is_valid():
            raise ValueError('invalid form')

        image = form.cleaned_data['image']
        self.url_get(req, image)
        return render(req, 'index.html', self.params)

    def url_get(self, req, url):
        from PIL import Image
        import base64
        import io
        from io import BytesIO

        img = Image.open(url)
        with io.BytesIO() as output:
            img.save(output,format="JPEG")
            contents = output.getvalue()
            data = base64.b64encode(contents)
            #print('data:image/jpeg;base64,' + str(data)[2:-1])
            self.params['urls'] = 'data:image/jpeg;base64,' + str(data)[2:-1]
```

# 結果
最初の画像です。ファイルを選択して、認識をクリックします。
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/681100/d16ab151-1620-6aa2-15c2-92f7978a29a3.png)

このような結果が表示されると思うので、これを元に画像を表示することができます。
![キャプチャ3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/681100/6143276c-1f1a-b9a6-ff6e-cf4eb7d879a4.png)

# 参考文献
プロジェクトの作成などは、この資料に基づいているので、プログラムも同一の部分は多くあります。
https://trafalbad.hatenadiary.jp/entry/2018/09/11/105500
【Ruby on Rails】Scopeに変数を渡す。

業務でscopeについて少し戸惑ってしまったので、備忘録としてここにまとめておきます。
ちなみに書いている人間は、エンジニア歴１ヶ月の人間です。
間違っている点などあれば、コメントお願いいたします。

## やりたかったこと
each分の変数をscopeに渡したい。

##　実際のコード
``` Office.rb
  scope :search, lambda { |keyword|
                   where('name LIKE (?) OR
                          address LIKE (?) OR
                          near_station LIKE (?) OR
                          introduction LIKE (?) OR
                          company LIKE (?)',
                          "%#{keyword}%",
                          "%#{keyword}%",
                          "%#{keyword}%",
                          "%#{keyword}%",
                          "%#{keyword}%")
                        }
```

``` offices_controller.rb
      keywords = params[:keyword].split(/[[:blank:]]+/).select(&:present?)
      offices_list = []
      keywords.each do |keyword|
        offices_list += Office.search(keyword)
```
コードは一部だけ抜粋していますが、このような形で実装することができました。
最終的には、上記のコードになりましたが下記のコードでも正常に動作はしました。

``` Office.rb
  scope :search, keyword { where('name LIKE (?) OR
                          address LIKE (?) OR
                          near_station LIKE (?) OR
                          introduction LIKE (?) OR
                          company LIKE (?)',
                          "%#{keyword}%",
                          "%#{keyword}%",
                          "%#{keyword}%",
                          "%#{keyword}%",
                          "%#{keyword}%")
                        }
```
30日でできるOS自作入門　5日目（前半）の疑問点と回答

30日でできるOS自作入門　5日目

######p.97「0x0ff4とかの番地がいったいどこから出てきたのか？」「asmhead.nasに数字を合わせただけ」asmhead.nasってもともとなんだっけ？

→3日目までharibote.nasだったもの。
p.62を見てみる。

```nasm:haribote.nas
CYLS	EQU		0x0ff0			; ブートセクタが設定する
LEDS	EQU		0x0ff1
VMODE	EQU		0x0ff2			; 色数に関する情報。何ビットカラーか？
SCRNX	EQU		0x0ff4			; 解像度のX
SCRNY	EQU		0x0ff6			; 解像度のY
VRAM	EQU		0x0ff8			; グラフィックバッファの開始番地
;（中略）
MOV		BYTE [VMODE],8	; 画面モードをメモする（C言語が参照する）
MOV		WORD [SCRNX],320
MOV		WORD [SCRNY],200
MOV		DWORD [VRAM],0x000a0000
```
なぜVMODE以降から番地を2つおきに確保しているのか？

→１つの番地当たり1Byte=8bitなので、１つの番地で表せる最大値は　11111111(2)=255
解像度はx方向が320で255を超えてしまうため、2Byteのメモリを確保する必要がある。
実際、その後の代入文では```MOV WORD```を使用している。
VRAMの0x000a0000はBIOSによって決められている値。

0x0ff4の出どころは分かったけど、その元になった0x0ff0っていったい？

```nasm:ipl10.nas
MOV		[0x0ff0],CH		;IPLがどこまで読んだのかメモ
```
→p.63「メモリマップによるとこのへんも誰にも使われていないようでしたので」
筆者が適当に決めて```CYLS```の値をメモした番地。

######p.98「このかたまりは合計12バイトです」charは1Byte、shortは2Byteだから9Byteじゃないの？
```c:bootpack.c
struct BOOTINFO{
    char cyls, leds, vmode, reserve;
    short scrnx, scrny;
    char *vram;
};
```
→p.76に記載がある。
「char *p;でもshort *p;でもint *p;でも、変数pは4バイトの変数です」
「この変数pは『番地』を記憶するための変数だからです」

ポインタは4Byteの変数なので12Byteで正しい。
「番地(vram)」は4Byteの変数として管理されている。その番地に入っている「値(*vram)」は1Byteの変数(char)として管理されている。
クイズゲームの簡単なWEBアプリを作成して

### ■なぜこの記事を書いたのか？
初めて自力でアプリケーションを作成し勉強になったことや反省点があったため
備忘録としてこの記事を作成しようと思いました。

### ■クイズアプリの概要
クイズの〇×ゲームができ、全問回答後には自分の点数と正解を表示する。
テキストファイルを修正することによって問題を追加・削除することが可能。


### 開発環境
- OS：windows10
- 言語：Java.11 HTML
- FW：spring boot
- DB：PostgreSQL
- IDE：eclipse

### 動作画面
![VID_20200929_235418.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/317229/a247670c-ae28-f235-ae6c-ef07606ed885.gif)


### ■勉強になったこと
##### ・複雑な問題はタスクを細かく分解することによって解決しやすくなる

一時回答済みのクイズをDBに登録するなど最初はどのようにすれば解決できるのか皆目もつきませんでしたが
一時回答の変数に格納する、javaからDBに接続する、javaでのDBの更新方法、など問題を細かくし
それぞれの解決方法を探して、組み合わせることによって問題が解決することが多かったです。

##### ・各処理のプログラムをシンプルにする
当たり前ですが、命名は簡潔に、処理はできる限り簡単にすることによってコードの見やすさが段違いにかわり
その上メンテもしやすくなる。

##### ・問題が発生した時は必ずエラー内容を確認すること
最初はエラーコードをまじまじと確認もせずに、解決しようとしていたので時間がかかっていましたが
エラーコードをしっかりと把握し、こういうことで問題が発生しているなとイメージしてから
エラーの解決方法を検索したほうが解決するまでの時間が短くすみ、問題が発生した原因も理解できる
事が多かったです。




### ■反省点
##### ・テストコードを書いておけばよかったこと
コードを書いているうちに冗長なコードが見つかり、リファクタリングを行ったのだが
コードを変更したことによって品質が下がっていないかを簡単に確認できたのではと思いました。

##### ・ビルド環境を整えてからコードを作成すればよかった
処理などアプリが完成してからビルドを行ったたのだが、コンパイルエラーなどどこでつまづいて
いるかが分かりづらかった。依存関係の量が少ないからよかったものの多い場合にエラー起きて1つずつ
解決していかないと思うとぞっとしました。。。

#### ■ソースコード
[github](https://github.com/Akiyoshi999/QuizApp "github")
WorkSpacesの利用者が再起動できるよう制御する

表題の通りです。WorkSpacesを利用する環境で、何らかの原因で再起動が必要になった際に利用者自身がマネジメントコンソール上から再起動できるようポリシーで制御します。

やることはWorkSpacesにIAMユーザ名と一致するタグをつけて、タグの値とユーザ名が一致する場合は再起動を許可するポリシーをつけます。今回は「audit」という名前のIAMユーザを作成し、WorkSpaces側にもタグを追加して制御できる確認をします。


### ポリシー

```
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "workspaces:DescribeWorkspaces",
                "workspaces:DescribeWorkspacesConnectionStatus",
                "workspaces:RebootWorkspaces",
                "workspaces:StopWorkspaces",
                "workspaces:StartWorkspaces"
            ],
			"Resource": "*",
			"Condition": {
				"StringLike": {"aws:ResourceTag/UserName":"${aws:username}"}
			}
        }
    ]
}
```

### WorkSpaces側
WorkSpacesに「UserName:audit」というタグをつけます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/110457/ea727398-56db-8977-de3b-30222fe53522.png)


これで利用者本人だけ再起動できる制御ができました。利用者にAWSへのログインが必要な時点で あまり良い施策ではありませんが、適宜管理部門に連絡していただき対応するより、自分自身で対応できるので利用者にとっても管理部門にとってもやらないよりはマシな案かと存じます。
Alibaba Cloud IoT Platformのデータ可視化について

データ分析と言えば、SQL構文でデータの集約やテーブルの結合などのイメージが多いではないでしょうか。実は、データの可視化も一つの強力な手段だと。特にIoT企業において、全てのデバイスはどこにあるのか、どういった状態(有効化かどうか)になっているのか、「可視化機能」でデバイスを管理できるならば、一目瞭然になります。
今回の記事はAlibaba Cloud IoTプラットフォームを利用して、[Link Analytic](https://help.aliyun.com/product/113682.html?spm=a2c4g.750001.list.257.1b107b13XJmz6e)の可視化機能をご説明いたしたいと思います。

## Link Analyticsとは
Link Analyticsとも呼ばれるIoTデータ分析は、Alibaba CloudがIoT開発者に提供するデバイスインテリジェンス分析サービスです。また、デバイスデータ管理、ETL、分析、可視化などの沢山の機能を網羅しています。 
早速可視化の機能を使ってみましょう。
## Link Analyticsの可視化
- Step 1 プロダクトを作成
こちらは一例として、空気品質計測器を作成します。
<img width="747" alt="スクリーンショット 2020-03-23 14.51.14.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/265269/ac94f4ac-b345-18a8-cf3d-2f7354647a9c.png">

- Step 2 デバイスを追加
さっき作成したプロダクトの下に、デバイスを追加します。下図のように、８つのデバイスを追加しました。
<img width="1142" alt="スクリーンショット 2020-03-23 14.59.36.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/265269/b1c50d48-1151-4869-ff15-815b0ce6696d.png">

- Step 3 経緯度情報をアップロード

現時点IoT PFがサポートされている位置表示方式は、デバイスからの発信 ([Geolocation](https://help.aliyun.com/document_detail/108675.html?spm=a2c4g.11186623.6.570.7e7a6b4e9qxUHi))、IoTコンソールから一括アップロード、および動的推測、3つの方法があります。今回はバーチャルデバイスを利用して、Geolocationの方式で試していきたいと思います。

具体的に、「Online Debug」から「Debug Virtual Device」を選択し、経緯度情報を入力します。

| 項目       |  データ型 |    説明    |
|:-----------------|:------------------|:------------------|
| Longitude            | double |        地理的な場所の経度を設定する。        |
| Latitude           | double |       地理的な場所の緯度を設定する。       |
| Altitude             |double |        地理的な場所の高さを設定する。        |
| CoordinateSystem |enum  | 座標システムを指定する。座標システムには、次の2種類があります。<br><br>・WGS_84: 国際的な緯経度の座標システム。<br>・GCJ_02: 中国国家調査局から策定した地理位置に従った座標システム。|


<img width="735" alt="スクリーンショット 2020-03-23 18.51.33.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/265269/236abf81-1150-49c8-79f7-bd1f151876c2.png">

- Step 4 可視化
「データ分析」→「可視化」から、新たなプロジェクトを作成します。ここで、下図のように、Step1から作成したプロダクトLADemoを選択します。

![図1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/265269/46aa70a2-4dff-3176-47c7-0ea755e76342.png)

そして、下図のように、デバイスの位置情報は直ちに2D地図上で反映されることが分かると思います。
<img width="995" alt="スクリーンショット 2020-03-23 18.25.35.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/265269/654f1f49-28c1-4000-0edc-c7a39a15a3d9.png">


## 最後

今回はAlibaba Cloud IoT PFの可視化の手順でした。2Dデータの可視化により、デバイスの動作状態をリアルタイムでマップ上に表示し、デバイスの表示と管理が容易になります。なお、データ結果ページのURLを他のユーザーと共有したり、権限制御したりすることも簡単にできます。Alibaba Cloud IoTを試してみる方の参考になれば幸いです。
TypeScriptでコードが書き直されるのはtsconfigのtargetが原因

typescriptなんもわからんので、つまづいたポイントの学習メモです。

# 問題

右も左もわからないままtypescriptを導入してあれこれ触っていたところ、エラースタックに書いた覚えのないコードが存在するという状況に遭遇した。コンパイルされたコードを見たところ、確かにそのようになっていた。

以下はコンパイル例（実際は全然違うけど）

```typescript
class Person {
    name: string
    family: string[]

    constructor(name: string, family: string[]) {
        this.name = name
        this.family = family
    }

    greet() {
        console.log(`Hello! My name is ${this.name}`)
    }

    introFamily() {
        for (let person of this.family) {
            console.log(person)
        }
    }
}
```

これが

```javascript
var __values = (this && this.__values) || function(o) {
    var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
    if (m) return m.call(o);
    if (o && typeof o.length === "number") return {
        next: function () {
            if (o && i >= o.length) o = void 0;
            return { value: o && o[i++], done: !o };
        }
    };
    throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
};
var Person = /** @class */ (function () {
    function Person(name, family) {
        this.name = name;
        this.family = family;
    }
    Person.prototype.greet = function () {
        console.log("Hello! My name is " + this.name);
    };
    Person.prototype.introFamily = function () {
        var e_1, _a;
        try {
            for (var _b = __values(this.family), _c = _b.next(); !_c.done; _c = _b.next()) {
                var person = _c.value;
                console.log(person);
            }
        }
        catch (e_1_1) { e_1 = { error: e_1_1 }; }
        finally {
            try {
                if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
            }
            finally { if (e_1) throw e_1.error; }
        }
    };
    return Person;
}());

```

コンパイルするとこんなんになってしまう。これではエラーの原因を突き止めるのに不便だ。どうにかならないか？そもそも、なぜこんな回りくどいことをしているのか？

# 原因と対策

`tsconfig.json`の`target`が、初期設定の`ES5`になっていた。typescriptにはスクリプトをES準拠に書き直してくれる機能がある。`class`やら`for-of`やらはES5にはないので、ES5でも動くようにコンパイラが自動で書き直してしまう、というわけだ。
スクリプトを環境に左右されずに動作させるための機能だが、今回は自分の環境だけで動けばよいので、生成されるコードはモダンな方が良い。よって、`target:"ES2019"`とすることで解決した。

```javascript
class Person {
    constructor(name, family) {
        this.name = name;
        this.family = family;
    }
    greet() {
        console.log(`Hello! My name is ${this.name}`);
    }
    introFamily() {
        for (let person of this.family) {
            console.log(person);
        }
    }
}
```

コンパイル結果が書いたソースほぼそのままになった。
[対応状況](https://node.green)を見ると、node 14.12.0なら一通りes2019の構文に対応している様子。

いやしかし、typescriptなんもわからん…。ソースマップを出力すればスタックトレースに出るよ！みたいな話も見た気もするんだけど。詳しい方教えて下さい。

#参考
[tsconfig.jsonの全オプションを理解する（随時追加中）](https://qiita.com/ryokkkke/items/390647a7c26933940470)
サーバーレスWeb APIを作ってみよう

API GatawayとFunction Computeと連携して、どのようにサーバーレス構成のWebサービスを作るのかをステップバイステップでこの記事でまとめたいと思います。

ロジックは非常に簡単ですが、Function Computeはイベント駆動型サービスなので、言い換えれば、関数をトリガーするイベントによって実行します。イベント設定に関しては、API GatawayでバックエンドサービスをFunction Computeに指定すれば、リクエストが来た時その関数をトリガーし、実行した結果をAPI Gatawayに返すとの流れです。

## Step1　Functionを作る

テンプレートを使いたいので、「テンプレート関数」と「api-gateway-nodejs6」を選択します。
![屏幕快照 2020-10-18 11.58.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/265269/49bbac74-cdba-8d41-0011-71a88e091b97.png)
関数の設定を行います。サービス名を入力し、それ以外は一旦デフォルトのままでOKです。
![屏幕快照 2020-10-18 11.53.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/265269/809d0bc9-3ea1-18ba-1b6a-9775307ab6b4.png)
## Step2　API Groupを作る

API作成を進める前に、まずAPI Groupを作る必要があるので、「インスタンス」を変更できないようで、グループ名だけを入力すればOKです。
![屏幕快照 2020-10-18 12.43.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/265269/eb407348-5ef8-66c2-c336-8517fac03702.png)

## Step3　APIを作る
キャプチャのように、APIを作成します。赤枠の認証部分は落とし穴ですので、要注意です。
セキュリティ認証はAlibabaCloudアプリを選定した場合のみ、APPCode認証を使うかどうかとの選択肢が表示されます。APPCode認証は基本的に同くAPI認証の役割を担っていますが、ただ署名などのオーバーヘッドの処理が必要ないので、効率が良いなどの利点が挙げられます。リリー後にオープンするのはお勧めです。
![屏幕快照 2020-10-18 17.00.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/265269/3921d1b6-8633-90ea-71ea-97ffdb5c2750.png)
次はAPIリクエストの定義を行います。リクエストモードに「パラメーターをパススルー」を選択しても良いです。
![111.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/265269/e481a9e4-7eac-28a1-6c95-e184aff23156.png)
そして、バックエンドを「FunctionCompute」を指定します。先ほど作成した関数名「demo001」を入力。
![屏幕快照 2020-10-18 18.24.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/265269/1634097d-0c67-4a0b-4540-06c618defd90.png)
最後「レスポンスの定義」を設定します。JSON、XML、バイナリなどの形式を勿論選択することができます。
![屏幕快照 2020-10-18 18.28.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/265269/6e43aa80-7aa9-216b-4dda-3e3e3719f068.png)
## Step4　動作確認
API Gatewayがテスト用の機能が統合されてますので、サードパーティのテストツールを使わず一ヶ所で済むのは便利だと思います。

具体的には、下記の「API使用」から「アプリ」→「アプリの作成」を選択します。
![屏幕快照 2020-10-18 18.41.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/265269/5c6b6280-ad60-94f4-0b72-45655a47706d.png)
アプリ作成ができたら、AppKeyとAppCodeも自動的に生成してくれます。
![屏幕快照 2020-10-18 18.45.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/265269/ce031398-060e-9f7e-d126-6314d23583ea.png)
いよいよ動作確認をやりますが、さっき作成したAPIの「認証」操作を選択したら、下図の画面が出ますので、「ステージ」をテストにし、「アプリ」を作成済みの「AppDemo」にします。
最後はAPIをテスト環境にデプロイしなければいけないので、気をつけましょう。
![屏幕快照 2020-10-18 18.49.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/265269/5aa4f716-206f-ba69-366b-b84e67246545.png)
「デバッグ」操作を選択したら、下記表示された画面でリクエストを発行してテストすることができます。認証方式はAPI署名との形でテストAppは先ほど承認を付与した「AppDemo」となっています。
![屏幕快照 2020-10-18 22.42.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/265269/a4948b28-e47d-ae69-dda1-caf46bf1c6b5.png)

## 最後
この記事でHTTPS対策、OpenID Connect認証、JWTのToken認証など高度なセキュリティ設定を触れなかったですが、必要な方はAlibabaCloud公式ドキュメントを参考にしてもらえば簡単に設定できると思いますので、ぜひ触ってみてください。
AWS 認定ソリューションアーキテクト – プロフェッショナル合格(2020/9/28) 

# 経緯
AWS SAPに合格した為、勉強方法を忘備録として記載します。
非常に大変でした。
以下、元々の経験値と勉強方法を記載します。
あくまで参考としてお読み下さい。

# AWS経験値
2年

## 経験のあるサービス
- Route53
- ACM
- Lambda(Python3)
- AWS Config
- GuardDuty
- Inspector
- CloudFormation
- CloudWatch Logs/Events
- S3
- RDS
- ECS
- EKS(案件ではなく、勉強がてら)
- EC2
- Fargate
- ALB
- CodeCommit
- CodeBuild
- CodeDeploy
- CodePipeline

# 学習
## 期間
6月末　参考書購入
9月末　試験受験

6月よりも前から模擬問題を解いてはいましたが、体系的に学べずモチベーションが上がりませんでした。
その為、本格的に始めたのは参考書の購入からです。
(模擬問題を2月と9月に受けたのが勿体ない・・・)

## 勉強時間
平日:0～3時間
土日:6～10時間

家で勉強ができない(しない)

## 参考書籍

- [AWS認定ソリューションアーキテクト-プロフェッショナル ~試験特性から導き出した演習問題と詳細解説](http://www.ric.co.jp/book/contents/book_1248.html)

参考書がなく苦しんでいる時に参考書が発売になりました。🙏
3章までは知っておくべき知識の概要
4章から8章は試験に沿った内容になっており、
プロフェッショナルの難易度と傾向を体感できました。
この本読み、他の模擬問題を解くを繰り返していました。

## 知識を整理
AWSの案件に携わっていても使用するサービスに偏りがあったり、特定機能しか触らないこともよくあるかと思います。
kinesisシリーズやIDフェデレーション関係、DynamoDB、分析系のサービスなど書きだしたらキリがないくらい触ったことのないサービスがたくさんあります。
模擬問題でもよく間違えてしまうので付け焼き刃的に覚えるのではなくノートにまとめることにしました。

## 参考にしたもの
- [BlackBelt AWS サービス別資料](https://aws.amazon.com/jp/aws-jp-introduction/aws-jp-webinar-service-cut/)
- Youtube
    - サービス名を検索するとBlackBeltの動画や過去のAWS Summitの動画などが配信されています。
    - 触れたことのないサービスは文字よりも動画のほうが頭に残りました。

公式の資料が無料で配信されており、とても有益なものばかりです。(ありがたい・・・)

## あとはひたすら模擬試験
試験直前は某所の模擬問題を順番にひたすら説きました。
答えを覚えてしまうと意味がないのでそうならない様に様々な問題を解きました。
(答えを覚えないので正答率が上がらずしんどかった)

## 学習に関して振り返ると
- 試験ガイドをちゃんと読む
    - [公式PDF](https://d1.awsstatic.com/training-and-certification/docs-sa-pro/AWS%20Certified%20Solutions%20Architect%20-%20Professional%20Exam%20Guide%20001%20v.1.1%20JPN.pdf)
    - 公式トレーニングやらホワイトペーパーがちゃんとリンク付けされてますね・・・

- よくある質問を読む
    - 一部のサービスで設定の項目まで求められる

- サービスの用途や実現できる/できないことを把握する
    - 使い分け
        - EC2かLambdaか
        - KinesisかSQSか
        - どの分析ツールか
        - CloudFormationかService Catalogか
        - 等々
- 移行戦略を理解する
- デプロイ戦略を理解する
- DR戦略を理解する
- 等々

## 今回受けて感じたこと
- 文章が長い
    - 事前情報通り問題も文章も長い問題があります。正直言って何言ってるかわからないものもありました。<br>そこで集中力と時間を使ってしまうともったいないので、フラグ立てて次に行ったほうが良いと思います。
    - 長い文章から選択肢と関連するワードを見つけるといいです。(「処理に長時間要する」だからLmabdaじゃないなとか)

- 短い問題もある
    - 模擬問題や参考書にやたらと深く問われる問題が多いので、問題全てがそのレベルで理解が必要なのかと絶望していましたが、本番では短い問題もありました。<br>
    油断はダメですが、無駄に壁を高く感じる必要はないかと思います。一区切りついたら一旦受けるのもありかもしれません(3万円ですが・・・💸)

- 問題の意図をちゃんと読む
    - 翻訳された文章のせいか読み解くのが大変ではありますが、「求められるのはコストか信頼性か」などの条件は書いてありますので反対を選ばない様に気を付けて下さい。

- 見直し大事
    - 幸い時間を余らせることができたので見直しする時間を取れました。<br>集中力が切れた状態でも4問くらい直す設問がありました。

# まとめ
- 事前勉強
  - 今まで受けた試験は参考書などの文字だけで事足りていましたが、公式の動画も学習に活用しました。
  - 資料を読むのだけではなく、動画を視聴することで理解が深まり非常に良かったです。
- 試験
  - 本番では見直しできる時間を作れたのは心理的に余裕ができたことも大きいと思います。

どなたかの参考になれば幸いです。

# 余談
- レッドブルと大粒ラムネのおかげかプラッシーボかわかりませんが、割と集中できました。<br>※用法容量をお守りください
- スコアレポートが翌日の19時頃見れた。
    - 2019年のSAAとった時はその翌日朝には見れたのでちょっと不安になりました。
- Markdownのメモが2865行(空行含む)で、容量が139KBになりました。

# めも
問題回答完了 残り時間:80分
見直し完了 残り時間:40分
スコア 829/1000(合格ライン750)
[Python] タイムゾーンを加味したdatetimeを比較するには

# 概要
Pythonでタイムゾーン付きdatetime(aware)とタイムゾーンなしdatetime(naive)で比較しようとするとエラーになったので解消方法をまとめました。

# 環境
```
$ sw_vers
ProductName:	Mac OS X
ProductVersion:	10.15.6
BuildVersion:	19G2021

$ python3 --version
Python 3.7.3
```

# 比較
datetime関数にタイムゾーン情報を渡さずに単純に比較してみると

```
$ cat sample.py
#!/usr/bin/env python3

from datetime import datetime, timedelta, timezone


def main():
    now = datetime.now()
    a_day_ago = datetime.now() - timedelta(days=1)
    print('success') if now > a_day_ago else print('failure')


if __name__ == '__main__':
    main()
```
問題なく比較できました

```
$ python3 sample.py
success
```
ただ、片方にタイムゾーン情報を渡してあげる(aware)と

```
tz = timezone(timedelta(hours=+9), 'Asia/Tokyo')
now = datetime.now(tz)
a_day_ago = datetime.now() - timedelta(days=1)
print('success') if now > a_day_ago else print('failure')
```
エラーとなってしまいました。  

```
$ python3 sample.py
Traceback (most recent call last):
  File "sample.py", line 23, in <module>
    main()
  File "sample.py", line 18, in main
    print('success') if now > a_day_ago else print('failure')
TypeError: can't compare offset-naive and offset-aware datetimes
```
Pythonのdatetimeにはタイムゾーン付きのもの(aware)となしのもの(naive)があるようです。  

ちなみにタイムゾーン付きの者同士で比較すると

```
tz = timezone(timedelta(hours=+9), 'Asia/Tokyo')
now = datetime.now(tz)
a_day_ago = datetime.now(tz) - timedelta(days=1)
print('success') if now > a_day_ago else print('failure')
```
問題なく比較できました。

```
$ python3 sample.py
success
```
違うタイムゾーンで試してみても

```
tz_tokyo = timezone(timedelta(hours=+9), 'Asia/Tokyo')
now = datetime.now(tz_tokyo)
tz_shanghai = timezone(timedelta(hours=+8), 'Asia/Shanghai')
a_day_ago = datetime.now(tz_shanghai) - timedelta(days=1)
print('success') if now > a_day_ago else print('failure')
```
問題なく比較できました。

```
$ python3 sample.py
success
```
datetimeではタイムゾーンの有無を意識していれば比較に困ることはなさそうです。
VisualStudioで、他のソリューションからプロジェクトをコピーする方法


Visual Studio 2019で、**他のソリューションにあるプロジェクトをコピーする方法**です。
簡単にできないか調べてみて行ってみたところ、次の方法でOKだと思います

ここでは、Test1のソリューションに、他のソリューションにあるプロジェクトTest2をコピーすることを考えます。

* エクスプローラーで、Test2のプロジェクトフォルダを、Test1のソリューションフォルダにコピーします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132059/5fbbdbea-0748-4454-902f-37d344cbc27f.png)

* VisualStudioの**ファイル＞追加＞既存のプロジェクト**
で、コピーしたフォルダの中の、Test2.csprojを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/132059/f92e48cc-b53f-2321-0faa-d70d90fec9e5.png)




ファイル＞追加＞既存のプロジェクト　は、ファイル自体はコピーされないので、最初にエクスプローラーでコピーしてしまうのがポイントです。
This copy of libswiftCore.dylib requires an OS version prior to 12.2.0.

雑メモ

以下のエラーが起きた

```
This copy of libswiftCore.dylib requires an OS version prior to 12.2.0.
```

以下の手順で修正された

- Xcode開く
- BuildSettings開く
- Runpath Search Paths 検索
- 一番上に `/usr/lib/swift` 追加

![Screen Shot 2020-09-30 at 8.50.49 PM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/167299/f4a397ec-6aef-1bbe-ebb0-81c6fe9eb9df.png)
一日試しても解決できなかった仮想環境へのファイル転送：備忘録

仮想環境へのファイル転送に関するメモ

```Terminal
scp 送るファイル名 送り先ファイル名:~/
```
で転送しようとするもうまくいかない。
下記サイトを参考に
https://qiita.com/JJJJJJJJ/items/5a8ff64ff89dad404e82
https://teratail.com/questions/122671
https://blog.katty.in/853
https://qiita.com/shuthimaru/items/2334f63845d8b0d85bdd


vagrantfaileでIPを確認を確認してhostsにvimエディタで書き込み。

```Terminal
scp 送るファイル名 送り先ファイル名:~/
```
で再チャレンジ

```Terminal     
ssh: Could not resolve hostname ＠＠＠: nodename nor servname provided, or not known
lost connection
```
でダメだった

```Terminal 
ping ホスト名
```

で確認すると

```Terminal 
PING ＠＠＠ (＠＠＠): 56 data bytes
64 bytes from ＠＠＠: icmp_seq=0 ttl=64 time=0.612 ms
```

ちゃんと返ってきている。

```Terminal 
scp 送るファイル名　ホスト名:~/
```

ディレクトリ名から指定したホスト名に変更   
進んだがパスワードを要求される
わからないので、vagrantとかMacそのもののパスを入れるが進まない

うまくいかないのでvagrant destroy とvagrant upで再構築

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
怒られる。

```
ssh-keygen -R ＠＠＠
```

でエラー原因のフォルダを削除
参考：https://qiita.com/grgrjnjn/items/8ca33b64ea0406e12938


```
scp 送るファイル名　ホスト名:~/
```

試すもまたパスワード要求、何もできないので投了です。

その他の参考サイト
https://kekaku.addisteria.com/wp/20190129104147
https://qiita.com/grachro/items/4d34a43a9a57946f3693
https://teratail.com/questions/95371
https://qiita.com/katsukii/items/c3df0653ac07d41fe03f
【PHP】stdClassについて

## stdClassとは
stdClass = プロパティやメソッドを一切持たない標準クラス

## 特徴
- 普通のクラスのようにnewを用いて使用

```php
$obj = new stdClass();
$obj->hoge = 'hoge';
```

- 配列で結果を返す代わりにstdClassを返す

```php
// 配列の場合
$dog= [];
$dog['name'] = 'pochi';
echo $dog['name'];

// stdClassの場合
$dog= new stdClass();
$dog->name= 'pochi';
echo $dog->name;

// 定義していないプロパティにアクセスするとエラーに
$cat = stdClass();
echo $cat->name; // PHP Notice:  Undefined property: stdClass::$fuga
```
配列ではなくオブジェクト形式でデータを保存したいときに使用。オブジェクトにすることで、`$obj->hoge` のような形で記述可能に

- 他の型からオブジェクト型にキャストを行うとstdClassのインスタンスになる

>オブジェクト以外の型の値がオブジェクトに変換される時には、stdClass というビルトインクラス（予めPHPの内部で定義されているクラス）のインスタンスが新しく生成されます。
引用：[オブジェクト](https://www.php.net/manual/ja/language.types.object.php#language.types.object.casting)

## 参考
- [連想Keyを使ったArrayの代わりにstdClassを利用する](https://qiita.com/onomame/items/be2261c6eb566edab030)
- [PHP、stdClassとは何ぞや？](http://piyopiyocs.blog115.fc2.com/blog-entry-963.html)
- パーフェクトPHP
UNIQUE関数の代替手段(Office 365やピボットテーブルを使わない)

# Abstract

UNIQUE関数はOffice 365でしか使えない。
→Office 2019以下で使えるExcel関数だけを用いた代替方法

```
// 1行目
=元のリストの一番上

// 1行目以降(配列数式にするため、{}以外を入力し、Ctrl+Shift+Enterで決定すること)
{=IFNA(INDEX(元のリストの絶対参照,MATCH(0,COUNTIF(一番上のセルの絶対参照:1つ上のセル,元のリストの絶対参照),0)),"")}
```
具体例や詳細は後述。

# Introduction

* UNIQUE関数とは  
Office 365から採用された関数で、Google Spreadsheetなどにも実装されている。  
重複した内容を含むリストから、重複のないリストを作成することが可能。  
以下に例を示す。

|元のリスト|重複しているか|UNIQUE関数の出力|
|:---:|:---:|:---:|
|AAA  ||AAA  |
|BBB  ||BBB  |
|CCC  ||CCC  |
|BBB  |重複|DDD  |
|DDD  ||  |
|DDD  |重複|  |
以上のように重複しているBBB, DDDが1つずつ表示されるようになる。

この関数は非常に便利だが、前述の通り、Office 365でのみ利用可能で、
Office 2019以前のバージョンでは同様のことを行うためにピボットテーブルを使う必要があった。
ピボットテーブルはグラフや標準誤差を算出したい場合などに不自由なため、
今回は、Excel関数のみでUNIQUE関数の代替手段を示す。

# Materials and Methods

Windows版Office 2013以降で動作を確認。

Abstractに示した関数の再掲

```
// 1行目
=元のリストの一番上

// 1行目以降(配列数式にするため、{}以外を入力し、Ctrl+Shift+Enterで決定すること)
{=IFNA(INDEX(元のリストの絶対参照,MATCH(0,COUNTIF(一番上のセルの絶対参照:1つ上のセル,元のリストの絶対参照),0)),"")}

```

# Results and Dicussion

以下、実際にExcelで入力した結果。
![unique2019.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396838/5b5063f8-19e8-6f12-d0ca-3eec65627960.png)



左(B, C列)に入力されている家計簿から、それぞれの項目を取得し、その合計金額を出した表。
例として、E6の内容を以下にテキストでも示した(Ctrl+Shift+Enterで配列数式として入力)。

```
{=IFNA(INDEX($B$3:$B$10,MATCH(0,COUNTIF(E$3:E5,"="&$B$3:$B$10),0)),"")}
```

詳細を解説する。
1行目は必ず重複しないため、そのままリストの内容を入力している。
2行目以降は、まず、COUNTIF関数(配列を返すことが可能)を用いることで、
「対象のセルより上のセル」と重複する値は1, 重複しない値は0に「元のリスト」を変換して配列として取得している。
次に、MATCH関数を用いて、初めて現れる0 (つまり、重複しない一番上の値)が「元のリスト」の何番目か特定している。
最後に、INDEX関数を用い、「元のリスト」の配列からMATCH関数で特定した順番の値を抜き出している。
IFNA関数は重複しない値がそれ以上ない場合に、空文字を返すために利用している。

# Conclusion

UNIQUE関数の代替手段としては完璧に動作する。
欠点としては、SORT関数を実装できないため(単体実装は可能だが、上記方法と併用不可)、
フィルターなどの併用が必要になる事が挙げられる。