OmniAICreator/Qiita-1.07M huggingface dataset:
リーダブルコード要約

リーダブルコードは何度も読み返すべき良書だと言われています。しかし一度読んだ本を何度も読み返すのは、頭からであれ部分的にであれ、正直結構めんどくさいです。
少しでも読み返す際のめんどくささを減らせたらいいなと思い、要約することにしました。

対象範囲は1~13章までです。14~15章は実際のコードに技法を適用していく内容になっており、サンプルコードありきの内容なので割愛します。
実装時に
「こういう時はどうやったら読みやすくなるんだっけ?」
と思った場合にサッと確認できる目次のような感じで使っていただけると幸いです。

## 理解しやすいコード

- 例えば複雑な処理を三項演算子で1行にまとめたコードは、if else を使って書かれたコードよりも優れていると言えるのか。
- コードは他の人が最短時間で理解できるように書かなければならない。他の人という言葉には、半年後の自分も含まれる。
- コードは短い方がいい。しかし理解するまでにかかる時間を短くすることの方が大切。

## 命名

- 変数の値やメソッドの動作を表すような、具体的で、明確な単語を選ぶ。単位などの情報を盛り込んでもいい。名前に情報を詰め込む。
- 類語辞典を使って調べるのもあり。
- 汎用的な名前は避ける。生存期間が短い、かつ、ある汎用的な単語より多くの意味を持たない場合はその限りではない。(つまり相応の理由がない限りは使わない)
- ループ処理のi、jなどは問題ない。しかしイテレーターが複数ある時はもう少し具体的な名付けをした方がいい。
- スコープが小さければ短い名前でもいい。スコープが大きい場合、名前に情報を詰め込んで明確にすべき。
- 頭文字や省略形は、新しいチームメンバーが意味を理解できるなら問題ない。プロジェクト固有の省略形は避けるべき。
- 名前から情報が損なわれなければ、不要な単語を削除してもいい。
- 命名規約を設ける場合はプロジェクト内で一貫性を持たせることが大切。
- 他の意味と間違えられることはないのかを何度も考える。誤解されないような命名をする。
- 限界値を含む変数 => min, maxを用いる。
- 範囲指定 => first, lastを用いる。
- 包含/排他的範囲 => begin, endを用いる。
- 真偽値 => is, has, can, shouldなど使う。否定形ではなく肯定形のほうがよい。
- 意味に対して先入観を持たれているであろう単語(慣習的に「この変数名なのでこういうデータだろう」みたいに思われそうなものなど)をそのまま使わない。

## コードの見た目

- コードを書くより読む時間の方が多いので、見た目の美しさは大切。余白、配置、意味のある順序などで整形する。
- 一貫性のある改行を行う。それが難しい場合、共通部分を関数にまとめるなどして改行しやすくすることもできる。
- カンマやイコールの位置を揃え、縦の線を揃える。
- ランダムではなく、意味のある順番に並べる。
- 整列には手間がかかると思われているが、筆者の経験上そこまで手間ではないらしい。もし手間になるようであれば、その時はやめればいい。
- 既存のスタイルに合わせて一貫性を保つことのほうが、正しいコードスタイルよりも大切。

## コメント

- コードからすぐにわかること(新しい情報を提供しないこと)はコメントに書かない。
- 名前を補完するためにコメントを使わない。その場合は名前を変える。
- コードを書いている時の自分の考えをコメントに書く。
- TODO, FIXME, HACK, XXX などの記法でコードの欠陥を書く。コードの品質や状態、改善の方向を示すことができる。
- 定数にコメントをつける。定数を決めた時に頭の中で考えていたこと(なぜその定数はその値なのかという背景)を記録する。
- 他人が読んだときに質問されそうなことを書く。ハマりそうな罠、ファイルやクラスの全体像についてなど。
- 関数内部の塊に対してコードをうまく要約したコメントをつける。
- コメントは正確で簡潔に。曖昧な代名詞を避け、情報密度の高い言葉を使う。
- 入出力の実例を書く。コーナーケースなどを書くといい。
- インラインコメントで名前付き引数を実現する。

## ループとロジック

- 条件式の引数は左側に調査対象(変化する)を、右側に比較対象(あまり変化しない)を置く。
- 条件は否定形より肯定形を使う。
- ifで分岐させる条件の並び順にこだわる。単純な条件を先に書く。もしくは関心を引いたり目立つ条件を先に書く。これらの優劣は状況によって変わるので場面で判断する。
- 三項演算子は、それによって簡潔になる場合にのみ使用する。基本的にはif elseを使用した方がいい。行数を短くするよりも、他人が最短時間で理解できる書き方をする。
- do whileは避ける。コードは上から下に読むのが自然だから。
- 関数から早く返す。ネストを浅く保つためにも早期リターンを心がける。
- ド・モルガンの法則を使って条件式の可読性をあげる。
- 短絡評価を多用しない。簡潔に使える場合はいいが、あとで他の人が読むときにわかりにくくなる場合は避ける。
- 論理式が複雑になってしまう場合は、実現したいことの反対を考えるのも一つの手。重なっている部分を見つけたい => 重ならない部分を見つける みたいな。

## 変数

- 式を表す名前の変数に式を代入する。大きな式を分割できる。また、簡潔な名前の変数を用いると式の内容が要約されて読みやすくなる。
- 役に立たない一時変数は削除する。複雑な式を分割していない、式をより明確なものにしていない、重複コードの削除になっていない、などの条件に当てはまる一時変数は不要。
- 中間結果を保持する変数を削除する。処理するのを先延ばしせず、早めに処理してしまえば中間結果を保持する変数はなくてもいい。
- 変数のスコープを狭くする。大きなスコープの変数は追跡が難しい。クラス内のメンバー変数であっても、クラスが大きければ追跡しにくい。ローカル変数にするなどしてスコープを狭める。
- 変数を操作する場所を減らす。一度だけ値を設定したり、定数にしてイミュータブルなものにするなど。

## コードの再構成

- プロジェクト固有の関数から、その関数の本来の目的とは関係のない処理を、別関数として切り出す。ただしやりすぎると逆に読みにくくなる。
- 切り出したものは汎用関数やヘルパーとして扱うといい。
- 関数には一度に一つのことだけをさせる。
- 関数が行なっているタスクをすべて列挙して、タスクごとに関数を分割する。
- 人間がどのように考えるかを重視したコードを書く。まずコードの動作を簡単な言葉でわかりやすく説明し、その説明に合わせてコードを書く。
- わかりやすく説明->実装 の手法は、大きなコードの塊に対しては再帰的に適用してゆく。説明->コード分割->分割されたコードに対して説明...みたいに。
- 過剰な機能は持たせない。
- 不必要なコードを削除する。
- 標準ライブラリを積極的に使う。ライブラリで何ができるのかを把握するために、定期的にドキュメントに目を通す。
bubble.ioでデータベースを削除してしまった際の解決法

