OmniAICreator/Qiita-1.07M huggingface dataset:
RecoilをCustom Hookに追加したらJestが失敗するようになった

# はじめに

Reactでログイン処理を行う上でRecoilを使うことになりました
その後、今まで動いていたテストが動かなくなりましたので解決方法をまとめます

# 問題

ログインAPIを叩くカスタムフックを作成して、成功したらログイン済みを表す`isLogin`のステートを`true`にする処理を`Recoil`を使って行いました

すると以下のように書いていたテストが通らなくなりました

```tsx:test.tsx
describe("useSignInlogin", () => {
  it("トップページに遷移すること", async () => {
    const response = {
      data: {
        token: "12345",
      },
    };
    mock.onPost(`http://localhost:8080/sign_in`).reply(200, response);
    const { result } = renderHook(() => useSignIn());

    await act(async () => {
      result.current.login("test@example.com", "password");
    });

    expect(mockedNavigator).toHaveBeenCalledWith("/");
  });
```

エラーをみるとテストが途中で失敗していそうでした

# 解決方法

そこで、Recoilでステートを更新する処理をコメントにするとテストがうまく動いていました

原因は`Recoil`で参照している`atoms`が参照できないことでした
`<RecoilRoot>`を利用して囲んだ箇所で利用できるのですが、カスタムフックだけをテストしているこのコードでは参照先がわからずエラーになります

ですので、テストを実行するカスタムフックを一時的に`<RecoilRoot>`でラップするように修正しました

```tsx:test.tsx
describe("useSignInlogin", () => {
  it("トップページに遷移すること", async () => {
    const response = {
      data: {
        token: "12345",
      },
    };
    mock.onPost(`http://localhost:8080/sign_in`).reply(200, response);
    const { result } = renderHook(() => useSignIn(), {
      wrapper: RecoilRoot, # 追加
    });

    await act(async () => {
      result.current.login("test@example.com", "password");
    });

    expect(mockedNavigator).toHaveBeenCalledWith("/");
  });
```

するとテストが通るようになりました

# おわりに

Recoilを初めて使うときに初心者がつまづきそうなエラーでした
公式ドキュメントを読みましょう

# 参考

https://recoiljs.org/docs/guides/testing/
ソリューションアーキテクト対策_リザーブドインスタンス篇

## はじめに
試験勉強した際のメモを自分用に記事化。
内容は公式やBlack Beltの写経ですので目新しいことはありません:pray:

## 公式のご紹介
とはいえこの記事に迷い込んだ方もいると思いますのでご紹介です。

https://aws.amazon.com/jp/ec2/pricing/reserved-instances/

## スタンダードRIとコンバーティブルRIの支払い属性
#### クラス
スタンダードとコンバーティブルのことをクラスという。
コンバーティブルRIは別のコンバーティブルRIとの交換が可能(途中で属性の変更が可能)。
ただし交換元のRIの価格と同等であることが条件。

#### 期間
スタンダードRIの期間は1年と3年。割引率は1年が40%で3年が60%。
コンバーティブルRIの期間も同じ。1年と３年で、割引率は1年が31%で3年が54%。

→コンバーティブルの方が契約途中で柔軟に変更できるため、割引率が低く設定されている。
スタンダードは変更が柔軟にできないため割引率が高く設定されており、こちらの方がコスト削減できる。

![スクリーンショット 2022-09-15 21.04.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/278897/e23a0ee5-975e-3b84-d797-c7b7aa44ff00.png)

いっつも忘れるけどテナンシーはハードウェアを占有してるかどうか。覚えれる気がしない

#### 支払いオプション
「全額前払い」、「一部前払い」、「前払いなし」の3つの種類の支払いオプションから選択できる。
支払いオプションとして「一部前払い」または「前払いなし」を選択した場合、残額は期間を通じて毎月支払う。

→前払いを選択した方がよりコストを削減することが可能。

## RIの属性
インスタンスタイプとかプラットフォームの説明、テナンシー、アベイラビリティーゾーンのこと。
RIの属性が使用しているインスタンスの属性と一致すると、RIの割引が適用され、予約されているキャパシティが利用できる。

## リザーブド購入オプションがあるサービス
EC2リザーブドインスタンス
RDSリザーブドインスタンス
ElastiCacheリザーブドキャッシュノード
DynamoDBリザーブドキャパシティ
Redshiftリザーブドノード

## おわりに
引き続き追記します！

簡単ですが以上です。
create-react-appで作成したアプリをnpm run ejectするとエラーが発生する

# create-react-appで作成したアプリをnpm run ejectするとエラーが発生する。原因と解決方法

## create-react-appで作成したアプリをnpm run ejectするとエラーが発生すると思います。
#### エラー↓です。
```
Using `babel-preset-react-app` requires that you specify `NODE_ENV` or `BABEL_ENV` environment variables. 」
```
#### この記事とこのエラーの発生原因と回避手段を紹介します。

## 「アプリ作成　→　eject　→　エラー再現　→　解決」の流れで説明します。

## ①create-react-appで'react-app'のアプリを作成する（雛形作成）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2500065/7407c292-73f7-4c2f-b69c-b7d167a96481.png)
```
create-react-app react-app
```
上記のように雛形作成できました。

## ②npm run ejectで設定ファイルなどを展開する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2500065/5c152c2e-e3e9-d87b-213c-3e845024daf8.png)

## ③vs-codeでフォルダを開く
何もせずにしばらく待つとエラーが表示されてしまう。
npm startで通常に起動できますが、やっぱり気持ちわるいよね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2500065/11b68928-08c6-77b5-76f6-a3b4e518b04f.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2500065/4f550cbc-f52e-6e9d-f982-e2c2102e33c3.png)

## ④なぜ「Using `babel-preset-react-app` requires that you specify `NODE_ENV` or `BABEL_ENV` environment variables. 」エラーが発生しているのか
https://github.com/facebook/create-react-app/issues/12070
の検討内容を参照してください。
一言でいうとライブラリの不具合です。
https://github.com/facebook/create-react-app/pull/12467/commits/757a1b1b325d305dc4b721ea4f79ff25421fd65f
で解決できたと思います。
ライブラリの更新で解決できるかと思いますが、現時点の解決手段
として以下の内容をpackage.jsonに追加すること
```
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ],
    "parserOptions": {
      "babelOptions": {
          "presets": [
             ["babel-preset-react-app", false],
             ["babel-preset-react-app/prod"]
          ]
      }
    }
  },
