OmniAICreator/Qiita-1.07M huggingface dataset:
プロジェクトの見積もり時に注意すること

## はじめに
プロジェクトの見積もりを複数経験しましたが、
周りからご指摘をいただいたので、備忘録のためにまとめます。

## プロジェクト見積もり時に注意すること

- 無理な期限を設定しない
- 余裕をもったスケジュールをひく
- 過去経験に基づいて不確かさを変える
- プロジェクトの要件に応じて各工程の重み付けを変える

それぞれ解説します。

### 無理な期限を設定しない
これはよく言われていることですが、無理な期限は設定してはいけません。
理由は以下です。

- 自分は残業して良くても周りのメンバーに迷惑がかかり、士気が下がるから
- リカバリーがきかないから

クライアントのことを思って強気な期限を設定しないように注意しましょう。

### 余裕をもったスケジュールをひく

先ほどの内容と逆のことを言っているだけかもですが、余裕をもったスケジュールをひきましょう。

理由は以下です。
- プロジェクト内で想定外のことが発生した際に対応できるようにするため
    - 要件が変わった、設計で見落としがあったなど
- プロジェクト外で想定外のことが発生した際に対応できるようにするため
    - 他プロジェクトにリソースが逼迫されている、メンバーが病気になるなど
- プロジェクトの特性によってはリリース日をずらせないため

余裕を持ったスケジュールと、納得する理由を用意して周りと交渉しましょう。

### 過去経験有無に応じて不確かさを変える

プロジェクトで工数を出す時はバラつきも一緒に考えましょう。

そのばらつきを考える際に過去経験を考えると良いです。

例えば、以下です。

- 過去経験がある場合→ばらつきを少なめに考慮する
- 過去経験がない場合→ばらつきを多めに考慮する

工数＋ばらつきを一緒に提示することで、後々リソースが足りないなどの問題が発生した場合に交渉しやすくなります。

### 過去経験有無に応じて各工程の重み付けを変える

プロジェクトで工数を出す時は各工程の重み付けを考えるかと思います。
その際の重み付けは過去プロジェクト経験有無で変えると良いです。

例えば、以下です。

- 過去経験がある場合→要件や設計は見えているので、実装の割合を増やす
- 過去経験がない場合→要件や設計は見えていないので、要件定義や設計の割合を増やす

この重みを変えることで、より精緻な見積もりができるようになるかと思います。

## まとめ
プロジェクトの見積もりを複数経験する中で、注意することを備忘録としてまとめました。
今後見積もりを実施する方に少しでも役立てば幸いです。
【Laravel】assertDatabaseHasで複数データを一気にテストしたい

## 環境
Laravel v9.5.1 (PHP v8.1.3)

## 状況
DBテストを書いていたら下記のエラー。
エラー文だけでググっても解決せず、少し苦労したので備忘録とする。

```
str_ends_with(): Argument #1 ($haystack) must be of type string, array given
```
複数のデータが入っているかを一気にテストしたかったため、
配列の配列を第2引数としていた。
直感的にこう書けるかなと思ったがだめっぽい。

```php
$users = User::factory(2)->create();

$this->assertDatabaseHas('post_histories', [
   'user_id' => $users[0]->id,
   'hoge_type' => 'hoge',
], [
   'user_id' => $users[1]->id,
   'hoge_type' => 'hoge',
]);
```
## 解決法

DBテストではレコードごとにデータが入っているかをテストする。
```php
$users = User::factory(2)->create();

$this->assertDatabaseHas('posts', [
   'user_id' => $users[0]->id,
   'title' => $params['title']
   'content' => $params['content']
]);

$this->assertDatabaseHas('posts', [
   'user_id' => $users[1]->id,
   'title' => $params['title']
   'content' => $params['content']
]);
```

