OmniAICreator/Qiita-1.07M huggingface dataset:
twitterの情報発信を助けるWebサービス「EMOEMO」公開しました。〜アプリ開発２週目〜

~~# EMOEO延期の理由は[こちら](https://qiita.com/teranatu/items/c099a58337a3ff7d6f47)から~~

#[EMOEMOはこちら](http://emotionalemo.herokuapp.com/)


# はじめに
初めまして！てらって呼んでください:relaxed:
簡単に自己紹介をするとごみくずプログラミング初学者です。(３ヶ月目)
現在個人開発中のWEBサービス（EMOEMO）を紹介してみようと思い記事を書いています。

#EMOEMOはどんなサービス？

**メモアプリからそのままツイート出来ます！**
**EMOEMOの提供するサービスの基本はこの１点です。**
メモを管理できたりする機能も随時実装予定ですが、これはおまけみたいなもんです。

#EMOEMOは何を解決するの？

プログラミング勉強をしていてわからない単語を調べる機会はあるかとおもいます。
私の場合はかなり多く単語をgooglekeepにメモっておいて、後からまとめて調べてそれをコピペしアウトプットとしてtwitterに呟いていました。
ある時、このコピペがだる過ぎてこれを解決したくてEMOEMOを製作し始めました。

#使ってみて欲しい人は？
- 情報発信を始めた人
- まさに1ヶ月前の自分とこれからの自分です。
- twitterのタイムラインを見過ぎてしまって、時間を無駄にしてしまっているなと感じている人

#今、進捗は感じなの？

LP部
<img width="1440" alt="スクリーンショット 2020-02-11 17.37.25.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565068/7a24b98a-4bcc-7ef6-aa3a-d3b3a2f5fa87.png">
<img width="1440" alt="スクリーンショット 2020-02-11 17.37.29.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565068/c3897dca-03f2-b3a2-c3e0-bf4956c009d6.png">

CRUD機能部（作って読めて編集できて削除出来るアプリケーションの基本機能の事です）
ここでメモを追加したり編集できたりできます。

<img width="1440" alt="スクリーンショット 2020-02-11 17.16.36.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565068/19ce3c2f-5266-8c15-e347-45f0aa0a0314.png">
メモをTwitterに送信できます。
<img width="1440" alt="スクリーンショット 2020-02-11 17.55.22.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565068/d3126666-296b-6fbb-f0e7-8e0424d7b2a2.png">

#ここまで作ってみての感想など。

やはり実現したい事は高度な技術を使っている場合が多く大変です。時間の制約がある以上そぎ落とすべき肉は必ずあるし、やりたい実装の取捨選択が大変でした。これこんな難しいの！？みたいな事はザラだし、逆にめっちゃむずいと思っていたけど簡単やんこれみたいな感じな事もよくあります。

最低限必要な機能を実装し、使ってもらう事が一番だと思っているので必要な機能のみを実装しとりあえず、使ってみてもらう事を１番の目標設定にしています。

#2月の14日にデプロイします！
スケジュールはこんな感じにしています。


<img width="1440" alt="スクリーンショット 2020-02-11 20.55.22.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565068/f3af706a-b0d0-29d8-feeb-74bde8c62bf7.png">


#最後に！！！！！！

もし最後まで読んでくださっていたら方がいたらいいねをお願いします！

またね！

#[EMOEMOはこちら](http://emotionalemo.herokuapp.com/)