```
するとエラーが解消できました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2500065/2a5ebb36-0658-6034-566d-dc7150502a4b.png)
ゼロからXMLを勉強しなおす2

# はじめに
UiPathでXMLファイルの形式を扱うことが多くなったことをきっかけに、
ゼロからXMLを勉強しようと思ったので、メモとして残します。
# 今回の学習内容
今回勉強した内容です。
## XMLの関連技術
XMLの関連技術は主に以下のようなものがある。
### XSLT(XML Stylehseet Language Transform)
XML文書をXMLを含めたほかの文書に変換するためのルールを記述するための言語。
主にXML→HTMLへの変換に利用される。変換ルールを記述した文書は「スタイルシート」と呼ばれる。
また、XSLT文書に則ってCML文書を変換するプログラムを「XSLTプロセッサ」と呼ぶ。

### DOM(Document Object Model)・SAX(Simple API for XML)
XML文書の解釈や検証を行うプログラムがXML文書をどのように利用するのか、その処理手順を標準化したもの。
DOMでは、XML文書を一つの木構造として処理するのに対し、SAXではXML文書を先頭から順番に読み込んで、要素が現れるたびに対応する処理手順を呼び出す。
DOMは文書の構造を自由にたどれるため、複雑な処理に適している。
しかし、すべてのXML文書をメモリに読み込んで処理するため、大きなXML文書の扱いには注意が必要。

それに対してSAXは、処理のたびに先頭からXML文書を読み込むため時間はかかるが巨大なXML文書を扱ってもメモリに負担がかからないメリットがある。

### XPath
XML文書の、要素や属性などの場所（アドレス）を指定するための言語。
HTML文書のように、アンカーが埋めこまれていなくても、文書中の任意の位置をさし示すことができる。
### XLink(XML Linkng Language)・XPointer(XML Pointer Language)
XML文書にHTMLのような、ハイパーリンク機能を持たせるための書式。
Xlinkは、オブジェクト間のリンクを記述し、XPointerはオブジェクトの参照方法を規定する。XLinkは文書中のどの要素もリンクすることができ、一つのリンクに3つ以上のリンク先を定義することもできる。

### XHTML(Extensible HyperText Markup Language)
HTMLをXMLで定義しなおしたマークアップ言語。
HTMLはWebブラウザメーカー主導で、独自の拡張が続いてきたためHTMLの使用自体に限界が見えてきていた。
そこで従来のブラウザでも問題なく表示ができ、XMLに準拠した文書を作成する言語仕様としてXHTMLが作成された。
XHTMLはHTMLではなくXML文書なので終了タグのない文書は許されない。
また、タグ名がすべて小文字に統一されていたり、XMLベースのMathML
### MathML(Mathematics Markup Language)
XMLを利用した数式を記述するための言語。
1998年にW3C韓国となった、MathMLは2種類のタグを使い、数式の表記と数式の意味を表現する。
### SVG(Scalable Vector Graphics)
Web向けに開発された画像データフォーマット。
SVGでは直線や曲線といったベクトル譲歩王で画像を表現するため、ファイルサイズが小さく、拡大縮小してもデータのクオリティが変化しないといった特徴がある。
### VoiceXML
XMLによる、音声対応型Web記述言語。
コールセンターの音声案内やカーナビなどへの応用が期待されている。
今まではこれらの技術はベンダーごとに別々に開発されていたが、
VoiceCMLに統合されることで、既存データの再利用やほかのシステムとの相互運用が可能となる。
### SOAP(Simple Object Access Protocol)
サーバなどによる、分散オブジェクトの構築に使用されるプロトコル。
SOAPは一般的に下位プロトコルとしてHTTPが用いられるため、サーバに余分なポートを開く必要がないという利点がある。

# おわりに
続きはまた今度書きます。
余談ですが、「自分の調べたことをまとめて、未来の自分や他人に伝わるように咀嚼する」ってすごいパワー使うなと思いました。
【WordPress/SANGO】サブディレクトリサイトのパンくずリストに親要素を追加する

## 状態

- 本サイトを運営（例： hogehoge.com ）
    - オウンドメディアを運営（例： hogehoge.com/magazine/ ）
        - WordPress
        - SANGO（ https://saruwakakun.design/ ）

## やりたいこと

- オウンドメディアのパンくずリスト内に「本サイト」を追加したい。
    - 実施前： ホーム>カテゴリ名>記事名
    - 実施後： 本サイト名>ホーム>カテゴリ名>記事名

## 対応方法・手順

1. WordPressにログイン
1. 「外観」>「テーマファイルエディタ」
1. 子テーマを使っている方は「親テーマ」のファイルを選択

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2531593/d903f991-d8ba-92bb-6438-0c8a987cf52a.png)

1. 「library」内の「functions」の「breadcrumb.php」を選択する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2531593/ad3609b8-3cb5-6c0a-b292-d45049c17a7c.png)


```
// パンくずリストを出力する
if (!function_exists('breadcrumb')) {
  function breadcrumb()
  {
    if ( is_home() || is_admin() ) return; // トップページ、管理画面では表示しない
    $str = '<nav id="breadcrumb" class="breadcrumb"><ul itemscope itemtype="http://schema.org/BreadcrumbList">';

    /*下記を追加する*/
    $str .= '<li><a href="https://' . $_SERVER['HTTP_HOST'] . '">追加する名前</a></li>';

    $str .= sng_bc_item("ホーム", home_url(), "1"); // ホームのパンくずは共通して表示
    if ( is_category() ) {
      $str .= sng_get_bc_category();
    } elseif ( is_tag() ) {
      $str .= '<li><i class="fa fa-tag"></i> タグ</li>';
    } elseif ( is_date() ) {
      $str .= sng_get_bc_date();
    } elseif ( is_author() ) {
      $str .= '<li>著者</li>';
    } elseif ( is_page() ) {
      $str .= sng_get_bc_page();
    } elseif ( is_single() ) {
      $str .= sng_get_bc_single();
    } else {
      $str .= '<li>'.wp_title('', false).'</li>';
    }
    $str .= '</ul></nav>';
    echo $str;
  }
}
```

以上で、無事にサイトタイトルを表示させることができました。

## さいごに

WordPress内のファイル操作は、必ずバックアップ後に実施してくださいね。
【Linux】特定の文字列を含む行に文字を追加する方法

## 特定の文字列を含む行に文字を追加する方法
sedコマンドを使用して以下のように実行すると特定の文字列を含む行の行頭または行末に文字を追加することができます。

- 行頭に追加
```zsh
sed -e "/検索する文字列/s/^/行頭に追加する文字/"
```

- 行末に追加
```zsh
sed -e "/検索する文字列/s/＄/行末に追加する文字/"
```
なんと！Webで！Reactを！ためせる！

TypeScriptでの挙動確認したいな〜とか、それを共有したいな〜って時は[TS Playground](https://www.typescriptlang.org/play)を使ってるのですが、そうなってくるとライブラリを使った時の挙動も試したくなるものです。

Reactなんかがそれですね。
TS Playgroundでimportする機能とか無さそうだしなぁ、と思ってぐぐってみました。

# TS Playgroundから他サービスにExport

[stackoverflow](https://stackoverflow.com/questions/62745934/how-to-import-library-with-typescript-playground)で説明されてたのがこの方法ですね。
TS PlaygroundのExportメニューから「Open in ...」で他サービスにコードを移行するやり方。
CodeSandboxとかに移行してReactをDependenciesに追加するといいですね。

# CodeSandboxでReactを使う

もう上で書いちゃってますけどReactをDependenciesに追加するか、[CodeSandbox](https://codesandbox.io/s/)のテンプレートから「React Typescript」を選ぶといいです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2835840/4329ecb6-6a1a-179e-d085-b327dbd95b83.png)

# まとめ
結局CodeSandboxとかStackBlitz使えばいいんじゃない？って話になるのでしょうか？
TS Playgroundとの比較も楽しいかもしれません。

こういうPlaygroundは記事書くときのサンプル作成にも便利ですよね〜。
色々タイポしがちな僕とかは特に（え
Git とSourceTree

# Git とは？
- コードを修正したときにファイルの変更ポイントがわかるようにする
  
    
- 複数人でコードを書くときに、後で書いたコードによる上書きを防止する
    
    ⇒チーム開発がしやすい
    
- 変更履歴が残るため、最新の状態のファイルがどれかが分かりやすい
    
    ⇒バグ修正などの時に遡って探しやすくなる
# 感想

コードを書くときに必然的に発生するミスを、修正しやすくする便利なツールなんだな、と思った。
# Sourcetreeとは？
   - GitのGUI（感覚的に操作できる）

Macでは、SourceTree導入の際にAppleで弾かれた際は、「システム環境設定」「セキュリティとプライバシー」から実行許可を出せる
雀魂 API リクエスト

:::note warn
**すべて自己責任の上で実行してください。**
:::


雀魂の API リクエストの内容を確認する方法と、API を呼び出す方法をまとめました。



# mitmproxy


https://wikiwiki.jp/majsoul-api/%E8%A7%A3%E6%9E%90%E3%83%84%E3%83%BC%E3%83%AB%E3%81%AE%E6%BA%96%E5%82%99%E3%81%AB%E3%82%83


**mitmproxy** というフリーソフトを使って、API リクエストの内容を確認できます。別途、デコードのために protoc と呼ばれるツールが必要です。


# API Visualizer

https://github.com/Cryolite/mahjongsoul_sniffer/tree/master/api-visualizer

雀魂の API リクエスト内容を可視化する **API Visualizer** です。Docker のインストールが必要となります。


# 牌譜屋


https://github.com/SAPikachu/amae-koromo-scripts/blob/master/majsoul.js


[Node.js](https://nodejs.org/ja/) を使って、**ゲームクライアントを起動せずに** API を呼び出すことができます。[牌譜屋](https://amae-koromo.sapk.ch/)で使用されているコードです。ちなみに、[TypeScript](https://github.com/vg-mjg/majsoul-api/) / [Python](https://github.com/MahjongRepository/mahjong_soul_api) / [Go](https://github.com/oscarfzs/majsoulgo) / [Elixir](https://github.com/chinponya/soulless) で書かれた同じ趣旨のコードがあります。



# 開発者ツール

## リクエスト内容の確認

API リクエストの内容をコンソールに出力するコードです。

```JavaScript
protobuf.rpc.Service.prototype._rpcCall ??= protobuf.rpc.Service.prototype.rpcCall;
protobuf.rpc.Service.prototype.rpcCall = function(api, _, __, req, callback) {
    const _callback = callback;
    callback = (err, res) => {
        console.log(
            "API:", api.name,
            "\nReq:", req,
            "\nRes:", res,
        );
        _callback(err, res);
    };
    this._rpcCall(...arguments);
};
```

```NOTIFY``` メッセージをコンソールに出力するコードです。

```JavaScript
net.Socket.prototype.__handleMsg ??= net.Socket.prototype._handleMsg;
net.Socket.prototype._handleMsg = function(msg) {
    if (msg[0] === net.HeaderType.NOTIFY) {
        console.log(net.MessageWrapper.decodeMessage(msg.slice(1)));
    }
    this.__handleMsg(...arguments);
};
```



## API の呼び出し

次のコードは、```fetchReviveCoinInfo``` という API を呼び出します。復活コインを受け取ったかどうかの確認が可能です。

```JavaScript
var Lobby = app.NetAgent._net_lobby._socket.services_.Lobby;
var req = {};
Lobby.fetchReviveCoinInfo(req, (err, res) => {
    console.log("has_gained:", res.has_gained);
});
```


***

API の仕様については、こちらのページを参照して下さい。


https://wikiwiki.jp/majsoul-api/API%E4%B8%80%E8%A6%A7%E3%81%AB%E3%82%83
【Flutter】paddingとSizedBoxの間隔の話

# Flutter2ヶ月目が考えてみた

column利用時に
paddingでtopを開けた方がいい時と
SizedBoxで高さを調整した方がいい時の話。

## 結論

SizedBoxはbackgroundColorと同じ色で間隔を開けたい時に使う

paddingはbackgroundColorと違う色で間隔を開けたい時に使う

## 要点

その間隔はどのwidgetに持たせるか考える。
UIにも責務がある。

## もっかいよく読んで

テキストを表示したい時、
テキストの上下にスペースがある。

backgroundColorと同じ色の間隔でよければ
[SizedBox]

そうでなければ
[padding]

## 誰向け？

Containerで間隔あけて、
さらにContainerで色付きwidgetをつくる人の為に…

## 最後に
iOSアプリ開発をしています。
主にSwiftですが、最近は熱が入ってきてFlutterも🦾
色々やってます。もし良かったら見てってください。

https://sogablog.net/
新・日本一わかりやすいReact入門【基礎編】をまとめてみる#01

# はじめに
この記事ではYoutubeチャンネル[【とらゼミ】トラハックのエンジニア学習講座](https://www.youtube.com/user/1492tiger)にて投稿されている[「新・日本一わかりやすいReact入門【基礎編】」](https://www.youtube.com/watch?v=XKSYF2aZnkQ&list=PLX8Rsrpnn3IWPoM7-1YPDksRRkamRY25k)をまとめることで自分のReactへの理解を復習し、より理解を深めていきたいと思う。

[フロント学習の最高の教材集](https://qiita.com/KNR109/items/201c133d6eeaabf675a7)にて紹介されていたため発見。
非常にわかりやすくReactの基礎が解説されておりオススメ。

# 0.1 Reactの基礎知識
ここではReactの概念と生まれた経緯が説明される。

### Reactとは
- Facebook社(現Meta社)が開発したUIライブラリ
UI(User Interface)ライブラリ = Webブラウザで見ている画面を作成するためのライブラリ

### 特徴
- コンポーネントという概念を使って画面構成を構築する
コンポーネントとはUI(見た目)+機能(動画を再生、停止させるなど)

### Reactの目指す地点
React以前の課題は、**DOMの直接更新によるHTMLの再描画負荷が高い**ことだった。

説明:
1. ブラウザはHTML文書を画面に描画する機能を持っている
1. HTMLの要素をjavascriptなどのプログラミング言語で変更したい場合**そのままでは直接変更できない**(HTML自体はただの文書のため)
1. HTML要素を操作するために **DOM(Document Object Model)** という仕組みを利用している
1. **DOMはHTMLにアクセスする窓口**のようなもので、プログラミング言語とHTMLの仲立ちをしてくれる
1. DOMを直接変更すると**複雑で重い処理が裏側で走るためブラウザに負荷がかかる**

上記を解決するため**仮想DOM**を使用する(以下は勝手な解釈)。
```
従来:   javascript ->           DOM -> HTML
React: javascript -> 仮想DOM -> DOM -> HTML
```

説明:
1. DOMを**javascriptのオブジェクトとして表現**する
1. DOMを操作したい場合、**まず仮想DOMを変更**する
1. 仮想DOMの変更処理が完了したら、仮想DOMとDOMの**差分に対して変更処理をDOMに促す**
1. DOMは変更処理をブラウザに反映する

つまりこういうことだろうか。
- DOMを直接変更すると最終的なDOM状況に至るまでの過程で余分な再描画処理が走る
- 仮想DOMを用いることで処理が完了した時点の最終的な差分のみをDOMに伝えられる
- 結果**ブラウザへの負荷が従来より小さくなる**
Burp Suiteで30Xのリダイレクトをバイパスする

ステータスコード302とかでリダイレクトされないようにする。

# シチュエーション

今、`http://10.10.10.228/portal/php/files.php`のページに行こうとすると、302のステータスコードで`index.php`に飛ばされてしまう：

