OmniAICreator/Qiita-1.07M huggingface dataset:
Googleフォームの回答に応じて服薬情報提供書に転記


```
function myFunction() {
  const sheetId = 'ここにスプレッドシートIDを記入'; //スプレッドシートID
  const thisSpreadSheet = SpreadsheetApp.openById(sheetId); //スプレッドシートを開く
  const answerSheet = thisSpreadSheet.getSheetByName("フォームの回答 1"); //「フォームの回答１」シートを開く
  const reportSheet = thisSpreadSheet.getSheetByName("服薬情報提供書"); //「服薬情報提供書」シートを開く
  const reportSheetId = "ここにシートIDを記入";  //「服薬情報提供書」シートのシートID
  const pharmacistMail ="ここにメールアドレスを記入";  //送信先のメールアドレス
  const folder = DriveApp.getFolderById('ここに保存先のドライブIDを記入')  //PDF保存先のフォルダID
  const lastRow = answerSheet.getLastRow(); //回答の最終行を取得（最新の回答の行）
  const lastRowData = answerSheet.getRange(lastRow,1,1,8).getValues();  //最終行の値を取得（最新の回答を取得）
  const timeStamp =  Utilities.formatDate(lastRowData[0][0],'JST','yyyy/MM/dd');  //タイムスタンプを年月日で取得
  const patientName = lastRowData[0][1];  //患者氏名を取得
  const patientMail = lastRowData[0][2];  //患者メールアドレスを取得
  const patientTel = lastRowData[0][3]; //患者電話番号を取得
  const patientClaim = lastRowData[0][4]; //患者の要望・質問を取得
  const reportWill = lastRowData[0][5]; //医師への報告希望の有無を取得
  const patientBirthDay = Utilities.formatDate(lastRowData[0][6],'JST','yyyy/MM/dd'); //患者の生年月日を取得
  const patientSex = lastRowData[0][7]; //患者の性別を取得

  //患者が医師への報告を希望する場合は、「服薬情報提供書」患者の情報を転機してPDF化して、薬剤師へメールします。
  if(reportWill == '希望します'){
    reportSheet.getRange(17,1).setValue("患者氏名　　" + patientName +"　様");
    reportSheet.getRange(18,1).setValue("電話番号　　" + patientTel);
    reportSheet.getRange(25,1).setValue(patientClaim + "\n" + timeStamp);   

    switch(patientSex){
      case "男性":
      reportSheet.getRange(17,2).setValue("性別：男性　　生年月日：" + patientBirthDay);break;
      case "女性":
      reportSheet.getRange(17,2).setValue("性別：女性　　生年月日：" + patientBirthDay);break;
      case "回答しない":
      reportSheet.getRange(17,2).setValue("　生年月日：" + patientBirthDay);break;
      default: break;
    }

    SpreadsheetApp.flush();

    var url = 'https://docs.google.com/spreadsheets/d/SSID/export?'.replace('SSID', sheetId);
    var opts = {
      exportFormat: 'pdf',
      format:       'pdf',
      size:         'A4',
      portrait:     'true',
      fitw:         'true',
      sheetnames:   'false',
      printtitle:   'false',
      pagenumbers:  'false',
      gridlines:    'false', // 忘れがちですがここをfalseにしないと薄い罫線が入ってしまいます。
      fzr:          'false',
      gid:          reportSheetId
    };
    var url_ext = [];
    for( optName in opts ){
     url_ext.push( optName + '=' + opts[optName] );
    }
    var options = url_ext.join('&');
    var token = ScriptApp.getOAuthToken();
    var response = UrlFetchApp.fetch(url + options, {
      headers: {
      'Authorization': 'Bearer ' +  token
      }
    });
    var blob = response.getBlob().setName(timeStamp+patientName+'様情報提供書.pdf');  
    folder.createFile(blob);

   GmailApp.sendEmail(
        pharmacistMail,
        '報告希望の情報が出されました',//件名です。
        '添付ファイルをご確認下さい。このメールは自動送信です。', //本文になります。
        {attachments: [blob]}
        );

  }else{
    GmailApp.sendEmail(
        pharmacistMail,
        '患者様より情報が寄せられました',//件名です。
        '回答をご確認ください。', //本文になります。
        );
  }
  
}
```
lualine.nvimでステータスラインをカスタマイズするときのTips

neovimやvimを豪華に彩る中でおそらく必須となるであろうステータスライン系プラグインの紹介記事です。

現在公開されているプラグインは様々な種類がありますが、luaで書かれた中ではおそらくlualine.nvimがデファクトです。

https://github.com/nvim-lualine/lualine.nvim

***導入後***
![2023-03-17 13.17のイメージ.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2664731/52bf9aa3-3dc0-ffcd-2aae-7f8058578f35.jpeg)

筆者のコード

https://github.com/Liquid-system/NeovimConfig/blob/main/lua/plugins/lualine.lua

READMEが非常に丁寧に書かれているので、ステータスラインの位置を指定し、lualineに同梱されているコンポーネントを設定するのが定石ですが、筆者はlualine.nvimの`examples`ディレクトリにある`evil_lualine.lua`をカスタマイズしています。

https://github.com/nvim-lualine/lualine.nvim/blob/master/examples/evil_lualine.lua

改良すべき点
Lspを表示するコンポーネントです。`null-ls`などのフォーマット系プラグインを使用している場合は`client.name ~= "null-ls" then`とif文で除外するのがベターです。

```lua
ins_right {
      -- Lsp server name .
      function()
        local msg = "No Active"
        local buf_ft = vim.api.nvim_buf_get_option(0, "filetype")
        local clients = vim.lsp.get_active_clients()
        if next(clients) == nil then
          return msg
        end
        for _, client in ipairs(clients) do
          local filetypes = client.config.filetypes
          if filetypes and vim.fn.index(filetypes, buf_ft) ~= -1 and client.name ~= "null-ls" then
            return client.name
          end
        end
        return msg
      end,
      icon = " LSP:",
      color = { fg = colors.orange },
    }
```

#### 結論
lualine.nvimは比較的癖のないプラグインで扱いやすいです。皆さんもぜひステータスラインライフを送りましょう！
シェルスクリプトでwhile readが1行目しか処理してくれない

```bash
cat foo.txt | while read line; do
    hogehoge
done
```

こんなスクリプトがあったとして、2行目以降が処理されないことがあります。そんな問題の解決策です。


# 結論

私の場合の解決策は以下の通りでした。

```bash
cat foo.txt | while read line; do
    hogehoge < /dev/null
done
```

ループの中の標準入力を `/dev/null` にしてしまいます。


# なにがおきているか

`hogehoge` のが標準入力を吸い込んでしまう場合に2行目が実行されません。 `while read` が読み取るべき2行目以降を `hogehoge` が消化してしまうのです。

具体的には `ssh` コマンドがよくこの問題に当たります。 Dockerで動かしているツールでも起き得ます。

`hogehoge` がまた別のシェルスクリプトのファイルを実行し、その中に `ssh` や `docker run` などがある場合でも同じことが起きます。


# 補足

ループの中身が大きくて、どのコマンドが標準入力を横取りしてしまっているのか不明な場合は、次のようにします。

```bash
cat foo.txt | while read line; do (
    hogehoge1
    hogehoge2
    hogehoge3
) < /dev/null; done
```
toC向けブラウザアプリでしくじった話

## はじめに
こんにちは。最近あまり手を動かさなくなってしまったフロントエンドエンジニアのbakupenです。
フロント開発で年明け2ヶ月で2件もしくじったので共有したいと思います。

## 概要
古いOSバージョン、ブラウザバージョンでアプリが動作しないという障害が起きてしまいました。

2件どちらもtoC（消費者）向けに作ったWebアプリで、
どんな端末・ブラウザを使うかわからないところがミソです。（一応Chromeを推奨したりはしている）

また、サービスのターゲットが高齢者寄りというところが結構重要で、開発時から考慮すべきところでした。

それではそれぞれのしくじりについて紹介していきます。

### [しくじりその1] JSのオプショナルチェーンがbabelでコンパイルされなかった

開発環境：Vue2 + vue-cli

#### babelってなに
まず、JS構文というのはどんどんバージョンアップされていきます。
新しい構文で書くほど、便利に、コードが簡潔に書けるようになったりするので、できれば新しい構文で書きたいと思うものです。
しかし、ブラウザのバージョンによっては新しいJS構文が読めず、画面を表示することができなくなります。

そんなときに活躍するのが、babelというコンパイラです。
babelはとても優秀で、新しい構文で書いたものを古いブラウザでも読めるように変換してくれます。

#### しくじりの内容

