OmniAICreator/Qiita-1.07M huggingface dataset:
AWS ECSへの(シェル)アクセス方法 (SSH)

## 注意点
セキュリティの観点から本番環境への適用は行わないほうが良いと思われます。

## 接続したいECSサービスのタスクロールに以下のポリシーをアタッチ
※ タスク実行ロールではないです。
``` json
{
   "Version": "2012-10-17",
   "Statement": [
       {
       "Effect": "Allow",
       "Action": [
            "ssmmessages:CreateControlChannel",
            "ssmmessages:CreateDataChannel",
            "ssmmessages:OpenControlChannel",
            "ssmmessages:OpenDataChannel"
       ],
      "Resource": "*"
      }
   ]
}
```


## ECSコンテナへのSSHを許容するようECSサービスへ設定
``` sh
## このタイミングでECSサービスが再起動します。
aws ecs update-service \
    --cluster クラスター名 \
    --service サービス名 \
    --enable-execute-command --force-new-deployment
```

## ECSタスクが再起動後に確認

``` sh
## enableExecuteCommandがtrueになっていること
aws ecs describe-tasks \
    --cluster クラスター名 \
    --tasks タスクID (fsajfkadfjkasfjla)
```


## ECSタスクのコンテナへのシェルアクセス (sshのイメージ)

``` sh
aws ecs execute-command \
    --cluster ECSクラスター名 \
    --task ECSタスクID (sakaksjfaksfjkafka) \
    --interactive \
    --container sshしたいコンテナ名 (task defに記載されています) \
    --region ap-northeast-1 \
    --command "/bin/bash"
```


## 採用PR

gRPCやマイクロサービス化・二次元コンテンツに興味がある、もしくはチャレンジしてみたいという方は是非一緒に働きましょう！

https://hrmos.co/pages/vivion/jobs/0000226

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/307359/2000f749-3e82-7a47-b1c4-4444e237f79c.png" width=45%>
rsyslogのコンフィグの設定について

## 環境
Ubuntu20.4

## はじめに
**/etc/rsyslog.conf**の中に下記の設定があります。この設定で、外部にあるコンフィグファイルを取り込むことができます。
```/etc/rsyslog.conf
$IncludeConfig /etc/rsyslog.d/*.conf
```

読み込み先のディレクトリには、デフォルトで２つのコンフィグファイルが存在します。つまり、この２つのファイルを取り込んでいることになります。
```
$ls /etc/rsyslog.d
20-ufw.conf  50-default.conf
```

20-ufw.confと50-default.confの内容を、/etc/rsyslog.confに直接記述してもいいが、外部ファイルにして取り込むことで、元のファイルを汚さずに済むといったメリットがあります。

20-ufw.conf  50-default.confの２つのコンフィグファイルの中身を見てみます。

## 20-ufw.conf

20-ufw.confの中身を参照します。
```
$ cat /etc/rsyslog.d/20-ufw.conf
# Log kernel generated UFW log messages to file
:msg,contains,"[UFW " /var/log/ufw.log

# Uncomment the following to stop logging anything that matches the last rule.
# Doing this will stop logging kernel generated UFW log messages to the file
# normally containing kern.* messages (eg, /var/log/kern.log)
#& stop
```

**:[プロパティ], [条件文], "値"** という形式でルールの設定を行っています。下記の１行を解釈すると、「メッセージ本体の中に"[UFW"の文字が含まれていれば、そのログは、/var/log/ufw.log に出力する」といった意味になります。
```
:msg,contains,"[UFW " /var/log/ufw.log
```

stopを入れると、stopの上部で振り分けられたログは、stop以降では、一切出力されないようになります。
```
& stop
```

コメントには「stopのコメントを外すと、UFWに関するログは、kern.logには書き込まれなくなります」といったことが書かれています。

>コメント文からの推測ではありますが、外部のコンフィグファイルは、20-ufw.conf、50-default.confの順番で読み込まれ、20-ufw.confで設定した内容は、50-default.confにおいても有効になるものと思われます。

## 50-default.conf

50-default.confの中身を参照します。


```
$ cat /etc/rsyslog.d/50-default.conf
#  Default rules for rsyslog.
#
#                       For more information see rsyslog.conf(5) and /etc/rsyslog.conf

#
# First some standard log files.  Log by facility.
#
auth,authpriv.*                 /var/log/auth.log
*.*;auth,authpriv.none          -/var/log/syslog
kern.*                          -/var/log/kern.log
mail.*                          -/var/log/mail.log

#
# Logging for the mail system.  Split it up so that
# it is easy to write scripts to parse these files.
#
mail.err                        /var/log/mail.err

#
# Emergencies are sent to everybody logged in.
#
*.emerg                         :omusrmsg:*
```

ルールの設定は、**[ファシリティ].[シビリティ]** という形式も取ります。auth、authprivは認証関連のメッセージです。下記の１行を解釈すると、「認証関連のメッセージは、全てのシビリティに対し、/var/log/auth.log に書き込む」といった意味になります。
```
auth,authpriv.*                 /var/log/auth.log
```

下記は「全てのメッセージの全てのシビリティを、/var/log/syslog に書き込むが、認証関連のメッセージにおいては、全てのシビリティで書き込みを行わない」といった意味になります。
```
*.*;auth,authpriv.none          -/var/log/syslog
```

下記は「カーネルに関するメッセージは、全てのシビリティを、/var/log/kern.logに書き込む」といった意味になります。
```
kern.*                          -/var/log/kern.log
```

下記は「メールに関するメッセージは、errのシビリティだけを、/var/log/mail.errに書き込む」といった意味になります。
```
mail.err                        /var/log/mail.err
```

下記は「全てのメッセージにおいて、シビリティがemergのログは、コンソール画面に表示する」といった意味になります。
```
*.emerg :omusrmsg:*
```
LivebookでKino.DataTableが表示されない

# 現象

- docker-composeで動かしているLivebook上で、Kino.DataTableが表示されない
- Mix.installは成功している
- その他の処理も実行できる

# 解決策

8081ポートを繋げる

```yaml:compose.yaml
---

version: "3.2"

services:
  livebook:
    build: .
    container_name: livebook
    ports:
      - "8080:8080"
      - "8081:8081" # これがないとエラーになる
    environment:
      - LIVEBOOK_HOME=/data
    volumes:
      - ./data:/data
```

# 原因

デバッグツールで通信を確認
→ `http://localhost:8081/iframe/v4.html`へのアクセスがエラーになっていた
Known Issues Spring 23


久しぶりに見ようと思うとリンクが見当たらないですね。

https://issues.salesforce.com/