![redirected.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2659122/6966b3ee-2572-8b9e-598d-526dd68dd1e0.png)

リダイレクトさせずに、`files.php`に行きたい。

# Burp SuiteのMatch and Replace

Burp Suiteにて、Proxy > Options > Match and Replaceと選択する：
![math_n_replace.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2659122/9f8be28c-3dde-d636-dc58-0d5a3edd3483.png)

「Add」をクリックして次のように新規ルールを設定する：
![rule.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2659122/322f3e24-07d7-15e3-1540-2f6323cbe3f9.png)

今回は302をバイパスするのが目的なので「302 Found」としたが、301または302の両方ともバイパスしたいなら「30[12] Found」と指定したのち、左下にある「Regex match」のボックスにチェックを入れればよい。

再び`files.php`へアクセスするとリダイレクトされずにそのページが表示された：
![ok.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2659122/e61f5f68-e219-ea25-8a6c-9f49242d2b2e.png)
【Java/Kotlin/JPA】entityをnullセーフにしたい

こんにちは。こまつです。

概要
---
Java8からJavaにもnullセーフが入りました。optionalを使えばヌルポがなくなります。
とか言いながら、Java+SpringDataJPAではoptionalをマッピングできません。カスですね。
Kotlinならどうなるんでしょうか。

前提
---
nullセーフとはヌルポになりうるコードをコンパイルエラーにしてくれるやつです。
Entityは特にnullセーフにする重要度が高いです。

```nulセーフサンプル.java
String randomStr = new Random().nextBoolean() ? "わーい" : null; // nullかも知れない文字列
Integer length1 = randomStr.length(); // 1/2でヌルポ
Optional<String> str = Optional.ofNullable(randomStr); // null知 文字列型定義
Integer length2 = str.length(); // コンパイルエラー
Integer length3 = str.map(s -> s.length()).orElseGet(() -> 0); // コンパイルOK(nullであればlength=0)
```


Java+JPAのOptionalはこうしたい。けどできない
---
肝心のOptional部分でJPAのエラーとなります。

```javaでjpa.java
@Entity
@NoArgsConstructor
@AllArgsConstructor
@Setter
@Getter
public class Post {
  @Id
  private Long id;
  @Column(length = 100, nullable = false)
  private String title;
  @Column(length = 1000, nullable = true) // nullを許容
  private Optional<String> body; <----こうしたいがエラーになる
}
```

のでJava+JPAではこうするしかない(たぶん)
---
AllArgsConstructorを諦めてコンストラクタ、アクセサを自前で実装しています。

```sono1.java
@Entity
@NoArgsConstructor
@Setter
public class Post {
  @Id
  private Long id;
  @Column(length = 100, nullable = false)
  private String title;
  @Column(length = 1000, nullable = true) // nullを許容 
  private String body;

  public Post(Optional<Long> id, String title, Optional<String> body) {
    this.id = id.orElseGet(() -> null);
    this.title = title;
    this.body = body.orElseGet(() -> null);
  }

  public Long getId() {
    return id;
  }

  public String getTitle() {
    return title;
  }

  public Optional<String> getBody() {
    return Optional.ofNullable(body);
  }
}
```

Kotlin+JPAなら
---
普通に実装すればnullセーフのプロパティを持てます。


```Entity.kt
@Entity
data class Post(
  @Id
  val id: Long,
  @Column(length = 100, nullable = false)
  val title: String,
  @Column(length = 1000, nullable = true) // nullを許容
  val body: String?, <---- JavaのOptional<String>と等価
): Serializable
```


実際に動くか登録してみます。
```実際に登録してみる.kt
val post = Post(1, "nullじゃない", "内容！")
postRepository.save(post)
val post2 = Post(2, "nullなんです", null)
postRepository.save(post2)
```


想定通りに登録されているようです。取得も問題ありませんでした。
![スクリーンショット 2022-09-13 12.15.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1342736/58c1259f-2fb6-ba1c-1ba4-621d8bee730f.png)

まとめ
---
この問題はJavaに対する大きな不満点でしたが、Kotlinでは解消されているようです。
FactoryBotの導入と使い方の基本 [RSpec]