```assertDatabaseHas```の実装を見てみると、配列の配列を渡せない実装になっていた！
(```array $data```の部分）

```php
protected function assertDatabaseHas($table, array $data, $connection = null)
{
   $this->assertThat(
       $table, new HasInDatabase($this->getConnection($connection), $data)
   );

   return $this;
}


class HasInDatabase extends Constraint
{
...
   public function matches($table)
   {
      return $this->database->table($table)->where($this->data)->count() > 0;
   }
...
}
```

## 参考
https://github.com/jimrubenstein/laravel-framework/blob/master/src/Illuminate/Foundation/Testing/Concerns/InteractsWithDatabase.php
PyflowでWindowsにPythonの小さな環境構築する

PyFlowというビジュアルスクリプトフレームワークもあるので気を付ける

PyflowのGitHub: [https://github.com/David-OConnor/pyflow](https://github.com/David-OConnor/pyflow)

## Pyflow

最小限のAPIを備えたシンプルで使いやすいインストールと依存関係を管理するシステムツール

+ 環境を自動で判別して，指定されているPythonで実行をするようにしてある
+ ユーザー側のPythonを利用せず[独自にコンパイルしたPythonを利用](https://github.com/David-OConnor/pyflow#python-binary-sources)することで環境に依存しないで構築できる
+ 依存関係のキャッシュされたデータベースや[warehouse](https://github.com/pypa/warehouse)などを利用しているためパッケージ依存関係の解決やlockingが速い
+ (Rustで開発されている)

個人的にはこれらが特徴として良いなあと思った

環境の自動判別などは,初心者には嬉しい機能だと思う

## インストール

[プラットフォームごと](https://github.com/David-OConnor/pyflow#installation)に用意されている

Rustがインストール済みであればcargoでインストールできる

```sh
cargo install pyflow
```

インストールされたかを確認する

```sh
# バージョン確認
pyflow -V
# 利用できるコマンド表示
pyflow -h
```

## プロジェクトの作成

```shell
# 既存のフォルダを初期化
pyflow init
# 新しくプロジェクト用のフォルダを作って初期化
pyflow new projectname
```

initコマンドを利用する際にはrequirements.txt, pipfileなどを利用してプロジェクト作成時にパッケージとそのバージョンを指定してインポートすることもできる

アスタリスクの箇所で任意のバージョンを指定する(このままでもインポートされる）

[バージョンの指定方法](https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html)はこれが参考になる

```toml:pipfile
[[source]]
name = 'pypi'
url = 'https://pypi.org/simple'
verify_ssl = true

[packages]
numpy = '*'
matplotlib = '*'

[dev-packages]
nose = '*'
black = '*'
```

プロジェクトのフォルダにはpyproject.tomlが自動で生成される

また上記のような設定ファイルを書かなくても パッケージなどは後でインストールできる

## パッケージのインストール

```bash
# 最新バージョン
pyflow install numpy
# 複数かつバージョン指定
pyflow numpy==1.21.6 matplotlib=3.5.1
# 開発用のlinterやfomatterをインストール
pyflow install black --dev
# アンインストール
pyflow uninstall numpy
```

pyproject.tomlを編集してもインストールできる

```
[tool.pyflow.dependencies]
numpy = "1.21.6"

[tool.pyflow.dev-dependencies]
black = "*"
```

## 実行

```sh
# REPL
pyflon python
# スクリプトを実行
pyflow filename.py
# linterやformatterを実行
pyflow black
# 外部のプロジェクトのスクリプトを一回だけ実行
pyflow script myscript.py
```

## おわり

書いていないことが多いので気になったら[GitHubのページ](https://github.com/David-OConnor/pyflow)へ

覚えることが少なく，単純な環境を作るだけならこれで良いなあと思う

TipsとしてVSCodeで実行するときには[tasks.jsonを利用する](https://code.visualstudio.com/docs/editor/tasks)と楽になる

参考までに

```json:tasks.json
{
    "tasks": [
        {
            "label": "pyflow install pacage",
            "type": "shell",
            "command": "pyflow",
            "args": [
                "install",
                "${input:packagename}",
            ]
        },
        {
            "label": "pyflow run script",
            "type": "shell",
            "command": "pyflow",
            "args": [
                "${relativeFile}"
            ],
        }
    ],
    "inputs": [
        {
            "id": "packagename",
            "type": "promptString",
            "default": "",
            "description": "Input package names"
        }
    ]
}
```
NestJS + prisma + GraphQL でRecordNotFoundを発生させる方法

# 概要
例えば、IDをもとに単一のオブジェクトを取得するqueryで存在しないIDを指定した際、nullとして返すのか404エラーで返すのか迷った。
(404エラーと表現したが、GraphQLではエラーの際、レスポンスステータスとしては200で返し、レスポンスボディにエラーの情報を入れるのが一般的。)
どちらが一般的なのかはよくわかっていないが、nullとして返すとフロントエンドでのハンドリングに一貫性がなくなりそうだったので、404エラーとして返す方法を試してみた。

# 結論

[rejectOnNotFound](https://www.prisma.io/docs/reference/api-reference/prisma-client-reference#rejectonnotfound) optionを使用し、NestJSの `NotFoundException` を発生させるようにした。

```typescript:prisma.service.ts
import { INestApplication, Injectable, OnModuleInit, NotFoundException } from "@nestjs/common";
import { PrismaClient } from "@prisma/client";

@Injectable()
export class PrismaService extends PrismaClient implements OnModuleInit {
  constructor() {
    super({
      log: ["query"],
      rejectOnNotFound: () => new NotFoundException(),
    });
  }

  async onModuleInit() {
    await this.$connect();
  }

  async enableShutdownHooks(app: INestApplication) {
    this.$on("beforeExit", async () => {
      await app.close();
    });
  }
}
```

私はApolloDriverを使っているが、存在しないIDにアクセスしようとした際、以下のように返してくれる。完璧だ。
![スクリーンショット 0004-04-21 19.06.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1783922/a1c858be-04a1-d8af-6d37-add1c060faeb.png)


# ボツ案1

`return await this.prismaService.findUnique.findUnique(id) | new NotFoundException();`

流石に安直すぎるか？となって却下。
構成によってはresolverとprismaを直接依存させたくないために、間にserviceをかませている場合もあると思うし、そうなるといちいち間にかませているserviceごとに書くことになって面倒というのもある。

# ボツ案2

`rejectOnNotFound: true` を指定

https://www.prisma.io/docs/reference/api-reference/prisma-client-reference#rejectonnotfound を見ると true/false を指定でき、trueにするとデフォルトで `NotFoundError` なるものを返してくれる。
これもいちいちcatchしてNestJSのNotFoundExceptionを投げ直すのが面倒なので却下。
TypeScript でGatsby のチュートリアル中の Link が型エラーとなってしまう問題の対処

# 問題

Gatsby のチュートリアルを実際に書きながら学ぼうと思い、こちらのチュートリアルに倣い、`<Link>` を追加した。

https://www.gatsbyjs.com/docs/tutorial/part-2/

```tsx:index.tsx
// Step 1: Import React
import { Link } from 'gatsby';
import * as React from 'react';

// Step 2: Define your component
const IndexPage = () => {
  return (
    <main>
      <title>Home Page</title>
      <h1>Welcome to my Gatsby site!</h1>
      <Link to="/about">About</Link>
      <p>I&apos;m making this by following the Gatsby Tutorial.</p>
    </main>
  );
};

// Step 3: Export your component
export default IndexPage;
```

この状態で VSCode および `yarn typecheck` を行うと以下のような型エラーが発生してしまった。

```:typecheckでのエラー表記
src/pages/index.tsx:11:8 - error TS2786: 'Link' cannot be used as a JSX component.
  Its instance type 'GatsbyLink<unknown>' is not a valid JSX element.

11       <Link to="/about">About</Link>;
```

```:vscodeでのエラー表記(日本語)
'Link' を JSX コンポーネントとして使用することはできません。
  そのインスタンスの型 'GatsbyLink<unknown>' は、有効な JSX 要素ではありません。
    'render()' によって返された型は、これらの型同士で互換性がありません。
      型 'React.ReactNode' を型 'import("/****/node_modules/@types/reach__router/node_modules/@types/react/index").ReactNode' に割り当てることはできません。
        型 '{}' を型 'ReactNode' に割り当てることはできません。ts(2786)
```

なお、`yarn gatsby develop` では正常に動作していたため、TypeScript の型関連のエラーであると考えられる。


# 原因

https://stackoverflow.com/questions/71831601/ts2786-component-cannot-be-used-as-a-jsx-component

`@types/react` のバージョンアップによって、型定義変更の影響が出ているのが原因のようだ。

こちらの StackOverflow の記事にも書かれている通り、`package.json` に以下の通り resolutions を追加して、バージョン18未満の `@types/react` と `@types/react-dom` を使うようにする。

```json:package.json
  "resolutions": {
    "@types/react": "17.0.14",
    "@types/react-dom": "17.0.14"
  }
```

書き換えた後は `yarn` を実行する。 書き換えの前後で `yarn list` の diff を取ると、今回は以下のようになっていた。 確かに、置き換え前は @types/react のバージョン18以上を使っていたことが分かる。

```diff
1035c1035
< │  └─ @types/react@18.0.5
---
> │  └─ @types/react@17.0.14
1040c1040,1044
< │  └─ @types/react@^17
---
> │  ├─ @types/react@^17
> │  └─ @types/react@17.0.14
> │     ├─ @types/prop-types@*
> │     ├─ @types/scheduler@*
> │     └─ csstype@^3.0.2
4391c4395
```


# 最後に

原因を見れば分かるが、明らかに過渡期の問題であり将来的には収束する問題ではある。
しかし、このレベルのエラーが発生するとなると、特に（自分を含む）TypeScript の初心者はこういった過渡期の問題にたまたまあたってしまうと辛いなあと思ってしまう。

過去に nuxt の stylus-loader でも古いバージョンを指定する、という解決策をしたことがあるが、JavaScript や　TypeScript では普通の文化なのだろうか…？
AWS関連プロジェクトで見積もる際にやることをまとめてみた

## はじめに

4月からポジションが上がり、プロジェクトを見積もることが増えました。
初めて見積もりを実施したものの、周りから割と精度が良いと言われたので、自分の備忘録を含めてプロジェクトの見積もり方法をまとめてみます。

## 見積もる際にやること
AWSを活用したプロジェクトを前提に記載します。
また、やることを列挙すると以下になります。

- 要件把握
- 概要アーキテクチャ図作成
- アプリケーションの工数見積もり
- AWS関連の工数見積もり
- DB関連の見積もり
- 他要素の見積もり
- プロジェクト管理

それぞれ詳細を記載します。

### 要件把握
まずは要件を把握します。
これをやらないことには始まりません。

### 概要アーキテクチャ図作成
次に要件を満たすための概要アーキテクチャ図を作成します。
この図を作成する中で実装すべきアプリケーションの数や、AWSの構成などをおおまかに把握できれば良いです。

### アプリケーションの工数見積もり
アプリケーションの数が分かったところで、この工数を見積もります。
観点としては大きく以下になります。

#### 過去プロジェクトで同様の実装をしたことがある場合
会社であれば過去に複数プロジェクトを実施しているはずです。
それらを参考に過去実装したことがあるか確認します。
実装したことがあれば、その際の工数を参考に工数を決めます。

#### 過去プロジェクトで同様の実装をしたことがない場合
当然過去経験のないトピックも存在します。
R&Dが必要な場合もあるため、多少バッファを考えて多めに見積もります。

### AWS関連の工数見積もり
次にAWS関連の工数見積もりです。
こちらもアプリケーションの工数見積もり時と同様の考え方です。

#### 過去プロジェクトで同様の構成としたことがある場合
会社であれば過去に複数プロジェクトを実施しているはずです。
それらを参考にAWS設計・構築の工数を見積もります。

#### 過去プロジェクトで同様の実装をしたことがない場合
過去経験がない場合も当然あります。
この場合、大きく以下のパターンがあるかと思います。
- 全て経験のあるサービスだが、構成が初めてである場合
- 未経験のサービスがある、かつ、構成が初めてである場合

後者ではR&Dが必要な場合もあるため、多少バッファを考えて多めに見積もります。

### DB関連の見積もり
次のDB関連の工数見積もりです。
DB関連は1度設計・構築すると後戻りが大変になるため、多めに工数を見積もります。

### 他要素の見積もり
他にプロジェクト特有の要素があれば見積もります。

### プロジェクト管理
これは、プロジェクト管理やクライアントとの調整などの工数です。
規模が大きいほどこの工数がかかるため、これまで見積もった要素の数パーセント、みたいな見積もりをします。

## まとめ
プロジェクトの見積もりを初めてやった時は「見積もりなんてできるか」と思っていたのですが、上記の流れでやると割と周りが納得してくれるような見積もりが作れるようになりました。

今後見積もりを作成する人がいたら、少しでも参考になれば幸いです。
Android タブレット端末で ROS の点群データを表示

ROSロボットシステムのLiDAR、ステレオカメラなどのデバイスより生成した点群データ（PointCloud2）をユーザに表示時、パソコンPCの画面で表示できますが、ビジネス現場で運用には、丁度不便です。
何か簡単にAndroid タブレット端末でROS の点群データを表示できるかを試してます。

# システム構成

```mermaid
sequenceDiagram
    Androidタブレット端末 -->> ROSロボット : Wifi接続
    ROSロボット -->> Androidタブレット端末: 点群データ
```

# Point Cloudアプリをインストール

[android_pointcloud_viewer](http://wiki.ros.org/android_pointcloud_viewer)のAndroidアプリを使用して点群データを表示します。

Gitから[android_ros_pointcloud_viewer](https://github.com/cogniteam/android_ros_pointcloud_viewer)のAndroidアプリソースコードをダウンロードします。

indigoのブランチが古いけど、Ubuntu 18.04のROS Melodicと問題なく使用できます。

Androidアプリソースコード丁度古いけど、最新のandroid studio(Blumblebee)で開きます。

android studioのProjectStructureでGradle PluginとGradleのVersionを変更します。
Gradle Plugin Version:3.2.0
Gradle Version:4.8.1

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386259/2d4f6bb8-1a33-b748-207d-a417bb3e7b14.png)

# ROSロボットから点群データを送信

ROSロボットからタブレット端末で表示したい群データをcloud/source (sensor_msgs/PointCloud2)の Topicで送信します。 


# Point Cloudアプリを起動

Master URIに、ROSロボットのMaster URIを設定します。

CONNECTボタンを押します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/386259/adc6a57f-5cab-5669-62e2-dca5c5961bff.png)

# タブレット端末で点群データを表示

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

#### APEXクラス内、SOQL検索結果が共有設定/共有ルールより影響あり・なしのパターン:

```
パターン01:
public class AccountTriggerHandler {

   //取引先の共有設定が私有
   //実行ユーザより、検索結果がnullの場合あり
　　List<Account> accList = [Select Id,Name From Account];
  
}

パターン02:
public with sharing class AccountTriggerHandler {

   //取引先の共有設定が私有
   //実行ユーザより、検索結果がnullの場合あり
　　List<Account> accList = [Select Id,Name From Account];
  
}

パターン03:
public without sharing class AccountTriggerHandler {

   //取引先の共有設定が私有
   //検索結果が全組織のデータ
　　List<Account> accList = [Select Id,Name From Account];
  
}

結論：
パターン01　と　パターン02　が結果が一緒、共有設定が私有の場合、実行ユーザより、検索結果が変わる場合ある。
パターン03が共有設定が無視して、すべてのレコードを取得できる。

```
APEX開発向上_001

### オブジェクト項目の値の付与/更新
```
ソース例０１：
  Account acc01 = new Account();
  acc01.put('Name','yosi');
  acc01.put('address','Tokyo');

  upsert acc01;


ソース例０２：
  Account acc02 = new Account();
  acc02.Name = yosi;
  acc02.address = Tokyo;

  upsert acc02;

```
【C#】iTextSharpを使って複数のGIFを1つのPDFに変換する

## 経緯

複数のGIFを1つのPDFに変換したかった
調べても有料のものしか見つからなかったけど、iTextSharpを使えばできたので記録に

## 前提

* GIF画像のサイズは全て同じ
* 動かないGIF画像を想定

## ソースコード

```cs
// GIF画像のバイト配列が入ったリスト
List<byte[]> gifByteList = new List<byte[]>();

// GIF画像をiTextSharpのImage型に変換してリストに詰める
List<iTextSharp.text.Image>() imageList = new List<iTextSharp.text.Image>();
foreach (var gifByte in gifByteList)
{
    iTextSharp.text.Image image = iTextSharp.text.Image.GetInstance(gifByte);
    imageList.Add(image);
}

// GIF画像のサイズでドキュメントを作成
float height = imageList.FirstOrDefault().Height;
float width = imageList.FirstOrDefault().Width;
RectangleReadOnly pageSize = new RectangleReadOnly(width, height);
Document document = new Document(pageSize, 0, 0, 0, 0);

// ドキュメントに画像を挿入
// サイズはピッタリなのでdocument.NewPage()は必要ない
document.Open();
foreach (var image in imageList)
{
    document.Add(image);
}
document.Close();
```

## Image.GetInstance()

引数に応じてiTextSharp.text.Image型のインスタンスを作成するメソッド
対応している画像の種類はGIF, JPEG, PNG
オーバーロードもいろいろあるみたいです
以下は一部を抜粋
1. <code>GetInstance(iTextSharp.text.Image image)</code>
1. <code>GetInstance(Uri url)</code>
1. <code>GetInstance(Stream s)</code>
1. <code>GetInstance(string filename)</code>
1. <code>GetInstance(byte[] imgb)</code>
1. <code>GetInstance(System.Drawing.Image image, BaseColor color, bool forceBW)</code>
1. <code>GetInstance(System.Drawing.Image image, ImageFormat format)</code>
1. <code>GetInstance(System.Drawing.Image image, BaseColor color)</code>

## 画像をドキュメントのサイズに合わせたいとき

元の画像の比率を変えずに、縦か横をA4サイズのドキュメントの幅いっぱいに合わせたいときは、以下の処理を追加するとよいと思います。

```cs:ドキュメントの余白なし
RectangleReadOnly pageSize = PageSize.A4;
Document document = new Document(pageSize, 0, 0, 0, 0);

// 画像サイズ変更
image.ScaleToFit(pageSize);
```

```cs:ドキュメントの余白あり
RectangleReadOnly pageSize = PageSize.A4;
float margin = 35f;
Document document = new Document(pageSize, margin, margin, margin, margin);

// 画像サイズ変更
float width = pageSize.Width - margin * 2;
float height = pageSize.Width - margin * 2;
image.ScaleToFit(width, height);
```

## 感想

追加でお金かけないとできないかな、って諦めてたけど試したらできたので良かったです。
Laravel8 guzzleでxml送信

```php
<?php
~~~略

use Illuminate\Support\Facades\Http;

~~~略

$xml = new \SimpleXMLElement('<Hogeattribute></Hogeattribute>');
$xml->addChild('hogeId', 'hoge1');

$response = Http::withBody(
    $xml->asXML(),
    'text/xml'
)->post('https://hoge');

$json = json_encode(simplexml_load_string($response->body()));
$data = json_decode($json, true);
```

## 参照
https://readouble.com/laravel/8.x/ja/http-client.html

https://blog.capilano-fw.com/?p=6033
buttonタグの中央寄せについて

buttonタグの中央寄せについて調べたので、
備忘録として残しておきます。

## divでラップする方法

```HAML
<div class="hoge_button">
   <button id="hoge">ボタン</button>
</div>
```

```CSS
.hoge_button {
   text-align: center;
}
```

## ブロック要素にする方法

```HTML
<button id="hoge">ボタン</button>
```

```CSS
button {
  display: block;
  margin: auto;
}
```

## 参考
https://it7c.hatenadiary.org/entry/20160321/1458554331

https://wbdv.potaro.org/?p=244
certbot letsencrypt cron で 更新

何回やってもハマるわ。

webrootモードにしないとnginxを停止しないと更新できなくなる。
まぁcronで止めて、更新後に起動するってのもできるが、
うまく動かない。

ということで webrootモードにする。

一通り ssl の設定が完了したあと

```

sudo mkdir -p /var/www/html/.well-known
sudo touch /var/www/html/.well-known/test.html

```

以下を
http と https の設定両方あれば両方に書く。


```nginx設定 (defualt.conf)

#適当な ドメインの server 内
location /.well-known {
    root  /var/www/html/;
}

```


以下のコマンドをやって
2 を選んでリニューアルする（すでにssl設定されていたとしても同様に。）

```
sudo systemctl restart nginx
sudo certbot certonly --webroot -w /var/www/html/ -d your.com
```

すでに webrootモードになっているので、
nginxを止めなくても以下のコマンドが成功する。

```
sudo certbot renew --dry-run
```


`OK`




# cron設定

7日ごとに certbot を更新してnginxを再起動

```
#基本はこれ（残り期間が少ない場合のみ更新）
0 1 */7 * * certbot renew --deploy-hook "systemctl restart nginx"

#強制変更したい場合
0 1 */7 * * certbot renew --force-renewal --deploy-hook "systemctl start nginx"
```


# ログを見る

上記やっている中でログを確認したい場合がある。


cronのログを見る
```
tail /var/log/cron
```

letsencryptのログを見る
```
tail /var/log/letsencrypt/letsencrypt.log
```


# エラーになる

適当にやりすぎるとレートリミットにひっかかる。
そうすると7日以上経過しないと処理できなくなるので要注意！
きっちりフォルダにアクセスできるようにしておこう。

```
IMPORTANT NOTES:
 - The following errors were reported by the server:

   Domain: your.com
   Type:   unauthorized
   Detail: Invalid response from
   http://your.com/.well-known/acme-challenge/kaaaa-aaa
   [2406:da14:48c:3c00:8b46:113:3187:7475]: 404

   To fix these errors, please make sure that your domain name was
   entered correctly and the DNS A/AAAA record(s) for that domain
   contain(s) the right IP address.


```

ってエラーが出たら
http://your.com/.well-known/acme-challenge
以下に test.html を作ってちゃんと見れるかを確認しよう。
404なのでフォルダにアクセスできないよと言っている。


以上
Mac mini (2011年モデル) にUbuntu 20.04 LTS をデュアルブート

# はじめに
一部雑な考察が入っています。
Mac mini (2011年モデル) にUbuntu20をデュアルブートしようとしたら、予想以上に色々と調べないといけなくて、面倒だったので、メモとして書き残し。
はじめはデスクトップではなくてサーバーを入れようとしたが、なぜか起動しないので、あきらめました、、

# 環境等
- Mac mini 2011モデル
- OS X EL Capitan 
- SSD増設済み(320G/500G) ※(ubuntu領域/全体)
- ubuntu-ja-20.04.1-desktop-amd64.iso をUSBの起動ディスクとして採用(若干昔にDLしたOSファイル)
- Ubuntuインストール時は、言語はEnglish、キーボードはJapanese

# めんどくさいポイント

## OSの起動ディスク(USB)について
- isoをdmgに変換しないといけないみたいなことを記載している記事もありましたが、isoで可能
- [balenaEtcher](https://www.balena.io/etcher/)というのが良ソフトだったのでそちらを採用。
- 作成後は`セットしたディスクは、このコンピュータで読み取れないディスクでした`というメッセージがでるが、気にせず`無視`を選択
- 起動時にoption(Win用キーボードではalt)を押しっぱなしにすると、USBを起動ディスクとして選択できる

## パーティションを切る
- ディスクユーティリティはMacのOS上から起動ディスクに対して変更することが可能
- フォーマットをMS-DOS(FAT)にして、領域を確保する必要がある

## インストール時
- `Install type` で `Something else` を選択する必要あり
- `Use as` で `Ext4 ...` を選択(必要があるかは謎)
- 対象のパーティションに対して、Mount pointを `/` にしてフォーマットする必要あり
- MacOSのマウントポイントの `/` と被っていても、OSが別で、認識も(多分)別なため、それぞれ起動する

## インストール後
- 起動ディスクがUbuntuになるが、Mac側の起動ディスク設定でどうにでもなるハズ
- Wifiがハードに合っているドライバを入れないといけないため、
```
sudo apt install firmware-b43-installer bcmwl-kernel-source
```
を実行して、再起動すると接続可能になった。(実行するには、有線でつなぐ必要はありますが)

# よくわかっていないポイント
## UbuntuサーバーのOSディスク(USB)が起動しない
- 同じようにbalenaEtcherをつかったり、コマンドからdmgを書き込んだりしてみたが、ほとんど起動ディスクとして認識されなかった or 認識されても、インストール画面が立ち上がらなかった

# 参考ページ
https://www.typea.info/blog/index.php/2021/05/06/mac-ubuntu/

https://ja.gouma.org/dual-boot/-How-to-Install-and-Dual-Boot-Linux-and-macOS/

https://tsaitoh.net/wp/2020/11/17/not-work-wifi-ubuntu-macbookair-2011/


# さいごに
Windowsマシンはもうちょっと楽な認識なのですが、rufus使ったり、bios起動調べたりするので、結局慣れな気もしてきました、、
vanilla-autokanaをNuxt.jsとTypeScriptで使用

`Vue`・`Nuxt`・`TS`の環境でふりがなをカタカナで自動入力したかったので、`Nuxt.js`に対応している自動カナ入力を探していましたが、出てこないということで、`vanilla-autokana`をインストールしてきて使って見ようと試みましたが、師匠の手を借りなんとか、使える形になりました。きっと断念された方も多いはず。。。
![スクリーンショット 2022-04-21 16.03.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1134006/3db50000-f4d5-cdab-7296-0c94165773f8.png)
まずはこのwindowにアクセスしているがSSR時にアクセスできていない問題です。
```
<script lang="ts">

import * as AutoKana from 'vanilla-autokana'

let autokanaName: any

mounted() {
  if (process.client) {
      autokanaName = require('vanilla-autokana')
     }
}
```

```
mounted() {
  if (process.client) {
      autokanaName = require('vanilla-autokana')
      }
  autokanaName = AutoKana.bind('#name', '#kana', { katakana: true })
}
```
としただけでは、このwindowエラーは回避できませんでした。

import * as AutoKana from 'vanilla-autokana'

を取って、`require`に直接バインドさせます。
```ts
<script lang="ts">

mounted() {
  if (process.client) {
        autokanaName = require('vanilla-autokana').bind('#name', '#kana', { katakana: true, })
      }
}
```
こうすることで、windowのエラーは回避できました。
![スクリーンショット 2022-04-21 16.54.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1134006/657cb055-4bb0-edd1-4a78-11f027410c5a.png)
次に来るのがこちらの問題、これはもうさっぱりわかりませんでした。`#(シャープ)`で指定した`ID`の要素を紐づけている訳ですが、`.(ドット)`でクラスの要素にしてもビクともしません。
![スクリーンショット 2022-04-21 17.11.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1134006/c0bf0fa6-d892-98f6-763c-43000d4cb23e.png)
`Vue`のドキュメントに`mounted`で`$nextTick`を使ってビュー全体をレンダリングするまで待つとあったのでそれを使います。
```ts
<template>

     <input
            id="name"
            v-model="form.name"
            class=""
            type="text"
            placeholder=""
            @input="handleNameInput"
          />
     <input
            id="kana"
            v-model="form.kana"
            placeholder=""
            type="text"
            class=""
          />

</template>

<script lang="ts">

interface Form {
  name: string
  kana: string
}

export default class Hoge extends Vue {

form: Partial<Form> = {}

async mounted() {
    
      if (process.client) {
        this.$nextTick(() => {
          autokanaName = require('vanilla-autokana').bind('name', 'kana', {
            katakana: true,
          })
        })
      }
    })
  }

handleNameInput() {
    this.form.kana = autokanaName.getFurigana()
  }

</script>
```
`$nextTick`を付与し`#`を外します。
![スクリーンショット 2022-04-21 17.46.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1134006/ffa79071-ed04-3779-188c-57de9c5c01f3.png)

`vanilla-autokana`を発動させることができました。
Cloud Run の認証が必要なサービスを Cloud Scheduler から実行する



# はじめに

* この記事では Cloud Run の認証が必要なサービスを GCP の定時ジョブ実行サービスである Cloud Scheduler から実行する方法を紹介します。

# Cloud Run 実行用のサービスアカウントの作成

* GCP コンソールにログイン
* メニューから「IAM と管理」の「サービスアカウント」に移動
* 「サービスアカウントを作成」から作成開始
    * 「サービスアカウント名」と「サービスアカウントID」は任意のもの
	* 「ロール」に「Cloud Run 起動元」を追加
    * 「作成」ボタン押下で作成完了

# Cloud Run のサービスの作成

## コンテナの作成

* https://github.com/GoogleCloudPlatform/golang-samples を clone
* コンテナをビルドして Cloud Registry に push

```
cd run/helloworld
gcloud builds submit --tag gcr.io/YOUR_PROJECT_ID/helloworld
```

## サービスの作成

* GCP コンソールにログイン
* メニューから「Cloud Run」に移動
* 「サービスの作成」から作成開始
    * 「既存のコンテナ イメージから 1 つのリビジョンをデプロイする」で push したコンテナを選択
	* 「サービス名」と「リージョン」は任意
	* 「認証」は「認証が必要」にチェックする
    * 「作成」ボタン押下で作成完了

# Cloud Scheduler のジョブの作成

* GCP コンソールにログイン
* メニューから「Cloud Scheduler」に移動
* 「ジョブを作成」から作成開始
    * 「名前」「頻度」「タイムゾーン」は任意のもの
	* 「ターゲット」は「HTTP」
	* 「URL」は作成したサービスの URL
	* 「HTTPメソッド」は「GET」
	* 「SHOW MORE」の中の「Auth ヘッダー」は「OIDC トークンを追加」で「サービスアカウント」は作成したサービスアカウントのメールアドレスを指定
    * 「作成」ボタン押下で作成完了
* 作成したジョブの「今すぐ実行」ボタンを押下して動作確認

# 手順通りに設定しても「PERMISSION_DENIED」になる場合

* Cloud Scheduler API を 2019 年 3 月 19 日より前に有効にした場合のみ必要なサービスアカウントが不足しており手動で作成しなければ正常に動作しないという状態になっています。
* 作成手順は https://cloud.google.com/scheduler/docs/http-target-auth?hl=ja#add です。
Oracle 一定期間前のデータを取得する方法(フラッシュバッククエリ)

## Oracle 一定期間前のデータを取得する方法(フラッシュバッククエリ)
使う機会はほとんどないと思うがコミットまでした更新・削除データを取得するクエリ。
テストとかでやらかした時とかに使うかも？

例：100分前のデータを取得するクエリ
```
select * from MY_TABLE as of timestamp(systimestamp - interval '100' minute)
```
POのScrumイベント参画

システムの機能要件を定義し、その優先順位を決め、開発プロジェクトを進行させるProduct Owner（PO）。役割としてとても重要であるのは間違いないのですが、SIerとしてAgile開発のプロジェクトに関わると、存外にこのPOという役割の重要性がクライアントにご理解頂けないことで、プロジェクトの運営に問題が生じることがあります。

<b>Scrumを組めるほどに時間がない？</b>

ウォーターフォール型のシステム開発と比べると、Scrumはかなり開発側とクライアント側（PO）がコミュニケーションに費やす時間が増える傾向があります。これがあるからこそビジネスに必要なシステムの要件がつぶさに検討できるし、軌道修正が迅速にできるし、ということになってきます。（多分）

しかし、ウォーターフォール型の開発でおおよそ典型的な週一、曜日と時間を指定したせいぜい1－2時間くらいの定例会と比較するとScrumの各イベントに要する時間というのは初めてこれに臨む人からすると「かなり多い」という印象を持たれると思います。

スプリント計画会議：約半日

バックログリファインメント：必要な都度

スプリントレビュー：そのスプリントでの全機能を一通り動かすしそれに対するフィードバックをもらうので2時間くらいは必要になってくる。

レトロスペクティブ：ワークショップ形式・全員参加の反省会。これも2時間くらいないとすごく中途半端になる。

普通のウォーターフォール型システム開発と比較して拘束時間が3－4倍くらいになるというのがScrum開発での感覚です。普通の事業会社の正社員だとシステム開発をすることに100％労働時間を投下できるわけではないので、大体のプロジェクトでこのうちのいくつかへのPOの参画が欠落していくのですが、多くのケースで「POが参加してくれるのがスプリントレビューだけ」という現実があります（笑）

結局、我々ベンダー側の営業だったりという人間がクライアント側のPOの代理だったり補佐だったりという立ち位置でスクラムイベントに参加するのですが、これは本来のクライアント側のPOとは似て非なるものであるわけで、顧客自身のニーズからは乖離していくことになるわけです。

<b>一人では判断できない？</b>

大企業は大企業とお付き合いしたがる傾向があるので、大きな企業には大きなSIerが普通は付きます。（作るシステムの規模も当然大きいので、小さなソフトハウスでは対応できないし何より保証できない）

そうなると、システムの要件を決めるという重要なタスクが「たった一人の判断」ということはありえなくなってくるわけです。大企業だと、要件を決めるために相当の数の部署だったりキーマンだったりというところと調整・根回しをしなければならないわけで、その意味で意思決定がたったの一人で完結するということはまずないわけです。

スプリントを開始する冒頭のタイミングでスプリント計画会議という、いわば「今後2－3週間で何をどういう順番で開発していくのか」という場が持たれますが、「何を」「どういう順番で」ということが、忙しい中一生懸命時間を工面してその場に居合わせてくれたPOの皆さんだけでは決めきれないという事態が生じます。

<b>鉄は熱いうちに打て</b>

この「POが思うようにイベントに参加してくれない」という事象はScrum開発の現場で非常にしばしば目にする状況です。これを防ぐには、プロジェクトが発足する冒頭の部分でウォーターフォールとAgileの違いを説明し、Agileを採用する場合には相応の「人的・時間的リソースの投下」と「その場で完結する意思決定の可能なメンバー」が必要だということをガッチリ説明してご納得頂いた上で始める、ということです。中途半端なScrumをやるくらいであれば「期間の短いウォーターフォールを繰り返す」という方が、まだ歪みが少なくて良いと思うのです。
nginx proxy

```
vi /etc/nginx/sites-enabled/default
```
```
location / {
                proxy_pass http://127.0.0.1:8080;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header Host $host;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 
        }
```
```
nginx -t
```
Dockerで構築したローカルのWebサーバー上で自分のIPアドレスがわからなかった話

### 困った出来事
Webサイト改修案件のリリース時に、移行中は特定のIPアクセス以外はメンテナンスページにリダイレクトするようにした。
```.htaccess
<IfModule mod_rewrite.c>

  ErrorDocument 503 /maintenance.html
  RewriteEngine on
  RewriteCond %{REQUEST_URI} !^/maintenance.html$
  RewriteCond %{REMOTE_ADDR} !=10.1.1.101 #自分のIPアドレス
  RewriteRule ^.*$ - [R=503,L]
</IfModule>
```

一応うまくIPアドレスの制御ができてるか確認するために、Docker上の開発環境で試してみたところ、
**自分自身もメンテナンスページにリダイレクトしてしまうんだが…？**
となり詰まった上解決方法が調べても出てこなかったので、ここに記しておく。


### 解決法
結論を先に書くと、**DockerではクローバルIPアドレスではなく、GateWayのIPアドレスを指定する必要があるらしい。**
私みたいに見様見真似でDockerを導入してみた人間には、「GateWayって…どこみればわかるん？？？」となるので、以下にその確認方法も載せておく。
何も指定しなければ*172.19.0.1*になるっぽい。

### 調べ方
#### 対象コンテナのネットワーク名を調べる
```.cmd
$ docker network ls
NETWORK ID     NAME                       DRIVER    SCOPE
4a07eb4edc93   bridge                     bridge    local
b67bed0ffcf0   sample_default             bridge    local
a74e1b333434   host                       host      local
76b4e13bf0cd   none                       null      local
```
とくにネットワーク名を指定していない時は*コンテナ名_default*になる模様。
今回はsample_defaultが対象のネットワークとして進める。
ちなみにネットワーク名などを変えたい時は以下の記事が参考になるかと。

https://qiita.com/satodoc/items/188a387f7439e4ec394f

#### ネットワークの詳細情報を確認する
```.cmd
$ docker network inspect sample_default 
[
    {
        "Name": “sample_default",
        "Id": "b67bed0ffcf092524d1758bb488410cd0ae2a4f41febd72d76aed9221f686",
        "Created": "2022-01-05T05:03:06.319979838Z",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.19.0.0/16",
                    "Gateway": "172.19.0.1" ←これ
                }
            ]
        },
--------------中略--------------------------------
    }
]
```
この中の`"Gateway":`にあたる部分がそれ。
【Raspberry pi 4】OSバージョン確認

## 環境
（追記予定）
## CLI接続方法
参考：[Tera Termを利用してCLI接続する（追記予定）](https://)
参考：[コマンドプロンプトでSSH接続する（追記予定）](https://)

## ハードウェア情報の確認方法
### Modelを確認する
~~~:model
admin@TKY-RP001:~ $ cat /proc/device-tree/model
Raspberry Pi 4 Model B Rev 1.4 admin@TKY-RP001:~ $
admin@TKY-RP001:~ $
~~~
*プロンプトの表記が改行されずに出てくるのはバグか仕様のようです。

### CPU-infoを確認する
~~~:cpuinfo
admin@TKY-RP001:~ $ cat /proc/cpuinfo
processor       : 0
BogoMIPS        : 108.00
Features        : fp asimd evtstrm crc32 cpuid
CPU implementer : 0x41
CPU architecture: 8
CPU variant     : 0x0
CPU part        : 0xd08
CPU revision    : 3

processor       : 1
(中略)

processor       : 2
(中略)

processor       : 3
(中略)

Hardware        : BCM2835
Revision        : d03114
Serial          : 100000008a57c336
Model           : Raspberry Pi 4 Model B Rev 1.4
admin@TKY-RP001:~ $
~~~

## OSバージョン情報の確認方法

### debian_versionを利用する
~~~:debian_version利用
admin@TKY-RP001:~ $ cat /etc/debian_version
11.3

admin@TKY-RP001:
~~~

### issueを利用する
~~~:issue利用
sit-admin@TKY-RP001:~ $ cat /etc/issue
Debian GNU/Linux 11 \n \l
admin@TKY-RP001:
~~~

### lsb-releaseを利用する
~~~:lsb-releaseのInstall
admin@TKY-RP001:~ $ lsb_release -a
No LSB modules are available.
Distributor ID: Debian
Description:    Debian GNU/Linux 11 (bullseye)
Release:        11
Codename:       bullseye

admin@TKY-RP001:~ $
~~~
*lsb-releaseはパッケージインストールが必要です。
インストールされていない場合は下記コマンドでインストールしましょう。
~~~:lsb-releaseのInstall
admin@TKY-RP001:~ $ sudo apt-get install lsb-release
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
lsb-release is already the newest version (11.1.0).
lsb-release set to manually installed.
The following package was automatically installed and is no longer required:
  libfuse2
Use 'sudo apt autoremove' to remove it.
0 upgraded, 0 newly installed, 0 to remove and 11 not upgraded.

admin@TKY-RP001:
~~~

## カーネルバージョンの確認方法
### unameを利用する
~~~:uname
admin@TKY-RP001:~ $ uname -a
Linux TKY-RP001 5.15.32-v8+ #1538 SMP PREEMPT Thu Mar 31 19:40:39 BST 2022 aarch64 GNU/Linux

admin@TKY-RP001:~ $
~~~

### hostnamectlを利用する
~~~:hostnamectl
admin@TKY-RP001:~ $ hostnamectl
   Static hostname: TKY-RP001
         Icon name: computer
        Machine ID: a467b64477be4c6cbc88916ec1a206a4
           Boot ID: 117f2b2f45d2445bb5ed65358ef347fc
  Operating System: Debian GNU/Linux 11 (bullseye)
            Kernel: Linux 5.15.32-v8+
      Architecture: arm64

admin@TKY-RP001:~ $
~~~
B - Chocolate

## 問題
https://atcoder.jp/contests/abc092/tasks/abc092_b



## 答え
```
n = int(input())
D, X = map(int, input().split())
A = [int(input()) for i in range(n)]
ans = 0
for i in range(n): #2の時、5の時、10の時
  for j in range(1,D + 1,A[i]):
    ans += 1
ans = X + ans
  
print(ans)
```

## ポイント

range(start, stop, step)のように引数に整数を3つ指定すると、start ≦ i < stopでstepずつ増加する等差数列が生成される。
第三引数が増える数となる。
引数stepに負の値を指定すると減少していく。この場合は、start ≦ stopでないと空となる。
これを使って合宿の日におけるAiの値が入る日はいくつあるのかを計算することができる。

https://note.nkmk.me/python-range-usage/#rangestart-stop-step
goで変数をtemplateの名前として利用する

# 実現したいこと
goで使用可能な`text/template`のテンプレート名として変数名を使いたいと思います。

しかしそのまま利用しようとする以下のコードはPanicが発生してしまいます。
```golang:失敗例
package main

import (
	"os"
	"strings"
	"text/template"
)

var TMPL = strings.Trim(`
{{- /* []string expected */}}
{{- define "sasakuna"}}
{{- range $i, $text := . }}
{{$i}}: {{$text}}
{{- end }}
{{- end }}
`, "\n")

func main() {
	tmpl := template.Must(template.New("").Parse(TMPL))
	tmpl = template.Must(tmpl.Parse(`{{ template .Name .Data}}`))

	tmpl.Execute(os.Stdout, struct {
		Name string
		Data []string
	}{
		Name: "sasakuna",
		Data: []string{"sasa", "kuna"},
	})

	// Output:
	// panic: template: :1: unexpected ".Name" in template clause
}
```
[Play Groundで開く](https://go.dev/play/p/-M5gYCHNwZV.go)

当然のことではありますが、テンプレート名として固定の文字列を使用すれば問題なく動作します。


```golang:変数を使用しない成功例
package main

import (
	"os"
	"strings"
	"text/template"
)

var TMPL = strings.Trim(`
{{- /* []string expected */}}
{{- define "sasakuna"}}
{{- range $i, $text := . }}
{{$i}}: {{$text}}
{{- end }}
{{- end }}
`, "\n")

func main() {
	tmpl := template.Must(template.New("").Parse(TMPL))
	tmpl = template.Must(tmpl.Parse(`{{ template "sasakuna" .}}`))

	tmpl.Execute(os.Stdout, []string{"sasa", "kuna"})
	
	// Output:
	// 0: sasa
	// 1: kuna
}
```
[Play Groundで開く](https://go.dev/play/p/9AUq0p50Q1G.go)

このことに関しては、かなり前の質問とそれに対する回答として記載されています。
https://stackoverflow.com/questions/28830543/how-to-use-a-field-of-struct-or-variable-value-as-template-name

中で示されている理由を読んでみると、参照関係を読み解きやすくするため？というふうに読めます。なんとなくわかりますが、不便さを感じる場面もあるかと思います。

## 対処方法
この問題に対処するための方法として、テンプレート内で関数が使用できることを利用します。
```golang:変数名で指定に成功
package main

import (
	"bytes"
	"fmt"
	"os"
	"strings"
	"text/template"
)

var TMPL = strings.Trim(`
{{- /* []string expected */}}
{{- define "sasakuna"}}
{{- range $i, $text := . }}
{{$i}}: {{$text}}
{{- end }}
{{- end }}
`, "\n")

func main() {
	inlineTemplate := generateInlineTemplates(
		[]string{
			TMPL,
		})
	tmpl := template.New("")
	tmpl = template.Must(tmpl.Parse(`{{ call .InlineTemplate .Name .Data}}`))

	tmpl.Execute(os.Stdout, struct {
		Name           string
		Data           []string
		InlineTemplate func(string, any) string
	}{
		Name:           "sasakuna",
		Data:           []string{"sasa", "kuna"},
		InlineTemplate: inlineTemplate,
	})

	// Output:
	// 0: sasa
	// 1: kuna
}

func generateInlineTemplates(
	definitions []string,
) func(string, any) string {
	templates := template.New("")
	for _, def := range definitions {
		templates = template.Must(templates.Parse(def))
	}
	return func(name string, param any) string {
		buf := bytes.NewBuffer([]byte{})
		tmpl := template.Must(templates.Parse(fmt.Sprintf(`{{template "%s" .}}`, name)))
		if err := tmpl.Execute(buf, param); err != nil {
			panic(err)
		}
		return buf.String()
	}
}
```
[Play Groundで開く](https://go.dev/play/p/O0J9yYVZlVW.go)

ポイントとしてはテンプレートで展開するためのコードを関数内で定義することです。関数の作りはかなり雑ですが、うまいことWrapすればほぼ気にすることなく利用可能かと思います。
ご自身の利用用途に合わせてご利用ください。
dockerでyumやsystemctlがつかえない

# 概要
dockerにcentosを入れてその上でApache,php,pythonを動かすときに色々と困ったので自分メモとしてQiitaに残しておきます。

初投稿なので色々と日本語がおかしかったりうまく書けていなかったりするところがあると思いますがご了承ください。

# はまったこと一覧
- dockerのコマンドがいまいち分かっていない
- パッケージを入れようとしたらyumが使えない
- yum問題解決後httpdを立ち上げようとしたらsystemctlコマンドが使えない

# dockerのコマンドがわからない
これは私の勉強不足です。
今後も使っていくと思うのでメモがわりに残しておきます。
```
docker pull centos
```
まずはマシンイメージをダウンロードしてきます。
```
docker run -it -p 9999:80 --name xxxxx centos /bin/bash
```
コンテナの作成、起動をします。
今回はApacheを使いたかったためホストOSの9999番ポートに来たものを80番ポートにポートフォワードします。

# yumが使えない
コンテナにcentosを入れていざApacheを使おうと思ったらyumコマンド時にエラー発生
```
Error: Failed to download metadata for repo 'appstream': Cannot prepare internal mirrorlist: No URLs in mirrorlist
```
直訳するとミラーリストにURLがないよと言われました。
このエラーで検索してみるとさまざまな解決法が出てきました。
ですがどれを試してもエラーは変わらず、ミラーリストにURLを登録するだけだと思っていましたがうまくいきませんでした。
もっと色々試してエラーを治してみたかったのですが今回はやりたいことがあったので別の方法を試しました。
#### centosのバージョンを指定してインストール
結局解決しなかったので
```
docker pull centos:centos7
```
これでcentosのバージョン指定をしてコンテナの作成をしたところcentos7ではyumが使えました。
こちらの方が楽ですね


# systemctlコマンドが使えない
yumが使えるようになりhttpdを入れていざWEBサーバ化と思ったらsystemctlがつかえないという事案が発生しました。
どうやらsystemdはcentos7のデフォルトでは有効化されていないということらしいです。
有効化するには管理者権限がいるためコンテナ起動時に  **--privileged**  というオプションが必要です。
さらにそれだけではエラーは治りません
```
Failed to get D-Bus connection: Operation not permitted
```
そこで最初に  **/sbin/init**  を実行してあげることでsystemctlが使えるようになります。
完成形
```
docker run -it --privileged -p 9999:80 --name **** centos:centos7 /sbin/init
```
これでApacheも入り、systemctlで立ち上げることができました。
とりあえずはこれで準備は終わりました。

# まとめ
ただphpとpythonをすこし動かしたいだけだったので簡単なことだと思ったのですが意外苦労したのでここにまとめておきます。
拙い文章で申し訳ないのですが、意外と皆さんつまるところではないのかなと思います。
こんな投稿で救われる人がいるなら共有しておこうと思い記事にしました。
間違っている部分や日本語がおかしいところ、この書き方が読みにくいなどがあればコメントしていただけると助かります。

# 参考記事
https://weblabo.oscasierra.net/docker-centos7/

https://momozo.tech/2020/02/22/centos7%E3%82%B3%E3%83%B3%E3%83%86%E3%83%8A%E3%81%A7systemctl%E3%81%8C%E4%BD%BF%E3%81%88%E3%81%AA%E3%81%84%E6%99%82/
Svelte.jsとpnpmを使ってprettier動かない時の対処法

## 初めに
Svelte.jsとpnpmを使って、prettierパッケージはプラグインとして自動的に検出できないことはあります。\
VS Codeを使用している人にとっては、prettierプラグイン（esbenp.prettier-vscode）も効かないことはあります。

## 対処法
`.prettierrc.cjs`で以下を追加
```js
  plugins: ['./node_modules/prettier-plugin-svelte'],
```

## VS Codeユーザー
`settings.json`で以下を追加

```js
"prettier.documentSelectors": ["**/*.svelte"]
```
また`.prettierrc.cjs`で以下を追加

```js
  overrides: [
    {
      files: '*.svelte',
      options: { parser: 'svelte' },
    },
  ]
```
補助記憶装置

復習回数1
## 補助記憶装置
CPUは<font color = blue>主記憶</font>上にある、データなどしか読み書きできない。
主記憶は小容量かつ揮発性を持っている。
<font color = blue>補助記憶装置</font>は大容量かつ安価で、不揮発性の特徴がある。しかし、アクセス速度は遅い。
## 磁気ディスク装置
<b>磁性体を塗った円盤状のディスクにデータが記録され、磁気ヘッドを移動させながらデータを読み書きする装置。別名：<font color = blue>ハードディスク</font>
### 磁気ディスク装置の構造
複数枚で構成されており、データを記録する最小単位の<font color = blue>セクタ。</font>
セクタがいくつか集まって円心円状の<font color = blue>トラック。</font>
トラックがいくつか集まり、一面となる。
中心から等距離にあるトラックの集まりを<font color = blue>シリンダ</font>という。これらは<font color = blue>セクタ方式。</font>

### アクセス時間
CPUが、データの読み書きの指令を出してから、終わるまでの時間のこと。

<b><font color = blue>位置決め時間（シーク時間）</font> - 磁気ヘッドを目的のデータが存在するトラックまで移動させるのにかかる時間
<font color = blue>回転待ち時間(サーチ時間)</font> - 目的のデータが、磁気ヘッドの位置まで回転してくるのを待つ時間
<font color = blue>データ転送時間</font> - 目的のデータが磁気ヘッドを通り過ぎるのに要する時間。</b>

## フラグメンテーション
<b>磁気ディスク装置にデータの追加や削除を繰り返すと、データが連続した領域に保存されなくなる(断片化)現象。これを解消するのが<font color = blue>デフラグ</font></b>

## フラッシュメモリ
<b>電気的に全・部分的に消去して内容を書き直せる半導体メモリ。
<font color = blue>USBメモリ</font>や<font color = blue>SDカード</font>が代表的。</b>

## SSD
<b>フラッシュメモリを用いた、磁気ディスク装置の代わりとなる記憶媒体。シーク・サーチ時間などが無い</b>

## 光ディスク
<b>レーザ光を使ってデータを読書きする記憶媒体</b>
### 記憶方式
<b><font color = blue>再生専用型・追記型・書換え型</font></b>がある

参考文献：イメージ&クレバー方式でよくわかる 栢木先生の基本情報技術者教室
PCをキーボード/マウスから解放し、PCの操作をシンプルにする（ハードRPAの紹介と最初の一歩）

2年越しに小さな改良重ねてきたハードRPAを紹介します！
https://vidya.asia/uicreator/

活用例はこちらから
https://qiita.com/ogr31/items/c574ba20844a5e0e74ed

![IMG_3459-removebg-preview.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2635808/3fa7cec4-9753-9060-c9af-78f6b0d20eee.png)
この1ガジェットのそれぞれのキーに、キーボード、マウス、ゲームパッドの機能を登録することができます。
![マルチ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2635808/5fcbe99b-ea46-85a8-72ee-30ec315557ab.png)
※写真のUIクリエーターは3世代前のものです。
ハードRPAをUSBでPCに接続するだけで、キーボード、マウス、ゲームパッドとして認識されます。
設定はブラウザーから行います。（Blocklyを使用しています）
https://vtech.sakura.ne.jp/visual/ui/
![screencapture-vtech-sakura-ne-jp-visual-ui-set-2022-04-21-15_12_39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2635808/6bba4ffc-358e-2d39-358d-85fe15024e75.png)
こちらのブラウザーからWebシリアルで直接UIcreatorに書き込むので接続替え/切り替えすることなくシームレスに設定を試すことができます。

ハードRPAにはキースイッチに並列に接続されたジャックが備え付けられています。
ここに外部スイッチ/センサーを接続することができ、キースイッチに代わってトリガーにすることができます。
![スライド16.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2635808/cc5dc557-d0e6-affa-94d7-b11740560633.png)
これによりPCの操作方法が無限大に広がっていきます。このジャックには＋５Vも出力されているので、センサーの設置を簡単にすることができます。
いくつか応用例をあげてみます。

１．製造現場でのPCへの記録は作業員にとって面倒なものです。このPCの一連のキーボード操作をハードRPAに接続したフットスイッチで行えば面倒さが無くなります。また工作機械に設置されたセンサーからの信号でPCの複雑な操作をすることができます。
![スライド19.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2635808/fd3e202d-8904-7ac5-e172-95b6a78c56ac.png)

２．通常のRPAの機能をハード的に代替わりすることができます。また日常行っている業務の単純操作を設定しておくことで、ワンキーで素早くストレスなく行うことができます。
![スライド18.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2635808/c703ae84-24fc-2de8-c82b-a0337b156a1a.png)

３．PC操作の苦手な方々のお手伝いができます。PCに慣れた人にとって単純な作業でも苦手な人にとっては苦痛です。例えば「メーラーを開ける」「シャットダウンする」といった操作を設定しておけば、ワンキー、外部スイッチで誰でも操作できるようになります。
![スライド20.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2635808/b76d7d58-3664-3946-1c53-0969f0201236.png)

４．M5StackVをカラスの認識センサーにし、カラスが来たらハードRPAのスイッチを入れ、ハードRPAはPCを操作し、猫の鳴き声のmp3を再生し、カラスが来たことをメールで送る、ということもノンプログラムでできます。
![スライド21.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2635808/2e8f81fd-938d-ef31-aae6-0e6d4ac93215.png)

５．いろいろなスイッチでPCを操作できるので、手が離せない作業をしているときに、キーボードやマウスの一連の作業をハードRPAが行います。
![スライド23.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2635808/18846b8f-dc70-576a-b2b9-d7bdd066dc89.png)

６．アプリのショートカットを設定しておくことで、専用のコンソールが出来上がります。例えばOBS Studioも放送局のコンソール卓のようにカメラの切り替えをお好みの物理ボタンで確実に行うことができるようになります。
![スライド24.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2635808/0c568415-0dc1-2c06-14af-762b1eb90050.png)

７．障碍者のPC操作をサポートします。多様なスイッチ/センサーをPCに接続できるので障碍に合わせたPC操作環境を手軽に作ることができます。
![スライド5.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2635808/e0be990c-bedc-956f-7d6e-41d86749c8ff.png)
ホーキング氏が使っていた音声発生も新たにシステムを開発することなく可能になります。
![スライド7.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2635808/24c2553c-2a89-784a-87f3-c8f1d53b579f.png)
EC2インスタンス同士で通信するためのセキュリティグループ設定いろいろ

# はじめに
EC2インスタンス同士で通信するためのセキュリティグループ設定について調べたら、いろいろな設定の仕方があることがわかったのでまとめておきます。  
ちなみに、セキュリティグループの変更は即適用で、EC2インスタンスの再起動などは必要ありません。
# EC2インスタンス同士で通信するためのセキュリティグループ設定
## 1. 通信相手のIPアドレスを指定
![ec2connect1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2528939/07d0a796-3087-50cc-a445-d0f57f1a4588.png)
まずは、通信相手のEC2インスタンスのIPアドレスを直接指定する方法です。  
一番最初に思い付くのがこの方法なのではないでしょうか。
この方法でも問題ないのですが、EC2インスタンスのENIをアタッチ、デタッチしたりしている場合は将来IPアドレスが変わる恐れがあるため、そういった状況に対応できるような柔軟な設定方法ではありません。  
また、通信相手が多数存在する場合は、セキュリティグループ設定が煩雑になります。
## 2. 通信相手のセキュリティグループを設定
![ec2connect2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2528939/b7b10cfa-5b6c-c8fd-1bbd-2d4cd2a65f70.png)
次は、通信相手のEC2インスタンスのセキュリティグループを指定する方法です。  
セキュリティグループにはIPアドレスしか設定できないと思っている方も多いと思いますが（私もそうでした。。。）、実はセキュリティグループも設定できるんです！  
複数のEC2インスタンスを使ってクラスタを組む場合など、同じセキュリティグループを適用しているEC2インスタンス同士の通信を許可したい場合は、セキュリティグループを指定すると設定が楽です。  
この方法だと、EC2インスタンスのIPアドレスが変わった場合でも、セキュリティグループの設定に影響がないのも嬉しいですね。
## 3. VPCまたはサブネットのIPアドレスを指定
最後に紹介するのが、VPCまたはサブネットのIPアドレスを指定する方法です。  
セキュリティグループにVPCやサブネットのIPアドレスを指定すると、そのネットワーク内部からの通信を許可できます。  
VPCやサブネットのIPアドレスは、VPCのコンソール画面で確認できます。  
![ec2connect6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2528939/a7fb17c2-921a-6601-a059-eb68c6173ba6.png)
![ec2connect4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2528939/c6f4009e-f3c6-832d-0b75-0f96c06e63af.png)
EC2インスタンスをデフォルトのネットワーク設定で立ち上げている方はVPCの存在をあまり意識することがないかもしれないので、念のため以下の図を載せておきます。   
EC2インスタンスはVPCというネットワーク上のサブネットに配置されています。  
![ec2connect5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2528939/4a20166b-f5df-e266-1541-56166cd58fc0.png)
ネットワークの外側からの通信だけブロックできればいい、というようなセキュリティグループ設定を行いたい場合はこのような設定も可能です。
# おわりに
セキュリティグループの設定は通信相手のIPアドレスを直接指定する方法以外にも、セキュリティグループや、VPC、サブネットの範囲で許可することもできるので、状況に合わせて使い分けられるとセキュリティグループの設定が楽になります。
【Python】リストの列に同じ値を埋める【Numpy】

# はじめに
自分が調べた限り、2次元リストの列に同じ値を埋める方法がfor文しかなかったので、使わない方法を以下に載せます。

~~~
import numpy as np

# 5x5の2次元リストを作成
array = np.zeros(5*5).reshape((5,5))

# 4列目に「1」を埋める
array[:,3].fill(1)
~~~

# おまけ
行に同じ値を埋めたい場合は以下になります。

~~~
# 3行目に「1」を埋める
array[2].fill(1)
~~~

# 追記
コメントでの@WolfMoon様のやり方が簡素だったので載せさせて頂きます。コメントありがとうございます。

~~~
array[:, 3] = 1 # 列に同じ値を代入
array[1, :] = 200 # 行に同じ値を代入
~~~

# まとめ
ゲーム制作でマップを2次元リストで表現する際に躓いたので載せました。
誰かの参考になれば幸いです。
また他に良い方法があればコメントで教えて下さるとありがたいです。
VPN接続をスクリプト内で実行する

## 前提
- Windows 10
- Windowsのsetting > network&internet > VPNからVPNを追加してあること

## VPN接続をコマンドで実行

C:\windows\system32\rasdial.exeを使う

### コマンドプロンプトからVPN接続する場合

``` connect-vpn.cmd
C:\windows\system32\rasdial.exe [VPN名*] [ユーザー名] [パスワード]
```
*VPN名は、Windowsのsetting > network&internet > VPNで設定したときのVPN名


### コマンドプロンプトからVPN接続解除する場合

``` connect-vpn.cmd
C:\windows\system32\rasdial.exe [VPN名*] /DISCONNECT
```

## ひっかかりポイント
パスワードやユーザー名に特殊な文字が入っていて認識されない場合がある

指定されたファイルが見つかりません　と表示されてしまって接続試行すらされない


### 回避策

- powershellでコマンド実行
- 必要があれば上記をbatで呼び出す



### PowerShellからVPN接続する場合
``` connect-vpn.ps1
C:\windows\system32\rasdial.exe [VPN名*] [ユーザー名] [パスワード]
```
*VPN名は、Windowsのsetting > network&internet > VPNで設定したときのVPN名


### batからPowerShellスクリプトを呼び出してVPN接続する場合
``` connect-vpn.bat
cd [connect-vpn.ps1のパス]
powershell ./connect-vpn.ps1
```


***

bat にしておくとスタートアップやタイムスケジューラで設定することもできて便利。

以上
シンボリックリンク先のcss、jsの読み込みについて


## 内容
環境構築をしていて行き詰まったのでメモ

シンボリックリンクで設定したcss、jsはChromeだと読み込めないらしい

## 参考URL
https://blog.rmblankslash.net/entry/403692254.html_1
JS　Youtube　埋め込み　レスポンシブ

```src.html
<div class="movie">
  <iframe src="https://www.youtube.com/embed/xxxxxx" allowfullscreen></iframe>
</div>
```

```script.js
$(()=>{
    const bw = document.body.scrollWidth;
    // 表示幅700以上の場合のみ
    if(bw > 700) {
        // 横：コンテンツ幅の80%、縦：横の9/16サイズ
        const w = $('.movie')[0].clientWidth;
        $('iframe').attr('width', w * 0.8);
        $('iframe').attr('height', w * 0.8 * 9 /16);
    }
});
```
【機械学習】二項分類の評価指標4つについてまとめてみたよ【混合行列】

二項分類のモデルの良し悪しを見るとき、混合行列をよく使う気がします。
そして、それに付随して再現率、適合率、Ｆ値、正解率とかが良く出てくる。これらが何なのかを忘れないようにメモっておきます。

# 混合行列

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395106/47c4d877-b928-7d8e-a4e4-38d7554e920c.png)

混合行列は上記のように、機械学習が出した予測値と実際に計測した値を並べた表になります。
表の青色の部分が正しく予測できた数、赤色になってるのが間違っている数を表します。

これらの値をもとに先述した評価指標を求めていくことになります。

# 再現率(TP/(TP+FN))
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395106/ac358782-3bf8-a742-7e20-bd5d99087c81.png)

再現率は**実際に正であるデータのうち正しく正であると予測できたデータの割合**を表します。
つまり、実際に正である値をどれだけとり逃すことなく予測できたかを表す指標です。
レコメンドのように、**可能性があるものは少しも取り逃したくない**というときに参考にするとよいでしょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395106/520ae506-744f-feb0-12b5-0085daf02c13.png)
(緑枠は正と予測したデータを表してます。)

注意点として、再現率100%でも**大量に負を正と誤って予測することがある**ので気をつけましょう。



# 適合率(TP/(TP+FP))
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395106/712715aa-1c5d-d755-3146-30d2c35d94d0.png)

適合率は**正と予測したデータのうち実際に正だったデータの割合**を表します。
つまり、正と予測したものがどれだけ正しかったかを表す指標です。
正と予測したものが必ず正であってほしい場合に参考にするとよいでしょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395106/c080f800-72ab-bf2e-dd53-06f6dd5aa70f.png)
(緑枠は正と予測したデータを表してます。)

注意点として、適合率が100％でも**大量に正解をとり逃すことがある**ので気をつけましょう。


# F値((2*再現率*適合率)/(再現率+適合率))
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395106/42b650ca-f9f5-a9a3-f3dc-3d1fb8a330a0.png)

F値は再現率と適合率の調和平均をとったものです。
調和平均とかいう難しい言葉を使ったいますが、要するにこの二つの指標をバランスよく判断している、と思っていいと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395106/39df28a6-3f57-610e-ed13-0a3a9e2aec2f.png)
(緑枠は正と予測したデータを表してます。)

上の図のようにF値は**どれだけ正のデータを正しく予測できているか**、を表す指標になります。
正の予測が外れたり、負のデータを誤って正と判断するとこの評価値は下がっていきます。
**特に使用用途が決まっておらず、精度を求めたいとき**はF値を参考にするといいかもしれません。

# 正解率((TP+TN)/(TP+TN+FP+FN))
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395106/72fda2bc-ab5e-8cba-28fe-7ec307e444b2.png)



正解率は**すべてのデータのうち正しく予測できた割合**を表しています。
一見それらしい値に見えますが、欠点があります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/395106/81c28ddc-2782-c50f-7499-668c894e20b8.png)
(割合の表示がミスってたので更新しました)
(緑枠は正と予測したデータを表してます。)

ここにデータ量が偏ったデータがあったとします。
このモデルは常に正と予測するだけのモデルですが、正解率は90％と出てしまいます。
このように**データの偏りによってよさそうな値でもよいモデルとは限らない**ことがあります。
**データが偏っておらず、かつ正、負ともに正確に予測したい場合**には正解率を利用してもいいのかもしれません。


# まとめ
精度の指標について振り返りが必要だったので簡単にまとめておきました。
これ以外にもaucや特異性などもあるようなので時間があれば追加でまとめておきます。
半導体メモリ

復習回数1
# 半導体メモリ
記憶装置に使用されている。

## ROM
<b>本来は、読み出し専用のメモリ。最近は書き込みも可能に。
電源を切っても記憶していた内容が消えない特性がある(<font color = blue>不揮発性</font>)
フラッシュメモリ - 電圧をかけて全・部分消去できる。書き換えはブロック単位で消去後に書き込む</b>
## RAM
<b>読み書きできるメモリ。電源を切ると記憶していた内容が消える特性がある</b>（<font color = blue>揮発性</font>）
RAMにはさらに、次のようなものがある。
### DRAM
コンデンサに電荷を蓄えたか否かで1ビットを表現。低速。
<font color = blue>SRAMと比べて大容量で安価。しかし、一定時間ごとに記憶内容を維持するリフレッシュ動作（再書込み）が必要。主記憶に用いられている。</font>
### SRAM
フリップフロップ回路で構成され高速。
<font color = blue>DRAMに比べて、小容量で高価。リフレッシュ動作（再書込み）が不要。
キャッシュメモリに採用。</font>

## キャッシュメモリ
<b>主記憶よりも高速で、CPUと主記憶の間に配置するメモリ</b>
主記憶から読み出したデータをキャッシュメモリに保持し、CPUが後で同じデータを読み出す時は、高速なキャッシュメモリから読み出すことで、実行アクセス時間の短縮を図っている。
アクセス速度は「主記憶<CPU」

## 実行アクセス時間
<b>アクセスするデータがキャッシュメモリに存在する確率を</b><font color = blue>ヒット率</font>という。
<font color = blue>ヒット率・キャッシュメモリのアクセス時間・主記憶</font>のアクセス時間が分かると実行アクセス時間を求めることができる。
(公式)
<b>ヒット率 * キャッシュメモリのアクセス時間 + (1 - ヒット率) * 主記憶のアクセス時間 </b>

### 一次キャッシュと二次キャッシュ
CPUは 一次キャッシュ・二次キャッシュ・主記憶の順にアクセスする。

## ライトスルー方式とライトバック方式

### ライトスルー方式
キャッシュメモリと主記憶の両方を書き込む方式。低速
### ライトバック方式
キャッシュメモリだけ書き込み、主記憶にはデータがキャッシュメモリから追い出される時に書き込む方式。高速

## メモリインタリーブ
主記憶装置を複数の区画に分け、連続するアドレスの内容を並列アクセスすることで、アクセスの高速化を図る。

## アクセス速度と容量
レジスタ -> 1次キャッシュ -> 2次キャッシュ -> 主記憶 -> SSD -> HDD

高速・小容量  ーーーーーーーーーーーーーーーーーーーーー   低速・大容量


参考文献：イメージ＆クレバー方式でよくわかる 栢木先生の基本情報技術者教室
GraalVM EEとCEの違い。

皆さん、

こんにちは。
Qiitaに記事を書き始めたお陰で、ご照会が増えてきました。
ありがとうございます。

GraalVMのEnterprise Edition（弊社製品）と　Consumer　Edition（オープンソース）の違いについて、ご質問を受けたので、下記に記載します。
よろしくお願いします。



![Difference btw EE&CE-v2_page-0001.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2634867/749138f9-a9f0-229a-7001-4b5ea9d49916.jpeg)
![Difference btw EE&CE-v2_page-0002.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2634867/ea23336f-ebfe-2fce-7a9b-07a8fc6dfadd.jpeg)
![Difference btw EE&CE-v2_page-0003.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2634867/fe25265d-9a98-8f71-3b48-b35a8bd0da6d.jpeg)
![Difference btw EE&CE-v2_page-0004.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2634867/e0fe5f62-c3bd-56ca-9d29-a1d8adc69c23.jpeg)
![Difference btw EE&CE-v2_page-0005.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2634867/c8d24b10-6884-50ce-a575-9982da51083c.jpeg)