|表題|カテゴリ|URL|
|:---|:---|:----|
|Experience Pages change their API Name upon deployment via Experience Bundle Experience **エクスペリエンス ページは、エクスペリエンス バンドルを介したデプロイ時に API 名を変更します**| DXP (Digital Experience Platform)|[Link](https://issues.salesforce.com/issue/a028c00000gAwEOAA0)|
|Accessibility: "View Version History" in Notes has incorrect role **アクセシビリティ: Notes の「バージョン履歴の表示」の役割が正しくありません**|Sales / Sales Productivity|[Link](https://issues.salesforce.com/issue/a028c00000gAwQCAA0/accessibility-view-version-history-in-notes-has-incorrect-role)|
button type="button"でsubmitされてしまう

分かってみれば簡単で単純だった。

ずっとわからずに彷徨っていた。
html自体がiframeやらdivやらのloadでやっていたりして複雑だったので、
あちこち探していたけど、なかなか解決しない。

あっちこっちにalertトラップを敷き詰めたり、
windows.beforeunloadのトラップをしてた見たり
いろいろしてみたけど、どこにも引っかからない。

引っかからないからstack traceも出来ない。

一体何故なんだ。

buttonを押すと、なぜかsubmitされてしまう。

type="button"にしているのに、、、

んでソースをよーく見てみたら、、、

```HTML
<button class="save" type="button>">保存</button>
                                 ↑ここ!!
```

くだらない
くだらなさ過ぎる

たったこれだけのせいで半日潰れた

オート補完機能(のバグ)がもたらした悲劇

まあ自分が悪いのだけど。
ニューラルネットのうずまきサンプル

https://colab.research.google.com/drive/1lcUfqdvrE2YOacfSKTMQOUAfMferqoFd#scrollTo=e_gi636CFo1v
にサンプルを置きました。

https://cs231n.github.io/neural-networks-case-study/
を改造し隠し層２層を入れてみました。
NNのありがたみとか思想がそれなりに理解できるかもです。

cs231nからリンクされてる
https://cs.stanford.edu/people/karpathy/convnetjs/demo/classify2d.html
もいろいろやってみるとなかなかに面白いです。
配列（for文と拡張for文の違い）

Java初心者のMisaです。
今日も引き続き配列に関して勉強しています。

通常のfor文と拡張for文について、参考書にでてきたのですが、最初は何が違うのか、拡張for文がどのような仕組みになっているのかわからなかったので、調べました。

for (int n : scores) {
System.out.println(n);
拡張for文の仕組み→指定した配列(scores)から要素を１つずつ取り出し、変数(n)にいれてから処理を実行する

拡張for文のメリットは、
①すっきりしたコードを書ける事
②例外を考慮する必要がない事

②の「例外を考慮する必要がない」というのが、例外とはなんぞや……という感じではあるので、また調べて見ようと思います。

デメリットとしては、
①細かい条件指定ができない
②配列やコレクション以外では使えない

使いどころを見極める必要があるそうなので、とにかく慣れていくしかないのかなと思いました。
Windows で OneDrive の長いパス名をなんとかしたい

## ■解決したい課題
・OneDrive のフォルダ名が長い
・OneDrive のフォルダ名が空白を含んでおり、コマンドラインでエスケープを要する
・すべてのツールが空白含むパスに対応しているか、心許ない
 
## ■解決策
ジャンクションを作成します。

```
C:\Users\username>mklink /j oneorg "OneDrive - 組織名"
oneorg <<===>> OneDrive - 組織名 のジャンクションが作成されました
```

mingw bash からは、シンボリックリンクとして見えます。
[ServiceNow] フィールドの値に応じてフォームビューを切り替える

# 概要
フォームに含まれる特定のフィールド(例えばステータス)の値に応じて、表示するフォームビューを切り替える方法についてまとめます。
表示ルール[View Rules]を使用します。

# 前提条件
* PDIのTokyoバージョンで確認
* adminユーザーで操作

# 詳細
## 1. UIビューを作成する
1. [System UI] > [Views]を開く
2. [New]ボタンで新規作成する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2841320/0314f673-e99a-8144-e108-62fb3d46a49f.png)
 Name : 内部的な名前。英数字のみが無難。
 Title : ビューの切替などで表示される文字列。(上と同じにしておく方がわかりやすい)
3. Submitする


## 2. フォームビューを作成する
1. 設定したいテーブルのレコードを開く
2. ≡(ハンバーガーメニュー) > [Configure] > [Form Design] または [Form Layout]を開く
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2841320/dcc659fc-cace-bef6-c919-f7dd3d75e08b.png)
3. [Form Design]の場合
画面上部のビュー設定欄で[New]を選択し、1で作成したUIビューのNameを入力
<img width=400 src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2841320/93dc2279-0a41-62ef-0c3e-1799aca09dff.png><img width=250 src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2841320/73565251-a2a7-d2f6-3bab-6d0b8e1b4d5e.png>
4. 表示したい項目を設定して[Save]する


## 3. 表示ルールを作成する
1. [System UI] > [View Rules]を開く
2. [New]ボタンで新規作成する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2841320/ed1e1e72-61a1-7cf9-32fb-162fd5c5b971.png)
    Name : 名前
    Table : フォームを設定したいテーブル __<font color=red>※</font>__
    Device Type : Browser
    Match conditions : All
    View : 1で作成したUIビューのNameを入力
    Conditions : フォームを設定する条件
    
    __<font color=red>※</font>アプリケーションスコープを設定している場合、指定できる[Table]はアプリケーションスコープ内のものに限られます__

3. [Submit]する

## 結果
* 指定した[Table]のレコードを表示する際、[Conditions]に合致した場合に、指定した[View]が適用される。
* タイトル部分には「View:～～～*」と表示され、自分でビューを変更した場合と違い、末尾に*が付与されている。
View部分にマウスオーバーすると、`View forced by a View Rule`とポップアップ表示される。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2841320/e2e96344-edbf-f5ed-7542-01c99266097b.png)
ルールが適用されている場合は、Viewのメニューも表示されない。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2841320/bb526f1a-116b-cb24-d72a-f6a0c8f306ff.png "ルール適用対象の場合はViewの変更不可")
これはURLに「&sysparm_view_forced=true」が設定されているため。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2841320/8c656688-9840-75e8-fb8a-60ad46ac84f7.png)
* ルールによりViewが適用されたレコードから、Prevous record(↑) または Next record(↓) で他のレコードに移動した場合、移動先でもビューが適用されたままになる。ただしルールの適用外であれば、View名の末尾に*はなく、Viewの変更が可能。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2841320/932901f7-4d19-f96c-ec7b-f5284c8e3c8f.png "ルール適用外の場合はViewの変更可能")


