OmniAICreator/Qiita-1.07M huggingface dataset:
C# PowerPointをHTMLに変換

<p><strong>今日はC#についての話です。そして、Spire.Presentationという無料のライブラリを使って、PowerPointをHTMLに変換する方法を紹介します。</strong></p>
<h4><strong>下準備</strong></h4>
<p><strong>1.E-iceblueの公式サイトから<a href="https://www.e-iceblue.com/Download/download-presentation-for-net-free.html">Free Spire. Presentation</a>無料版をダウンロードしてください。</strong></p>
<p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/l/lendoris/20210507/20210507153842.png" alt="f:id:lendoris:20210507153842p:plain" title="" class="hatena-fotolife" itemprop="image" /></p>
<p><strong>2.Visual Studioを起動して新規プロジェクトを作成してから、インストールされたファイルにあった相応しいSpire. Presentation.dllを参照に追加してください。</strong></p>
<p><strong>（Net 4.0を例としたら、デフォルトパスは“Bin→NET4.0→Presentation.dll”というようになります。）</strong></p>
<p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/l/lendoris/20210507/20210507153932.png" alt="f:id:lendoris:20210507153932p:plain" title="" class="hatena-fotolife" itemprop="image" /></p>
<h4><strong>元のファイル</strong></h4>
<p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/l/lendoris/20210507/20210507153954.png" alt="f:id:lendoris:20210507153954p:plain" title="" class="hatena-fotolife" itemprop="image" /></p>
```C#
using Spire.Presentation;
namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            //PowePoint Objectを作成します。
            Presentation ppt = new Presentation();
            //ファイルをロードします。
            ppt.LoadFromFile(@"Sample.pptx");
            //HTMLで保存します。
            ppt.SaveToFile("ConvertPPTtoHtml.html", FileFormat.Html);

        }
    }
}
```
<h4><strong>実行結果</strong></h4>
<p><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/l/lendoris/20210507/20210507154027.png" alt="f:id:lendoris:20210507154027p:plain" title="" class="hatena-fotolife" itemprop="image" /></p>
<p> </p>
HTTP/2 とは

## 勉強前イメージ

聞いたことはあるけど、何が違うとかは知らない

## 調査

### HTTP/2とは

2015年に公開されたHTTPのバージョンでHTTP/1.1と互換性があります。
ポート番号はHTTP/1.1と変更はありません。

### HTTP/2ができた理由

HTTP/1.1ができた当初のwebサイトは現在よりコンテンツは多くなかったです。
しかし近年様々なコンテンツが配信され、webサイトのリクエスト量も多くなってきました。
このような背景からwebの高速化、またセキュリティの向上も必要とされ、
改定が行われHTTP/2が作られました。

### HTTP/2の概要

細かく書くといっぱいありますが、主なものを記載します。

- リクエストの高速化

HTTP/1.1では、リクエストが完了するまで次のリクエストを送ることができなかったのです。
すると、1つずつしか読み込めないため、表示までが遅くなってしまいます。
そこでHTTP/2では複数リクエストを同時に処理出来るようになりました。