FactoryBotの使い方や導入方法をメモしておきます。
# FactoryBotを使うには
### 1, gemのインストール
```
gem "factory_bot_rails"
```
bundle installを実行する。
### 2, ジェネレートする
```
rails g factory_bot:model モデル名
```
`spec/factories`というディレクトリが生成される。その中に`モデル名s.rb`というファイルが生成される。このファイルにテストデータを作成していく。
# FactoryBotの使い方（例としてUserモデルを扱う）
### サンプルデータの作成
```ruby
FactoryBot.define do
	#この中に書いていく
  factory :user do
		first_name { "aaa" }
    last_name { "aaa" }
		email { "aaa@example.com" }
		password { "password" }
	end
end
```
### サンプルデータを呼び出す
```ruby
user = FacrtoryBot.build(:user)
```
### オーバーライド
以下は性をnilに上書きした。
```ruby
FactoryBot.build(:user, last_name: nil)
```
### シーケンス
ユニークな値を作りたい時に便利。
```ruby
factory :user do
	first_name { "aaa" }
  last_name { "aaa" }
	sequence(:email) { |n| "sample#{n}@example.com" }
	password { "password" }
end
```
Userオブジェクトがcreateまたはbuildされるたびにんが１づつ増えるので、上記の場合emailは必ずユニークな値になる。
### 関連付け
前提：UserモデルとPostモデルが存在し、一対多の関係。
```ruby
factory :post do
	title: { "旅行" }
  content: { "めっちゃ楽しかった〜〜" }
	association :user
end
```
これでPostオブジェクトも作られる。（Postオブジェクトのテストデータを作成する時に、紐づくuserを新しく作っているので注意。）
### 関連付けの際にclass_nameを使っている場合
例えば以下のようにclass_nameを定義している場合。posterは投稿する人という意味。
class_nameについてはこちら。([https://qiita.com/wacker8818/items/eccdf0a63616feb14a70](https://qiita.com/wacker8818/items/eccdf0a63616feb14a70))
```ruby
class Post < ApplicationRecord
	belongs_to :poster, class_name: 'User', foreign_key: :user_id
end
```
### クラスメソッドにより生成される魔法のマッチャ
以下のようなクラスメソッドを定義しているとする。（Userオブジェクトの年齢が１３歳未満であればtrueを返すメソッド。）
```ruby
class User < ApplicationRecord
	def kid?
		age < 13
	end
end
```
すると`be_kid`というマッチャをRSpecが自動生成してくれる。実際に使ってみる。
```ruby
it "１２歳はまだ子供である" do
	FactoryBot.build(:user, age:12)
	expect(user).to be_kid
end
```
### テストデータの継承
2つ目以降のuserを作る時には`trait`メソッドを使うことで簡単に作れる。
```ruby
factory :user do
	first_name { "aaa" }
  last_name { "aaa" }
	sequence(:email) { |n| "sample#{n}@example.com" }
	password { "password" }

	trait :second do
		first_name { "bbb" }
	  last_name { "bbb" }
	end
end
```
traitで定義したテストデータを呼び出すときは以下のように書く。
```ruby
user_second = FactoryBot.build(:user, :second)
```
これでbbb bbbといったユーザーが作られた。
### コールバック
RSpecでもbefore_action的なことができる。
以下の例ではコールバックを使って、Userがオブジェクトを作った直後に3つのPostオブジェクトを自動生成する。

### 参考にした記事
以下の書籍。
https://leanpub.com/everydayrailsrspec-jp
ActionController::RoutingErrorの凡ミス

# ログイン機能のつけている最中に。
今回は、ログイン機能を実装しようとしたところ、ログインボタンを押しても、画面も動かず、ターミナルにしれっとエラーが出てくるだけで、意外と時間を食ってしまいました。

## 読まずに進めるのは危険
エラーが出てしまうと、どうしても拒否反応が出てしまって、読む気にならない時ありますよね。私もそうでしたし、たまにそうです。
しかしながら、エラーが出るということは、後で大きなエラーになる前に気づけたということなので、ポジティブに行きましょう！笑

### ソースコード
```ruby:config/routes.rb
Rails.application.routes.draw do
  get '/login', to: "sessions#new"
  post "/login", to: "session#create"
  namespace :admin do
    resources :masters
  end

  get 'master/index'
  root to: 'top#index'
  resources :users

end

```

```ruby:masters_controller
class Admin::MastersController < ApplicationController
  before_action :login_required
  before_action :authenticate_user

  def new
    @master = Master.new
  end

  def create
    @master = Master.new(master_params)

  end

  def show
  end

  def index
    @users = User.all
  end

  def master_params
    params.require(:master).permit(:name, :email, :admin, :password, :password_confirmation)
  end

  def login_required
    redirect_to login_path unless current_user
  end

  def authenticate_user
    if @current_user == nil
      redirect_to login_path, notice: "権限がありません。"
    end
  end
end

```

```ruby:sessions/new.html.slim
h1.fw-bolder.border-bottom.border-dark.border-3.title_border_mr_7 ログイン

= form_with scope: :session, local: true do |f|
  .form-group
    = f.label :name, "名前"
    = f.text_field :name, class: "form-control", id: "session_name"
  .form-group
    = f.label :password, "パスワード"
    = f.text_field :password, class: "form-control", id: "session_password"
  = f.submit "ログインする", class: "btn btn-primary my-5 mx-auto d-flex"

```

主に現場Rails5を参考にして進めていました。

### 出てきたエラー
```
Started POST "/login" for ::1 at 2022-09-13 18:32:51 +0900
  
ActionController::RoutingError (uninitialized constant SessionController

      Object.const_get(camel_cased_word)
            ^^^^^^^^^^
Did you mean?  SessionsController

            raise MissingController.new(error.message, error.name)
            ^^^^^):
  
Started GET "/login" for ::1 at 2022-09-13 18:32:51 +0900
Processing by SessionsController#new as HTML
  Rendering layout layouts/application.html.slim
  Rendering sessions/new.html.slim within layouts/application
  Rendered sessions/new.html.slim within layouts/application (Duration: 1.2ms | Allocations: 705)
  Rendered layout layouts/application.html.slim (Duration: 6.5ms | Allocations: 2487)
Completed 200 OK in 34ms (Views: 9.1ms | Allocations: 2753)
```

入力された値をpostで"/login"に投げれてはいるが、何やら、ルーティングが間違っているよう。

#### 解決策
とにかく、どこの何がエラーになっているのかを特定するべし。

`uninitialized constant SessionController`こちらを直訳すると、「定義されたクラスを読み込むことができない。」

sessioncontrollerが読み込まれていないよう...
？？
session「s」controllerだよな？
ルーティングを見返してみると、createアクションのコントローラーが単数形に...

複数形であるコントローラーを単数形でかいてしまったがための、エラーだったのですね...

単なる凡ミスですが、エラーを正しく読むことができればエラーは意外と簡単に見つけることができます。
私自身まだまだですが、みなさんエラーと仲良くなっていきましょう！
mimemagicのbundle installに手間取った件

## 起きたこと
しばらく昔に触っていたローカルでそのまま動かしていたRuby on Railsプロジェクトを久々に動かそうと`bundle install`したら、以下のエラーが。

```terminal
Gem files will remain installed in /Users/hoge/projects/hogehoge/vendor/bundle/ruby/2.7.0/gems/mimemagic-0.3.9 for inspection.
Results logged to /Users/hoge/projects/GitHub/hogehoge/vendor/bundle/ruby/2.7.0/extensions/x86_64-darwin-21/2.7.0/mimemagic-0.3.9/gem_make.out

An error occurred while installing mimemagic (0.3.9), and Bundler cannot continue.
Make sure that `gem install mimemagic -v '0.3.9' --source 'https://rubygems.org/'` succeeds before bundling.

In Gemfile:
  breadcrumbs_on_rails was resolved to 4.0.0, which depends on
    rails was resolved to 6.0.3, which depends on
      actionmailbox was resolved to 6.0.3, which depends on
        activestorage was resolved to 6.0.3, which depends on
          marcel was resolved to 0.3.3, which depends on
            mimemagic
```

## やったこと

### その１ gem install
なんか昔も同じことで引っかかったなぁと思いつつ、言われた通りに個別に`gem install`
```terminal
$ gem install mimemagic -v '0.3.9' --source 'https://rubygems.org/'
Building native extensions. This could take a while...
Successfully installed mimemagic-0.3.9
Parsing documentation for mimemagic-0.3.9
Done installing
```

成功するやん、と思ってもう一回`bundle install`
→おなじエラーで失敗
ワンアウト!

### その2 shared-mime-infoの再インストール
ググってみると以下のような記事が
https://techblg.app/articles/handle-error-occurred-while-installing-mimemagic/

ググった感じ、同じエラーに遭遇したほとんどの先人たちが下記コマンドで`shared-mime-info`を入れ直して`bundle install`しなおせば解消するって言ってる
```terminal
$ brew install shared-mime-info
Warning: shared-mime-info 2.2 is already installed and up-to-date.
To reinstall 2.2, run:
  brew reinstall shared-mime-info
```
もう入ってるよーとのこと。
念の為resintallして`bundle install`
```terminal
$ brew reinstall shared-mime-info
$ bundle install
```
→おなじエラーで失敗
ツーアウト！


### その3 一度bundle installしたGemを全て削除して再インストール
エラー文をもう一度読み直すと以下の記載が

```terminal
Gem files will remain installed in /Users/hoge/projects/hogehoge/vendor/bundle/ruby/2.7.0/gems/mimemagic-0.3.9 for inspection.
Results logged to /Users/hoge/projects/GitHub/hogehoge/vendor/bundle/ruby/2.7.0/extensions/x86_64-darwin-21/2.7.0/mimemagic-0.3.9/gem_make.out
```

エラー文的に、残ってる(remain)gemがイケてなさそうだなぁと思って一度`vendor/bundle`を吹っ飛ばして、再度`bundle install`

```terminal
$ rm -rf vendor/bundle
$ bundle install
```

成功して、再びプロジェクト動くようになりました。Happy Smileツーベースヒット!🤗

。。。
時間ある時Dockerで動かせるようにしようと思いました。
【初心者向け】moduleの使い分け

# 執筆経緯
moduleは色々な使い方ができるのは知っていたのですが具体的にどうやって使えばいいのかを
勉強していて気付いたことを共有したいと思い執筆に至りました。

# 対象の読者
- ruby初心者の方
- moduleの使い方がわからない方

上記の方たちに向けて記事を書いていこうと思います！

# moduleの使い方その1
moduleは色々な使い方がありますがまず紹介するのは名前空間としての使い方です！

```ruby:
class OtukaTakashi
  def initialize(from,age)
    @from = from
    @age = age
  end
end

class OtukaTakashi
  def initialize(job,talent)
    @job = job
    @talent = talent
  end
end
```
上記の様に別々に定義されて使い方も異なるclassがあります。
それぞれ違うところで1個のclassのみが使われている内はいいですがある日一緒に使うことになったら
どうやって区別すればいいのか困りますよね？
そんな時にmoduleの出番です！！

```ruby:
module AbeCabinet
#これはAbeCabinetに属するclass 
  class OtukaTakashi
    def initialize(from,age)
      @from = from
      @age = age
    end
  end
end

module DiveIntoCode
#これはDiveIntoCodeに属するclass 
  class OtukaTakashi
    def initialize(job,talent)
      @job = job
      @talent = talent
    end
  end
end
```
moduleの下にclassを定義することでmoduleに属するclassという意味になるので名前の衝突は発生しなくなります。
上記のclassを参照する時は
```ruby:
AbeCabinet::OtukaTakashi.new(osaka,58)
DiveIntoCode::OtukaTakashi.new(unemployed,magic)
```
というようにmodule::classという書き方で参照することができます！！

:::note info
上記の使い方だけでなくクラスの
グループやカテゴリーを分けるときにも
名前空間としてmoduleが使用されます。
:::
# moduleの使い方その2
moduleはincludeやextendすることでインスタンスメソッドやクラスメソッドとして呼び出すことができますが
module単体でメソッドを定義したい、というケースもあると思います。
そんな時は

```ruby:
module Pokemon
  def self.name(text)
    puts "#{text}"
  end
end
```
上記の様に記述することで
```ruby:
Pokemon.name('pikachu')
```
として呼び出すことができるようになります。具体的に言うとmodule名.method名という形で記述すると呼び出すことができます！！

:::note info
module_function :メソッド名とすることでミックスインとしても特異メソッドとしても
使用できるように定義することができます！
またclassと同じように定数を定義することができます！
:::


# 終わりに
使い方を紹介する時の例はそれぞれの使い方のみを例として挙げましたが実際はそれぞれの使い方を組み合わせて
使われることもあるので覚えておきましょう！！
初心者が初心者に向けて書いたので間違いなどがあると思いますがその際は優しく教えて頂けると助かります！
Nuget.Server をクラウド上に配置して Nuget パッケージを公開する

# はじめに

本稿は、Visual Studio で NuGet.Server をクラウド上に配置して、自分で作った Nuget パッケージを公開する方法を紹介します。
Nuget というのは、Microsoft がサポートする .NET (.NET Core を含む) のコード共有メカニズムのことです。

# Nuget.Serverの配置方法

`NuGet.Server` というライブラリを利用してノンコーディングで作成できます。

詳しい手順は以下のページを参照ください。

https://docs.microsoft.com/ja-jp/nuget/hosting-packages/nuget-server

上記手順の通りに実行すると、私の環境(Visual Studio 2022 Version 17.3)では、下図のようにWebconfigに `<compilation debug="true" targetFramework="4.6"/>` という行が2つ作られて重複するエラーが発生するため、一方を削除します。  
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/403606/87ea925c-c251-1ec5-e6b4-431758e00651.png)

あとは、Visal Studioのプロジェクトを選択時のコンテキストメニューから[発行]を実行することで、Nuget.Serverを配置できます。

# Azure に配置する例

Azure App Service の Free のエディションでホスティングできます。App Service の詳細は以下を参照ください。

https://azure.microsoft.com/ja-jp/pricing/details/app-service/windows/  

下図はApp Serviceへの接続例です。  
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/403606/302919a1-473f-db75-289f-b92ebeb0dfc4.png)