[個人開発をして気付いた事](https://qiita.com/teranatu/items/4de58f0c4c760adfc8dc)
iPad mini5とRaspberry Pi ZeroをUSBで繋いでみた

## はじめに
iPad ProとRaspberry Pi4をUSB-C経由で接続するのが流行っている？のでしょうか…
[https://www.raspberrypi.org/blog/connect-your-raspberry-pi-4-to-an-ipad-pro/](https://www.raspberrypi.org/blog/connect-your-raspberry-pi-4-to-an-ipad-pro/)

残念ながらiPad ProもRaspberry Pi4も持っていません

でもRaspberry PiをUSB経由で接続するといえば、Raspberry Pi Zeroです
手元にあるiPad mini5とRaspberry Pi Zero WをUSB経由で繋げてみました

## 使うもの
* iPad mini5
  - Lightning端子のiOSなら大丈夫だと思います
* Raspberry Pi Zero W
  - Raspberry Pi Zeroでも良いです
* 純正 Lightning USB 3 カメラアダプタ
* モバイルバッテリー等外部電源


## 準備
Raspberry Pi Zero Wは以下の記事等を参考にconfig.txtとcmdline.txtを修正しておきます
[Raspberry Pi ZeroをUSBケーブル1本で遊べるようにする](https://qiita.com/marron-akanishi/items/2ce4ae07c71dc8358093)


## 接続
下のような感じでそれぞれを接続します
` iPad mini5 -- Lighitning USB 3 カメラアダプタ -- Rapberry Pi Zero W 
　　　　　　　　　　　　　　　　　　　　　　　　　-- モバイルバッテリー　`
![B07E6F4F-D0CD-4DE6-9BF1-54D707AB5D37.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/481960/d97ea4eb-1621-85e6-4df8-d6d4fb647b1b.jpeg)

Lightning端子からだと外部USB機器へ十分な電力を供給できないためLightning USB 3 カメラアダプタにモバイルバッテリー等の外部電源が必要と思います


## 確認
iPad側の設定アプリを開きます
いつもは見慣れないEthernetの項目が表れて、インターフェイスとしてRNDIS/Ethernet Gadgetが認識されています
![FE47C7F8-8A9B-4DA9-BD0C-756418CC029E.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/481960/c4ee0e2b-5131-2537-080b-736ea803b969.jpeg)

この状態でSSHアプリからRaspberry Pi Zeroに接続できるようになります
ユーザー名等初期値の場合は ` pi@raspberry.local ` でログインできます

ifconfigで見ると、usb0というインターフェイスができています
![535DA6F3-B2B4-4E50-B46F-B91DC14E32D0.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/481960/40599b5b-e0eb-5d8a-70a1-9e2ea3175d5b.jpeg)


## 未解決
この状態だとiPadとRaspberry Piが直接接続されているだけなので、Raspberry Piはインターネット側に出れません…
iPadのインターネット共有を経由させればいいのかなぁ？
Raspberry Pi Zeroだとモバイルルーターとか無線LANのアクセスポイントへの接続を設定すれば、そこからインターネット側に出れますが…あんまりスマートじゃないですね…
[Ruby on Rails] includesメソッドの書き方まとめ

# 実務でまさかのincludesメソッドに戸惑う
「この画面の情報をスプレッドシートに出力しておいて」

「はーい」
（データを取ってくるだけなら余裕だろ、、、）

（あれ、関連するモデル多すぎじゃね？）

（関連するモデルに関連するモデルも取得、、あれ、、頭が、、、）

って感じで整理できていない部分がありましたので、今回まとめておきます。

# 前提
- モデルの関連付けだけをテーマに書きます。
- includesする際、単数形か複数形かはアソシエーションによって判断します。
- N+1問題を解決するためにincludesします。( [参考記事](https://www.sejuku.net/blog/26168) )

# 今回例示するモデル
- Tweets：ツイート
- Users：ユーザー
- Comments：ツイートに対するコメント
- Tags：ツイートにつけるタグ
- Addresses：ユーザーの住む住所

ここでは便宜上、関連するモデルを子モデル、子モデルに関連するモデルを孫モデルと呼ぶことにします。

## ① 子モデルが1つの場合

```rb
Tweet.includes(:user)
```

こちらはTweetに紐づくUser（子）を取得します。

## ② 子モデルが2つの場合

```rb
Tweet.includes(:user, :tags)
```
こちらはTweetに紐づくUser（子）およびTag（子）を取得します。 `([:user, :tags])` と書く場合もあるので、それは所属するチームでの決まりに従うと良いでしょう。

## ③ 子モデル・孫モデルが1セットの場合

```rb
Tweet.includes(user: :address)
```

:(コロン)の位置に注意です。こちらはTweetに紐づくUser（子）とそのUserに紐づくAddress（孫）を取得します。

#### 孫モデルが複数ある場合
```rb
Tweet.includes(user: [:address, :comments])
```
明示的に[]が必要です。こちらはTweetに紐づくUser（子）とそのUserに紐づくAddress（孫）およびComment（孫）を取得します。

## ③ 子モデル・孫モデルが1セットと子モデルが1つの場合

```rb
Tweet.includes(:tags, user: :address)
```

注意すべき点は、孫モデルまで参照するものを後ろに記述することです。こちらはTweetに紐づくTag（子）およびUser（子）とそのUserに紐づくAddress（孫）を取得します。

※ `Tweet.includes(user: :address, :tags)`とすると、筆者の場合 `SyntaxError: unexpected ')', expecting =>` と表示されてしまいます。
※ もし子モデル・孫モデルのセットが増えたなら、後ろに加えれば大丈夫です。

# 【募集】 STIをincludesする場合
今現在まだ実務で出会っていませんが、STIを参照する際のincludesの形はどうなるのだろう、、と今から不安です。もし、参考記事などございましたらご教授いただければ幸いです。

# これからも新しい書き方を見つけたら更新していきます
実務未経験から働き始めて約１週間。まだまだこんなものではないと思いますので、気付き次第随時更新していきます。

# 参考記事
[Rails ActiveRecord/SQL 小技集](https://qiita.com/tomomomo1217/items/1ccd21bfb97730763255#%E5%AD%90%E3%83%A2%E3%83%87%E3%83%AB%E5%AD%AB%E3%83%A2%E3%83%87%E3%83%AB%E3%81%AE%E7%B5%90%E5%90%88%E3%81%A8%E7%B5%9E%E8%BE%BC%E3%82%92%E3%81%86%E3%81%BE%E3%81%84%E3%81%93%E3%81%A8%E3%82%84%E3%82%8B)
dockerでHelloWorldする

# dockerでHelloWorldする

### 環境情報
* OS: Linux (centos 7.7.1908)
* docker: 19.03.5

## 手順

### イメージの一覧を確認する

```
docker images
```

まだ何もないことを確認  
実行結果  

```console
[root@centos-sample aky100200]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
[root@centos-sample aky100200]#
```

### Hello-Worldの準備
hello-worldイメージをpullする

```
docker pull hello-world
```

実行結果

```console
[root@centos-sample aky100200]# docker pull hello-world
Using default tag: latest
latest: Pulling from library/hello-world
1b930d010525: Pull complete
Digest: sha256:9572f7cdcee8591948c2963463447a53466950b3fc15a247fcad1917ca215a2f
Status: Downloaded newer image for hello-world:latest
docker.io/library/hello-world:latest
[root@centos-sample aky100200]#
```

イメージが取得できているか確認

```
docker images
```

hello-worldが追加されている

```console
[root@centos-sample aky100200]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
hello-world         latest              fce289e99eb9        13 months ago       1.84kB
[root@centos-sample aky100200]#
```

### Hello-World
実行

```
docker run hello-world
```

実行結果

```console
[root@centos-sample aky100200]# docker run hello-world

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/

[root@centos-sample aky100200]#
```

「Hello from Docker!」が出力されている。

### まとめ
次はlinuxイメージを作りたい。

## 参考
* [CentOS 7にDocker CEをインストールしてコンテナ型仮想化を使う - レムシステム エンジニアブログ](https://www.rem-system.com/centos-docker-install/)
* [Docker Hub](https://hub.docker.com/)
Rails6 DBにsaveする時にROLLBACKしてしまい原因がわからない時

# 目的

- DBにsaveする際にROLLBACKしているときのエラーの表示方法をまとめる

# 実施方法

- saveの命令の後ろに`!`をつけてあげるとエラー文が表示される。

# 具体的な例

- `@user.save`をただ実行しただけの時

    ```ruby
    User Exists? (0.5ms)  SELECT 1 AS one FROM `users` WHERE `users`.`email` = 
    BINARY 'miriwo.rails@gmail.com' LIMIT 1
    (0.2ms)  ROLLBACK
    => false
    ```

- `@user.save!`を実行した時

    ```ruby
    User Exists? (0.5ms)  SELECT 1 AS one FROM `users` WHERE `users`.`email` = 
    BINARY 'miriwo.rails@gmail.com' LIMIT 1
    (0.2ms)  ROLLBACK
    Traceback (most recent call last):
        1: from (irb):21
    ActiveRecord::RecordInvalid (Validation failed: Password can't be blank)
    ```

- 最後にエラー文が一文追加されたことがわかる
Slack から LINEWORKS にメッセージ転送する Bot 作ってハマったこと

# 概要

Slack の Events API をつかった Bot 開発に挑戦しました。ハマった内容をまとめます。

## Bot 仕様

Slack から LINE WORKS へメッセージを転送します。
Slack Bot が登録されているプライベートチャンネルに投稿されたメッセージを
LINE WORKS 側の Bot が受取り、特定のユーザに通知するというものです。

システム構成は以下のような感じです。Bot プログラムは AWS Lambda で実装しました。

![Untitled Diagram.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72233/c16d5654-e73a-20b1-2980-3b78a92b5f13.png)

（なぜこんなことをしているか）
社内標準のチャットツールは LINE WORKS なのですが、私の所属する情シスグループでは slack を常用しており、特に社内システムからのアラートの通知先として活用しています。今回、とある社内組織にシステムのアラートを共有する必要があり、かつ標準ツールである LINE WORKS をつかってもらいたいという意図から、勉強を兼ねて Botを作ることにしました。

## Slack Event API とは

Slack にメッセージが投稿された、ユーザーがワークスペースに登録されたといったイベントをフックする API です。API のスコープやメソッドを使い分けることで、特定のチャンネルのイベントに限定したり、ワークスペース全体を監視したりすることができます。

## ハマったこと

Slack Bot が所属していないチャンネルのメッセージも転送されてしまいました。
設定によってプライベートチャンネル限定だったり、パブリックチャンネル限定だったり。

## 原因

Slack API の「Event Subscriptions」の各種設定が誤っていました。

1. 設定「Subscribe to bot events」と「Subscribe to events on behalf of users」の違い
2. イベント「message.groups」と「message.channels」の違い

をよくわからないまま、なんとなく設定していたことにより、不安定な振る舞いをしていました。

## 1. 設定「Subscribe to bot events」と「Subscribe to events on behalf of users」の違い

前者の「Subscribe to bot events」はワークスペース上の様々なイベントを対象とします。例えばワークスペース名の変更を検知する「team_rename」イベントや"誰かに"DMが投げられたことを検知する「message.im」などです。これらのイベントは、特定のユーザーやチャンネルに限定されず、すべからく拾われます。

一方、後者の「Subscribe to events on behalf of users」は招待されたチャンネルに関するイベントのみを対象とします。

## 2. イベント「message.groups」と「message.channels」の違い

groups と channels、一見同じものを指しているように見えますが

* groups = プライベートチャンネル
* channels = ワークスペース上のすべてのチャンネル(パブリック、プライベート関係なし)

となります。

Bot 仕様である「Slack Bot が登録されているプライベートチャンネル」に限定する場合は
"Subscribe to bot events" でイベント"message.groups" を選択しなければなりません。

![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72233/e060f2da-0bf5-66a5-83c3-1565681b91f0.png)

一方、私は "message.channels" を選択していました。一見似ていますが、groups はプライベートチャンネルのみ、channnels はパブリックチャンネルを含むすべてとなります。このため、Bot を登録しているチャンネル以外のメッセージもみだりに転送されてしまう事態に。

## まとめ

* groups = プライベートチャンネル
* channels = ワークスペース上のすべてのチャンネル(パブリック、プライベート関係なし)
* ドキュメント読め

## 参考
* Slack 関連
 * Slack API
    https://api.slack.com/
 * Incoming Webhook
    https://api.slack.com/messaging/webhooks
 * Events API
    https://api.slack.com/events-api
  
* LINE WORKS 関連
  * LINE WORKS Developers
    https://developers.worksmobile.com/jp/?lang=ja
  * トーク Bot
    https://developers.worksmobile.com/jp/document/5?lang=ja
【個人メモ】Node.js LINEBOT雛形

## プロジェクト作成とハローワールド

```console
$ mkdir linebot
$ cd linebot 
$ npm init -y
```
```console
$ npm i @line/bot-sdk express 
```
```console
$ npm install dotenv --save
```

```console
$ touch index.js $$ .env
````
```console
$ code .
```

```index.js
'use strict';

const express = require('express');
const line = require('@line/bot-sdk');
const PORT = process.env.PORT || 3000;
const dotenv = require('dotenv')
dotenv.config()

const config = {
    channelAccessToken: process.env.CHANNEL_ACCESS_TOKEN,
  channelSecret: process.env.CHANNEL_SECRET
};

const app = express();

app.get('/', (req, res) => res.send('Hello（GET)')); 
app.post('/webhook', line.middleware(config), (req, res) => {
    console.log(req.body.events);

     if(req.body.events[0].replyToken === '00000000000000000000000000000000' && req.body.events[1].replyToken === 'ffffffffffffffffffffffffffffffff'){
        res.send('Hello!(POST)');
        console.log('疎通確認用');
        return; 
    }

    Promise
      .all(req.body.events.map(handleEvent))
      .then((result) => res.json(result));
});

const client = new line.Client(config);

function handleEvent(event) {
  if (event.type !== 'message' || event.message.type !== 'text') {
    return Promise.resolve(null);
  }

  return client.replyMessage(event.replyToken, {
    type: 'text',
    text: event.message.text 
  });
}

app.listen(PORT);
console.log(`Server running at ${PORT}`);
```

```..env.sample
CHANNEL_ACCESS_TOKEN = "xxxxxxxxxxxxxxxxxxx"
CHANNEL_SECRET = "xxxxxxxxxxxxxx"
BASE_URL = 'xxxxxxxxxxxxx.ngrok.io'
```

```console
$ ngrok http 3000
```
BASE_URLの書き換え

```console
$ node index.js
```
webhookURLの設定

https://xxxxxxxxxxxxxxxxxx.ngrok.io/webhook
ミルクボーイ「Fortran」

「どうもミルクボーイですお願いします～。あ、ありがとうございます、今、**512MBのUSBメモリ**をいただきました～、こんなんなんぼあっても困りませんからねえ」

「_おかんがねえ、好きなプログラミング言語の名前忘れたらしいねん_」
「言語の名前忘れたん？コンパイルしたり実行したりするときに打たへんのかいな、ほなおれがおかんの好きな言語考えたげるわ」

「_おれもよくわからへんねんけど、なんか歴史がめっちゃ古くて、大学では今でも最初に教わるらしいねん_」
「そりゃお前、Fortranやな。**世界最初の高級言語やのに今でも大学で教えられる**んやから、大したもんやで」

「_でもな、おかんが言うには、初心者でもすぐ使いこなせる簡単な言語らしいねん_」
「ほなFortranちゃうかあ。Fortranは**習うときは簡単っていうけどそれはアセンブラとかCに比べての話**やからね？2020年にもなったら平均よりは難しい言語なのよ。えーじゃあもうちょっと詳しく教えてくれる？」

「_おかんが言うには、いまだに2008って名前がつく規格が普及してへんらしいねん_」
「Fortranやないか！もう2020年やのに[Fortran2008の機能はGNUのコンパイラも網羅はしてへん](http://fortranwiki.org/fortran/show/Fortran+2008+status)からね？絶対Fortranやん、なんでFortranちゃうの」

「_俺もそう思ったんやけど、おかんが言うには、組み込みからフロントエンドまで何でもできるらしいねん_」
「ほなFortranちゃうかあ。今どきFortranが通用するの数値シミュレーションくらいやもんねえ？MPIのインターフェースがCかFortranくらいやから仕方なく使ってるのよ。そんな並列化の手法も今はMPIだけちゃうからね？もうじゃあ何なのよ」

「_おかんがね、今もNASAからも求人があるって_」
「Fortranやないか！ちょっと前の[ちょっとしたニュース](https://www.bbc.com/news/amp/technology-39803425%3Fusqp%3Dmq331AQOKAGYAb6-2_qep-ehuAE%253D)になったやつね？俺も見てカレンダーの年確認したわ。逆に数値計算はFortranしかないんかいなとも思ったわ、もうそんなんFortranやん」

「_でもおかんが言うには、移植が一瞬らしいねん_」
「ほなFortranちゃうやないか！Fortranのソースなんか大抵継ぎ足し継ぎ足しされてきた秘伝のソーススパゲティなのよ！**同じFortranでもintelはコンパイル通るのにcrayでは通らんとかざらにある**からね！？おれは教授に言われてやった移植作業に時間とられて教授に『何やってるんですか、そんなの移すだけでしょう』って言われたのよ！？もう絶対FortranやのになんでFortranちゃうのよ」

「_俺もそう思ってん、でもおかんが言うには、NAGがめっちゃ優しいらしいねん_」
「Fortranやないか！！『Fortran わからんこと』って検索したらNAGさんが教えてくれるねん！！Fortranerは絶対NAGのドキュメントにはお世話になるのよ！！！もう絶対Fortranで決まりやん、なんでちがうのよ」

「_おかんが言うには、クラスが自然な形で記述できるらしいねん_」
「Fortranちゃうやん！FortranでOOPは地獄の道やねん！！まず言語仕様が後付けやから無理なのよ！！それをソーススパゲティに適用するとか、[stdioを一切使わないでメールサーバ書くの](https://jp.quora.com/%E4%BB%96%E4%BA%BA%E3%81%AE%E3%82%B3%E3%83%BC%E3%83%89%E3%82%84%E8%A8%AD%E8%A8%88%E3%82%92%E8%A6%8B%E3%81%A61%E7%95%AA%E3%81%93%E3%82%8C%E3%81%AF%E3%81%82%E3%82%8A%E5%BE%97%E3%81%AA%E3%81%84%E3%81%A0%E3%82%8D)と同じくらい難しいから！！**やったとしても誰も評価してくれへん**のよ！！教授には『それ意味あるんですか、そんなことより研究してください』って言われるのが関の山や！！もうほんまにわからへんやん、じゃあ今のところ何やと思ってんのよ」

「_オトンがね、BASICちゃうかって_」
「いや絶対ちゃうやろ、どうも、ありがとうございました～」
nginxについて

# Nginxとは
Apacheの代替えとして提案されたwebサーバソフトウェアである。
Apacheには同時多数接続時の処理に弱い問題点があった。（クライアント1万台問題）
そこで、高負荷に強いwebサーバソフトウェアとして開発されたのがNginx

リバースプロキシ : クライアントとwebサーバの間に立ち、代わりに処理を行う。
ロードバランサ　 : クライアントからのリクエスト複数のサーバーに分散させる。

# Apacheとの比較

|        |Nginx|Apache|
|-------|-------|------|
|高負荷への強度|強|弱|
|メモリ使用量|少|普|

さらもNginxには多くの機能がモジュール化されているため、機能構成変更が容易である。
リバースプロキシ、ロードバランサとしての機能もある。



# 参考文献
>https://academy.gmocloud.com/qa/20160616/2761
>https://qiita.com/kamihork/items/49e2a363da7d840a4149
Office365 MFAの選択肢（ハードウェア トークンからの確認コード）

# Office365 MFAの選択肢（ハードウェア トークンからの確認コード）
Azure Active Directory Premium P1/P2が必要
OTPカードが必要（今回使ったのは海外で売っている2000円くらいのカード、、、日本で売ってないんかね？）
※Azure Active Directory Premium P1/P2を持っていないとOATHトークンという項目が見えなかった

## Azure Active Directory 管理センター側
1. OTPカード販売元からトークン用のファイルを入手し、ファイルをアップロード
その後、アクティブ化を行う（アクティブ化時にコード入力が必要）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315938/c85d3ae8-0bd4-a1d1-8186-afcbf59164af.png)

2. MFAを有効化する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315938/251be34f-7499-58a8-3d34-c6744ab2607c.png)
[Java] TreeMap successor method and entrySet complexity

## Succcessor Method

As we know `TreeMap` is implemented by Binary Search Tree. So I am very curious about the `entrySet` or `subMap` method implementation and complexity.

It turns out java do it very straight forward. For entrySet, it start from the first node and by finding successor to move to next node. 

It has a successor method to find next node by the following steps.

- if current node is null, then no next, return null
- if current node has right child
    - find the most left one of right child as next node
- if current node does not have right child, check current node is left or right child
    - if it is left child, the parent is next code
    - if it is right child, then go back to parent
 
```java
/**
 * Returns the successor of the specified Entry, or null if no such.
 */
static <K,V> TreeMap.Entry<K,V> successor(Entry<K,V> t) {
    if (t == null)
        return null;
    else if (t.right != null) {
        Entry<K,V> p = t.right;
        while (p.left != null)
            p = p.left;
        return p;
    } else {
        Entry<K,V> p = t.parent;
        Entry<K,V> ch = t;
        while (p != null && ch == p.right) {
            ch = p;
            p = p.parent;
        }
        return p;
    }
}
```
## Complexity
About the complexity, [here](https://cs.stackexchange.com/a/6383) has a good explain. 
Assume we go through a balanced BST. We can separate it as two parts. 

- The leaf nodes
- All other nodes

The average steps is 2 according to the explain [here](https://cs.stackexchange.com/a/6383). so the average complexity of successor is `O(1)` and the complexity of going through all elements with entrySet is `O(n)`.
Office365 MFA 確認コード表示デバイス追加する場合

# Office365 MFA 確認コード表示デバイス追加する場合
2台目のスマホに入れるとか、機種変更しましたーとの理由で再度確認コードを設定する画面を表示する場合の方法
※管理者とユーザーで連携しながらやりましょう
ちなみにデバイス無くしちゃった…というときは方法ないです。（Intuneとか使って消去…別途Intuneネタは書こう）

1. 「ユーザー設定の管理」を押す
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315938/66b73b2e-42ce-ea94-4b4e-2fbb0e5597fa.png)


2. 「選択したユーザーについて連絡方法の再指定を必須にする」にチェックを入れて保存
これでまた設定画面が出るようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315938/19cf912e-b2a8-be38-9b15-dcb6f3412689.png)
【機械学習】K-meansを勉強してみる


# K-meansクラスタリングとは?
K-means はクラスタリングに使われる教師なし学習方法です。
K個のクラスタに分類し、平均値を重心とするのでK-meansと呼ばれています。

# K-Meansのアルゴリズム
1) ランダムに1~k個のデータポイントをクラスタの重心$\mu_i$として選ぶ。
2) 残りの全てのデータポイントを1で選んだ一番近いクラスタに割り振る。
3) 各クラスタで平均値を計算し、$\mu_i$をアップデートする。
4) 2~3を重心の変更がなくなるまで繰り返す。



<img width="855" alt="Screenshot 2020-02-11 at 21.33.59.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407366/2fab669b-1b4e-a320-3815-de96e7631434.png">

# Kの決め方　(Elbow Method)
K-meansではクラスタの数 Kを指定する必要があります。Kが多すぎると過学習してしまったり、逆に少なすぎると、本来分けられるべきデータが同じクラスタに入ってしまう可能性もあります。そこで、最適なKを見つけるのに**Elbow method**という方法があります。

Elbow method では y軸に損失をとり、x軸にクラスタ数 K をとる下のようなグラフを描きます。この時、肘のように曲がっている部分に値するKを最適なクラスタ数とするので、Elbow Method と呼ばれています。

<img width="411" alt="Screenshot 2020-02-11 at 22.10.03.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407366/cbd2a943-cefc-4b71-a793-90943640d62b.png">





# scikit learn で K-Means

### パラメター
|パラメター|概要|値|デフォルト|
|---|---|---|---|
|n_clusters|クラスタの数|int|8|
|init|初期重心の設定|'k-means', 'random', データポイント|'K-means++'(速く収束させるように自動で選んでくれる)|
|n_init|何回重心を変えるか|int|10|
|max_iter|繰り返しの回数|int|10|
|tol|収束の許容値|float|1e-4|
|precompute_distance|距離を行列か個々で計算するか|'auto', bool|'auto'|
|random_state|重心の初期値のランダム方法|int, RandomState instance| None|
|n_jobs|各実行時の同時処理の数|int|None|

### Pythonの実行例

#### Elbow Method
```python

from sklearn import datasets
import matplotlib.pyplot as plt
import pandas as pd
from sklearn.cluster import KMeans

iris = datasets.load_iris()
X = iris.data[:, :2]
y = iris.target

from sklearn.cluster import KMeans
wcss = []

for i in range(1, 11):
    kmeans = KMeans(n_clusters = i, init = 'k-means++', max_iter = 300, n_init = 10, random_state = 0)
    kmeans.fit(X)
    wcss.append(kmeans.inertia_)
    

plt.plot(range(1, 11), wcss)
plt.title('The elbow method')
plt.xlabel('Number of clusters')
plt.ylabel('WCSS') 
plt.show()

```

![download.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407366/8e2678a4-84c7-ac87-a4ae-6f7112f93956.png)

丁度3ぐらいが肘にあたるので、K = 3で学習させる。

#### Predict 

```python

kmeans = KMeans(n_clusters = 3, init = 'k-means++', max_iter = 300, n_init = 10, random_state = 0)
y_kmeans = kmeans.fit_predict(X)

plt.scatter(X[y_kmeans == 0, 0], X[y_kmeans == 0, 1], s = 100, c = 'red', label = 'Iris-setosa')
plt.scatter(X[y_kmeans == 1, 0], X[y_kmeans == 1, 1], s = 100, c = 'blue', label = 'Iris-versicolour')
plt.scatter(X[y_kmeans == 2, 0], X[y_kmeans == 2, 1], s = 100, c = 'green', label = 'Iris-virginica')

#Plotting the centroids of the clusters
plt.scatter(kmeans.cluster_centers_[:, 0], kmeans.cluster_centers_[:,1], s = 100, c = 'yellow', label = 'Centroids')

plt.legend()
```

![download (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/407366/200ad574-3c6f-bf8b-fc3e-5f59da874cb2.png)

# K-meansの利点と欠点
### 利点
- シンプル。
- 可視化しやすい。

### 欠点
- スケールに依存しやすい。
- 不均一で広範囲に散らばるデータには向いていない。
Windowsでgulpの環境構築。yarn編

#yarnでgulpの環境構築
gulpの環構築の時にサラッと出来るように自分用に投稿。
完璧に初心者なのであしからず

※ちなみにyarnもgulpもnodeもインストール済みとして書きます。

##環境
・yarn
1.21.1
・gulp
CLI version: 2.2.0
Local version: 4.0.2 `
・node(楽だからnodistで管理したほうがいいかも)
v11.13.0

##手順
 test(任意)フォルダの中に移動します

```
 C:\Users\(ユーザー名) > CD test
```

```
 C:\Users\(ユーザー名)\test >
```
ちなみにtestフォルダの中は下記になります

```
 test─┬─css
      ├─scss
      │  └─main.scss
      └─index.html
```
package.jsonを生成しないとダメなので下記を実行

```
 C:\Users\(ユーザー名)\test > yarn init
```
実行すると色々聞かれるけどエンター連打。
そうするとtest直下にpackage.jsonが生成される。

```
 test─┬─css
      ├─scss
      │  └─main.scss
      ├─package.json
      └─index.html
```
macはこの時にgulpのローカルインストールをする

```
 C:\Users\(ユーザー名)\test > yarn add gulp
```
パッケージをインストールします。なのでとりあえず下記を実行。
(後で色々変更できるけどとりあえず)

```
 C:\Users\(ユーザー名)\test > yarn add --dev gulp
 C:\Users\(ユーザー名)\test > yarn add --dev gulp-sass
 C:\Users\(ユーザー名)\test > yarn add --dev gulp-autoprefixer
 C:\Users\(ユーザー名)\test > yarn add --dev gulp-plumber

```

次にgulpfile.jsの生成。これは自分で作らないとだめなやーつ。
作ったらtestフォルダに放り投げといて下さい。
中身はざっくりこんな感じ。

```
const { watch, series, task, src, dest } = require('gulp');
const sass                               = require('gulp-sass');
const autoprefixer                       = require('gulp-autoprefixer');
const plumber                            = require('gulp-plumber');
 
const convertToCss = () =>
	src('scss/*.scss')
      .pipe(plumber())
      .pipe(sass())
      .pipe(autoprefixer())
      .pipe(dest('css/'));
 
const watchscss = () =>
	watch('scss/*.scss', convertToCss);
 
exports.default = watchscss;

```
.pipe(dest('css/'));の部分を
.pipe(dest('css'));にしててそれに気づかず大変でした。

最後に下記を実行して終了

```
 C:\Users\(ユーザー名)\test >　yarn gulp

```
これでちゃんとコンパイルが出来ているはず。
何故かこれだけの作業なのに結構時間がかかった。
Queueを使った問題

#Atcorder154　D問題
***配列***を操るのがまだ苦手なんだなぁって再認識させられた問題だった...
この問題を***Queue***で解いて、配列の苦手を克服していこう！
https://atcoder.jp/contests/abc154/tasks/abc154_d

```c++
#include<bits/stdc++.h>
#define rep(i,n) for(int i=0; i<(n); i++)
using namespace std;
using ll = long long;
const ll INF = 1e9 + 7;

int main(){
    ll N,K; cin >> N >> K;
    vector <int> P(N);
    rep(i,N) cin >> P[i];
    double mx=0;
    double s=0;
    queue<double> Q;
    rep(i,N){
        s+=(1.0+P[i])/2.0;
        Q.push((1+P[i])/2.0);
        if (Q.size()>K){
            s-=Q.front(); Q.pop();
        }
        if (Q.size()==K){
            mx=max(mx,s);
        }
    }
    printf("%.10f\n",mx);
    return 0;
}
```

#累積和を用いても解ける
```c++
#include<bits/stdc++.h>
#define rep(i,n) for(int i=0; i<(n); i++)
using namespace std;
using ll = long long;
const ll INF = 1e9 + 7;
typedef pair<int,int> P;// pair型は２つの値の組を表せる

double A[1001001],B[1001001];
int main(){
    int N,K; cin >> N >> K;
    B[0]=0;
    for (int i=0; i<N; i++) cin >> A[i];
    for (int i=0; i<N; i++) A[i]=(1+A[i])/2.0;
    for (int i=1; i<N+1; i++) B[i]=A[i-1]+B[i-1]; //累積和
    
    double ans=0;
    for (int i=0; i<=N-K; i++){
        ans=max(ans,B[i+K]-B[i]);
    }
    cout << fixed << setprecision(12) << ans << endl;
    return 0;
}
```
#累積和の考え方
配列A:　1　6　3　8　4　2　9　5　7
配列B:　0　1　7　10　18　22　24　33　38　45
***配列Aの2番目の数(3)から6番目の数(9)までの和は配列Bの7番目の数(33)から配列Bの2番目の数(7)を引いた数である。これを一般化すると、
配列Aのx番目の数からy番目までの和は、配列Bのy+1番目の数からx番目の数を引いた値である。*** 
https://qiita.com/xryuseix/items/1059101a31107ba330d4
GE〇オンラインレンタルの55円キャンペーンメールを受信したらGoogleカレンダーに登録するGoogle Apps Script

#作成動機
なんとなくやってみたかった

#コード
```javascript:Code.gs
function createEvents(mail) {
  var calendar = CalendarApp.getDefaultCalendar();
  var title = mail['subject'];
  var startTime = new Date(mail['date']);
  var endTime = new Date(mail['date']);
  var location = '';
  
  if(mail['duedate']) {
    endTime = new Date(mail['duedate']);
  }
  
  if(mail['location']) {
    location = mail['location'];
  }
  
  var option = {
    description: mail['body'],
    location: location
  }
  
  console.log("add event detail")
  console.log("title = " + title)
  console.log("start = " + startTime)
  console.log("end = " + endTime)
  console.log("body = " + mail['body'])
  console.log("location = " + location)
  
  //return calendar.createEvent(title, startTime, endTime, option);
  calendar.createEvent(title, startTime, endTime);
}

function extractDueDate(target,pattern) {

  var regexp = new RegExp(pattern,'i')
  var match_result = target.match(regexp);

  if( match_result.length > 0 ) {
    return match_result
  } else {
    return "" 
  }
  
}

function fetchContactMail(filterPattern) {
 var now_time= Math.floor(new Date().getTime() / 1000) ;
 var time_term = now_time - ((60 * get_interval) + 3);
 
 var strTerms = '(is:unread after:'+ time_term + ')';
 
 var myThreads = GmailApp.search(strTerms);
 var myMsgs = GmailApp.getMessagesForThreads(myThreads);
 var valMsgs = [];

 for(var i = 0; i < myMsgs.length;i++){
   
   var contents = myMsgs[i][0].getFrom() + myMsgs[i][0].getSubject() + myMsgs[i][0].getPlainBody()
   
   regexp = new RegExp(filterPattern,'i')
     
   if(! contents.match(regexp) )
   {
     continue
   }
  
   var mailcontents = {
     "date": myMsgs[i][0].getDate()
     , "from" : myMsgs[i].slice(-1)[0].getFrom()
     , "subject" : myMsgs[i].slice(-1)[0].getSubject()
     , "body" : myMsgs[i].slice(-1)[0].getPlainBody()
   }
   valMsgs[i] = mailcontents
 }
 
 return valMsgs;
}

function main() {
 newmail = fetchContactMail("旧作全品55円")
 if(newmail.length > 0){
   for(var i = newmail.length-1; i >= 0; i--){
     //send_line(newmail[i])
     var dueDates = extractDueDate(newmail[i]['body'],"【期間限定】(.*?)年(.*?)月(.*?)日.*?\\)(.*?)まで")
     
     console.log(dueDates[1])
     console.log(dueDates[2])
     console.log(dueDates[3])
     console.log(dueDates[4])
     
     newmail[i]['duedate'] = new Date(dueDates[1] + "/" + dueDates[2] + "/" + dueDates[3] + " " + dueDates[4])
     
     createEvents(newmail[i])
   }
 }
}
```
フロントエンドエンジニアとして6か月働いてコードレビューで指摘されたこと３つ

##1.見た目とデザインを合わせる
自分が作ったものとデザイナーからもらったXDファイルの見た目が異なっていた。

（※Adobe XD は、ユーザー操作性をデザイン、プロトタイプ化、共有するためのプラットフォームです。ワイヤフレーム、ビジュアルデザイン、インタラクションデザイン、プロトタイプ化、プレビュー、共有間の切り替えが簡単な、オールインワンの強力なツールです。（公式サイトより））以下、XD


######どういう指摘をされたか
H殿、K氏「ここが違うよ」
例えば、XDでは文字色が白なのに、書いたコードでは黒になっていると単純なものであった。
また、自分はPC版からコードを書くため、SP版用文字サイズの変更し忘れのミスを一番指摘された。

######それはなぜか
自分が書いたコードが、間違っていた。
単純に見落としでの間違いだった。
コードレビューの前に自分で最終確認をしていなかったためである。

######どのように直したか
一か所ずつ確認するようになった。

もちろん、XDを確認しながらコードを書くが、一通り書き終えてから
XDの文字サイズ、文字色、余白の幅などを再確認するようになった。

まだまだ指摘はされますが....


##2.不要なコードの削除
コードレビューの前にまたまた最終確認をしておらず指摘をされたこと....


######どういう指摘をされたか
H殿、K氏「これいらないよね」
CSSでXDファイルでファイル通りの見た目にするために実験的に書いていたCSSプロパティが不要だった。

######それはなぜか
1.見た目とデザインを合わせるでも記載したが、コードレビューの前に自分が書いたコードの最終確認を怠ったためである。

######どのように直したか
実験的に書いたコードは、確認し終えたらすぐ消すように習慣づけるようにした。
また、最終確認の際も気を付けてコードを確認するようになった。


当たり前のことなのにできていなかったためミスを起こしていた.......


##3.クラス名

######どういうコードを書いたか
```html

<!-- 修正前 -->
<div class="header-contents-logo">

<!-- 修正後 -->
<div class="header-logo">
```

修正前は、見たままの入れ子構造通りに書いていた。

######どういう指摘をされたか
H殿、K氏「クラス名、関数名のつけ方が下手糞」

H殿「logoの親コンポーネントはなにー？」

ぼく「header.....」

H殿「header-logoでいい」

######それはなぜか
まだ、クラス名のつけ方に慣れていなかった。
親コンポーネントなどの規則を知らなかったため。

######どのように直したか
書き方を知らなかったので、
他サイトのクラス名をディベロッパーツールで確認、Bootstrapで学習するようにした。
また、CSSの命名規則を調べるようになった。
基本情報技術者　マネジメント系　第1章 プロジェクトマネジメント④


# ④コミュニケーション、リスク、ステークホルダ、調達

## プロジェクトコミュニケーションマネジメント
計画、実行、関しコントロールプロセスに関わります。

重要なのは、ステークホルダに実績を報告することです。

以下の点が大事です。

* 情報の緊急度
* 技術の可用性
* プロジェクト要員配置
* プロジェクト期間
* プロジェクト環境

## プロジェクトリスクマネジメント
好機を発生させ
脅威を抑えるのが重要です。

#### リスクマネジメント
下記の手順で大まかに行われます。

1,リスクの識別
2,リスクアセスメント(アセスメントとは分析して評価)
3,リスク対応の策定

#### 評価値
下記のような形で求めます。

被害金額(影響度)x発生確率

#### 残留リスク
優先度が低く、残したままにしたリスク

### RBS(Risk Breakdown Structure)
リスクをトップダウンで抽出し、階層構造で表す図です。

### コンティジェンシプラン
リスクの顕在化した場合の代替計画

### コンティンジェンシ予備
リスク対策予算

### 脅威に対するリスクコントロール
下記のようなコントロールがあります。

* リスク回避
* リスク移転
* リスク軽減
* リスク保有

## ステークホルダマネジメント
ステークホルダと上手く共同プロジェクトにすること

### ステークホルダ特定
ステークホルダ周りの調査

### ステークホルダエンゲージマネジメント
エンゲージマネジメントとは［物事への関心の深さ］

## プロジェクト調達マネジメント
計画、実行、監視コントロール、終結プロセスが関わります。

### RFI (Request For Information)
ベンダに情報提供を依頼

### RFP (Request For Proposal)
ベンダに提案を依頼

### RFQ (Request For Quotation)
ベンダに見積もりを依頼
Javascriptは書く順番が大切

Vue.jsを書いていて、どうしても動かずハマってしまった部分がありました。
FirebaseをWebアプリに連携しようとして、 `main.js` に以下のように記述していました。

```javascript

<script>
import { firestorePlugin } from 'vuefire'
    import firebase from 'firebase'
    import 'firebase/firestore'
    
    Vue.use(firestorePlugin)
    
    export const db = firebase.firestore()
    export const auth = firebase.auth()
    
    Vue.config.productionTip = false
    
    firebase.initializeApp({                
      apiKey: "",
      authDomain: "",
      databaseURL: "",
      projectId: "",
      storageBucket: "",
      messagingSenderId: "",
      appId: ""
    })

</script>

```

**scriptは上から下に向けて実行される**ため、これだと `ｄｂ` のインスタンスを作成する場合にfirebaseの認証がされていないことになります。
そのため、 `db` のインスタンスが作成されず、表示することができませんでした。
正しくは、 `firebase.initializeApp` を `db` のインスタンス作成より前に書き、

```javascript

<script>
import { firestorePlugin } from 'vuefire'
    import firebase from 'firebase'
    import 'firebase/firestore'
    
    Vue.use(firestorePlugin)

　　 firebase.initializeApp({                
      apiKey: "",
      authDomain: "",
      databaseURL: "",
      projectId: "",
      storageBucket: "",
      messagingSenderId: "",
      appId: ""
    })
    
    export const db = firebase.firestore()
    export const auth = firebase.auth()
    
    Vue.config.productionTip = false
    
    

</script>

```

とすることで解決します。
またひとつ前進しました。
設計、資料作成に活躍、クラウドサービスアイコン集

# AWS
<a href="https://aws.amazon.com/jp/architecture/icons/">AWS アーキテクチャアイコン</a>

# GCP
<a href="https://cloud.google.com/icons/">アーキテクチャ図用のソリューション アイコン</a>

# Azure
<a href="https://www.microsoft.com/en-us/download/details.aspx?id=41937">Microsoft Azure Cloud and AI Symbol / Icon Set - SVG</a>

# Oracle Cloud
<a href="https://docs.cloud.oracle.com/ja-jp/iaas/Content/General/Reference/graphicsfordiagrams.htm">トポロジおよびダイアグラムのグラフィック</a>

# NIFTY Cloud
<a href="https://pfs.nifcloud.com/icons/">アイコン＆シンボル ダウンロード</a>

# さくらのクラウド
クラウド用ではありませんが。
<a href="https://knowledge.sakura.ad.jp/4724/">さくらのアイコンセット</a>
【rails】credentials.yml.encについて

#はじめに
初学者がポートフォリオ作成でハマったことをメモします。
AWSにデプロイする際credentials.yml.encでハマったので箇条書きでメモしておきます。

##credentials.yml.encについて
・秘密情報を保持するためのファイル。
・configディレクトリに作成される。
・rails newで作られる。
・暗号化されておりgithubで管理出来る。
・復号化する為には同じくrails newで作成されるconfig/master.keyを使う。(master.keyはデフォルトで.gitignoreに含まれており、master.keyがGitリポジトリに含まれないようになっている。)
・master.keyを削除してしまった場合はcredentials.yml.envを削除した後`sudo EDITOR=vim rails credentials:edit`で新しいcredentials.yml.envとmaster.keyを作成する。
・リポジトリーをcloneした場合master.keyはコピーされていない為、master.keyをコピぺする必要がある。 
・直接エディタから編集する事ができない。vimを使って編集可能。　`$ EDITOR=vim bin/rails credentials:edit`
・デフォルトでコメントアウトがついている為注意。
・master.keyが共有できない環境では環境変数：RAILS_MASTER_KEYを指定する。




##参考にした記事
https://qiita.com/yamamoto_shuji/items/5afd9ffe13f36ff29677
https://qiita.com/scivola/items/cc06ddbfd94d3118f693
LPトレースでマークアップを鍛える方法

Webサイト作成初学者や、マークアップエンジニア志望の非エンジニア向けです。
ブログサイトやコーポレートサイトのマークアップはできるけどLPが苦手、、、、といった人へ届け！

# マークアップ力を鍛える
HTMLを学び始めると、 `<h1>`、`<p>`、`<a>`、`<ul>`、`<li>`、`<img>`などが最初に覚えるタグだと思います。
HTML５から学び始めれば、 `<header>`や`<article>`などのタグも知っている人は多いかもしれません。

ブログのようなサイトであれば、簡単にマークアップができていても、
LPなどレイアウト自由度が高くなると、突然速度が落ちる例は少なくないかと思います。

LP作成ではもちろんCSSスキルは大事ですが、まずは正しいマークアップができるかがだ最も大事です。

そこで、複雑なLPマークアップであっても速度を落とさずに開発するための練習に最適なのが、
**商品PRサイトのトレース**です！！！
これはとても良い練習になります。


以下はアサヒ飲料株式会社さんの十六茶の商品サイトのワンカットです。
↓------------------  PCサイズ  ------------------↓
![asahi_16cha_lp.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513045/bd468086-34d2-5748-8b27-9072120b5995.png)
↓-------------- SPサイズ ------------------↓
![asahi_16cha_lp_sp.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513045/aacfdd85-f919-c37b-d387-26cff9db5c46.png)

出典：https://www.asahiinryo.co.jp/16cha/sp/

私が考えるポイントは以下です。

- デザインからワイヤーに変換
- PC/SPの違い
- レイヤー構造を意識


レスポンシブデザインは今では必須です。
（個人的には令和の今時、PCイラナクナイ？なんて思うサイトもありますが...心の声）

# デザインから設計をしっかり行おう
まずは設計です。
行き当たりばったりの開発は危険ですし、後々「こうしていればよかった...」なんてことも多いです。

デザインをワイヤーとして考えてあげると、シンプルに考えることができるようになります。
![asahi_16cha_lp.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513045/a2c3b122-8b51-98e3-9dad-014f2c84b119.png)

この時、SP用のデザインとPC用のデザインをしっかり見て要素を分けましょう。

- 人のイラストは常にサイドに配置されている
- 「十六茶」のひみつはSPの場合に改行が増えている
- 動画はフォーカス時にはサイズアップ
- 再生ボタンはフォーカス時のインタラクションに影響されない
- ボタンは常に中央
- ボタンはボーカス時にアニメーション

上記の要素を実現するためにマークアップを行います。
**要素はまとめればまとめるほど自由度を失います。**

適度な単位で要素を区切ってあげられるようにします。
>人のイラストはタイトルイメージ中で常にサイド下部に配置したいので、
配置領域用の`<div>`タグで囲ってあげよう...

# 答え合わせしっかり行おう
トレース後はしっかり答え合わせを行います。
完成して満足してはいけません。
しかし、答え合わせと言ってもトレース素材が正解！ということではありません。

自分のソースと、素材のソースの違う点は学びになります。
なぜ違う結果になっているのか考えるようにしましょう。

>「そういうやり方もあるのか」
「こっちの方が〇〇だからこっちの方がこの場合は良いな」

など。

眺めるだけでは、思っている以上に細部まで目が行き届いていなかったことに気がつくでしょう。

**サイトトレースは、自分のスキルに落とし込むことと、表現方法を学ぶ大きな一つの手段です。**
しかも、大企業の商品サイトLPでは、モダンな技術が活用されることが多いので、流行りを追う手段でもあります。

# さいごに
トレースをたくさん行えば、やった分だけ、あなたの材料は増えていきます。
デザイナーさんからのデザイン共有を受けた際に、あなたのアイディアでより良いLPが出来上がるかもしれません。

>「こんなこともできるよ！」
「あ、あのサイトのこんな感じか！」

Webは、教材がオンライン上に星の数ほど転がっています。
自分よりすごい人の作品がこんなに転がっている業界なんて滅多にないですよ。
有意義に活用しましょう！
Swift Realmを使って、順番に保存する方法教えてください

Realmを使って、TalbeViewCellのTextFieldに入力された6つの文字だけ保存したいです。



コードは以下のようになっています。よろしくお願いします。![スクリーンショット 2020-02-11 22.12.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/411375/ae889cd9-4951-b255-409f-cefad2c6b334.png)


import UIKit
import RealmSwift

class TableViewController: UITableViewController, UITextFieldDelegate{
    override func viewDidLoad() {
        super.viewDidLoad()
        /* 6つのtextFieldにRealmデータを反映したい */
    }
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    // MARK: - Table view data source

    override func numberOfSections(in tableView: UITableView) -> Int {
        // #warning Incomplete implementation, return the number of sections
        return 1
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // #warning Incomplete implementation, return the number of rows
        return 6
    }

    /* セルの設定　*/
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "myCell", for: indexPath) as! TableViewCell
        //テキストフィールドのデリゲート設定
        cell.textFieldOutlet.delegate = self

        return cell
    }

    /* エンターが押された時*/
    func textFieldShouldReturn(_ textField: UITextField,  cellForRowAt indexPath: IndexPath) -> Bool {

/*ここでtextFieldの文字をRealmに保存（indexPath.rowのデータのみ更新したい)*/

        //　今フォーカスが当たっているテキストボックスに文字が入力されていたら
        if textField.text != "" {
            //　今フォーカスが当たっているテキストボックスからフォーカスを外す
            textField.resignFirstResponder()
            //次のタグ番号を持っているテキストボックスがあればフォーカスする
            let nextTag = textField.tag + 1
            if let nextTextField = self.view.viewWithTag(nextTag) {
                nextTextField.becomeFirstResponder()
            }
        }else{
            
        }
        return true
    }

    /* トラッシュボタンが押された時*/
    @IBAction func deleteButtonPush() {
        let alertController = UIAlertController(title: "タスクをすべて削除しますか？",message: nil,preferredStyle: .alert)
        let action:UIAlertAction = UIAlertAction(title: "はい", style: .default){ (void) in

        /*　ここでテキストフィールドのデータを全て削除したい　*/

        }
        let cancel:UIAlertAction = UIAlertAction(title: "いいえ", style: .default){ (void) in
        }
        /* 表示　*/
        alertController.addAction(action)
        alertController.addAction(cancel)
        present(alertController, animated: true, completion: nil)
    }
}



import UIKit

class TableViewCell: UITableViewCell {

    @IBOutlet weak var textLabelOutlet: UILabel!
    @IBOutlet weak var textFieldOutlet: UITextField!
    
    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
    }

    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)

        // Configure the view for the selected state
    }
}


import UIKit
import RealmSwift

class Task: Object {
    @objc dynamic var task: String? = nil
}
【Kotlin】実型パラメータに nullable な型が指定されたときにデフォルト値 null で使えるようにする

例えば次のようなジェネリックなクラスとメンバ関数があったときに

```Kotlin
class MyClass<T> {
    fun function(arg: T) {
        ...
    }
}
```

次のように `T` に nullable な型を指定していた場合には

```Kotlin
val myInstance = MyClass<AnyType?>()
```

メンバ関数の `T` 型の引数にはデフォルト引数として `null` が指定されているものとして次のように引数を省略したい。

```Kotlin
myInstance.function() // コンパイルエラー！　MyClass<T>.function(T) にデフォルト引数が指定されていないため。
```

## 普通にデフォルト引数を指定してはいけないのか？

`T` は実型パラメータとして non-null な型も指定できる（nullable な型のみを指定できるようにはしたくはない）ので、
次のようにデフォルト引数として `null` を指定するとコンパイルエラーになる。

```Kotlin
class MyClass<T> {
    fun function(arg: T = null) { // コンパイルエラー！　T は nullable とは限らない。
        ...
    }
}
```

## 解法

ではどうするか。

次のように、実型パラメータが non-null だった場合にだけ呼び出し可能な拡張関数を定義する。

```Kotlin
fun <T> MyClass<T?>.function() = function(null)
```

これで次の様に使える。

```Kotlin
myInstance.function() // OK
```
pythonで選択ソートを実装してみた

pythonとアルゴリズムの勉強かねがね、選択ソートを実装してみました。

1.ランダムなリストを作成する
例:
[1,3,0,4,2]

2.操作対象リストの中で最小の値を探す
例:
[1,3,0,4,2]→0が最小

3.一番左を0と入れ替えて、0は操作完了にする

[1,3,0,4,2]→[0,3,1,4,2]

-次は左から二番目、その次は三番目…と順に対象にして2.と3.を繰り返す-

[1,3,0,4,2]
[0,3,1,4,2]
[0,1,3,4,2]
[0,1,2,4,3]
[0,1,2,3,4]

…という処理を選択ソートと呼ぶらしいです。

```select_sort.py

import random

# 準備する値の数を入力
numbers = 10

# チェック済の値を格納するリストの作成
pop_list = []

# 乱数の作成
num_list = list(range(numbers))
random.shuffle(num_list)

def _select_min(num_list, pos):

    _min = None
    _left = num_list[pos]
    _pos = 0

    for i in range(pos, len(num_list)):
        if _min == None or _min > num_list[i]:
            _min = num_list[i]
            _pos = i
    
    num_list[pos] = _min
    num_list[_pos] = _left

    return(num_list)

# メイン処理
print("START : ",num_list)
for i in range(len(num_list)):
    num_list = _select_min(num_list, i)
print("GOAL  : ",num_list)

```
Processingの始め方

#Processingとは？

プログラミングを用いてアート作品を制作することはCreativeCodingと呼ばれています。
CreativeCodingには様々な言語が持ちいられておりそれぞれ得意分野などがあるように感じます。
その中で今回私が使い始めたProcessingについて簡単に紹介したいと思います。

##Processingの特徴
・簡単に始められる
・使い方がシンプル
・表現できることが多い

まず上から順に説明していきます

#### 簡単に始められる
導入が非常に簡単で
https://processing.org
上記のサイトにアクセスし、Downloadから自分のOSにあったものをダウンロードします。
ZIPファイルがダウンロードされますので、好きなところに解凍したら準備は完了です。
Processing.appをダブルクリックで起動すればすぐにエディッタが表示され使えるようになります。

#### 使い方がシンプル
表示されたエディッタにコードを記述したら
画面上にある▶️再生ボタンを押すとコンパイルされて、記述したものが描写されて表示されます。
①コードを記述
②▶️再生ボタンを押す
この２つしかありません。簡単ですね。

####表現できることが多い
コードを記述して図形を描写したりなどに加えて、音楽ファイルの再生や画像ファイルの読み込み、さらにはカメラから取り込んだ映像を利用したりと様々なメディアを利用することができます。
これらを組み合わせることで表現できる範囲はかなり広がります。
筆者はフェスなどが好きなので音に合わせて動くインタラクティブな作品を作って行きたいと考えています。

####最後に
簡単ではありますがProcessingの始め方になリます。
プログラミングの入門言語として使われることもあるらしく
googleが小学生に贈る10冊という記事でもProcessingは扱われていました。
https://japan.googleblog.com/2019/12/books-for-students.html
創作活動をする人がもっと増えるといいですね！
人狼必勝パターンカタログ　＊狼アーマー噛み無し＊

# 前提
６人村　２村人　２人狼　１狩　１占い

# 名称
狼アーマー　噛み無し

# 効果
二日目アーマーから村スライドで真村になり、村負け
Vue.jsでのdeep selectorの書き方

久しぶりの投稿です。
備忘を兼ねて簡単に書きます。

# deep selector？
Vue.js でscoped付でstyle を書いている場合に、そのコンポーネントの子コンポーネントにもstyleを追加したい場合に使用するcss のセレクターの書き方です。

## 書き方
```
.hoge >>> .huga{...}
```
`>>>`または`/deep/`で出来るとなっています。
（参考：https://vue-loader-v14.vuejs.org/ja/features/scoped-css.html）

# が、効かない場合がある。その時は？
原因を調べていないのですが、Versionか構成かで上記の書き方だと効かない場合があります。
調べてみたところ、次の書き方だと意図したとおりになりました。

```
.hoge ::v-deep .huga{...}
```
どうも、`>>>`や`/deep/`が解釈されなかったようです。
もしdeep selectorが解釈されていない場合があったら、`::v-deep`を試してください。

# 参考

Deep Selectors
https://vue-loader.vuejs.org/guide/scoped-css.html#deep-selectors

Vue LoaderのDeep Selectorの::v-deep
https://blog.mahoroi.com/posts/2019/03/scoped-css-v-deep/

スコープ付き CSS
https://vue-loader-v14.vuejs.org/ja/features/scoped-css.html
自分のDockerコンテナIDをホスト名に設定する

ホスト名をキーとして扱うサービスに対応するために、Docker コンテナ内から、自分のコンテナ ID を取得して `docker-0b2e383f` のようなホスト名を設定する。

```
#!/bin/bash

docker="$(egrep ':/docker/[0-9a-f]+$' /proc/self/cgroup | head -1)"
docker="${docker##*/}"
hostname "docker-${docker:0:8}"
```

https://gist.github.com/kawanet/a44493c0c3942b4b8f5d768f5a304564
RPAを仕事で使ってみたのでまとめてみた

# まずはじめに
2018年から仕事でWinActorを使う機会があり、少しロボを作ったりしました。
そして今現在、現場が変わってUiPathでロボを本格的に作ることになりました。
2種類の代表的なRPAソフトを使い、RPAで出来ることや得意不得意がわかってきたのでRPAを知らない人にもどういう物なのかを知ってもらうための記事を書くことにしました。

# RPAってなーに？
働き方改革も相まって数年前からトレンドになっています。
大手企業がこぞって導入を進めており、2019年のEXPOでも大盛況の分野になっているRPAについて説明します。

## RPA＝ロボティクス・プロセス・オートメーション
ロボティクス・プロセス・オートメーションの略。
ようするにロボットです。
ただドラ◯もんやペ◯パーくんとは違い、PC上で発生する作業を専門で行うロボットがRPAです。

## RPAはデジタルレイバー
RPAは“文字を入力する”や“ボタンをクリック”といったPCの操作を再現することができ、まさに人と同じように操作させることが可能です。
定型的に発生する文書作成やメールなど事務作業をロボットに代行させることが出来るので、デジタルレイバー(電子世界の労働者)とも呼ばれているようです。
そのため、働き方改革の取り組みとしてRPAを取り入れ始めている企業が増えています。

# RPAで出来ること
先の説明でPCの操作を再現すると書きましたが、具体的には以下ができます。

* データの取得
* 文書の作成
* WEBアプリやExcelなどの操作
* メールの送受信

## 使い方(WinActorやUiPathの場合)
私が使用したWinActorやUiPathの場合、マウス操作で処理を作る事ができます。
あらかじめ"データの取得"や"テキストファイルの新規作成"といった処理が記された部品が用意されています。
これをフローチャートとして作業の順番通りに部品を置いていくだけで作れます。
プログラミングは不要です。
作ったロボは必要なタイミングで手動で実行することも可能ですし、他のサービスを使ってスケジュールを組んでロボを自動で呼び出すといった使い方もあります。

## 活用例
例えば「WEBサービスにログインしてExcelのデータをブラウザの所定のフォームに入力して登録。完了したら担当者にメールする。」という作業が定期的にあるとします。
以下のように部品をフローチャートに配置すれば登録業務ロボの出来上がりです。

![フロー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/517685/65d5b6e1-9a0a-d519-4a94-eab95ef54c25.png)

> // コメント
上記例だとWEBページが開くまでの待機処理や登録失敗した時の考慮がないので、実際は条件分岐やtry-chatchなどが入ると思います。

# RPAの得意・不得意
通常のプログラムよりも得意不得意が明確です。
すべてRPAで行おうとすると処理が煩雑で速度が遅いということもあり得ます。
## 得意なこと
アプリケーションから別のアプリケーションへデータを取得・出力する事が最も得意と言えると思います。
CSVやExcelからデータ取得はもちろん、データスクレイピング(WEBブラウザなどの表データを抽出)が可能です。

## 不得意なこと
複雑な処理や計算をさせるにはあまり向いていません。
変数の利用や表形式のデータの絞り込み・加工は可能ですが、部品は1つずつ組み合わせるしかなく、複雑な処理ほど長大なフローチャートになりがちです。
場合によってはマクロなどを使用した方が容易で分かりやすい処理になります。

> // コメント
WinActorやUiPathはスクリプトを書いて独自の部品を作ることも可能です。
しかしフローチャート形式でひと目で処理が読めるのが長所の一つなので、可読性やメンテナンス性が落ちてしまう恐れがあります。

# ロボの開発について
感覚的にはExcelマクロと同じに思います。
開発スキルの無い非エンジニアでも手軽に作ることも可能ですし、エンジニアならば従来の開発と同様の設計思想である程度の規模のロボを作ることも可能です。

## 自動記録で作る
Excelマクロのように自動記録機能があります。
自動記録中のマウス操作やキー入力の動きをすべて覚えこませる事ができるので、これだけでロボを作れます。
条件分岐や例外の考慮が不要の場合はこれで十分です。

## プログラムを組むようにロボを作る
条件分岐、ループ処理、例外処理といった部品があるので従来の開発と同じような設計ができます。
またロボから別のロボを呼び出すことも出来るので、共通部品的なロボを作成して汎用性を持たせたり、複数人で開発ということも可能です。

実際、私が携わる業務では以下のような構成でロボを開発しています。

<dl>
 <dt>メインロボ</dt>
 <dd>メインの処理を書いたロボ。ここから各ロボを呼び出す</dd>
 <dt>事前処理ロボ</dt>
 <dd>設定値の読み込みなどを処理する</dd>
 <dt>業務ロボ</dt>
 <dd>業務の処理はすべてこのロボの中で行う</dd>
 <dt>エラー処理ロボ</dt>
 <dd>ロールバックなどエラー時の処理をする</dd>
 <dt>事後処理ロボ</dt>
 <dd>try-catch-finallyのfinallyにあたる部分。処理の通知などを行う</dd>
</dl>

![ロボの構成.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/517685/93956b73-ec4c-da32-996e-c4a3ba423a12.png)

# 私個人の所感
開発経験のある人ならば特に支障なくすぐに扱えるものだと思います。
ただプログラムならば1行2行で済む処理もRPAではいくつもの部品を組み合わせて実現させる必要があることもあり、もどかしい部分も多いです。

RPAの持つ最大の長所は**アプリとアプリを連携させることが出来る**だと思います。
これまで使用していたアプリの移行などが不要で自動化を目指せる、というのはエンドユーザーにとって有り難いことだと思います。
このような長所の面から今後、RPAの導入はますます増えることになるのではないでしょうか。
APLpyでcontour mapが描けないとき

APLpy(version 2.0.3) でcontour mapを書こうとして[Beginner Tutorial](https://aplpy.readthedocs.io/en/stable/fitsfigure/quickstart.html)にあるようにやったらgc.show_contourのところで

```.sh
ValueError: The output dimension of 'a' must be equal to the input dimensions of 'b'
```
って怒られてなんだそれはって感じ。

ググったら[ここ](https://github.com/aplpy/aplpy/issues/423)に、バージョンを1.1.1まで落とせと書いてあったので

```.sh
pip install APLpy=1.1.1
```
でダウングレードしたら普通に動いた。
SAP S/4HANAで購買発注が登録されるたびiPhoneに「アイーン」とPush通知が来たらぜったいどきどきしちゃう（まとめ）

# README

この記事は「SAP S/4HANAで購買発注が登録されるたびiPhoneに「アイーン」とPush通知が来たらぜったいどきどきしちゃう」シリーズのまとめ記事です。このシリーズでは、その名の通りSAP S/4HANAでの伝票登録をトリガーにiPhoneにPush通知を送信するための諸々の構築方法について説明しています。

複数に分割して書いた記事へのリンクをこの記事にまとめておくことにします。

# INDEX

実装方法をまとめた記事は下記の4つです。
（もしもやってみたい人がいれば）一応上から順番にやっていけばだいたい実装できるようになっていると思います。

1. [とりあえず「アイーン」とpush通知してくれるiOSアプリをSAP CP Mobile Service (Cloud Foundry) を活用して実装してみた](https://qiita.com/monamona/items/a1b065ca245aa5d8b2be)

2. [SAP CP Mobile Services (Cloud Foundry) のPush通知APIを叩いてみた](https://qiita.com/monamona/items/7ddd673c12205ef51ef4)

3. [SAP S/4HANAでの伝票登録をIDocで拾ってSAP CP Integration Serviceをトリガーしてみた](https://qiita.com/monamona/items/b13c0eef82f849323b78)　**※ アップデート予定あり**

4. [SAP CP Integration Serviceでメッセージ編集とかHTTPリクエストとかをやってみた](https://qiita.com/monamona/items/3b87538586850fb5dd26)

# いったい何を実装しているのか

上記の手順で最終的に実現できる構築物の処理の流れはざっくりこんな感じです。

- SAP S/4HANAで購買発注伝票が登録されると、IDocと呼ばれる機能がそれを拾って、Remote Function CallでSAP CP Integration Service内のIntegration Flowをトリガーする。
- IDocからのリクエストbodyのなかに購買発注伝票番号が含まれているので、Integration Flow内でこれをうまく編集し、さらにSAP CP Mobile ServiceのPush通知APIを叩く。
- APIが叩かれると、iPhoneアプリに「あい〜〜ん！　購買発注伝票(9999999999)が登録されました！」と通知が来る。

……と文章で書いてみましたが、たぶん下記の構成図のほうがわかりやすいかなと思います。

<img width="1024" alt="スクリーンショット 2020-02-11 21.31.37.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320955/3d4415e3-98e1-5a22-35cb-b06868d5ce8b.png">

# どうしてこんなことになったのか

SAP S/4HANAからの通知がスマホに来たらぜったいどきどきしちゃうなと思ったからです。

現に、お店でランチを食べているときに誰かがS/4HANA社内環境で伝票登録をしたらしく、わたしのスマホが大音量で「アイーン」と鳴ったときにはかなりどきどきしました（この記事では説明を省略しているのですが、そのときはこのアプリの通知音を「アイーン」音声にカスタムしていました）。

ぜひ甘酸っぱくもほろ苦いSAPライフのためにこのアプリケーションをお役立てください。


# 関連情報？

この実装をもとに、chillSAP主催のライトニングトークイベント「[SAPなんでもLT祭 ~若手編~](https://techplay.jp/event/764310?utm_campaign=event_764310&utm_medium=social&utm_source=ownerEvent&utm_content=feed_t)」でデモを行いました。
その時のスライドは[slideshare](https://www.slideshare.net/lisacomona/sap-s4hanaiphonepush)にアップロードしているので、よろしければ合わせてご覧ください。 

<img width="1021" alt="スクリーンショット 2020-02-11 21.55.17.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320955/b5ae2673-a21f-f434-53f2-27140c4062ff.png">

おしまい
Pythonで全探索により部分和問題を解く

##問題（蟻本 P.34）

>整数a1, a2, ...., anが与えられます。その中からいくつか選び、その和をちょうどkにすることができるかどうかを判定しなさい。

```python
#入力
n = int(input())
a = list(map(int, input().split()))
k = int(input())

#判定用の変数
cnt = 0

#全探索
for i in range(1<<len(a)):
    l = []
    for j in range(len(a)):
        if (i>>j & 1) == 1:
            l.append(a[j])
    if sum(l) == k:
        cnt += 1
print('Yes' if cnt>=1 else 'No')
```
基本情報技術者　マネジメント系　第1章 プロジェクトマネジメント③


# ③コスト、品質、人的資源

## プロジェクトコストマネジメント
計画プロセスと監視コントロールプロセスが関わります。

要は費用計画

### コンディンジェンシ予備
エラーや予定外の遅延に備えた、予備費

### ファンクションポイント法
点数と振り分ける方式です。

機能ごとの複雑差をレベルと基準に点数計算します。


#### 含まれない物
* アルゴリズムの複雑さ 
* プログラムの行数

### COCOMO
ファンクションポイント法に
プログラム行数や人員の能力といった要素も考慮に入れます。

下記の計算式で計算します。

システムの開発工数P = a X Kb (bは乗数)

Kは、プログラムの工数(1000単位)です。
a,bは統計的に定められた係数です。

### アーンドバリュー法
進捗状況を金銭的価値に置き換えて計算する手法です。

## プロジェクト品質マネジメント
計画、実行、監視コントロールプロセスが関わります。

#### 品質計画
目標と測定方法を定めます。

#### 品質保証
実行します。

#### 品質管理
目標満足を測定します。

### システム/ソフトウェア製品の品質特性

品質は JIS X 25010 : 1030 で定められていいます。

#### 機能適合性

#### 性能効率性

#### 互換性

#### 使用性

#### 信頼性

#### セキュリティ

#### 保守性

#### 移植性

### QC7つ道具
品質管理を行うさいに利用する図法です。

## プロジェクトマネジメント人的資源マネジメント
リーダーの役割

### チームの活動形態

#### コロケーション
メンバが一つの場所に集まって作業を行うこと

#### ウォールーム、プロジェクトルーム
コロケーション用のルームのこと

#### バーチャルルーム
リモートでの作業

### コンフリクトマネジメント
意見、対立の調整