OmniAICreator/Qiita-1.07M huggingface dataset:
アセットパイプラインで圧縮された画像を、JavaScriptで参照するためのパスの書き方

タイトルの内容、
JavaScroptにおける画像ファイルパスの書き方がわからず詰まったので備忘録として残します

# 結論

#### imagesまでのパスは抜く

ファイル格納場所が
app/assets/images/hoge.png
の場合は以下のように記述する
/assets/hoge.png

理由はまだわかっていないのですが、
一旦上記方法で対応できました！

---


#### 以降はアセットパイプラインに対する補足のため、タイトルの内容からは逸れます

##### ①そもそもアセットパイプラインとは？
　画像やJS、CSS。HTMLファイルなどを最小化して連結するためのフレームワーク
　容量が軽くなるだけでなく、作業効率的なメリットも大きいようです　(後述)


　↓詳しい解説(引用：https://qiita.com/uma002/items/9a94ebc93c5f937502cd)
>作業がしやすいように画像、javascript、css、htmlファイルを分解つしてコーディングして、最終的に1つのファイルにまとめる仕組みのことです。
>
>普段railsを使うときには意識することはありませんが、htmlファイルはapp/viewsに配置されてjavascriptファイルはapp/assets/javascriptsに配置されていると思います。
>
>このようにファイルは分けて管理した方が、人間にとってはわかりやすいですが、最終的には全て統合して一つのファイルに統合して扱われます。さらに字を詰めることでファイルの容量を最小化する働きがあります。

##### ②なぜアセットパイプラインを通すのか？
　そもそもRailsで画像を格納できる場所は2つあります
　　①app/assetsディレクトリ：アセットパイプラインが通るディレクトリ
　　②publicディレクトリ：アセットパイプラインが通らず（圧縮対象にならず)にファイルが参照できるディレクトリ

　②に格納した場合、容量の負担増加に加え
　画像を同じファイル名で置き換えた場合に、ブラウザがキャッシュにある画像で済ませてしまうため、
サーバーにある変更後の画像に辿り着かない
　という問題が発生するようです（あくまで一例、それ以外にも問題はあるはず）
　
　そのため、余程のことがない限りアセットパイプラインを通すのが◎になります

# 参考

https://railsguides.jp/asset_pipeline.html

https://qiita.com/take95/items/f955228e0c5e4c68e3ef

https://qiita.com/kakudaisuke/items/4c9c9eb3eb79c38d9a20

https://qiita.com/uma002/items/9a94ebc93c5f937502cd
NextJS　CRUD with Firebase

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654025/071a146c-1e67-bb01-5743-7e3ff9917370.png)

# NextJs CRUD with Firebase
https://youtu.be/o7jTN4s78GQ

# Tips
>1, next/link With URL Object
2, hasOwnProperty()
3, React Firebase Hooks

# 1, next/link With URL Object

https://nextjs.org/docs/api-reference/next/link

### Link can also receive a URL object and it will automatically format it to create the URL string. Here's how to do it

```javascript:index.js
import Link from 'next/link'

function Home() {
  return (
    <ul>
      <li>
        <Link
          href={{
            pathname: '/about',
            query: { name: 'test' },
          }}
        >
          About us
        </Link>
      </li>
      <li>
        <Link
          href={{
            pathname: '/blog/[slug]',
            query: { slug: 'my-post' },
          }}
        >
          Blog Post
        </Link>
      </li>
    </ul>
  )
}

export default Home
```

# 2, hasOwnProperty()

### The hasOwnProperty() method returns a boolean indicating whether the object has the specified property as its own property (as opposed to inheriting it).

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty

```javascript:index.js
const object1 = {};
object1.property1 = 42;

console.log(object1.hasOwnProperty('property1'));
// Expected output: true

console.log(object1.hasOwnProperty('toString'));
// Expected output: false

console.log(object1.hasOwnProperty('hasOwnProperty'));
// Expected output: false

```


# 3, React Firebase Hooks
https://www.npmjs.com/package/react-firebase-hooks

### useAuthState
```javascript:index.js
const [user, loading, error] = useAuthState(auth, options);
```

### Full Example
```javascript:index.js
import { getAuth, signInWithEmailAndPassword, signOut } from 'firebase/auth';
import { useAuthState } from 'react-firebase-hooks/auth';

const auth = getAuth(firebaseApp);

const login = () => {
  signInWithEmailAndPassword(auth, 'test@test.com', 'password');
};
const logout = () => {
  signOut(auth);
};

const CurrentUser = () => {
  const [user, loading, error] = useAuthState(auth);

  if (loading) {
    return (
      <div>
        <p>Initialising User...</p>
      </div>
    );
  }
  if (error) {
    return (
      <div>
        <p>Error: {error}</p>
      </div>
    );
  }
  if (user) {
    return (
      <div>
        <p>Current User: {user.user.email}</p>
        <button onClick={logout}>Log out</button>
      </div>
    );
  }
  return <button onClick={login}>Log in</button>;
};
```
Linuxでexpectコマンドを用いたシェルスクリプトを使用できなかった時に代わりに使用したシェルスクリプト

# 概要
私が案件先で、Linux環境で元々は手動で実行していたプロセス起動シェルスクリプトを自動でプロセス起動ができるようID/PWの自動入力シェルスクリプト作成の依頼をされ、expectコマンド(対話シェルを自動化するためのコマンド)を使用したシェルスクリプトを作成しようと思ったが使用できない環境で困っており、その際に代用で使用したシェルスクリプトを記載いたします。

# 説明
今回は例として以下のシェルスクリプトでID/PWが自動入力できるか確認します。

●start.sh
```start.sh
#!/bin/sh

echo "IDを入れてください"

read ID

if test ${ID} = hogehoge >dev/null 2>&1 ; then
    echo "IDを確認しました"
else
    echo "IDが違います"
    exit 1
fi

echo "PWを入れてください"

read PW 

if test ${PW} = hugahuga >dev/null 2>&1 ; then
    echo "PWを確認しました"
else
    echo "PWが違います"
    exit 1
fi

echo "ID:$ID/PW:$PWの入力を確認しました"
```

次にID/PWを自動入力するためのシェルスクリプトを作成します。

●ID_PW_Autofill.sh
```ID_PW_Autofill.sh
#!/bin/sh

while read XXXX ; do		※1
	eco "XXXX:$XXXX" 1>&2
	
	case $XXXX in
		*"IDを入れてください"*)			※2
			;;
		*"PWを入れてください"*)			※3
			;;
	esac
done
```
※は注意書きですので実際は必要ありません。
※1「XXXX」は変数の値を指しています。(好きな値入れても大丈夫です)
※2「IDを入れてください」の中身はstart.shでIDを求められる時の文言を記載します。(文言を間違えるとIDの自動入力ができないので注意)
※3「PWを入れてください」の中身はstart.shでPWを求められる時の文言を記載します。(文言を間違えるとPWの自動入力ができないので注意)

次にID/PWを記載したファイルを作成します。

●ID_PW.txt
```ID_PW.txt
hogehoge
hugahuga
```
今回IDをhogehoge、PWをhugahugaにしてます。
これでID/PWを自動入力するための材料は集まりました。
後は以下コマンドを実行します。
```
#cat IW_PW.txt | sh start.sh | sh ID_PW_Autofill.sh
XXXX：IDを入れてください
XXXX：IDを確認しました
XXXX：PWを入れてください
XXXX：PWを確認しました
xxxx：ID:hogehoge/PW:hugahugaの入力を確認しました
#
```
IP_PW.txtのID/PWの値をID_PW_Autofill.shの「XXXX」変数の値として代入しているので、IDは"IDを入れてください"の後に自動入力され、PWは"PWを入れてください"の後に自動入力されるようになりました。

# おわりに
最後まで読んでいただきありがとうございました。
expectコマンドが使用できなかったときは焦りましたが、代用できて本当に良かったです。
Linuxの経験がまだ浅いため、もっと簡単に自動入力できる方法などご存じでしたらコメントください！
逆ジオコーディングをpythonで

# 逆ジオコーディング

大量に座標から住所変換したいのだが
APIは無料範囲では使い物にならんし、こんなことに金払う気にもならない。ひとつあったのが、Javascriptだったりして動かし方がわからない。
他にスタンドアロンで動くものがないから作った。