# パッケージの公開

nugetパッケージを公開する手順は以下の「パッケージを外部からフィードに追加する」の章を参照ください。  

https://docs.microsoft.com/ja-jp/nuget/hosting-packages/nuget-server#adding-packages-to-the-feed-externally


# まとめ

この方法で、自分が.NETで作ったNugetパッケージを、クラウド上に配置して、それをユーザーにダウンロードしてもらう事ができます。

ちなみに私は、エンジニアリングマネージャーとして「ハピネスチームビルディング」と名付けたチームの皆で主体的に楽しく成長する活動を実施しています。
ITエンジニア向け情報誌「Software Design」で連載している内容を以下で公開していますので、よろしければ、そちらも参照ください。

https://note.com/kojimadev/n/nbe692f9b3cec

Twitterでも開発に役立つ情報を発信しています → [@kojimadev](https://twitter.com/kojimadev)
paizaラーニング レベルアップ問題集 ソートメニュー応用編 JavaScript スケジューリング

スケジューリング (paizaランク B 相当)

https://paiza.jp/works/mondai/sort_advanced/sort_advanced__problems_speedup_step6

解いてみました。

キャンペーンの参加数を最大化するには、
終了日が早い順にソートをすれば良いです。

あるキャンペーンが終わって、次のキャンペーンに参加する条件は、
あるのキャンペーンの終了日と次のキャンペーンの開始日を比較すれば良いです。

C++ の場合の模範解答を参考にJavaScriptでコードを書いてみました。
```javascript:JavaScript
const fs = require("fs");
const input = fs.readFileSync("/dev/stdin", "utf-8").trim();
const lines = input.split("\n");
//キャンペーンは n 回開催
const n = Number(lines[0]);

//キャンペーン開始日・終了日の配列
let campaign = [];
for (let i = 1; i <= n; i++) {
    campaign.push(lines[i].split(" ").map(Number));
}
//キャンペーン終了日の早い順にソート
campaign.sort((a, b) => a[1] - b[1]);

let participated_campaigns = 0;//参加できるキャンペーン日数
let campaign_lastday = 0;//あるキャンペーンの終了日
for (let i = 0; i < n; i++) {
    //あるキャンペーンの終了日より、開始日が早ければ
    if (campaign_lastday < campaign[i][0]) {
      participated_campaigns++;//参加できる
      campaign_lastday = campaign[i][1];//終了日を更新
    }
}
console.log(participated_campaigns);
```
また、メソッドを使って、キャンペーン開始日・終了日の配列をソートするところを、まとめて以下のようにも書けます。
```javascript:JavaScript
//キャンペーン開始日・終了日の配列
const campaign = lines.slice(1)
    .map(line => line.split(" ").map(Number))
    //キャンペーン終了日の早い順にソート
    .sort((a, b) => a[1] - b[1]);
```
Sample App of Flutter3 x MySQL8 with mysql_client　4

# ついにListView化に成功　

![スクリーンショット 2022-09-13 17.33.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1646810/b12c833d-0dc3-f84e-6401-f81b16c320f9.png)



[総コードはこちら](https://github.com/dongri727/sample_app_flutter_mysql8)
[元の記事はこちら](https://qiita.com/dongri727/items/412b97eed4943006a0a0)


 FlutterのTextFormFieldに書き込まれた文字列をつかって、SQL文を書く、という作業にはだいぶ慣れてきた。でも、MySQLから取得したデータをFlutterで表示する、がなかなかできなかった。Firestoreから取得して表示、のように、サンプルがいっぱいあるわけではない。いっぱいどころか、この時代の、この広いネット上の、どこにもそんなサンプルはないのだ。それはそれで、ある意味、とてもおもしろい。　

　ということで、メンターさんに助けられながら悪戦苦闘した成果がこちら。

## Listを定義。　
```
  var targetColumn1 = '';
  var targetColumn2 = '';
  var searchTerm1 = '';
  var searchTerm2 = '';
  var logique = '';

  List<Map<String, String>> displayList = [];
```

varで定義しているのは「Flutterで書いてMySQLに送る」文字列。以下のように使って、
- column1の値がterm１であるか、またはcolumn２の値がterm２であるデータを年代順に表示

というSELECT文を書いている。年代順に表示するためには、year のデータがint型でなければならない。文字列型だと「最初の文字」の順番で並んでしまうので例えば1357,23,456,8みたいなことになる。　

```
"SELECT * FROM timeline WHERE $targetColumn1 = '$searchTerm1' $logique $targetColumn2 = '$searchTerm2' ORDER BY year ASC"
```

一方、Listには、MySQLから取得したデータを蓄積する。

## Listに蓄積　statefullWidgetに適用　

 MySQLから取得したデータをリスト化している。ミソは変数名をシングルクォートで囲っているところ。実はなんでそうするのか、まだよくわかっていない。　
　これは、columnの０列目から順番に名前を付けた形になっている。なので皆さん、好きに命名してください。

```
    List<Map<String, String>> list = [];
    for (final row in result.rows) {
      final data = {
        //'selectedId': row.colAt(0)!;
        'selectedYear': row.colAt(1)!,
        'selectedName': row.colAt(2)!,
        'selectedCountry': row.colAt(3)!,
      };
      list.add(data);
    }

    setState(() {
      displayList = list;
```

## データをListTileに載せる。　

　ここの表記法もずいぶん悩まされたが、できあがってみると、なるほどな、と思ったりもする。いや、それはかっこつけがすぎるか、ほんとはまだよくわかっていない。


```
                  child: SingleChildScrollView(
                    child:
                    Column(children: displayList.map<Widget>((data) {
                      return Card(
                        child: ListTile(
                          leading: Text(data['selectedYear']?? ""),
                          title: Text(data['selectedName']?? ""),
                          trailing: Text(data['selectedCountry']?? ""),
                        ),
                      );
                    }
                    ).toList()
                    ),
              ),
```

## スマホの画面が小さいので

　検索窓５つと、不特定多数のListTile、何度も黒黄の縞模様エラーに悩まされながら、配置を確定。いくつでも表示して、スクロールで見られます。

　でも、bottomNavigationBarはまだついてません。今日はここまで。
はじめてのUnity

# Unityのインストール
## 1.UnityHubのインストール
私が手探りで実施した際は[こちら](https://store.unity.com/compare-plans)から実施しましたが、調べると以下公式サイトに丁寧な案内がありました。
インストールはかなり時間がかかりました。

https://forpro.unity3d.jp/tutorial_cat/unity-install/

## 2.プランについて
自己学習、スキルアップが目的ですので、無料のPersonalを選択。
## 3.PCのスペックについて
システム要件は[こちら](https://docs.unity3d.com/Manual/system-requirements.html#editor)
私の場合は自宅にあった家庭用PCのため、ビルドなどはかなり待たされますが、簡単なプロジェクトであれば今のところ問題なく使えています。今動作している環境は以下です。
 - Widnwos11
 - Intel(R) Core(TM) i7-6500U CPU @ 2.50GHz   2.59 GHz
 - 8.00 GB

## 4.学習に際して初心者が感じたこと
#### Unityバージョンは合わせた方がよいか
チュートリアルなどのデモはWebで豊富に入手できます。とりあえず感覚を掴みたい、サクサク進めたい場合はUnityバージョンを揃えるのが良いかと。
最新のUnityで行うと細かいところの操作方法や機能が変更されているので、探したりするのに時間を要しますが、私は最新状態を把握するためにも、極力最新バージョンを用いるようにしています。

#### 日本語パッケージの是非
UnityHub上で日本語パッケージをインストールすることで、日本語化が可能です。
英語力が最低レベルの私にとってUnityのGUIが日本語になるのは大変助かりましたが、いざ学習していくと表現が分かりにくかったり、チュートリアルは大抵英語ですので対応付けが難しかったりで、結局は英語に戻しました。

# 次回
次回はUnityの基本操作が学べるチュートリアルの実践について記録していこうと思います。
Flow vs LiveData


どれにします? どの流れにします?

![スクリーンショット 2022-09-13 17.29.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/588914/578bb333-c6b1-7ae4-3beb-d0f8a5c2bc2a.png)


https://twitter.com/maochanz/status/1569603511511564294

https://twitter.com/gamesdev_Dan/status/1278271269151158274
Ubuntu22.04でphpenv使おうと思ったらopensslのバージョン違いでbuildできない件

macの対策はたくさん記事が引っかかるけどubuntuの情報はあまり無いので同様の現象で詰まった方のために残しておきます。
掲題ですが、phpenvとphp-buildをインストールしたubuntu22.04で、php7.4.30や8.0.23をインストールしようとした所、下記のエラーが出ました。下のログは8.0.23をインストールしようとした場合のログですが、7.4.30でも同様のエラーが出ていた筈です。私の環境では7.4.30でも同様の対処でbuild通る様になりました。

```bash
-----------------------------------------
/tmp/php-build/source/8.0.23/ext/openssl/xp_ssl.c:1240:9: warning: ‘DH_free’ is deprecated: Since OpenSSL 3.0 [-Wdeprecated-declarations]
 1240 |         DH_free(dh);
      |         ^~~~~~~
In file included from /usr/include/openssl/dsa.h:51,
                 from /usr/include/openssl/x509.h:37,
                 from /usr/include/openssl/ssl.h:31,
                 from /tmp/php-build/source/8.0.23/ext/openssl/xp_ssl.c:31:
/usr/include/openssl/dh.h:200:28: note: declared here
  200 | OSSL_DEPRECATEDIN_3_0 void DH_free(DH *dh);
      |                            ^~~~~~~
-----------------------------------------
```

どうもOpenSSLのバージョン違いでbuildコケてる様だ、ということで、opensslの1系をインストールしなければならないということまでは分かったのですが、1.1をソースからbuildして`phpenv isntall 8.0.23 --with-openssl=dir`みたいなオプションを付けても同様のエラーが出続けて、なんでやねんってなってハマりました。

そこで色々見てみた所、こんなissueが出てました。やっぱ皆困ってるんですね・・・

https://github.com/php-build/php-build/issues/718

で、このissueを読むまで知らなかったのですが

* php-buildにはopenssl 1.0をインストールすることができるbuild-openssl-1.0.shが付属している
* --with-opensslは機能しない

ということが分かりました。そこで該当のshellを走らせてopenssl1.0をインストールした後、オプションを変更して

```bash
PKG_CONFIG_PATH="$PKG_CONFIG_PATH:/usr/local/opt/openssl@1.0/lib/pkgconfig" phpenv install 8.0.23
```

で通る様になりました。めでたし。

まあ実は`--with-openssl`が機能しないのはphp-buildのmanページに書いてあったんですけどね。ちゃんとman読めってことですかねすみません。

https://github.com/php-build/php-build/blob/master/man/php-build.5

```
with_openssl
Adds --with-openssl to the list of configure options. Legacy command, which is left in for backwards compatibility with definitions written before --with-openssl was moved to the default configure options.
```
Kaggleの既読NoteBookの色を変えるChrome拡張機能を作った

皆さんこんにちは。題名の通り、Kaggleの既読NoteBookの色を変えるChrome拡張機能を開発してみました。

## 背景
KaggleのCompetitionページには日々新しいNoteBookが投稿されます。非常に有益な知見が多く参考になるのですが、如何せん投稿数が多く、どれを読んだことがあって、どれを読んだことがないかを把握するのが難しいのが現状だと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/385803/c5813687-8f3d-61fe-b57b-b23722ba1812.png)

Kaggle側で既読のStatusを変える機能を実装して貰えればいいのですが、待っていられませんよね。というわけで、既読したNoteBookの色を変えるChromeの拡張機能を簡単に開発してみました。

## 先駆者
実はKaggle関連の拡張機能を調べていると[kaggle watch](https://chrome.google.com/webstore/detail/kagglewatch/bnhfgkjmniihijokbjbikfogiegopkbc?hl=ja)というものをみつけました。しかし、昔に開発されていたもののようで、今は思ったような動作が確認できませんでした...。

## 完成品
以下はTitanicのCompetitionページでのデモ動画になります。
※Notebookや履歴の数が多くなるほど反映に時間がかかるかもしれません

<iframe width="560" height="315" src="https://www.youtube.com/embed/rSbg0NNLRIk" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

## 使い方
[GitHub](https://github.com/ryuki999/Kaggle-NoteBook-Status)からリポジトリをダウンロード、解凍し、Google Chromeの「パッケージ化されていない拡張機能を読み込む」から本フォルダを読み込み、機能をONにするだけで使用可能です。

動作環境は開発環境であるWindows10とGoogle Chromeを想定しています。Chromeの閲覧履歴にアクセスして過去の既読を確認しており、Macでも同様に動くかは不明です。

## 最後に
Kaggle NoteBookは大切な知見なので、丁寧に読み込みたいですよね。非常に簡素な機能ですが、皆さんのKaggle Lifeの助けになればと思います。
PowerAutomate チェックアウト、チェックイン必須なSharePoint上のファイルを扱うときの注意点

# はじめ
PowerAutomateでチェックアウト、チェックイン必須なSharePoint上のファイルを扱うときに、沼ったのでここに対処法を記す

# 現象
SharePoint上のExcelファイルをチェックアウトしたあとに、行を削除しようとしたときに以下のエラーメッセージが出力された
> 値を取得できませんでした。動的な呼び出し要求が次のエラーで失敗しました: {
> "status": 403,
> "message": "The request is forbidden by Graph API. Error code is 'EditModeWorkbookCheckedOutRequired'. Error message is ・・・

# 原因
対象のファイルがSharePointのライブラリ設定でチェックアウト、チェックインが必要なファイルであり、PowerAutomateでそのようなファイルを扱うときは、チェックアウトをした状態で変更しなくてはならないため

※対象のファイルをチェックアウトするフローが途中にあったとしてもエラーになる

# 対処法
対象ファイルを手動でチェックアウトし、それからPowerAutomateのフローを完成させ保存し、チェックアウトを破棄する（チェックインするとExcelにロックがかかったままとなってしまうことがあるため、原則チェックアウトを破棄したほうが良い。）。

ちなみに誰かがチェックアウトしているときに、チェックアウトのフローを流すとエラーが起きるので、例外処理するかチェックアウト、チェックインを必須ではないようにするのがおすすめ。

# おわり
先輩に教わって何とか解消したものですが、私自身結構沼ったので皆さんお気を付けください。
python3.14がC++より早くなるらしい？

海外サイトを見ていてこんな見出し記事がありました

https://towardsdatascience.com/python-3-14-will-be-faster-than-c-a97edd01d65d

なんとなく紹介

後半に画像があって、どんどん実行速度が速くなる図がある

技術力が全くない40代初心者だからよくわからないけれど、誰か解説記事書いて欲しい

pythonがんばぁりぅれええ
【Golang】Go言語で簡易的なcatコマンドを作成してみた

# はじめに
Go言語を勉強する中で簡易的なcatコマンドを作成したのでまとめます。
Go言語に慣れるための練習として書いているため、エラー処理などは思いついたまま書いています。よりGo言語らしい(？)書き方があると思いますが、今回は気にせず書いています。
簡易版ということで、オプションは`[-n]`と`[-b]`の２つだけを実装しています。

# コード
今回はオプション機能に関するコードを main.go とは別のファイルに書いています。
よって、goのファイルは `main.go` と `cat_option.go` の２つになっています。

## main.go
```main.go
package main

import (
	"bufio"
	"flag"
	"fmt"
	"log"
	"os"
)

func main() {
	var (
		n = flag.Bool("n", false, "行番号を付けて表示する")
		b = flag.Bool("b", false, "空行以外に行番号を付けて表示する")
	)

	flag.Parse()

	// 引数の数が多いとき
	if len(os.Args) > 3 {
		fmt.Println("引数の数が違います。")
		os.Exit(1)
	}

	var scanner *bufio.Scanner
	if len(os.Args) == 2 {
		fp, err := os.Open(os.Args[1])
		if err != nil {
			log.Fatalln(err)
		}
		defer fp.Close()
		scanner = bufio.NewScanner(fp)
	} else if len(os.Args) == 3 {
		fp, err := os.Open(os.Args[2])
		if err != nil {
			log.Fatalln(err)
		}
		defer fp.Close()
		scanner = bufio.NewScanner(fp)
	} else {
		os.Exit(1)
	}

	if *n {
		catN(scanner)
	} else if *b {
		catB(scanner)
	} else {
		cat(scanner)
	}
}
```
## cat_option.go
```cat_option.go
package main

import (
	"bufio"
	"fmt"
)

// そのまま表示
func cat(scanner *bufio.Scanner) {
	for scanner.Scan() {
		fmt.Println(scanner.Text())
	}
}

// -n:行番号を付けて表示
func catN(scanner *bufio.Scanner) {
	lineNum := 1
	for scanner.Scan() {
		fmt.Printf("%5d: %s\n", lineNum, scanner.Text())
		lineNum++
	}
}

// -b:空行以外に行番号を付けて表示
func catB(scanner *bufio.Scanner) {
	lineNum := 1
	for scanner.Scan() {
		if len(scanner.Text()) == 0 {
			fmt.Println(scanner.Text())
		} else {
			fmt.Printf("%5d: %s\n", lineNum, scanner.Text())
			lineNum++
		}
	}
}

```
# 簡単にコードの説明
今回はコマンド引数を扱うために flag パッケージを使用しています。

オプションとして `-n` と `-b` を実装しており、それぞれ以下のような機能となっています。
`-n：行番号を付けて表示`
`-b：空行以外に行番号を付けて表示`

例として`-n`が引数として与えられた時、 変数 n は true となって下の if 文によって関数 `catN` が呼び出されます。また、オプションとして何も指定されず、引数にファイル名(パス名)だけが渡された場合はファイルの中身をそのまま表示します。
```
	if *n {
		catN(scanner)
	} else if *b {
		catB(scanner)
	} else {
		cat(scanner)
	}
```

# 実行してみる
以下のサンプルを使って実行してみます。
```sample.text
apple
banana

orange, orange

mango
```

## ビルド
`＄go build -o $GOBIN/cat_command`
※ビルドに関する説明は省略します。

## 実行
実行する際には以下の２通りで実行します。
（今回は対象のtxtファイルなどがカレントディレクトリにある場合を想定しています。パス名を指定することで他のディレクトリにあるファイルも表示することができます。）

オプションを指定しない場合：`＄cat_command [ファイル名]`
オプションを指定する場合：`＄cat_command [オプション] [ファイル名]`

それでは、いくつかの方法で実行してみます。
`＄cat_command sample.txt`
```
$cat_command sample.txt
apple
banana

orange, orange

mango
```

`＄cat_command -b sample.txt`
オプションを指定し、空行以外に行番号をつけて表示します。
```
$cat_command -b sample.txt
    1: apple
    2: banana

    3: orange, orange

    4: mango
```
`＄cat_command -a sample.txt`
存在しないオプションを指定した場合、実行に失敗しヘルプが表示されます。
```
$cat_command -a sample.txt
flag provided but not defined: -a
Usage of cat_command:
  -b    空行以外に行番号を付けて表示する
  -n    行番号を付けて表示する
```
ノートアプリ「Obsidian」について書かれた本

# Obsidianとは

このQiitaをはじめとして、ITエンジニアは**Markdown記法**をよく使います。
そして、Markdownでメモやノートを書くとき、EvernoteやNotion、HackMDなどのクラウド型のサービスもあります。
Markdown以外を使ったノートアプリで、OneNote、Scrapboxなどが使われることもあります。

しかし、個人用のノートの場合、データをクラウドに保存するのではなく、**ローカルに保存したい**こともあるでしょう。
VSCodeなどのテキストエディタで書く方法もありますが、複数のノートを連携することを考えると、ノートアプリが便利です。

そんな中、ローカルで動いて、Markdownで書ける **「Obsidian」** の人気が高まっています。
ObsidianはWindowsでもmacOSでも、AndroidでもiOSでもiPadOSでも動く無料のノートアプリです。

https://obsidian.md

単純にノートを書くだけでなく、プラグインが豊富にあり、HTMLやCSS、JavaScriptを使ってさまざまな拡張ができることも特徴です。

便利なアプリですが、英語の情報が多く、どう使っていいのかわからない人も多いはず。
インターネット上の記事を探す方法もありますが、いくつかの本でObsidianが取り上げられています。
日本語で書かれた本や雑誌の中から、Obsidianが登場する本を紹介します。

（注）
少なくとも半ページくらいはObsidianについて書かれている本に絞っています。
本文中に「Obsidian」という単語が登場する程度のものは除外させていただきます。

# 本

## Obsidianで“育てる”最強ノート術 —— 情報もアイデアも、ぜんぶつなげて整理しよう

2023-10-18発売予定の新刊です。

https://www.amazon.co.jp/dp/4297137194

## Obsidianノート術

Obsidianのインストールからノートの作成方法、プラグインの使い方などについての本です。
技術書典13にて頒布、Kindleでも購入できます。

(2023-09-10販売終了）ttps://www.amazon.co.jp/dp/B0BBDLNYDD

## Obsidianでつなげる情報管理術

Obsidianでメモを作成するときの考え方として、著者が提唱する「DiMFiT」について書かれた本です。

(2023-09-10販売終了）ttps://www.amazon.co.jp/dp/B0B4K499F4
(2023-09-25「完成版」として販売開始）

https://www.amazon.co.jp/dp/B0CHY6MK42

## 自分だけの情報整理術を見つけ出す　 ふかぼり仕事術

対談形式でObsidianの活用法についてデイリーノートやタスク管理術について書かれた本です。

https://www.amazon.co.jp/dp/B0B938PV3F

## 情報をまとめて・並べるだけ！超シンプルな「手帳」兼「アイデア帳」運用術: 文章を書き、考える人のためのObsidian活用術 情報整理大全

手帳として、そしてアイデアメモとしてObsidianを使う考え方を書かれた本です。

https://www.amazon.co.jp/dp/B09S2Y8297

## 現役高校教師の「行動につながる」情報マネジメント術: 文章を書き、考える人のための「デジタルノート 」活用術 情報整理大全

EvernoteからUlysses、Scrapbox、NotePlan3、そしてObsidianへの移行までノートアプリの変遷について書かれた本です。

https://www.amazon.co.jp/dp/B09VF6YCYP

## アトミック・シンキング: 書いて考える、ノートと思考の整理術

ノートを書いて思考する、著者が提唱する「アトミック・シンキング」について書かれた本です。
ノートツールの例としてObsidianが登場します。

https://www.amazon.co.jp/dp/B0B8XBRW93

## Obsidian 次世代型のメモアプリ: Zettelkasten 知的生産の技術を超えて

非エンジニアによってObsidianの入門的な使い方について解説された本です。

https://www.amazon.co.jp/dp/B0C8ZMFM8P

## Obsidianで電子書籍をつくりたい

Obsidianでノートを書くだけでなく、電子書籍を作ることについて書かれた本です。

https://www.amazon.co.jp/dp/B0C93HPLMJ

## 読書を自分に活かす「つながる読書ノート」の作り方

ObsidianやScrapboxを使って読書ノートを作成する本です。

https://www.amazon.co.jp/dp/B0CKC59K6P

## 雑誌

## MacBook仕事術! 2022

Macアプリの紹介の1つとして見開きで紹介されています。

https://www.amazon.co.jp/dp/4866365501

## 家電批評 2022年02月号

iPadアプリの紹介の1つとして紹介されています。

https://www.amazon.co.jp/dp/B09LHD9HR6

## シェルスクリプトマガジン vol.89

Markdownの活用としてObsidianが紹介されています。

https://www.amazon.co.jp/dp/4904807863/

# その他

他にも出版されれば（見つけられれば）、随時追記していきます。
見つけられた方は [Twitter(@masuipeo)](https://twitter.com/masuipeo) までご連絡ください。
SPSS Statisticsによる生存分析④時間依存のCox回帰

[SPSS Statisticsによる生存分析①生命表](https://qiita.com/Makimaki2020/items/bae6c577cd8b20a37163)
[SPSS Statisticsによる生存分析②Kaplan-Meier](https://qiita.com/Makimaki2020/items/5a7222a845b6ee796093)
[SPSS Statisticsによる生存分析③Cox回帰](https://qiita.com/Makimaki2020/items/6e4af9157fcf520cfa92)
[SPSS Statisticsによる生存分析④時間依存のCox回帰](https://qiita.com/Makimaki2020/items/9b7fcb0fba5168dae66d)

# はじめに
■環境
Windows 10
SPSS Statistics 28.0.1
SPSS Advanced Statisticsオプション

■データ
https://github.com/Makimaki2020/sampledata/blob/main/Survival.sav?raw=true
このデータには、患者238人のケガの治療法(治療法A、治療法B)、薬の投与量、健康状態(良い、悪い)、治療完了までの日数と状況(治療完了、打ち切り)があります。

# SPSS Statisticsの生存分析
生存分析とは、ある事象(イベント)が起こるまでの時間の長さに対する分析です。たとえば、患者の治療時間や生存期間、登録会員が退会するまでの期間、機械、システム、製品、部品の故障までの時間や寿命の長さ、またローン審査にかかる時間など分析することができます。これらのデータの特徴は時間の経過に伴い分析の対象が減少していく点にあります。患者の治療時間を扱う場合、治療完了のステータスになるとその患者のデータはその時点から対象から除かれます。また、何らかの事情で途中で治療を取りやめてしまった場合にもその患者のデータはその時点から対象から除かれます。このような「打ち切り」を含むデータを生存分析では扱うことができます。

生存分析分析のメニューは次の通りです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/855260/e244129f-5a65-4865-5d68-af2f79b46f68.png)
それぞれのメニューの主な目的と概要です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/855260/37691edf-f6a3-3c45-a9d6-b926826a6120.png)

# 時間依存のCox回帰
ここでは、時間依存のCox回帰を取り上げます。
このメニューの主な目的は、時間に依存する共変量を含む共変量に基づいて、事象までの時間をモデル化することです。
手順は、[分析]メニュー＞[生存分析]＞[時間依存のCox回帰]を選択します。
[時間依存の共変量の計算]ダイアログで、式を入力します。
ここでは、治療を開始してから365日(約１年)以降から治療法によるハザード比が一定でなくなっています。
Cox回帰メニューで作成したログマイナスログのグラフ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/855260/36cb1adc-e3f9-0f25-7844-b4c9da78957b.png)

時間変数[T_]が365よりも大きい場合を真(１)、そうでない(365以下の)場合を偽(０)として、治療法を乗じます。
T_COV_は時間と治療法の交互作用です。時間は、(生存時間＞365)＝１、(生存時間＜＝365)＝０です。治療方法は、治療法A＝０、治療法B＝１です。T_COV_＝０は、❶(生存時間＜＝365)×治療法A、❷(生存時間＜＝365)×治療法B、❸(生存時間＞365)×治療法A、T_COV_＝１は、❹(生存時間＞365)×治療法Bで、T_COV_は❶から❹までの４種類で❶、❷、❸は０、❹は１です。

時間依存の共変量の計算に関しては、こちらもご覧ください。
https://www.ibm.com/docs/ja/spss-statistics/28.0.0?topic=statistics-computing-time-dependent-covariates

これにより時間と治療法の交互作用の項ができることになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/855260/25a9fa57-18f3-cad0-cb3e-b291f9b30145.png)
[モデル]ボタンをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/855260/d50b3df1-d467-d655-9dd8-01285e7b25d2.png)
　①　時間変数を[生存変数]に指定します。
　②　状況や状態などを表す変数を[状態変数]に指定し、[事象の定義]で[状態変数]の事象(イベント)を表すコードを指定します。
　③　[ブロック]に共変量として説明変数を指定します。このとき、時間依存の共変量変数[T_COV_]も指定します。
　④　[カテゴリ]ボタンをクリックして、カテゴリ型の共変量を指定します。
　⑤　[オプション]ボタンをクリックして、[モデル統計量]の[expに関するCI]を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/855260/b9e1053a-01f7-6764-12e3-e97d099a92fd.png)
実行結果を見てみましょう。
カテゴリ変数のコーディングを確認しておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/855260/83dda46c-7b27-52f5-7a97-3e988433670c.png)
T_COV_以外の条件は同じで、T_COV_が０から1に代わるとハザード比であるExp(B)は0.264です。つまり、365日以降の治療方法Bは治療の効果が下がることになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/855260/7721b13b-4535-0839-485c-224fd367e7df.png)

# まとめ
SPSS Statistics生存分析の時間依存のCox回帰の主な機能を紹介しました。

## 参考
https://www.ibm.com/blogs/solutions/jp-ja/spss-stats-tips-08/
SPSS Statisticsによる生存分析②Kaplan-Meier

[SPSS Statisticsによる生存分析①生命表](https://qiita.com/Makimaki2020/items/bae6c577cd8b20a37163)
[SPSS Statisticsによる生存分析②Kaplan-Meier](https://qiita.com/Makimaki2020/items/5a7222a845b6ee796093)
[SPSS Statisticsによる生存分析③Cox回帰](https://qiita.com/Makimaki2020/items/6e4af9157fcf520cfa92)
[SPSS Statisticsによる生存分析④時間依存のCox回帰](https://qiita.com/Makimaki2020/items/9b7fcb0fba5168dae66d)

# はじめに
■環境
Windows 10
SPSS Statistics 28.0.1
SPSS Advanced Statisticsオプション

■データ
製品同梱サンプルファイル pain_medical.sav

# SPSS Statisticsの生存分析
生存分析とは、ある事象(イベント)が起こるまでの時間の長さに対する分析です。たとえば、患者の治療時間や生存期間、登録会員が退会するまでの期間、機械、システム、製品、部品の故障までの時間や寿命の長さ、またローン審査にかかる時間など分析することができます。これらのデータの特徴は時間の経過に伴い分析の対象が減少していく点にあります。患者の治療時間を扱う場合、治療完了のステータスになるとその患者のデータはその時点から対象から除かれます。また、何らかの事情で途中で治療を取りやめてしまった場合にもその患者のデータはその時点から対象から除かれます。このような「打ち切り」を含むデータを生存分析では扱うことができます。

生存分析分析のメニューは次の通りです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/855260/e244129f-5a65-4865-5d68-af2f79b46f68.png)
それぞれのメニューの主な目的と概要です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/855260/37691edf-f6a3-3c45-a9d6-b926826a6120.png)

# Kaplan-Meier
ここでは、Kaplan-Meier(カプランマイヤー法)を取り上げます。
このメニューの主な目的は、生存率曲線を求め、生存時間を群(グループ)間で比較をすることです。
手順は、[分析]メニュー＞[生存分析]＞[Kaplan-Meier]を選択します。
　①　時間変数を[生存変数]に指定します。
　②　状況や状態などを表す変数を[状態変数]に指定し、[事象の定義]で[状態変数]の事象(イベント)を表すコードを指定します。
　③　生存時間を比較(効果を評価)したい[因子変数]を指定します。
　④　[因子の比較]ボタンをクリックして、[検定統計量]の[ログランク]、[Breslow]、[Tarone-Ware]を選択します。
　⑤　[オプション]ボタンをクリックして、[作図]の[累積生存率]を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/855260/0ddf7200-deae-f2ab-23c8-ab8fe9fe5547.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/855260/e71128c8-9c70-5f7b-6f9b-29b5382ccb03.png)
実行すると[生存率表]が１つのテーブル内で[新薬]と[既存薬]に分割されて出力されます。一部を抜粋してみます。このテーブルから薬が効果を発揮する時刻を見ることができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/855260/1ee3c7cb-cef0-5050-7c6f-ab48eb2b2c6a.png)
生存率曲線は、生存率表を視覚的に表したものです。横軸はイベントまでの時間を示します。このプロットでは、薬が患者に効果を発揮するたびに、生存率曲線が低下します。縦軸は生存確率です。したがって、生存率曲線上の任意の点は、特定の治療を受けている患者がその時点までに薬の効き目(効果)を得られていない可能性を示しています。新薬のプロットは、このテストの大部分を通じて既存薬のプロットより下にあり、新薬は既存薬よりも早く効き目がある可能性を示唆しています。これらの違いが偶然によるものかどうかを判断するには検定の結果を確認します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/855260/92d6adac-3ff9-847c-cb15-2fff1614ad84.png)

[生存時間の平均値および中央値]テーブルは、新薬・既存薬の効果が発揮された時間の統計量です。信頼区間が重複しているので「平均」生存時間に大きな差があるとは考えにくいです。
[全体の比較]テーブルは検定結果です。どの検定手法でも有意確率が0.10 より大きいため、生存率曲線間の差を判断することはできませんでした。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/855260/cc09e508-c0c3-1723-40b6-18de1721a598.png)

さらに、ストラータ(層別)変数を追加することで、因子ごとのストラータごとの比較も可能です。

# まとめ
SPSS Statistics生存分析のKaplan-Meireの主な機能を紹介しました。

## 参考
https://www.ibm.com/blogs/solutions/jp-ja/spss-stats-tips-08/