# 参考
* [ビュー管理](https://docs.servicenow.com/ja-JP/bundle/tokyo-platform-user-interface/page/administer/navigation-and-ui/concept/view-management-overview.html)
* [ビュールールの作成](https://docs.servicenow.com/ja-JP/bundle/tokyo-platform-user-interface/page/administer/navigation-and-ui/task/t_CreateAViewRule.html)

以上
C#/VB.NET Word をJPGに変換する方法

ドキュメントを編集するとき、Wordは非常に良い選択です。しかし、保存と転送の際には、Wordを他のドキュメント形式に変換することが考えられます。例えば、WordをJPGに変換します。プログラミングによる変換を考えるなら、[Free Spire.Doc for .NET](https://jp.e-iceblue.com/introduce/spire-doc-for-net.html)ライブラリが役に立つかもしれません。以下に詳細な変換方法とコードを示します。
## Free Spire.Doc for .NETをインストールする
**方法1**：[NuGet](https://www.nuget.org/packages/FreeSpire.Doc)でFree Spire.Doc for .NETをインストールする
Visual Studioを開いて新しいプロジェクトを作成します。次に、「Solution Explorer」で「References」を右クリックし、「Nuget Manage Packages」を選択します。Free Spire.Doc for .NETを検索してインストールします。
**方法2**：手動でSpire.doc.dllを追加する
[Free Spire.Doc for .NET](https://jp.e-iceblue.com/download/free-spire-doc-for-net.html)をローカルにダウンロードしインストールします。次に、Visual Studioて新しいプロジェクトを作成し、右側の「Solution Explorer」で「References」を右クリックし、「Add Reference」>「Browse」を選択して、インストールパス下のBINフォルダのdllファイルを見つけ、「OK」をクリックして、プログラムに参照を追加します。
## Word をJPGに変換する方法
* Document オブジェクトを作成します。
* Document.LoadFromFile()メソッドを使用して Word 文書を読み込みます。
* Document.SaveToImages()メソッドを使用して、Word 文書を Bitmap 画像に変換します。
* 画像コレクションをループし、特定の画像を取得して JPG として保存します。
C#:
```C#
using Spire.Doc;
using Spire.Doc.Documents;
using System;
using System.Drawing;
using System.Drawing.Imaging;

namespace ConvertWordToJPG
{
    class Program
    {
        static void Main(string[] args)
        {
            //Documentオブジェクトを作成する
            Document doc = new Document();

            //Wordを読み込む
            doc.LoadFromFile("C:\\Users\\Administrator\\Desktop\\Template.docx");

            //文書全体のページを画像に変換する 
            Image[] images = doc.SaveToImages(ImageType.Bitmap);

            //画像コレクションをループする
            for (int i = 0; i < images.Length; i++)
            {
                //画像をJPGとして保存する
                string outputfile = String.Format("‪Image-{0}.jpg", i);‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬
                images[i].Save("C:\\Users\\Administrator\\Desktop\\Images\\" + outputfile, ImageFormat.Jpeg);
            }
        }
    }
}
```
VB.Net:
```VB
Imports Spire.Doc
Imports Spire.Doc.Documents
Imports System
Imports System.Drawing
Imports System.Drawing.Imaging
 
Namespace ConvertWordToJPG
    Class Program
        Shared  Sub Main(ByVal args() As String)
            'Documentオブジェクトを作成する
            Document doc  =  New Document()
 
            'Wordを読み込む
          　doc.LoadFromFile("C:\\Users\\Administrator\\Desktop\\Template.docx")

            '文書全体のページを画像に変換する 
            Dim images() As Image =  doc.SaveToImages(ImageType.Bitmap) 
 
            '画像コレクションをループする
            Dim i As Integer
            For  i = 0 To  images.Length- 1  Step  i + 1
                '画像をJPGとして保存する
                Dim outputfile As String =  String.Format("‪Image-{0}.jpg",i) ‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬‬
                images(i).Save("C:\\Users\\Administrator\\Desktop\\Images\\" + outputfile, ImageFormat.Jpeg)
            Next
        End Sub
    End Class
End Namespace
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2811193/b6277b91-803a-6596-2d1e-76ed2e92aaae.png)
PowerApps ポータル画面入力チェックカスタマイズ追加

```javascript
//必須項目チェックを追加する
function RequiredCheckAdd(id, name) {
    if (typeof (Page_Validators) == 'undefined') {
        Page_Validators = [];
    }
    // Create new validator
    var newValidator = document.createElement('span');
    newValidator.style.display = "none";
    newValidator.id = id + "Validator";
    newValidator.controltovalidate = id;
    newValidator.errormessage = "<a href='#" + id + "_label'>" + name + " は必須フィールドです。</a>";
    newValidator.validationGroup = "";
    newValidator.initialvalue = "";
    newValidator.evaluationfunction = function () { };
    // Add the new validator to the page validators array:
    Page_Validators.push(newValidator);
    $("a[href='#" + id + "_label']").on("click", function () {
        scrollToAndFocus(id + '_label', id);
    });
}
//上記のチェックを追加する前に直前チェックしたころより、残りメッセージをクリアするため、以下のメソッドでクリアする
function CheckRequired(flg) {
    //前回チェックメッセージが残された場合、クリア
    if (typeof (Page_Validators) !== 'undefined') {
        for (let i = 0; i < 2; i++) {
            for (let i = 0; i < Page_Validators.length; i++) {
                var element = Page_Validators[i].outerHTML;
                if (element.includes("new_field1Validator") || element.includes("new_field2Validator")) {
                    Page_Validators.splice(i, 1);
                }
            }
        }
    }

    if (flg == 1) {
        //field1が空白の場合
        if ($("#new_field1").val() === "") {
            RequiredCheckAdd("new_field1", "フィールド１");
        }
        //field2が空白の場合
        if ($("#field2").val() === "") {
            RequiredCheckAdd("new_field2", "フィールド２");
        }
    } else if (flg == 2) {
        //field3が空白の場合
        if ($("#new_field3").val() === "") {
            RequiredCheckAdd("new_field3", "フィールド３");
        }
    }
}
【JavaScript】文字を整数に変える合言葉

その名も…parseInt()

Saasのプログラム書いているスキマにスキルを身につけようとpaizaラーニングを始めました。
初心にかえり、基礎からやっていますが独学でやっていたツケが回ってきたのか、初めて知ることも多く勉強になります:pray_tone1:
リンク ➡ https://paiza.jp/

中でもスキルチェックにお熱で…ついさっきまで詰んでいたのが、
入力された配列の足し算！
簡単そうに見えて意外と沼でした:fearful:

paizaでの入力値って縦表記なうえに文字列:scream_cat:
1
2
3
こんな感じ。

いくら足し算してもNanであしらわれます。。。

めっちゃ探しに探した結果、parseInt(数値にしたいヤツ)　これだけ；；

これだけでやりたいこと全て叶っちゃいました:hugging::sparkles:

何ならfor文で出力した値も計算できるっ！完璧:clap:
package.json の依存関係を更新する方法


## npmのバージョニング

npm は [semantic versioning](https://docs.npmjs.com/about-semantic-versioning) を採用しています。

```
1.          2.            3
↑メジャー  ↑マイナー   ↑パッチ
```

- メジャーは、互換性のない API の変更に関するもの
- マイナーは、下位互換性のある機能用
- パッチは、下位互換性のあるバグ修正用

## ^(キャレット)と~(チルダ)の意味

- キャレット(マイナー)
  - ^1.2.3 = 1.x
  - 1.2.3 <= version < 2.0.0
- チルダ(パッチ)
  - ~1.2.3 = 1.2.x
  - 1.1.2 <= version < 1.2.0

## 依存関係の更新

```bash
# 依存関係に更新情報があるのか確認する
npm outdated
# package.jsonを修正したら依存関係を更新する
npm update
# インストールされているバージョンを確認する
npm ls
```

## メジャーバージョンをアップグレードする場合

```bash
# ncuのインストール
npm install -g npm-check-updates
# 更新内容を確認
ncu
# 更新（メジャーバージョンを含む）
ncu -u
```

:::note warn
メジャーバージョンをアップグレードするときは十分注意をしてください
:::

Visual Studio Code に [Version Lens](https://marketplace.visualstudio.com/items?itemName=pflannery.vscode-versionlens) をインストールしている場合は、すべてのパッケージの最新バージョンが表示されます。

## 参考

https://betterprogramming.pub/how-to-upgrade-dependencies-in-package-json-e5546804187f
https://docs.npmjs.com/cli/v8/configuring-npm/package-json
https://github.com/npm/node-semver#versions
M1macでeclipseの開発環境

今回はM1macでEclipseの開発環境構築の手順のご紹介です。

インストールするものは、**Pleiades All in One**　のみです。

## Pleiades All in One のインストールと起動方法
Pleiades All in Oneをインストールすると、**JDKのインストールや環境変数の設定も不要！**

「Pleiades All in One」のインストール手順は以下の通りです。
1\. [Pleiades All in Oneのインストール先](https://mergedoc.osdn.jp/) 
2\.今回は最新の「Eclipse 2022」を選択する。（赤い丸のところです。）
 ![スクリーンショット 2023-03-02 2.56.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3209753/2e6e6db4-8709-7e15-0536-f4436031b414.png)
3\.　「Mac」→「Java」→「**Full Edition**」の「Download」をクリック
![スクリーンショット 2023-03-02 3.09.39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3209753/9db9e33d-56c5-e6f0-6416-176b48a346ea.png)
4\. ダウンロードしたファイルをダブルクリックすると以下の画面が表示されるので
　「Eclipse」のアイコンを「Applications」のアイコンに**ドラッグアンドドロップ**します。
![スクリーンショット 2023-03-02 13.36.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3209753/0cc71858-1b42-e6e0-8778-4265e20fbfe4.png)
5\. 「アプリケーション」の中にある「Eclipse」をダブルクリックします。
![スクリーンショット 2023-03-02 13.39.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3209753/347d30c3-ee81-3209-04d2-05580e3d1f0e.png)

6\. ダブルクリックすると以下のような画面が表示されるので、「**キャンセル**」を押します。
![スクリーンショット 2023-03-02 13.43.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3209753/029ab652-67af-757a-e9d9-684a1eab808d.png)

7\. 上記ではできなかったため、別の方法で「Eclipse」を開きます。
　　・「Eclipse」のアイコンの上で**右クリック**します。
　　・「開く」をクリックします。
　　（macではアイコン上で**2本指で同時**に押すと右クリックになる）
　　![スクリーンショット 2023-03-02 13.44.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3209753/6123448f-c1c6-4ec8-f050-6b7ac71bdc84.png)

8\. 以下の画面が表示されたら、「**開く**」をクリックします。
![スクリーンショット 2023-03-02 13.44.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3209753/f67b5299-3615-7972-a0ac-84bfaa2fb7a1.png)

9\. 次に以下の画面に移ると思うので、何も変えずにデフォルトのまま「**起動**」をクリック
![スクリーンショット 2023-03-02 14.13.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3209753/25de1cf4-dcb3-6215-60f8-2717e4d91fd0.png)

10\. これで「Eclipse」が起動できました！
![スクリーンショット 2023-03-02 14.28.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3209753/1a5ad965-a77f-b4a9-af14-a43a77f965b4.png)
--ignore-platform-req=ext-gdは何をしているの？

composer installコマンドにおける--ignore-platform-req=ext-gdオプションは、GDグラフィックライブラリがPHPにインストールされていない場合に、Composerがインストールを中止するのを防ぐために使用されます。

GDグラフィックライブラリは、PHPで画像を操作するために必要な拡張機能の1つです。通常、Composerはプロジェクトに必要なパッケージをインストールする前に、PHPに必要な拡張機能がインストールされているかどうかをチェックします。--ignore-platform-req=ext-gdオプションを使用すると、Composerはこのチェックを無視し、パッケージをインストールすることができます。

ただし、このオプションを使用する場合、GDグラフィックライブラリがインストールされていないため、パッケージが機能しない場合があります。そのため、実行前に十分に検討し、必要に応じてGDグラフィックライブラリをインストールすることをお勧めします
ChatGPT APIに対応したNode-RED更新

ChatGPT API（gpt-3.5-turbo）に対応した[Node-RED](https://flows.nodered.org/node/node-red-contrib-simple-chatgpt)を更新しました。
基本的な設定はこちらの記事をご確認ください。

https://qiita.com/h-takauma/items/80a7ab7c167155baf324

# 新しくなった部分
* 会話の初期設定ができる
* 会話の継続ができる

実際にNode-REDを使って詳しく見ていきます。今回は手っ取り早く[enebular](https://enebular.com/)を使って検証します。

https://enebular.com/

## 会話の初期設定
Nodeの設定画面に `SystemSetting`があるのでそこに初期設定を明記します。例えばこんな感じです。

```text
末尾に「テヘペロ」とつけてね
```

![s100.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154355/94b5b196-fd84-9fad-72a6-e18ae753bdb1.png)

これを実行するとこんな感じでAIが返答します。

```text
おはようございます！テヘペロ。
```

![s101.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154355/97caa5c8-c1ef-ba00-f4b7-d46437f9c869.png)

ツンデレで返してほしい場合や、AIにキャラクター設定したり色々試せます。

## 会話の継続
過去のバージョンだと会話の継続を行うために小細工が必要でしたが、今回公開されたAPIだと簡単に会話の継続をすることができます。
simple-chatgptの返答プロパティ `pastMessages`に会話の履歴を返すようにしています。これを利用して会話の継続を行うことができます。

例えばこんな感じ

![s102.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154355/90d7b03c-4718-b39f-c6f5-6de08bc927ba.png)

`その人` = `織田信長`だということを会話の流れから把握しているのが分かります。
ちなみにchangeノードは単純にmsg.payloadに値を入れているだけです。

![s103.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154355/368c7e16-a58d-3c02-e9ab-fdc608daa5bc.png)

## msgオブジェクトの中身
msgオブジェクトの中身はこんな感じです。`pastMessages`にこれまでの履歴を全部入れています。

```json
{
  "_msgid": "6e89395571345cae",
  "payload": "織田信長は1534年に生まれました。",
  "pastMessages": [
    {
      "role": "user",
      "content": "織田信長を20文字で要約して"
    },
    {
      "role": "assistant",
      "content": "\n\n日本史上最強の大名。天下統一を果たし、刷新的な改革を行い大成した。"
    },
    {
      "role": "user",
      "content": "その人はいつ生まれた？"
    },
    {
      "role": "assistant",
      "content": "織田信長は1534年に生まれました。"
    }
  ]
}
```
![s104.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154355/a15e46c5-72fd-b66c-3f52-994ca123f236.png)

## 新規で会話する場合

`pastMessages`の中身を削除してしまえば会話が初期化されます。
誰に殺されたのか聞いてみたところ、こんな感じで`その人`が誰なのか分からなくなっています。

![s105.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154355/10b6b05b-1a8f-4fb1-7a05-522ec0f5777d.png)

もし削除していなければ、会話は継続しています。

![s106.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154355/2c57ae54-3e51-e8a1-065c-290039b57db3.png)

## まとめ
ChatGPTのAPIが公開され、できることが一気に増えました。料金も安いので様々なアプリに実装されていくかと思います。AIの進化が本当に止まらないですね！

システム化のご検討やご相談は弊社までお問い合わせください。

https://www.i-enter.co.jp
ChatGPT API Javaバージョン

以下のコードでJavaでChatGPTのAPIにアクセスできます。
# ■Maven
```Maven
<dependency>
	<groupId>com.google.code.gson</groupId>
	<artifactId>gson</artifactId>
	<version>2.8.8</version>
</dependency>
```
# ■Java
```Java
package com.example.controller;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;

@Controller
@RequestMapping("")
public class TestChatCompletionController {

	@RequestMapping("")
	public String openAIChat() {
		
        String url = "https://api.openai.com/v1/chat/completions";
        String api_key = System.getenv("OPENAI_API_KEY");
        String model = "gpt-3.5-turbo";
        String message = "{\"role\": \"user\", \"content\": \"Hello!\"}";

        try {
        	// HTTPリクエストの作成
            URL obj = new URL(url);
            HttpURLConnection con = (HttpURLConnection) obj.openConnection();
            con.setRequestMethod("POST");
            con.setRequestProperty("Content-Type", "application/json");
            con.setRequestProperty("Authorization", "Bearer " + api_key);
            con.setDoOutput(true);

            // リクエストの送信
            OutputStreamWriter out = new OutputStreamWriter(con.getOutputStream());
            out.write("{\"model\": \"" + model + "\", \"messages\": [" + message + "]}");
            out.close();

            // レスポンスの取得
            BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
            Gson gson = new Gson();
            JsonObject jsonResponse = gson.fromJson(in, JsonObject.class);
            JsonArray choicesArray = jsonResponse.getAsJsonArray("choices");
            JsonObject messageObject = choicesArray.get(0).getAsJsonObject().get("message").getAsJsonObject();
            String content = messageObject.get("content").getAsString();

            // レスポンスの出力
            System.out.println(content);
        } catch (Exception e) {
            System.out.println(e);
        }	
        return "start";
	}
}

```
「URLで共有」機能を作るときに絶対にやるべきセキュリティ設定

# 結論
あるURLを知っている人だけが見れる共有機能を作るときには、`noindex`ディレクティブを使用すべき。そうしないとGoogle検索等の結果に表示されてしまい、URLを通じた限定共有機能として意味をなさなくなる。

# `noindex` ディレクティブ
`noindex`ディレクティブはGoogle等の検索エンジンに対して、検索結果に表示しなように指示する仕組み。HTMLファイルなら以下のようにヘッダに記載できる。

```html
<meta name="robots" content="noindex nofollow">
```

それ以外のファイルでもHTTPヘッダに以下のように記載できる。

```
X-Robots-Tag: noindex, nofollow
```

`noindex`はそのファイルを検索結果に表示しないことを指示する、`nofollow`はそのファイル内にあるリンク先をたどらないことを指示する。基本的にこの二つを書いておけば良い。

# `robots.txt`との違い
`noindex`ディレクティブは`robots.txt`とよく似た機能を持っているが、目的が異なる。`robots.txt`は無駄なコンテンツがクロールされてサイトの質が低く評価されたり、多くのリクエストが飛んでサーバに負荷がかかるのを防ぐための仕組みである。[Googleも「`robots.txt`を検索結果に表示させない目的で使用するな。その場合`noindex`を使え。」と言っている](https://developers.google.com/search/docs/crawling-indexing/robots/intro?hl=ja)。

# Trello流出事故
すでに結構前の話だが、Trelloというタスク管理サービスにおいて、社内の内部情報と見られる情報がGoogle検索することで表示されてしまうという事故があった。これは言うなれば、インターネット上のサービスには同じ公開共有の仕組みでも`noindex`ディレクティブを使用した公開と使用しない公開の2種類があるという認識がユーザになかったことに起因すると思われる。ユーザはTrelloの公開設定をたとえばGoogle DriveのURL共有と同じモノだと考えたのだろう。実際URLを打ち込めば誰でもアクセスできるという点は同じである。しかしGoogle DriveのURL共有は`noindex`という検索結果に表示させない仕組みを利用しているが、Trelloはそういうモノではなかった、その認識がなかったために起きた事故なんじゃないかと思う。（調査はしてないので間違っているかも。）
CISのGLBからの振り分けを100:0にする（Origin Poolの優先順位を設定）

# はじめに
2台のWebサーバーがあり、CISのGLB機能で割り振りを行う事は珍しくありません。
2台のサーバーがアクティブ・アクティブであれば、GLBからラウンドロビンで割り振れば特に問題ありません。

今回は、普段はサーバー1に全てのリクエストを割り振り、サーバー1がダウンした時だけサーバー2に切り替えたい、という要件だったので、複数Origin Poolを作り、Poolに対する優先順位を設定する方法で実現しました。

# Origin Poolが1つの場合
一番シンプルに、1つのOrigin Poolに２台のWebサーバーを入れる構成では、2台のサーバー間で重み付けをすることはできても、今回の要件を満たす設定はできません。

重みを「1:0.1」のように差を付けただけでは、少数ながらサーバー2に割り振られます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59627/f15f93ea-ffb1-cb70-f043-c76b7e4fd4d9.png)

「1:0」にすると、サーバー1がダウンした時もサーバー2には割り振られず、エラー画面が表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59627/62cf8820-1a7a-8687-52e5-23ede85f95ac.png)

# Origin Poolを2つにして優先順位を付ける

今回の要件は、2つOrigin Poolを作り、Poolに対する優先順位を設定する方法で実現できます。
https://cloud.ibm.com/docs/cis?topic=cis-glb-features-pools&locale=ja
>複数のプールを構成して、フェイルオーバーの優先順位 (プール A > プール B > プール C) を設定することもできます。

2つのOrigin Poolを作り、サーバーを1台ずつ所属させます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59627/d35eef7a-8d5f-3441-8b26-ba72d3637629.png)

ロードバランサー配下に2つのPoolを所属させ、Pool1の優先度を高くします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59627/3ade5a60-e7e5-434e-45e9-cb1870c08da0.png)

デフォルトではロードバランサーの設定項目である「トラフィック・ステアリング」が「ランダム」になっており、pool2の優先度を下げていても半分くらいはpool2に割り振られてしまうため、「オフ」にします。これで、優先度の高いpool1にしか割り振られない状態になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59627/ce836a34-3703-a840-d842-b3a9c44912ef.png)

参考

https://developers.cloudflare.com/load-balancing/understand-basics/traffic-steering/steering-policies/standard-options/

# 動作確認

普段はサーバー1にのみリクエストが行っています。

サーバー1をダウンさせると、ロードバランサーが検知し、pool2のサーバー2にリクエストが行くようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59627/26a94895-395d-4b33-e851-e013e0428644.png)

サーバー1を立ち上げ、ロードバランサーが正常を検知すると、再び、サーバー1にしかリクエストが行かない状態に戻ります。


なお、サーバー2の代わりに、[Static Website Hosting](https://cloud.ibm.com/docs/cloud-object-storage?topic=cloud-object-storage-static-website-options)の機能を有効にしたICOSを向くようにし、そこに静的なHTMLファイルを置いておけば、維持コストや運用の手間がほとんどかからないSorryページとして使うことができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59627/72fbc191-7fca-9e2f-6ef8-27a335010aeb.png)
論文要約：LLaMA: Open and Efficient Foundation Language Models

## Abstract
7Bから65Bのパラメータを持つLLMであるLLaMAを紹介します。

数兆個のトークンを使ってモデルを学習し、独自でアクセスできないデータセットに頼ることなく、一般に入手可能なデータセットのみを用いて最先端のモデルを学習することが可能であることを示しています。

特に、LLaMA-13BはほとんどのベンチマークでGPT-3（175B）を上回り、LLaMA-65Bは最高のモデルであるChinchilla70BやPaLM-540Bに匹敵する性能を有しています。

## Introduction

### LLMのスケールが続いている
膨大なテキストコーパスで学習させた大規模言語モデル（LLM）は、テキストの指示や少数の例から新しいタスクを実行する能力を示してきました。
このようなFew-shotの特性は、モデルを十分なサイズにスケールアップしたときに初めて現れ、その結果、これらのモデルをさらにスケールアップすることに焦点を当てた一連の研究が生まれました。

### 与えられた計算予算において最適なデータセットとモデルサイズのバランスを得る
しかし、（Hoffmann+, 2022）は、与えられた計算予算において、最高の性能は最大のモデルによってではなく、より多くのデータで訓練されたより小さなモデルによって達成されることを示します。
（Hoffmann+, 2022）のスケーリング則の目的は、特定の学習計算バジェットに対して、データセットとモデルサイズをどのように拡張するのが最適かを決定することです。

### 推論コストまで考えると、最適なバランスよりもモデルサイズを小さくした方が良い
しかし、この目的は、言語モデルを大規模に提供する際に重要となる推論バジェットを無視します。
この文脈では、目標とする性能レベルがある場合、望ましいモデルは学習速度が最も速いものではなく、推論速度が最も速いものです。
ある性能レベルに到達するためには、大きなモデルを学習する方が安いかもしれませんが、長く学習した小さなモデルの方が、最終的には推論速度が安くなります。
例えば、Hoffmannら（2022）は200Bトークンに対して10Bモデルの学習を推奨していますが、我々は7Bモデルの性能が1Tトークン後でも向上し続けることを発見しています。

### 学習トークンを増やすと小さなモデルでも精度が向上
本研究の焦点は、一般的に使用されているものより多くのトークンで学習することにより、様々な推論バジェットで最高の性能を達成する一連の言語モデルを学習することです。
その結果、LLaMAと呼ばれるモデルは7Bから65Bのパラメータを持ち、既存のLLMと比較しても遜色のない性能を発揮します。例えば、LLaMA-13Bは10倍小さいにもかかわらず、ほとんどのベンチマークでGPT-3を上回ります。
このモデルは、単一のGPUで実行できるため、LLMへのアクセスや研究の民主化に貢献すると考えています。
また、65Bパラメータモデルは、ChinchillaやPaLM-540Bなどの大規模言語モデルにも匹敵する性能を有しています。

**学習データの概要**
<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614092/1b13fa1a-a7b5-2ef4-57a9-a073a0ba5aab.png width=400>

Chinchilla、PaLM、GPT-3とは異なり、我々は一般に入手可能なデータのみを使用しており、我々の研究はオープンソースと互換性があります。
OPT (Zhang et al., 2022), GPT-NeoX (Black et al., 2022), BLOOM (Scao et al., 2022), GLM (Zeng et al., 2022) などの例外もありますが、PaLM-62BやChinchillaに対して競争力のあるものは存在しないのです。


本論文の残りの部分では、我々はTransformerアーキテクチャ（Vaswani et al., 2017）に対して行った修正の概要と、我々の学習方法を紹介します。
次に、我々のモデルの性能を報告し、標準的なベンチマークのセットで他のLLMと比較します。
最後に、責任あるAIコミュニティからの最新のベンチマークのいくつかを用いて、我々のモデルにエンコードされたバイアスと毒性をいくつか明らかにします。

**モデルサイズなどの情報**
<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614092/fb7ebeb6-d200-f320-9ba1-e9d60d4c5dea.png width=600>

**Lossの推移**
<img src=https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614092/086afc48-6bc4-a3d8-9935-f493d7f57349.png width=400>

**精度1**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614092/f430fa09-fdeb-36e7-4590-60d6c18c9519.png)

**精度2**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/614092/84319915-8720-a891-2034-f54e2efd0ac6.png)
paizaラーニング レベルアップ問題集 DPメニュー JavaScript 最安値を達成するには 1

最安値を達成するには 1 (paizaランク B 相当)

https://paiza.jp/works/mondai/dp_primer/dp_primer_apples_step0

# 解答例
問題文に沿って実装します。
```javascript
const fs = require("fs");
const input = fs.readFileSync("/dev/stdin", "utf-8").trim();
const lines = input.split("\n");

const [n, a, b] = lines[0].split(" ").map(Number);

const dp = Array(n + 1).fill(0);

dp[0] = 0;//りんご０個、０円
dp[1] = a;//りんご１個はa円のみ
//りんご２個以降
for (let i = 2; i <= n; i++) {
  //i個買う時の最小金額=小さい方(i-1個の最小金額+りんご1個の金額、i-2個の最小金額+りんご２個の金額)
  dp[i] = Math.min(dp[i - 1] + a, dp[i - 2] + b);
}
console.log(dp[n]);
```
kivy.resources を詳しく見る(Kivy 2.2.0 dev)


# kivy.resources

ソースを追ってみただけなのでソース見たほうがはやいかもしれず。

## kivy.resources.resouce_paths

「あらかじめ決められた一連のフォルダーを検索します。 」(拙訳; kivy 2.2.0 dev より)

っていうのがこの resouce_paths リストである。

初期値は

```python
import kivy.resources
kivy.resources.resource_paths
```

['.', '', '/home/hoge/fuga/lib/python3.10/site-packages/kivy', '/home/hoge/fuga/lib/python3.10/site-packages/kivy/data/..']

で、ソースから抜粋:

```python
['.',
dirname(sys.argv[0]),
dirname(kivy.__file__),
join(kivy_data_dir, '..')]
```

iOS の場合は:   
   
```python
['.',
dirname(sys.argv[0]),
join(dirname(sys.argv[0]), 'YourApp'),
dirname(kivy.__file__),
join(kivy_data_dir, '..')]
```

である。

ただし、検索時は `reversed(resource_paths)` するので後ろから前への順番で行うことに注意。

## resource_add_path

resources_paths の「末尾」に追加する。よって追加した path が検索対象として真っ先に検索される。

既に登録済のものがあった場合は何もしないので、優先順位を上げたい場合は一旦 `resource_remove_path` してから `resource_add_path` する必要があるだろう。たぶん。

追加する path は一切加工されない。 `abspath()` とか一切しない。

## resource_remove_path

既にリストの中に path があれば削除する。

引数で指定する path は一切加工しないので、リスト中に存在するパスと全く同じものを指定しなければならない。

## resource_find

filename に resource_paths というリストの中の
パスを「逆順」に適用しながら、探します。

つまり resource_paths に /hoge/fuga というパスが
あれば join('/hoge/fuga', filename) というファイルを探します。

無かったら作成とかしません。無かったら `None` を返します。
まずそこが大前提です。

よって filename が None だったら 単に return します(Noneを返します)

検索順:

1. use_cache が True の場合は 60 秒以内は無条件にキャッシュされたものが返ってきてしまいます。 一旦 use_chche を False にして使うか、 60 秒を超えて待ちましょう(?)
2. filename の 先頭が 'atlas://' なら何もせずに filename をそのまま返します。
3. abspath(filename) 存在してるパスなら abspath() したものを返します(filenameに '/home/hoge/fuga/hoehoe.db' とか絶対パスでフルパスを指定した時など。たぶん)
4. resource_paths に対して逆順で、 abspath(join(「resource_paths のパスのどれか」, filename)) が存在したならそれを返します。
5. filename.startswith("data:") filename が 'data:' で始まる場合はfilenameそのものを返します
6. (use_cache が True で、 返す found_filename があるなら、 found_filename をキャッシュに登録します。)
7. とにかく何かあれば found_filename を返して 無ければ None を返します。
Elixir 学習記（4. パターンマッチング）

# Elixir学習記

| ← 前 | [目次](https://qiita.com/SF-28/items/197df5e03ab9787f40a0) | 次 → |
| :-: | :-: | :-: |
| [3. 演算子](https://qiita.com/SF-28/items/82dfb7cd5398656adbac) | 4. パターンマッチング | - |

# パターンマッチング

Elixirでは **マッチ演算子`=`** を使って、左辺と右辺のパターンマッチングができる

```elixir
1 = 1
1

1 = 2
** (MatchError) no match of right hand side value: 2

x = 1
1

1 = x
1

2 = x
** (MatchError) no match of right hand side value: 1

x = 2
2

1 = y
** (CompileError) xxx : undefined function y/0 (there is no such import)
```

- 左辺に変数が含まれている場合、右辺にマッチするようにバインドされる
- 左辺と右辺が等しくないときは、MatchErrorになる
- 定義されていない変数を右辺に置くと、関数とみなされCompileErrorになる

パターンマッチングなので、以下のような処理も可能

```elixir
# まとめてバインド
{ a, b, c } = { 1, 2, 3 }
# a = 1, b = 2, c = 3

# 特定の値をバインド
{:ok, result } = {:ok, "Success"}
# result = "Success"

# 意図しない形式はエラーにする
{:ok, result} = {:error, :oops}
** (MatchError) no match of right hand side value: {:error, :oops}
```

左辺で指定するパターンに変数を使いたいけど、バインドはしたくないという場合
:point_right:  **ピン演算子`^`** を使う

```elixir
status = :ok

{^status, result} = {:ok, "Success"}
# result = "Success"
```


## 変数のバインド以外は、何に使えるの？

こちらの記事がめちゃくちゃ分かりやすいです

https://qiita.com/naoya@github/items/9da982febe89d83cb5b5

>パターンマッチは Elixir のあれやこれ ･･･ 変数束縛、データ型の分解、繰り返し処理、関数の選択的実行、条件分岐などの基礎をなす重要な機能のひとつである。

# 参考資料

- [Elixir 公式ガイド](https://elixir-lang.jp/getting-started/introduction.html)
    - [パターン・マッチング](https://elixir-lang.jp/getting-started/pattern-matching.html)
- [Elixir Tutorial](https://www.tutorialspoint.com/elixir/index.htm)
    - [Elixir - Pattern Matching](https://www.tutorialspoint.com/elixir/elixir_pattern_matching.htm)
- [Elixir School](https://elixirschool.com/ja)
    - [パターンマッチ](https://elixirschool.com/ja/lessons/basics/pattern_matching)

# 感想

- パターンマッチングを正しく理解することはElixir学習で欠かせない
- リストの分解と再帰
  - Enum.map以外でコレクションを扱う強力な方法を知れた
- むやみにif文を使わない
  - パターンマッチングを活用すればもっと簡潔に書けないか？を考えてみる
apt-getって何？

apt-getは、Debianとその派生物（Ubuntu、Linux Mintなど）で使用されるコマンドラインツールで、パッケージの管理を行うために使用されます。

apt-getを使用すると、ソフトウェアパッケージを検索、インストール、更新、削除することができます。また、依存関係の解決やパッケージのバージョン管理などの機能も提供されます。

例えば、以下のようなコマンドを実行することで、Apacheウェブサーバーをインストールすることができます。

```sql
sudo apt-get update
sudo apt-get install apache2
```

最初のコマンドは、パッケージリストを最新の状態に更新し、2番目のコマンドはApacheウェブサーバーのパッケージをインストールします。

apt-getを使用することで、複数のパッケージを一括でインストールすることもできます。また、パッケージの検索や情報の確認などの機能も提供されます。

また、よく上記コマンド順のように `apt-get update`後に`apt-get install~`するコードを見ることは多々あると思います。それは`apt-get install~`から始まると、build中にエラーが発生する可能性があるため、apt-get updateしてからinstallした方がおすすめです
設計パターン丸写しのディレクトリ分けから卒業

# ディレクトリの構成の話です

さてソフトウェア開発において、MVCやDDDは広く使われている設計パターンの1つです。しかしそういった設計パターンに引きづられたディレクトリ分けには問題点があり、概念別のディレクトリ構成がより良い選択肢であることがあります。本記事では、技術駆動なディレクトリ分けの問題点と概念別のディレクトリ構成のメリットについて解説します。

# 技術駆動なディレクトリ分け

設計パターンに引きづられたディレクトリ分けをここでは***技術駆動なディレクトリ分け***と呼びます。

## MVCフレームワークにありがち

```
myapp/
├── controllers/
│   ├── user_controller.py
│   ├── product_controller.py
│   └── ...
├── models/
│   ├── user_model.py
│   ├── product_model.py
│   └── ...
├── views/
│   ├── user_view.py
│   ├── product_view.py
│   └── ...
├── main.py
├── requirements.txt
└── README.md
```

Rails, Laravel, DjangoのようなMVCアーキテクチャを採用したフレームワークではお馴染みのディレクトリ構成です。今回は例としてPythonになってますがModel, View, Controllerという***各設計単位ごとにディレクトリが切られている***という点はどのフレームワークも同じはずです。

## DDDでもありがち

```
myapp/
├── domain/
│   ├── entities/
│   │   ├── product.py
│   │   ├── customer.py
│   │   └── ...
│   ├── value_objects/
│   │   ├── price.py
│   │   ├── email.py
│   │   └── ...
│   ├── repositories/
│   │   ├── product_repository.py
│   │   ├── customer_repository.py
│   │   └── ...
│   ├── services/
│   │   ├── order_service.py
│   │   ├── customer_service.py
│   │   └── ...
│   ├── use_cases/
│   │   ├── create_order.py
│   │   ├── update_customer.py
│   │   └── ...
```

EntityやValue ObjectといったDDD特有の設計単位がそのままディレクトリ分けや命名に反映されています。***これも技術駆動なディレクトリ分けです。***

# 技術駆動の何がダメなの

このディレクトリ構成では、さまざまな混乱が生じてしまいます。DDDの例で登場したファイルは、大きく種類分けすると商品(product)、顧客(customer)に大別されます。しかし、設計パターンでフォルダ分けしているために、どれがどの種類に関連があるのか一目では分かりません。

そしてこれらのファイルは、どれがどれに強く関係し合うでしょうか？たとえば商品は、`product_repository.py`などが商品関連であることがわかります。では値オブジェクトの `price.py` はどうでしょうか。一見商品の売値に関係がありそうですが、そうではなく実は買値でも用いられるものです。名前的にわかりにくく、何かの拍子にうっかり買値に売値が使われてしまう可能性があります。当然バグ化する可能性が高まります。また、`email.py` はアカウント操作でしか用いられません。しかし、何かの仕様を満たすために、アカウント操作以外の用途で無理に `email.py` が使われたりすると、本来の用途以外のものと結び付いてロジックが非常に混乱してしまいます。

本来強く関係し合うはずのファイルが技術駆動なディレクトリ分けではバラバラになってしまうのです。

(仙塲 大也. 良いコード／悪いコードで学ぶ設計入門保守しやすい　成長し続けるコードの書き方 (Japanese Edition) (pp.326-327). Kindle 版.  を参考)

# 概念駆動なディレクトリ分け

```
root/
├── user/
│   ├── User.php
│   ├── UserController.php
│   ├── UserView.php
│   └── user.css
├── product/
│   ├── Product.php
│   ├── ProductController.php
│   ├── ProductView.php
│   └── product.js
├── cart/
│   ├── Cart.php
│   ├── CartController.php
│   └── CartView.php
├── common/
│   ├── Database.php
│   └── Utils.php
└── index.php
```

概念駆動なディレクトリ分けでは、機能や概念ごとにディレクトリを分け、そのディレクトリ内に必要なファイルをまとめます。例えば、"user"というディレクトリには、ユーザーに関連するModelやView、Controllerなどをまとめます。こうすることで、それぞれの機能や概念だけでしか使われないクラスを外部から隠蔽できるので、無関係な概念から参照される危険性がなくなります。また同じ分類どうしでまとまっているので、たとえばuser関係に仕様変更が生じた場合、userフォルダ内のファイルを読みに行けば良くなります。関連ファイルをあちこち探し回る手間が低減します。

(仙塲 大也. 良いコード／悪いコードで学ぶ設計入門保守しやすい　成長し続けるコードの書き方 (Japanese Edition) (p.328). Kindle 版. を参考)

※なお、この記事で挙げた例ではモデリングが不十分です。ある程度成熟したDDDにおいて `user` などという名前でモデルを作成することは考えにくいですが、モデリングの話はここでは枝葉なので割愛しました。
Linuxのシステムドライブお引越し手順

# ことのはじめ

先日システムドライブで使っていたSSDからSMARTエラーが
出ちゃったのでシステムドライブのお引越しをキメてみた。

# 作業の流れ

- LiveCDから起動
- 新規SSDにパーティション作成
- rsyncでシステムドライブの中身をコピー
- GRUBのインストール

## 用意するもの

- Linuxが稼働しているPC
- 稼働しているOSと同じバージョンのLiveCD
- 新しいSSD
- 折れない心

## 新旧SSDとデバイス名の関係

旧SSD：/dev/sda
新SSD：/dev/sdb

## LiveCDから起動する

BIOSのブートオプションからLiveCDのドライブを選択し起動する

## rootになる

以下のコマンドでrootになる。

```bash
sudo su -
```

## 新SSDにパーティションを作成

```bash
fdisk /dev/sdb
Command (m for help): n
Command action
   e   extended
   p   primary partition (1-4)
p
Partition number (1-4):1
First cylinder (1-767) :1
Last cylinder or +size or +sizeM or +sizeK: <そのままEnter>
Command (m for help): t
Partition number (1-4):1
Hex code (type L to list codes) : 83
Command (m for help): w
```

## 新SSDをext4でフォーマット

```bash
mkfs.ext4 /dev/sdb1
```

## rsyncでシステムドライブの中身をコピー

LiveCDから起動し、新SSDと旧SSDをそれぞれマウント。

```bash
mkdir /mnt/old
mount /dev/sda1 /mnt/old
mkdir /mnt/new
mount /dev/sdb1 /mnt/new
```
rsyncで特殊フォルダを除外してコピー。

```bash
rsync -aAXHv --exclude={"/mnt/old/dev/*","/mnt/old/proc/*","/mnt/old/sys/*","/mnt/old/tmp/*","/mnt/old/run/*","/mnt/old/lost+found"} /mnt/old/ /mnt/new
```

## 特殊フォルダをバインド

特殊フォルダ `/sys` `/proc` `/dev` をバインド。

```
mount --bind /sys /mnt/new/sys
mount --bind /proc /mnt/new/proc
mount --bind /dev /mnt/new/dev
```

## GRUBのインストール

以下のコマンドを実行してGRUBをインストールし、ブート構成情報を再作成する。

```bash
chroot /mnt/new
grub-install --recheck /dev/sdb
update-grub
```

## システムドライブのUUIDを更新する

通常システムドライブはUUIDでマウントされているため、
コピーしたままの`fstab`では起動できない。
そのため、新SSDのUUIDを調べて`fstab`に反映させる必要がある。

```bash
blkid /dev/sdb
```
`UUID="新SSDのUUID"` をfstabのrootファイルシステムの行にある
UUIDと置き換える
（ダブルクォーテーションは外した方がいいかも）

```text:fstab
#UUID=旧SSDのUUID / ext4 noatime,errors=remount-ro 0 1
UUID=新SSDのUUID / ext4 noatime,errors=remount-ro 0 1
```

## 再起動する

再起動し、動作確認してみる。

```bash
reboot
```
MeCabのcsvファイルを差し替える

## ケース
unidic-csj-3.0.1.1 の lex.csv をよりバージョン新しい（語彙サイズの大きい） unidic-csj-3.1.1-full の lex_3_1.csv に変更したい。
でも CRF 学習した model.def は unidic-csj-3.0.1.1 のまま使いたい。
```
$ wc -l unidic-csj-3.*/*.csv
   875923 unidic-csj-3.0.1.1/lex.csv
   879222 unidic-csj-3.1.1-full/lex_3_1.csv
  1755145 total
```

## 差し替えは可能

以下の条件を満たしていれば mecab-dict-gen コマンドで差し替えが可能。
* char.def が同一
* unk.def が同一
* feature.def が同一
* rewrite.def が同一
* dicrc が同一
```
$ diff unidic-csj-3.0.1.1/char.def unidic-csj-3.1.1-full/char.def
$ diff unidic-csj-3.0.1.1/unk.def unidic-csj-3.1.1-full/unk.def
$ diff unidic-csj-3.0.1.1/feature.def unidic-csj-3.1.1-full/feature.def
$ diff unidic-csj-3.0.1.1/rewrite.def unidic-csj-3.1.1-full/rewrite.def
$ diff unidic-csj-3.0.1.1/dicrc unidic-csj-3.1.1-full/dicrc
```
↑ diff はないので満たしている。

## 必要なもの

* unidic-csj-3.0.1.1 の char.def
* unidic-csj-3.0.1.1 の unk.def
* unidic-csj-3.0.1.1 の feature.def
* unidic-csj-3.0.1.1 の rewrite.def
* unidic-csj-3.0.1.1 の dicrc
* unidic-csj-3.0.1.1 の model.def
* unidic-csj-3.1.1-full の lex_3_1.csv　← これだけバージョンが違う

```
$ ls
char.def  dicrc  feature.def  lex_3_1.csv  model.def  rewrite.def  unk.def
```

ちなみに、うちでは lex_3_1.csv から NFKC 正規化済エントリを除外しているので配布されているものより語彙サイズは小さいです。

## 手順

実際に行うことは、unidic-csj-3.0.1.1 の model.def に記載されたパラメータで matrix を作り直すだけ。
その過程で unidic-csj-3.1.1-full から引っこ抜いてきた lex_3_1.csv に新しい id 対応と生起コストが記述される。

### 準備

lex_3_1.csv と unk.def の左右 id 列と生起コストを初期化（値を 0 に）する。

うちは vi 使ってるので、 vi で各ファイル開いて、
```
:%s/,\d\+,\d\+,-\?\d\+,/,0,0,0,/g
```
で一斉置換。

### 新しい matrix 作成

```
$ mecab-dict-index
./pos-id.def is not found. minimum setting is used
reading ./unk.def ... 35
emitting double-array: 100% |###########################################|
./pos-id.def is not found. minimum setting is used
reading ./lex_3_1.csv ... 870629
emitting double-array: 100% |###########################################|
./matrix.def is not found. minimum setting is used.
reading ./matrix.def ... 1x1

done!

$ mkdir ../final

$ mecab-dict-gen -o ../final -m model.def
model.def is not a binary model. reopen it as text mode...
reading ./unk.def ... 35
reading ./lex_3_1.csv ... 870629
emitting ../final/left-id.def/ ../final/right-id.def
emitting ../final/unk.def ... 35
emitting ../final/lex_3_1.csv ... 870629
emitting matrix      : 100% |###########################################|
copying ./char.def to ../final/char.def
copying ./rewrite.def to ../final/rewrite.def
copying ./dicrc to ../final/dicrc
copying ./feature.def to ../final/feature.def
copying model.def to ../final/model.def

done!

$ cd ../final/

$ mecab-dict-index
./pos-id.def is not found. minimum setting is used
reading ./unk.def ... 35
emitting double-array: 100% |###########################################|
./pos-id.def is not found. minimum setting is used
reading ./lex_3_1.csv ... 870629
emitting double-array: 100% |###########################################|
reading ./matrix.def ... 20858x18551
emitting matrix      : 100% |###########################################|

done!
```

差し替え完了。

これで model.def は旧バージョンのまま、lex ファイルだけ更新できた。

（モデルが CRF なので、この方法、 MeCab 用の他の辞書で .csv に単語を追加した場合にも使える）
paizaラーニング レベルアップ問題集 DPメニュー JavaScript 【階段の上り方】階段の上り方 3

【階段の上り方】階段の上り方 3 (paizaランク B 相当)

https://paiza.jp/works/mondai/dp_primer/dp_primer_stairs_boss

# 解答例
dp[i]はi段目に上る方法の通りを表します。
dp[0] = 1;は、0段目にいる、という意味です。dp[0] = 0;だと、0段目にいないことになります。0段目にいるという意味で１です。0段目に至る方法も1つだけとして、1です。2だと、0段目に至る方法が２つあるという意味で、よくわからないことになります。

for (let i = 1; i <= n; i++)で一段ずつ見ていきます。

dp[i] = 0;は、i段目に至る方法がない、そこには行けないという意味の0が初期値です。

もしi>=aならば、i-a段目からi段目にいけるので、
dp[i]+=dp[i-a](またはdp[i] = dp[i] + dp[i - a];)です。
dp[i-a]>=1なら、i-a段目とi段目がつながるイメージです。
dp[i-a]=0なら、i-a段目にはいないので、つながりません。

b,cについても同様です。

すると、dp[i]に上るのに、何通りあるか、いくつ繋がるか、求まります。

これをi=nまで繰り返すと、0段目からn段目までの行き方が全てつながり、全部で何通りあるか求まります。

```javascript
const fs = require("fs");
const input = fs.readFileSync("/dev/stdin", "utf-8").trim();
const lines = input.split("\n");

const [n, a, b, c] = lines[0].split(" ").map(Number);

const dp = Array(n + 1).fill(0);

dp[0] = 1;
for (let i = 1; i <= n; i++) {
  dp[i] = 0;
  if (i >= a) {
    dp[i] = dp[i] + dp[i - a];
  }
  if (i >= b) {
    dp[i] = dp[i] + dp[i - b];
  }
  if (i >= c) {
    dp[i] = dp[i] + dp[i - c];
  }
}
console.log(dp[n]);
```
S3のjsonファイルを参照してCloudWatchアラームをCLIで設定する

# はじめに
20台以上あるEC2のメモリー使用率を監視して閾値超過したらアラーム通知することになりました。
20台をコンソールからチマチマ設定するのが手間なので、jsonファイルに定義してCLIでさくっと設定したいなぁということでやり方を調べました。
ついでにjsonファイルをローカル環境に持っているのも嫌なのでS3に保存しておきCLIで呼び出したいと思います。
# サービス構成
いたって普通。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2884210/7d37b572-cfd9-b1bf-1221-170dc32c9f42.png" width="400">
# CloudWatchアラームのjson作成
CloudWatchアラームをjsonで定義したファイルを作成します。
```言語:json
{
  "AlarmActions": [
    "arn:aws:sns:ap-northeast-1:11111111:aws_alarms"
  ],
  "AlarmName": "MemoryUtilization_Over80%",
    "Namespace": "xxx",
  "MetricName": "Memory % Committed Bytes In Use",
  "Dimensions": [
    {
      "Name": "InstanceId",
      "Value": "i-xxx"
    },
    {
      "Name": "InstanceId",
      "Value": "i-yyy"
    },
  ],
  "Statistic": "Maximum",
  "Period": 300,
  "EvaluationPeriods": 1,
  "Threshold": 80,
  "ComparisonOperator": "GreaterThanOrEqualToThreshold"
}
```
各項目の意味は次のとおりです。
* AlarmName: アラームの名前を指定する。
* ComparisonOperator: メトリックスの比較演算子を指定する。この例では、GreaterThanOrEqualToThreshold つまり、しきい値以上の場合にアラートを発生させるように設定されている。
* EvaluationPeriods: アラームがトリガーされる前に必要な連続した測定値の数。
* MetricName: 監視するメトリックスの名前を指定する。この例では、Memory % Committed Bytes In Use、つまりメモリ使用率を監視している。
* Namespace: 監視するメトリックスの名前空間を指定する。この例では、xxx、つまり Amazon CloudWatch エージェントによって生成されたメトリックスを監視している。
* Period: メトリックスのサンプリング間隔を指定する。
* Statistic: メトリックスの集計方法を指定する。この例では、Maximum つまり、測定値の最大値を使用してアラートを発生させるように設定されている。
* Threshold: アラートが発生する閾値を指定する。この例では、80%を閾値として設定している。
* ActionsEnabled: アクションを有効にするかどうかを指定する。この例では、trueに設定している。
* AlarmActions: アラームの発生時に実行するアクションを指定する。この例では、指定された SNS トピックに通知するように設定されている。
* Dimensions: 監視対象のリソースに関する情報を指定する。この例では、EC2 インスタンスの ID を InstanceId という名前で指定している。連続記載で複数のEC2を指定可能。

このファイルをS3に保存します。S3のバケットポリシーにはCLIで作業するIAMユーザーで参照権限を付けておきます。
こんな感じ。
```言語:json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowCloudWatchAlarms",
            "Effect": "Allow",
            "Principal": {
                "AWS": [
                    "arn:aws:iam::111111:user/username"
                ]
            },
            "Action": [
                "s3:GetObject",
                "s3:ListBucket"
            ],
            "Resource": [
                "arn:aws:s3:::bucketname",
                "arn:aws:s3:::bucketname/*"
            ]
        }
    ]
}
```
# CLIでの設定
まず、S3に保存したファイルをインスタンスにコピーします。
```
aws s3 cp s3://xxx/MemoryUtilization_Over80%.json MemoryUtilization_Over80%.json
```
続いてCloudWatchアラームに反映します。
```
aws cloudwatch put-metric-alarm --cli-input-json file://~/MemoryUtilization_Over80%.json
```
# 削除する場合
設定した内容はコンソールからも確認可能です。
また、設定削除はCLIは次のとおりです。
```
aws cloudwatch delete-alarms --alarm-names 'MemoryUtilization_Over80%'
```
データ周期を集約する(SPSS Modeler データ加工逆引き5-13)

# データ周期の集約

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/44a7876f-e8b5-f55f-0ca4-edaf6ff7d8b5.png)


## 1.想定される利用目的

・センサーデータの周期の統一
・時系列データのデータ量削減

## 2.サンプルストリームのダウンロード

サンプルストリーム
https://github.com/hkwd/spsssample/raw/master/230302%E3%83%87%E3%83%BC%E3%82%BF%E5%91%A8%E6%9C%9F%E3%81%AE%E9%9B%86%E7%B4%84/%E3%83%87%E3%83%BC%E3%82%BF%E5%91%A8%E6%9C%9F%E3%81%AE%E9%9B%86%E7%B4%84.str

サンプルデータ
https://raw.githubusercontent.com/hkwd/spsssample/master/230302%E3%83%87%E3%83%BC%E3%82%BF%E5%91%A8%E6%9C%9F%E3%81%AE%E9%9B%86%E7%B4%84/Sensor300.csv

## 3.サンプルストリームの説明

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/5e103ee7-3d12-acd1-ea2b-e0506024650b.png)


入力するデータは以下の通りです。1分おきにセンサーデータが発生しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/e4b26946-30b5-fe5e-2c32-8e3357cee090.png)


①.[フィールド作成]ノードを編集します。取り出したい周期でグループ化するインデックスを作ります。
CLEM式に「(@INDEX-1)  div  15」を入力します。
ここでは15回で1サイクルの周期にしています。divで割る値で周期は調整可能です。例えば(@INDEX-1)  div  10にすれば10分おきの周期にできます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/57d205a4-df9b-6d20-9d42-8e6db79b701f.png)

以下のように15レコード毎にインデックスが作られます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/c00a1841-b089-0765-7077-c1286c3ddf6c.png)


②.[レコード集計]ノードで[キーフィールド]を[周期]に設定します。そして、[TS]の[最小値]と[VAL]の[平均]を求めます。[平均]ではなく[中央値]で代表値を作ることもできます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/c2885e02-a2cf-574c-29c0-a0d9ca3e5a3a.png)


[テーブル]を実行します。15分周期でデータを平均や中央値で集約することができました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/63d2bb2f-7dec-d342-9d04-64368a97084b.png)



#### TIPS

逆にデータの周期をより細かいデータに統一したいこともあると思います。その場合には線形補間をすることが可能です。

#### 時系列の欠損値を線形補間する(SPSS Modeler データ加工逆引き5-9)

https://qiita.com/416nishimaki/items/196b0ebacbf93ac62984


## 4.参考情報

#### 線形補間について解説した記事

https://www.ibm.com/blogs/solutions/jp-ja/modeler-tips-03/

#### SPSS Modeler ノードリファレンス目次

https://qiita.com/416nishimaki/private/503037195081d3323eee

#### SPSS Modeler 逆引きストリーム集（データ加工）

https://qiita.com/416nishimaki/private/4bf813e6cba84b2a1008
htmlのrange外で他の変数を参照する方法(Go)

記事編集ページのセレクトバーはカテゴリテーブルのrangeで回していたが、
valueに編集する記事レコードのcategoryIdをselectedとしてどう表示するか。。

          <select class="form-select" name="categoryId" aria-label="Default select example">
            <option selected>カテゴリを選択</option>
            {{ range .Category }}
            {{ if eq .ID .Art.CategoryId }}
            <option value="{{ .ID }}" selected>{{ .Name }}</option>
          {{ else }}
            <option value="{{ .ID }}">{{ .Name }}</option>
          {{ end }}
            {{ end }}
          </select>

これだと
executing "content" at <.Art.CategoryId>: can't evaluate field Art in type models.Category
exit status 1
.Category rangeの中に.Art.CategoryIdなんてありません、と怒られますが。。

```
{{ if eq .ID .Art.CategoryId }}
```
　この部分を
```
{{ if eq .ID $.Art.CategoryId }}
```
　$をつけてあげることで、range外の変数を返せるようです.