[NoCodeWalker](https://nocodewalker.com/)というオンラインサロンに所属しています[よしお](https://twitter.com/timonsy)と申します。

サロン内で質問があり、日本語Web上に無さそうな[bubble.io](https://bubble.io/)の情報発信を目的としてつらつらを記しております。

今回はタイトルそのままいきます。

#bubble.ioでデータベースを削除してしまった際の解決法
bubble.ioは日本語化されていないので、誤ってせっかくのデータベースを
削除してしまった。
なんてことありますよね。（バックアップの取り方も英語なので難しい）
ググっても出てこないので、共有したいと思います。



##ググったら出てくるやつ
ググったら
「時間を指定して、その時間の状態に戻す」といった記事は出てくる。
でもコレって、DesignとかWorkFlowは戻るっぽいけど
**データベースは帰ってこないんです。**

⬇右上の赤線の部分クリックして
![スクリーンショット 2021-02-04 18.49.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276430/8ad8d25f-78a0-a477-0888-baba59157030.png)


~~意図的に薄くしてる~~’History’をクリックすると


![スクリーンショット 2021-02-04 18.57.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276430/e7de6aeb-3cd3-14d9-878d-56296d7c5e57.png)
こんな画面が出てくるやつですね。
セーブポイントを設定していれば、赤枠の上の四角の中に
戻せるポイントが出てくるのですが、オートセーブ全盛時代に
なかなか活用し難いです。（私は機能の仮説検証に使うくらいです）
赤枠内に時間を入力したらその時間の状態に戻せます。
（無課金で１２時間前がリミット）

でも、**データベースは帰ってこないんです。**

##データベースの復元の方法
肝心のデータベースの方法ですが、やり方は上記と結構似ています。
![スクリーンショット 2021-02-05 19.13.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276430/4c921369-3ee8-a76c-4f29-86e91699677b.png)

①Dataタブの
②App dataの
③Copy and restore databaceをクリック

![スクリーンショット 2021-02-05 19.18.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276430/0bdb3f5b-fce8-ed8d-8771-91e6ed5a2f2d.png)

こんなポップアップが出てくるので、赤枠内のプルダウン
’Database version to restore'は
DevelopmentのデータなのかLiveなのか？
’Dara type to restore'は
どのタイプのデータなのか（All typesで基本いいかと）

赤枠一番下の'Time to restore to'に戻したい日時を入れて
’Restore to this date'のButtonクリック
![スクリーンショット 2021-02-05 19.26.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276430/a9c2c01f-3ee0-ddec-0189-a40495742403.png)

最後、Inputに’RESTORE DATA TO PAST VERSION'を入力して
'Confirm'Buttonクリックで戻ります！

##注意
戻せる日時はプランによって違ってきます。
無課金ですと１２時間前がリミットです。
その他こちら参照まで
![スクリーンショット 2021-02-05 19.51.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276430/8958b77d-d0c4-5239-e37e-6fa5af0a2f5e.png)
【書籍紹介】東京大学のデータサイエンティスト育成講座

<p>「東京大学のデータサイエンティスト育成講座」について紹介していこうと思います。![Epson_20210205193255 (2).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1001770/47340a98-3bac-9118-9c28-a99ff45baa20.jpeg)
<h1>言いたいこと
<p>・データサイエンス入門書籍として、お勧めです。
・見やすい、わかりやすい、続きやすい。（筆者はオライリーが読みにくいと感じます）
・データの前処理から機械学習までと幅広い知識を得られる。（→専門性には欠ける）
・演習問題が付いているので、何が分かっていないかが分かる。
・「この本を修めたら、次に何をすべき」かがあちこちに書かれている。
・手元に置いときたい一冊

<h1>対象読者
<p>・python初心者(未経験でも行ける)
・データサイエンス未経験者
・統計学基礎知識を習得済みの者（高校数学は必修）
ゴリゴリ、データサイエンスを学んでいる方は不必要

<h1>なにを、どこまで学べるのか。
<p>・データの前処理、加工←わかりやすく、実務ですぐ使えるように書かれている
・描画（棒グラフをはじめヒートマップなどもかく）
・記述統計（広く浅く）
・時系列データ（深くはやらない）
・教師あり、なし学習（ロジスティック回帰、正則化、決定木、K近傍法、SVM、クラスタリング、主成分分析、マーケット分析）
・モデルの検証方法とチューニング（ホールドアウト法、交差検証法、アンサンブル学習）


<h1>最後に
<p>私は、先輩プログラマーから紹介されて、この本をやりました。データサイエンス入門書が沢山ありすぎて、この本が若干埋もれてしまっているのが残念です。と思っていたのですが、メルカリで調べると全て売り切れてました。人気っぽいです。
GitPythonでprivateなsubmoduleを取り込む

# やりたいこと
- いろいろな事情によりGitPythonを使って、他のリポジトリをcloneしたい
- そのリポジトリはprivateである
- さらに、そのリポジトリの中にprivateなsubmoduleが存在する

要はprivateにリポジトリだろうがなんだろうが

```sh
git clone git@github.com:hoge/fuga.git
git submodule update --init
```
したいということ


# やったこと

## とりあえず普通にcloneする
この段階ではまだsubmoduleは空の状態になる。

```python
import git

GITHUB_TOKEN = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
REPO_OWNER = 'hoge'
REPO_NAME = 'fuga'
DIST_PATH = 'piyo'  # リポジトリをcloneするときの名前

GIT_CLONE_URL = f'https://{GITHUB_TOKEN}@github.com/{REPO_OWNER}/{REPO_NAME}.git'

# 単にmasterをcloneするだけのとき
cloned_repo = git.Repo.clone_from(
    GIT_CLONE_URL,
    DIST_PATH)

# branch指定、sshのhost key verification無視設定、
# commit履歴深さ設定などを追加するとこんなかんじ
cloned_repo = git.Repo.clone_from(
    GIT_CLONE_URL,
    DIST_PATH
    env={'GIT_SSH_COMMAND': 'ssh -o "StrictHostKeyChecking=no"'},
    branch='poyo',
    depth=1)

```

submoduleがpublicであれば、 `clone_from()`の引数に `recursive=True`を追加するだけでよい。

## gitmoduleの上書き
submoduleのcloneは、具体的には `.gitmodules`に記述された`url`が使われる。
昨今わざわざID/passでgitを利用する人間は稀だと思われるので、以下のように書かれていると思われる。

```.gitmodules
[submodule "poyo"]
	path = piyo
	url = git@github.com:hoge/fuga.git
```

つまり、このurlをtoken付きのhttpsに書き換えてあげることでsubmoduleを取得できるようになる。
`clone_from()`でrecursiveオプションを付与しないのは、`.gitmodules`の書き換えより先に接続しようとしてしまい、権限不足でエラーが発生するためである。

単純にファイルを開いて置換処理を行い、そして保存すればよい。

```python
# submoduleの取得に用いるURLを、sshからtoken付httpsに書き換える
gitmodules_path = os.path.join(DIST_PATH, '.gitmodules')
with open(gitmodules_path, 'r') as f:
    gitmodules = f.read()
    gitmodules = gitmodules.replace('git@github.com:', f'https://{GITHUB_TOKEN}@github.com/')
with open(gitmodules_path, 'w') as f:
    f.write(gitmodules)
```

## `git submodule update --init`する
"gitpython submodule"でググるとわかるが、リリースされて10年くらいの間に実装が二転三転しており(しかも全部生きてるっぽい)、submodule周りの実装がなんか4つくらいある。

動作確認できてシンプルに実現できたやつを紹介しておく。

```python
for submodule in cloned_repo.submodules:
    cloned_repo.git.submodule('init', submodule.name)
    cloned_repo.git.submodule('update', submodule.name)
```

うまくゆけばsubmoduleの中身が反映されているはず。


# その他躓いたこと
公式のGitPythonリポジトリにはrequirementsとして下記のように書かれている(2021年2月5日現在)。
- Git (1.7.x or newer)
- Python >= 3.4

ただし、実際のところgitコマンドがsshなど他にちょいちょい依存しているので、それらも忘れないようにインストールしなければならない。
特にGitPythonを使うケースというのはdockerコンテナ内などであることが多いと思うが、そういう環境だと`apk add openssh`しておくみたいな「基礎的すぎて思いも寄らない箇所」への依存でコケたりするので注意が必要(一敗)。
【フロント初心者必見】これまでに受けたFBを集めた

#はじめに
**・自分以外の人が、見ても伝わることを前提にコードを書いていく**

**・処理が増えても汎用的に使えるか確認する**

#クラス命名
###・クラス名「だけ」を読んだときに、その要素がどのページのどの要素なのかがざっくりわかるような命名

###・タグ名をクラス名に含める×
例）× p-about-contents--a

###・位置情報をクラス名×
例）leftやrightなど。
運用上に問題あり。意味のある名称に。

###・枝番をクラス名×
例）× p-top-topics__itemText--1

###・抽象的な命名は避ける
例）コンポーネントにおいて、contents
コンポーネントは役割が明確なため、クラス命名も明確に。

###・クラス名は、一つの要素に基本的に一つだけ
→複数つけるときは、jsで利用する特殊な場合のみ

#CSS
###・SCSSで使うアンパサンド（&）
→**擬似要素や、同一要素に別クラス**がついた時にのみ使用する
例）

```sample.scss
// 擬似要素
.block {
  &:before {}
}

// 同一要素に別クラス
.box {
  &.is-hidden {
     display: none;
   }
}
```

###・ネストは深くしすぎない（CSSに限らず）
→視覚的に見にくい

###・汎用性に欠ける書き方はしない→ループを使う

```sample.scss
// 汎用性に欠ける×
.block {
  &:nth-child(1),
  &:nth-child(2),
  &:nth-child(3) {
    margin-right: 10px;
  }
}
```

この書き方だと、要素が増える度にコードを追加しないといけない

###・marginの相殺は起こさない
→子要素のmarginが親要素からはみ出さないように
予期せず、デザインが崩れる基に。
marginとpaddingつくる余白の意味を理解しましょう。

###・背景色のためだけの疑似要素は配置しない
→意味がないから。

###・コンポーネントにmarginはつけない
→使いまわしにくいから

###・色の指定は16進数
```sample.css
h2 {
    color: #0000ff;
}
```

色の表現が多彩。

###・ショートハンドで書く

###・デザインに影響を与えないプロパティは削除する
→ディベロッパーツールを使いましょう

###・marginとpaddingを正しく使い分ける

###・widthやheightのauto
→デザインの表現上、必要なければ書く必要はない

###・タグ名に直接スタイルをあてない
```sample.css
/* × */
a {
  color: #fff;
}
```

###・スマホの画面
→320px~750pxまでの画面幅で違和感ないようにリキッドレイアウトコーディングすることを意識

#HTML

###・tableタグは使わない
→古いから

###・imgタグにはalt属性を。
alt属性：画像が表示できない際の代替えテキスト。
ユーザーに対しての利便性の効果があり、SEO対策にも。

alt属性が浮かばないときは、cssのbackgroundに。
そのように使い分けを行う。

###・htmlの記述を少なくする
→使用していないブロック（CSSを当てていないなど）は取り除く

###・コピーライトはエスケープする
```sample.html
<!-- × -->
<small>©</small>

<!-- エスケープする〇 -->
<small>&copy;</small>
```

###・li要素には最低でも2つ以上の要素入れる
→そもそも、1つだとリストである意味がないから

###・aタグなら必ずhref属性を入れる

###・意味を持たない要素はタグではなく、疑似要素に。
例）テキストの横にある、矢印アイコンとか

#JavaScript(jQuery)
###・メソッドチェーンを使用する
例）
$('nav li')　×
findでつなげる　〇

###・ 一つのスコープの中で２回以上使うDOMの変数化
→毎度、DOMにアクセスすることによる負荷を軽減するため

###・変数宣言はコンマ区切りの改行を行う
```sample.js
let num = 1,
    sum = 2;
```

###・jQueryオブジェクトは、変数も$で始める
→jQueryオブジェクトを変数に格納していると分かりやすくするため。

###・（※重要）変数のスコープ
→関数の外で宣言した変数を、関数の内側で使わない。
グローバル変数の乱用をしない。
クロージャーを使いましょう。
[【JS】やっと分かった、クロージャー。](https://qiita.com/baby-0105/items/dbe85b22f8e1791ee3a6)

###・引数名に命名について
→関数における引数名は、元の値がなんであるか明示的にわかるようにする。

###・関数の区分
→関数は挙動。
例）rightOrleftや、stopOrgoなどの分け方は ×
「曲がる処理」「発進する処理」で区分する。

###・clickイベントなどはonでバインド
```sample.js
// ×
$('button').click(function(){
  console.log('ボタン押しました');
});

// 〇
$('button').on('click', function(){
  console.log('on');
});
```

###・キューに動作がたまらないように
→ボタン連打したときに、回数分動作しないように

###・代入演算子の両脇にはスペースを
```sample.js
// ×
let fruit="apple"

//　〇
let fruit = "apple"
```

→途中から追加されたHTML要素を検出できようにするため。

#その他
###・デザイン崩れ
基本中の基本。
スマホ画面でも、PCでもズレているところがないかきちんと確認する。

###・不要なスペースは削除する
→VScodeをお使いであれば、プラグインを入れることで簡単に対応できます。

###・ボタンのクリック範囲が正しいか確かめる。
→視覚、また、操作的におかしいところの修正。
見た目のクリック範囲とaタグのクリック範囲を合わせる。
Linuxの勉強

#Linuxはコマンドで操作
コマンド→「命令」
シェル→入力されたコマンドを理解し実行する
シェルの機能
1.コマンド入力を受け付ける
2.シェルスクリプトの実行
シェルスクリプトとは、「コマンドの入力を自動化」するもの
１つのファイルにコマンドを１行ずつ記述して作成。作成したシェルスクリプトを実行することで、コマンドの実行を自動化することができる。
**利用開始時にユーザ名とパスワードを入力する。（ログイン)**
**ログアウト「exit」**
**シャットダウン**
1.suコマンドとパスワードを入力してrootユーザになる。
  プロンプトが「$」→「#」になる。
2.「shutdown -h now」でシャットダウンを実行する。
#コマンドの実行
1.「アプリケーション」メニューから「システムツール」、「端末」を選択する。
#標準入出力
Linuxのプログラムには、「1つの入口と2つの出口」がある。
それぞれ、標準入力、標準出力、標準エラー出力という。
#リダイレクト
標準入出力先を変更する機能のことをリダイレクトという。
キーボードの代わりにファイルを標準入力につなぐ。これを入力リダイレクト「<」とよぶ。
```$ ls > ls-sample```
コマンドを実行すると、ls-sampleというファイルが作成される。
#標準エラー出力
```$　ls -l apple > ls-l-sample```
「apple」というディレクトリが存在しなかった場合、「そのようなファイルやディレクトリはありません」といったエラーメッセージが標準出力される。
```$　ls -l apple 2> ls-l-output```
エラーメッセージは指定したファイルに出力される。コマンドの「２」は、標準エラー。標準出力は「１」
#正規表現の利用例
①「^a」　aで始まっている行
②「z$」　zで終わっている行
③「a.z」　aとzの間に１文字が入っている
④[az]　aもしくはzに続く
⑤[^az]　aもしくはzで始まらないで、azが続くもの
CSSのプロパティ

#CSSのプロパティ
HTMLで記述したテキストや要素を装飾するのが<b>CSS</b>という言語です。<br><b>セレクタ</b>で要素を選択し、<b>プロパティ</b>というものを使って装飾していきます。
記述は

```css
.セレクタ {
  プロパティ:　　；
}
```
という風に書きます。

プロパティにはどのようなものがあるのかざっくりと説明していきます。

##文字や要素の装飾など

###・【colorプロパティ】
文字の色を指定します。

###・【font-sizeプロパティ】
文字の大きさを変更します。単位として主に<b>px</b>を使います。

###・【font-familyプロパティ】
フォントの種類を指定することができます。

###・【background-colorプロパティ】
背景色をつけることができます。

###・【heightプロパティ】
要素の高さを指示できます。単位としては<b> px , % , vh </b>などがあります。

###・【widthプロパティ】
要素の横の長さを指示できます。単位としては<b> px , % , vw</b>などがあります。

###・【font-weightプロパティ】
文字の太さを変えることができます。単位としては<b>px</b>などがあります。
太字にするときは<b>bold</b>を指定します。

###・【list-styleプロパティ】
HTMLの<b>li要素</b>に使えるプロパティです。<br>:none;をつけることでリストの文頭の「<b>・</b>」を消すことができます。

###・【border-radiusプロパティ】
要素の角を丸めてくれます。単位は<b>px</b>をつかいます。

```css
.セレクタ {
  color: red;
  color: #ffffff;

  font-size: 200px;

  font-family: フォント名;

  background-color: blue;

  height: 100px;

  width: 100px;

  font-weight: bold;

  list-style: none;

  border-radius: 10px;
}
```

##余白とBorder
要素周りの余白などを指示するプロパティです。

###・【borderプロパティ】
要素の周りに枠線をつけることができます。<br>記述方法は「border:　<b>線の太さ　線の種類　線の色</b>;」を指示します。

###・【paddingプロパティ】
要素とborderの内側の余白を指示します。

###・【marginプロパティ】
borderの外側の余白を指示します。

また、これら border , padding , margin は上下左右だけに適応させることが可能です。２つ方法があり、１つ目は

|方向|   |
|:---:|:---:|
|上|top|
|右|right|
|下|bottom|
|左|left|

この表の右側の文字を「border-」などに続けて書くとその方向に余白、枠線、を作ります。
２つ目は<b>値を複数指定する</b>方法です。

border , padding , marginの値を複数入力するとそれぞれ方向が決まっており、

```css
.セレクタ {
  /* 値を４つ指定した場合 */
  border: 上  右  下  左 ;

  /* 値を３つ指定した場合 */
  border: 上  左右  下 ;

  /* 値を２つ指定した場合 */
  border: 上下  左右 ;
}
```

という方向に余白をつけることができます。
余白のプロパティをまとめるとこんな感じになります。

```css
.セレクタ {
  border-top: 20px;
  padding-right: 30px;
  padding-left: 30px;
  margin-bottom: 50px;
  margin-right: 40px;
}
/* ↓結果は上とかわりません↓ */
.セレクタ {
  border: 20px 0 0 0;
  padding: 0 30px;
  margin: 0 40px 50px 0;
}
```

##要素の種類
###・【displayプロパティ】
要素の種類を変更することができます。<br>要素の種類には主に<b>ブロック要素 , インライン要素 , インラインブロック要素</b>の３つにわけることができます。
####・ブロック要素
見出し要素、p要素、div要素がこれにあたります。<br>横幅は文字数関係なく横いっぱいに広がっているので連続しているとブロックのように縦に積み上がっていくイメージです。
####・インライン要素
a要素、span要素などがこれにあたります。<br>文字数によって横幅が決まってくるのでブロック要素が縦に積まれていくのに対し、インライン要素は横に並んで表示されます。
####・インラインブロック要素
中身はブロック要素ですが、インライン要素のように横に並んで表示されます。

displayプロパティに記述する値の種類としては以下の通りです。

|値|説明|
|:--:|:--:|
|block|ブロック要素になります。|
|inline|インライン要素になります。|
|inline-block|インラインブロック要素になります。|
|flex|要素が横並びになります。|
|none|ブラウザ上では非表示になります。|

記述は以下のようになります。

```css
.セレクタ {
  display: block;
  display: inline;
  display: inline-block;
  display: flex;
  display: none;
}
```

-----
####次は「display:flex;」を使用した「Flexbox」を使っていこうとおもいます。
HerokuにGitHubアカウントと連携して簡単にデプロイしたいし自動でマイグレーションしたい

Herokuにデプロイするのに苦戦しまくった私の備忘録です。
#開発したアプリをHerokuで公開したい！
Herokuにデプロイするにあたって、いろんなサイトを巡ってみた結果どうやらローカルのgitリポジトリからheroku createして…みたいなのが一般的らしいですね。
…嘘だろ？
何もかも初心者の私は躓きまくりました。

HerokuのDeployタブ内をよく見ると、見慣れたアイコンがあるじゃないですか。

![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/508560/608badae-a8ee-de10-5c9d-51b107064c63.png)

…あれ、これってもしかしてGitHubと連携してデプロイできるやつじゃないですか？
というわけで、やってみましょう。
画像は連携済みのものですが、「GitHub」をクリックし、その後下に出てくるボタン「Connect to GitHub」を押すだけです。
連携したいリポジトリを選択すればあら簡単！
成功するはずです。
ちなみに手動デプロイは、「Manual deploy」にある「Deploy Branch」ボタンを押して待てば完了です。

ね、簡単でしょう？


#デプロイ時に自動マイグレーション
デプロイするたびに毎回手動でマイグレーションするのは忘れそうで怖いですよね。
自動で行う方法があります。
ルートディレクトリ(READMEなどがあるところ)に 「Precfile」 というファイルを作成して以下を記載するだけ。

```Procfile
release: bin/rails db:migrate
```

db:migrate のマイグレーションのコマンドをデプロイ時に自動で実行することができます。
link_toとimage_tag を併用した時のエラーを解消

#image_tag に link_to でリンクをつけたかった

```ruby:エラーコード
link_to image_tag room.cover_photo(:medium), room
```

#下記のエラー表示
![スクリーンショット 2021-02-05 19.02.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/468139/13dba5b4-e253-08a0-4d2d-60687360eb3e.png)

#やっとこと

image_tagを（）で囲む

```ruby:解消したコード
link_to (image_tag room.cover_photo(:medium)), room
```

無事、指定の画像にリンクをつけることができました！

# 参考にした内容
http://banker0507.blogspot.com/2012/07/linktoundefined-method-symbolizekeys.html

https://stackoverflow.com/questions/7568148/paperclip-image-inside-link-to-undefined-method-symbolize-keys-for-desig
【Ruby】Herokuでアプリを削除する方法

【コード】

```
heroku app 
> enter

<Did you mean app? [y/n]
> y enter

アプリ名が表示

heroku apps:destroy --app アプリ名

>アプリ名を再入力
```

【解説】
Herokuで自動生成されたアプリ名がわからなくなってしまい,
解決に時間をかなり使ったので,
アプリ名の確認と削除の方法を共有したいと思います.



<作成したアプリの確認>

1行目の

```
heroku app
```
でアプリ名を確認します.
Did you mean app? [y/n]と問われるので,
yでenterを押します.

すると作成したアプリ名の一覧が表示されます.

<作成したアプリの削除>

```
heroku apps:destroy --app 削除したいアプリ名
```
を入力すると, >　が表示され,入力待ちとなるので,
再度削除したいアプリ名を入力し,
enterを押すと指定したアプリが削除されます.
【CSS】レスポンシブ　PCで表示　スマホで非表示のまとめ

# 使い方


### （例）class名にis_pcを入れるとPCのときだけ表示されます。

```
is_pc ・・・PCで表示したいところに使う
is_sp・・・スマホで表示したいところに使う
is_ipadPro_pc・・・ipadPro・pcで表示したいところに使う
is_ipad_ipadPro_pc・・・ipad・iPadPro・pcで表示したいところに使う
is_sp_ipad・・・スマホ・ipadで表示したいところに使う
is_sp_ipad_ipadPro・・・スマホ・ipad・ipadProで表示したいところに使う



/* ipad・スマホ・iPadPro以外（PC = 1025px以上の幅(1025px含む) ）*/
@media (min-width: 1025px) {
  .is_sp_ipad_ipadPro {
    display: none;
  }
}


/* ipad・スマホ以外（ipadPro・PC　= 811px以上の幅(811px含む) ）*/
@media (min-width: 811px) {
  .is_sp_ipad {
    display:none;
  }
}


/* スマホ以外（ipad・iPadPro・PC = 541px以上の幅(541px含む) ）*/
@media (min-width: 541px) {
  .is_sp {
    display:none;
  }
}


/*  ipad pro 1024px以下の幅(1024px含む)  */
@media (max-width: 1024px) {
  .is_pc {
    display:none;
  }
}


/*  ipad 810px以下の幅(810px含む) */
@media (max-width: 810px) {
  .is_ipadPro_pc {
    display:none;
  }
}


/*  Smartphone 540px以下の幅(540px含む) */
@media (max-width: 540px) {
  .is_ipad_ipadPro_pc {
    display:none
  }
}
```

### あとがき

web用のデザインじゃない時、複雑なデザインの時のレスポンシブには悩まされますが、こちらのまとめを使うことで少しでもレスポンシブが楽になればと思い共有させていただきました。
自己流でまとめたものなので、もっとこうすればいいよ。などあればお気軽にコメントください。
制約にコメントが書きたい！、、、ことってないですか？

Storyboardを使っていると制約に対してコメントを付けたいことがある。
イレギュラーな感じで制約をつけた場合とか、パっと見でどうしてこの制約を付けたのか後からわからなくなりそうな場合など、理由を書き残しておきたいと思うからだ。

NSLayoutConstraintにそういう機能つかないかなあと思っていたのだが、なんのことはない自分でそういうカスタムクラスを作ればよかったのだ。

```Swift
import Foundation

class DescriptibleLayoutConstraint: NSLayoutConstraint {
    @IBInspectable private var constraintDescription: String?
    
    override var description: String {
        guard let constraintDescription = constraintDescription else { return super.description }
        return "\(super.description)\n[\(constraintDescription)]"
    }
}
```

NSLayoutConstraintをカスタマイズする発想がなかった...。
反省・・。
JestによるAxiosモック化方法の覚え書き

# この記事について
Jestによる単体テストで、HTTPリクエスト送信ではおなじみのライブラリ・Axiosをモック化するに少々手間取ったことがあったので、その方法について記したものです。

# 環境情報
* Jest: `25.1.0`
* Axios: `0.19.1`

# モック化の方法
## シンプルなパターン
HTTPリクエストを送信するための関数(axios.post, get, put, deleteなど)は、`jest.spyOn`だけでモックにすることが可能です。

```js

import axios from 'axios';

jest.mock('axios');
const postApiMock = jest.spyOn(axios, 'post').mockName('axios-post');

// モックの戻り値を適宜セット
postApiMock.mockResolvedValue({});
```

## カスタム設定のある場合
axios.createを使うと、設定をカスタマイズしたaxiosインスタンスが取得できますが、前述の方法だけではモック化が出来なくなります（初期化処理でエラーとなります）。
そこで、インスタンスを生成するファクトリメソッド自体をモック化することで対処します。
`jest.mock`の第2引数についての説明は、Jestの[ドキュメント](https://jestjs.io/docs/ja/jest-object#jestmockmodulename-factory-options)も参考にしてください。

```js
const mockApi = jest.fn().mockName('mock-api');
jest.mock('axios', () => ({
  __esModule: true,
  default: {
    create: jest.fn(() => {
      return {
        interceptors: {
          request: { use: jest.fn() },
          response: { use: jest.fn() },
        },
        post: mockApi,
      };
    }),
  },
}));
```
Pythonのscheduleライブラリでジョブ実行時に引数を渡す

小ネタです。

Pythonの[schedule](https://schedule.readthedocs.io/en/stable/)ライブラリがスクリプトの定期実行になかなか便利なのですが、実行するジョブの中に引数を入れたい場合、通常の感覚とちょっと違うやり方だったので書いておきます。基本的な使い方は
https://qiita.com/dgkmtu/items/3bd3794b44a0aa03bfe3
を参考にしました。

結論として、ジョブに引数を入れて実行する場合には、以下のようにして動きます。

```python
import schedule
import time

def job(x, y): # x, yを引数に持つジョブ
    print("job execute w/ argument: x = {}, y = {}".format(x,y))

# jobに引数を入れるときはdo(job, 引数)とする    
schedule.every().second.do(job, x=1, y=2)

while True:
    schedule.run_pending()
    time.sleep(1)

# 実行結果
# job execute w/ argument: x = 1, y = 2
# job execute w/ argument: x = 1, y = 2
# ...
```

感覚だと

```python
schedule.every().second.do(job(x=1,y=2))
```

のようにしたくなるのですが、[公式Reference](https://schedule.readthedocs.io/en/stable/examples.html#pass-arguments-to-a-job)によると

```python
schedule.every().second.do(job, x=1, y=2)
```

と、`do`の引数として使用するようです。
Raspberry Pi Picoで サーボモーターを動かす

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">ラズパイPicoでサーボモーターを動かす。<br>PWMが16ビットだった <a href="https://t.co/2DoQA0SSZs">pic.twitter.com/2DoQA0SSZs</a></p>&mdash; Sam Akada@HomeKit (@sam_akada) <a href="https://twitter.com/sam_akada/status/1357614957135728641?ref_src=twsrc%5Etfw">February 5, 2021</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

# 接続図
![SERVO.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/452335/fc20905b-28b1-242b-bf84-bce3abb9002b.jpeg)

# microPythonのソースコード
```python
from machine import PWM, Pin
import time

servo1 = PWM(Pin(28))
servo1.freq(50)

while True:
    servo1.duty_u16(1500)
    time.sleep(1)
    servo1.duty_u16(3000)
    time.sleep(1)
```

# 参考
開発環境のセットアップは下記を参考にしてください。
- [M1 Macで Raspberry Pi PicoのLチカ](https://qiita.com/SamAkada/items/13cf63b6fc8a8198c160)
Nuxt.js に Stylus を入れてみたが、コンパイルエラーになったのでその解決策

# 問題

記事執筆日付で、Nuxt.js (v2.14.12, TypeScript ver) で Stylus を使おうと思って、 `yarn` (v1.22.10) で以下の通りインストールして利用しようとした。

```bash
$ yarn add --dev stylus stylus-loader
...
info Direct dependencies
├─ stylus-loader@5.0.0
└─ stylus@0.54.8
info All dependencies
├─ stylus-loader@5.0.0
└─ stylus@0.54.8
Done in 15.21s.
```

しかし、`<stype lang="stylus">` を vue ファイルに含めて `yarn dev` として実行すると以下のエラーが発生する。

```bash
 ERROR  Failed to compile with 1 errors                                                                     friendly-errors 17:48:21

 ERROR  in ./pages/index.vue?vue&type=style&index=0&lang=stylus&                                            friendly-errors 17:48:21

Module build failed (from ./node_modules/stylus-loader/dist/cjs.js):                                        friendly-errors 17:48:21
TypeError: this.getOptions is not a function
    at Object.stylusLoader (/*************/node_modules/stylus-loader/dist/index.js:19:24)
```


# 原因と解決策

同じエラーメッセージで悩むパターンが過去にあった。

https://github.com/vuejs/vue-cli/issues/5947

こちらでは、新しいバージョンの stylus-loader が対応していないということで、１つ古いバージョンの stylus-loader を使えば対応できるとのことだった。
先のインストールログから、stylus-loader のバージョンが 5.0.0 とメジャーバージョンアップされており、まだ vue-cli がこのバージョンに対応していないことが想像できる。

そのため、一度アンインストールして、stylus-loader の4系を入れなおす。

```bash
$ yarn remove --dev stylus stylus-loader
$ yarn add --dev stylus stylus-loader@4
...
info Direct dependencies
├─ stylus-loader@4.3.3
└─ stylus@0.54.8
info All dependencies
├─ stylus-loader@4.3.3
└─ stylus@0.54.8
```

これで再度 `yarn dev` を実行すれば、コンパイルエラーではなくなった。

当然、時間経過とともに vue-cli で stylus-loader の5系が使えるようにはなるとは思うが、これを見ると今後も loader のバージョンアップの都度同様のエラーが発生する可能性があるので、その場合の解決策として利用できるとも考えて書き記す。
TypeScript 独自の型ファイルを作るときのためのメモ


ちょっと苦戦したので忘れないようにメモです。

## やりたいこと
・グローバルな独自の型定義ファイルをプロジェクト内に作りたい


## やったこと
・`src/@types` にindex.d.tsを配置。
・tsconfig.jsonにて、`typeRoots`を追加。


```tsconfig.json
{
  "compilerOptions": {
    "allowSyntheticDefaultImports": true,
    "noImplicitAny": true,
    "module": "es6",
    "target": "es5",
    "allowJs": true,
    "typeRoots": ["src/@types", "node_modules/@types"]
  },
  "files": [
    "src/index.ts"
  ]
}
```


すると、型が読み込まれなかった...🤔
下記のように、指定のディレクトリの階層を一つあげるとうまくいった。

```tsconfig.json
 "typeRoots": ["src", "node_modules/@types"]
```

どうなったか？？
↓
コンパイルエラー‹•.•›

```
[tsl] ERROR
      TS2688: Cannot find type definition file for 'css'.

[tsl] ERROR
      TS2688: Cannot find type definition file for 'modules'.
```

そもそも、src以下の型定義が全てグローバルになるのは嬉しくないです。


## typesRootsの注意点

https://github.com/microsoft/TypeScript/issues/27956
こちらのgithubのissueに解答を見つけた。

>When types is not specified (this seems to be the case that mystifies the most users): Subdirectory '{0}' of 'typeRoots' directory '{1}' is not a valid types package. If the presence of this subdirectory is intentional, change the 'typeRoots' or 'types' option. See https://www.typescriptlang.org/docs/handbook/tsconfig-json.html#types-typeroots-and-types .
When types is specified: Could not find a types package named '{0}' (specified in the 'types' option) in any directory specified by the 'typeRoots' option. See https://www.typescriptlang.org/docs/handbook/tsconfig-json.html#types-typeroots-and-types .
(Of course, the long link could be replaced with an aka.ms link.)

`types`オプションが指定されていないと、`typeRoots`以下に型定義ファイル以外があると混乱してしまうようです。
でも `src/@types`だとエラーが起きちゃうし...


## 解決方法
typeRootsで指定するフォルダの中に、直で型定義ファイルをおいちゃダメでした。
src/@types/global/index.d.tsという配置にして、

```
"typeRoots": ["src/@types", "node_modules/@types"]
```

にすればいけました。
本来パッケージ単位で扱うものだからですね。
めでたしめでたし。
[メモ]ログイン情報をページ読み込み時に一度だけ呼び出す

#概要
ページを読み込んだときに必要なデータをgetする際に、`mounted()`から呼び出すことがあると思います。
mountedはコンポーネントが呼び出されるたびに実行されるので、
**コンポーネントA→コンポーネントB→コンポーネントA**とページ遷移したらコンポーネントAの`mounted`は二回呼び出されることになります。
しかし、ページ遷移するたびに`mounted`すると時間もかかってしまうので、1回目のコンポーネントを読み込んだ時だけ`mounted`を呼び出そうと思います。

#解決策
ログインユーザーの情報を呼び出したいと思います。

```auth.js
//ログインしているユーザー情報を取得するメソッドです
const state = {
    user: null,
};
const getters = {
    user: state => state.user ? state.user: '',
};
const mutations = {
    setUser(state,user){
        state.user = user;
    },
};
const actions = {
    async fetchUser(context){
        await axios.get('/api/user', {
            headers: {
                Authorization: `Bearer ${state.token}`
            }
        }).then((result)=>{
            context.commit("setUser", result.data.user);
        }).catch(error=>{
            console.log(`Error! HTTP Status: ${error}`);
        })
    },
}

```

##改善前
```.vue
<script>
computed: {
    user(){
        return this.$store.getters["auth/user"];
    },
},
mounted() {
    console.log('mounted start!');
    this.$store.dispatch('auth/fetchUser'); //上記のメソッド呼び出し
}
</script>
```


##改善後
```.vue
<script>
mounted() {
    console.log('mounted start!');
    const user = this.$store.getters["auth/user"]; 
    if(!user){ //gettersにログインユーザー情報が入っていない場合だけ呼び出す
         this.$store.dispatch('auth/fetchUser');
    }
}
</script>
```
WordPressアドレス(URL)を誤って変更してしまった話

ポカしました。

wordpressの設定欄には変更してはいけない項目があり、全く知らずに変更してしまいました。

・WordPressアドレス（URL）

サイトにも繋がらず混乱してしまいましたが、以下のことをすることで解決いたしました。

①サーバーのデータベースからphpMyAdminにアクセス。

②wp_optionsのsite_urlをクリック

③元のURLに変更

サイトにアクセスできないので一瞬戸惑いますが、意外と簡単に治ります。

お試しあれ。
pythonで果物分類してみた④Herokuへのデプロイ方法

#8.アップロード説明


####Herokuの設定

* **Herokuの会員登録をし、ログインしてください。**

* **次に、Herokuをインストールします。**

* **HerokuCLIのサイトからインストールを行ってください。**

* **HerokuCLIのインストールを行うと同時にgitもインストールされます。**

Herokuへのデプロイ方法は以下の通りです。

アプリのファイルのあるディレクトリに移動(cd コマンド)

heroku login で指示された通りにメールアドレスやパスワードを入力する

**Herokuに移動**
・　Create New App -> App nameを入力し、国をUnited Statesで登録する
・  アプリのページに遷移しSetteingsに移動、Add buildpackをクリックしてPythonを追加する
下の3つのファイルを アプリのあるディレクトリに移動させる(このipynbファイルと同じディレクトリにあるmnist_appディレクトリにあります。)
``Procfile, requirements.txt, runtime.txt``

Heroku上で動作を確認する際には、``mnist.py``としてきたファイルを必ず ``main.py`` という名前にしてください。

ディレクトリ(フォルダ)内に、``main.py , Procfile , requirements.txt , runtime.txt ``, 学習済みモデル , ``templatesフォルダ , staticフォルダ　, uploadsフォルダ``があることを確認し、

**〜ターミナル（コマンドプロンプト）のアプリファイルのある階層で〜**
※つまり、 cd コマンドを用いて自分のアプリのあるディレクトリ(フォルダ)に移動してください。

###手順

``・git init(これは初回のみです)
・heroku git:remote -a (アプリ名)
・git add .
・git commit -m “(何を変更したかメッセージを書く)”
・git push heroku master``
としてデプロイをしてください。


###デプロイできない場合
######heroku stack:set heroku-18 を使用して切り替えを行います。

``・heroku login
・heroku git:remote ~
・heroku stack:set heroku-18
・git add .
・git commit -am "make it better"
・git push heroku master
``
ターミナルで$ heroku loginを実行

```
$ heroku login
```
実行後

```
heroku: Press any key to open up the browser to login or q to exit: 
```
エンタープッシュ後

![スクリーンショット 2021-02-04 23.57.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/942550/61aad613-4c64-aa68-aebf-91f1a6300e81.png)

###アプリケーションの作成
以下のコマンドをターミナルで叩くことでheroku上にアプリケーションを作成することができます。「アプリケーション名」は、herokuを利用している全ユーザ内でユニークであればどんな名前でもOKです。

```
heroku create アプリケーション名
```




順番に実行する

```・git add .
・git commit -m “(何を変更したかメッセージを書く)”
・git push heroku master
```

しばらくデプロイ作業のログが出続けると思いますが、1~2分もすれば終わると思います。

###表示確認
ターミナルに以下のコマンドを入力するとherokuでのWebページを開くことができます。
（もしくはデプロイ作業のログの最後の方に出たURLでもWebページを開くことができます。）

```
heroku open
```
実行後表示されます。
![スクリーンショット 2021-02-05 10.31.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/942550/487afd8f-bfc3-79da-1e0d-29feb443e7a4.png)

#9.記事URL

```
https://fruits-app-000.herokuapp.com/predict
```
画像を用いた単体テストコードをする場合の画像挿入方法

# 結論
publicディレクトリの中に、imagesディレクトリを作り、その中に画像を挿入する。

# 過程
商品を出品する際に、画像がないと登録できない、というテストをしようとした。
その際に、まずfakerを導入。
そして、下記のように記述。

```ruby:spec/factories/items.rb
 after(:build) do |item|
      item.image.attach(io: File.open('public/images/test_image.png'),filename: 'test_image.png')
    end 
```
この記述をすることで、テスト時に画像を自動で挿入してくれる。

# 注意点
画像を保存したときの名前の通りに、ファイルの名前を入れないと読み込んでくれないこと。
また、使用する画像は、PCのなかに、取り込まないといけないこと。
【わたし用備忘録】Cybozu Frontend Monthly #7 資料・メモまとめ

# Cybozu Frontend Monthly #7
開催日時：2020.01.26
1月に話題になったフロントエンドのトレンドを紹介

- [イベントページ](https://cybozu.connpass.com/event/202029/)
- [当日の資料](https://cybozu.github.io/frontend-monthly/posts/2021-01)
- [Youtubeアーカイブ](https://www.youtube.com/watch?v=MMFzKjIzdRA)

<br>
## JavaScript アンケート周り

- [State of JS 2020](https://2020.stateofjs.com/ja-JP/)
- [2020 JavaScript Rising Stars](https://risingstars.js.org/2020/ja)

Gulp、Redux、Gatsbyあたりがトレンドから外れそう？？
ReduxよりRecoilが圧倒的差でスター数多い（！）
[Redwood](https://redwoodjs.com/)という素敵フレームワーク

<br>
## Don’t Use Inverted Color Cues on Toggle Buttons

- [Don’t Use Inverted Color Cues on Toggle Buttons｜uxmovement](https://uxmovement.com/buttons/dont-use-inverted-color-cues-on-toggle-buttons/)

トグルボタンのアクセシビリティ
![icc-cuetouse.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/690270/c2b408aa-93d4-471c-3a96-05f4426f698b.png)

<br>
## Classiにフロントエンドエキスパートチームを作った話

- [Classiにフロントエンドエキスパートチームを作った話](https://tech.classi.jp/entry/2021/01/18/103110)
- [FrontendOps](https://giamir.com/frontendops)

重要な問題を認識して、そのチームで必要なツールなどを作っていこうという意識
![image-20210126171856680.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/690270/299d214f-bd23-d538-753b-a2f50d2aa42e.png)

<br>
## Front-End Performance Checklist 2021 — Smashing Magazine

- [Front-End Performance Checklist 2021 — Smashing Magazine](https://www.smashingmagazine.com/2021/01/front-end-performance-2021-free-pdf-checklist/)

パフォーマンスに関するチェックリスト

- [チェックリストPDF](https://www.dropbox.com/s/34noajrbm324iai/performance-checklist-1.4.pdf?dl=0)
- [チェックリストPDFのアーカイブ](https://www.smashingmagazine.com/category/checklists)

https://estimator.dev/
あるブラウザをサポート対象外にした時のパフォーマンス改善指標が出る
chrome拡張機能でデフォ搭載されるかも！
※[参考文献](https://addyosmani.com/blog/performance-hud/)

<br>
## Agenda for the 80th meeting of Ecma TC39

- [Agenda for the 80th meeting of Ecma TC39](https://github.com/tc39/agendas/blob/master/2021/01.md)

JSXは特に便利に使える！
![image-20210126173046406.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/690270/55e6db3e-a169-5c5c-07d9-1e2d7cdef2fc.png)

<br>
## Enabling Popups - MicrosoftEdge/MSEdgeExplainers

- [Enabling Popups - MicrosoftEdge/MSEdgeExplainers](https://github.com/MicrosoftEdge/MSEdgeExplainers/blob/main/Popup/explainer.md)

ポップアップhtmlの新しい提案
![image-20210126173656925.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/690270/51d5f76f-7b24-9ca5-8be2-b2b790426c19.png)

<br>
## How We Improved SmashingMag Performance

- [How We Improved SmashingMag Performance](https://www.smashingmagazine.com/2021/01/smashingmag-performance-case-study/)

パフォーマンス改善に関する提案というか実際にやったこと
これやべえ
![image-20210126175058995.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/690270/cf57187c-c2fe-4e57-bac4-da712b71c271.png)

<br>
## Upgrading DevTools' architecture to the modern web

- [Upgrading DevTools' architecture to the modern web](https://youtu.be/BHogHiiyuQk)

☝️動画なので注意
実際にchromeDevtoolsが取り組んだアーキテクチャ移行についての動画

<br>
<br>
**おわり**:qiitan:
情報セキュリティについて

# はじめに
引き続き研修で学んだことをアウトプットしてきます！

今回は「セキュリティについて」です。

# 学んだこと
情報セキュリティ10大脅威というPDFをもとに学習しました。
参考：https://www.ipa.go.jp/files/000066223.pdf

知らない用語も多々ありましたので、まとめていきたいと思います

### 標的型攻撃による被害
組織的セキュリティ脅威の上位にあたる被害。

#### 標的型攻撃とは
特定のターゲットを狙いを絞って、メールやウェブサイトからウイルスに感染させる攻撃

- メールを利用した手口
 - ウイルスを含んだ添付ファイルを開かせる
 - ウイルスを含んだウェブサイトへのリンクをクリックさせる
 
- ウェブサイトを利用した手口
 - 標的組織がよく利用するウェブサイトを調べて、それを閲覧するとウイルスに感染するように改ざん

### ランサムウェアによる被害
これも上位に当たる被害。

#### ランサムウェアとは
- Ransom（身代金）とソフトウェアを組み合わせて作られた名称で、コンピュータウイルスの一種。
- 感染したパソコンのファイルやデータが読み取れなくなり、そのデータ復元させる代わりにお金を要求する。
- ランサムウェアやスパイウェアなどの悪いプログラム全般を総称してマルウェアと呼ぶ。

#### 標的型攻撃とランサムウェアの違いは？
標的型攻撃はターゲットを絞って攻撃を仕掛けるのに対し、ランサムウェアなどは無差別型攻撃といい、不特定多数に攻撃を仕掛ける。

一方で`標的型ランサムウェア`という新たな被害も増えている。

### 標的型ランサムウェア
特定の組織、団体を狙ってランサムウェアを使用してお金を要求する攻撃

2020年のセキュリティ事件に関する記事にもあるように、どの企業が対象になってもおかしくない状態。
参考：https://www.itmedia.co.jp/enterprise/articles/2012/22/news033.html

- マルウェアの進化によりウイルス検知もしにくく、知らないうちに攻撃されていることも。 

- ランサムウェアによって暗号化されたデータ復元のためのお金の要求に加えて、暗号化する前にデータを盗んでおき、お金を支払わなければデータを公開するといった二重に脅迫するという手口

### サプライチェーンの弱点を悪用した攻撃

#### サプライチェーンとは？
原材料を調達して、加工し実際の製品をつくり、消費者に届けるまでの一連の流れのこと

このサプライチェーンを利用し、比較的セキュリティ対策が手薄な取引先を経由して攻撃する

### 対策
- UTM・IDS/IPS・WAFの導入
- 取引先など全体を含めたセキュリティ対策の向上

##### UTMとは？
複数のセキュリティシステムが統合されたもの

##### WAFとは？
webアプリケーションに特化したファイアウォール

##### ファイアウォールとは？
- インターネットを通じた不正アクセスを防ぐ
- 外部ネットワークと内部ネットワークの間に設置されており、指定されたポート番号やIPアドレスのみ通信を許可するといった仕組み

##### IDSとIPSの違いは？
`IDS`：侵入検知システム。不正な通信を検知し、アラートを送信する
`IPS`：侵入防止システム。不正な通信を検知し、通信を防止する

### 個人でできる対策
- 送信元が不明なメールは開かない
- 添付ファイルやリンクを安易にクリックしない
- OSをアップデートする
- バックアップを取得する
- 情報を集めて意識を高める

# まとめ
どんなセキュリティリスクがあるのかを知っていることで対策をとることができ、自分で意識しなければならない点も理解することができるので日頃からセキュリティに関して意識することが大切であると感じました。今後もニュースなどにアンテナを貼り、どんなリスクがあり、どんな対策がとれるのかを考えながら情報収集していきたいと思います。
RailsにVue導入時のWebpackerエラー　ActionView::Template::Error (Webpacker can't find hello_vue…

単純な間違いなのですが気づくまでに時間がかかったので。
Webpacker利用時のケアレスミスに気をつけてって話。

ローカルでは問題なく動いていたのにデプロイすると

![E382B9E382AFE383AAE383BCE383B3E382B7E383A7E38383E38388202015-12-132022.27.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/707182/d156fe55-0b36-89b3-0653-7b49a886411f.png)


#エラー
EC2インタスタンスにsshで入り`production.log`を覗いてみると、

```production.log

ActionView::Template::Error (Webpacker can't find hello_vue...
```

#原因
問題はhtml.erbファイルにある

```
<%= javascript_pack_tag 'hello_vue' %>
<%= stylesheet_pack_tag 'hello_vue' %>
```

**この`<%= stylesheet_pack_tag 'hello_vue'  %>`が不要！**
使ってないのになぜかしれっと置いてた。

`<%= javascript_pack_tag 'hello_vue' %>`の方を利用することで
`app/javascript/packs`配下のhello_vue.**js**を読み込みます。

`<%= stylesheet_pack_tag 'hello_vue'  %>`を利用すると
`app/javascript/packs`配下のhello_vue.**css**を読み込みます。


`hello_vue.css`なんてファイル使ってなかった…

#教訓
**Webpackerを利用してる時は必要ないタグを置いていると開発環境では問題なく動くが本番環境ではエラーが出てしまう！注意！**
環境変数の切り替え方法。下に記述した内容でオーバーライドされる。

個人メモです。

開発環境やstg環境、prd環境で環境変数を切り替える場合に、それぞれ別の.envファイルを用意する方法もあるが、**１つの.envファイルで中の変数を切り替える**方法でも対応できる。

###(例)PWとUSER名を切り替える
例えば、PWとUSER名を切り替える場合は以下のようになる。

```env:.env
DB_USERNAME=a-san
DB_PASSWORD=xxx
# DB_USERNAME=b-san
# DB_PASSWORD=yyy
```

これをb-sanに切り替えるには、下のコメントアウトを外すだけでOK。

```env:.env
DB_USERNAME=a-san
DB_PASSWORD=xxx
DB_USERNAME=b-san
DB_PASSWORD=yyy
```

同じ変数がある場合、下に記述されている内容で上書きされる。
Raspberry Pi Picoをwindowsから書き込んでLチカしてみた

少し出遅れた感がありますが、
Raspberry Pi Picoが届きました。

書き込み方法の確認のためにWindowsからThonnyを使用してLチカしてみましたのでその方法を残しておきます。
##Raspberry Pi Pico, Micro Pythonとは
Raspberry Pi Picoとはarmベースのマイコンです。
Arduino公式からRaspberry Pi Pico用のarduino coreの開発をしているというアナウンスはあったのですが、2020/02/05現在ではまだできないようです。

ということで、続報に期待して今回はMicro PythonでのLチカに挑戦です。

MicroPython（マイクロパイソン）は、C言語で記述されマイクロコントローラ上での動作に最適化された、Python 3と高い互換性を持つプログラミング言語処理系である。※wikipedia

Micro Pythonを使用するうえでメリットとして考えられるのが、
言語仕様が充実しているので実装が簡単にできること
マイコン用の組み込みライブラリが用意されていること
です。

個人的にはArduinoIDEを使用することで同じようなメリットを受けることができるのかなと考えています。

書き込みの流れとしては、
Micro Python開発環境をPCに入れる
マイクロパイソンファームウェアをRaspberry Pi Picoに書き込む
作成したPythonコードをRaspberry Pi Picoに転送して実行する
というようになっています。

実際の処理のイメージとしては下記の図のようになっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244155/66ef7b20-54b9-3cfd-0683-9f459353d318.png)


##手順
開発環境であるThonyをダウンロードします。
Windows用のThonnyは[こちら](https://github.com/thonny/thonny/releases/download/v3.3.3/thonny-3.3.3.exe)からダウンロードすることが出来ます。
ダウンロードが終了したらexeファイルを実行してインストールします。
特に難しい設定はないので、インストーラに従ってインストールしてください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244155/c013cb71-fe9a-e8b5-d41e-42b27059d175.png)


最後にFinishを押してインストールは完了です。

最初にThonnyを立ち上げるときに設定が必要になります。

ToolsからOptioonを開きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244155/5463e2ed-5452-0725-004f-9694aa3437e4.png)

Generalでlanguageを日本語に変更してください。
Thonnyを再起動すると設定が反映されます。

Raspberry Pi Picoへのファームウェアの書き込みの準備をしていきます。
先ほどと同じようにtoolからoptionを選択してください。

インタプリタでMicro Python(Raspberry Pi Pico)を選択します。
Raspberry Pi PicoをBOOTSELボタンを押しながらPCと接続します。
私の場合はportは自動検出のままで大丈夫でした。
install or update firmwareをクリックします。
書き込みが可能であればインストールボタンがクリックできるようになりますのでクリックして書き込みを行ってください。
書き込みができないときは接続の手順をやり直してみてください。

書き込みが終了したらこのようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244155/606dad3a-7a2a-4565-fb43-1274275a0316.png)

Lチカのプログラムを書き込みます

```
import machine
import utime

led = machine.Pin(25, machine.Pin.OUT)
while True:
    led.value(1)
    utime.sleep(1)
    led.value(0)
    utime.sleep(1)
```
f5ボタンを押すか、緑の三角ボタンを押すと実行できます。
実行する前にはコードを保存する必要があるのですが、
Raspberry Pi Picoへ保存するようにしてください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244155/7b4b1a47-e9cd-9580-f3b8-ba867537791a.png)

三角ボタンを押すことで
Lチカを実行することが出来ました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/244155/70612ec5-6e65-088e-45b6-93cbec3edf72.png)

##参考情報
https://notenoughtech.com/featured/c-c-and-micropython-sdk-for-raspberry-pi-pico-on-windows/
https://picockpit.com/raspberry-pi/raspberry-pi-pico-and-micropython-on-windows/

Inter face 2021年3月号
STM32F767のMbedでの液晶,AQM0802Aで表示(i2c)


1.SCLとSDAを接続、プルアップも忘れずに
2.電源の接続
3.下記のソースコードを書き込む
4.コンパイル実行で表示されたら終了
5.おわり

おまけ
古いスイッチサイエンスのソースを参考にしました。
aと表示される。

```c++

#include "mbed.h"
 
#define ADDR     (0x7C) //  address
 
I2C i2c(I2C_SDA, I2C_SCL);
 
DigitalOut myled(LED1);
 
Serial pc(SERIAL_TX, SERIAL_RX);
 
volatile char TempCelsiusDisplay[] = "+abc.d C";

int main()
{
 
    char data_read[2];
  
    //init
    wait(0.2);

    data_read[0] = 0x0;

    data_read[1]=0x38;
    i2c.write(ADDR, data_read, 2);

    data_read[1]=0x39;
    i2c.write(ADDR, data_read, 2);

    data_read[1]=0x14;
    i2c.write(ADDR, data_read, 2);

    data_read[1]=0x70;
    i2c.write(ADDR, data_read, 2);

    data_read[1]=0x56;
    i2c.write(ADDR, data_read, 2);

    data_read[1]=0x6C;
    i2c.write(ADDR, data_read, 2);

    wait(0.2);

    data_read[1]=0x38;
    i2c.write(ADDR, data_read, 2);

    data_read[1]=0x0C;
    i2c.write(ADDR, data_read, 2);

    data_read[1]=0x01;
    i2c.write(ADDR, data_read, 2);

    wait(0.2);

    data_read[0]='@';
    data_read[1]='a';
    i2c.write(ADDR, data_read, 2);


    while (1) {

        // Display result
        pc.printf("temp = %s\n", TempCelsiusDisplay);
        myled = !myled;
        wait(2.0);

    }
 
}


```


![i2c_8x2_767_e_1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/840352/1f1c348b-0b7f-a99e-0dcf-4bf09584c75e.jpeg)
railsでフォロー機能を非同期化する

# 開発環境
Mac OS Catalina 10.15.7
ruby 2.6系
rails 6.0系

# 前提

・フォロー機能は実装済み(フォロー機能に関するgemは使用していません)
・フォロー機能を実装する際の中間テーブ名はrelationshipsテーブル



フォロー機能に関しては下記のURLの記事を参考に実装すると良いかと思います。
理解しやすくまとめてくれています。
https://qiita.com/mitsumitsu1128/items/e41e2ff37f143db81897



# フォローボタン部分を部分テンプレートで切り出す

まずはフォローボタンを部分テンプレートで切り出します。
後にcreate.jsとdestroy.jsでこの部分テンプレートを差し替えるためです。

自分はsharedディレクトリを作っているので、その中に切り出しました。


```views/users/show.html.erb
# 自分はユーザー詳細ページにフォローボタンを設置しています。
<% if user_signed_in? && current_user.id != @user.id %>
  <div>
    <%= render "shared/follow", user: @user %>
  </div>
<% end %>
```

```views/shared/_follow.html.erb

  <% if current_user.following?(user) %>
    <%= form_for(current_user.relationships.find_by(follow_id: user.id), html: { method: :delete }) do |f| %>
      <%= hidden_field_tag :follow_id, user.id %>
      <%= f.submit 'フォロー解除', class: 'btn btn-danger btn-block' %>
    <% end %>
  <% else %>
    <%= form_for(current_user.relationships.build) do |f| %>
      <%= hidden_field_tag :follow_id, user.id %>
      <%= f.submit 'フォローする', class: 'btn btn-primary btn-block' %>
    <% end %>
  <% end %>

```

# 切り出した部分テンプレートの親要素にIDを付与

後にjs.erbファイルでこのIDを取得して、中身を差し替えるためです。

```views/users/show.html.erb
<% if user_signed_in? && current_user.id != @user.id %>
  # 下記1行にIDを付与
  <div id="follow-ajax">
    <%= render "shared/follow", user: @user %>
  </div>
<% end %>
```


# form_forをremote: trueにする

form_forをremote: trueにします。

form_forはform_withと異なり、デフォルトでremote: trueになっているわけではないので、非同期にしたい場合はremote: trueを記述してあげる必要があります。

```views/shared/_follow.html.erb

    # 次の１行にremote: trueを追加
    <%= form_for(current_user.relationships.find_by(follow_id: user.id), html: { method: :delete },remote: true) do |f| %>


    # 次の１行にremote: trueを追加
    <%= form_for(current_user.relationships.build, remote: true) do |f| %>
```

# コントローラーのリダイレクトの記述を削除


コントローラーでリダイレクトの記述をしている場合は削除します。
なければスルーで大丈夫です。

```relationships_controller.rb
 def create
    following = current_user.follow(@user)
    following.save
    # リダイレクトの記述があれば削除する
  end

  def destroy
    following = current_user.unfollow(@user)
    following.destroy
    # リダイレクトの記述があれば削除する
  end

```

# create.jsとdestroy.jsを編集する

どちらもコードは同じです。

前述のように自分はsharedディレクトリに部分テンプレートを入れているので、partialオプションの記述が'shared/follow'となります。
また、localsオプションで、切り出した部分テンプレート内で使う変数をしっかりと渡してあげましょう。

```create.js.erb
document.getElementById('follow-ajax').innerHTML = '<%= j(render partial: 'shared/follow', locals: { user: @user }) %>
```

```destroy.js.erb
document.getElementById('follow-ajax').innerHTML = '<%= j(render partial: 'shared/follow', locals: { user: @user }) %>
```

以上です。
参考になれば幸いです。
そういえば、スターハックとかいうのあったな。

最近のコーディング事情といえば、スマホのデバイス対応が重点的に多くなった気がします。
一昔前は、PCのアイなんちゃら、っていうブラウザの対応に四苦八苦していた思い出。

ちょっと懐かしくなってしまったものも含めて、休憩がてら書いてみました。

## スターハック
- IEの古いブラウザ表示対策に使われていたcssハック。アイなんちゃらさんは、Macにもいて微妙に違うブラウザ差異に悩まされ四苦八苦した記憶。<br>↓こういうやつ

```sample:css
* html p {
  padding-top:10px;
}
```
セレクタの前に `* html` と記述するだけなんですけどね。
6のみ7のみ8のみ・・・オイオイいつまでブラウザ対応続くんだ！Macと7と8と9と10で微妙に違う指定になってもうキリがありませんでした。<br>最近だいぶん統一されてきて楽になったので良かった。もうこいつらに出会う事はほぼほぼないだろう。

## tableコーディング
- 言わずもしがな、divやdlやulなどに置き換わり、主要なコーディング（レイアウト段組み）では使用せず、本来の用途（表・summary）として使われていますね。<br>`spacer.gif`を駆使して、無理くりデザイン反映した記憶があります。<br>「HTMLには文章構造のみ・デザイン装飾はCSSに分離」と言い出した偉い人バンザイ。<br>ちなみに、カド丸とかもすべてテーブルで対応してました。<br>参考までに：[昔の人はtableでカドマルを作ってた、ってよ！](https://qiita.com/m_hamada/items/1b72f6a87839ed4a9b3f)

## .gifから.png
- `gif` に置き換わる透過画像として、`.png`の拡張子が徐々に認められつつある時が訪れました。`.png`の方が色数をより多く使って画像にできてキレイ！という事で、だんだん使われなくなっていきましたね。（今でもバナーなどでgifアニメとしては、残ってるのかな。というか、pngアニメって聞いたことないな、そういえば。）<br>私は「ジフ」派だったが、「ギフ」って読む人に出会うと、フフッてなってた。<br>IE6で勝手に水色背景つけてきたのは今でも許さんぞ！（笑

##Flash
- 当時はアニメーション制作に欠かせないものでした。脆弱性の問題などで、Flashの標準無効化が進み、今では、html5のvideoタグや他のプロパティに成り代わっています。フラッシャーの人は青天の霹靂だったろうなあ・・・。Flashの作品集を見るのが好きでした。

## 謎の余白問題
marginやpaddingを使ってると、あるブラウザでは意図しない余白になったりすることが多々ありました。<br>また、あるブラウザでは、htmlの改行を余白とみなす場合があるので（これは今もたまにある？）、↓のようにタグで無理やりなくしたりしてた。

```sample:html
<ul>
<li>項目１<
/li><li>項目２<
/li><li>項目３</li></ul>
```

改行位置はうろ覚え。なんだこれ、って感じですが、本当にやってました。今では考えられナーイ！

どんどん便利になっていく中、いまでは役にたたないこんな知識あっても仕方ないんだけど、ふと懐かしく思った次第でした。便利に生まれ変わった技術を脳内刷新していくぞー。
【Python】受信したメールの添付ファイル名に日本語が含まれているときの対応

## 環境
python 3.7.5

## 省くこと
gmailのアプリパスワード取得の手順は省きます。

## メールサーバーにログイン
```mail.py
import imaplib
import email

# 自身のメールアドレス
gmail_address = 'hoge@gmail.com'
# googleアカウントで取得したアプリパスワード
gmail_app_password = 'hogehogehogehoge'

gmail = imaplib.IMAP4_SSL("imap.gmail.com", '993')
gmail.login(gmail_address, gmail_password)
# select()でボックスを選ぶのですがここでは選択しない
gmail.select()
```

## メール一覧を取得
```mail.py
# ALLの部分を変更することで検索をかけることができます
head, data = gmail.search(None, 'ALL')
for num in data[0].split():
    result, email_data = gmail.fetch(num, '(RFC822)')
    raw_email = email_data[0][1]
    raw_email_string = raw_email.decode("utf-8")
    email_message = email.message_from_string(raw_email_string)
    
    body = ''
    attachments = []

    for part in email_message.walk():
        if part.get_content_type() == "text/plain":
            charset = part.get_content_charset()
            # 本文に合わせてdecode
            payload = part.get_payload(decode=True)
            if charset is not None:
                payload = payload.decode(charset, "ignore")
                body = self.__delete_emoji(payload)
            else:
                # 基本的にこれで適切なfile_nameが取れるのですが、日本語が含まれていると、decodeしなければなりません。
                file_name = part.get_filename()
                # fileがある場合のみ実行
                if file_name:
                    # 日本語の場合はうまく取得できないのでraw_dataを取得
                    file_name_raw = email.header.decode_header(part.get_filename())
                    # decodeされる前のfilenameを取得
                    encoded_file_name = file_name_raw[0][0]
                    # filenameのcharsetを取得
                    file_charset = file_name_raw[0][1]
                    # charsetがある場合のみdecodeしてあげる
                    if file_charset:
                        file_name = encoded_file_name.decode(file_charset)

                    attachment = {
                        'name': file_name,
                        'data': part.get_payload(decode=True)
                    }
                    attachments.append(attachment)
```

part.get_filename()では日本語を含むものをうまくdecodeしてくれなかったので、自前でdecodeで対応できました。
[Android]RoomでInsert時にOnConflictStrategy.REPLACEを使う際の注意点

Android のプロジェクトで Room を使用してハマったことがあったので共有したいと思います。

結論から言うと、`ForeignKey` で指定される Entity があった場合、その Entity を Insert する際に `OnConflictStrategy.REPLACE` を使用してはいけません。

## 理由

Dao で `@Insert` アノテーションに `OnConflictStrategy.REPLACE` を指定すると、SQL 的には `INSERT OR REPLACE` 文が実行されます。

SQLite の仕様では `INSERT OR REPLACE` 文では既存の行を削除した上で、行を追加、更新するようになっています。

参考: https://sqlite.org/lang_conflict.html

>When a UNIQUE or PRIMARY KEY constraint violation occurs, the REPLACE algorithm deletes pre-existing rows that are causing the constraint violation prior to inserting or updating the current row

ですので `REPLACE` の対象が `ForeignKey` で指定されている Entity のレコードであった場合に意図しない動作が発生する場合があります。

## 例

`記事` と `お気に入りの記事` の Entity が以下のように定義されていたとします。

（`お気に入りの記事` では `ForeignKey` で `記事` の Entity が指定されています）

```:Article.kt
// 記事
@Entity(tableName = "articles")
data class Article(
    @PrimaryKey val id: Int,
    val title: String,
    val contents: String
)
```

```:FavoriteArticle.kt
// お気に入りの記事
@Entity(
    tableName = "favorite_articles",
    foreignKeys = [
        ForeignKey(
            entity = Article::class,
            parentColumns = ["id"],
            childColumns = ["articleId"],
            onDelete = ForeignKey.CASCADE
        )
    ]
)
data class FavoriteArticle(
    @PrimaryKey val articleId: Int
)
```

そして Dao で以下のようなメソッドを定義していたとします。

```:ArticleDao.kt
@Dao
abstract class ArticleDao {

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    abstract fun insertArticle(article: Article)
    
    ...
}
```

そして `記事` と `お気に入りの記事` のレコードがそれぞれデータベースに保存されていた場合に、上記の Dao のメソッドで既存の `記事` を更新するとデータベースに保存されている関連した `お気に入りの記事` が削除されてしまいます。

（`ForeignKey` の `onDelete` に設定している値によって `お気に入りの記事` がどうなるか挙動は変わりますが、この例の場合だと `ForeignKey.CASCADE` を設定しているので削除されます）

## 解決方法

例えば以下の例のように `OnConflictStrategy.IGNORE` などに設定しておき、Transaction を張ってレコードがあれば更新、なければ新規作成のようにする方法が考えられます。

```:ArticleDao.kt
@Dao
abstract class ArticleDao {

    @Insert(onConflict = OnConflictStrategy.IGNORE)
    abstract fun insertArticle(article: Article)

    @Query("UPDATE articles SET title = :title, contents = :contents WHERE id = :articleId")
    abstract fun updateArticle(articleId: Int, title: String, contents: String)

    @Query("SELECT COUNT(*) FROM articles WHERE id = :articleId")
    abstract fun countArticle(articleId: Int): Int

    @Transaction
    open fun insertOrUpdateArticle(article: Article) {
        if (countArticle(article.id) > 0) {
            // レコードがあれば更新
            updateArticle(article.id, article.title, article.contents)
        } else {
            // レコードがなければ新規作成
            insertArticle(article)
        }
    }
    
    ...
}
```