![1# HTTP_2 とは - diagrams.net - Google Chrome 2021-05.png](HTTPs://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/129517/d9ce7450-b8ed-62cf-bb4b-77330f72a316.png)


- セキュリティの向上

HTTP/2ではセキュリティ面で制限をかけており、以下のような制限があります。
もし、こちらが対応できなかったらコネクションエラーになってしまいます。

```
- TLS1.2以上
- SNI をサポート
- 指定の暗号化スイートを仕様
- TLSの圧縮機能を無効
```

## 勉強後イメージ

軽くしかまだやってないから内容薄い・・・
構築するときとかにも勉強しよう。
ただ、HTTP/2を対応しようとすると結構大変だなーって感じ。
古いTLSのバージョンとか使ってたらあかんのね。

## 参考

- [【図解】HTTP/2って？HTTP/1.1との違いと導入メリット・課題まとめ](HTTPs://www.kagoya.jp/howto/webhomepage/HTTP-2/)
- [HTTP/2の特徴 HTTP/1.1との違いについて](HTTPs://blog.redbox.ne.jp/HTTP2-cdn.html)
Gtk3アプリ イベントハンドラー編

###Gtk3アプリ イベントハンドラー編

####コード上でイベントハンドラーを書くパターン
従来通りイベントハンドラーとコールバック関数を書くやり方
Riderのエディタの場合関数のコードヒントが効きます。

```cs
namespace event2GtkApplication
{
    class MainWindow : Window
    {
        [UI] private Button _button1 = null;

        public MainWindow() : this(new Builder("MainWindow.glade")) { }

        private MainWindow(Builder builder) : base(builder.GetRawOwnedObject("MainWindow"))
        {
            builder.Autoconnect(this);

            _button1.Clicked += Button1_Clicked;
        }

        private void Button1_Clicked(object sender, EventArgs a)
        {
          Console.WriteLine(e);
        }
    }
}
```
####課題
すべてのコントロールにイベントハンドラーとコールバック関数を書かないといけない。
コールバック関数の引数がわからないことがある。
Windows版のVisalStudioはボタンを押すとイベントハンドラーとコールバック関数を自動生成してくれて便利な機能があった

####Gladeにコールバック関数名を書くやり方
Gladeにコールバック関数名を書きコードにコールバック関数を書きます。
イベントハンドラーはAutoConnectで裏で処理してくれてる

<img width="650" alt="スクリーンショット 2020-03-29 12.53.22.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/182324/3928f266-f6f5-eeae-90c2-6cad9b7f6422.png">

```cs
using System;
using Gtk;
using UI = Gtk.Builder.ObjectAttribute;

namespace EventGtkApplication
{
    partial class MainWindow : Window
    {
 
        [UI] private Button btn2 = null;  
        public MainWindow() : this(new Builder("MainWindow.glade"))
        {
        }

        private MainWindow(Builder builder) : base(builder.GetRawOwnedObject("MainWindow"))
        {
            builder.Autoconnect(this);

        }        
        public void on_btn2_clicked(Object sender,EventArgs e)
        {
            Console.WriteLine("" + sender);
            Console.WriteLine("" + e);       
          
        }
    }
}
```

######イベントーハンドラーの記入は不要

```
btn2.Clicked += on_btn2_clicked;
```

#####以下の状態だとビルドができない
- Glade上にコールバック関数名を記入。コード上にコールバック関数がない
- Glade上にコールバック関数名を記入。コード上のコールバック関数の名前が一致しない

#####以下の状態だとビルドができる
- Glade上に２つのボタンに同じコールバック関数を名記入。コード上のコールバック関数が同じ（非推奨）

####課題
コールバック関数も自動生成したい。
Windows VisualStudioやMonoDevelopでは自動生成があり便利だった。
GTK3はリリースしてから１０年以上経つ。流石に自動生成するオープンソースがあるはず

####Gladeからコールバック関数を自動生成するものを探す

https://www.codeproject.com/Articles/19644/Glade-Code-Changer

https://github.com/c-buzz/GladeToCpp

https://github.com/welbornprod/glader

gitに上がっているGladeToCppが理想に違いが自動生成されるコードはC++であり対象外

あとはpythonでpythonのGTKを生成するものが少々

glade gtk python generatorで検索するとヒットします。

C#を書き出してくるものがあまり見当たらない


[Gtk3アプリ イベントハンドラー生成ツールの作成](https://qiita.com/tana_/items/b3dfcc589829d470e32d)へ続く
PHP は初期値なし reduce できない

reduce とか fold とか呼ばれる関数の一般的なイメージってこうですよね。

```python
def reduce(f, xs):
    l = len(xs)
    if l == 0:
        return None  # or error
    elif l == 1:
        return xs[0] # 単要素なら確定
    else:
        # 単要素になるまで削って再帰
        xs2 = copy.copy(xs)  # (ミュータブルはめんどくさいな)
        x = xs2.pop(-1)
        return f(x, reduce(f, xs2))
```

で、これだと `len(xs) == 0` のときが厄介なので、ご都合で、配列の先頭要素に一時的に入ってくれる初期値引数をオプションで持っていたりします。

```python
def reduce(f, xs, i = None):
    if i is not None:
        xs2 = copy.copy(xs)
        return reduce(f, xs2.insert(0, i))

    l = len(xs)
    # 以下上と同じ
```

Python の reduce はこんな感じ:

```
% python3
Python 3.9.2 (default, Mar 15 2021, 17:27:56) 
...
>>> from functools import reduce
>>> reduce(max, [-1, -2, -3])
-1
>>> reduce(max, [-1, -2, -3], 0)
0
>>> reduce(min, [-1, -2, -3])
-3
>>> reduce(min, [-1, -2, -3], 0)
-3
>>> 
```

Ruby の reduce (= inject):

```
% irb    
irb(main):001:0> [-1,-2,-3].inject{|a,b| a > b ? a : b}
=> -1
irb(main):002:0> [-1,-2,-3].inject(0){|a,b| a > b ? a : b}
=> 0
irb(main):003:0> [-1,-2,-3].inject{|a,b| a < b ? a : b}
=> -3
irb(main):004:0> [-1,-2,-3].inject(0){|a,b| a < b ? a : b}
=> -3
irb(main):005:0>
```

(Ruby なんでもメソッドなので 2 引数の min/max 関数ないの地味にめんどい)

では本題...

「PHP は他の言語と違って reduce の初期値がつねに効いてくるから注意な」
「えっ? なにそれどういうこと??」

```
% php -a 
Interactive shell

php > echo array_reduce([-1,-2,-3], 'max', 0);
0
php > echo array_reduce([-1,-2,-3], 'max');
-1
```

同じな気がするんだけどな...

```
php > echo array_reduce([-1,-2,-3], 'min', 0);
-3
php > echo array_reduce([-1,-2,-3], 'min');
php >
```

は? えっ???

https://www.php.net/manual/ja/function.array-reduce.php

```php
array_reduce (
    array $array,
    callable $callback,
    mixed $initial = null
) : mixed
```

この `$initial = null` なんですが、「引数なしでコールして null のままだったら初期値を配列の先頭要素から取ってくる普通の reduce になる」って意味ではなく、本当に `$callback` の初回コール初期値に null をぶっ込んできます。

というわけで種明かし。

```
% php -a 
Interactive shell

php > var_dump(max(null, -1));
int(-1)
php > var_dump(min(null, -1));
NULL
```

max は null と比較したら null でない方を返すけど、min は null と比較したら null を返す関数だったので、array_reduce の初期値 null がずっと生き残っていて `echo null` になったというわけです。

初回で null との比較が起きることを想定した関数なんて逆に書きにくいですね。こうすれば普通の初期値なし reduce になるのかな?

```php
$xs = [-1,-2,-3];
echo array_reduce(array_slice($xs, 1), 'min', $xs[0] ?? null);
```

うーん...

```php
echo array_reduce([-1,-2,-3], 'min', PHP_INT_MAX);
```

やっぱ素直にこういう「ループで書いたら初期値こうだよね」って感じのコード書くのが妥当な気がします。
バックエンド（django）とフロントエンド（vuejs）の間でデータをやり取りするときに発生するCORSエラー

```
Access to XMLHttpRequest at 'http://localhost:8080' from origin 'http://localhost:8080' has been blocked by CORS policy:
Response to preflight request doesn't pass access control check: It does not have HTTP ok status.
```
APIサーバーとWebサーバーをそれぞれ別のポートで立てている場合に生じるエラーである。
このエラーはブラウザーのセキュリティのためのエラーなのでヘッダーに許可を与える必要がある。


今回の場合でいうとvue.js（localhost8080）からDjango(localhost:8000)へAPIリクエストを投げたときに起きるエラーです。

##CORSの対策

Djangoに対してCSRF対策を行う。
[Github](https://github.com/adamchainz/django-cors-headers)によると

・python -m pip install django-cors-headers
・INSTALLED_APPSに`corsheaders`を追加
・MIDDLEWAREにもレスポンスを追加
・`CORS_ORIGIN_ALLOW_ALL=True`にする



この事によりアクセス許可を送ることができ正常にデータを送信することができる。
dockerがすぐ落ちる　docker-compose up

docker-compose upしても１分と持たずlocalhostが見れない、リロードするたびに落ちる。

解決策
dockerのMemory上げる。
docker desktop => 右上の歯車アイコン => Resources => Memoryを4GBに（既に4GBであれば5GBに上げる） => apply and restart

できた！

原因は不確かですが、
npm installで重たいものを入れたせいかもしれない・・・
論理的な思考とは

普段から論理的な思考を鍛えることはできます。

#常に疑問を持とう
例えば今だと、新型コロナウイルス感染者数ですね。
昨日は500人、本日800人の新規感染者数が発表されました。となった場合、増えたなあという感想は正しいです。
が、まず母数がいくつなのか？という疑問をすぐ持たないといけません。
例えば母数（この場合、検査数）が全然違っていた場合、人数だけ増えても、で？という話ですよね。

#言葉の正確さ
ちなみに感染者数という言葉は実は正しくありません。
正しくは、陽性者数です。
検査でわかるのは陽性者数であり、感染者数ではないからです。
逆に言うと、いくら検査しても感染者数というのはわからないのです。

上記の話に限定すると、指標としては、感染者数（実は陽性者数）より陽性率を発表した方が、まだよさそうに思うのですが、いかがでしょうか？
ちなみに下記が東京都の検査の陽性率です。
https://stopcovid19.metro.tokyo.lg.jp/cards/positive-rate/

#言葉の正確さ、定義を相手と合わせよう
ある言葉に対し、自分の中での定義と相手の定義が違っている事は多々あります。
なのでそこをまず合わせていないと、システムを作る場合も大変なことになります。
相手に確認し、曖昧さを排除すること、それがよいシステム作りにつながります。
システムエンジニア、プログラマに向いている人

どんな方が向いているか？ですが（あくまでも個人的な意見）

**①論理的な思考ができる**
（日ごろから訓練が必要）
**②丁寧に仕事ができる**
（誤字脱字が少ない、わかりやすいドキュメントをきっちり作る心がけ）
**③粘り強い**
（一つのエラー原因を追究するのに数日かかることも）
**④勉強し続けることができる**
（流行の言語はどんどん変わる）
**⑤コミュニケーション能力がある**
（相手の言うことに耳を傾けることができ、自分の意見をはっきり述べることができる）

ですかね。
①②は社会人なりたての頃はある程度あればよくて、これからの訓練でどんどん伸ばすことができます。
ですが、③～⑤は生来的なところ、学生時代の過ごし方が大きいかもしれません。
全部を完全に満たすことはできませんが、どれかが極端にかける人は、長く続かない、ように思います。
人気の言語

今人気の言語はどんなものがあるでしょうか？改めて調べてみました。

#Tiobe index
人気の言語指数としてよく使われるTiobe Indexを見てみます。
https://www.tiobe.com/tiobe-index/

2021/5現在では
**1.C**
**2.Python**
**3.Java**
**4.C++**
**5.C#**
ですね。
C,C++は組み込み系、以外はWeb系で使われることが多いです。

PythonはAIもあってやっぱり人気ですね。
C,C++は圧倒的に実行速度が速いです。
なので古い言語ですが、今後も残り続けると思います。自動運転のソースコードもC,C++じゃないでしょうか？

言語は移り変わりが激しいので、表に載っていても、数十年後は消えている可能性はあります。
なので、初めから特定の言語にこだわらない方がよいと思います。

人気はないけれど、レガシーシステムに載っているからなくならない言語といえば、COBOLですが、COBOLを作った人は、グレースホッパーという女性です。

女性初の数学の博士号取得者、かつアメリカ海軍の軍人かつ計算機科学者という本当に凄い人で、COBOLを作ったのもなんと50代。彼女の有名な言葉
**“The only phrase I’ve ever disliked is, ‘Why, we’ve always done it that way.’ I always tell young people, ‘Go ahead and do it. You can always apologize later.'”**
を若い方に送りたいです。
PC版LINEにおける電話番号ログインのサポート終了のお知らせ

![PC版LINEにおける電話番号ログインのサポート終了のお知らせ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/787462/b167c947-ddd1-c44a-4ae2-06b13844b8ed.png)


PC版LINEをお使いの方は、既にこのメッセージを目にされたと思います。

一見、メールアドレスを紐づけしてあげれば問題ないように見えます。
しかし、スマートフォンへのアカウント引き継ぎしていない場合は
アカウント引き継ぎを行うよう、促しのメッセージも載っています。

今回、PC版でLINEアカウントを作成したお客様から
「これってどうしたらいいの？」
とお問い合わせを頂きましたので、LINEに問い合わせしてみました。


---
【結論】
問い合わせた結果・・・「え、本当に？」という結論でした。

　・PCで、固定電話などを使って登録したLINEアカウントは
　　アカウントを、電話番号を持つモバイルデバイスに引き継ぐ必要がある。

<b>　・モバイルデバイスに引き継いでいないアカウントは
　　たとえメールアドレスが紐づけしてあったとしても
　　2021/05/27をもってLINEが利用できなくなる。
</b>

・・・という事のようです。

---
ねんのため、<b>PCから、固定電話などを使って登録し
モバイルデバイスに紐づけしていないLINEアカウントは
必ず、モバイルデバイスに紐づけしておきましょう。。</b>

（開発現場に、こういうアカウントいますよね、たぶん、、）
（アナウンスメッセージを読み返しても、未だにこの結論に頭が追い付かない、、）
Django3のmakemigrationsの小技

#概要
今、開発しているdjangoのprojectのmigration時に、models.pyのコートを書いては消し、としているので、よくデータベースを消すはめになります:frowning2:
そこで、自分で調べてみて、簡単にmigrationの変更を削除、更新できるようにしたいと考え、忘備録として記していこうと思います。また私の環境で
`find . -path "*/migrations/*.py" -not -name "__init__.py" -delete`
`find . -path "*/migrations/*.pyc"  -delete`
と書いたら、Djangoを再インストールするハメになったので。このコマンドは使わないようにします:angel:。

#開発環境
django==3.2.1
python==3.9.1
データベース==MySQL

#きっかけ
今回、私はaccountsというアプリケーションの中のmodelsに、UserというAbstractBaseUserをオーバーライドさせたmodelsを作成したのですが、primary_keyを設定して、makemigrationsしてしまったので、こんなのがターミナルに毎回出てきてしまいます。
`WARNINGS:
accounts.User: (models.W042) Auto-created primary key used when not defining a primary key type, by default 'django.db.models.AutoField'.`
これを消すために、migrateして、データベースに保存されてしまったprimary_keyの値をなかったことにしたいと思います。

#migrateのコマンドまとめ
<dl>
  <dt>makemigrations<dt><br>
  <dd><code>python manage.py makemigrations (アプリケーション名)</code></dd>
　<br>
  <dt>migrate<dt><br>
  <dd><code>python manage.py migrate (アプリケーション名)</code></dd>
  <br>
  <dt>migrationした時のnameを変更</dt><br>
  <dd><code>python manage.py makemigrations --name (付けたい名前)</code></dd>
  <br>
  <dt>migrateの履歴を見る<dt><br>
  <dd><code>python manage.py showmigrations (アプリケーション名)</code></dd>
  <dd>[ ]=migrateしてない</dd>
  <dd>[ X ]=migrate済み</dd>
  <br>
  <dt>migrateの巻き戻し<dt><br>
  <dd><code>python manage.py migrate (ファイル名)</code></dd>
  <dd>ファイル名というのは0001や0002から始まるファイルを指しています。<br>指定したファイル名の直前まで、巻き戻すことになります。</dd>
  <br>
  <dt>migrateを全てやり直し<dt><br>
  <dd><code>python manage.py migrate (アプリケーション名) zero</code></dd>
  <br>
  <dt>履歴からも削除<dt><br>
  <dd>migrationファイルを削除</dd>
  <br>
</dl>



#私の場合
`python manage.py showmigrations accounts`
結果
`accounts
 [X] 0001_initial`
[]の中の`X`はmigrateした際に、表示されます。(makemigrations時には空のままです。)
migrate時にデータベースの方にmodelが保存されるようです。つまり、この`X`が消えれば、データベースの変更がなくなるらしい:v:。なので、次のコマンドを使って、migrateをなかったことにしてみます。
`python manage.py migrate accounts zero`
結果
`accounts
 [ ] 0001_initial`
となりました。
これを完全に消すためには、アプリケーション内のmigrationsと\_\_pychahe__の中にある0001から始まるファイルを消します。
この後、使っていたデータベースも削除して、makemigrations,migrateを行いましたが、warningは消えませんでした。。。
とりあえず、errorにはなっていないので、このまま進めていこうと思います。
このwarningについて、知見のある方は連絡をしていただけると助かります。
【2021年現在】初心者でも大丈夫。chartkickのインストールの仕方(rails 6)

アプリケーションにグラフを差し込むのに便利なchartkickの説明(導入メイン)となります。


## 1.Chartkickの導入

gemfileに

```
gem 'chartkick'
```
を記述。その後忘れずにbundle installも！

続いて

```
% yarn add chartkick chart.js
```
※こちらのコマンド忘れずに

そしてapp/javascript/packs/application.js内に

```
import "chartkick/chart.js"
```
を記述する！
※もしグラフが上手く表示されない場合は
app/javascript/packs/application.js内の記述を

~~import "chartkick/chart.js"~~ではなく

```
require("chartkick")
require("chart.js")
```
としてみてください。
**rails５以前**
の方は

```
//= require chartkick
//= require Chart.bundle
```
こちらを。

## 2.グラフ表示

いよいよグラフ表示です！

グラフを表示させたい「○○.html.erb」に

```
<%= pie_chart [['赤', 50], ['青', 50]]%>
```
と記述。
この段階で画面上に円グラフが表示されているか確認することで、chartkickがちゃんと導入できているか確認することができます。
※もし上手く表示されない場合、『サーバー閉じてからのrails s』　
もしくは『js内の記述を変更』してみてください

## 3.グラフについて

pie_chartの部分を変更すればグラフの種類も変更可能です

**column_chart(縦棒グラフ)**
**bar_chart(横棒グラフ)**
**line_chart(折れ線グラフ)**


今回は速攻でグラフが表示されるかを確認するためコントローラーを経由せず、ビュー内に直接データ記述(赤50青50)しました。

一般的な使い方としては
コントローラ内にデータ記述する方法など色々ありますので下のリンクをご参考に。

##参考サイト

[chartkick](https://chartkick.com/)
[【Rails】Rails完結！グラフを簡単に作成できるライブラリChartkickについて簡単にまとめてみた](https://techtechmedia.com/chartkick-graph-rails/)
Zsh　zshプロンプト自作　githubのbranchを表示できるようにした。

## branchを表示するようにしました。

githubを活用したチーム開発が始まったのでbranchを表示する必要がありました。
調べるといい感じのスクリプトが紹介されていたので、自分用に少し書き換えて、使いやすいようにしました。
ほぼ、コピペですので、詳しい解説等は、リンク先を参照してください。

参考: [1箇所コピペするだけでgitブランチ名を常に表示【.zshrc】](https://suwaru.tokyo/1%E7%AE%87%E6%89%80%E3%82%B3%E3%83%94%E3%83%9A%E3%81%99%E3%82%8B%E3%81%A0%E3%81%91%E3%81%A7git%E3%83%96%E3%83%A9%E3%83%B3%E3%83%81%E5%90%8D%E3%82%92%E5%B8%B8%E3%81%AB%E8%A1%A8%E7%A4%BA%E3%80%90-zshrc/)

```zsh
# プロンプト

# git ブランチ名を色付きで表示させるメソッド
function rprompt-git-current-branch {
	local branch_name st branch_status

	if [ ! -e  ".git" ]; then
		# git 管理されていないディレクトリは何も返さない
		return
	fi
	branch_name=`git rev-parse --abbrev-ref HEAD 2> /dev/null`
	st=`git status 2> /dev/null`
	if [[ -n `echo "$st" | grep "^nothing to"` ]]; then
		# 全て commit されてクリーンな状態
		branch_status="%F{green}"
	elif [[ -n `echo "$st" | grep "^Untracked files"` ]]; then
		# git 管理されていないファイルがある状態
		branch_status="%F{red}?"
	elif [[ -n `echo "$st" | grep "^Changes not staged for commit"` ]]; then
		# git add されていないファイルがある状態
		branch_status="%F{red}+"
	elif [[ -n `echo "$st" | grep "^Changes to be committed"` ]]; then
		# git commit されていないファイルがある状態
		branch_status="%F{yellow}!"
	elif [[ -n `echo "$st" | grep "^rebase in progress"` ]]; then
		# コンフリクトが起こった状態
		echo "%F{red}!(no branch)"
		return
	else
		# 上記以外の状態の場合
		branch_status="%F{blue}"
	fi
	# ブランチ名を色付きで表示する
	echo "${branch_status}[$branch_name]"
}

setopt prompt_subst

PROMPT='`rprompt-git-current-branch` %F{magenta}%~%f
$ '
```
Amazon SNSを用いてAndroid(GMSとHMS)とiOSに対応したプッシュ通知の実装方法８―サーバー(Amazon SNS：プッシュ通知を配信)

# Amazon SNSを用いてAndroid(GMSとHMS)とiOSに対応したプッシュ通知の実装方法―サーバー(Amazon SNS：プッシュ通知を配信)

LambdaとAPI Gatewayで配信用のAPIを作成します。

Lambdaでは、aws-sdkライブラリを使って、プッシュ配信内容をAmazon SNSのトピックに送ります。

### Lambdaのサンプル

```javascript:index.js
// AWS SDKをロードする
const AWS = require('aws-sdk');
// リージョンを設定する
AWS.config.update({region: 'ap-northeast-1'});

// SNSサービスのオブジェクトを生成
const sns = new AWS.SNS();

exports.handler = function (event, context, callback) {
    // プッシュのパラメータを設定する
    const params = {
        // プッシュ内容
        Message: JSON.stringify({
            default: event.default,      // デフォルトデータ
            GCM: event.GCM,              // FCMデータ
            APNS: event.APNS             // APNSデータ
        }),
        // 配信プロトコルごとにカスタムペイロードに設定する
        MessageStructure: "json",
        // 対象トピック
        TopicArn: 'Amazon SNSのトピックのARN'
    };

    // Amazon SNSにアクセスするためのPromiseを作成する
    const promise = new Promise((resolve, reject) => {
        sns.publish(params, (error, data) => {
            if (error) {
                reject(error);
                return;
            }
            resolve(data);
        });
    });

    promise.then((result) => {
        // レスポンスを返す
        callback(null, result);
    }).catch((error) => {
        callback(null, { error : error });
    });
}
```

# GitHub
https://github.com/Rei2020GitHub/MyPublicProject/tree/master/PushDemo(H%2BG)/AWS/Lambda/amazon-sns-demo-send-push-notification

# 参考
<b>Amazon SNSを用いてAndroid(GMSとHMS)とiOSに対応したプッシュ通知の実装方法</b>
[１―概要](https://qiita.com/Rei_2020/items/69b9d9344e6d23dea097)
[２―クライアント(Android-GMS)](https://qiita.com/Rei_2020/items/2f4424cb3a5bbf86abc3)
[３―クライアント(Android-HMS)](https://qiita.com/Rei_2020/items/9d3764fc150e0e7a8014)
[４―クライアント(iOS-APNS)](https://qiita.com/Rei_2020/items/d839753f1514338809f9)
[５―サーバー(Amazon SNS：プッシュトークンの保存)](https://qiita.com/Rei_2020/items/c2ecd5bcd3866fe7d4e4)
[６―サーバー(Amazon SNS：プッシュトークンの管理：HMS)](https://qiita.com/Rei_2020/items/5e1906e3a4d1b737a803)
[７―サーバー(Amazon SNS：プッシュトークンの保存：HMS)](https://qiita.com/Rei_2020/items/6ad6f4ef13d5155cffa7)
[８―サーバー(Amazon SNS：プッシュ通知を配信)](https://qiita.com/Rei_2020/items/6ff3c1b8d3f7f44d27f0)
[９―サーバー(Amazon SNS：プッシュ通知を配信：HMS)](https://qiita.com/Rei_2020/items/40df3519b99c80fdea3d)
[１０―サーバー(Amazon SNS：プッシュ通知を配信：複数のデバイスに同時配信)](https://qiita.com/Rei_2020/items/ee32f3caeff8257097e6)
Amazon SNSを用いてAndroid(GMSとHMS)とiOSに対応したプッシュ通知の実装方法７―サーバー(Amazon SNS：プッシュトークンの保存：HMS)

# Amazon SNSを用いてAndroid(GMSとHMS)とiOSに対応したプッシュ通知の実装方法―サーバー(Amazon SNS：プッシュトークンの保存：HMS)
Amazon SNSではHMSのプッシュ通知を直接にサポートしていないので、プラットフォームアプリケーションの作成もサブスクリプションの作成もいりません。
（※後にプッシュ通知を配信するときにサブスクリプションの作成はいります）

### AWS LambdaでDynamoDBにプッシュトークンを登録する方法

```javascript:index.js
// AWS SDKをロードする
const AWS = require('aws-sdk');
// リージョンを設定する
AWS.config.update({region: 'ap-northeast-1'});
// DynamoDBサービスのオブジェクトを生成
const ddb = new AWS.DynamoDB();

exports.handler = async (event) => {
    const response = {};

    // 入力データを検証
    if (!event) {
        response.error = "No data";
        return response;
    }
    // 入力データを検証（トークンがない）
    if (!event.hasOwnProperty("token")) {
        response.error = "No token";
        return response;
    }
    // 入力データを検証（トークンがない）
    if (!event.hasOwnProperty("token_type")) {
        response.error = "No token type";
        return response;
    }

    const token = event.token;
    
    if (event.token_type == "HMS") {
        const params = {
            TableName: 'token_info',
            Item: {
                'token' : {S: token}
            }
        };
    
        // DynamoDBへ書き込む
        await ddb.putItem(params, function(err, data) {
            if (err) {
                response["error"] = err;
            } else {
                response["result"] = data;
            }
        }).promise();
    } else {
        response.error = "Invalid token type";
    }

    return response;
};
```

# GitHub
https://github.com/Rei2020GitHub/MyPublicProject/tree/master/PushDemo(H%2BG)/AWS/Lambda/hms-push-demo-add-push-token

# 参考
<b>Amazon SNSを用いてAndroid(GMSとHMS)とiOSに対応したプッシュ通知の実装方法</b>
[１―概要](https://qiita.com/Rei_2020/items/69b9d9344e6d23dea097)
[２―クライアント(Android-GMS)](https://qiita.com/Rei_2020/items/2f4424cb3a5bbf86abc3)
[３―クライアント(Android-HMS)](https://qiita.com/Rei_2020/items/9d3764fc150e0e7a8014)
[４―クライアント(iOS-APNS)](https://qiita.com/Rei_2020/items/d839753f1514338809f9)
[５―サーバー(Amazon SNS：プッシュトークンの保存)](https://qiita.com/Rei_2020/items/c2ecd5bcd3866fe7d4e4)
[６―サーバー(Amazon SNS：プッシュトークンの管理：HMS)](https://qiita.com/Rei_2020/items/5e1906e3a4d1b737a803)
[７―サーバー(Amazon SNS：プッシュトークンの保存：HMS)](https://qiita.com/Rei_2020/items/6ad6f4ef13d5155cffa7)
[８―サーバー(Amazon SNS：プッシュ通知を配信)](https://qiita.com/Rei_2020/items/6ff3c1b8d3f7f44d27f0)
[９―サーバー(Amazon SNS：プッシュ通知を配信：HMS)](https://qiita.com/Rei_2020/items/40df3519b99c80fdea3d)
[１０―サーバー(Amazon SNS：プッシュ通知を配信：複数のデバイスに同時配信)](https://qiita.com/Rei_2020/items/ee32f3caeff8257097e6)
Amazon SNSを用いてAndroid(GMSとHMS)とiOSに対応したプッシュ通知の実装方法６―サーバー(Amazon SNS：プッシュトークンの管理：HMS)

# Amazon SNSを用いてAndroid(GMSとHMS)とiOSに対応したプッシュ通知の実装方法―サーバー(Amazon SNS：プッシュトークンの管理：HMS)
Amazon SNSではHMSのプッシュ通知を直接にサポートしていないので、HMSのプッシュトークンの管理を自前で管理しなければなりません。

# 管理方法
DynamoDBを使います。カラムは一つだけで大丈夫です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/704548/5b25be37-695b-584a-0b1a-9b72834dc357.png)

# 参考
<b>Amazon SNSを用いてAndroid(GMSとHMS)とiOSに対応したプッシュ通知の実装方法</b>
[１―概要](https://qiita.com/Rei_2020/items/69b9d9344e6d23dea097)
[２―クライアント(Android-GMS)](https://qiita.com/Rei_2020/items/2f4424cb3a5bbf86abc3)
[３―クライアント(Android-HMS)](https://qiita.com/Rei_2020/items/9d3764fc150e0e7a8014)
[４―クライアント(iOS-APNS)](https://qiita.com/Rei_2020/items/d839753f1514338809f9)
[５―サーバー(Amazon SNS：プッシュトークンの保存)](https://qiita.com/Rei_2020/items/c2ecd5bcd3866fe7d4e4)
[６―サーバー(Amazon SNS：プッシュトークンの管理：HMS)](https://qiita.com/Rei_2020/items/5e1906e3a4d1b737a803)
[７―サーバー(Amazon SNS：プッシュトークンの保存：HMS)](https://qiita.com/Rei_2020/items/6ad6f4ef13d5155cffa7)
[８―サーバー(Amazon SNS：プッシュ通知を配信)](https://qiita.com/Rei_2020/items/6ff3c1b8d3f7f44d27f0)
[９―サーバー(Amazon SNS：プッシュ通知を配信：HMS)](https://qiita.com/Rei_2020/items/40df3519b99c80fdea3d)
[１０―サーバー(Amazon SNS：プッシュ通知を配信：複数のデバイスに同時配信)](https://qiita.com/Rei_2020/items/ee32f3caeff8257097e6)
Amazon SNSを用いてAndroid(GMSとHMS)とiOSに対応したプッシュ通知の実装方法４―クライアント(iOS-APNS)

# Amazon SNSを用いてAndroid(GMSとHMS)とiOSに対応したプッシュ通知の実装方法―クライアント(iOS-APNS)
iOSデバイスではAPNSでプッシュ通知を配信できます。クライアント側の実装は https://developer.apple.com/documentation/usernotifications/registering_your_app_with_apns をご参照いただければと思います。ここではAWSとの連携部分を重点的に紹介します。

# AWSとの連携要点
プッシュトークンは以下の箇所で返ってきます。

```swift
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
    let tokenParts = deviceToken.map { data -> String in
        return String(format: "%02.2hhx", data)
    }
    let token = tokenParts.joined()
    // ここでプッシュトークンをAWSに渡します
}
```

プッシュトークンを受け取って、AWSに送ります。

# 参考
<b>Amazon SNSを用いてAndroid(GMSとHMS)とiOSに対応したプッシュ通知の実装方法</b>
[１―概要](https://qiita.com/Rei_2020/items/69b9d9344e6d23dea097)
[２―クライアント(Android-GMS)](https://qiita.com/Rei_2020/items/2f4424cb3a5bbf86abc3)
[３―クライアント(Android-HMS)](https://qiita.com/Rei_2020/items/9d3764fc150e0e7a8014)
[４―クライアント(iOS-APNS)](https://qiita.com/Rei_2020/items/d839753f1514338809f9)
[５―サーバー(Amazon SNS：プッシュトークンの保存)](https://qiita.com/Rei_2020/items/c2ecd5bcd3866fe7d4e4)
[６―サーバー(Amazon SNS：プッシュトークンの管理：HMS)](https://qiita.com/Rei_2020/items/5e1906e3a4d1b737a803)
[７―サーバー(Amazon SNS：プッシュトークンの保存：HMS)](https://qiita.com/Rei_2020/items/6ad6f4ef13d5155cffa7)
[８―サーバー(Amazon SNS：プッシュ通知を配信)](https://qiita.com/Rei_2020/items/6ff3c1b8d3f7f44d27f0)
[９―サーバー(Amazon SNS：プッシュ通知を配信：HMS)](https://qiita.com/Rei_2020/items/40df3519b99c80fdea3d)
[１０―サーバー(Amazon SNS：プッシュ通知を配信：複数のデバイスに同時配信)](https://qiita.com/Rei_2020/items/ee32f3caeff8257097e6)
Amazon SNSを用いてAndroid(GMSとHMS)とiOSに対応したプッシュ通知の実装方法３―クライアント(Android-HMS)

# Amazon SNSを用いてAndroid(GMSとHMS)とiOSに対応したプッシュ通知の実装方法―クライアント(Android-HMS)
HMSデバイスでは、HMS Push Kitでプッシュ通知を配信できます。クライアント側の実装は https://developer.huawei.com/consumer/jp/doc/development/HMSCore-Guides/android-client-dev-0000001050042041 をご参照いただければと思います。ここではAWSとの連携部分を重点的に紹介します。

# AWSとの連携要点
プッシュトークンは以下の２箇所で返ってきます。

```kotlin
class MainService: HmsMessageService() {
    override fun onNewToken(token: String?) {
        super.onNewToken(token)
        // ここでプッシュトークンをAWSに渡します
    }
}
```

```kotlin
val token = HmsInstanceId.getInstance(context).getToken(appId, "HCM")
if (token.isNotEmpty()) {
    // ここでプッシュトークンをAWSに渡します
}
```

この２箇所でプッシュトークンを受け取って、AWSに送ります。

仮にAWSでLambdaとAPI Gatewayで次のようなAPIを作ったとします。

API：https://your.domain.amazonaws.com/add-push-token
メソッド：POST
ヘッダー：Context-Type : application/json
リクエスト：

```json
{
	"token": "Your Token",
	"token_type": "HMS"
}
```

そうしたら、クライアント側では、次のようにデータを送ります。

```kotlin
fun sendPushToken(
    context: Context,
    pushToken: String
) {
    val queue = Volley.newRequestQueue(context)
    val param = JSONObject().apply {
        put("token", pushToken)
        put("token_type", "FCM")
    }

    val postRequest: JsonObjectRequest = object : JsonObjectRequest(
        "https://your.domain.amazonaws.com/add-push-token",
        param,
        object : Response.Listener<JSONObject>{
            override fun onResponse(response: JSONObject?) {
                // プッシュトークンの送信が成功
            }
        },
        object : Response.ErrorListener{
            override fun onErrorResponse(error: VolleyError?) {
                // プッシュトークンの送信が失敗
            }
        }) {
    }

    queue.add(postRequest)
}
```

# 参考
<b>Amazon SNSを用いてAndroid(GMSとHMS)とiOSに対応したプッシュ通知の実装方法</b>
[１―概要](https://qiita.com/Rei_2020/items/69b9d9344e6d23dea097)
[２―クライアント(Android-GMS)](https://qiita.com/Rei_2020/items/2f4424cb3a5bbf86abc3)
[３―クライアント(Android-HMS)](https://qiita.com/Rei_2020/items/9d3764fc150e0e7a8014)
[４―クライアント(iOS-APNS)](https://qiita.com/Rei_2020/items/d839753f1514338809f9)
[５―サーバー(Amazon SNS：プッシュトークンの保存)](https://qiita.com/Rei_2020/items/c2ecd5bcd3866fe7d4e4)
[６―サーバー(Amazon SNS：プッシュトークンの管理：HMS)](https://qiita.com/Rei_2020/items/5e1906e3a4d1b737a803)
[７―サーバー(Amazon SNS：プッシュトークンの保存：HMS)](https://qiita.com/Rei_2020/items/6ad6f4ef13d5155cffa7)
[８―サーバー(Amazon SNS：プッシュ通知を配信)](https://qiita.com/Rei_2020/items/6ff3c1b8d3f7f44d27f0)
[９―サーバー(Amazon SNS：プッシュ通知を配信：HMS)](https://qiita.com/Rei_2020/items/40df3519b99c80fdea3d)
[１０―サーバー(Amazon SNS：プッシュ通知を配信：複数のデバイスに同時配信)](https://qiita.com/Rei_2020/items/ee32f3caeff8257097e6)
Amazon SNSを用いてAndroid(GMSとHMS)とiOSに対応したプッシュ通知の実装方法２―クライアント(Android-GMS)

# Amazon SNSを用いてAndroid(GMSとHMS)とiOSに対応したプッシュ通知の実装方法―クライアント(Android-GMS)
グーグルモバイルサービスが入っているデバイスでは、Firebase Cloud Messaging（FCM）でプッシュ通知を配信できます。クライアント側の実装は https://firebase.google.com/docs/cloud-messaging/android/client をご参照いただければと思います。ここではAWSとの連携部分を重点的に紹介します。

# AWSとの連携要点
プッシュトークンは以下の２箇所で返ってきます。

```kotlin
class MyFirebaseMessagingService : FirebaseMessagingService() {
    fun onNewToken(registrationToken: String) {
        // ここでプッシュトークンをAWSに渡します
    }
}
```

```kotlin
FirebaseMessaging.getInstance().token.addOnCompleteListener(OnCompleteListener { task ->
    if (!task.isSuccessful) {
        return
    }

    val token = task.result

    // ここでプッシュトークンをAWSに渡します
})
```

この２箇所でプッシュトークンを受け取って、AWSに送ります。

仮にAWSでLambdaとAPI Gatewayで次のようなAPIを作ったとします。

API：https://your.domain.amazonaws.com/add-push-token
メソッド：POST
ヘッダー：Context-Type : application/json
リクエスト：

```json
{
	"token": "Your Token",
	"token_type": "FCM"
}
```

そうしたら、クライアント側では、次のようにデータを送ります。

```kotlin
fun sendPushToken(
    context: Context,
    pushToken: String
) {
    val queue = Volley.newRequestQueue(context)
    val param = JSONObject().apply {
        put("token", pushToken)
        put("token_type", "FCM")
    }

    val postRequest: JsonObjectRequest = object : JsonObjectRequest(
        "https://your.domain.amazonaws.com/add-push-token",
        param,
        object : Response.Listener<JSONObject>{
            override fun onResponse(response: JSONObject?) {
                // プッシュトークンの送信が成功
            }
        },
        object : Response.ErrorListener{
            override fun onErrorResponse(error: VolleyError?) {
                // プッシュトークンの送信が失敗
            }
        }) {
    }

    queue.add(postRequest)
}
```

# 参考
<b>Amazon SNSを用いてAndroid(GMSとHMS)とiOSに対応したプッシュ通知の実装方法</b>
[１―概要](https://qiita.com/Rei_2020/items/69b9d9344e6d23dea097)
[２―クライアント(Android-GMS)](https://qiita.com/Rei_2020/items/2f4424cb3a5bbf86abc3)
[３―クライアント(Android-HMS)](https://qiita.com/Rei_2020/items/9d3764fc150e0e7a8014)
[４―クライアント(iOS-APNS)](https://qiita.com/Rei_2020/items/d839753f1514338809f9)
[５―サーバー(Amazon SNS：プッシュトークンの保存)](https://qiita.com/Rei_2020/items/c2ecd5bcd3866fe7d4e4)
[６―サーバー(Amazon SNS：プッシュトークンの管理：HMS)](https://qiita.com/Rei_2020/items/5e1906e3a4d1b737a803)
[７―サーバー(Amazon SNS：プッシュトークンの保存：HMS)](https://qiita.com/Rei_2020/items/6ad6f4ef13d5155cffa7)
[８―サーバー(Amazon SNS：プッシュ通知を配信)](https://qiita.com/Rei_2020/items/6ff3c1b8d3f7f44d27f0)
[９―サーバー(Amazon SNS：プッシュ通知を配信：HMS)](https://qiita.com/Rei_2020/items/40df3519b99c80fdea3d)
[１０―サーバー(Amazon SNS：プッシュ通知を配信：複数のデバイスに同時配信)](https://qiita.com/Rei_2020/items/ee32f3caeff8257097e6)
Amazon SNSを用いてAndroid(GMSとHMS)とiOSに対応したプッシュ通知の実装方法１―概要

# Amazon SNSを用いてAndroid(GMSとHMS)とiOSに対応したプッシュ通知の実装方法―概要
プッシュ通知の実装にあたって、一番大きな問題点は複数種類のデバイス対応です。
たとえば、次のようなデバイスがあるとします。

- Android（GMS）
- Android（HMS）
- iOS
- FireOS

通常のやり方ですと、

- Android（GMS）のクライアント側のFCMの実装
- Android（HMS）のクライアント側のHMS Push Kitの実装
- iOSのクライアント側のAPNSの実装
- FireOSのクライアント側のADMの実装
- Android（GMS）のサーバー側のFCMの対応
- Android（HMS）のサーバー側のHMS Push Kitの対応
- iOSのサーバー側のAPNSの対応
- FireOSのサーバー側のADMの対応

があります。
これですと、実装がかなり大変になります。

実装の手間を省くのに、Amazon SNSを使うことが一つの解決方法です。

# Amazon SNSのソリューション
Amazon SNSは次のデバイスのプッシュ通知に対応しています。

- Amazon Device Messaging (ADM)
- Apple プッシュ通知サービス (APNS)
- Firebase クラウドメッセージング (FCM)
- Windows プッシュ通知サービス (WNS): Windows 8 以降と Windows Phone 8.1 以降が対象
- Microsoft プッシュ通知サービス (MPNS): Windows Phone 7 以降が対象
- Baidu Cloud Push: 中国国内の Android デバイスが対象

Android（HMS）には直接に対応していませんが、Amazon SNSのAWS Lambdaのサブスクリプション機能とAWS Lambdaを組み合わせれば、対応が可能になります。

# ソリューション図
### Android（GMS）やiOS等
![image1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/704548/0f4a1883-5526-42d4-0f62-f121355a13df.png)

### Android（HMS）
![image2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/704548/766978cd-884d-a546-c905-a426d228d418.png)

# 参考
<b>Amazon SNSを用いてAndroid(GMSとHMS)とiOSに対応したプッシュ通知の実装方法</b>
[１―概要](https://qiita.com/Rei_2020/items/69b9d9344e6d23dea097)
[２―クライアント(Android-GMS)](https://qiita.com/Rei_2020/items/2f4424cb3a5bbf86abc3)
[３―クライアント(Android-HMS)](https://qiita.com/Rei_2020/items/9d3764fc150e0e7a8014)
[４―クライアント(iOS-APNS)](https://qiita.com/Rei_2020/items/d839753f1514338809f9)
[５―サーバー(Amazon SNS：プッシュトークンの保存)](https://qiita.com/Rei_2020/items/c2ecd5bcd3866fe7d4e4)
[６―サーバー(Amazon SNS：プッシュトークンの管理：HMS)](https://qiita.com/Rei_2020/items/5e1906e3a4d1b737a803)
[７―サーバー(Amazon SNS：プッシュトークンの保存：HMS)](https://qiita.com/Rei_2020/items/6ad6f4ef13d5155cffa7)
[８―サーバー(Amazon SNS：プッシュ通知を配信)](https://qiita.com/Rei_2020/items/6ff3c1b8d3f7f44d27f0)
[９―サーバー(Amazon SNS：プッシュ通知を配信：HMS)](https://qiita.com/Rei_2020/items/40df3519b99c80fdea3d)
[１０―サーバー(Amazon SNS：プッシュ通知を配信：複数のデバイスに同時配信)](https://qiita.com/Rei_2020/items/ee32f3caeff8257097e6)
これだけは知っておきたい！ビジネス層のためのデータ分析超入門 ③ 二項分類のユースケース

#はじめに
エンジニア歴1年目の私が、機械学習について調べたことをまとめていきたいと思います。

今回は、以前記述した「[これだけは知っておきたい！ビジネス層のためのデータ分析超入門 ② 評価指標](URL "https://qiita.com/m-ide/private/3ff2cabedd546be68c02")」を踏まえたユースケースについて確認していきます。

分類問題で重要なのは、望まれる状況がどのような状態で望まない状況がどのようなものであるかをとらえることです。

どの評価指標を最適化するべきかのひとつの考え方として偽陽性・偽陰性に分類されたクラスの影響度合いを考えるというものがあります。これによって再現率／適合率のどちらを最適化すべきかの判断ができます。

「どの場合にどの指標をみるのか」がざっくり把握できれば幸いです！
 

# ゴール
今回は以下のユースケースについて考えていきたいと思います。

 

# ユースケース一覧

 

1. 緊急のドキュメント探索
2. 画像プライバシー保護システム
3. スパムフィルタ
3. キーワードによるフォト検索

 

## 1. 緊急のドキュメント探索

緊急性の高いドキュメントを他よりも優先するシステムを構築したいとします。
ケースとしては、ファイルフォルダーに蓄積されているドキュメントの仕分けなどで、NDAのような重要書類と過去に行われた定例会議の議事録のような緊急性の低い書類の探索とします。


+ 偽陽性（FP）
緊急でないドキュメントを緊急であるドキュメントとして分類されること。

+ 偽陰性（FN）
緊急であるドキュメントを緊急でないドキュメントとして分類されること。

![無題のプレゼンテーション (25).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1268348/af08d466-36fa-1c3e-f551-0e7cde0f678f.png)



このようなケースでは、偽陽性（FP）であれば誤って分類されたものは緊急でないと判断して、無視して良いのですが、偽陰性だと重大な問題を見落とすケースにつながってしまう恐れがあります。

そのため、**「再現率」**を最適化する方が好ましいです。
（取りこぼしなく緊急なドキュメントを緊急なドキュメントと判断するモデル）
 

## 2. 画像プライバシー保護システム

登録された画像内の機密情報（クレジットカードの番号など）を検出し、それをぼかすシステムを構築するとします。

+ 偽陽性（FP）
ぼかす必要のないものをぼかしてしまう。（画像内のなんらかの数字など）

+ 偽陰性（FN）
クレジットカード番号がぼかされずに残ってしまう。


![無題のプレゼンテーション (22).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1268348/7fe5a2f5-962a-d1b4-5b72-8421ed49f4af.png)


このようなケースでは、偽陽性の場合は気になるところはありますがシステム上の弊害はありません。しかし、偽陰性であると、個人情報が盗まれてしまう恐れがあり重大な問題につながってしまいます。

そのため、**「再現率」**を最適化する方が好ましいと言うことができます。
（取りこぼしなく機密情報をぼかすようにするモデル）
 

## 3. スパムフィルタ

スパムメッセージとそうでないものをフィルタリングし、スパムメールを受信フォルダから削除するシステムを構築するとします。

+ 偽陽性（FP）
スパムでないメールが誤ってスパム認定され、受信フォルダから削除される。

+ 偽陰性（FN）
スパムメールがフィルタリングされずに受信フォルダに残る。

![無題のプレゼンテーション (24).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1268348/98404ce7-a66e-075f-c97f-2327593bcfe4.png)



今回のケースでは、これまでのケースの反対になります。
偽陽性の場合、正常なメールがスパムメールと認定され削除されてしまうと、もし削除されてしまったメールが重要であった場合に問題が発生してしまう可能性があります。しかし、偽陰性の場合、多少の不快感は残るものの、ビジネス上の損失には直結しません。

そのため、**「適合率」**を最適化するのが好ましいです。
（スパムをスパムと正しく認定する割合を高くするモデル）


##4.キーワードによるフォト検索

特定のキーワードに対応する最適なストックフォトを見つけるシステムを構築するとします。
例えば、「犬の画像」と検索した際に表示された画像に実際に犬が含まれていれば正常に分類されていると判断します。

 

偽陽性（FP）
キーワードと無関係な画像（車の画像など）が表示されている。

 

偽陰性（FN）
画像内に犬が写っているが、検索結果に表示されなかった画像が存在する。

 
![無題のプレゼンテーション (27).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1268348/c92696fe-c578-beb9-af43-98a48d1fb222.png)

偽陽性については、検索キーワードと関連しない画像が表示されているため好ましい状態ではありません。偽陰性については、キーワードと関連する画像が表示されているため、取りこぼしの画像があったとしても検索システムとしては問題にはなりません。

 

そのため、**「適合率」**を最適化する方が好ましいです。
（実施される画像検出が正しく行われるモデル）
# さいごに
簡単ではありますが、データ分析評価指標でのユースケースについて解説しました。

ぜひ、参考になれば幸いです。
[Django] ALLOWED_HOSTSとは

# 結論
セキュリティ対策（HTTPヘッダーインジェクション）のために、サービスを提供するホストをリストで与える設定値

# 説明
### ALLOWED_HOSTの役割
ヘッダーインジェクション攻撃を防ぐためにある
ALLOWED_HOSTSに設定されてないホストへのリクエストの場合、そのリクエストを弾く。

### ALLOWED_HOSTSの使い方
サービスを提供するホストを設定する。
**本番環境ではこの設定が必須**
例えばサービスのドメインが`www.example.com`なら以下のように設定する。

```python:settings.py
ALLOWED_HOSTS = [
     'www.example.com'
]
```

IPを指定しても良い

```python:settings.py
ALLOWED_HOSTS = [
    '20.0.0.0'
]
```

### 開発時はアスタリスクを指定しておくと楽
基本的に開発時は、`*`を設定して置けば良い

```python:settings.py
ALLOWED_HOSTS = ['*']
```




# 参考
[DjangoのALLOWED_HOSTSの役割と使い方 - なるぽのブログ](https://yu-nix.com/blog/2021/1/11/django-allowed-hosts/)
[Django ALLOWED_HOSTSの設定](https://deep-blog.jp/engineer/4287/)
スプレッドシート でIMPORTRANGEしようとしたら、権限の追加ができなかった。

Qiitaに書くほどでは無いかもしれませんが、備忘録と誰か同じ悩みを持った人の助けになれば嬉しいです。

とは言っても原因まではわからないので悪しからず。

## エラー内容
私の環境で起きた現象は以下のとおりです。

1. スプシでIMPORTRANGEをして、外部シートの参照をしようとした。
2. 権限の追加が必要と出たので、追加しようとする
3. 外部シートの権限がないとか言われるが、権限はちゃんとある ←ココからおかしい
4. その後IMPORTRANGEしようとしているセルの権限の追加表示がずっとぐるぐるして動かない

この現象が私のみではなく、関係者全員に同様の現象が起きていました。

## 参照先シートの共有設定を変えたら直った
早速結論ですが、参照先シートの共有設定を変えたら直りました。

具体的に変更したのは、個別設定ではなくリンクを取得の方です。

同一ドメインのメンバは閲覧可能設定にしていたのですが、この設定を初期状態に戻したら参照できるようになりました。

## 誰か原因わかったら教えてください。
検索しても同様の現象が起きたっていうページがなかったので、正直なぜダメだったのか全然わからない状態です。

誰か詳しい人教えてください。
【Rails】Herokuデプロイ時　We're sorry, but something went wrong.

## はじめに

![heroku.erro.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/859347/c84187aa-02f0-a203-ec3b-8e2dc5b40b95.png)

デプロイが終わりサイトを開くと出てきた時のエラーです。
その為の解決方法を記載して行きます！^^

## 解決方法

本番環境にデプロイした後にDBをマイグレートする必要があります!
なので以下のコマンドを入力します。

```:ターミナル
heroku run rails db:migrate
```

これで無事エラーが解決されたと思います！

## herokuコマンド


以下にherokuコマンドを少し書いておきます（メモ書程度）🙇


|コマンド|内容|
|-----|----|
|git push heroku master| masterブランチをHerokuにデプロイ
| git push heroku ブランチ名:master |master以外のブランチをHerokuにデプロイ
|git push heroku develop:master|developブランチをHerokuにデプロイ
|git push heroku HEAD:master|現在のブランチをHerokuにデプロイ
|heroku create アプリ名| Herokuアプリを作成
|heroku destroy| Herokuアプリを削除
|heroku open| Herokuアプリをブラウザで開く
|heroku logs -t| ログを確認
|heroku run rails c| コンソールを起動
|heroku run rails db:migrate| マイグレーションを実行
|heroku run rails db:seed| seeds.rbを実行
|heroku addons:create アドオン名|アドオンを追加
|heroku addons:create papertrail|Papertrailを追加
|heroku addons:create heroku-postgresql|PostgreSQLを追加
|heroku addons:open papertrail|Papertrailをブラウザで開く
|heroku pipelines:open パイブライン名| パイプラインをブラウザで開く
|heroku apps|Herokuのアプリ一覧を表示
|heroku restart|再起動
|heroku pg:reset|データベースを削除し作り直す

## 最後に

日々コメダ珈琲にてプログラミング楽しく学習していますゴリあんです😊
立派なエンジニアとして成長を何か貢献したいと考えております！
PHPでSESSIONが保存できなくなった話

#経緯
phpで作ったログインフォームが、昨日突然ログインできなくなった。
原因が分からず色々試しているうちにサーバをrebootしたら復旧した。
解決かと思ったら、今朝またログインできなくなっていた。
#調べる
```php:login.php
<?php
session_start();
if($_POST["id"] == "admin" && $_POST["password"] == "ABC123"){
	$_SESSION['login'] = true;
	$_SESSION['id'] = $_POST["id"];
	header('Location: index.php');
	exit;
}
echo '<form action="login.php" method="POST">';
echo 'id:<input type="text" name="id">';
echo 'password:<input type="password" name="password">';
echo '<input type="submit" value="ログイン">';
echo '</form>';
```

```php:index.php
<?php
$session_return = session_start();
if(!$session_return){
	echo "セッションエラー";
}
if(!$_SESSION['login']){
	var_dump($_SESSION);
//	header('Location: login.php');
	exit;
}
echo "ログイン成功";
```

```
array(0) {}
```

どうやら$_SESSIONに書き込みができなくなっているようだ。
しばらくしてlogin.phpがエラーを吐いている事に気がついた。

```
Warning: Unknown: write failed: No space left on device (28) in Unknown on line 0
Warning: Unknown: Failed to write session data (files). Please verify that the current setting of session.save_path is correct (/var/lib/php/session) in Unknown on line 0
```

「No space left on device」って・・・あ。

```
# df
Filesystem     1K-blocks     Used Available Use% Mounted on
tmpfs             249360        0    249360   0% /dev/shm
/dev/vda4       15948532 15250520         0 100% /
/dev/vda2         487652   130694    327262  29% /boot
tmpfs              49872        0     49872   0% /run/user/0
```
・・・ディスク埋まってる。

```
# du -k / | sort -rn | head -10
15374837	/
13146344	/var
12804060	/var/log
12739304	/var/log/httpd
2042276	/usr
828688	/usr/lib
491660	/usr/lib/firmware
447940	/usr/share
262768	/usr/bin
220276	/var/lib
```

そういえばapacheのログの設定してなかったな。

```
# ls -l /var/log/httpd/
total 12739300
-rw-r--r-- 1 root root     2170880 May  7 12:55 access_log
-rw-r--r-- 1 root root 13038845952 May  7 12:55 error_log
```
Oh!

#解決
```
# rm /var/log/httpd/error_log
# vi /etc/httpd/conf/httpd.conf
ErrorLog "/dev/null"
LogLevel alert
# service httpd restart
```
これでよし。

```
ログイン成功
```

めでたしめでたし😇
初心者が過去問精選 10問やっていく②


https://qiita.com/drken/items/fd4e5e3630d0f5859067

この記事の過去問を初心者が解いていきます。続きです

##問４ ABC 087 B - Coins (200 点)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/764631/aa5f6ee4-87c9-c43e-0851-8c7678fb1fb3.png)


```python
x = int(input())
y = int(input())
z = int(input())
total=int(input())
count =0
for i in range(x+1):#500円が〇枚あるときの探索(x枚までで)
  for j in range(y+1):#100円が〇枚あるとき(y枚までで）
    for k in range(z + 1):#50円が〇枚あるとき(z枚までの間で)
      if total == i * 500 + j * 100 + k * 50:#totalが合計と同じになればcount+1する
        count = count +1
print(count)
```
はじめ見たときは全く別の解き方で解こうとしていましたが効率の良い解き方はないかなと思って全探索の考え方を検索してときました。
最初何しているのかわからなかったですが一つ一つ何をしているのかをほどいていくと意外に単純なことしてるのだと気づきました。

##第 5 問: ABC 083 B - Some Sums (200 点)


```python
N,x,y = map(int,input().split())
lst=[]
def GG(n):#数値nの各桁の合計を得る関数
  sum2 = 0
  while n > 0:
    sum2 += n % 10
    n //= 10
  return sum2
  

for i in range(N+1):#N+1にしないと0から始まってるのでー1の状態で終わる
  if x <= GG(i) <= y:
    lst.append(i)
print(sum(lst))

#ここから下は最初にやろうとして失敗したコード    
while i < N+1:
  sun = 0
  s = i % 10
  n =int( i / 10 )
  sun = sun + s
  if s == 0:
    sun = sun+ n
  print(sun)
  print(type(sun))
  if x <= sun <= y:
    lst.append(i)
  i += 1
print(sum(lst))
```
結構苦戦しました。さいしょにやろうとしたコードだと桁の合計を求めようとしてぐちゃぐちゃになったり一回しかiを１０で割れてなかったりして失敗しました。
なら関数作ったりしたらいいというヒントをもとに関数作ってそれをFORの中で実行という形にしました。

##第六問 ABC 088 B - Card Game for Two (200 点)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/764631/a8bfbefe-b7f6-3507-45e6-ac506d22e354.png)

```python

n = int(input())
ss = list(map(int,input().split()))
#print(n,ss)
ss.sort(reverse=True)#降順にソート
odd = 0 #奇数
even = 0 #偶数
#print(ss)#listの確認
for i in range(n):
  if i % 2 ==0:#0，2，4，6，8～の時
    even = even + ss[i]
  elif i % 2 == 1:#13579～の時
    odd = odd + ss[i]
print(even-odd)
```
ソートの問題・・ということなのでソートを使った解き方をしています。
大きいほうから交互にとるという条件なので奇数偶数で行ける層と思いやってみたらいけました。
問5のような系統の問題のほうが苦手意識がありました。
今週はこのくらいで練習問題をいくつか挙げてくれているのでそれをやりつつ、土日で一気に残りの4問やっていこうと思います！



#ZONE4問目

```
t = []
x = input()
a = list(x)
count= 0
print(a)
nagasa = len(x)
for i in range(nagasa):  
  if a[i] == "R":
    t =t[::-1]
    count = count + 1
    print(count)
  else:
    gg  = a[i]
    t.append(gg)
    
print(t)
print(type(t))
for aa in range(nagasa):
  if t[aa] == t[aa-1]:
    del t[aa]
    del t[aa-1]
print(t)
```

ここは競技プログラミングのメモ（解けなかった)なので無関係なやつです
リストと参照　Python競プロメモ⑤


```
list_a = [1,2,3]
list_b = list_a
list_b[0] = "a"
print(list_a)
print(list_b)
```
上のコードを実行すると、結果は以下のようになる。

```
["a",2,3]
["a",2,3]
```
書き換えたのは、list_bの0番目の要素だけのはずだが、printしてみると明らかなように、list_aもまた0番目の要素が"a"となっている。これはリストが参照され、同じリストとして扱われるためである。

ここで、この解決策を記述しておく。
参照せずに、まったく同じリストを作成したいときはcopy()を用いることで可能となる。
そのコードを実際に記述すると

```
import copy
list_a = [1,2,3]
list_b = copy.copy(list_a)
list_b[0] = "a"
print(list_a)
print(list_b)
```
先ほどのコードと、copyの部分だけが異なっているが、このコードを実行すると、以下のようになる。

```
[1,2,3]
["a",2,3]
```
このように、list_bだけが書き換えられて、list_aはそのままのリストとして取り出すことに成功した。
パラメーターを使って動的にドーナツグラフの中の数字を変える

円グラフの色分けに使用したフィールドでパラメーターを作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1247969/66721c9a-6762-e98c-c637-838961884dc2.png)

選択したカテゴリのみの売上を表示する計算フィールドを作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1247969/de73aba8-8a0a-c062-32e7-43be83db9347.png)

全体のうち、選択したカテゴリの売上のパーセンテージを表示する計算フィールドの作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1247969/0213d4fe-22d8-5653-f875-d318ee75b538.png)

１の最小値のメジャーを２つ作成し、
一方で円グラフを作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1247969/e1fe4e03-fb3f-8f4f-e372-47f08763ef15.png)

もう一方に先程作成した計算フィールドをラベルに入れる
書式設定でパーセンテージに表記を変更する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1247969/ad922006-8d0b-a02b-6815-2bfadf1f2036.png)

二重軸を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1247969/1b68031e-1c16-b461-5d15-5c37d885f9e8.png)

ツールバーの「ワークシート」から「アクション」を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1247969/3ee88b92-9a60-1a68-ce23-085b0ca652e5.png)

パラメーターアクションを設定する
ソースシートは現在のシート名
パラメーターは先程作成した「パラメーター１」
フィールドはパラメーターに使用した「カテゴリ」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1247969/4960b2a3-568f-1b11-aa24-db81f0ebf48c.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1247969/29c8ed39-9f83-e30f-0be3-d28381312712.png)
マウスオーバーすると
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1247969/46bb0f5f-faa0-b218-2bcd-b408a5a86832.png)
【AE】エフェクトをオンオフスクリプト

特定のエフェクトをオフにしたいとき。

```jsx
var effectMatchName = "ADBE AIF Perlin Noise 3D";//エフェクト名をマッチネームで指定

function EffectInOff(effectName,flagValue){
    app.beginUndoGroup("特定のエフェクトを有効or無効にする");
    var myComp = app.project.activeItem;
    var selLay = myComp.selectedLayers;
    for (var i = 0 ;  i <selLay.length; i++ ){
        var myLay = selLay[i];
        var numProp = myLay.property("ADBE Effect Parade");
        var flag;
        var effectsIndex = 1;
        //$.writeln(numProp.numProperties)
        if (numProp.numProperties > 0){
            var n = 1;
            while ( n <= numProp.numProperties){
                var mn = numProp.property(n).matchName;//マッチネーム
                $.writeln("▼"+mn);
                if (　mn　== effectName ){
                    flag = true;
                    effectsIndex = n;
                    break;
                }else{
                    flag = false;
                }
                n++;
            }
        }
        if (flag == true){
           numProp.property(effectsIndex).enabled = flagValue;
        }else{
           
        }
    }
    app.endUndoGroup();
}

EffectInOff(effectMatchName,false);//第２引数はbooleanでエフェクトオン・オフ
```
[Unity] Inspector上でVector3の各成分を(min,max)に制限する

[Inspector上でVector3の各成分を(0,1)に制限する](https://qiita.com/ELIXIR/items/2a913942a29db77d21da)の続きです。
パラメータを追加することで(0,1)だけではなく(min,max)にすることも可能です。

```UserAttributes.cs
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
/// <summary>
/// Vector2/3を(min.max)に制限する <-<summary>を入れるとマウスオーバーで説明が出ます
/// </summary>
public class ClampVectorAttribute : PropertyAttribute {
    public float min;
    public float max;
    public ClampVectorAttribute(float min, float max)
    {
        this.min = min;
        this.max = max;
    }
}

#if UNITY_EDITOR
[CustomPropertyDrawer(typeof(ClampVectorAttribute))]
public class ClampVectorDrawer : PropertyDrawer
{
    // Necessary since some properties tend to collapse smaller than their content
    public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
    {
        return EditorGUI.GetPropertyHeight(property, label, true);
    }

    // Draw a disabled property field
    public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
    {
        ClampVectorAttribute attr = (ClampVectorAttribute)attribute;
        switch (property.type)
        {
            case "Vector2":
                property.vector2Value = new Vector2(
                    Mathf.Clamp(property.vector2Value.x, attr.min,attr.max),
                    Mathf.Clamp(property.vector2Value.y, attr.min, attr.max)
                );
                break;
            case "Vector3":
                property.vector3Value = new Vector3(
                    Mathf.Clamp(property.vector3Value.x, attr.min, attr.max),
                    Mathf.Clamp(property.vector3Value.y, attr.min, attr.max),
                    Mathf.Clamp(property.vector3Value.z, attr.min, attr.max)
                );
                break;
        }
        EditorGUI.PropertyField(position, property, label, true);
    }
}
#endif

```
REST APIについて

## はじめに

フロントエンド開発を学んでいくにあたって、REST APIについてちょっとだけ調べてみました。（以下ざっくり解釈である旨ご了承ください。。）

## RESTとは

**REST(Representational State Transfer)** とは設計方法のひとつで、その制約に従ったシステムをRESTfulと呼ぶようです。  

REST API（RESTful API）は、URLを一意のものとして、クライアントからのリクエストに対してJSON形式などのレスポンスを返すが一般的で、数多くのサービスで使用されています。

一意のURL、たとえば http://hogehoge.net/user/1 に対して、HTTPメソッドであるGET、POST、PUT、PATCH、DELETEを用途別に送ることで送ったメソッドにあわせた返答をもらうことができるため、APIの利用者は直感的に情報を扱うことが可能になります。

REST APIを簡単に体験するには、JSON Placeholderが便利です。

https://jsonplaceholder.typicode.com

POST、PUT、PATCH、DELETEはブラウザからは操作できないためPostmanなどクライアントソフトを使うことでテストできます。

## 参考サイト

https://www.postman.com/

https://www.xlsoft.com/jp/blog/blog/2017/06/23/post-1638/