Vue.jsなどフレームワークを使って開発する際は大体最初にbabelを入れるかと思います。
開発構築当初の`babel.config.js`はこんな感じ。
```
module.exports = {
  presets: ["@vue/cli-plugin-babel/preset"],
};
```
しかし、これだけだと足りませんでした。
2020年に追加された[オプショナルチェーン](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Optional_chaining)が、コンパイルされなかったのです。
そのため、古いブラウザを使っているユーザーには真っ白い画面をお見せすることになってしまいました…。

#### 対応
`babel.config.js`をこのように１行追加しました。
```
module.exports = {
  presets: ["@vue/cli-plugin-babel/preset"],
  plugins: ["@babel/plugin-proposal-optional-chaining"],  //ここ追加
};
```

オプショナルチェーン以外にも新しめの構文を使った時は、[babelのドキュメント](https://babeljs.io/docs/babel-plugin-proposal-optional-chaining)で独自設定が必要かどうか確認するといいと思います。

参考記事：https://blog.mahoroi.com/posts/2018/12/try-babel-proposal-optional-chaining/

### [しくじりその2] CSSの単位`dvh`は新しすぎた

開発環境：React + Vite

#### dvhってなに
CSSでは要素の高さや幅を指定することができます。
指定する際に主に使われている単位が`px`や`%`だと思いますが、`vh` `vw`という単位もあります。
`%`が「親要素」に対する割合で指定するのに対し、「ビューポイント（端末の画面の大きさ）」に対する割合で指定するものです。
`vh`は高さ、 `vw`は幅になります。

この高さを指定する`vh`、スマホ利用を想定したページでの使い勝手が少し悪いのですが、それを改善する`dvh`という単位が2022年11月に新しく追加されました。

https://zenn.dev/moneyforward/articles/svh-dvh-lvh-for-all-browser

#### しくじりの内容
Google Chrome 108から対応とのことで、103などちょっと古いChromeで`dvh`を使ったページを開こうとすると画面が真っ白になってしまいました。

#### 対応
dvhを使わず、こちらのサイトを参考にJavaScriptを使ってビューポイントの高さを取得しました。

https://step-by.work/415/

## おわりに
今回の2件以外で過去にtoC向けのアプリを開発したことがなかったので、なかなか苦戦したとともに勉強になりました。
どちらもメインターゲットが高齢者なので、高齢者向けのスマートフォンから利用されることを想定する必要がありました。

高齢者向けのスマートフォン、ブラウザのバージョン更新止めてるんじゃないかなと思いました。
（おそらくバージョンアップによるUI変更で混乱しないためかと思われます）
そのためか、「最新のブラウザで利用してくれないユーザー」が普通に存在していました。

セキュリティ大丈夫なのかと思いますが、現場も大変そうですからね…。
satoriをOGP画像生成以外の用途で使う（最終的にはZoom背景ジェネレーターになった）

## この記事の概要

最近では、ブログのOGPを動的に生成したいときにsatoriが使われているのをよく見ます。

https://github.com/vercel/satori

ただ、色々使えそうなライブラリの割にこのユースケースしか見ないような気もします。
（自分が知らないだけだったらすみません）

というわけで、違う使い方を模索してみました。

## 作ったもの

こねくりまわした結果、Zoomなど用のバーチャル背景用ジェネレーターができました。

https://github.com/xrxoxcxox/background-image-generator

READMEに貼った動画のような感じで、好きなテキストを打ち替えてダウンロードができます。

## コード（抜粋）

```jsx
import { useEffect, useState } from 'react'
import satori from 'satori'
import { Card } from './Card'
import { downloadSvgAsPng } from './svg-utils'
import './style.css'

const notoSansJP = fetch('/NotoSansJP-Regular.otf').then((res) =>
  res.arrayBuffer()
)

export default function App() {
  const [role, setRole] = useState('Human')
  const [name, setName] = useState('John Doe')
  const [svgString, setSvgString] = useState('')

  const handleChangeRole = (e) => {
    setRole(e.target.value)
  }
  const handleChangeName = (e) => {
    setName(e.target.value)
  }

  useEffect(() => {
    ;(async () => {
      const svg = await satori(<Card role={role} name={name} />, {
        width: 1920,
        height: 1080,
        fonts: [
          {
            name: 'Noto Sans JP',
            data: await notoSansJP,
          },
        ],
      })
      setSvgString(svg)
    })()
  }, [role, name])

  return (
    <>
      <div dangerouslySetInnerHTML={{ __html: svgString }} />
      <label>
        Role
        <input type='text' onChange={handleChangeRole} />
      </label>
      <label>
        Name
        <input type='text' onChange={handleChangeName} />
      </label>
      <button type='button' onClick={() => downloadSvgAsPng(svgString)}>Download</button>
    </>
  )
}
```

別途定義した`Card`コンポーネントを呼び出して、svgに変換してビューとして埋め込み、役職や名前をリアルタイムでプレビューできるようにしました。
そしてsvgをpngとしてダウンロードする関数も別途定義しておき[^resvg]、それを噛ませてダウンロードしています。

[^resvg]: なお、この機構もresvgとして提供されてるじゃん。と後から気がつきました。 https://github.com/yisibl/resvg-js

今回はinputの数だけuseStateを定義してしまいましたが、数が増えたとき用に1つにまとめておいた方が良さそうな気はしています。

## 最後に

天邪鬼なので「みんなと違う使い方をしてみたいなあ」から始まっていますが、これはこれで便利かもしれません。
よくあるのがデザイナーしかAdobeライセンスを持っていなくて、ちょっとしたテキスト変更だけなのにデザイナーに頼まないといけなくて面倒、みたいなシチュエーションです。

メルマガ用の画像やツイート用の画像など、OGPとして生成しづらい場面用にテンプレートとして用意しておくことができそうな気がしています。

---

最後まで読んでくださってありがとうございます！
Twitterでも情報を発信しているので、良かったらフォローお願いします！

https://twitter.com/xrxoxcxox

Devトークでのお話してくださる方も募集中です！

https://jobs.qiita.com/employers/qiita-inc/dev_talks/489
OpenAPI Generatorを使ってライブラリを生成しているサービスについて調べてみた

# はじめに
OpenAPI Generatorを使っている各社サービスがどのようにクライアントライブラリを生成しているのか調べてみた。

OpenAPI Generatorのサイトに、利用しているサービスの一覧が載っている。

https://openapi-generator.tech/users

ここからいくつかピックアップして、どのようにクライアントライブラリを生成しているか調べてみた。

# 注意
- 今回は、各社のパブリックリポジトリや公開ドキュメントなどをみて、そこから推測される方法をまとめたため、実際とは異なる場合がある。
- 例としてピックアップしたライブラリは、基本Pythonが中心となっている (個人的にPythonを利用することが多いため)。

# Kubernetes
JavaやPython、TypeScript, Go、Rustなど、主要な言語のライブラリを生成。

Generate用のリポジトリで管理。

https://github.com/kubernetes-client/gen/tree/master/openapi

このリポジトリで生成用のスクリプトや設定値を管理し、各言語のライブラリを生成。

Python用のライブラリ

https://github.com/kubernetes-client/python

また、HostやAPI Keyの設定は、デフォルトの直接指定する方法に加えて、kubeconfigファイルをロードするためのHelper関数 `config.load_kube_config()` も別途カスタムで実装されている。 

# DataDog
JavaやPython、TypeScript, Go、Rustなど、現在主流な言語のライブラリを生成。

Python用のライブラリ

https://github.com/DataDog/datadog-api-client-python

Keyは別途API keyをDataDogの画面から取得して使う。

生成については、Spec fileを管理しているプライベートリポジトリにて、更新があったら各クライアントライブラリも自動で生成されるようになっている。

また、OpenAPI Generatorを拡張した「Apigentools」というツールで生成をおこなっており、これはDataDogがcontributorとして開発している様子。

https://github.com/DataDog/apigentools

# Mastercard
公開されているリポジトリにはJava, Python, NodeJS, Ruby, PHP, C#のライブラリが存在しているが、基本的にはSpec fileを用いてOpenAPI Generatorで各自で生成するように案内されている。

Guide

https://developer.mastercard.com/platform/documentation/security-and-authentication/generating-and-configuring-a-mastercard-api-client/

Tutorial (ここにサンプルとして生成されたライブラリコードが格納されている)

https://github.com/Mastercard/mastercard-api-client-tutorial

API利用のためのKey生成 (one-legged OAuth 1.0a) は、別ライブラリが用意されている。

https://github.com/Mastercard/oauth1-signer-python

# Twilio
JavaやPython、NodeJS, Goなどの主要な言語のライブラリを生成。

Generate用のリポジトリで管理。

https://github.com/twilio/twilio-oai-generator

各言語ごとに実行ファイルを実行して生成。Kubernetesのように自動生成されている形ではなさそう。

Python用のライブラリ

https://github.com/twilio/twilio-python/

# Freee
Freee APIのSpec fileが公開されており、それを用いて各自で生成するようガイドしている。

https://developer.freee.co.jp/guideline/client-code-generate-php
Starapi(4.7.1)でmediaで作った画像URLをGraphQLで取得した

starapi(4.7.1)の画像のapiの取得がむずかったので、備忘録。(3以下?のバージョンから変わったようだ...)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/638403/3db96452-954b-d3b6-f290-90e3ee864672.png)
のようにmediaでimageを作った。
idごとに複数の画像を入れているので↓
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/638403/19d3413f-57ce-a8ea-5d73-da75c9f23bf2.png)
idごとの画像urlを取ってきたかった。（全部のデータならhttp://localhost:1337/api/upload/files で見れる）