検索用のデータは[Githubにおいた](https://github.com/kirin123kirin/japan_research/releases/download/v0.1/revgeo.pkl)

```python
import pickle
import os
import re
from math import cos, sin, sqrt, atan2
import json
import sys

datadir = os.path.join(os.path.dirname(__file__), "dat")
maxint = sys.maxsize

"""
    e-Stat 統計地理情報システム 境界データダウンロードより取得したデータに基づいて作成
    https://www.e-stat.go.jp/gis/statmap-search?page=1&type=2&aggregateUnitForBoundary=A&toukeiCode=00200521&toukeiYear=2020&serveyId=A002005212020&datum=2011
    この作品は、クリエイティブ・コモンズの 表示 4.0 国際 ライセンスで提供されています。ライセンスの写しをご覧になるには、 http://creativecommons.org/licenses/by/4.0/ をご覧頂くか、Creative Commons, PO Box 1866, Mountain View, CA 94042, USA までお手紙をお送りください。 
"""

def get_address(lat, lon):
    def contains(minmax):
        max_x, max_y, min_x, min_y = minmax
        if max_x < lat:
            return False
        if min_x > lat:
            return False
        if max_y < lon:
            return False
        if min_y > lon:
            return False
        return True

    def distance(dic):
        dlat = dic["X_CODE"] - lat
        dlon = dic["Y_CODE"] - lon

        if dlat ** 2 > 1 or dlon ** 2 > 1:
            return maxint

        a = sin(dlat / 2) ** 2 + cos(dic["X_CODE"]) * cos(lat) * sin(dlon / 2) ** 2
        return 12742.02 * atan2(sqrt(a), sqrt(1 - a))

    dist = maxint
    ret = {}

    for i in [i for i, (minmax, _) in enumerate(areas) if contains(minmax)]:
        for j in [j for j, (minmax, _) in enumerate(areas[i][1]) if contains(minmax)]:
            for dic in areas[i][1][j][1]:
                d = distance(dic)
                if d < dist:
                    dist = d
                    ret = dic

    return ret


if __name__ == "__main__":
    areas = pickle.load(open(datadir + "/revgeo.pkl", "rb"))

    for x in sys.argv[1:]:
        print(get_address(*x.split(",")))

```

## 但し書き
辞書も軽く、軽快に検索できるが精度を求める場合はhttps://y-mattu.hatenablog.com/entry/2017/09/18/185014
などを参考にした方が良い。

なぜかというと、上記のプログラムはポリゴンではなく町字レベルの住所毎に国土交通省が設定した重心点の座標があるので、直線距離が最も近い町字レベルの住所を表示しているのに過ぎない。
川を隔てて隣り町の中心の方が距離が近かったらそっちの住所になったりすることもあるので、今回の僕の場合みたいに多少違っててもいいから高速に住所を取りたい場合だけ使用できる。

# 今後のために何か役に立つかも？
```python
def isin_poligon(x, y, polygon):
    """
    ポリゴンは反時計回りであること！など制約事項があるため
    今回使わなかったが、ポリゴンの内側にあるかどうかを判定するアルゴリズムもあった。
    今後何かの役に立つかもしれない。
    """
    cnt = 0
    L = len(polygon)
    for i in range(L):
        x0, y0 = polygon[i - 1]
        x1, y1 = polygon[i]
        x0 -= x
        y0 -= y
        x1 -= x
        y1 -= y

        cv = x0 * x1 + y0 * y1
        sv = x0 * y1 - x1 * y0
        if sv == 0 and cv <= 0:
            # a point is on a segment
            return True

        if not y0 < y1:
            x0, x1 = x1, x0
            y0, y1 = y1, y0

        if y0 <= 0 < y1 and x0 * (y1 - y0) > y0 * (x1 - x0):
            cnt += 1
    if (cnt % 2 == 1):
        return True
```
【Swift】Apple Silicon搭載Mac以外はインストールできなくする

# はじめに
以前、Apple Siliconで分岐させる記事を書きました。

https://qiita.com/SNQ-2001/items/0499a07202279f8202e0

しかし、Appleから「Apple Siliconしか使えないならIntel Macではインストールできないようにしろ！」とのレビューをいただきました。
丁寧に対応方法まで記載されていたので記録しておきます。

# 方法
① プロジェクトを選択します
② ターゲットを選択します
③ 「Build Settings」を選択します
④ 「Excluded Architectures」の欄の囲ってある箇所をダブルクリックします。
![スクリーンショット 2023-02-26 19.33.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/b7570b71-2728-bdc6-c020-cfe516abdaea.png)

⑤ 「+」をクリックします
![スクリーンショット 2023-02-26 19.37.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/0ac0ed18-5fe4-275e-f343-dc7ad0fc6a35.png)

⑥ `x86_64`を入力します
![スクリーンショット 2023-02-26 19.38.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/209ec634-780a-c733-9fdf-564bf94d3b19.png)

# 確認
「My Mac (Rosetta)」がなくなりました。
|変更前|変更後|
|-|-|
|![スクリーンショット 2023-02-26 19.36.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/f96fdf72-9349-e9ab-1a45-1b75dc96fffc.png)|![スクリーンショット 2023-02-26 19.40.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/6b038817-4697-a5c4-ed76-a43c9bc8039b.png)|

# おわり
Appleが対応方法を教えてくれるなんて珍しいです。
Amplify(v10.7.x)でAPI(GraphQL)をmock apiで起動したときに「NO SCHEMA AVAILABLE」と表示される時の対処法

amplifyコマンドをしばらくアップデートしてなかったから最新版に上げとくか。と思って作業前に最新版にアップロードしてからあれこれチュートリアルを始めたら、動かなくなってしまったので対処法の備忘録です。

# 何が起きた？

モックAPIを起動して表示されたURLにアクセスしたときに、画面上のExplorerが「NO SCHEMA AVAILABLE」となっていて何も表示されなかった。

実行したコマンド：

```bash
amplify mock api
```

| 期待していない状態 | 期待している状態 |
|:---:|:---:|
| ![スクリーンショット 2023-02-26 19.25.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79238/ab5e5a89-8e7a-a418-9569-eb17eb679da4.png) | ![スクリーンショット 2023-02-26 19.36.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79238/cdd9474b-7baf-97b0-d634-5df840d37d77.png) |

https://github.com/aws-amplify/amplify-cli/releases/tag/v10.7.3

# 原因

内部処理の詳しいところまでは追いかけていないですが、Issueで話されている内容を見た感じだと10.7.x系で発生しているバグのようですね。

バージョンの確認方法：

```
$ amplify version
10.7.3
```

https://github.com/aws-amplify/amplify-cli/issues/10488#issuecomment-1434523750

# 対処方法

10.6.x系の最新バージョンにダウングレードすると動くようになるようです。10.6.x系の最新バージョンを次のコマンドの通りにインストールするとダウングレードすることができます。

```bash
npm install -g @aws-amplify/cli@10.6.2
```

自分の環境でも試してみたところ、無事に解消しました。最新にアップグレードする必須性は今のところなかったので、しばらくこれで様子見することにします。
【備忘録】multiprocessとmultiprocessingの違いについて

# multiprocess
multiprocessing(Pythonの標準ライブラリ）を改良したサードパーティライブラリ
色々便利になっているらしい。

# 違い
種々あるらしいので、見つけ次第追記
- multiprocessは関数内関数を引数に持つことができる。
```python:sample.py
from multiprocess import Pool
import multiprocess as mp # multiprocessingと競合する。

def crawl(urls):
    def scrape_detail_page():
        '''
            詳細ページをスクレイピング
        '''
        # スクレイピング内容をサーバーに突っ込む処理
        
        return None

    # 並列処理
    cpu_num = mp.cpu_count()  
    pool = Pool(processes=cpu_num)
    
    with tqdm(total=max_page) as page:
        for _ in pool.imap_unordered(request_process, range(1, max_page+1)):
            page.update(1)
```
pythonで最寄り駅を検索するプログラム

# 位置地図座標から最寄り駅を探索したい

大量に検索したかったのでAPIだと制限とかあるし遅い。
この程度のことに有料とかはありえない。
調べてもAPIは見つかるのだが、オフラインで使えるものが見つからなかったのでpythonで作ってみた。

国土交通省のオープンデータを加工しまくった。
検索用データはデカいので[Githubにおいた](https://github.com/kirin123kirin/japan_research/releases/download/v0.1/station.pkl)

経路や地理条件を厳密に考慮して最寄りを出しているわけではなく、最も直線距離が近い駅を出力するようにしたものなので、あくまでざっくりで良い場合に限る。

```python
import sys
import os
import pickle
from math import cos, sin, sqrt, atan2

"""
座標から最寄り駅探索
station_data.pklの出典:「国土数値情報(鉄道データ)」(国土交通省) (https://nlftp.mlit.go.jp/ksj/gml/datalist/KsjTmplt-N02-v3_0.html) (データ年度:令和3年度取得)
を加工編集
"""
filename = os.path.join(os.path.dirname(__file__), "dat/station_data.pkl")
with open(filename, "rb") as f:
    stations = pickle.load(f)

N = len(stations)


def get_station(lat, lon):
    scale = 2 ** 10
    ret = {}

    for dic in stations:
        dlat = dic["lat"] - lat
        dlon = dic["lon"] - lon

        if dlat ** 2 > 1 or dlon ** 2 > 1:
            continue

        a = sin(dlat / 2) ** 2 + cos(dic["lat"]) * cos(lat) * sin(dlon / 2) ** 2
        d = 12742.02 * atan2(sqrt(a), sqrt(1 - a))

        if d < scale:
            scale = d
            ret = dic
    return ret


if __name__ == "__main__":
    for x in sys.argv[1:]:
        print(get_station(*x.split(",")))
```
CircleCIのテスト環境下のPostgresにpg_bigmの拡張機能を導入

# はじめに
とあるSaaSの会社に入社し、入社後すぐにRailsのプロダクトを１人で見ていくことになったときのお話。記事のタイトルどおり、すでにそのプロダクトのPostgresqlにpg_bigmという拡張機能が入っていて、CircleCi上でビルドする際にかなり苦戦したので、その時の対応手順の備忘録を記す。

# 壁１：ビルド中のマイグレーションに失敗
まずは普通にCircleCiの公式サイトを調べて、config.ymlを書いてみる。
すると、マイグレーションの部分で躓く。
```
Caused by:
ActiveRecord::StatementInvalid: PG::Error: ERROR:  operator class "gin_bigm_ops" does not exist for access method "gin"
: CREATE INDEX CONCURRENTLY item_keywords_bigm_idx ON item_keywords USING gin (keyword gin_bigm_ops)
```

# 一次対応
まずはエラーの意味を解釈。
「pg_bigmのインデックスを貼りに行こうとしたが、その途中でメソッドが存在しないからコケた」
で、そもそもpg_bigmってなにか？このプロダクトにおいてはどうやって導入されたのかを調べてみる。

# pg_bigmを認識する
シンプルに言うと日本語の検索を早くしてくれる拡張機能。Postgresqlに標準に搭載されているものではなく、自らPostgresqlにインストールして有効にし、テーブルの日本語カラムにpg_bigmのIndexを貼り、データ検索を高速化できる。似たようなものにpg_trgmというものがある（日本語の検索にはあまり優れていない）

なるほど。Railsレベルではなく、Postgresqlに直接なにかを施したものか。
このプロダクトもおそらくそういう経緯があったのだろう。つまりは、DBイメージに対して、pg_bigmをインストールし、有効にしてやる必要があるらしい。

# 二次対応
どうやって、CircleCi上にpg_bigmを入れるか。
=> Ci上のcommandで、wgetから拡張ファイルをインストールして、展開、導入するか

まずはMultipathを自分のMac（M1）に導入し、今試行錯誤するために、CircleCi上で使っているDockerのrubyのイメージとPostgresqlのイメージを導入してpg_bigmの導入を試してみて、うまくいくコマンドの黄金ルートを検証する（導入方法：https://pgbigm.osdn.jp/pg_bigm-1-2.html）

# 壁２：インストールはできているが有効化されない

結局同じエラーに引っかかる。でも、ログを見たところインストール自体はできている。

```
CREATE EXTENSION
  name   | default_version | installed_version |                             comment                              
---------+-----------------+-------------------+------------------------------------------------------------------
 pg_bigm | 1.2             | 1.2               | text similarity measurement and index searching based on bigrams
```

confファイルに
```
shared_preload_libraries = 'pg_bigm'
```

の記述をした後に、再起動が必要っぽい。だが、CircleCi上のDBイメージに対してで再起動なんかするものなのか？
コマンドを試し、色々調べたが、あんまりそういう例が出てこないことから、別の方法を探す。
基本的にクソほど調べて、自分が思うような対応方法でカスリもしなかったら、そもそもソリューションの方向性が間違っていることが多い。

# ３次対応
コマンドでCircleCi上のDBイメージにpg_bigmを入れることをベースにしたソリューションを考えていたが、発想の転換して、「もともとpg_bigmが入っているイメージがあったりしないだろうか」と考えた。こういう脳に切り替えた後、情報の見え方が違う。何なら自らイメージを作ってDockerHubにアップする人もおったりする模様。今回自分は「maruta/postgresql-bigm:9.4-bigm1.2」というイメージが自分のプロダクトに完全に一致していたのでこちらを採用。するとうまくいった！！
R に devtools がインストールできなかったので解決してみた。

MacOS に Homebrew を使って R をインストールしました。

```zsh
brew install R
```
その後、R で `devtools` をインストールしようと思ったのですがエラーがでてきました。
```r
install.packages("devtools")
```
```
<stdin>:1:10: fatal error: 'hb-ft.h' file not found
#include <hb-ft.h>
         ^~~~~~~~~
1 error generated.
```

調べてみると、`hb-ft.h`というヘッダーファイルが見つからないことを示しており、
このヘッダーファイルは、HarfBuzzというオープンソースのテキストレイアウトエンジンで使用されるものとのこと。
つまり、このエラーはおそらくHarfBuzzがシステムにインストールされていないか、
インストールされているもののパスが設定されていないようです。
なので、次のコマンドでHarfBuzzがインストールされているか調べてみます。
```zsh
brew list | grep harfbuzz
```
やはりインストールされていないので、次のコマンドでインストールしてみます。
```zsh
brew install harfbuzz
```

そして、再度 `devtools` をインストールしてみます。すると次のエラーがでました。
```
string_bidi.cpp:11:10: fatal error: 'fribidi.h' file not found
#include <fribidi.h>
```
このエラーメッセージも調べてみると、`fribidi.h` というヘッダーファイルが見つからないことを示しており、このヘッダーファイルは、Unicodeテキストの双方向性を解決するためのFreeType Bidiライブラリで使用されるものなようです。

```zsh
brew install fribidi
```
をしてみて再度実行しました。するとエラーが出ず `devtools` がインストールすることができました。
正規表現の入り口

正規表現って難しいでしょ・・・？

と思う方向けに簡単にまとめたものです。

これだけ知っておけば、なんとなく分かったつもりになれると思うので、さらっと目を通してみてください。

[] {} ()の3種類と
\+ \* ? . の記号さえ覚えればなんとかなると思います。


## []
a b c d e f g h i j
という文字列があって、そこに対して正規表現を掛けた場合を例にしてます。

角括弧は、カッコの中に記載した1文字が該当します
・[abcdef] もしくは [a-f]
と記載した場合
**a** **b** **c** **d** **e** **f** g h i j
Boldにしてる箇所が該当します

また、
・[acf]
と記載した場合
**a** b **c** d e **f** g h i j
Boldにしてる箇所が該当します

ちなみに
小文字のアルファベットを引っ掛ける場合は
[a-z]
大文字のアルファベットを引っ掛ける場合は
[A-Z]
小文字大文字のアルファベットを引っ掛ける場合は
[a-zA-Z]
[A-Za-z]
と書きます

## {}
波括弧は直前に記載した文字の繰り返しを表します

例えば、
"CCレモン"という文字列を引っ掛けたいのであれば
C{2}レモン
と記載すればOKです

もし、"CCレモン"以外に、"CCCレモン"や"CCCCレモン"も引っ掛けたい場合は、
"C{2,4}レモン"と記載すればOKです。
このように記載すると、2回以上4回以下の繰り返しを表します。

## ()
丸括弧はカッコの中に書いた文字をまとめて対象にする事ができます

例えば
(キレイ){2}
とすると、
某手洗い石鹸の、"キレイキレイ"を正規表現で表す事ができます

他にも、
(どん){3}の森と書くと
某県にある、"どんどんどんの森"を正規表現で表す事ができます

## + * ? .
あとは、
- \+ -> 1回以上の繰り返し
- \* -> 0回以上の繰り返し
- ? -> 0~1回の繰り返し
- . -> 任意の1文字
を表します。

先程のCCレモンを例にあげると
1. レモン
2. Cレモン
3. CCレモン
4. CCCレモン

があるとすると、
"C+レモン"は、"C"が1回以上出てくる2,3,4を表します
"C*レモン"は、"C"が０回以上出てくる1,2,3,4を表します
"C?レモン"は、"C"が0or１回出てくる1,2,3,4を表します
（正確には、"C?レモン"という正規表現は"レモン"or"Cレモン"を表すため、これらを含む1と2,3,4の"Cレモン"の場所が一致します)

また、
"."は任意の１文字を表すため、".*"と記載すると、
１行全てがひっかかります。


正規表現はvscodeの文字列検索ウィンドウを表示して".*"のマークのボタンを押すと使用できますので、ぜひいろいろやってみてください！
【JavaScript】 オブジェクトが指定されたプロパティを自身のプロパティとして持っているかどうか確認するには？

# オブジェクトが指定されたプロパティを自身のプロパティとして持っているかどうか確認するには？

### こちら、ご参考下さい！

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty

```javascript:index.js
 //構文
 obj.hasOwnProperty(prop)

 //example
 const object1 = {};
 object1.property1 = 42;

 console.log(object1.hasOwnProperty('property1')); // Expected output: true

 console.log(object1.hasOwnProperty('toString')); // Expected output: false

 console.log(object1.hasOwnProperty('hasOwnProperty')); // Expected output: false

```
Debian 11にNode.js 19をインストール

簡単にインストールできます

```bash
curl https://raw.githubusercontent.com/creationix/nvm/master/install.sh | bash
source .bashrc
nvm install node
node --version
```

https://www.vultr.com/docs/how-to-install-node-js--npm-on-debian-11/#Installing_NodeJS_with_NVM
MacでXWindowを動作させる

# どういうことするの
Mac上のC言語でXWindowを操作するので、環境構築をしたい。

# 環境
macOS Catalina 10.15.7 (macOS 13? でも動作確認済み)

# インストール
## brew編
[いつもお世話になっております。](https://brew.sh/)ターミナルで以下を入力する。
```sh
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
```
管理者権限を持っている人のアカウントで入って、パスワード入力してインストールする。

## XQuartz編
ターミナルで以下を入力し、インストールする
```sh
brew install --cask xquartz
```
もしくは[公式ウェブ](https://www.xquartz.org/)からpkgをダウンロードし、インストールする。

## Xlib編
上をインストールしても、以下のようなエラーが出るのでXlibをインストールする。
```
main.c:6:10: fatal error: 'X11/Xlib.h' file not found
#include <X11/Xlib.h> // XWindow
         ^~~~~~~~~~~~
1 error generated.
```

ターミナル上で以下を入力し、インストールする。
```sh
brew install libx11
```

### まだエラーが出る場合
これでもできない場合、パスがあってない可能性がある。ここでどこにあるのか示したいがパスを忘れたので助けてください。(適当すいません)
FlutterのAndroidのアプリ公開に失敗する

## はじめに
・Androidアプリを公開するにあったって、Google Play Consoleからアプリを公開しますが、buildしたファイルをuploadしようとすると、エラーが起こった際のまとめを備忘録として残そうと思います。

## 「広告ID」の警告が出た場合

ref:

https://qiita.com/kokogento/items/eb53b68da8a42e7a4266

https://roguefactory.blog/android/play-console-ad-id-warning/


## 「このファイルは Android 12 以降にはインストールできません」の警告が出た場合

・対処法
android/app/src/main/AndroidManifest.xmlに```android:exported = “true”```を追記する。
```xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.news_api">
   <application
        android:label="news_api"
        android:name="${applicationName}"
        android:icon="@mipmap/ic_launcher">
        <activity
            android:name=".MainActivity"
            android:exported="true"
            android:launchMode="singleTop"
            android:theme="@style/LaunchTheme"
            android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
            android:hardwareAccelerated="true"
            android:windowSoftInputMode="adjustResize"
+           android:exported = “true”>
```

ref:

https://halzoblog.com/error-bug-diary/20220626-2/
【JS】some()とevery()がとても便利だったのでまとめてみた

# はじめに
some()とevery()がとても便利だったのでメモ的にまとめてみました。
もし誰かのお役立てば幸いです。

# some()とevery()
どちらも配列の要素を、指定した条件と比較してtrue　/　falseを返す関数です。
それぞれの違いを、サンプルコードも交えながら解説します。

## some()
some()は配列内に、指定した条件を満たす要素が１つでもあればtrueを返します。

```index.js
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

arr.some(value => value < 5)
// true

arr.some(value => value < 0)
// false
```

## every()
every()は配列内の要素が全て、指定した条件を満たすときにtrueを返します。

```index.js
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

arr.every(value => value > 0)
// true

arr.every(value => value > 5)
// false
```

# 余談

ちなみに、some()と似たようなメソッドにincludes()というメソッドがあるのですが、次のような違いがあります。
includes() : 特定の要素が配列に含まれているか
some() : 配列内の要素の１つ以上が与えられた条件を満たすかどうか

# まとめ
some()は配列内の要素が条件を１つでも満たしていればtrueを返し、
every()は配列内の要素が全て条件を満たしていればtrueを返すメソッドでした。

for文やindexOf()などで冗長なコードを書くのではなく、どちらも便利で直感的なメソッドなので、積極的に使っていきたいですね。
話題のPhysics-informed Neural Networkで圧密沈下予測

## はじめに
　私は力学屋が本業ですが、2年ほど前から仕事で機械学習を触っています。なんとか機械学習を活用したいなと思っているのですが、機械学習は統計ベースのため力学的背景を持っていないという欠点を拭えずにいました。そんな中Physics-informed Neural Network（PINN）という手法を見て「これなら欠点解決じゃん！」とこの手法に飛びつきました。今回は地盤分野の基礎的な解析である一次元圧密沈下解析を（PINN）で解いてみたいと思います。

## 圧密沈下とは
　皆さんの足の下に存在する地盤は土粒子と土粒子の間を埋める水（間隙水）、空気で構成されています。更に土粒子の細かさによって粘性土、砂、礫、岩に分けられます。一方、地盤に荷重がかかると土粒子が密になり、体積が減少します。これが地盤沈下です。一般的に粘性土は透水係数が非常に小さいことから、載荷してから沈下が終了するまでに非常に長い時間がかかります。これを圧縮と区別して圧密と呼びます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691433/6bb6a1eb-ca1f-5fcd-ceb3-9f899a71181d.png)
https://shinsa-hosho.jp/basic-knowledge-of-jiban/mechanism-of-ground-subsidence
　
　地盤上に建物を建てる際にはこの圧密沈下でどの程度沈下が生じるか、いつまで沈下が生じるかが重要な問題となります。これを地盤調査を行いその結果を用いて設計で沈下解析を行います。解析には圧密沈下を表現するモデルが必要となりますが、最も簡単なものにTerzaghiの圧密理論があります。これは荷重を載荷した際に瞬間的に過剰間隙水圧が発生し、それが消散することで沈下が発生するという仮定のもと、過剰間隙水圧の消散時間を計算するものです。実際の設計にも使用されています。
　圧密理論は以下の熱伝導型偏微分方程式で表されます。

```math
\frac{\partial u}{\partial t} = cv\frac{\partial^2 u}{\partial z^2}
```

ここで、u：過剰間隙水圧、t：時間、z：地表面からの距離、cv：定数（圧密係数と呼ぶ）です。

## Physics-informed Neural Networkとは
　PINNは物理法則を活用してデータを用いずにNeural Networkの学習を行うという手法です。これまでNeural Networkで数値解を求めようとすると、データドリブンという手法が主かと思います。これは、別途数値解析で求めた解析解をデータとして入力し、データから入力と出力の関係をNeural Networkで近似するという手法になります。一方、PINNはデータの代わりに支配方程式と境界条件を入力し、それぞれの式が0になるようにNeural Networkで近似するという手法になります。自由落下を例にすると、下図のように初期・境界条件と微分方程式（運動方程式）によるロスを計算し、そのロスを最適化することでNeural Networkの解を算出します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691433/227d720d-f463-2c8c-b796-69cc828d95e6.png)
https://qiita.com/nnnnnnn/items/df62e9fb0ec999df96a2

　データドリブン法はデータの範囲外の精度が保証されない、Neural Networkの解が力学的根拠を持たないという欠点がありますが、PINNは構成式が対応できる範囲であれば力学的根拠のある解を算出できるという利点があります。

## PINNで圧密方程式
　PINNで圧密方程式を求めようとすると以下のようになります。まず、下図のように仮想的な地盤を考えます。上部は排水できますが、下部は岩等の不透水層になっているとします。

![Picture1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691433/9cb77deb-7c27-ab66-fd61-a827f2b22a20.png)

境界条件は上部では過剰間隙水圧が発生しないのでu=0となります。また、不透水層では境界条件は以下のようになります。

```math
\frac{\partial u}{\partial z} = 0
```

最後に初期条件はu（z=H）=p（上載荷重）になります。以上を考慮すると下図のような手法でNeural Networkの解を求めることになります。

![Picture2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691433/e79fbf7f-f0f2-5c64-a541-4af496bd297e.png)

試しに実際に計算した結果を以下に示します。理論解の求め方は土質力学の教科書等を読んでください。計算結果は理論解とほぼ一致しています。PINNが解析手法として有用であることが伺えます。

![Picture3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/691433/c1fc755a-39be-9f18-b1f6-e4bdc9a21ed1.png)

## おわりに
　PINNについての論文をいくつか読んでみましたが、現状では一次元がメインで二・三次元の実用例はほぼないように思います。一次元だけでは数値解析の代わりにはなりえないのでまだまだ研究が必要そうです。
Pulumi(typescript) でセキュリティグループとEC2を作成する

#### VPC一覧表示、Subnet一覧表示、Secuirty Group 作成、EC2作成


```typescript:index.ts
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";


function consoleIds(ids:string[]){
	ids.forEach(id => {
			console.log(` ID: ${id}`);	
		}
	);
}

async function  consoleVpc(vpcid:string){
	const vpc= await aws.ec2.getVpc({id:vpcid});
	console.log(` ID: ${vpc.id}`);
	console.log(` CIDR: ${vpc.cidrBlock}`);
	console.log(` Name: ${vpc.tags.Name}`);
}

async function consoleSubnet(subnetId:string){
	const subnet=await aws.ec2.getSubnet({id:subnetId});

	console.log("Existing Subnet:");
	console.log(` subnetID: ${subnet.id}`);
	console.log(` CIDR: ${subnet.cidrBlock}`);
	console.log(` Name: ${subnet.tags.Name}`);
	console.log(` VPC: ${subnet.vpcId}`);	

	// Get the VPC
	console.log("VPC INFO:");
	const vpc=consoleVpc(subnet.vpcId);
}

function consoleSubnets(ids:string[]){
	ids.forEach(subnetId => {
			//console.log(` ID: ${id}`);
			consoleSubnet(subnetId);
		}
	);
}

function consoleVpcs(ids:string[]){
	ids.forEach(vpcid => {
			//console.log(` ID: ${id}`);
			consoleVpc(vpcid);
		}
	);
}

const getVpcs = async function(){
	const vpcs=await aws.ec2.getVpcs({});
	console.log("Existing VPCs:");
	consoleVpcs(vpcs.ids);
	
	console.log(vpcs.tags);
}

const getSubnets = async function(){
	const subnets=await aws.ec2.getSubnets({});
	console.log("Existing Subnets:");
	consoleSubnets(subnets.ids);
	console.log(subnets.tags);
}

//
// Create a security group
//
const testSecGroup = new aws.ec2.SecurityGroup("testSecGroup", {
    vpcId: "<vpc-id>",
    ingress: [
        {
            protocol: "tcp",
            fromPort: 22,
            toPort: 22,
            cidrBlocks: ["0.0.0.0/0"],
        },
        {
            protocol: "tcp",
            fromPort: 3000,
            toPort: 3000,
            cidrBlocks: ["0.0.0.0/0"],
        },
    ],
	egress: [
		{
			protocol: "-1",
			fromPort: 0,
			toPort: 0,
			cidrBlocks: ["0.0.0.0/0"],	
		}
	],
    tags: {
        Name: "makuhari,test",
    },
});

//
// Create keypair
//
const myKeyPair = new aws.ec2.KeyPair("testkeypair", {
    publicKey: "<public-key>",
});

//
// Create a new EC2 instance
//
const myInstance = new aws.ec2.Instance("test-instance", {
    instanceType: "t2.micro",:
    ami: "ami-078296f82eb463377",
    vpcSecurityGroupIds: [testSecGroup.id],
    subnetId: "<subnetId>",
    keyName: myKeyPair.id,
	associatePublicIpAddress: true,
});

//getVpcs();
//getSubnets();
//myKeyPair();




```
.NET プロジェクトにおけるサテライト アセンブリの生成ディレクトリに出現する条件および解決策

## 出現条件

参照または間接参照されるプログラム アセンブリに`EmbeddedResource`が存在すること。

1. `EmbeddedResource`のリソース形式が`a.json`、`a.zh.json`のようにファイル`名`+`言語識別子`+`拡張子`であること。

2. `WithCulture`が設定されておらず、デフォルトで`true`であること。

3. `NuGet`パッケージを通じて渡されるサテライト アセンブリ。

### 例

- Console1.csproj

```xml
<Project Sdk="Microsoft.NET.Sdk">

	<PropertyGroup>
		<OutputType>Exe</OutputType>
		<TargetFramework>net5.0</TargetFramework>
	</PropertyGroup>

	<ItemGroup>
	  <EmbeddedResource Include="a.json" />
	  <EmbeddedResource Include="a.zh.json" />
	</ItemGroup>

</Project>
```

- プロジェクトのパス構造

```
ConsoleApp1/
    a.json
    a.zh.json
    ConsoleApp1.csproj
```

- 生成されたパス構造

```
net5.0/
    zh/ConsoleApp1.resources.dll
    ConsoleApp1.dll
```


## 解決策1:`EmbeddedResource`で`WithCulture="false"`を設定します

- Console1.csproj (変更後)

```xml
<Project Sdk="Microsoft.NET.Sdk">

	<PropertyGroup>
		<OutputType>Exe</OutputType>
		<TargetFramework>net5.0</TargetFramework>
	</PropertyGroup>

	<ItemGroup>
	  <EmbeddedResource Include="a.json" />
	  <EmbeddedResource Include="a.zh.json" />
	</ItemGroup>

	<ItemGroup>
		<EmbeddedResource Update="**\*" WithCulture="false" />
	</ItemGroup>

</Project>
```

## 解決策2: プロジェクトの参照に対して`ResolveAssemblyReferencesFindRelatedSatellites`を`false`に設定します

- ConsoleApp2.csproj


```xml
<Project Sdk="Microsoft.NET.Sdk">

	<PropertyGroup>
		<OutputType>Exe</OutputType>
		<TargetFramework>net5.0</TargetFramework>
		<ResolveAssemblyReferencesFindRelatedSatellites>false</ResolveAssemblyReferencesFindRelatedSatellites>
	</PropertyGroup>

	<ItemGroup>
		<ProjectReference Include="..\ConsoleApp1\ConsoleApp1.csproj" />
	</ItemGroup>

</Project>
```


## 解決策3:`NuGet`パッケージに対して`SatelliteResourceLanguages`を無効値に設定します

- Console3.csproj

```xml
<Project Sdk="Microsoft.NET.Sdk">

	<PropertyGroup>
		<OutputType>Exe</OutputType>
		<TargetFramework>net5.0</TargetFramework>
		<SatelliteResourceLanguages>_</SatelliteResourceLanguages>
	</PropertyGroup>

	<ItemGroup>
		<PackageReference Include="Microsoft.CodeAnalysis" Version="3.9.0" />
	</ItemGroup>

</Project>
```

## まとめ


今回は、.NETプロジェクトでサテライトアセンブリが生成される条件と解決策について紹介しました。

`EmbeddedResource`を使用するアセンブリを参照または間接的に参照している場合に、サテライトアセンブリが生成されます。生成条件は以下の通りです。

1. `EmbeddedResource`のフォーマットが`a.json`、`a.zh.json`のように、ファイル名に言語識別子が含まれている場合。
2. `WithCulture`が設定されていない場合、デフォルトで`true`となります。
3. `NuGet`パッケージによってサテライトアセンブリが渡された場合。

- 解決策は以下の通りです。

1. `EmbeddedResource`に対して、現在のアセンブリに対して`WithCulture="false"`を設定します。
2. プロジェクト参照の場合は、`ResolveAssemblyReferencesFindRelatedSatellites`を`false`に設定します。
3. `NuGet`パッケージに対しては、`SatelliteResourceLanguages`を無効な値に設定します。

これらの手順を実行することで、不要なサテライトアセンブリの生成を回避することができます。
Vimについて

# 初めに
この記事は**新しいLinuxの教科書**の備忘録です。
メモ程度に記録していきます。
**ここではVimについてまとめます。**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1878034/f5f1a666-83f0-6182-7cec-c5818fa27bdd.png)


# Vimとは
`Vim`はLinuxのテキストエディタのことで、最小限のキー操作で編集作業が行えるので、非常に効率の良いエディタである特徴があります。

`Vim`はほとんどのLinuxディストリビューションで標準でインストールされています。
**※Macにも標準でインストールされています。**

インストールされているかは`vim --version`コマンドで確認することができます。
```
$ vim --version
VIM - Vi IMproved 8.2 (2019 Dec 12, compiled Apr 19 2022 21:42:29)
```

インストールするには`vim`コマンドを各種ディストリビューションのインストールします。
```:CentOS
# yum install vim 
```

```:Ubuntu
$ sudo apt-get install vim
```

# Vimの操作方法
## 起動
`Vim`の起動には`vim`または`vi`コマンドを実行します。`vim`は元々`vi`コマンドの後継として開発されたので`vi`コマンドでも起動できます。

```
$ vim
```

`vim`コマンドの後にファイル名を指定するとそのファイルを編集することができます。この時存在しないファイル名の場合はファイルの新規作成が行われます。
```
$ vim <ファイル名>
```
`vim`では何もない行を`~`で表現します。

## Vimの基本的なコマンド
|コマンド  |内容  |
|:-:|:-:|
|:q  |Vimを終了する  |
|:q!  |ファイルを保存せずにVimを終了する |
|:w  |ファイルを上書き保存する  |
|:w <ファイル名>  |名前をつけてファイルを上書き保存する  |
|i  |カーソル位置の左に文字を追加する  |
|a  |カーソル位置の右側に文字を追加する  |
|x  |カーソル位置の文字を削除する  |
|Escキー  |インサートモードからノーマルモードに移動  |
|w  |次の単語の先頭に移動する |
|b |前の単語の先頭に移動する  |
|W  |スペース区切りで次の単語の先頭に移動する |
|B |スペース区切りで前の単語の先頭に移動する  |
|h  |左に移動する  |
|j  |下に移動する  |
|k  |上に移動する  |
|l  |右に移動する  |
|0  |行の先頭に移動する |
|$ |行の末尾に移動する  |
|gg  |一行目に移動する |
|G |最後の行に移動する  |
|<数字>G |<数字>行目に移動する  |


### 補足
* **先頭に`:`がついていれば`Vim`コマンドで、ついていなければ編集コマンドです。**
* **文字の削除は`x`でもできますが、普通に`Deleteキー`でも削除できます。**
* **カーソル移動はコマンドを使わなくても十字キー（カーソルキー）でも操作できます。**


## カット・コピー・ペースト
普通のエディタ同様`Vim`上でカット・コピー・ペーストが行えます。

カットには`d`を用います。`d`の後に上記の表にあるコマンドを組み合わせることで範囲指定してカットが行えます。
コピーには`y`を用います。範囲指定の方法はカットの時と同様です。
|コマンド  |内容  |
|:-:|:-:|
|d$  |行末までカット  |
|d0  |行頭までカット |
|x,dl |一文字カット  |
|dw  |一単語カット |
|dgg |最初の行までカット  |
|dG |最後の行までカット  |
|dd |カーソルの行をカット |
|yy |カーソルの行をコピー  |

カットした文字を`p`コマンドでペーストすることができます。
`d`を`y`に変えればコピーできます。

**誤ってカットしてしまった場合、`Ctrl+z`のように元に戻すには`u`を押します。**
**`Ctrl+Shift+z`のように元に戻したい場合は`Ctrl+r`を押します。**
Springでポートフォリオを作成する　2-7.機能一覧

# 前回まで
前回は機能一覧を作成しました。

https://qiita.com/Jackoguro/items/89be9512f984fa8d2d3c

第2-7弾の今回は機能一覧の中から「設定」の詳細をまとめていきます。

# 参考資料
参考にした資料を載せておきます。
今回の機能一覧はUdemyの以下のコースを受講した際の資料を参考に書いてみました。

https://www.udemy.com/course/digisaku_requirements_definition_and_system_design/

また、今回は参考にしたアプリがあるので載せておきます

https://play.google.com/store/apps/details?id=com.habitrpg.android.habitica&hl=ja&gl=US

https://www.studyplus.jp/

# 機能一覧
今回作成するWebアプリの機能一覧は大きく分けると以下になります。
- [ ] 全体共通
- [ ] クエスト
- [ ] ステータス
- [ ] レポート
- [ ] 所持品
- [ ] ショップ
- [ ] パーティー
- [ ] 設定 

今回は「設定」に関して機能を決定していきます。

# 機能決定の流れ
今回は以下のようにして機能を決定していきました。
1. 検討する項目を挙げる
2. 検討する項目ごとに要求内容を挙げる(要求フェーズ)
2. 挙げられた要求内容が実現可能か検討する(検討フェーズ)
2. 実際に実装する内容を決定する(要件フェーズ)

また、今回は個人開発であるため、本来であればクライアントから挙げられる要求も、エンジニアが行う検討も1人で行っています。
そのため、実際の開発とはあまり近くないかもしれないですが、その点ご了承ください

## 検討する項目を挙げる
全体共通において検討すべき項目は5つあります。

1. アカウント設定

## 要求フェーズ
「検討する項目を挙げる」で挙げられた項目について要求内容を作成します。

### 1. アカウント設定

#### 1. プレイヤー名、ユーザーID、パスワードの変更ができる

#### 2. アカウントの削除ができる

## 検討フェーズ
要求フェーズで挙げられた内容を検討します。

### 1. アカウント設定

#### 1. プレイヤー名、ユーザーID、パスワードの変更ができる
OK

#### 2. アカウントの削除ができる
誤操作をしても大丈夫な対策はあるのか？


## 要件フェーズ
検討フェーズで挙げられた内容を踏まえて最終決定します。

### 1. アカウント設定

#### 1. プレイヤー名、ユーザーID、パスワードの変更ができる
OK

#### 2. アカウントの削除ができる
アカウント削除する際は確認メッセージを表示する

# 最後に
設定の機能一覧は以上になります。
以上で現段階での機能一覧の洗い出しは終了です。
Springでポートフォリオを作成する　2-6.機能一覧

# 前回まで
前回は機能一覧を作成しました。

https://qiita.com/Jackoguro/items/89be9512f984fa8d2d3c

第2-6弾の今回は機能一覧の中から「ショップ」の詳細をまとめていきます。

# 参考資料
参考にした資料を載せておきます。
今回の機能一覧はUdemyの以下のコースを受講した際の資料を参考に書いてみました。

https://www.udemy.com/course/digisaku_requirements_definition_and_system_design/

また、今回は参考にしたアプリがあるので載せておきます

https://play.google.com/store/apps/details?id=com.habitrpg.android.habitica&hl=ja&gl=US

https://www.studyplus.jp/

# 機能一覧
今回作成するWebアプリの機能一覧は大きく分けると以下になります。
- [ ] 全体共通
- [ ] クエスト
- [ ] ステータス
- [ ] レポート
- [ ] 所持品
- [ ] ショップ
- [ ] パーティー
- [ ] 設定 

今回は「ショップ」に関して機能を決定していきます。

# 機能決定の流れ
今回は以下のようにして機能を決定していきました。
1. 検討する項目を挙げる
2. 検討する項目ごとに要求内容を挙げる(要求フェーズ)
2. 挙げられた要求内容が実現可能か検討する(検討フェーズ)
2. 実際に実装する内容を決定する(要件フェーズ)

また、今回は個人開発であるため、本来であればクライアントから挙げられる要求も、エンジニアが行う検討も1人で行っています。
そのため、実際の開発とはあまり近くないかもしれないですが、その点ご了承ください

## 検討する項目を挙げる
全体共通において検討すべき項目は5つあります。

1. 装備屋
2. 道具屋 

## 要求フェーズ
「検討する項目を挙げる」で挙げられた項目について要求内容を作成します。

### 1. 装備屋

#### 1. 職業別に表示する装備を変更する
職業別に表示する装備を変更する

#### 2. レア度を分けて表示する
レジェンド、エピック、レア、アンコモン、コモン

#### 3. 所持金が足りない装備は色を薄くする

#### 4. ホバーしている装備の詳細を表示することができる
・装備名
・画像
・レア度
・装備詳細
・金額

#### 5. 検索機能
・検索ボックス
・ソート(レア度、名前の順、金額)
・フィルター(レア度、装備箇所、所持金で買える装備)

### 2. 道具屋 

#### 1. カテゴリー別に表示するアイテムを変更する

#### 2. レア度を分けて表示する
レジェンド、エピック、レア、アンコモン、コモン

#### 3. 所持金が足りないアイテムは色を薄くする

#### 4. ホバーしているアイテムの詳細を表示することができる
・アイテム名
・画像
・レア度
・アイテム詳細
・金額

#### 5. 検索機能
・検索ボックス
・ソート(レア度、名前の順、金額)
・フィルター(レア度、所持金で買える装備)

## 検討フェーズ
要求フェーズで挙げられた内容を検討します。

### 1. 装備屋

#### 1. 職業別に表示する装備を変更する
OK

#### 2. レア度を分けて表示する
OK

#### 3. 所持金が足りない装備は色を薄くする
OK

#### 4. ホバーしている装備の詳細を表示することができる
装備詳細には何を表示するのか？

#### 5. 検索機能
・検索は完全一致と部分一致のどちらを採用するのか？
・検索は装備名で行うのか？
・ソートはデフォルトでは何でしているのか？
・ソートは複数掛け合わせることができるのか？
・ソートの各並べ替え順は？
・フィルターとソートは併用することができるのか？

### 2. 道具屋 

#### 1. カテゴリー別に表示するアイテムを変更する
OK

#### 2. レア度を分けて表示する
OK

#### 3. 所持金が足りないアイテムは色を薄くする
OK

#### 4. ホバーしているアイテムの詳細を表示することができる
アイテム詳細には何を表示するのか

#### 5. 検索機能
・検索は完全一致と部分一致のどちらを採用するのか？
・検索はアイテム名で行うのか？
・ソートはデフォルトでは何でしているのか？
・ソートは複数掛け合わせることができるのか？
・ソートの各並べ替え順は？
・フィルターとソートは併用することができるのか？"

## 要件フェーズ
検討フェーズで挙げられた内容を踏まえて最終決定します。

### 1. 装備屋

#### 1. 職業別に表示する装備を変更する
初期段階ではそれぞれの職業に最低3セットずつ装備を用意する

#### 2. レア度を分けて表示する
OK

#### 3. 所持金が足りない装備は色を薄くする
OK

#### 4. ホバーしている装備の詳細を表示することができる
・現在の装備とのステータスの変化を表示する
・所持金が足りない場合、その旨のメッセージを表示

#### 5. 検索機能
・検索ボックスは部分一致、アイテム名と部分一致する装備品を表示する
・デフォルトでは取得日でソートしておく。
・ソートは単体のみで使用可能
・レア度は高い方から順にソート
・名前の順はA～Z順にソート
・金額は高いもの順にソート
・フィルターはソートとの併用可能

### 2. 道具屋 

#### 1. カテゴリー別に表示するアイテムを変更する
OK

#### 2. レア度を分けて表示する
OK

#### 3. 所持金が足りないアイテムは色を薄くする
OK

#### 4. ホバーしているアイテムの詳細を表示することができる
・現在のアイテムの所持数を表示する
・所持金が足りない場合、その旨のメッセージを表示

#### 5. 検索機能
・検索ボックスは部分一致、アイテム名と部分一致するアイテムを表示する
・デフォルトでは取得日でソートしておく。
・ソートは単体のみで使用可能
・レア度は高い方から順にソート
・名前の順はA～Z順にソート
・金額は高いもの順にソート
・フィルターはソートとの併用可能

# 最後に
ショップの機能一覧は以上になります。
次回は設定の機能一覧になります。
DDD初心者でも仲良くなりたい ~値オブジェクト編~

## はじめに
- 値オブジェクトとはドメインオブジェクトの基本
- 概念自体はシンプルで、システムに登場する金銭や単価といった値をオブジェクトとして定義するもの


## PHP（Laravelで書いてみる）
ユーザーを登録する処理で、値オブジェクトを使わない場合と使った場合で比較してみます。

### 値オブジェクトを使わない場合の処理
```UserRepository.php
class UserRepository extends BaseRepository
{
    private crateUser (string $userId, string $name) 
    {
        // 新規ユーザー作成をする処理
    }
}
```
```UserLogic.php
class UserLogic {
    private $userRepository;

    public function __construct(UserRepository $userRepository)
    {
        $this->userRepository = $userRepository;
    }
    
    private function createUser()
    {
        $userId = 'komeda_tarou';
        $name = 'コメダ太郎';
        
        $this->userRepository->createUser($userId, $name);
    };
}
```
ユーザー追加のための何気ない処理を書いています。ここでいくつか気になる点をあげるとすると、createUserメソッドに渡す引数の`$name`と`$userId`の順番を間違えてしまう可能性があります。今回の場合順番を間違えたとしてもどちらも文字列のため保存されてしまいます。

また、userIdの型は今回はstring型を渡す必要がありますが、string型かint型かどうかはロジッククラスからは分かりません。これらを値オブジェクトを使って解決してみます。

### 値オブジェクトを使う場合の処理
まず、値オブジェクトクラスを作成します。
```値オブジェクトクラス.php
class UserId
{
    private $value;
    
    public function __construct(string $value)
    {
        $this->value = $value;
    }
    
    public function getValue(): string
    {
        return $this->value;
    }
}

class Name
{
    private $value;

    public function __construct(string $value)
    {
        $this->value = $value;
    }

    public function getValue(): string
    {
        return $this->value;
    }
}
```

上記で作成した値オブジェクトを引数として使うことによって、値を入れ間違う危険が減ります。値オブジェクトを使うように修正してみます。
```UserRepository.php
class UserRepository extends BaseRepository
{
    private crateUser (UserId $userId, Name $name) 
    {
        // 新規ユーザー作成をする処理
    }
}
```
```UserLogic.php
class UserLogic {

    private function createUser()
    {
        $userId = new UserId('komeda_tarou');
        $name = new Name('コメダ太郎');
        
        $this->userRepository->createUser($userId, $name);
    };
}
```
もし`$userId`と`$name`に不正な値が入らないように制限をかけたい場合、値オブジェクトクラスの中で、制限をかけることができます。今回はコンストラクタ内に、許可しない値が渡された場合はExceptionを投げるようにしてみます。

### 値オブジェクトの中で、不正な値が入らないように配慮
- 制限①： $userIdは`_`を含まなければならない
- 制限②： $nameは10文字以下でなければならない

```値オブジェクトクラス.php
class UserId
{
    private $value;
    
    public function __construct(string $value)
    {
        // 制限①：　$userIdは`_`を含まなければならない
        if (false === strpos($value, '_')) {
            throw new Exception();
        }
        $this->value = $value;
    }
}

class Name
{
    private $value;

    public function __construct(string $value)
    {
        // 制限② $nameは10文字以下
        if (mb_strlen($value) <= 10) {
            throw new Exception();
        }
        $this->value = $value;
    }
}
```
それぞれの制限に対して違反する値が渡されたときは、Exceptionを返すようになりました！
## 最後に
値オブジェクトは「ルールを定義して、そのルールに反する操作を許容しない」ということをクラスとして定義している。
zodのemail()は日本語が入力できるよ

:::note info
こちらの記事で説明した「`zod`の`email()`で日本語が含まれる場合もバリデーションエラーとならない」はバージョン`3.22.0`以降でエラーとなるように変更されました。

```ts
const schema = z.string().email();
console.log(schema.parse("あいうえお@example.com"));

// ~ 3.21.4
// あいうえお@example.comと出力される

// 3.22.0 ~
/*
ZodError: [
  {
    "validation": "email",
    "code": "invalid_string",
    "message": "Invalid email",
    "path": []
  }
]
*/
```

そのため、以降の本文は`zod`のバージョンが`3.21.4`までの場合に当てはまることをご留意ください。
:::


[zod](https://zod.dev/)の小ネタです。

タイトルで全部言っちゃっているんですけどね:neutral_face:
ここで言う日本語とはひらがな、カタカナ、漢字を指しています。

今回利用しているバージョンは以下です。

```json
"zod": "^3.20.6"
```

## zodのemail()を検証する

ではどういった場合に`email()`でエラーとなるのか検証します。

以下`test@example.com`という値はメールアドレスとして適切と判定されました。

```ts
const schema = z.string().email();
console.log(schema.parse("test@example.com")); // test@example.comと出力
```
---
`test`という値はメールアドレスとして不適切と判定されました。
これはメールアドレスとして用いる値ではないので想定通りです。

```ts
const schema = z.string().email();
console.log(schema.parse("test")); // errorがthrowされる

/*
Error: [
{
"validation": "email",
"code": "invalid_string",
"message": "Invalid email",
"path": []
}
]
*/
```
---

日本語入力した場合でも弾いてくれるのかどうか確認します（なおタイトルでお察し）。
`あいうえお@example.com`という値はメールアドレスとして適切と判定され...るんかい！

```ts
const schema = z.string().email();
console.log(schema.parse("あいうえお@example.com")); // あいうえお@example.comと出力
```

これは想定外だなと思いつつも、[Laravelの`email`バリデーションも場合によっては日本語入力できた](https://qiita.com/zako1560/items/a463fab7b698e09eb5a0 "Laravelのemailバリデーション")な...ということを思い出しました:rolling_eyes:

## zodのemailバリデーションルールを確認してみる
zodのemailバリデーションルールを確認します。

ソースコードを見るとメールアドレスバリデーションは正規表現を用いているようです。また、その正規表現はいくらか変遷があったようですが、現行は以下のようです。

https://github.com/colinhacks/zod/blob/e6939195fbb5191402ba3d6f5b7aade463de6e51/src/types.ts#L526

```ts
const emailRegex = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|([^-]([a-zA-Z0-9-]*\.)+[a-zA-Z]{2,}))$/;
```

たしかに **@以降**は入力可能なものを`半角英数字`や`.`に限定していることが見てとれますが、 **@以前**は入力してはいけない記号類と入力していはいけないパターンが指定されているだけのようです。

メールアドレスのバリデーションを正規表現だけで完璧にやるのは難しいので、zodでは最低限`x@x.xx`の形式であることを担保しているのかな、という推測をしています。

とは言え、メールアドレス（@以前）にも日本語の入力は許可せず、半角英数字記号のみを許可したいです。どうすればよいでしょうか？

## email()に正規表現を組み合わせて半角英数字記号のみ許可する

自分は`Unicode`の正規表現[^1]を用いて、半角英数字、ならびに主要な（よく使う）記号類のみを許可するようにしています。

```ts
const pattern = /^[\u0021-\u007e]+$/u; // 半角英数字記号のみ
const schema = z.string().email().regex(pattern); // 上記正規表現をルールに追加
console.log(schema.parse('あいうえお@example.com'));

/*
Error: [
{
"validation": "regex",
"code": "invalid_string",
"message": "Invalid",
"path": []
}
]

*/
```

エラーの`validation`を見ると、`あいうえお@example.com`は`regex`のルールに抵触してくれたようです:grinning:

入力したものが`x@x.xx`の形式であることは`.email()`の方で担保してくれるため、`.regex()`の方では入力値が半角英数字記号であるかどうかをチェックするだけで良さそうです（ありがたい）。

バリデーションルールを提供してくれるライブラリやフレームワークにはメールアドレスのバリデーションで日本語が入力できてしまう場合もあるので、気をつけねばという話でした。

[^1]:この`Unicode`の範囲にどういったものが含まれるのかは以下サイトを参照しました。
https://tools.m-bsys.com/ex/unicode_table.php
Chrome DevToolsって2色あんねん

LightとDarkの2色あんねん

⚙押すねん
![Screenshot from 2023-02-26 18-31-04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435735/bdcf1d02-6b6a-1d5c-7386-2367c1a43ac3.png)

Darkにすんねん
![Screenshot from 2023-02-26 18-31-19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435735/85303a76-a313-3c8f-a39b-bad5226dd2e1.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435735/b80f1913-47b6-4689-c296-87dc8cd9d582.png)

ダークテーマって300色あんねん
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/435735/2848cdc8-0487-03d9-a343-95c1a15fac54.png)
個人開発のリスクとリターン

「個人開発したい」
と思って、プログラミングの世界に入ってきた人は少なくないです。
かくいう、私も若干そうです。

年々アプリ（スマホもWebも）のクオリティが上がっており、個人開発では厳しい社会が広がってきています。
そこで個人開発のリスクとリターンについて考えてみました。
これから個人開発を始めようと思っている人のためになりますように。

## 個人開発のリスクとリターン
個人開発の一番の醍醐味は、自分がアプリの開発者だと言えることでしょう。
また、「アプリで稼ぎたい！」ということも実現できます。
実際、個人でゲームアプリを作成して、1ヶ月で数千万円稼いでいる人もいるとかいないとか。

そんな夢が沢山詰まっている個人開発ですが、当然リスクもあります。
（どんな開発でもリスクは付きものですが）

### 個人開発は、自分一人で全ての調査・開発を行う必要がある
開発が好きな人なら全く気にならないと思いますが、すべての調査と開発をする必要があります。
技術的に厳しいことや、その後の運用や改修を考えた時に、すべてを自分一人で行います。

スキルがあるなら問題は少ないですが、スキルがない状態の時にはなかなかにハードルが高いです。
開発の段取りを間違えると、時間も膨張しますしね。

今回は調査と開発と書いていますが、営業活動も自分でやる必要があります。
「Twitterでバズったらいいんですよ！」
と思っているかもしれないですが、個人開発のアプリを多くのユーザーに届けるにはかなりの努力が必要ですよ。

### 長期的な運用でやる場合に他の人に任せられない
アプリが当たり、多くのユーザーに使われるようになりました。
続いて、2つ目以降のアプリの開発をしていきます。
しかし、2つ目も3つ目も自分が開発・運用をしていく。
そうなると、徐々に運用に時間を割くことが増えて、開発に使える時間が減っていきます。

つまるところ、チーム開発のように他の人に仕事を教えて長期的な運用を任せる、そして自分は他の開発を始める。
ということができなくなります。

自分だけが直すから、作業自体は簡単だったり手取り早かったりする可能性はありますが、アプリの数を増やしたり、規模の大きなアプリは開発できません。
アプリはどこまで行っても、運用と改修を繰り返すので、作成したあとのことも考えて作ると二度手間がなくて良いですね。

### さいごに
個人開発のリスクとリターンについてでした。
個人でやると自由ですが、猫の手も借りたいほど手が足りない状況になることがありますね。

個人開発は夢がありますが、このあたりの課題を含んでいるので、そこも見越して開発進めていきたいですね。
いつの間にか、バーコードスキャンするflutter_barcode_scannerが使えなくなっていたので、barcode_scan2を使う

## はじめに
・今回の記事は、タイトルのまんまだが、バーコードスキャンに関係するパッケージのflutter_barcode_scannerが使えなくなっていたので、代替パッケージのbarcode_scan2をアプリに組み込んだという話だ。
・今から1年以上前、私がフリーターの時に作ったアプリをリリース出来ずにいた。そのアプリを手直しして公開に踏み切りました。アプリ公開する際にビルドに失敗するので、調べてみたらflutter_barcode_scannerは使用できなくなっていました😭

## アプリ概要
・Google Books APIを使用した、本の検索ができるアプリケーションです。

・app

https://play.google.com/store/apps/details?id=com.cygnu.scan_books

・code

https://github.com/cygnu/scan_books

## パッケージ
・barcode_scan2: ^4.2.3
・freezed: ^0.14.2
・flutter_riverpod: ^0.14.0+1
・http: ^0.13.3
・state_notifier: ^0.7.0
・webview_flutter: ^4.0.2

## コード

・flutter_barcode_scannerを使用したコード

```dart
Future<String> scanBarcode() async {
  String barcodeScanRes;

  try {
    barcodeScanRes = await FlutterBarcodeScanner.scanBarcode(
        '#ff6666', 'Cancel', true, ScanMode.BARCODE);
  } on PlatformException {
    barcodeScanRes = 'Failed to get platform version.';
  }

  if (!mounted) return '';

  return barcodeScanRes;
}
```

・barcode_scan2を使用したコード

```dart
Future<String> scanBarcode() async {
  ScanResult scanResult;

  try {
    scanResult = (await BarcodeScanner.scan()) as ScanResult;
  } on PlatformException {
    scanResult = ScanResult(
      type: ResultType.Error,
      format: BarcodeFormat.unknown,
    );
  }

  return scanResult.rawContent;
}
```

あまり変わらないので、学習コストは低かった。よかった😊

## 参考文献
https://pub.dev/packages/barcode_scan2

https://qiita.com/Limitex/items/58f15911ed645f40522a
Springでポートフォリオを作成する　2-4.機能一覧

# 前回まで
前回は機能一覧を作成しました。

https://qiita.com/Jackoguro/items/89be9512f984fa8d2d3c

第2-4弾の今回は機能一覧の中から「レポート」の詳細をまとめていきます。

# 参考資料
参考にした資料を載せておきます。
今回の機能一覧はUdemyの以下のコースを受講した際の資料を参考に書いてみました。

https://www.udemy.com/course/digisaku_requirements_definition_and_system_design/

また、今回は参考にしたアプリがあるので載せておきます

https://play.google.com/store/apps/details?id=com.habitrpg.android.habitica&hl=ja&gl=US

https://www.studyplus.jp/

# 機能一覧
今回作成するWebアプリの機能一覧は大きく分けると以下になります。
- [ ] 全体共通
- [ ] クエスト
- [ ] ステータス
- [ ] レポート
- [ ] 所持品
- [ ] ショップ
- [ ] パーティー
- [ ] 設定 

今回は「レポート」に関して機能を決定していきます。

# 機能決定の流れ
今回は以下のようにして機能を決定していきました。
1. 検討する項目を挙げる
2. 検討する項目ごとに要求内容を挙げる(要求フェーズ)
2. 挙げられた要求内容が実現可能か検討する(検討フェーズ)
2. 実際に実装する内容を決定する(要件フェーズ)

また、今回は個人開発であるため、本来であればクライアントから挙げられる要求も、エンジニアが行う検討も1人で行っています。
そのため、実際の開発とはあまり近くないかもしれないですが、その点ご了承ください

## 検討する項目を挙げる
全体共通において検討すべき項目は5つあります。

1. 学習概要
2. 学習時間
3. 時間配分

## 要求フェーズ
「検討する項目を挙げる」で挙げられた項目について要求内容を作成します。

### 1. 学習概要

#### 1. 今日、今週、今月、総計の学習時間を表示する

### 2. 学習時間

#### 1. 個別の学習時間と棒グラフを表示する
・日、週、月に分けて表示することができる

### 3. 時間配分

#### 1. 個別の時間配分と円グラフを表示する
・日、週、月に分けて表示することができる

## 検討フェーズ
要求フェーズで挙げられた内容を検討します。

### 1. 学習概要

#### 1. 今日、今週、今月、総計の学習時間を表示する
学習時間は時間(h)単位で表示するのか？

### 2. 学習時間

#### 1. 個別の学習時間と棒グラフを表示す
学習時間が0時間の場合は？

### 3. 時間配分

#### 1. 個別の時間配分と円グラフを表示する
・表示する順番は？
・学習時間が0時間の場合は？

## 要件フェーズ
検討フェーズで挙げられた内容を踏まえて最終決定します。

### 1. 学習概要

#### 1. 今日、今週、今月、総計の学習時間を表示する
グラフは表示せず、メッセージを表示する

### 2. 学習時間

#### 1. 個別の学習時間と棒グラフを表示す
・登録された順から表示する
・グラフは表示せず、メッセージを表示する

### 3. 時間配分

#### 1. 個別の時間配分と円グラフを表示する
・値段はレア度により変更する
・初期段階では所持品を売る機能は実装しない

# 最後に
レポートの機能一覧は以上になります。
次回は所持品の機能一覧になります。
paizaラーニング レベルアップ問題集 新・Bランクレベルアップメニュー JavaScript 【配列 1】平面で計算

【配列 1】平面で計算 (paizaランク C 相当)

https://paiza.jp/works/mondai/b_rank_new_level_up_problems/b_rank_new_level_up_problems__calculate_in_two_dimensions

# 解答例(C++の場合参考)
縦横斜めそれぞれ和を求め、最大値比較する。
```javascript
const fs = require("fs");
const input = fs.readFileSync("/dev/stdin", "utf-8").trim();
const lines = input.split("\n");

const N = Number(lines[0]);
const A = lines.slice(1).map(line => line.split(" ").map(Number));

let ans = 0;
//縦横
for (let i = 0; i < N; i++) {
  let row_sum = 0;//横行
  let col_sum = 0;//縦列
  for (let j = 0; j < N; j++) {
    row_sum += A[i][j];
    col_sum += A[j][i];
  }
  ans = Math.max(row_sum, col_sum, ans);
}
  
//斜め
let left_right_down = 0;//右下へ
let left_right_up = 0;//右上へ

for (let i = 0; i < N; i++) {
  left_right_down += A[i][i];
  left_right_up += A[N - 1 - i][i];
}
ans = Math.max(left_right_down, left_right_up, ans);

console.log(ans);
```

# 応用例
全ての斜めの和についても実装してみた。
```javascript
const fs = require("fs");
const input = fs.readFileSync("/dev/stdin", "utf-8").trim();
const lines = input.split("\n");

const N = Number(lines[0]);
const A = lines.slice(1).map(line => line.split(" ").map(Number));

let max = 0;
//縦列
for (let j = 0; j < N; j++) { //列固定
  let sum = 0;
  for (let i = 0; i < N; i++) { //行、縦に足してく
    sum += A[i][j];
  }
  max = Math.max(max, sum);
}

//横列
max = A.reduce((acc, row) => Math.max(acc, row.reduce((a, b) => a + b)), max);

//斜め列
//右上に
//スタート地点、左上隅から左下へ
for (i = 0; i < N; i++) {
  //右上に足してく
  let sum = 0;
  for (let a = 0; a <= i; a++) { //右上へ
    sum += A[i - a][a];
  }
  max = Math.max(max, sum);
}

//スタート地点、左下から右下へ
for (let j = 1; j < N; j++) {
  //右上に足してく
  let sum = 0;
  for (let a = 0; a < N - j; a++) { //右上へ
    sum += A[N - 1 - a][j + a];
  }
  max = Math.max(max, sum);
}

//右下に
//スタート地点、左上から右上へ
for (j = 0; j < N; j++) {
  //右下に足してく
  let sum = 0;
  for (let a = 0; a < N - j; a++) { //右下へ
    sum += A[a][j + a];
  }
  max = Math.max(max, sum);
}

//スタート地点、左上から左下へ
for (i = 1; i < N; i++) {
  //右下に足してく
  let sum = 0;
  for (let a = 0; a < N - i; a++) { //右下へ
    sum += A[i + a][a];
  }
  max = Math.max(max, sum);
}
console.log(max);
```
【Nuxt.js】axios-moduleでエラーハンドリングを共通化する

# 概要
`axios-module(@nuxtjs/axios)`を使用。

axiosで非同期通信後のエラーハンドリングを共通化したかった。
ここでは[Interceptors](https://axios.nuxtjs.org/helpers/#interceptors)というものを使っていきます。

# 手順
### 1.pluginsディレクトリにエラーハンドリング用のファイルを作成
今回はわかりやすく`axios.js`としますが、特になんでも大丈夫です。
```axios.js
export default function ({ store, $axios, redirect }) {
  $axios.onError((error) => {
    // ここに処理を書いていく
    if (error.response.status === 400) {
      alert('Bad Responseです。');
    }
  });
}
```

### 2.nuxt.config.jsに追加したプラグインを設定する
`plugins`に以下の通り、追加します。
ここに追加することでレスポンスが400で返ってくるとアラート画面が表示されるようになります。

```nuxt.config.js
plugins: ['~/plugins/axios.js'],
```

# 参考
https://axios.nuxtjs.org/helpers/