OmniAICreator/Qiita-1.07M huggingface dataset:
Salesforceの本番環境のApex,TriggerをSFDXコマンドで削除する。

# やりたいこと
Saleforceの本番環境から使わなくなったApex ClassやTriggerをSFDXコマンドで削除したい。

# sfdx force:source:deployコマンドで削除する場合
### 準備
対象Apex Class、Apex Trigger のmeta-xmlファイルのstatusを `Deleted` へ変更して保存する。

### コマンド
```
sfdx force:source:deploy -p "force-app/main/default/classes/hogehoge.cls" -l RunLocalTests -u ユーザーID
```

オプションの説明
- p | --sourcepath SOURCEPATH
- u | targetUserName
- l | テストレベル指定オプション

### 説明
- 対象Class,Triggerはカンマで複数指定可能
- 本番でのdeployなのでテスト実施必須。オプションでテストレベル指定する。（-l RunLocalTests）

コマンド詳細
[Salesforce CLI Command Reference](https://developer.salesforce.com/docs/atlas.en-us.224.0.sfdx_cli_reference.meta/sfdx_cli_reference/cli_reference_force_source.htm)

# force:mdapi:deployコマンドで削除する場合(公式で調べた内容)
以下の公式を参考にして実施
[組織からのコンポーネントの削除](https://developer.salesforce.com/docs/atlas.ja-jp.224.0.api_meta.meta/api_meta/meta_deploy_deleting_files.htm)
### 手順
1. 任意の場所にpackage.xml と destructiveChanges.xml の 2 ファイルを作成する。
2. 上記 2 ファイルを zip ファイルに固める。
3. sfdx force:mdapi:deploy を実行する。

# あとがき
ClassやTrigger単体を削除するなら sfdx force:source:deploy で削除するほうがラクです。
force:mdapi:deployでの削除は、他のリソースもまとめて削除したい時に使うといいのかもしれません。

本番環境にある不要なApexを削除するのに調べた内容まとめました。
いわずもがなですが、本番環境のリソースを削除する際はくれぐれも注意して実施しましょう。
【Node.js】環境構築　for Mac Catalina

勉強と忘れないようメモ:writing_hand:

#Node.jsとは？
サーバーサイドで動くJAVASCRIPTのこと

#Node.jsを学ぶメリット
**１．JACVASCRIPTだけでWEBサイトが作れる（フロント、サーバー両方）**
　　　
**２．フロンエンドの開発環境でも使われる**
フロントエンドでも以下作業自動化のために使われるので覚えて損はないのではなかろうか

* バリデーション（エラーのチェック）
* 画像やCSS、JSファイルへの圧縮
* テンプレートエンジン
* Saas -> CSSへのコンパイル
* ローカルサーバー環境
* ,,etc

#環境構築方法
**１．  公式のNODE.jsのサイトからZIPファイルを落としてくる**
これはおすすめできないらしい。
NODE.jsのバーションがたくさんあり、作業中に頻繁にバーションを変える。
なので、バーションを変える際にZIPファイルを毎回落としてくる手間が発生し大変になるとのこと

**２．  nodebrew（NODE.jsのバーション管理するツール
）を使う**
こちらで実装（今回はhomebrewを使わない）

#環境構築手順
>[参考　GITHUB　nodebrew](https://github.com/hokaccha/nodebrew)

**１．nodebrewインストール　**
以下をターミナルで打鍵

```text:ターミナル
$ curl -L git.io/nodebrew | perl - setup
```
`HTTPリクエストを通してサーバーにアクセスしてダウンロード/送るコマンド`

セットアップログ終了後以下を打鍵

```text:ターミナル
export PATH=$HOME/.nodebrew/current/bin:$PATH
nodebrew -v
```
`exportでnodebrewのパスを通している`
`nodebrew -vでバージョンが表示されていれば成功`

**2．nodebrewでNode.jsをインストール**

```text:ターミナル
nodebrew install-binary <version>
↓バーション入力例↓ 
nodebrew install-binary latest
nodebrew install-binary stable
nodebrew install-binary v8.9.1
```
`latest は最新版`
`stable　は安定版で最新版`

```text:ターミナル
nodebrew　ls　でインストールしたNode.jsを確認
```

作業するNode.jsを選択

```text:ターミナル
nodebrew　use v8.9.1
```


**３.ターミナルを閉じてもパスを通す方法**

上記で設定した方法だと、ターミナルを閉じたらパスが通らなくなるので、ターミナルを閉じてもパスを通す
以下シェルスクリプト実行

```text:ターミナル
touch .zshrc
vi .zshrc
i を打鍵
export PATH=$HOME/.nodebrew/current/bin:$PATH
を貼り付け
esc を打鍵
:wq を打鍵
```

ターミナルの環境設定を開き、シェルタブ内のコマンドを実行にチェック
pip20.3でプライベートリポジトリにあるパッケージのインストールに失敗した

### 経緯

業務ではGitLab上にPython用パッケージを作成し、pipenvでインストールして使用しています。
ところが2020/12初めにごろに`pipenv install`がエラーとなりました。

```
[pipenv.exceptions.InstallError]: WARNING: Generating metadata for package mypkg01-1-0-0 produced metadata for project name mypkg01. Fix your #egg=mypkg01-1-0-0 fragments.
[pipenv.exceptions.InstallError]: ERROR: Requested mypkg01 from git+https://github.com/hoge/mypkg01.git@****#egg=mypkg01-1-0-0 (from -r /tmp/pipenv-3IcLPF-requirements/pipenv-qe3mt8-requirement.txt (line 1)) has different name in metadata: 'mypkg01'
ERROR: Couldn't install package: mypkg01-1-0-0
```

調査したところpip20.3がリリースされた影響で、pipを20.2.4にダウングレードするか、pipの`--use-deprecated=legacy-resolver`オプションを使用することで回避できるようです。
ただ、pip21ではオプションすらなくなるそうなので原因を解消すべく調査を続けました。
※`pipenv run pip install pip==20.2.4`で`pipenv install`にて使用するpipをダウングレードすることができます。

### 原因と解決方法

原因は**依存関係の書式**でした。
`mypkg02`パッケージをインストールする際に、依存している`mypkg01`をインストールしようとして`mypkg01-1-0-0`という名前のパッケージを探してしまっていました。
なお、インストールしようとしていたパッケージの依存関係の定義は以下のように記述していました。

```
[metadata]
name = mypkg02
version = file:mypkg02/VERSION

[options]
zip_safe = False
packages = find:
python_requires = >=3.0
install_requires =
    mypkg01 @ git+https://github.com/hoge/mypkg01.git#egg=mypkg01-1.0.0
```

これを下記のように書き換えることで解決しました。

```diff
-    mypkg01 @ git+https://github.com/hoge/mypkg01.git#egg=mypkg01-1.0.0
+    mypkg01 @ git+https://github.com/hoge/mypkg01.git@1.0.0#egg=mypkg01
```

pip20.3では修正前の書式が使用できないようです。
pip20.3のCHANGELOGには上記の変更については記述されていませんでしたが、依存関係の解決方法を変更したとの記述がありますので、その影響だと推測されます。（コードは追ってません。）
【Java】標準入力を取得・出力する方法

#プログラミング勉強日記
2020年12月21日
Cでは標準入力を使ったことがあるが、Javaで標準入力を使ったことがなかった。その今日勉強した内容をまとめる。

#標準入力・標準出力とは
　簡単に言うとキーボードからの入力のことを標準入力という。JavaではSysytemクラスのinフィールドで標準入力を取得する。

　標準出力は、プログラムからデータを表示するための装置のようなもので、ディスプレイに表示されるものをいう。JavaではSysteクラスのoutフィールドを使う。

#Scannerの使い方
　java.util.Scannerクラスには以下のようなメソッドが用意されている。

- 1行分の入力を取得するnextLineメソッド
- 空白文字までの入力を取得するnextメソッド
- 数値の入力を取得するnextIntメソッド

##nextLineメソッドの使い方
　nextLineメソッドは、改行までの1行分の入力を取得することができる。

```java:サンプルコード
import java.util.Scanner;

public class Sample {
  public static void main(String[] args) {
    Scanner scan = new Scanner(System.in);
    String str = scan.nextLine();

    System.out.println(str);
    scan.close();
  }
}
```

##nextメソッドの使い方
　nextメソッドは、空白文字までの入力を取得できる。

```java:サンプルコード
import java.util.Scanner;
 
public class Sample {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        String str1 = scan.next();
        String str2 = scan.next();
 
        System.out.println(str1);
        System.out.println(str2);
        scan.close();
    }
}
```

##nextIntの使い方
　nextIntを使うとint型の数値を取得できる。浮動小数点型のすうちを取得するnextDoubleメソッドやnextFloatメソッドもある。

```java:サンプルコード
import java.util.Scanner;
 
public class Sample {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        int num1 = scan.nextInt();
        int num2 = scan.nextInt();

        int sum = num1 + num2;
        // 入力した数値の足し算を出力する
        System.out.println(num1 + " + " + num2 + " = " + sum);
        scan.close();
    }
}
```


#参考文献
[クラスScanner](https://docs.oracle.com/javase/jp/8/docs/api/java/util/Scanner.html)
[【Java入門】標準入力を取得、出力する方法(Scannerを解説)](https://www.sejuku.net/blog/65530)
ReactにMarkdownを組み込んでドキュメントページを素早く作る

#はじめに

ReactでWEBページを作成する際、ドキュメントページは手慣れたMarkdownで書いて、素早く形を作っていきたいと考えた。

その際に便利な[markdown-to-jsx](https://github.com/probablyup/markdown-to-jsx)というComponentを使ったのでまとめてみる。

最小構成のコードをcodesandboxにまとめた。
[codesandbox/markdown-to-jsx test](https://codesandbox.io/s/shy-bird-130k8?fontsize=14&hidenavigation=1&theme=dark)

#ポイント

■下記のように直接Markdownファイルを読み込もうとすると、

```
import contents from "./contents.md";

Cannot find module './contents.md' or its corresponding type declarations.ts(2307)

```
という警告が出た。
これを修正するために、global.d.tsファイルを作成し、

```
declare module "*.md";
```

と書くと警告が消えた。


■コードのMarkdown記法の修飾

QiitaのコードのMarkdown表現

```
黒バックに白字、インデント、上下スペース
```
これを実現するためには、styles.cssで

```
code {
  font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
    monospace;
  color: white;
}

pre {
  background-color: black;
  padding-top: 1em;
  padding-left: 1em;
  padding-bottom: 1em;
}
```

とすれば実現できた。ついでにコードを表現するのに定番なフォントも設定してみた。


■組み込み方

いろいろいじってみたが、下記が最小構成で動作した。

```
import * as React from "react";
import "./styles.css";
import Markdown from "markdown-to-jsx";
import contents from "./contents.md";

export default function App() {
  return <Markdown className="App" children={contents} />;
}

```

ヘッダー、フッター等コンポーネントを組み合わせて見栄えの良いドキュメントページが構築しやすくなった。
CodeBuildでGithubのコミット番号を取得しようとしてもできなかった

# 現象
連携しているgithubリポジトリのコミット番号を取得したいが失敗してしまう。

```
[Container] 2020/12/21 08:39:46 Running command IMAGE_TAG=$(git rev-parse --short HEAD)
fatal: not a git repository (or any parent up to mount point /codebuild)
Stopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM not set).

[Container] 2020/12/21 08:39:46 Command did not exit successfully IMAGE_TAG=$(git rev-parse --short HEAD) exit status 128
[Container] 2020/12/21 08:39:46 Phase complete: PRE_BUILD State: FAILED
[Container] 2020/12/21 08:39:46 Phase context status code: COMMAND_EXECUTION_ERROR Message: Error while executing command: IMAGE_TAG=$(git rev-parse --short HEAD). Reason: exit status 128
```

# 解決
CodeBuildにはデフォルトで環境変数が用意してあった。
SourceのコミットIDを利用したい場合は、`CODEBUILD_RESOLVED_SOURCE_VERSION`を使えばOK！
[用意されている環境変数一覧](https://docs.aws.amazon.com/ja_jp/codebuild/latest/userguide/build-env-ref-env-vars.html)
Typescript（Angular）始める時のVSCode設定

最近、フォーマッターの設定だとかいろいろやったので、次回何か作り始めるときにパッと準備ができるように最低限の設定方法を備忘録として残しておきます。


# ワークスペース化

いろんなプロジェクトに携わっていると、拡張機能が混ざり合ってしまうので、ワークスペース化して必要な拡張機能だけを有効にします。
また、ワークスペース化する事で、他の人に同じ設定や推奨拡張機能を共有できます。
（ワークスペース化せずに.vscode下にsetting.jsonおいたりするのもあり）

- ファイル -> 名前をつけてワークスペースを保存
- プロジェクトルートにワークスペースファイルを保存します
- 次回作業時はこのワークスペースファイルを開くと設定した内容でVSCodeが立ち上がります


# 拡張機能

プロジェクトに必要な拡張機能をワークスペースにインストールします

- 拡張機能を選択 -> インストール
    - インストール後、いったん無効にしてから`有効にする（ワークスペース）`を選択してワークスペース内でのみ有効とします


ワークスペースの推奨拡張機能として登録しておきます

- 拡張機能を選択 -> 歯車マーク -> ワークスペースの推奨事項に追加する
- これやっておくと、他の人にプロジェクトを共有した際に推奨されていますとポップアップが出る


以下はAngular開発時に最低限あった方が良いものです
必要に応じて追加でインストールします



## TSLint

TypescriptのLinter
この拡張機能を入れておくと、Lintを実施しなくてもリアルタイムにtslint.jsonにしたがってチェックしてくれるので便利。
※TSLintは推奨されなくなっているみたいなので、そのうちESLintに移行した方が良さそう

識別子：`ms-vscode.vscode-typescript-tslint-plugin`

## Prettier

フォーマッター
いろんな拡張子に対応しており、Angularも対応しているため、インデントやセミコロンやスペースの有無など、細かい記載レベルの統一を測れる

識別子：`esbenp.prettier-vscode`

## Angular Language Service

Angular開発には必須？

識別子：`angular.ng-template`



# 自動フォーマット設定

## Prettierの設定

拡張機能でPrettierをインストールしたので、自動でフォーマットするようにしておきます。

- 設定をファイルに記載します
    - 各種オプションについては[リファレンス](https://prettier.io/docs/en/options.html)参照
    - デフォルト値から変えたいプロパティのみ定義してあげます（明示したい場合はデフォルト値で記載するのもあり）
    - tslint.jsonと整合性が合うように設定します
- VSCodeの設定で`Prettier: Config Path`に`.prettierrc`を指定します

```..prettierrc
{
  "printWidth": 150,
  "singleQuote": true,
  "tabWidth": 4,
  "trailingComma": "all"
}
```

- フォーマット対象から外すディレクトリ／ファイルを指定します

```..prettierignore
node_modules
dist
```

## 自動フォーマット設定

設定にて`Editor: Format On Save`にチェックを入れます
※ワークスペースタブで実施

## デフォルトフォーマッター設定

- ワークススペースファイル（xxx.code-workspace）を開きます
- settings下に以下のように各ファイルのデフォルトフォーマッターをPrettierに紐付けます

```xxx.code-workspace
    "settings": {
                ・・・
		"[typescript]": {
			"editor.defaultFormatter": "esbenp.prettier-vscode"
		},
		"[javascript]": {
			"editor.defaultFormatter": "esbenp.prettier-vscode"
		},
		"[html]": {
			"editor.defaultFormatter": "esbenp.prettier-vscode"
		},
		"[css]": {
			"editor.defaultFormatter": "esbenp.prettier-vscode"
		},
		"[scss]": {
			"editor.defaultFormatter": "esbenp.prettier-vscode"
		},
		"[json]": {
			"editor.defaultFormatter": "esbenp.prettier-vscode"
		}
    }
```


## 手動で一括フォーマットしたい場合

- .prettierrcがある場所で以下のコマンドを叩けば、全ファイル一括フォーマットを行います
- プロジェクトの開始時に上記で設定した内容を一括で反映したいときに使います

```
npx prettier --write .
```
[Android] ブラウザを同じタブで開く方法（Chrome以外にも対応）

今開発中のアプリでは、アプリとブラウザを行ったり来たりする機能がありますが、単純に実装したところアプリから対象のWebページをブラウザで開く際に毎回新しいタブで開かれてしまったので、解決法を探ってみました。

ネット上ではChrome限定で行う方法などしか見つかりませんでしたが、もうちょっと汎用的な方法を見つけましたので、こちらに残しておきます。

# 環境

- Pixel 3a (Android 11)

# 方法

こんな感じで

```kotlin
fun openBrowser(url: String) {
  val intent = Intent(Intent.ACTION_VIEW).apply {
    data = Uri.parse(url)

    val resolveInfo = context.packageManager.resolveActivity(this, PackageManager.MATCH_DEFAULT_ONLY)
    val packageName = resolveInfo?.activityInfo?.packageName ?: PACKAGE_NAME_CHROME
    putExtra(Browser.EXTRA_APPLICATION_ID, packageName)
  }

  context.startActivity(intent)
}
```

# 説明

Intentに `EXTRA_APPLICATION_ID` でブラウザアプリのアプリケーションIDを指定しない場合、デフォルトアプリに設定されているブラウザが立ち上がりますが、常に新しいタブで開いてしまいます。

そこで、例えばChromeを開く場合は、 `EXTRA_APPLICATION_ID` に "com.android.chrome" を指定してやれば、同じページを開いているタブがすでに存在する場合は、Chromeがそのタブを再利用して開いてくれます。すべてのブラウザが同様に動作してくれるかは未確認ですが、少なくともChromeとOperaでは同様にタブを使い回してくれることを確認済みです。

デフォルトに設定されているブラウザアプリのパッケージ名はPackageManagerの `resolveActivity` から取得できるので、それを `EXTRA_APPLICATION_ID` に指定してやることで、デフォルトのブラウザアプリが開きつつ、同じタブで開いてくれます。

懸念事項としては、 `resoleActivity` から取得したパッケージ名と、 `EXTRA_APPLICATION_ID` で指定すべきアプリケーションIDが一致しないようなブラウザアプリが存在する場合にうまく動かないということが考えられます。この辺りは色々なブラウザについて調査する必要がありそうです。

# 補足

## デフォルトのブラウザアプリが設定されていない場合は？

Operaをデフォルトに設定した状態でOperaをアンインストールして、デフォルトのブラウザアプリが設定されていない状態にしてパッケージ名が取得できるか確かめてみたところ、 "com.android.chrome" が取得されました。てっきり `resolveInfo` がnullで返ってくるものかと思っていましたが、よしなに返してくれるようです。（端末によって変わるかもしれません。）

## `EXTRA_CREATE_NEW_TAB` について

Androidの `Browser` クラスのドキュメントを眺めていると、何かそれっぽい `EXTRA_CREATE_NEW_TAB` なるものを見つけました。

> public static final String EXTRA_CREATE_NEW_TAB
>
> Boolean extra passed along with an Intent to a browser, specifying that a new tab be created. Overrides EXTRA_APPLICATION_ID; if both are set, a new tab will be used, rather than using the same one.

これにfalseを設定したらいけるんじゃね？と思って `EXTRA_APPLICATION_ID` の有無と組み合わせて試してみましたが、特に動作に変わりは見られなかったため、今回は指定していません。
【ミライトデザイン社内勉強会#10】「IDDD本から理解するドメイン駆動設計」輪読会~1章「DDDへの誘い」~

## [ドメイン駆動設計のメリットと始め方 ～ 1章「DDDへの誘い」 (1/3)：CodeZine（コードジン）](https://codezine.jp/article/detail/9546)

> 『顧客と開発者が共通言語で会話して、一体感あるチームとして、事業価値の高いソフトウェアを開発する手法』
> 高品質はバグのないという意味ではなく、ビジネス的にも成功していることを指します。

### 戦略的設計と戦術的設計がある
- 戦術的設計だけを取り入れているものが軽量DDDと言われたりする
- 戦術的設計は戦略的設計をどう実装するかを考えるためにある


 
### 軽量DDDになるのはどんな原因があるの？
- 技術者が技術のことにしか興味がないから起こり得るのかも
    - Entitiyや集約などの実装のやり方にしか注目していないと起こりがち
- 開発者が単独でDDDをすることはできないので、戦術的設計ができない環境もある
    - 顧客（ドメインエキスパート）と一緒に開発することが必要
        

### 戦略的設計でドメインエキスパートと話合ったことをそのままプログラムとして実装する
- ここで使われるのが戦術的設計
- 設計したモデルがそのままコードに落としこまれている必要がある
- 開発者と顧客が一緒にビジネスを考えられるようになる
- 戦術的設計は要するに単なるオブジェクト思考
    - 業務をオブジェクト化して手続き型じゃなくてオブジェクト指向で書こうって話


### ユビキタス言語
- DSLの一種
    - DSL（ドメイン固有言語）
        - ある領域だけで通用する言語
- 顧客と技術者で同じ呼び方で統一する
    - 例えば、同じ状態のユーザーのことを顧客側では一般会員、技術者側では無料会員と呼んでいるなど同じ対象に対して呼び方が違うと会話に齟齬が生じることにもなる
        - 顧客側でも呼び方がまちまちだったりするので、チーム内で統一する必要がある
- ユビキタス言語をそのままモデルに落としこむ
- さらにモデルをそのままコードにも落としこむ
    - ユーザーが氏名を変えるならそれはユーザーモデルに氏名を変更するメソッドがあるべき
        - コントローラーとかにユーザーの氏名をDBから直接変更するようなメソッドが存在してはいけない
- ユビキタス言語がないとシステムのことを顧客に説明するときに苦労する
    - ユビキタス言語がモデルに落とし込まれていると、プログラミングの知識がない人にもモデル図などを見せながらシステムのことを説明することができる。



### ユビキタス言語ってどうまとめるのがいの？
- 概念モデル図を作ってそれをユビキタス言語集みたいにしている
    - [概念モデルのサンプル - Ken's Blog](http://muraken720.hatenablog.com/entry/20091127/p1)
    - 図だと関連まで表せるので顧客にも説明しやすい
- ユビキタス言語の辞書を作ってるところもある
- テキストドキュメントだと、すでに追加されているかどうかがわからなくなったりすることもある

### 途中でコンテキストを分けることはあるのか？
- 1つだっかものが別れるとかは普通にありそう
- 複数のものが1つになることはありえなくはないけど、基本なさそう
- コンテキストが別れる = 別コンテキストのことは全くわからないということ
    - Published Languag（apiから返ってくるjsonとか）でのみでしかやりとりはできない

### コアドメインに集中することって具体的にはどういう意味？
- 技術的な問題（SQLとか）とビジネスロジックを分けてドメインに集中するってこと
- ソースコード上ではコアドメインとサブドメインに違いは特にない
-  [hiroコアドメイン参考](https://twitter.com/hirodragon112/status/1321374422142349312?s=20)
- ビジネスがプログラムを作成した後に変化しないことはほぼありえないので、ビジネスが変化するとモデルが変化する、モデルの変化にプログラムが追従できることがDDDのメリット
- ドメイン駆動設計はモデル駆動設計の中の一部
    - LPのような単発ものにはコストがかかりすぎるのでDDDである必要はない

> エヴァンスは日本語翻訳版の序文にて「DDDの原則」は次の3つと述べています。

```
コアドメインに集中すること
ドメインの実践者とソフトウェアの実践者による創造的な共同作業を通じて、モデルを探究すること
明示的な境界づけられたコンテキストの内部で、ユビキタス言語を語ること
```
> 開発が進むにつれてDDDの技術的な側面に集中しまうことがあるかもしれませんが、DDDの本質を見失わないようこれらの原則を意識しておくことは重要です。

#### アジャイルを前提としたDDD

> なお、DDDはアジャイル開発を前提としています。そのため、アジャイル開発の経験があるメンバーのほうがDDD導入がスムーズになる可能性があります。

>　また、DDDでは設計段階から、アジャイルの概念における「テストファースト」でモデルを検討することが可能です。例えば、新しいモデルの概念がドメインに出てきた場合、以下の流れで開発を行います。

```
1	ドメインで必要とされるモデルについて、チーム全体で検討する
2	どのように使用するかについて、チーム全体で考える
3	開発者は、テストコードを書く
4	開発者は、ドメインモデルのコーディングを行う
5	開発者は、リファクタリングを行す
6	ドメインエキスパートは、テストコードを見て、ユビキタス言語の認識が正しいかを確認する
```

## 次回
[【ミライトデザイン社内勉強会#11】「IDDD本から理解するドメイン駆動設計」輪読会~第2章「ドメイン」「サブドメイン」「境界づけられたコンテキスト」を読み解く~ - Qiita](https://qiita.com/tkek321/items/71096b6404ab2091f9b1)
Ruby 2.5.2 から2.7.1にバージョンアップでやったこと

#はじめに
AWS上で動いているWebサイトのRubyのバージョンが2.5.2であり、このバージョンのEOL（End Of Life）が2020/12/25で、日付が近づいてきた。
そのため、Rubyをバージョンアップすることにした。
（以下 AWS上の警告の抜粋）

```
 ###### WARNING:
remote: 
remote:        Potential EOL Ruby Version
remote:        
remote:        You are using a Ruby version that has either reached its End of Life (EOL)
remote:        or will reach its End of Life on December 25th of this year.
remote:        
remote:        We suggest you upgrade to Ruby 2.6.x or later
remote:        
remote:        Once a Ruby version becomes EOL, it will no longer receive
remote:        security updates from Ruby core and may have serious vulnerabilities.
remote:        
remote:        Please upgrade your Ruby version.
remote:        
remote:        For a list of supported Ruby versions see:
remote:          https://devcenter.heroku.com/articles/ruby-support#supported-runtimes
```

#前提条件
　・  AWS Cloud9で動作しているRubyのバージョンアップ
　・  Ruby 2.5.2から2.7.1にバージョンアップ
　・  Rails 5.2.4.3
 ・  AWS上のバージョンアップなので関係ないと思うが、MacOS 10.15.7(Catalina)でAWSにアクセスして作業する

#バージョンアップ
インストール可能なRubyのversionを調べる

```
$ rbenv install --list
```

インストールしたいRubyのversionを指定してバージョンアップを実行する

```
$ rbenv install 2.7.1
```

インストールしたRubyのversionを確認する

```
$ rbenv versions 
 * 2.7.1 (set by /home/ec2-user/environment/eventorg/.ruby-version)
```

環境全体にRubyバージョンを反映したい時

```
$ rbenv global 2.7.1
```

特定のプロジェクトのみ反映したい時

```
$ rbenv local 2.7.1
```

次に、Gemfile内でRubyのバージョンを2.7.1に指定して、rubyのバージョンをコマンドで確認すると、

```
$ ruby -v
　 Your Ruby version is 2.5.2, but your Gemfile specified 2.7.1
```

とエラーが出る。

rvm install "ruby-2.7.1" を実行した後、ruby -vを実行すると、

```
$ ruby -v
 ruby 2.7.1p83 (2020-03-31 revision a0c7c23c9c) [x86_64-linux]
```

と出力され、エラーが消える。

新しいRubyのバージョンにGemをインストールする

```
$ gem install bundler
```

Gemfile内のRubyのバージョンが2.7.1となっている上で、下記を実行する

```
$ bundle install --path=vendor/bundle
```

新しいバージョンのRubyをインストールすると、railsコマンドが使えなくなってしまう

```
$ rails --version
rbenv: rails: command not found
```

そのため、gem をアップデートする

```
$ gem update --system
```

bundlerをインストールする

```
$ gem install bundler
```

railsをインストールする

```
$ gem install rails
```

Railsのバージョンを確認する

```
$ rails --version
Rails 5.2.4.3
```

以上でrailsコマンドが使えるようになる。 $rails s を実行して、アプリにアクセスできたので、バージョンアップは完了とする

#まとめ
バージョンアップはRuby->Gem->Railsの３つの順番で作業は流れていきます。この３つの塊を意識すると、バージョンアップのイメージは沸きやすいと思いました。
ご参考になれば幸いです。


# 参考記事
[rubyのバージョンアップ](https://qiita.com/Hironori-Matsuse/items/133195508793dc63d155)
[【Ruby】Your Ruby version is 2.6.3, but your Gemfile specified 2.5.8](https://qiita.com/ROY_M/items/43fd1370e3d89ae50074)
[Rubyのバージョン変更](https://qiita.com/satotaka/items/9c9a6ccc110b159b967b)

以上
[Rails]gem draperを使用して、decoratorを導入する方法

##目的

gem draperを使用して、decoratorを導入する。
このGemを導入するときに詰まった部分をメモとして残す。

##開発環境
・Ruby 2.6.4
・Rails 5.2.3

##参考資料
[Decoratorの役割とDraperについて](https://qiita.com/jonson29/items/00077b54bb91ed74fdb8)
[Draperの使い方 まとめ](http://nekorails.hatenablog.com/entry/2018/10/13/070437)
[Rails Viewの表示のためにDecoratorを用意してHelperとModelを助ける](https://qiita.com/shizuma/items/ce9e863e9c94e88e0a57)

##導入手順
###①gem 'draper'をインストールする。

まずはGemをインストールします。

```Gemfile.
gem 'draper'
```

以下の２行をターミナルに入力すれば、draperを使うことができます。

```
$ bundle install
$ rails generate draper:install
```


###②デコレーターを作成

まず、app/decorators/user_decorator.rb を作成します。

```
$ rails generate decorator User
```

今回はフルネームを呼び出すメソッドを作っていきます。
last_nameとfirst_nameは、事前にUserモデルのカラムに追加してあります。

```app/decorators/user_decorator.rb
class UserDecorator < Draper::Decorator
  delegate_all

  def full_name
    "#{object.last_name} #{object.first_name}"
  end
end
```


###③ 作ったメソッドをViewファイルで呼び出す。
現在ログインしているユーザー(current_user)をフルネームで表示します。

```
#メソッドを使いたいViewファイルにて

<%= current_user.decorate.full_name %>
```


以上の手順でgem 'draper'を使って、decoratorを導入できました。
この流れでエラーが出てしまった場合は、参考資料など見ながら解決してみてください。
「Firebase触ってみた」


## 概要
はじめてFirebaseを使用してみました。
今後新しくアプリ作成する時、すぐにある程度のところまで進めるように順序をまとめます。

1回やってみると思ったよりも簡単に作れるので、オススメです。

## 使用したサービス
Cloud Firestore → サーバを介さずに直接Firestoreにアクセスでき、リアルタイムに更新されたデータを取得できる

Authentication → アプリケーションに簡単に認証機能を追加することができる

Hosting → デプロイが楽にできる

## 環境を作成するまでの流れ
###Node.jsのinstall (LTS)
https://nodejs.org/en/

###Firebaseのアカウント作成
https://firebase.google.com/pricing?hl=en

![Screen Shot 2020-12-20 at 10.17.49 AM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520526/eb7872e8-58b6-a8e5-fbfc-608580bda0b9.png)

###Projectの作成
自分の作りたいアプリの名前を入力し作成します。

###FirestoreでDB作成
作成するときに本番環境モードかテストモードかが選択できます。本番環境モードは細かいパーミッションの設定ができます。

Firestoreのデータ構造はCollection、document、dataというふうに分かれていて、少しわかりにくいですが触ってみればすぐに理解できると思います。

###.env作成
FirebaseのProjectSetting→Firebase SDK snippetでConfigのチェックを入れるとスクリプトが表示されます。
このスクリプトを元にFirebaseのAPIKEY等のパラメータを記載します。


###Authentication設定
Authenticationに進むと、画面上に様々な認証方式が表示されるので、好きなものを選択します。
選択してチェックを入れるだけでFirebase側のやることは終わりです。
![Screen Shot 2020-12-21 at 5.28.35 PM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520526/e6ca94d1-1c8c-cde3-0598-293685208533.png)

```Login.tsx
const Login: React.FC = (props: any) => {
  const [isLogin, setIsLogin] = useState(true);
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");

  useEffect(() => {
    const unSub = auth.onAuthStateChanged((user) => {
      user && props.history.push("/");
    });
    return () => unSub();
  }, [props.history]);

// 省略
  return (
  );
};

export default Login;
```


## Hosting設定
Hostingに進み、Firebase CLIのインストールのコマンド入力

```
sudo npm install -g firebase-tools
firebase init
```

そしてターミナル上でデプロイしたいプロジェクトを選択

```
firebase deploy
```

するとHosting URLが表示されるので、こちらにアクセス

##まとめ
業務では余り使う機会なさそうだけども、実際に使ってみて、早くて便利だなと感じたのでこれからもう少し触ってみたいです。
JavaScriptのassertテストで「AssertionError [ERR_ASSERTION]: The expression evaluated to a falsy value:」と返された時の対応

どうも、N高生のゆういちです。
見慣れないエラー文を直面したので、その解消法をご紹介します。

N予備校アプリのプログラミング授業より「XSSの脆弱性対策」で、
脆弱性が正しくできているかどうかを意図的に試すことをしました。
その際にテスト中に起こったエラーを解消したことを書きます。

該当のエラー文が以下です。

```
assert.js:350
    throw err;
    ^

AssertionError [ERR_ASSERTION]: The expression evaluated to a falsy value:

  assert(html.includes("<script>alert(\'test\');</script>"))

    at Object.<anonymous> (/home/vagrant/workspace/secret-board-3028/test.js:19:1)
<以下略>
```

`AssertionError [ERR_ASSERTION]: The expression evaluated to a falsy value:`と出ましたが、「テストしたところ、falseという値を返します」と言われましたね。
値が合致していないということかな？

# 該当コード
```test.js
'use strict';
const pug = require('pug');
const assert = require('assert');

const html = pug.renderFile('./views/posts.pug', {
  posts: [
    {
      id: 1,
      content: "<script>alert(\'test\'); </script>",
      postedBy: 'guest1',
      trackingCookie: 1,
      createdAt: new Date(),
      updatedAt: new Date()
    }
  ],
  user: 'guest1'
});

assert(html.includes("&lt;script&gt;alert(\'test\');&lt;/script&gt;"));
console.log('テストが正常に完了しました');
```

投稿を表すオブジェクトのcontentプロパティにscriptタグを入れて、assert関数によってその文字列が含まれているかどうかを判定します。

# 解決したこと

contentプロパティの`"<script>alert(\'test\'); </script>"`の、;と<の間に1つ半角スペースが入ってあるのが気になったので、これを消して再度テストを実行。

```
$ node test.js
テストが正常に完了しました
```

無事に実行できました。単純な記述ミスでしたので早めに気づいてよかったです。
assertはfalseの時はエラーメッセージが返ってくるということをヒントに、文字列が間違っているのかなと仮説を立てたことでなんとか実現したいことができました。

初歩的ながら記述やスペルが合っているかを確認することは大事だと気づかされました。
ではまた！
【Rails】Slim記法について

## Slimとは？

Rubyのテンプレートエンジンです。
特徴はhtmlのように閉じタグを必要としないところかと。

また、条件分岐などの`end`は必要とせず全てインデントで判断します。
そのため、少しでもインデントがずれると、エラーが発生します。気をつけましょう。


## Slimの概要

- `<>`不要
- `<%%>` → `-`
- `<%= %>` → `=`
- `<div class="hoge></div>` → `.hoge`
- `<div id="hoge"></div>` → `#hoge`

上記の通りです。
めちゃくちゃ楽ですね。

## 書き方

### `class`

```hoge.html

<div class="hoge huga">こんにちは！</div>

```

```hoge.slim

.hoge.huga こんにちは！

```

### `if文`

```hoge.html

<% if user_signed_in? %>
 <li>新規投稿</li>
<% else %>
 <li>ログイン</li>
<% end %>
```

```hoge.slim

- if user_signed_in?
  li 新規投稿
- else
  li ログイン

 /end不要
```

以上です。
簡易的な記事になりましたが参考にしてください^^
[MySQL] MySQLでデータベースを作成

#データベースを作成し値を入力する

※ 自分用の覚え書きでございます。

・db_users　というデータベースを作成します
・tbl_users　というテーブルを作成します
・値を INSERT します

>mysql> CREATE DATABASE db_users;

>mysql> USE db_users;

>mysql> CREATE TABLE tbl_users (id INT AUTO_INCREMENT, name TEXT, age INT(3) , PRIMARY KEY (id)) DEFAULT CHARSET=utf8;

>mysql> INSERT INTO tbl_users (name, age) VALUES ('山田太郎', 15);

SELECT * FROM tbl_users; で以下のように表示されます。
![006a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/897250/a1f85238-58da-33d2-9c65-9889572976e1.png)
WordPressプラグインの脆弱性が発覚したのでGithub Advanced search を使って対処する

[WordPressのプラグインContactForm7に脆弱性が見つかったとの報告](https://www.itmedia.co.jp/enterprise/articles/2012/18/news138.html)に伴い、同プラグインを使用している過去案件のアップデートを行いました。たまに似たことがあるので、社内共有のために手順をまとめておきます。弊社は基本的にすべてソースコードをGithubにあげているので、[Advanced search](https://github.com/search/advanced)を使えば問題のあるプロジェクトを探せます。

*今回は、CF7についてですが、他のプラグインでも同じ手法でいけると思います。ファイル名や検索ワードは、その都度変更して対応してください。あと、弊社の中の人じゃない場合は、もちろんOwnerも変えてください。*

すでにパッチのあたっているものは作業の必要もないので、プラグインのバージョンが記述されている箇所を検索に引っ掛けるようにして、目視でアップデートの必要性を判断します。

![スクリーンショット 2020-12-21 15.57.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4404/9b3b5900-e17e-89a8-ac47-55f6f17b29a5.png)

サイドバーで「Code」を選択すると、このように一覧が取得できるので古いバージョンのプロジェクトは、個別にアップデート作業を行います。今回は、[5.3.2](https://contactform7.com/2020/12/17/contact-form-7-532/)でパッチがあたっているので、それより古いバージョンを使っているプロジェクトが該当します。

![スクリーンショット 2020-12-21 17.36.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4404/6efe1f83-78c4-6602-820f-a1c553343f7a.png)

以上です。プラグインのアップデートも一括でできるといいですね…。
[自分流] rails初期設定メモ

自分用です

```ruby:gem
gem 'ridgepole'
gem 'slim-rails'
gem 'html2slim'
gem 'pry-rails'

bundle
```

```
config.time_zone = 'Tokyo'
config.generators.template_engine = :slim
```

```
bundle exec erb2slim app/views app/views 
```

```
default: &default
  adapter: postgresql
  encoding: unicode
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  password: xxx
  host: localhost
  username: postgres

省略
```

いままでは過去に作ったフォルダーをコピペしてたけどいちいちフォルダー開くのもめんどいんでメモ。
ただQiitaを開いてこのページ開くのも十分めんどいかも
使うかどうかは自分次第

あ、あと開発におすすめのgemなどあったら教えてください(^^♪
僕がおすすめなのは圧倒的にridgepoleとslim
この二つは慣れたらすごくいい

ちなみに、今はrailsでwebアプリの開発をすすめながらjavascriptを一から勉強してます。
javascriptは本気で勉強したことがなかったのですが、あるものを作りたくてやり始めました。
Rails6 環境構築からHerokuデプロイまでの流れ

Railsチュートリアルを1周終えたので、2周目はアウトプットと備忘録のために、要点を絞ってまとめたいなと思いました。この記事では第3章まで行う、環境構築からデプロイまでの流れをまとめます。

## 目次
[1 開発環境構築](#1-開発環境構築)
[2 Git](#2-git)
[3 Heroku](#3-heroku)

## 環境
Rails 6.0.3
Ruby 2.6.3
AWS Cloud9
Heroku

##1 開発環境構築
###1.1 Railsをインストール
gemコマンドを使って、Railsをインストール

```
$ gem install rails -v 6.0.3
```

正常にインストールされたか確認

```
$ rails -v
Rails 6.0.3
```

###1.2 Yarnをインストール
Rails6からはJavaScriptソフトウェアの依存関係を管理するyarnを使用するため、インストールします。

```
$ source <(curl -sL https://cdn.learnenough.com/yarn_install)
```

###1.3 プロジェクトを作成

```
rails _6.0.3_ new プロジェクト名
```

###1.4 Gemfile設定
Gemfileに必要なgemを記載したら、Bundlerを用いてgemをインストールしていきます。今回は本番環境の設定も込みで行います。

```:Gemfile
・
・
# 開発環境、テスト環境でSQLite3を使用
group :development, :test do
  gem 'sqlite3', 'バージョン' 
  # Rails6では、1.4.1で指定。ただしActiveRecordが対応していないことによるエラーが発生する場合があり、その時は1.3に
  ・
end
・
・
# 本番環境でPostgreSQLを使用
group :production do
  gem 'pg', 'バージョン' # Rails6では、現時点1.1.4で指定
end
・
```

```
$ bundle install --without production
```
--without productionオプションを追加することで、本番環境のみで使用するよう設定します。
この時にカレントディレクトリに移動し忘れてることがよくあります💦

##2 Git
###2.1 名前とメールをGitに設定
```
$ git config --global user.name "自分の名前"
$ git config --global user.email "自分のメアド"
```

###2.2 クラウドIDEでデフォルトエディタ設定
```
$ sudo ln -sf `which nano` /usr/bin
```

###2.3 Gitのパスワード保持の時間を設定

```
$ git config --global credential.helper "cache --timeout=86400"
```
一日保持したい場合は86400秒となります。毎回名前とパスワードをpushの時に入力するのは面倒なので重宝してます。

###2.4 Gitリポジトリ初期化
```
$ git init
$ git add -A
$ git commit -m "コミットメッセージ"
```
-Aでカレントディレクトリにある全てのファイルが追加されます（.gitignore等のファイルは追加されません）

###2.5 GitHubでリポジトリ作成
ここの手順は割愛します。

###2.6 pushする
```
$ git remote add origin https://github.com/GitHubアカウント名/プロジェクト名.git
$ git push -u origin master
```
##3 Heroku
###3.1 Cloud9への接続許可を設定
Herokuの前にまずローカル環境で起動するために必要な設定を行います。

```:config/environment/development.rb
Rails.application.configure do
  ・
  ・
  config.hosts.clear
end
```

###3.2 正常にデプロイできたか確認するための「hello world」

```app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  def hello
    render html: "hello world"
  end
end
```

```config/routes.rb
Rails.application.routes.draw do
  root 'application#hello'
end
```

```
git commit -am "コミットメッセージ"
```

変更をgitにコミットしておきます。

###3.3 Herokuをインストール

```
$ source <(curl -sL https://cdn.learnenough.com/heroku_install)
```

###3.4 Herokuにログイン

```
$ heroku login --interactive
```
--interactiveオプションを付けることで、ブラウザを開くことなくログインすることが可能です。

###3.5 アプリケーション作成

```
$ heroku create
```

###3.6 Herokuにデプロイする

```
$ git push heroku master
```

###3.7 アプリケーション名を変更しておく

```
$ heroku rename アプリケーション名
```

####ここまできて、開発環境・本番環境共に「hello world」がブラウザに表示されていれば成功です！！

##4 SSLか

ここから、実際にデータを取り扱う時のセキュリティを考慮した設定を記述していきます。
複数行を一括でINSERTするときのVALUESの書き方

# 複数行を一括でINSERTする

```
-- カンマで区切るだけ
INSERT INTO hogehoge
  (hoge_code, hoge_name)
VALUES 
  ('code1', 'name1'),
  ('code2', 'name2'),
  ('code3', 'name3')
;
```
PythonからPostgreSQLのテーブルにINSERTする時にハマった話

#問題点
```python
import psycopg2

# DB接続情報
postgre_user_name = "admin"
postgre_user_password = "password"
postgre_server_port = 5432
postgre_database_name = "hogefuga"

connection = psycopg2.connect(f"host=localhost port={postgre_server_port} dbname={postgre_database_name} user={postgre_user_name} password={postgre_user_password}")
cur = connection.cursor()

result = json.dumps(result)
id = 1234
number = 1234

sql_sentence = f"INSERT INTO slip(content, id, number) values('{result}', '{id}', '{number}');"
print(sql_sentence)
cur.execute(sql_sentence)
```

上記コード実行後、テーブルを確認してもインサートされていない…。

print(sql_sentence)で出力されたクエリをzshから直接実行するとちゃんとインサートされる。

```terminal
INSERT INTO slip(content, id, number) values('{"billing_sum":3257.21}', '111011111110000008001', '14');
INSERT 0 1
```

#解決方法
curオブジェクトをexecuteした後、psycopg2.connectオブジェクトをcommit()してあげる。

```python
import psycopg2

# DB接続情報
postgre_user_name = "admin"
postgre_user_password = "password"
postgre_server_port = 5432
postgre_database_name = "hogefuga"

connection = psycopg2.connect(f"host=localhost port={postgre_server_port} dbname={postgre_database_name} user={postgre_user_name} password={postgre_user_password}")
cur = connection.cursor()

result = json.dumps(result)
id = 1234
number = 1234

sql_sentence = f"INSERT INTO slip(content, id, number) values('{result}', '{id}', '{number}');"
print(sql_sentence)
cur.execute(sql_sentence)
connection.commit() # ←この一行
```

psycopg2 ではデフォルトでトランザクションが有効になっているので commit を行わないと反映されない。トランザクションを無効にする場合は autocommit = True を設定する必要がある。

※トランザクションとは複数の処理を一つにまとめたもの。
一例として、銀行口座間の振り込みが挙げられる。
AさんからBさんに5,000円振り込みを行う場合、
①Aさんの口座から5,000円減額する
②Bさんの口座を5,000円増額する
どちらかだけの処理が成功したら困るので、一連の処理にまとめる。
トランザクションは成功か失敗かしかない。
firebase functionsでデプロイした関数を確認する

意外とわからない人もいそう＆自分も忘れそう＆
確認する方法が明示的に書かれているページが
検索で出てこなかったので備忘録的に残してみます。

firebase fuctionsでデプロイした後
あれ？この関数の中身って今どんなだっけ？となった時。

知っている方はなんて事のない情報ですが
firebase functionsはcloud functionsをラップしているので
GCPの管理画面から確認できます。
個人的に迷った部分だけ画像を付けています。

１.まず以下のリンクからダッシュボードにアクセス
https://console.cloud.google.com/home/dashboard

2.画面上部にプロジェクトを選択できるプルダウンがあるので
開くとfirebaseのプロジェクトが出てくると思います。
functionsを使用しているものを選びます。
![1heada.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/169482/3eeefbd0-4fdc-8f44-16e5-8afbf92c2916.jpeg)


3.プロジェクトを選んだら左メニューからCloud Functionsをクリックします。
![sidebar.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/169482/fa7e785f-07bd-8650-1eef-83cfcb533458.jpeg)


4.関数名をクリックします。

5.画面上部の編集というリンクをクリックします。
![edit.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/169482/39884ec4-94fc-f72a-cb06-27bac0b68301.jpeg)


6.編集画面の下の次へというリンクをクリックします。
![next.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/169482/91607568-40c7-3352-c13d-d1ff74b0c68b.jpeg)


これで現在デプロイされている具体的なファイルが出てきて確認できます。
MySQLでコマンドは合っているはずなのにデータベース作成ができないと思ったら予約語だった

#MySQLでコマンドは合っているはずなのにデータベース作成ができないと思ったら予約語だった

###使用環境
* windows10
* XAMPP 7.3.18 (MariaDB 10.4.11)

##背景
```CREATE DATABASE condition;```でconditionというデータベースを作成しようとしたら、コマンドは合っているはずなのにエラーが出て作成できない。

**エラー内容**

```
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'condition' at line 1
```
構文エラー？何度コマンドを見直してもコマンド自体は合っている。

##原因
今回データベース名にしようとしていた**condition**は**予約語**だった！
予約語は盲点だった...
[MySQL5.6リファレンスマニュアル](https://dev.mysql.com/doc/refman/5.6/ja/reserved-words.html)

>予約語(reserved word)
予約語とは、プログラミング言語などの人工言語の仕様に定められている、開発者が付ける識別名として利用できない文字列のこと。予約語に挙げられた単語やフレーズは変数名や関数名などに使用することはできない。
[IT用語辞典](http://e-words.jp/w/%E4%BA%88%E7%B4%84%E8%AA%9E.html)

ちなみにMySQLとMariaDBのバージョンの互換性は以下

|MySQLバージョン|MariaDBバージョン|
|:--|:--|
|5.1|5.1, 5.2, 5.3|
|5.5|5.5, 10.0|
|5.6|10.0, 10.1, 10.2, 10.3, 10.4|
|5.7|10.2, 10.3, 10.4|

[OpenStandia](https://openstandia.jp/oss_info/mariadb/)

##対処方法
データベース名を予約語以外にすることで解決。
update文が遅い

## 結論

indexが使えていなかった…。
update文のwhere句を見直し、indexを利用したら大幅に改善された。

## はじめに

コードとか具体的な数値はないし、日報ベースで拙い文章ですがご容赦を…。

社内のシステムAからBにデータを連携しているバッチがあり、DBにデータを一つずつinsertまたはupdateを実施していた。
普段は差分同期だったので、前回の同期した日時から記録しておいて、バッチが起動した際は前回の同期した日時以降に更新があったものだけ同期するだけでよかった。
自分が前任者から引き継いだタイミングで、同期するデータの見直しがあって最初から再同期して欲しいと要望があった。

## 予測と見直し

数日かかっても良いとのことだったので、前回の同期した日時を変更して全件対象になるようにした。
同期しながら終了時刻の予測をしようと思っていたが、それにしても異様に遅いし、だんだん遅くなる…。
（今思えば、だんだん遅くなるのは、同期するデータの見直して今まで同期されていなかったものが同期されて連携先のテーブルが大きくなったのが原因と思う）

終わりが見えないので、同期方法を改善しようと思いコードを確認した。
データの同期は、同じキーのレコードがない場合はinsert、同じキーのレコードがある場合は比較して、差分がある場合はupdate、をするようになっていた。
DBはpostgresなのでupsertが利用できるかなと思ったが、バージョンが9.3.2でupsertが追加前のものなので諦める…。
upsertをマネて最初にupdateを実施して更新件数が0件ならinsertを実施するように変更してみた。
若干速くなったような気がしたが大幅に改善できたとは言えないので困った…。

## 見直しその2と改善

insertとupdate文やテーブルがおかしいのでないかと思い確認してみた。
システムAとBは同じテーブルに見えて連携先のテーブルは、キーが追加されて複合キーになっていた。
updateのとき、where句は連携元のキーのものしか検索してないので、全件検索になっていたっぽい。
（今までそれで大丈夫だったのか置いておいて…）
where句に連携先に追加されていたキーも入れてandで検索したら、それなりに速くなったし、だんだん遅くなることもなくなった。

## 終わりに

バッチの処理内容とかテーブル構成とか理解している気になって、
小手先の変更で改善しようとしたのが間違いだったと思う。
sqlが何かしら遅い場合は、最初にindexを疑うことにする。
githubとslackの連携

状態としてはすでにgithubのアプリはダウンロードされている状態。

・後は自分のgithubアカウントとslackを連携
・通知を入れたいチャンネルと結びつける
・リポジトリとslackを連携

##1.githubアカウントとslackを紐づける
ワークスペースの左上にある「その他」をクリックして「App」から「git」をクリックする

そしたらGitとDMが出来るようになる。
そこで

```
/github signin
```
を実行して、githubアカウントとslackを紐づける。

##2.チャンネルにgithubを招待
通知を入れたいチャンネルで

```
/invite @GitHub　
```
を実行する。

##3.チャンネルと通知元のリポジトリを連携
チャンネルで

```
/github subscribe ユーザー名/リポジトリ名
```
を実行。

もしかしたら

```
Either the app isn't installed on your repository or the repository does not exist. Install it to proceed.
```
と出てくるかもしれないので、そしたら
緑の```install github app```
をクリックしてgithubのページに飛んでインストールをする。

それから再度slackに戻ると```Subscribed to　～～～～```と出ているはずだ。
これで完了である。

試しに```issue```などを作ってみると通知が来るはずである。
pandasのDataFrameのapplyで複数列を返す。

#pandasのDataFrameのapplyで複数列を返す場合のサンプルです。
## apply で　 result_type='expand'　を指定します。（バージョン0.23以上）



以下は[pandas.DataFrame.apply](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.apply.html)より


result_type{‘expand’, ‘reduce’, ‘broadcast’, None}, default None
これらは、axis = 1（列）の場合にのみ機能します。
「expand」：リストのような結果が列に変換されます。
「reduce」：リストのような結果を展開するのではなく、可能であればシリーズを返します。 これは「expand」の反対です。
「ブロードキャスト」：結果はDataFrameの元の形状にブロードキャストされ、元のインデックスと列が保持されます。
デフォルトの動作（なし）は、適用された関数の戻り値によって異なります。リストのような結果は、それらの一連の結果として返されます。 ただし、apply関数がSeriesを返す場合、これらは列に展開されます。

バージョン0.23.0の新機能。

#テストデータ
```python
import pandas as pd 
dt={
    "x"  :[1100 , 1200 , 1300 ]  ,
    "y"  :[2100 , 2200 , 2300 ]  ,
    }

df=pd.DataFrame(dt)
print(df.to_markdown())
```
|    |    x |    y |
|---:|-----:|-----:|
|  0 | 1100 | 2100 |
|  1 | 1200 | 2200 |
|  2 | 1300 | 2300 |




#サンプルソース
```python

def fnc(x):
    return x["x"]+1,x["x"]+2 

df[["a","b"]]=df.apply(lambda x:fnc(x),axis=1, result_type='expand')
print(df.to_markdown())
```


|    |    x |    y |    a |    b |
|---:|-----:|-----:|-----:|-----:|
|  0 | 1100 | 2100 | 1101 | 1102 |
|  1 | 1200 | 2200 | 1201 | 1202 |
|  2 | 1300 | 2300 | 1301 | 1302 |

#参考

[pandas.DataFrame.apply](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.apply.html)
文字を逆順にする再帰関数の良い作り方

#文字を逆順に表示する為の考え方
1. 特定の単語の最後の値を取得する
2. 既存単語の最後の値を削除する
3. ２の後の単語の最後の値を取得し１の取得した文字の後につなげる
4. 1~３を単語の文字数がぜろになるまで繰り返す
5. 取得した文字を出力

#完成コード
```test.php
<?php
    function reverseStr($word,$reword){
        if(strlen($word)<1){
            return $reword;
        }
        return reverseStr(substr($word,0,-1), $reword.$word[-1]);
    }
    $word = "abcdefgh";
    echo reverseStr($word, null);
    //hgfedcba
    echo strlen("");
    //0
?>
```

#コードの解説
再帰関数にも色々種類があるが、末尾再帰を意識して作成している。
このことについて、通常の再帰関数との違いを比較しながら解説を行っていく。




####末尾再帰の場合
__前提条件：入力値をabcdとする__

```test.php
<?php
    function a($word,$reword){
        if(strlen($word)<1){
            return $reword;
        }
        return a(substr($word,0,-1), $reword.$word[-1]);
    }
?>
```
#### 解説
初期の入力値が(abcd,"")だった場合に想定される関数の遷移は下記のようになる
a(abcd,"")
=> a(abc,d)
=> a(ab,dc)
=> a(a,dcb)
=> a("",dcba)
=> dcba
１つずつ値を返して処理を実行するのでメモリへの負担が少ないことが言える。

####通常の再帰の場合
__前提条件：入力値をabcdとする__

```test.php
<?php
   function a($word){
        if(strlen($word)<1){
            return $word;
        }
        return $word[-1] + a(substr($word,0,-1));
    }
?>
```
#### 解説
初期の入力値が(abcd,"")だった場合に想定される関数の遷移は下記のようになる
a(abcd)
=> a(abcd){ d + a(abc)　}
=> a(abcd){ d + a(abc) { c + a(ab) } } 
=> a(abcd){ d + a(abc) { c + a(ab) { b + a(a) } } }
=> a(abcd){ d + a(abc) { c + a(ab) { b + a } } }
=> a(abcd){ d + a(abc) { c + ba } }
=> a(abcd){ d + cba }
=>dcba

#現在解説を修正中です。

#他言語のコード（参考までに）
```test.js
  function reverseStr(word, reword){
      if(word.length < 1){
          return reword;
      }
      return reverseStr(word.slice(0,-1), reword + word.slice(-1));
  }
  var word = "abcdefgh";
  console.log(reverseStr(word, ""));
```

```test.rb
def reverseStr(word, reword)
   if(word.length < 1)
       return reword
   end
   return reverseStr(word[0..-2],reword+word[-1])
end
word = "abcdefgh"
puts reverseStr(word, "")
```

```test.py
def reveseStr(word, reword):
    if len(word) < 1:
        return reword
    return reveseStr(word[0:-1], reword + word[-1])
    
word = "abcdefgh"
print(reveseStr(word, ""))
```
コンテナ上のJupyterHubの死活監視について調べてみた

JupyterHubをKubernetes上で動かすことになり、どのような死活監視できるか調べてみた。
こういった機能はAPIベースで提供することが求められており、yamlにてその定義が行われているようだ。

設定箇所を調べてみると、jupyterhubのdeployment.yamlに記載があった。
kubernetes用のパッケージマネージャである<a href="https://jupyterhub.github.io/helm-chart/jupyterhub-0.10.0.tgz">helm(version 0.10.0)の中</a>を見てみる。

jupyterhub-0.10.0/jupyterhub/templates/hub/deployment.yaml

```
          # livenessProbe notes:
          # We don't know how long hub database upgrades could take
          # so having a liveness probe could be a bit risky unless we put
          # a initialDelaySeconds value with long enough margin for that
          # to not be an issue. If it is too short, we could end up aborting
          # database upgrades midway or ending up in an infinite restart
          # loop.
          livenessProbe:
            initialDelaySeconds: {{ .Values.hub.livenessProbe.initialDelaySeconds }}
            periodSeconds: {{ .Values.hub.livenessProbe.periodSeconds }}
            timeoutSeconds: {{ .Values.hub.livenessProbe.timeoutSeconds }}
            failureThreshold: {{ .Values.hub.livenessProbe.failureThreshold }}
            httpGet:
              path: {{ .Values.hub.baseUrl | trimSuffix "/" }}/hub/health
              port: http
          {{- end }}
          {{- if .Values.hub.readinessProbe.enabled }}
```

http://サーバIP:ポート/hub/health で監視できるようだ。
やってみる。HTTPレスポンス200番で帰ってきた。

```
[xxxx@localhost container]$ curl http://localhost:32546/hub/health -v
> GET /hub/health HTTP/1.1
> Host: localhost:32546
> User-Agent: curl/7.61.1
> Accept: */*
>
< HTTP/1.1 200 OK
< server: TornadoServer/6.0.4
< content-type: text/html
< date: Mon, 21 Dec 2020 07:55:48 GMT
< x-jupyterhub-version: 1.2.1
< access-control-allow-headers: accept, content-type, authorization
< content-security-policy: frame-ancestors 'self'; report-uri /hub/security/csp-report
< etag: "da39a3ee5e6b4b0d3255bfef95601890afd80709"
< content-length: 0
< connection: close
<
* Closing connection 0

```
運用ゲームタイトルのKPI取得について

本記事は [サムザップ #1 Advent Calendar 2020](https://qiita.com/advent-calendar/2020/sumzap1) の12/22の記事です。
昨日の記事は [@yoshihiko_k](https://qiita.com/yoshihiko_k) さんの[「15分で一緒に作ろう！NotionをヘッドレスCMSにして爆速ブログを作る方法」](https://qiita.com/yoshihiko_k/items/1f6067f2be88aa0dc65b)でした。 

サムザップで開発ディレクターを担当しております中村です。

７年以上運用しているギルドバトル系のゲームを担当しているのでゲームKPIについて書こうと思います。
今のプロジェクトでは、データのビジュアライズツールとしてtableauを使用しています。
データは下記の様なフローで取得しています。
#構成
![tableau.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266880/14cbc3cd-1fae-930a-8e7e-c0de9f7845a4.png)
重要KPIとしては

* ユニークユーザ数
* 参加ギルド数,率
* アクティブバトル数,率
* バトル白熱率
等を追っています。

ユニークユーザ数、参加ギルド数、参加率はマネタイズに影響する重要KPIです。
シンプルにアクセスログやRDBからカウント集計した数字出しています。当然ながら多ければ多いほど良いです。

アクティブバトル数と率、バトル白熱率は、ゲームバランスや体験に大きく影響するKPIです。
この指標の低下が続くと先ほどあげた「ユニークユーザ数」「参加ギルド数」「参加率」の低下をまねきます。

###アクティブバトル数と率
1バトル最大20人vs20人のユーザがどれだけアクティブに動いているかの差を出しています。
戦力差や勝敗に関係なくアクティブなユーザ同士が戦うことでゲーム体験が向上するという考えのもと数字を出しています。

定義としては以下です
1. 両ギルドの平均アクション回数X回以上
2. 総アクション数が多い方を基準とした場合の差が30%以内
式 : 1- (少ない方/多い方） <= 0.3
1.2両方が真の場合にアクティブとする。


###バトル白熱率
ギルドバトルにおいてどれだけ接戦をしていたかを出しています。
こちらは主に戦力や戦術がどれだけ拮抗しているかを確認するために出しています。
特にアクティブ率の高い上位ギルドの白熱率を重要視しています。

定義は
1. 一定の時間帯で獲得ポイントがX以上
2. 獲得ポイント差が20%以内

###パラメータグラフ
他にもギルドをいくつかピックアップしてバトル中のバフデバフ効果、ステータス差、ポイント差をグラフ化して環境のチェックをしています。この仕組みは、もともと運営側でゲーム環境調査の為に取っていたデータですが、イベントの生配信解説の為に公表した際にユーザにも好評だった為、ゲーム内にも実装したエンジニア発案の機能になります。
![param_g.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266880/dc0d85c1-3158-f42b-c20d-a55168d8b4be.png)

ゲーム内機能として実装するにあたり変更した点は、今まではバッチサーバから定期的にデータを取得するのみでしたが同様の方法で全ユーザのデータを取得するのは難しかった為、ポーリングやユーザアクションをトリガーに取得しています。
![param_f.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266880/ccc15267-4f97-f0d3-9182-27b15e9ec248.png)

#おわりに
今回は運用ゲームタイトルのバトルまわりのKPIについて書きましたが他にもゲームバランスやマネタイズにかかわるようなKPIは多く取得しています。7年以上地道にKPIを改善しつつ運用しており新しい指標も日々検討しています。
また他の指標についても機会あれば書きます。
Windowsチューニング

レジストリ系
Windowsデスクトップアイコンの表示/非表示
https://automationlabo.com/wat/?p=2327

Microsoft IMEの設定
http://smart-pda.net/software/Pocket%E3%81%AE%E6%89%8B/Chapter-110009.html/

グループポリシー系
Windows機能の有効化または無効化
https://www.code-lab.net/?p=20887
サインイン/ログオン時のCtrl+Alt+Delの有効化/無効化
https://www.billionwallet.com/secpol/ctrl-alt-del-security-policy.html
カラムの追加や編集（migration）


##1. Migrationファイルを作成する。

```bash:bash

  #[カラム追加]カラムの追加のためのマイグレーションファイル発行
$ rails g migration Addカラム名Toテーブル名 カラム名:型名
  #[カラム削除]カラムの削除のためのマイグレーションファイル発行
$ rails g migration Removeカラム名Fromテーブル名 カラム名:型名
  #[カラム名前変更]カラムの変更のためのマイグレーションファイル発行
$ rails g migration rename_カラム名_column_to_頭大文字テーブル名
  #[カラムデータ型変更]カラムの追加のためのマイグレーションファイル発行
$ rails g migration Addカラム名Toテーブル名 カラム名:型名

```

##2. 作成したマイグレーションファイルを見て、内容を確認・記載する。
　**※注意：以下のような状態だと変更はなしになる。**

```rb:Migration

class Renameカラム名ColumnTo頭大文字テーブル < ActiveRecord::Migration[5.2]
  def change
  end
end
```


####2-1. 名前だけ間違えてしまった場合

```rb:Migration

class Renameカラム名ColumnTo頭大文字テーブル名 < ActiveRecord::Migration[5.2]
  def change
    rename_column :テーブル名, :変更前カラム名, :変更後カラム名
end
```

####2-2. データ型レベルで間違えた場合

```rb:マイグレーションファイル
class Addカラム名Toテーブル名 < ActiveRecord::Migration
  
 #新たに追加するカラム
  def up
    add_column :items, :customer_id, :integer
  end
  
 #削除したいカラム
  def down
    remove_column :items, :customer_id, :string
  end
end
```


##3. SQLに反映する。

```bash:bash
$ rails db:migrate
```
うまく行かなかったらすごい数のエラー文が出る


##4. schema.rbを見て正しく書き込まれていることを確認する。
　
　
　
　
　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　**　以上**
Pythonで学ぶアルゴリズム　第9弾：線形探索

# #Pythonで学ぶアルゴリズム< 線形探索 >

##はじめに
基本的なアルゴリズムをPythonで実装し，アルゴリズムの理解を深める．
その第9弾として線形探索を扱う．

##線形探索
探索：多くのデータの中から欲しいデータを見つけること
線形：先頭から順に調べる

つまり，線形探索とは何も複雑なことはせずに順に前から調べて探索すること．

##プログラムでの線形探索
リストにデータを格納して，先頭から順に調べる．
これは，プログラムの構造が非常にシンプルで実装も簡単
⇒ **データの数が少ない場合には有効**な方法

##実装
以下に線形探索のコードとそのときの出力を示す．

#####コード
```python:linear_search.py
"""
2020/12/21
@Yuya Shimizu

線形探索
"""
#線形探索関数
def linear_search(data, target):
    for i in range(len(data)):
        if data[i] == target:
            return i
    return False


if __name__ == '__main__':
    data = [50, 20, 70, 60, 40, 90, 30] #探索を行う対象データ
    target = 40  #探索する値
    found = linear_search(data, target)
    
    if not found:
        print(f"{target} is not found in the data")
    else:
        print(f"{target} is found at data[{found}]")
```
#####出力
```
40 is found at data[4]
```

次いで，Falseが返されるときの出力結果も示す．
#####出力
```
45 is not found in the data
```

##線形探索関数の簡単な説明

`for`文で回すが，戻り値としてデータのインデックスを返したいので，あえて`for i in range(len(data))`としている．また，`for`内で，`return`することで，探索の結果見つからないということを`for`文の外で`return False`と記述するだけで，表現できる．

##感想
線形探索は非常に単純で直感と重なる．その他の探索の基礎となるとは思う．これからの学びがまた楽しみとなった．

##参考文献
Pythonで始めるアルゴリズム入門　伝統的なアルゴリズムで学ぶ定石と計算量
　　　　　　　　　　　　　　　　　　　　　　　　 増井 敏克　著　　翔泳社
【SQL入門】4大命令の全体像（メモ）

# はじめに
現在Web系エンジニアを目指し、転職活動中のmaruoです。
転職へ向けて情報収集していく中で、エンジニア未経験者はSQLの理解が乏しいと伺い、
現在『スッキリわかるSQL入門 第2版』で学習中です！
今回は、第1章〜第2章で学習したことをアウトプットしていきたいと思います。

# データベースの概要
- データベースとは、管理や分析を目的としてさまざまなデータを蓄積したもの。
- データベース管理システム（DBMS）によって管理され、DBMSにSQLを送信することでデータを操作できる。
- 表形式でデータを管理するデータベースをリレーショナルデータベース（RDB）という。
- DBMSのうち、複数の表の形式でデータを取り扱うものをRDBMSといい、ソフトウェア製品として発売されているほか、OSSとして無償で公開されているもの（MySQLやPostgreSQLなど）もある。

# 4大命令の全体像

|命令  |各命令で固有の部分  |絞り込み  |検索結果の加工  |
|---|---|---|---|
|SELECT  |列名　FROM テーブル名  |WHERE  |その他修飾|
|UPDATE  |　　　　　 　テーブル名　SET 列名 = 値  |WHERE  ||
|DELETE  |　　　FROM テーブル名　  |WHERE  ||
|INSERT  |　　　 INTO テーブル名 ( 列名 )   VALUES ( 値 )　  |  ||

- 4大命令のすべてに共通することは、**テーブル名を必ず指定する**こと。
- ` WHERE`句を伴わない` UPDATE`文はほとんど使う機会はない。**` WHERE`句で対象行を指定しないと、` UPDATE`文はすべての行を書き換えてしまう**から。
- ` WHERE`句なしの` DELETE`文を実行する際は、気を付ける！ **` WHERE`句で対象行を指定しない` DELETE`文は全データを削除する**から。
- また、` SELECT` ` UPDATE` ` DELETE` ` INSERT`の4大命令は、以下の2通りに分類できる。

## 分類①（データを書き換えるかどうか）
検索系：` SELECT`
更新系：` UPDATE` ` DELETE` ` INSERT`

- 検索系は、データベースのデータを書き換えず、SQLの実行結果を表として表示する。
- 更新系は、データネースのデータを書き換える、実行結果は基本的に成功か失敗かで、表として表示はされない。
- よって、` ORDER BY`という検索結果の表の行を並べ替える修飾語は、` SELECT`文にしか指定できない。

## 分類②（データがすでに存在しているかどうか）
既存系：` SELECT` ` UPDATE` ` DELETE`
新規系：` INSERT`

- 既存系は、すでにデータベースに存在するデータに処理を行う。
- 新規系は、データベースに存在しないデータについて指定を行う。
- よって、新規系の` INSERT`文では、対象行を指定する` WHERE`句は利用できない。

# 終わりに
まだSQLの全体像しか学習していませんが、4大命令の操作方法を理解しただけで、データを自由に書き換えることができて楽しい！引き続き学習を進めていきたいと思います！

# 参考書
- 『スッキリわかるSQL入門 第2版』株式会社インプレス
CaboChaをPythonにバインディングできない際にすること

# 環境
Ubuntu 20.04 LTS
pyenv 1.2.8
Python 3.7.3
CaboCha 0.60
※コマンドラインから直接CaboChaを動かすことができるが,pythonへのバインディングだけがうまくいかない人向けです.

# 遭遇したエラー
```
$ python
Python 3.7.3 (default, Mar 27 2019, 22:11:17) 
[GCC 7.3.0] :: Anaconda custom (64-bit) on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import CaboCha
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/Jittsu/cabocha-0.60/python/CaboCha.py", line 15, in <module>
    import _CaboCha
ModuleNotFoundError: No module named '_CaboCha'
```
CaboChaのインストールはできており,コマンドラインからの使用はできるが,Pythonから使うことができない状態が起きました.

# 解決方法
pyenvを使用している方が以下のコマンドを実行すると,pythonのパスが使用しているものと異なるため,
ModuleNotFoundErrorが発生する.

```
$ sudo python3 setup.py build_ext
$ sudo python3 setup.py install
$ sudo /sbin/ldconfig
```

代わりに以下のコマンドを実行する.

```
$ sudo $(which python) setup.py build_ext
$ sudo $(which python) setup.py install
$ sudo /sbin/ldconfig
```

```
$ python
Python 3.7.3 (default, Mar 27 2019, 22:11:17) 
[GCC 7.3.0] :: Anaconda custom (64-bit) on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import CaboCha
>>>
```
使えるようになりました.

# 参考
https://teratail.com/questions/190826
AIによる生活習慣病の改善

#はじめに
　私はよく生活のリズムが崩れ、朝起きられなく学校に遅刻したり、お菓子を食べすぎて、夕食が食べられなくなることが頻繁に起こります。このままでは２０代半ばにして体重８０㎏になってしまう！そう感じた私は、最近普段の生活にAIの技術を取り入れることで将来の生活習慣病の改善につながるのではないかと考えこの記事を書きました。

##生活習慣病について
生活習慣病とは、「食習慣、運動習慣、休養、喫煙、飲酒等の生活習慣が、その発症・進行に関与する疾患群」のことを指しており、例えば以下のような疾患が含まれるとされています。

|食習慣|運動習慣|
|:--:|:--:|
|インスリン非依存糖尿病|インスリン非依存糖尿病|
|肥満|肥満|
|高脂血症|高血圧症候群|

|喫煙|飲酒|
|:--:|:--:|
|循環器病|アルコール性肝疾患等|

[引用](https://www.e-healthnet.mhlw.go.jp/information/dictionary/metabolic/ym-040.html)

##AIで生活習慣病の改善
2020年10月15日、東芝が生活習慣病の発症リスクを低減する生活習慣改善ソリューションを提案するAI(人工知能)を開発したと発表した。[参考記事](https://monoist.atmarkit.co.jp/mn/articles/2010/27/news012.html)
この記事では健康診断の結果から５年先のリスクを可視化するものだがこれを応用することで普段の日常生活のデータからAIが将来の生活習慣病のリスクを事前に知らせ、改善に至るまでの経緯まで求めることができるのではないかと考える。
例えば、アプリケーション化とし、その日食べた物の内容や写真を記載したり、その時間に何をしたかを記述することにより、AIがデータを読み取り、その人の５年先の未来を手軽に知ることができるのではないのかと考えている。

###メリット
・手軽に自分自身の情報を知ることができる
・日常の生活の見直しにつながる

##デメリット
・多くのデータを蓄えさせるので漏洩などの防止するセキュリティ対策

#終わりに
 普段の生活習慣が間違っているのか、どう直せばいいのかわからないという人は、youtubeなどでプチ流行りしたモーニングルーティーンなどナイトルーティーンなどを参考にすると良いかもしれません。
[参考 手越](https://www.youtube.com/watch?v=WB-8itwmkZQ)
[参考 ローラ](https://www.youtube.com/watch?v=g0uYNM4NbS4)
#感想
　生活習慣病について自分でもよく知ることができた良い機会だったし、AIの技術が気づくとすごい所まで進歩していることに驚いた。
WordPressで管理画面のサイドバーの並び替える

ワードプレスのテーマtwentytwentyoneを基盤に、管理画面のサイドバーのメニューの順番を並び替える実装を行ったので、備忘録的にこの記事を残す。

# 環境情報

PHP：version 7.3.12
WordPress：version 5.5.3
WPテーマ：twentytwentyone

# 作業

```functions.php
// メニューの並び替え
function my_custom_menu_order($menu_order) {
    if (!$menu_order) return true;
    return array(
        'index.php', //ダッシュボード
        'separator1', //セパレータ１
        'edit.php', //投稿
        'edit.php?post_type=カスタムポストのスラグ', //カスタムポスト
        'separator2', //セパレータ２
        'edit.php?post_type=page', //固定ページ
        'edit-comments.php', //コメント
        'separator-last', //最後のセパレータ
        'themes.php', //外観
        'plugins.php', //プラグイン
        'users.php', //ユーザー
        'tools.php', //ツール
        'options-general.php', //設定
        'upload.php', //メディア (一番下に移動しました)
    );
}
add_filter('custom_menu_order', 'my_custom_menu_order'); 
add_filter('menu_order', 'my_custom_menu_order');
```