## ?populate=*で見てみる
最初
http://localhost:1337/api/genres
で見たところ、バージョンが3まではこれで画像データも出てきていたが、バージョン４では見れない。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/638403/44a4b010-ebc0-7f5a-ef6d-b3fa9bc0a40f.png)

で画像のデータは見えないが、
https://docs.strapi.io/dev-docs/api/rest/populate-select#population
にあるように
![68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f3633383430332f33646239363435322d393534622d643362362d663239302d3930653365653836343637322e706e67.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/638403/32199b50-246b-05e1-7fcf-aced0c6c0b19.png)

http://localhost:1337/api/genres?populate=image
にしたところ、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/638403/bc52d9b2-8429-9ac5-11ec-f4522dae4b32.png)
と画像のデータが見えるようになった。

## ↑上を元にgraphqlで取ってくる
![68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f3633383430332f62356531613137332d376536652d663538662d636563372d6566663836323366623161332e706e67.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/638403/b0763edc-dbae-b33a-a037-582bc69b1caf.png)

これでid毎に紐づいた画像のurlを取ってくることができるようになりましたとさ。
~~昔は{url}だけでよかったのに今は{data{attributes{url}}みたいに書かないといけないんだそうな。~~
ちゃんと複数取って来れるゾ！
めでたしめでたし？
【SCSS】定義の再利用

## SCSSの定義再利用
SCSSでは別ファイルに定義を書くとさらに別ファイルでその定義を使用することができます。

## やり方
`main.scss`と`sub.scss`というファイルがあるとします。
`main.scss`がカラーの設定である`color:rgb(255,255,255);`を複数回使用するとすると、全部変えるのはめんどくさいですよね？

その時に`sub.scss`に
```css:sub.scss
　$mainColor:rgb(255,255,255);
```
を定義しておきます。

main.scssには
```css:main.scss
@import "Colors";
.example1{
   color:$mainColor;//定義を使用
}

.example2{
   color:$mainColor;//定義を再度使用
}
```

このようにして定義を使いまわすことができます。

もし、mainColorを変更したい！となった場合。`sub.scss`を変更するだけで済みます。

```css:sub.scss
　$mainColor:rgb(0,0,0);//black
```
にすることでmain.scssは変更しなくでも大丈夫になります。
JavaScriptのArrayメソッド集〜破壊・非破壊別まとめ〜

# はじめに
自分用に、Array操作で破壊的なのか非破壊的なのかまとめとこうと思い、備忘録で残します〜！

誰かの参考になれば幸いです。

# そもそも破壊的？非破壊的？ってなに

JavaScriptのArrayメソッドには、破壊的メソッドと非破壊的メソッドがあります。違いは、元の配列に変更を加えるかどうかです。

## 破壊的メソッド
破壊的メソッドは、元の配列を変更します。これらのメソッドを使用すると、配列の要素が追加、削除、または変更され、配列の状態が変わります。

## 非破壊的メソッド
非破壊的メソッドは、元の配列を変更しません。これらのメソッドを使用しても、元の配列の状態はそのまま保たれます。代わりに、新しい配列が生成されたり、特定の値が返されたりします。

破壊的メソッドと非破壊的メソッドを適切に使い分けることで、配列操作を効果的に行うことができます。
元の配列の状態を保持したい場合は、非破壊的メソッドを使用し、状態の変更が必要な場合は、破壊的メソッドを使用するイメージでしょうか。

# まとめ

| 破壊的メソッド     | 説明                                      | 非破壊的メソッド  | 説明                                              |
|--------------|---------------------------------------|--------------|-------------------------------------------------|
| `push()`     | 配列の最後に要素を追加する                         | `concat()`   | 既存の配列に1つまたは複数の配列を結合した新しい配列を返す       |
| `pop()`      | 配列の最後の要素を削除し、その要素を返す              | `slice()`    | 配列の一部を新しい配列として返す                                   |
| `shift()`    | 配列の最初の要素を削除し、その要素を返す              | `map()`      | 配列のすべての要素に関数を適用し、結果を新しい配列として返す       |
| `unshift()`  | 配列の先頭に1つまたは複数の要素を追加する             | `filter()`   | 配列の要素のうち、指定した関数を満たすものだけを新しい配列として返す |
| `splice()`   | 配列の要素を削除/追加し、削除された要素の配列を返す     | `find()`     | 配列の要素のうち、指定した関数を満たす最初の要素を返す              |
| `reverse()`  | 配列の要素の並びを逆にする                           | `findIndex()`| 配列の要素のうち、指定した関数を満たす最初の要素のインデックスを返す |
| `sort()`     | 配列の要素をソートする                            | `includes()` | 配列が特定の要素を含むかどうかを返す                                |
| `fill()`     | 配列の要素を指定した値で埋める                       | `indexOf()`  | 指定した要素が最初に現れるインデックスを返す                         |
|              |                                           | `lastIndexOf()`| 指定した要素が最後に現れるインデックスを返す                         |
|              |                                           | `reduce()`   | 配列の要素を1つの値にまとめる（左から右へ）                         |
|              |                                           | `reduceRight()`| 配列の要素を1つの値にまとめる（右から左へ）                         |
|              |                                           | `every()`    | 配列のすべての要素が指定した関数を満たすかどうかを返す              |
|              |                                           | `some()`     | 配列のいずれかの要素が指定した関数を満たすかどうかを返す             |
wemosでalexaデバイス

# 概要

wemos d1で、alexaデバイスを作ってみる。
開発環境を作る。

# 環境

windows vista 32bit
arduino ide v1.8.5

# ライブラリーをボードマネージャーで入れる。

- esp8266 v 3.1.1は、動かん。
- esp8266 v 2.7.4入れた。

# usbに繋ぐと、com10に、見える。

# ボードは、wemos d1 r1を選ぶ。
- upload speed 57600


以上。
【TypeScript】分割代入　メモ

## 分割代入
オブジェクトの分割代入はオブジェクトや配列から必要なプロパティ要素を抽出して、変数に代入する方法です。

## オブジェクトの分割代入
userというオブジェクトから`name`と`age`というプロパティを取り出して、それぞれの変数に代入しています。
```typescript
const user = { name: 'John', age: 30 };
const { name, age } = user;

console.log(name); // John
console.log(age); // 30
```

普通、オブジェクトのプロパティを取ろうとすると、
```typescript
console.log(user.name)
console.log(user.age)
```
の様にしなければなりませんが、分割代入をすることで無駄な記述が減ります。

## 配列の分割代入
次に配列の分割代入です。
```typescript
const numbers = [1, 2, 3, 4, 5];
const [first, second, ...rest] = numbers;

console.log(first); // 1
console.log(second); // 2
console.log(rest); // [3, 4, 5]
```
配列もオブジェクトの時と同じように分割代入を使用することができます。
IBM Workload Scheduler 10.1 Fix Pack 2を使用して新規インストール(RHEL8)

IBM Workload Scheduler(IWS) 10.1 Fix Pack 2が 2023/02/28 付でリリースされました。

2024/06/03追記：
Fix PackはGA版のインストールを前提とせず、Fix Pack イメージを使用して新規インストールできる場合があります。その場合はGA版をインストールする手間を省略できます。
ただし、Fix Packにより新規インストール可否が異なる場合があるため、Readme に特に記載がない場合は Fix Pack での初期インストールが可能かIBM Supportへお問い合わせいただくことをお勧めします。

以下はRHEL8 サーバーへの新規インストールを試した際のメモです。

# Fix Pack Readme の確認
インストールする前にFix PackのReadmeに目を通し、Fix Pack 適用上の考慮点、適用手順などを確認します。
ReadmeはDynamic Workload Console(DWC), IWSの２つに分けて提供されます。


[Readme file for IBM Workload Scheduler Version 10.1 Fix Pack 2](https://www.ibm.com/support/pages/node/6958046 "Readme file for IBM Workload Scheduler Version 10.1 Fix Pack 2")

[Readme file for Dynamic Workload Console Version 10.1 Fix Pack 2](https://www.ibm.com/support/pages/node/6958048 "Readme file for Dynamic Workload Console Version 10.1 Fix Pack 2")

インストールする環境に応じて考慮点が異なりますので、Readmeは必ず目を通してください。
自身の検証環境で留意すべき点として、以下がありました。
* IBM Workload Scheduler Version 10.1 Fix Pack 2 was formally tested by using WebSphere Application Server Liberty Base 22.0.013 and 23.0.0.1.　（WAS Liberty のバージョン）
* On UNIX™ operating systems, before installing the IBM Workload Scheduler Fix Pack, ensure that your umask is set to 022.　（Fix Packインストール時は umask を022に設定する）



# Fix Pack イメージのダウンロード
[IBM Support Fix Central](https://www.ibm.com/support/fixcentral/ "Fix Central") より必要なFix Pack イメージをダウンロードします。
製品セレクターとして "IBM Workload Scheduler"、インストール済みバージョンとして"10.1"　プラットフォームはご使用のプラットフォームを選択し、「次へ進む」をクリックします。
![スクリーンショット 2023-03-17 12.37.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135603/ccfa920f-714f-95a4-dda1-58c4069b9e73.png)

続いて表示される「フィックスの特定」ページで"フィックスの参照"ラジオボタンを選択して「次へ進む」をクリックします。
![スクリーンショット 2023-03-17 12.38.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135603/570d1c34-a49d-6d57-2888-f6a7f588d152.png)

続いて表示されるリストから、必要なフィックスパックを選択して「次へ進む」をクリックします。Fix Packはコンポーネント毎、プラットフォーム毎に分かれているのでご使用のプラットフォーム用のFix Packを選択してください。

今回はRHEL8(x86_64)へインストールするので、以下を選択しました。

|イメージ名 |内容|
|---|---|
|10.1.0.2-2023.02-IWS-SERVER-LNX_X86_64 |IWSサーバー Fix Packイメージ|
|10.1.0.2-2023.02-IWS-CONSOLE-LNX_X86_64 |DWC Fix Packイメージ|
|10.1.0.2-2023.02-IWS-AGENT-LNX_X86_64 |IWS Agent(FTA/DA)Fix Packイメージ|

「次へ進む」をクリックするとIBM idでのログインを促されます。（すでにログインしている場合はダウンロード・オプションを選択する画面へ進みます。）
以降はページ上のガイドに従ってダウンロードを行います。

# Fix Pack を使用したインストール

インストール手順はGeneral Availability(GA)版と基本的に変わりませんでした。
GA版を使用した手順は[こちら](https://qiita.com/satoponpon/items/dc7a5bee43046a6a0700 "IBM Workload Scheduler 10.1 をRHEL8環境へインストールしてみた")で公開しております。
前提チェック、前提RPMの導入、必要ユーザーの作成、Db2のインストール含め上記を参考にしてください。
[IWS MDMのインストール](https://qiita.com/satoponpon/items/dc7a5bee43046a6a0700#iws-mdm%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB "IWS MDMのインストール")　以降の手順を実施する際に、ダウンロードした Fix Pack イメージを使用します。



以上です。
「CKKS解説ブログ」を解説する 2/5

この記事は [2023年四半期カレンダー（３月版）](https://qiita.com/0917laplace/items/663c7b78854b5a0d47f7) の６日目の記事です．

CKKSの第２回です．

|何回目  |内容  |
|---|---|
|1  |CKKSの一般論, 前提知識  |
|2  |vanila encoding, full encoding  |
|3  |encrypt, 暗号文の足し算・スカラー倍 |
|4  |暗号文の掛け算 |
|5  |Rescaling |

今回は，encoding, decoding の話がメインで
・vanila encoding
・full encoding
の2つを解説していきます．

# vanila encoding

本節は以下の内容に対応します:
https://blog.openmined.org/ckks-explained-part-1-simple-encoding-and-decoding/

## イントロ

まず，CKKSは次の流れで encode, 暗号化が行われます

![CKKS_view.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1298501/e45e11da-e776-6103-373d-03a9e95f7707.png)

つまり，$m \in \mathbb{C}^{N / 2}$ なるメッセージ（cleartext）を取って，それを $p(X) \in \mathbb{Z}[X] / (X^N + 1)$ なる平文にエンコードし，更に $c = (c_0(X), c_1(X)) \in (\mathbb{Z} / q \mathbb{Z})[X] / (X^N + 1)^2$ なる暗号文へ暗号化するわけです．

以下では，$N$ を2べきとして，$M = 2 N$ とします．このとき，命題0.15から $\Phi_M(X) = X^N + 1$ です．
1の $M$ 乗根を $\displaystyle \zeta_M = e^{\frac{2 \pi \sqrt{-1}}{M}}$ で表すことにします．

いきなり，encodeの方法を考えるのは難しいので，まずは，複素ベクトル $z \in \mathbb{C}^N$ を多項式 $\mathbb{Z}[X] / (X^N + 1)$ へと
エンコードする方法を考えていきます．

## vanila encoding

![CKKS_1_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1298501/542d3675-b1c1-11f2-31ea-23647c9e9174.png)

![CKKS_1_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1298501/e7f99cae-dc40-4299-98e8-e97ac1ea449a.png)

![CKKS_1_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1298501/56c1f010-12d9-be94-c827-21de4796f49b.png)

## 具体例

＊コードはブログの方を参照してください，ここでは理論的に計算をします

![CKKS_1_4_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1298501/be25879f-4f75-414a-fe20-470fd25dbf1f.png)

![CKKS_1_4_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1298501/a73e1737-26c0-ba40-972b-36e921591e08.png)

![CKKS_1_4_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1298501/21ee739d-10a7-bfc8-f36b-aab12d169261.png)


# full encoding

本節は以下の内容に対応します:
https://blog.openmined.org/ckks-explained-part-2-ckks-encoding-and-decoding/

## CKKS encoding

![CKKS_2_2_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1298501/444cc442-b2e8-3f84-cd29-786ae79f8c63.png)

![CKKS_2_2_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1298501/d2023364-cd7c-f64f-061f-d4929933f0b1.png)

![CKKS_2_2_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1298501/480a64eb-1665-cbc3-deff-e6e61fbae6c7.png)

![CKKS_2_2_4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1298501/90030e89-d42c-c3e2-f073-a8373abe618c.png)


# まとめとか感想とか
前置きが随分と長いなぁという印象ですが，次回から暗号化とか暗号文に対する演算の話になります
実は「イデアル格子暗号入門」の内容をご存知の方なら，そんなに苦労せずにこの後を読めるのかなと・・・

--------------------------------------
今回の内容はここまでです．ここまでご覧になってくださった方々ありがとうございます！
「CKKS解説ブログ」を解説する 1/5

この記事は [2023年四半期カレンダー（３月版）](https://qiita.com/0917laplace/items/663c7b78854b5a0d47f7) の５日目の記事です．

今回からCKKSにも踏み込んでいきます．

|何回目  |内容  |
|---|---|
|1  |CKKSの一般論, 前提知識  |
|2  |vanila encoding, full encoding  |
|3  |encrypt, 暗号文の足し算・スカラー倍 |
|4  |暗号文の掛け算 |
|5  |Rescaling |

今回はCKKSの中身には入らずに
・CKKSの一般論
・前提知識
の2つを解説していきます．

# CKKSの一般論

CKKS暗号方式とは，

J. H. Cheon, A. Kim, M. Kim, Y. Song: ``Homomorphic Encryption for Arithmetic of Approximate Numbers'', In: International conference on the theory and application of cryptology and information security, Springer, Cham, pp.409-437, 2017.

によって，提案された暗号方式です．

なんですが，僕が１から解説するのもあれなので，いくつかCKKSの話題を引用しておきます

[格子暗号のCKKS形式のパラメータ、精度ビットなどについて解説！（SEALライブラリ）](https://qiita.com/kenmaro/items/931835476ca8781de9f9)

[SEAL による準同型暗号](https://learn.microsoft.com/ja-jp/azure/architecture/solution-ideas/articles/homomorphic-encryption-seal)

[BFV, CKKS, TFHE って何が違うんですか？①](https://qiita.com/0917laplace/items/a3ba76a889a80662fddc)

# 前提知識

今回は次回からの議論で使う数学を導入します．相変わらず別の媒体で書いたものをスクショして載せます．

## 多項式環

![0_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1298501/fc12c004-d74f-cdb8-981e-4d15fe8580c6.png)

## 1の原始根

![0_2_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1298501/53af7837-b98e-c9d5-329c-7b9aee95a7d8.png)

![0_2_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1298501/70a28a4a-7779-57d4-7507-b3e700fe0d59.png)

## 円分多項式

![0_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1298501/7b9c222f-e8ee-5608-2222-7d58d30332fb.png)

## L∞ノルム

![0_4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1298501/3ce3e13c-807e-a09f-83c0-8f00f4ec0d97.png)

# まとめとか感想とか
ナンバリングは今回記載のものを採用していきます
次回からは解説ブログの理論的な部分を補強する形で書いていき，実装に関する話はブログを参照していただく形で進めていきます

--------------------------------------
今回の内容はここまでです．ここまでご覧になってくださった方々ありがとうございます！
Vue2 × Vuetify でローカルのCSVファイルをテーブル表示してみた

## はじめに
Vue2とVuetifyでローカルのCSVファイルをテーブルに表示してみました。
実装の流れは以下の通りです。

1. Vueプロジェクトの作成
1. papaparseライブラリのインストール
1. CSVファイルを選択するinput要素と表示するテーブルの作成
1. CSVファイルを読み込むハンドラーメソッドの作成


## 開発環境
- Windows 11
- Vue CLI 5.0.8
- Vue 2.7.14
- npm 6.14.14
- Node.js 14.17.5


## 実装
### Vueプロジェクトの作成
Vue CLIを使ってVueプロジェクトを作成します。

```:ターミナル
vue create フォルダ名（任意）
```

作成したプロジェクトがあるフォルダに移動し、以下のコマンドを実行して、Vuetifyを追加します。
```:ターミナル
vue add vuetify
```
途中でプリセットの選択を聞かれるので、Default(recommended)を選択します。

今回は、Vueプロジェクト内のHelloWorld.vueを編集していきます。最初に、デフォルトで生成されるコードを削除し、templateタグとscriptタグのみを残してください。

```HelloWorld.vue
<template>
</template>

<script>
</script>
```

### papaparseライブラリのインストール
papaparseは、CSVファイルの解析を簡単に扱えるライブラリです。

まずは、以下のコマンドでpapaparseをインストールします。

```:ターミナル
npm install papaparse --save
```
script開始タグの直下でpapaparseをインポートします。
```JavaScript
import Papa from 'papaparse'
```

### ファイルを選択するinput要素と表示するテーブルの作成
HelloWorld.vueのtemplateタグを以下のように書き換えます。

input要素のtype属性を"file"にすることで、ファイルをアップロードできるようになります。また、ファイルが選択された際には@changeイベントを介してhandleFileUploadメソッドが呼び出されます。このhandleFileUploadメソッドは後ほど作成します。

v-data-tableタグを使用することで、テーブルを配置できます。:headers属性は、テーブルの列名を定義した配列で、:items属性はテーブルの行データを定義した配列です。これらのプロパティは、scriptタグのdata内で定義します。

```HelloWorld.vue
<template>
  <div>
    <input type="file" @change="handleFileUpload" />
    <v-data-table :headers="headers" :items="items" />
  </div>
</template>
<script>
import Papa from 'papaparse'

export default {
  data() {
    return {
      headers: [],
      items: []
    }
  }
}
</script>
```

### CSVファイルを読み込むハンドラーメソッドの作成
次に、handleFileUploadメソッドを作成します。1行目をヘッダーとして使用し、2行目以降をitemsプロパティに入れます。

```HelloWorld.vue
<template>
  <div>
    <input type="file" @change="handleFileUpload" />
    <v-data-table :headers="headers" :items="items" />
  </div>
</template>

<script>
import Papa from 'papaparse' 

export default {
  data() {
    return {
      headers: [],
      items: []
    }
  },
  //以下、methodsを追加
  methods: {
    handleFileUpload(event) {
      const file = event.target.files[0]
      Papa.parse(file, {
        header: true,
        complete: (results) => {
          this.headers = Object.keys(results.data[0]).map((key) => ({
            text: key,
            value: key
          }))
          this.items = results.data
        }
      })
    }
  }
}
</script>

```

ここまで終えると、実装は完了です。テーブルに表示してみましょう。

「ファイルを選択」をクリックし、任意のCSVファイルをアップロードします。
![screencapture-localhost-8080-2023-03-16-20_46_57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3124507/ade5c00c-402f-a819-8754-0b2c5b8cec96.png)

アップロードが完了すると、以下のようにテーブルに表示されます。
![screencapture-localhost-8080-2023-03-16-20_49_38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3124507/1aea15fd-7704-ed91-898c-8df1da6dcb7c.png)


## おわりに
今回は、Vue2とVuetifyを使用して、ローカルのCSVファイルをテーブルに表示してみました。
papaparseというライブラリを使用することで、CSVを簡単に解析することができました。ライブラリを使うことで、開発のハードルを下げることができますね。ぜひ使ってみてください。
Coroutine の中断を活かす実装

Coroutine の中断を活かした実装ができていなかったので、戒めに記事を書きます。

## 結論
Coroutine を使用する際は、[中断](https://developer.android.com/kotlin/coroutines?hl=ja#features)を考慮してパフォーマンスやメモリの節約を考慮する。

## 詳細
Coroutine 内で待ち合わせ処理を行うために、CountDownLatch を使用していました。

Kotlin の Coroutine は[中断](https://developer.android.com/kotlin/coroutines?hl=ja#features)がサポートされているため、1 つのスレッドで多数の Coroutine を実行できます。
これにより、Coroutine を実行しているスレッドがブロックされません。
しかし、CountDownLatch の await のような suspend　関数でない方法で待ち合わせ処理を行うと、中断が行われずスレッドがブロックされます。

極端な例ですが、下記の CountDownLatch の例では、スレッドがブロックされてしまいます。
```kotlin
    @Test
    fun coroutineTestWithCountDownLatch() = runTest {
        val latch = CountDownLatch(1)
        launch(Dispatchers.Default) {
            delay(2000)
            latch.countDown()
        }
        println("call async 1")
        val def1 = async {
            println("coroutine 1 start(${Thread.currentThread().id})")
            latch.await()
            println("coroutine 1 end")
        }
        println("call async 2")
        val def2 = async {
            println("coroutine 2 start(${Thread.currentThread().id})")
            println("coroutine 2 end")
        }
        def1.await()
        def2.await()
    }
```

実行すると、下記のようなログが出力され、1つ目の async で実行した処理が終わってから、2つ目の async の処理が行われています。
```console
call async 1
call async 2
coroutine 1 start(10)
coroutine 1 end
coroutine 2 start(10)
coroutine 2 end
```

上記の例の CountDownLatch を CompletableDeferred に変更するとスレッドはブロックされません。
```kotlin
    @Test
    fun coroutineTestWithCompletableDeferred() = runTest {
        // CountDownLatch を CompletableDeferred に変更
        val def = CompletableDeferred<Any>()
        launch(Dispatchers.Default) {
            delay(2000)
            def.complete(Any())
        }
        println("call async 1")
        val def1 = async {
            println("coroutine 1 start(${Thread.currentThread().id})")
            def.await()
            println("coroutine 1 end")
        }
        println("call async 2")
        val def2 = async {
            println("coroutine 2 start(${Thread.currentThread().id})")
            println("coroutine 2 end")
        }
        def1.await()
        def2.await()
    }
```

ログは下記の通りで、1つ目の async で実行した処理の中断中に、2つ目の async の処理が行われています。
```console
call async 1
call async 2
coroutine 1 start(10)
coroutine 2 start(10)
coroutine 2 end
coroutine 1 end
```

## 補足
CountDownLatch と同じ理由で、排他制御に関しても、synchronized よりも Mutex の withLock を使った方が、スレッドを有効に活用できます。
Centos6 Centos7

CentOS6
```sh
シャットダウン 
shutdown -h now	

再起動	
reboot shutdown -r now	

シングルユーザーモード	
init S
	
サービス一覧	
chkconfig --list	

サービス自動起動ON(sshd)	
chkconfig sshd on
	
サービス自動起動OFF(sshd)
chkconfig sshd off	

サービス起動(sshd)
service sshd start

サービス停止(sshd)
service sshd stop	

サービス強制終了	
kill -9 <sshdのPID>	
```

CentOS7
```
シャットダウン 
systemctl poweroff

再起動
reboot systemctl reboot

シングルユーザーモード	
systemctl rescue

サービス再起動(sshd)
systemctl restart sshd

サービス状態確認	
systemctl status sshd

サービス設定リロード	
systemctl reload sshd

サービス一覧
systemctl --type service

サービス自動起動ON(sshd)
systemctl enable sshd

サービス自動起動OFF(sshd)
systemctl disable sshd

サービス起動	
systemctl start sshd

サービス強制終了
systemctl kill --signal=9 sshd
```
CentOS_RemoteDesktop

### 環境情報
CentOS 8.5.2111
xrdp-0.9.21-1.el8.x86_64

# xrdpをインストール
WindowsからLinuxへリモートデスクトップ接続を出来るようにする。
```
#yum install epel-release
```

vimで開いてenabled=1　→　enabled=0に変更。
```
#vi /etc/yum.repos.d/epel.repo 
```
```epel```リポジトリを使用してインストール。
```
#yum install --enablerepo=epel xrdp
```

ファイアウォールのTCP3389番を開放して再起動。
```
#firewall-cmd --permanent --add-port=3389/tcp && firewall-cmd --reload 
```

xrdp.serviceを起動、自動起動を有効。
```
#systemctl start xrdp.service && systemctl enable xrdp.service
```

# Windowsからリモートデスクトップ接続
リモートデスクトップを開ける
<img width="600" alt="linux_リモートデスクトップ１.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2929519/b17b5307-41b5-34b4-58e4-46840ed829b6.png">

コンピューター名にIPアドレスを入力。ユーザー名も
※ローカルユーザーだと何故かはじかれるため？、rootでログイン。
<img width="600" alt="linux_リモートデスクトップ２.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2929519/db778bc7-5e46-ba1d-fee8-669f6dac5ed5.png">

「はい」をクリック
<img width="600" alt="centosデスクトップ3.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2929519/0b54e582-b92b-c727-8dde-ecdf43d16d39.png">
PHP：composer.phar 実行時に「Could not open input file: composer.phar」というエラーが出た時の対処。

# 現象

php composer.phar XXX といったコマンドを入力した時、Could not open input file: composer.phar というエラーメッセージが出る。

```エラー.hph
Could not open input file: composer.phar
```
# 解決策
以下コマンドでを実行
```php
php -r "readfile('https://getcomposer.org/installer');" | php
```

ダウンロード成功
```php
All settings correct for using Composer
Downloading...

Composer (version 2.5.4) successfully installed to: C:\Users\user\Documents\laravel\composer.phar
Use it: php composer.phar
```
S3に、Cognitoの認証ユーザ別のフォルダを用意し、アクセス制限をかける方法

## 設定

IDプールがクライアントに渡すロールのポリシー設定を下記のようにすると、"IDプールが発行するID名のフォルダ" 配下にしかアクセスできなくなる。

※フォルダという表現は正確ではないけど、良い言い方がないので・・


#### CognitoのIDプールが渡すロールのポリシー設定

```JSON
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "s3:PutObject"
            ],
            "Resource": "arn:aws:s3:::backetname/${cognito-identity.amazonaws.com:sub}/*"
        }
    ]
}
```

#### クライアント側でのID取得方法（Amplify想定）

```javascript

const currentCredentials = await Auth.currentCredentials();
const identityId = currentCredentials.identityId;

// 取得されるIDは下記の形式（リージョン以降は、ユーザプールの sub 属性の値）
// ap-northeast-1:12345678-abcd-1234-abcd-12345678abcd
```

#### 結果

↓のパスにしかアクセスできない。
bucketname/ap-northeast-1:12345678-abcd-1234-abcd-12345678abcd/

アクセスできる例：
bucketname/ap-northeast-1:12345678-abcd-1234-abcd-12345678abcd/aaaa.txt
bucketname/ap-northeast-1:12345678-abcd-1234-abcd-12345678abcd/bbbb.txt

アクセスできない例：
bucketname/ap-northeast-1:98765432-zzzz-zzzz-zzzz-12345678abcd/aaaa.txt


## 参考

* [AWS公式](https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/id_roles_providers_oidc_user-id.html)
* [Cognito のIDプールでS3のユーザー毎フォルダにアクセスしてみる](https://qiita.com/silverbox/items/7a7ef64401e15f62ee52)
* [[素朴な手順]CognitoでIdentityID別にS3バケットへのアクセス許可をつけてみます](https://dev.classmethod.jp/articles/cognito-trigger-allow-access-per-identity-id/)
Web開発のローカル開発環境をEC2にしたらチームが幸せになった話

# 困ってたこと

弊社では人の入れ替わりも激しく、開発委託も始まり出したことで "開発環境の構築" の負荷が上がっており、その解決として、開発環境の仮想化のために Vagrant + Dockerを利用していたのですが、解消しきれず下記のような問題が上がっていました。

- Windows/macごとの環境構築手順の作成
- 環境依存による不具合の発生（M1 macでvagrantが動かないなど）
- 環境構築手順の指導


...やってられるか！！( 'д'⊂彡☆))Д´) ﾊﾟｰﾝ

となって、クラウドインフラ上に開発環境をおけば、コピーするだけで開発環境渡せるし全部解消するやんけ！となり、その時にチームではAWSを利用していたため、AWSのEC2で作ろうとなりました。

結論としては、開発環境をWeb上に持っていくことで当初想定していたよりも色々とメリットが多く、デメリットが少ないとなりました。もう手元の環境での開発にはもどれんっす

# EC2で開発するようになって変わったこと

EC2を立てて、そこにSSHで接続しながら開発することで、上記で書いた問題点はそれぞれ解決したのですが、予想外の副次的なメリットや少しの不都合もありました。

### [メリットだったこと]
- 新規環境構築が爆速（AMIコピーして一部の認証情報書き換えるだけ）
- 作業に困ったメンバーなどが発生した際に、他のメンバーが環境に直接入ってフォローできる
- 手元のPCの負荷がない
- 手元の開発環境に入れないといけない機密情報を最小限にできる
- PCがクラッシュしても安心

### [デメリットだったこと]
- オフライン開発できない（今時ほぼないと思うけど、ネットが不安定だとつらい）
- 一部のツールが使えない ※


※　詳細は後述しますが、SSH接続やポート指定して利用するツール以外で直接ディレクトリを参照するようなツールだと利用できないものがあります。

# どんな使い方をしているのか？

大まかにはソースコード管理でGit、ミドルウェアは Docker で起動する構成にしています。
自分の環境では Ruby on Rails　を利用することが多いのですが、VScode の Remote Development を利用してEC2上のコードを直接編集して、ブラウザなどのアクセスも VScode にてポートフォワーディングを行なってローカルポートと繋げることでWeb画面やDBを手元のツールから接続して利用しています。

参考までに上記の環境に手元のPCから接続して使用しているツールを列挙しておきます。

- VScode: エディターとしての利用とポートフォワーディングで利用
- Sequel Ace: ポート指定でDBに接続するクライアントツール
- ブラウザ： VScodeで接続したポートにlocalhostで接続して動作確認など行う。

mac上で開発していた際には、SourceTreeでGitの操作をしていましたが、こちらはsshで接続した先のディレクトリで利用する方法がわからず... VScodeのGit操作を利用するかコマンドラインから利用するようにしています。
必須の開発ツールがある場合には環境を作り込む前に接続して利用できるか確認するとよさそうです。


# 最後に

上記の環境を立てるまでmacを用いて開発をしていましたが、正直違和感なく開発できるなという感触です。
実際に使ってみる時にはWeb上に公開された環境になるのでIPアドレス制限など接続制限の設定も忘れずに...
【新機能】Copilot in Power Apps（GPTベースAI機能）

昨日Power AppsにもGPTベースのAI機能「Copilot」が搭載されることが発表されました！
今後はこのCopilot（副操縦士）を我々キャプテンがどう扱っていくか、が大事になってきますね。

今回発表された機能についてご紹介します。

# 今まで
実はPower Appsには2021年に自然言語からPower Fxを生成するGPTベースの機能を初めて導入して以来、以下のような機能が実装されてきました。
- アップロードされた画像をもとにアプリを生成
- 事例をもとにデータを整形
- 修正の提案

# これから
そして今回、アプリケーション開発の最初のステップにGPTの機能を導入します。
開発者は、Power AppsのCopilotとの自然言語による会話を通じて、アプリを構築することができるようになります。

# 今回紹介された３機能

## アプリ作成
Copliotに「こういうアプリがほしい」と話しかけると、そのアプリを画面だけでなく、テーブルとサンプルデータ（これ地味にうれしい）、バックエンドのロジックまで作ってくれます。
あとは私達が確認を行って、必要に応じて修正するだけです。

### 実際の画面
「こういうアプリ作って」とホーム画面で話しかけます。
以下の画面では「現場点検の詳細アプリを作成して」と書いてます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2883014/821c42b2-24b3-d2e9-c62d-fe5e21f6203f.png)

テーブルを作ってくれるので
「列を追加して」「サンプルデータ入れて」などと右のチャットで話しかけると、自動で列やサンプルデータの作成を行ってくれます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2883014/6f75fd5b-0cec-0f87-04f5-4dad56ab773a.png)

少し待つと、アプリの編集画面に表示されるのはある程度形ができているアプリです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2883014/8234deed-80d2-3e88-4511-b9570f390f5e.png)

## データ系
ユーザーは、実行中のアプリに直接組み込まれたAIアシスタントの助けを借りて、アプリ内のデータに関するインサイトを会話形式で得ることができます。

イメージつきづらいと思うので具体例を挙げますが、
例えば、機器検査アプリで、検査関連のデータを扱う際には以下のような問いかけをして、その結果を得ることができます。
「検査が失敗する最も一般的な理由は何ですか？」
「その種類の問題で最も活発な検査員は誰ですか？」
「最も頻繁に検査される機器はどれですか？」

### 実際の画面
以下の例だと
「最近、どの現場を点検されましたか？」と聞くと、
「最近変更した検査現場は、Contoso LtdとNorth Tradersです。」と返信がきています。
データ分析の新しい形ですね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2883014/1eac9f04-b44a-dd6c-3f37-b10e6e80b192.png)

## Power Appsの標準コンポーネントにチャットボットが追加
Power Virtual Agentsチャットボットが、今回、Power Apps側でコンポーネントとして登場し、簡単にアプリにチャットボットを埋め込むことができるようになりました。

今までは、標準でPower AppsのアプリにPower Virtual Agentsで作ったチャットボットを埋め込むことができなかったのですが、Power Virtual Agentsも会話ブースターや自然言語ボット構築などパワーアップしたことを機に、アプリ側でも簡単に使えるようになりました。

### 実際の画面
コンポーネントの中に「チャットボット」があり、これをクリックすると、、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2883014/2ea6776b-6dd3-f304-f739-2b4fc6dcad72.png)

簡単にチャットボットが埋め込めます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2883014/fecd364b-6506-5c0c-7995-d4ebefbde307.png)



# まとめ
どうでしたでしょうか。
Power Appsもどんどん進化していきますね。
Power Apps Copilotだけではなく、最近続々と発表されるAIについて思うことですが、今までは我々がコンピュータ語を覚えて会話（コーディング）してきましたが、コンピュータのほうが我々の言語を覚えてくれてるんですね。
これからは本当に**ノーコード**になっていきますね。

#### 参考文献
今回、以下の記事を参考にしております。

https://powerapps.microsoft.com/ja-jp/blog/announcing-a-next-generation-ai-copilot-in-microsoft-power-apps-that-will-transform-low-code-development/
【コピペでOK】Markdownテンプレート

#### はじめに
記事を書く際に1から書くのが面倒、記事を投稿してみたいけど抵抗がある、Markdownの書き方が分からない方のためにコピペで中身だけ書けば作れるテンプレートを用意しました。
ぜひ、コピペでご活用ください。
自分用でもあることをご理解お願いいたします。
必要に応じて、追記や除去、バッククォートの調整をしてください。
投稿の際にメモ等を消してください。

## テンプレート

```
## はじめに（見出し）
文章を記入～

メモ
**太字**　アスタリスク２つで囲むと太字にできます。

下記のように先頭にアスタリスクを付けることで箇条書きできます。
* リスト１
* リスト２
* リスト３

### システム要件　（見出し #の数を増やすことで文字サイズを小さくできます）
文章を記入～
必要に応じて見出しを書き換え

メモ
下記のようにリストと太字を合わせることもできます。
* **リスト１**
* リスト２
* **リスト３**

写真を張りたい、絵文字を使いたい場合はアイコンから可能

## システム構成　（見出し）
文章を記入～

## 解説　（見出し）
コードの説明等を記入。
`(バッククォート)３つで囲むことでコードを挿入できます。
コピペにするために「」をつけています。本書きでは外してください。

「```言語名:ファイル名.拡張子
コードを記入
```」

「```Python:python.py
# Pythonの例
a = input()
print(a)
```」
コードの説明

「```Java:Main.java
//Javaの例
import java.util.Scanner;

public class Main {
  public static void main(String[] args) {
    Scanner input = new Scanner(System.in);
    String s = input.next();
      System.out.println(s);
    input.close();
    }
}
```」
コードの説明

リンクの挿入の仕方
[リンク先のタイトル等を記入](ここにURLをコピペ)

## まとめ　（見出し）
文章を記入～

## 参考　（見出し）
文章を記入～

参考にさせて頂いたリンク先等の記載
[参考１](ここにURLをコピペ)
[参考２](ここにURLをコピペ)
[参考３](ここにURLをコピペ)
```

参考、活用くださると幸いです。
ありがとうございました！

**参考**
[Qiita Markdown 書き方 まとめ](https://qiita.com/shizuma/items/8616bbe3ebe8ab0b6ca1)
GCP_仮想マシン管理について（メモ）

# GCPの仮想マシン管理について
## ●単一の仮想マシン　インスタンスの管理
単一インスタンスとはそれだけで作成されたインスタンスのことです、インスタンス　グループやほかの種類のクラスタに含まれていないインスタンスです。

インスタンスを操作する方法は三つあります。  
　　　①Cloud Console　 ⇒　見えるかで操作  
　　　②Cloud　SDK　　　 ⇒　ローカル上からコマンドで操作  
　　　③Cloud　Shell　　 ⇒　Cloud上でコマンドで操作  
### インスタンスの起動、停止、再起動、削除  
   * インスタンスが停止している時には、コンピューティングリソースが消費されいないため、課金されることはありません。  
   * 仮想マシンが再起動すると、メモリの内容が失われます。永続ディスクまたはCloud　Stoargeには保存できます。  
   * GPUをインスタンスに追加する  
   * スナップショットの作業はできる  
     * スナップショットは永続ディスクにあるデータのコピーです。スナップショットを使うと、データを復元できます。
     * 最初スナップショットを作成する時、GCPは永続ディスクにデータを完全のコピー を作成する。次回そのスナップショットを作成する時、差分のみをコピーする
     * スナップショットの作業をすることには、Compute　Stoarge　Adminのロールが割り当てられる必要があります。
   * イメージでの作業  
     * ディスク、イメージ、スナップショットを使用して、イメージを作成できます。
## ●インスタンスグループの管理
   * インスタンスグループに適用されるすべてのgcloudまたはコンソールコマンドはインスタンスグループのすべてのメンバーに適用されます。
   * Googleは、マネージドと非マネージドという２種類のインスタンスグループを提供しています。
   * マネージドグループでは、これらの仮想マシンは同じインスタンステンプレートを使用して作成される。グループ内のインスタンス数を自動的に調整できます、また、負荷分散と併用することで、インスタンスグループの全体負荷を分散できます。
   * 非マネージドグループでは、異なる仮想マシン内にある異なる構成に対して、グループとして、作業する必要時のみ使用する。
   * インスタンスグループを作成するには、まず、インスタンステンプレートを作成する必要があります。
  　　```gcloud compute instance-templates create INSTANCE-TEMPLATE-NAME```
   * マネージド　インスタンスグループでは、負荷分散のほかに、自動スケーリングも 構成することができます。自動スケーリング ポリシーを設定して、ＣＰＵ使用率、モニタリングメトリクス、負荷分散能力、キューベースのワークロードに基づく、インスタンスを追加または削除します。
【シェル】バッチとして古いファイルを定期的に自動で削除

## 背景
とあるシステムを運用していて、最後まで処理が終わったら作成したファイルを削除というのをやっていたが、処理が複雑なので消えていないファイルがちらほら出てきていた。まあバグということになる。
いちいち処理ごとに削除するのをやめて、定期的に作成からある程度時間が経ってるファイルは全部消す方針にした。そっちのほうがバグもないしラク。

## ファイルが作成されてから1日経っているファイルは全て削除

```
dir_path="ディレクトリのパス"
# 指定したディレクトリ内のファイル一覧を取得し、ループで処理する
for file in "$dir_path"/*
do
  # ファイルの作成日時を取得し、1日前かどうかをチェックする
  if [ $(find "$file" -type f -mtime +0 | wc -l) -ne 0 ]; then
    # 1日経過している場合は削除する
    rm "$file"
  fi
done
```
あとは、クーロンに設定して1日に1時間に1回とかこのシェルを実行とかしちゃえばいい。
Microsoft Teams上でAWS Chatbotを作成する方法

# 注意事項
本記事は、以下のURLをChatGPTに学習させ作成した手順です。
https://aws.amazon.com/about-aws/whats-new/2023/03/aws-chatbot-available-microsoft-teams/
実際に動作検証をしたわけではありませんので、ご注意ください。


# 手順
1. **AWS Chatbot設定**:
  まず、AWS Management Consoleにログインしてください。 検索バーで「AWS Chatbot」を検索し、サービスページにアクセスします。

2. **クライアントを追加**:
  AWS Chatbotダッシュボードで、「クライアントを設定する」をクリックし、Microsoft Teamsを選択します。

3. **Microsoft Teamsアプリのインストール**:
  Microsoft Teamsのアプリストアで「AWS Chatbot」を検索し、アプリをインストールします。インストール後、チームやチャネルに追加してください。

4. **設定ウィザードを使用**:
  Microsoft TeamsでAWS Chatbotを開き、設定ウィザードに従って操作を進めます。このウィザードでは、AWSアカウントとの接続、IAMロールの作成、通知設定などが行われます。手順に従って設定を完了してください。

5. **イベント通知を設定**:
  AWS Chatbotでイベント通知を受信したいサービス（例：Amazon SNS, AWS CloudWatch, AWS CodeStarなど）を選択し、通知設定を行ってください。これにより、選択したサービスからの通知がMicrosoft Teams上のAWS Chatbotに送信されます。

6. **コマンドを使用してAWSリソースと対話**:
  Microsoft Teams上のAWS Chatbotで、AWS CLIやAWS SDKと同様のコマンドを使用してAWSリソースと対話できます。たとえば、「@AWS Chatbot describe-instances」のようなコマンドでEC2インスタンスの情報を取得できます。


# 免責事項
本記事は、一般的な情報提供を目的として作成されており、特定の状況に適用されることを保証するものではありません。本記事の情報は、公開日現在のものであり、予告なく変更されることがあります。記事内の情報やソースコードは、利用者の責任において使用されるものとします。本記事の情報やソースコードを利用することにより生じたいかなる損害についても、筆者および関連組織は一切の責任を負いません。

また、本記事で紹介されている製品やサービスに関連する商標、著作権、特許権等は、各権利保有者に帰属します。本記事は、権利保有者との契約関係や、その他の法的関係により権利が制限される場合があります。したがって、本記事の情報を利用する前に、権利保有者との契約内容や適用される法律を確認することをお勧めします。

利用者は、本記事の情報やソースコードを利用することにより、本免責事項に同意したものとみなされます。本免責事項に同意できない場合は、本記事の情報やソースコードを利用しないでください。
Xcode 14.2でコンパイルエラーがすぐ消えてしまう現象について

# 背景
- Xcode14.2で開発を行っていると、ビルドエラーが表示された後、数秒で表示されていたはずのビルドエラー表示が見えなくなってしまう現象が発生し困っています。
- ビルドエラーを確認したい場合は、２，３回ビルドし直さないとビルドエラー内容を表示してくれません。

## 事象の画像
`ビルド直後に表示されるビルドエラー`
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245300/95456122-5bba-61e8-24c2-33a7d1be46f7.png)

`ビルドエラー表示から数秒後`
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245300/c2ca8769-b0b0-ccc9-b77f-64bc0d6260df.png)

## 試したこと
- 以下試しましたが、全てだめでした。DerivedDataの削除何回かのビルドでは改善されたように見えましたが、どこかのタイミングで再発してしまいます。
    - DerivedDataの削除
        - `rm -rf ~/Library/Developer/Xcode/DerivedData`
    - キャッシュの削除
        - `rm -rf $HOME/Library/Caches/com.apple.dt.Xcode/`
    - Clean Build　Folder
    - Xcodeの再起動
    - PC再起動
    - Storageから「プロジェクトビルドデータとインデックス」の削除

### Storageから「プロジェクトビルドデータとインデックス」の削除→だめだった
![スクリーンショット 2023-03-17 16.44.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245300/e4aca86f-ec31-f6f7-c33b-a40a08653e9c.png)
![スクリーンショット 2023-03-17 16.44.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245300/0b8e8ca8-f4c8-75d2-2584-ed09814c9543.png)


## 調査
他にも同じ現象で発生している人がいないか調べたところ、Developer Forumsで投稿がありました。
どうやら2022年１１月頃から同じ事象が発生している方がいるようでした。
[XCode 14 compile errors immediately disappear or do not appear at all](https://developer.apple.com/forums/thread/715103)

一応対応策を書いてくれている方もいるようですが、執筆時点（2023.03.17）では未解決のようです。
最終的にはAppleのバグ修正待ちかなぁ・・・。

進展あれば更新します。

## 情報追記（2023年3月28日）
- コメントで下記記事を試したところ解決したとの情報を頂いたので、試してみました。情報提供ありがとうございます！
私の場合は解決には至りませんでした。
ただ、解消の糸口になるパターンも有るかと思いますので、試してみることをおすすめします。
[Xcodeにコンパイルエラーが表示されないときの対処法](https://qiita.com/fujimina/items/49d1630e01610abdf22e)

- ちなみに試しに新規プロジェクトを立ち上げて現象が再現されるかどうか試したところ、今回の現象は再現されませんでした。
既存プロジェクトにおいてCocoaPodsやXcodeプロジェクト設定など、特定の何かが原因となっている可能性はありそうです。

- [Xcode 14.3 RC 2 (14E222b) March 27, 2023 リリースノート Known Issues](https://developer.apple.com/documentation/xcode-release-notes/xcode-14_3-release-notes#Known-Issues:~:text=%E3%81%97%E3%81%9F%E3%80%82(102896200)-,%E6%97%A2%E7%9F%A5%E3%81%AE%E5%95%8F%E9%A1%8C%E7%82%B9,-%E3%83%91%E3%83%83%E3%82%B1%E3%83%BC%E3%82%B8%E3%81%AE%E4%BE%9D%E5%AD%98)
を見ていましたが、似たような現象のようなそうでないような...。
> ビルド前のスキーム アクション (パッケージ プラグインのコンパイルなど) でエラーが発生した場合、Xcode のワークスペース ウィンドウの上部にあるステータス メッセージが更新されないことがあります。これにより、以前のステータスが表示されたままになり、以前のステータスが「Build Succeeded」だった場合に混乱が生じる可能性があります。(104306342)

## 対処療法
- `Show live issues`をOFFにすればエラーがすぐ消えることはなくなります。
    - Xcodeのメニュー > Settings... > General > Issues > `Show live issues`のチェックボックスを外す。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245300/2e4b1971-aa5c-7e4a-e7bd-318ceed3d121.png)
    - 自動でissues検知しなくなるので、ビルドエラーなどがそのまま残ってくれます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/245300/a5cd3190-44a8-68ee-db2a-5926dab8216a.png)
次善解: 難病患者（工学博士）による医療従事者へ第2講 確率　安全(92)

難病、疫学、感染症など複雑な事象では、最適解を求めることは難しい。　
他の条件が変わらなければ、最適解は存在するかもしれない。　
社会現象、生命現象は、毎日変化しており、ある瞬間の最適解は、次の瞬間に最適解でなくなるかもしれない。　

最適制御を維持しつづけるのは、エネルギー、費用（投資、保守）、寿命などから不可能なことがあるかもしれない。　

制御の世界を、微分方程式で記述することがあります。物理現象でも、化学現象でも、生命現象でも、社会現象でも微分方程式で記述することがあります。課題は、時定数と誤差です。　

時定数とは、ある現象があってから、影響がでるまでの時間です。　
誤差は、それぞれの値の計測方法の違いから、生じるものです。やっかいなのは、測定の時間が同じでない場合を、どのように扱うとよいかです。違う時間に測ったものを、同じ時間に測ったと仮定して論を進めると、真逆の結論に達することがあるかもしれません。

微分方程式で記述すると、一般解を求めることができる場合があります。
一般解とは別の特異解が存在する場合もあります。
特異解は
最適解が存在しない
# 参考資料　
難病患者（工学博士）による医療系学生・医療従事者への３２講（０）医工連携
https://qiita.com/kaizen_nagoya/items/84bbba518dd9ca0aad7c

# Reference
Ethernet 記事一覧　Ethernet(0)
https://qiita.com/kaizen_nagoya/items/88d35e99f74aefc98794

Wireshark 一覧 wireshark(0)、Ethernet(48) 
https://qiita.com/kaizen_nagoya/items/fbed841f61875c4731d0

線網（Wi-Fi）空中線(antenna)(0) 記事一覧(118/300目標)
https://qiita.com/kaizen_nagoya/items/5e5464ac2b24bd4cd001

一覧の一覧( The directory of directories of mine.) Qiita(100)
https://qiita.com/kaizen_nagoya/items/7eb0e006543886138f39

仮説（0）一覧（目標100現在40）
https://qiita.com/kaizen_nagoya/items/f000506fe1837b3590df

安全（0）安全工学シンポジウムに向けて: 21
https://qiita.com/kaizen_nagoya/items/c5d78f3def8195cb2409

プログラマが知っていると良い「公序良俗」
https://qiita.com/kaizen_nagoya/items/9fe7c0dfac2fbd77a945

小川清最終講義、小川清最終講義（再）計画, Ethernet(100) 英語(100) 安全(100)
https://qiita.com/kaizen_nagoya/items/e2df642e3951e35e6a53

＜この記事は個人の過去の経験に基づく個人の感想です。現在所属する組織、業務とは関係がありません。＞
This article is an individual impression based on the individual's experience. It has nothing to do with the organization or business to which I currently belong.
# 文書履歴(document history)
ver. 0.01 初稿 　20230317
### 最後までおよみいただきありがとうございました。
いいね　💚、フォローをお願いします。
####  Thank you very much for reading to the last sentence.
Please press the like icon 💚　and follow me for your happy life.