OmniAICreator/Qiita-1.07M huggingface dataset:
Citusを使うときの制約や気になったことメモ

CosmosDB for PostgreSQLを使用する場合、そのもととなっているCitusと制約事項は同じなのではと思い、Citusの制約事項を調べた時のメモ。Citusの最新バージョンは12だが、CosmosDB for PostgreSQLは11.3で動いているらしいので11.3で調べている。。。

使用するかもしれない用途は、マルチテナントで提供するサービスであるため、distribution columnをキーにしていること...や、単一シャード内でのみ有効...は通常用途では問題とならないが、サービス運用/管理時にシャードをまたいで処理を行いたいようなときに課題がありそうと感じた。

### [Creating and Modifying Distributed Objects (DDL)](https://docs.citusdata.com/en/v11.3/develop/reference_ddl.html)

* [distribution columnのデータ型は変更できない](https://docs.citusdata.com/en/v11.3/develop/reference_ddl.html#adding-modifying-columns)
一時的にdistribution columnを変更した後で必要なデータ型変更を行い、distribution columnを変更することで回避可能

* [ワーカーノードをまたいだ一意性制約/外部参照制約は使えない](https://docs.citusdata.com/en/v11.3/develop/reference_ddl.html#adding-removing-constraints)
同一ワーカーノード内で制約を作成する場合、distribution columnをキーに含めること
外部参照制約を設定できるのは下記
  - 2つのローカルテーブルの間
  - 2つの参照テーブルの間
  - ローカルテーブルと参照テーブルの間　ただし、参照テーブルからローカルテーブルを参照する場合、ON DELETE(UPDATE) CASCADEは使用できない
  - 同一シャードにある分散テーブルの間　ただしdistribution columnをキーに含んでいること
  - 分散テーブルが参照テーブルを参照する場合　逆に参照テーブルから分散テーブルを参照することはできない

### [Ingesting, Modifying Data (DML)](https://docs.citusdata.com/en/v11.3/develop/reference_dml.html#ingesting-modifying-data-dml)
* [デフォルトの設定では、複数のシャードにまたがる更新/削除は、1PhaseCommitが使用される](https://docs.citusdata.com/en/v11.3/develop/reference_dml.html#updates-and-deletion)
オプション設定により、2PhaseCommitに変更できる
* 単一シャードに対する操作の場合は、SELECT ... FOR UPDATEが使用できる

### [Querying Distributed Tables (SQL)](https://docs.citusdata.com/en/v11.3/develop/reference_sql.html#querying-distributed-tables-sql)
* 集計がどこで行われるかが性能を左右する(上から性能が良い)
  - distribution columnでグルーピングしている場合は単一ワーカーノードで処理が完結する
  - avg min(他多数)などの集計の場合は各ワーカーでシャード内の集計を実施、コーディネーターノードに送付する。コーディネーターノードはそれらから最終的な集計結果を算出する
  - 上記以外の場合は、各ワーカーで集計条件に該当する行を抽出し、コーディネーターノードに送付する。コーディネータノードはそれらを使用して集計を実施する
* [マテリアライズドビューはローカルテーブルとしてコーディネーターノードに格納される](https://docs.citusdata.com/en/v11.3/develop/reference_sql.html#views-on-distributed-tables)

### [SQL Support and Workarounds](https://docs.citusdata.com/en/v11.3/develop/reference_workarounds.html#sql-support-and-workarounds)
* SELECT ... FOR UPDATEは単一シャードでのみ有効
* TABLESAMPLEは単一シャードでのみ有効
* 相関サブクエリは結合条件のカラムががdistribution columnに含まれている場合のみサポートされる
* 分散テーブルの外部結合は結合条件がdistribution columnに含まれている場合のみサポートされる
* WITH RECURSIVEは単一シャードでのみ有効
* GROUPING SETSは単一シャードでのみ有効
* MERGEは下記の場合のみサポートされる

| source | target | 備考 |
|-----------|------------|------------|
| ローカルテーブル | ローカルテーブル |  |
| 分散テーブル | 分散テーブル | 同一シャード内のみ |
【公開】Discord のリアクションに反応し通知する Bot 「リアクション通知くん」

## はじめに
以前、Discord の返信や応答などに使われるリアクションに気づかないことがあり不便なため、リアクションに反応して通知してくれる Bot を作りました。ユーザがリアクションすると Bot がメッセージ主にメンションする流れになっています。動作に関しては以下記事を参考にして下さい。この度、この Bot を公開させて頂くことにしました（需要があるかは知りませんが…）。ぜひ使ってみて下さい。
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1115291/54a2de5e-a96a-3964-c84e-80a5daf9b0b7.png)

https://qiita.com/Pumila/items/cf447c24538e13994a38

以下、ソースコードになります。

https://github.com/Pumi1a/ReactionDetect

2025/03/11追記
Botの新規追加ができないと言われる前に先手を打っておきます。Botの使用数が91になりました。お使い頂きまずは感謝です！100の大台が見えてきたわけですが、ものすごくめんどうくさいことが・・・なんか利用ポリシー作らないと制限かかるらしいんですよね、、、
そのうち暇なときにでもやっておきます。~~データベースも追加はすぐできるんですが、Botの再起動めったにないんでもうどうでもいいんですよね。~~ ということで先手は打ったので使えなくても文句言わないで下さい。では！


## 注意点
エラー報告は開発者の [Twitter](https://twitter.com/Pumi1a) か [github](https://github.com/Pumi1a/ReactionDetect) までお知らせ下さい。
なお、利用しているホスティングサービスは "Railway" になります。性能はメモリが 8GB、CPU が 8 コアになります。そこまで負荷のかかる Bot ではないと思いますが、もしかしたら安定しなくなるかもしれません。"Railway" については以下記事にまとめています。

https://qiita.com/Pumila/items/29f26fb349d5592046ae

# 導入方法
**注意：Bot の導入はサーバの管理者権限を持っている方しか出来ません。**
[こちら](https://discord.com/api/oauth2/authorize?client_id=1063085355726798869&permissions=2048&scope=bot%20applications.commands)からクリックしてログイン後、導入したいサーバを選択して[はい]、続いて認証を押下して下さい。ロボットかどうかの確認画面でチェックして導入完了です。
必要なくなったら、サーバ負荷軽減のために追放して頂けると助かります。

## 使い方
### 各スラッシュコマンドの説明
Bot の各スラッシュコマンドについて説明していきます。スラッシュコマンド実行時にエラーが出たときはもう一度コマンドを実行してみて下さい。

#### 通知先のチャンネルを変更する
通知先のチャンネルを変更することができます。デフォルトはシステムメッセージのチャンネルになっています。
1. "/" を入力して、リアクション通知くんのアイコンをクリックし、コマンド一覧から、`/set_channel` を選択して下さい。
2. 通知をさせたいチャンネル名を入力し、実行して下さい。候補として挙がっているものから選択しても構いません。
3. Bot に投稿権限がないチャンネル、もしくはテキストチャンネルではないチャンネルを選択した場合、以下のような警告が出ます。`Warning: No permission to post in the channel {new_channel.name}.`, `{new_channel.name} is not a text channel.`。
3. Bot から `Set channel to {new_channel_name}.` とメッセージが来ます。
![キャプチャ.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1115291/08c532b7-ca08-59f8-18f7-7aaec400dd19.png)

## 最後に
Discord のリアクションに反応し通知する Bot を作ったはいいものの、公開しようと思いつつ色々と忙しくて、公開できませんでした。ちょうど機会があったのでこの度公開させて頂きました。ぜひ使ってみて下さい。

ご意見、ご感想、ご要望、エラー報告などは[Twitter](https://twitter.com/Pumi1a) まで。
【RuboCop】commitした際にRuboCopを実行する方法【Lefthook】

## gemのインストール
以下のコマンドを実行して`Lefthook`をインストールします。
```:ターミナル
$ gem install lefthook
```

## Lefthookの設定
Lefthookの設定をします。
`lefthook.yml`を作成し、以下のように記述します。
```lefthook.yml
pre-commit:
  parallel: true
  commands:
    rubocop:
      files: git diff --name-only --staged
      glob: "*.rb"
      run: rubocop --force-exclusion {files}
```

## 動作確認
以下のコマンドを実行し、正常に動作するか確認します。
```:ターミナル
＄ lefthook install && lefthook run pre-commit
```
Veeam V12の誰も気づかないようなUpdate！！！

# 僕とVeeamの出会い

エンジニア2年生の時、とある公共系の案件(かなりキツかった...)と同時並行で、VMC(VMware Cloud on AWS)環境にバックアップシステムとしてVeeamを構築して、試験及び手順書の作成、お客さんに引き渡しをするといった案件がありました。

その経緯は、社内で**Veeamer**(Veeamの基本設計や構築ができ、頼れる人)を育成したいといったことをグループ内で言っていたので、僕が手を挙げました。
その当時積極性がなかった僕がなぜ立候補したかというと、**何かの技術では社内でTOPの経験と知識を身に着けたいと思っていたからです。**
(それまでAWSやオンプレといろいろ経験を積ませてもらったものの、どれかに飛びぬけているわけでもありませんでした。)

最近だと、同じグループ内や、別拠点のグループから構築時の相談をされたりと、少し頼られてきてうれしい限りです。
あの時手を挙げてよかった！！！

↓直近のVeeamイベント、参加して社内に資料共有しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3494465/f29c7103-057d-0f40-dff5-e5af9427767f.png)



# 地味に驚いたV12からの機能！！！

さて、Veeam V12は2023年4月に発表されました。
目新しい機能といえば、**多要素認証(MFA)**や**S3への直バックアップ**です。
(V11まではSOBR(Scale-out Backup Repository)といった機能を使用しないとS3でバックアップデータを保管することはできませんでした)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3494465/79b9fce2-fa48-9700-3050-282cc66877eb.png)


さて、今回地味にびっくりしたのは、ホスト名の変更に関わるものです。
実は、Veeamさん、**BackupServerのインストール後にホスト名を変更すると、コンソールに接続できなくなるといった問題がありました。**
これは[Veeamのkb](https://www.veeam.com/kb2350)でも対応策が記載されてます。
リリースされてかなり時間が空いてしまいましたが、先日漸く、Veeam V12の検証環境を立てて、いろいろ触ってみました。

インストールした後に気付きます
「**あっ、検証用仮想マシンのホスト名変えてないや...確か変更後の作業しないとコンソールに接続できないんだよな...**」と思いながらホスト名変更
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3494465/31fedd90-0f8d-ccb3-928c-73069960e001.png)

続いて再起動
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3494465/a6648dee-ddad-5ef1-56e0-4c7f21cdd461.png)

再起動後にホスト名変更確認

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3494465/07c0c894-edf1-d0a0-905c-bee09c1e7c29.png)
再起動後、Veeamはサービスが立ち上がるのが数分かかるので気長にまってコンソールに接続してみると...
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3494465/80014759-1835-16e8-336e-b6df66dff68e.png)

「あれ！？はいれた！！！」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3494465/75f7672c-e1f6-0051-e06c-652275715ddb.png)
なんとVeeamの構成データベース側を変更しなくとも、は入れてしましました！
ちいさい修正ですが、**個人的にはうれしいアップデート**でした！

# さいごに
さて、今回は僕のVeeamとの出会いといったポエムを書いてしまいましたが、ソフトウェアとしてVeeamは好きです。(いろいろ優秀だし、、、)
最近はVeeamでの移行もやっていて、ますます関わることが増えています。
(お客さんにVeeamを提案するような機会もありました。)
これ以外にもVeeamについて記事を書いていくので、よろしくお願いします！
それではまたどこかで。
Big Object

## はじめに
実際に使用したことはないものの、要件定義の段階で話に挙がったBig Objectについて、今回はまとめたいと思います。

## Big Objectとは
Big Objectとは、Salesforce上で10億件以上のデータを保存、管理することができる機能のこと（通常のオブジェクトとは異なるストレージに保存されている）。
一般的なオブジェクトと同様に、①標準Big Object（項目監査履歴など）と②カスタムBig Objectに大別される。

## Big Objectの使用用途
- 顧客の360度View
    - 顧客に関するすべてのデータ。
- 監査と追跡
    - ユーザのSalesforce利用状況の追跡。
- 履歴アーカイブ
    - データの履歴管理。

ざっくり言うと、1つのオブジェクトに大量のレコードが作成されるような環境で、一定時間経過したレコードをアーカイブとして保存するような用途に適している。

## Big Objectの制約事項
- 入力規則を使用することができない。
    - データの品質を担保する場合は、Apexクラスなどを用いる必要がある。
- 項目変更履歴を使用することができない。
- リストビューで表示することができない。
    - SalesforceのUI上に、レコード情報を表示することができないため、画面表示したい場合はVisualforceやLWCを使用する必要がある。
- Apexトリガを使用することができない
    - Big Object の作成/更新/削除を起点としたトリガを実装することができない。
- プロセスビルダー、フローでBig Objectのデータを扱うことができない。
- レポート、ダッシュボードでBig Objectのデータを表示することができない。

## カスタムBig Objectの作成手順
1. 「設定」メニューの「Big Object」から新規作成ボタンをクリックし、オブジェクト名とAPI名を入力する。
1. カスタム項目を作成する。
    1. 選択リスト、主従関係のリレーション項目、数式項目は作成することができない。
    1. Big Objectのサフィックスは「__b」になっていて、項目は「__c」となる。
1. インデックスを作成する。
    1. インデックスとは、データベース内のテーブルの行を高速に検索するためのデータ構造のこと。
    1. インデックスに使用する項目は入力必須にする必要がある。

## データの取得
Big ObjectへのアクセスにはSOQLクエリを使用する。1つは通常のSOQLで、もう1つは非同期SOQLである。
通常のSOQL文において、以下のルールが存在する。
- WHERE句はインデックスの位置順通りに指定する必要がある。
- WHERE句の最後以外は＝とする必要がある。
- !=、LIKE、NOT IN、EXCLUDES、INCLUDESを使用することができない。

非同期SOQLは処理時間に制限なく、大量データの集計に活用可能である。
Windows10で回復ドライブを再作成する

## 参考

https://www.kuronekofreedom.com/entry/2021/10/30/231758

システムドライブの増設のために回復ドライブを削除してパーティションを拡張したが、
回復ドライブをそのまま削除してしまったため、winrm.wimが残ってなかった

diskpartでset idでGUIDを指定する方法もうまくいかなかった

windowsのisoをダウンロードしてきて、中身を展開して無理やり該当ファイルを持ってくることで解決した
ALBをターゲットグループ無しで立てたい

## 前書き
先日、プロジェクトの作業でALBを作る機会がありました。ロードバランサーは、通常その先にあるターゲットへのトラフィックを分散させるために使用します。
しかし、今回はまだターゲットとなるリソースを作成しておらず、とりあえず疎通確認だけを先に済ませておきたい、という状況でした。
ターゲットグループ用のLambdaやEC2を暫定的に作成してもよかったのですが、ALBはターゲットを作らずとも固定値を返すことができるということは知っていたので、その方法を使おうと思い立ちました。
しかし、いざマネコンからALBを作成しようとしたら「you must select st least one target group」というエラーが表示され、ターゲットグループを選択せずにALBを作成することを許してもらえませんでした......
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2661124/d7ad89bd-1bb5-7134-c950-e91f3a2f7575.png)
（そういえばELBの画面ってなんで日本語で表示されないんですかね？）

## CloudFormationでターゲットグループを指定せずにALBを作成
そこで思いついた方法が、CloudFormationで何も設定されていない、いわば素の状態のALBを作成してしまおうという作戦です。

CloudFormationのType AWS::ElasticLoadBalancingV2::LoadBalancerを確認したところ、ターゲットグループを指定する箇所がなさそうでした。これはイケそう。

```yaml
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
Properties: 
  IpAddressType: String
  LoadBalancerAttributes: 
    - LoadBalancerAttribute
  Name: String
  Scheme: String
  SecurityGroups: 
    - String
  SubnetMappings: 
    - SubnetMapping
  Subnets: 
    - String
  Tags: 
    - Tag
  Type: String
```


https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-elasticloadbalancingv2-loadbalancer.html



実際に使用したテンプレートが以下です

```yaml
AWSTemplateFormatVersion: "2010-09-09"
Description: 
  ALB Create

Resources:
# ------------------------------------------------------------#
#  ALB
# ------------------------------------------------------------#
  MySecurityGroup:
    Type: 'AWS::EC2::SecurityGroup'
    Properties:
      GroupDescription: Security Group for qiita-test-alb
      GroupName: qiita-test-alb
      # めんどくさいのでマネコンから設定する
      # SecurityGroupIngress: 
      #   - 
      # VpcIdを入力
      VpcId: xxxxxxxxxx

  MyLoadBalancer:
    Type: 'AWS::ElasticLoadBalancingV2::LoadBalancer'
    Properties:
      Type: 'application'
      # Subnetsを入力
      Subnets:
        - xxxxxxxxxx
        - xxxxxxxxxx
      SecurityGroups:
        - !Ref MySecurityGroup
      Scheme: internet-facing
      Name: qiita-test-alb
```


作成完了！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2661124/3f6c8d4d-11da-9e78-23ac-ebc8c91345b3.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2661124/1e122634-5b4f-f793-62bf-926035600eff.png)

セキュリティグループはマネコンから設定するほうが楽そうだったので、マネコンから設定します。
今回は、自分のPCのIPアドレスからのアクセスのみを許可するインバウンドルールを作成しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2661124/0ed0f948-1207-70c2-2ff2-010810ceb768.png)

そして最後に、固定値を返すルールを設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2661124/5cb300eb-8523-b604-1685-c2e9023667c0.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2661124/a04e4beb-60b1-7c20-78f3-5509c79a596d.png)

アクセス成功！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2661124/cd6ff858-13dd-2bab-703e-6e83f4544208.png)



## まとめ
以前も記事に書いたのですが、AWSは意外とサービスによって仕様がバラバラです。

https://qiita.com/kisama2000/items/aae8d370733389d95537

ALBも固定値を返すだけのものが作成できるのであれば、マネコンからも作成させてくれればいいのに、と思いました。
マネコンはめちゃくちゃ便利ですが、なんでもできる完璧な仕様になっているわけではなく、あくまで使いやすくしてくれてるおまけ程度に考えるのがいいかもしれませんね。
Qiita CLI導入方法

# はじめに
本記事は以下のリポジトリ内容を実際にやってみてQiita CLIを導入するまでのメモとなります。

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

# 1. 事前準備
- Node.jsのインストール
    - [【Windows/Mac/Linux（Ubuntu）】Node.jsインストール方法](https://qiita.com/ryome/items/eec08b28aff294e8c3d6)

# 2. 開発環境

**使用技術とバージョン**

| 技術 | バージョン |
| --- | --- |
| Node.js | v18.12.1 |

※ バージョン18.0.0 以上が必要。

# 3. Qiita CLI インストール

- コマンド
```sh:コマンド
npm install @qiita/qiita-cli --save-dev
npx qiita version
```

- 実行例
```sh:実行例
>npm install @qiita/qiita-cli --save-dev

added 151 packages in 8s

43 packages are looking for funding
  run `npm fund` for details

>npx qiita version
0.6.0
```

:::note info
以下のコマンドは、npm（Node Package Manager）を使用して@qiita/qiita-cliというパッケージをインストールし、バージョンの確認をしています。

```sh:コマンド
npm install @qiita/qiita-cli --save-dev
npx qiita version
```

※ `--save-dev` オプションは、このパッケージを開発依存性としてプロジェクトに追加することを意味します。

:::

# 4. Qiita CLI セットアップ

- コマンド
```sh:コマンド
npx qiita init
```

- 実行例
```sh:実行例
>npx qiita init
設定ファイルを生成します。

  Creating C:\【path】\.github\workflows\publish.yml
     Created!

  Creating C:\【path】\.gitignore
     Created!

  Creating C:\【path】\qiita.config.json
     Created!

Success! ✨

次のステップ:

  1. トークンを作成してログインをしてください。
    npx qiita login

  2. 記事のプレビューができるようになります。
    npx qiita preview
```

:::note info
以下のコマンドは、Qiita CLI の初期セットアップを行います。

```sh:コマンド
npx qiita init
```

初期セットアップ後は以下のようなフォルダ構成になります。
```
C:.
│  .gitignore
│  qiita.config.json
│
└─.github
    └─workflows
            publish.yml
```

:::

# 5. Qiita CLI 使い方

## qiita login

- コマンド
```sh:コマンド
npx qiita login
```

- 実行例
```sh:実行例
>npx qiita login

以下のURLにアクセスしてトークンを発行してください。（「read_qiita」と「write_qiita」にチェックを入れてください）
  https://qiita.com/settings/tokens/new?read_qiita=1&write_qiita=1&description=qiita-cli

発行したトークンを入力: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Hi ryome!

ログインが完了しました 🎉
以下のコマンドを使って執筆を始めましょう！

🚀 コンテンツをブラウザでプレビューする
  npx qiita preview

🚀 新しい記事を追加する
  npx qiita new (記事のファイルのベース名)

🚀 記事を投稿、更新する
  npx qiita publish (記事のファイルのベース名)

💁 コマンドのヘルプを確認する
  npx qiita help
```

:::note info
以下のコマンドで、Qiita のアカウントと紐付けし、記事の取得や投稿、更新が行えるようになります。

```sh:コマンド
npx qiita login
```

※ 途中で以下のように発行したトークンを入力を求められるので、リンクからトークンを発行し入力します。

```
以下のURLにアクセスしてトークンを発行してください。（「read_qiita」と「write_qiita」にチェックを入れてください）
  https://qiita.com/settings/tokens/new?read_qiita=1&write_qiita=1&description=qiita-cli

発行したトークンを入力: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
```

![0001.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/449867/7918f97a-7b4d-6259-1fad-996aa1695b12.png)

※ `スコープ` は、 `read_qiita` と `write_qiita` にチェックを付けます。
:::

## npx qiita preview

- コマンド
```sh:コマンド
npx qiita preview
```

- 実行例
```sh:実行例
>npx qiita preview
Preview: http://localhost:8888
```

:::note info
以下のコマンドで、Qiita Preview(プレビュー画面)にアクセスすることが可能になります。

```sh:コマンド
npx qiita preview
```

![0002.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/449867/561032d0-3afe-50ee-ae64-454886dcf909.png)

※ プレビュー画面では、 `新規記事作成` や `画像アップロード` 、 `記事の確認` などができます。
※ プレビュー画面のデフォルトのURLは `http://localhost:8888`
:::

# GitHub

https://github.com/ryomeblog/ryome-qiita

# 参考文献

https://github.com/increments/qiita-cli
UiPathの面白い？アクティビティで遊ぶ～ランダムな日付アクティビティってなんかや？～

## はじめに
①本記事は、2023年7月開催の「UiPathブログ 発信チャレンジサマー」の22日目のブログです。
ブログの詳細、参加方法については以下のブログを参照ください。

https://note.com/shumpei_w/n/nd082bdf28853

②このブログ情報は、2023/7時点の情報です。
③UiPathはCommunity Edition、Versionは2023.6.1です。

## Testingアクティビティって？
ある日UiPath Studioをあさっていた筆者は、面白そうなアクティビティを発見。
Testingアクティビティ？なにそれ？
調べてみるとreiさんのブログに到着。見てみると、ランダムなテストデータの自動作成ができるとのこと。マジ？(実は見つけるまで知らなかった)

https://note.com/ss_uipath/n/n93b41f751b49

https://note.com/ss_uipath/n/n3fc44c864987

なので、早速Testingアクティビティのパッケージをインストールしてみました。ワクワク。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502614/39aabbd5-d851-cf4e-477e-6b1c302e6102.png)

## 「ランダムな日付」アクティビティって何？
その中で今回は「ランダムな日付」アクティビティで日時がランダムに出てくるようにしてみましょう！
「ランダムな日付」アクティビティは、指定した範囲の日付をランダムに出力することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502614/b54b27db-fa86-9332-d1f2-74836f28cb3a.png)
公式サイトは以下の通りです。

https://docs.uipath.com/ja/activities/other/latest/workflow/random-date

このアクティビティはプロパティが出てこないので、アクティビティに直接触って設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502614/c15ee5e4-f86e-a41d-9690-ebc4b3af645d.png)

まずは日時を設定してみましょう。
日付のところのカレンダーマークを押すとカレンダー表示が出てきますので、開始日付と終了日付をそれぞれ設定しちゃいましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502614/5850b261-e41d-efa8-daaf-fcc919157793.png)
時間は、0:00～24:00の24時間設定できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502614/9a7c6a75-2a9f-a53f-f77b-2fe369ba04da.png)
なお、手動にはなりますが1分単位も設定できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502614/e55fee30-dd26-c66f-3086-2533029938bc.png)

あと、出力はDateTime型変数になります。

## 使ってみよう

試しに2023年7月1日～7月31日までの日付を出してみましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502614/a482de22-4236-d135-ed2c-40f61c405314.png)

結果は...
1回やってみました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502614/6f4a7c1d-76da-541f-fd0e-22f0d8fe8c01.png)
2回目です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502614/df452e77-cf9c-84f6-8235-2e67d1f2456f.png)
3回目です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502614/37cf8472-62a8-84e8-5718-99abc8b46289.png)

おお、すごか～！

## じゃもちょっと遊びましょう
試しに5回繰り返して、2023年7月21日～7月31日の間の日時がランダムに出てくるか試してみましょう。
日時もString型で出せるようにメッセージボックスに出してみましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502614/94cd3dfa-388f-c2dc-b852-0fc4e64a63c6.png)

結果は...
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/502614/c61bf36b-2974-b7c9-257f-ef097e67c6ca.png)
おお、すごい！

## まとめ
本来はテスト実行の際に使用するアクティビティなのですが、このランダムな日付は実行日が決まっているロボットのテストにも設定日を設定するだけで動かせそうなので、テストで役立ちそうです。
ちょうど夏休み真っ只中なので、自由研究等でお子さんと試しに動かしてみるのもよいかもですね。
最後までお読みいただきありがとうございました。

## 参考URL
ランダムな日付

https://docs.uipath.com/ja/activities/other/latest/workflow/random-date

UiPathでランダムな値を生成するテストアクティビティを使ってみる

https://note.com/ss_uipath/n/n93b41f751b49

UiPathでのテスト自動化に欠かせない「検証」アクティビティを使いこなす

https://note.com/ss_uipath/n/n3fc44c864987
某プロフィールサイトより早いサイトをGitHub Pages縛りで作りたかった

## 概要

インターネット史上、最速のサイトとして名高い某男優のプロフィールサイトを超えるため、Lighthouseのスコア改善に取り組んだメモです。

私の経験としては、サイトの速度改善はおろか、フロントエンドもおぼつかないため間違いあればそっと教えてください。

## 成果物

ペラのHTMLに似たようなスタイルと背景画像を当てた。
サイトのデザイン的な要件としては割りと似た条件になったはず。

![スクリーンショット 2023-07-22 13.07.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/290859/a4483ca5-a8a1-74b3-ca49-2f9e5b664c9f.png)

## 成果物に対する速度改善

ここでは参考にしたサイトを上げていく。
各項目の詳しい説明はリンク先を参照願う。

### assetの遅延読み込み

https://qiita.com/rana_kualu/items/95a7adf8420ea2b9f657

### フォントのセルフホスト

https://tm23forest.com/contents/selfhosted-googlewebfonts-psi-okoraren

### 画像サイズを指定する

https://web.dev/i18n/ja/optimize-cls/

### faviconを入れる

https://stackoverflow.com/questions/8765274/does-favicon-404-affect-performance

### 画像をwebp形式にする

https://developers.google.com/speed/webp?hl=ja

## 計測

今回はネットワークや計測マシンの条件を揃えるため、lighthouse-metrics.comを使用する。
これを使用することで、異なるリージョンのLighthouse scoreを一気に計測できる

https://lighthouse-metrics.com/

### 某男優サイトの計測結果

URLを指定するとLight Houseでエラーとなるため、`/top.htm`が描画される速度を計測する。

![スクリーンショット 2023-07-22 13.05.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/290859/183f8141-64b8-3da0-8145-e963c5d74fd9.png)

早すぎ

### 成果物の計測結果

https://lighthouse-metrics.com/lighthouse/checks/d7e7cd12-d9ce-48e4-a68a-55cb8bb7caa4

![スクリーンショット 2023-07-22 16.39.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/290859/33c2e5f8-fdd8-a338-3b9f-e40f28a6df3e.png)

おせえ、、、

## 比較結果

自作のサイトは足元にも及びませんでした。

## 今後の展望

- self hostしたフォントファイルのcache-controlをなるべく長期間にしたい
    - GitHub Pagesは[cache-controlを変更できないの](https://github.com/orgs/community/discussions/11884)でホスティング先を変える必要があり、却下
- ロード時に一瞬レイアウト崩れしているのが気になる。
    - まあ非同期読み込み使いまくってるし、仕方なくね？
- 結局Web Fontを使っているのが問題だよなあ
    - 他で頑張っても全体の速度改善には繋がりにくい

## 結論 

- スコアにこだわるならWeb Fontは捨てる
- Light Houseのスコアにこだわりすぎ注意
    - 有名なサイトでもスコアが50切るサイトある、、、
        - さてどこだろうか
マージ済みのブランチだけを対象としてローカルのブランチを一括で削除する方法

プロジェクトを進める中で、利用しなくなったブランチがたまってしまうことはよくあります。

そこで、ブランチを1つ1つ手動で削除するのは手間がかかるため、マージ済みのブランチだけを対象としてローカルのブランチを一括で削除する方法を紹介します。

## コマンド実行

以下のコマンドを使用することで、マージ済みのブランチだけを対象としてローカルのブランチを一括で削除することができます。

```zsh
git branch | xargs git branch -d
```

このコマンドは、以下の手順で動作します。

1. `git branch --merged`: このコマンドは、現在のブランチがマージされたブランチの一覧を表示します。

2. `grep -v "\*"`: `grep`コマンドはテキストを検索するためのコマンドです。-vオプションは、指定したパターンに一致しない行を表示することを意味します。ここでは、アスタリスク（*）に一致しない行（現在のブランチを除く）を表示します。

3. `xargs -n 1 git branch -d`: `xargs`コマンドを使って、マージされた各ブランチに対して`git branch -d`を実行します。`-n 1`オプションは、1つずつの引数を使って`git branch -d`コマンドを実行することを意味します。これにより、アスタリスクがついた現在のブランチを削除するのを避けることができます。

## 補足

もしJetBrain製品（例: IntelliJ IDEA）を使用している場合は、[GitToolBox](https://plugins.jetbrains.com/plugin/7499-gittoolbox)というプラグインを導入することで、GUIを使って一括でブランチを削除する方法もあるので検討してみて下さい。
LXCで「rm -rf /*」やってみた in proxmox

作成日：2023年7月22日

**自分の中で**最凶コマンドと名高い`rm -rf /*`を実行するとどうなるのか、実際に試してみました。

# `rm -rf /*`とは
ざっくりと説明すると「OSのrootディレクトリ配下を再帰的かつ強制的に削除する」コマンドです。


## 今回の環境
proxmox内に作成したUbuntuのLXCで実行します。
```
OS:Ubuntu 22.04 LTS (GNU/Linux 5.15.83-1-pve x86_64)
```


## コマンド実行前のディレクトリ構成
treeコマンドでデフォルトのディレクトリ構成を確認すると、このようになっていました。22個もあるんですね。
![コマンド実行前のディレクトリ構成](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/327331/1bcb6481-db6e-125f-917a-db9c30b159f7.png)

## *を付けずに実行してみる
「危ないから本当にやるなら`--no-preserve-root`を付けなね！」と親切に警告を表示してくれます。確認しましたが、ディレクトリは何も消えていませんでした。
![*を付けずに実行した結果](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/327331/2476e4be-5989-7d4e-bec8-84df2f873e36.png)

## 実行してみる
次は`*`を付けて`rm -rf /*`を実行してみました。すると、以下のように`rm: cannot remoev`という行が大量に表示されました。
![最凶コマンド実行結果](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/327331/b6cbcc43-870f-5270-4435-18a1997ae65b.png)

暫くして処理が終わり、
もしかして思ったよりディレクトリは消えてないのでは？と思ったので`tree`で確認してみます。
![/usr/bin/tree: No such file or directoryの画像](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/327331/edf67d9b-e1df-541b-284d-40f9f1a4b940.png)

**`tree`が消えてました**。

じゃあ普通に`ls`で見てみるかぁ～と思い実行してみると、

![/usr/bin/ls: No such file or directoryの画像](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/327331/3b2a4751-ab19-f2af-aa72-76c86f02b9af.png)

**`ls`も消えてました**。


それもそのはずで、bashの組み込みコマンド(buildin commands)以外は全て消えています。組み込みコマンドの一覧は`help`で確認することが出来ます。

組み込みコマンドだけでなんとか出来ないのかと思いましたが、何も思い浮かばなかったので、大人しくproxmox側から覗いてみたいと思います(オンプレでベアメタルならbootableデバイスを挿してboot deviceを変更する、みたいな復旧手順になるかなぁ～と妄想したりしました)。

## Proxmox側から見に行ってみる
LXCは`/var/lib/lxc/{container_id}`という場所にあります(chatGPTに教えてもらった)。中にはこのようなものが入っています。
```
apparmor  config  rootfs  rules.seccomp
```
このうち、今回破壊したのは`rootfs`(root file system)です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/327331/f7c939e4-053c-3a22-e065-ba4fe50a2f17.png)
中身は見事に空になっていました。実行時に`cannot remove`と表示されていた`/sys`もありません。

結局消えるんか....

コンテナのメタデータだけが残っているような状態なのかなぁと思いました。

## 感想
こうなってしまえば、後はrootfsを再度移植するぐらいしか手だて無くない？という気持ちです。そもそもLXCはホストのカーネルを用いながら、cgroupとnamespaceで分離しているような環境なので、ファイルシステムを消してしまえばそらそうなるかという気もします。

次回は、仮想化してない環境で試してみようと思います。

**追記**
使い終わったLXCが削除できないことに後から気付き、そちらも別記事にしました。

https://qiita.com/tatmius/items/5374ac13b39343b81056

## 参考
https://dev.classmethod.jp/articles/tried-rm-rf-root-on-amazon-linux-2/

https://ytyaru.hatenablog.com/entry/2020/06/23/000000
ELBの操作をAWSCLIで行う

# 目的（やりたいこと）
- ELBの各操作をCLI行いたい

メンテナンスなどでELBが指定するターゲットグループから、ターゲットのマシン（EC2）を登録除外するときに行う。GUIでも実施可能だが煩雑。GUIも頻繁にアップデートされるため、コマンドで実施。

# 前提条件
- Cloudshellを利用

# 手順

## ターゲットグループARN取得
ターゲットグループのARNが必要のため、これを取得する。GUIでも可能だが、ここではコマンドで行う。事前にターゲットグループの名前を確認し、以下コマンドを追記修正する。
```sh
export TARGET_GROUP_ARN=`aws elbv2 describe-target-groups --query "TargetGroups[].[TargetGroupName,TargetGroupArn]" --output text | column -t | grep -i "検索対象ELBターゲットグループ名" | awk '{print $2}'`
```

TARGET_GROUP_ARN変数にARNが代入されたことを確認する。
ARNは``arn:aws:elasticloadbalancing:ap-northeast-1…``という名称。

```sh
echo ${TARGET_GROUP_ARN}
```

<br>

## インスタンスID取得
EC2のタグ「Name」に対して、「target-grp-machine01」と設定しているマシンのインスタンスIDを確認する（このマシンがターゲットグループ配下にいると仮定）。タグNameでなくとも、なにかしらタグとValueを入れていれば検索できる。

EC2_NAME変数にtarget-grp-machine01を代入。
```sh
export EC2_NAME=target-grp-machine01
```

この名前から、Nameタグを検索し、インスタンスIDを表示してINSTANCE_ID変数に代入。
```sh
export INSTANCE_ID=`aws ec2 describe-instances --filter "Name=tag:Name,Values=${EC2_NAME}" --query "Reservations[].Instances[].[InstanceId]" --output text | column -t`
```

インスタンスIDが代入されたことを確認する。
```sh
echo ${INSTANCE_ID}
```

<br>

## ターゲットグループのターゲット状態確認
ターゲットグループの対象EC2の状態を確認する。healthyになっているかどうかなどをこのコマンドで確認する。

```sh
aws elbv2 describe-target-health --target-group-arn ${TARGET_GROUP_ARN} --query 'TargetHealthDescriptions[].{Id:Target.Id,Port:Target.Port,State:TargetHealth.State}' --output text | column -t
```

ポート番号も表示されるため、次のコマンドで利用する。
<br>


## ターゲットグループ除外
ターゲットグループから確認したインスタンスIDを除外する。

```sh
aws elbv2 deregister-targets --target-group-arn ${TARGET_GROUP_ARN} --targets Id=${INSTANCE_ID}
```

状態は先ほどの「ターゲットグループのターゲット状態確認」コマンドで確認する。

```sh
aws elbv2 describe-target-health --target-group-arn ${TARGET_GROUP_ARN} --query 'TargetHealthDescriptions[].{Id:Target.Id,Port:Target.Port,State:TargetHealth.State}' --output text | column -t
```

実行後はしばらくdrainingとなり、最終的にリストから対象インスタンスが消える。

<br>

## ターゲットグループ登録
CloudShellは10分ぐらいでサインアウトされるので、念のため環境変数を確認する。値が入っていればOK。なければ再度代入。

```sh
echo ${TARGET_GROUP_ARN}
echo ${INSTANCE_ID}
```

以下コマンドで対象インスタンスをターゲットグループに登録する。ここでは443（https）で負荷分散しているが、環境に合わせて「Port=」の数値は変更する。
```sh
aws elbv2 register-targets --target-group-arn ${TARGET_GROUP_ARN} --targets Id=${INSTANCE_ID},Port=443
```

状態は先ほどの「ターゲットグループのターゲット状態確認」コマンドで確認する。

```sh
aws elbv2 describe-target-health --target-group-arn ${TARGET_GROUP_ARN} --query 'TargetHealthDescriptions[].{Id:Target.Id,Port:Target.Port,State:TargetHealth.State}' --output text | column -t
```

登録直後はしばらくinitialとなり、最終的に対象インスタンスがhealthyと表示される。
<br>


# 参考
【AWS CLI】ALBおよびNLB関連の情報取得編

https://blog.serverworks.co.jp/aws-cli-elbv2

<br>
AWS – ターゲットグループのターゲット情報の取得

https://www.itc109.com/knowledge/aws/get-aws-target-group-target?doing_wp_cron=1689722960.9591031074523925781250

<br>
【AWS】ALBからの切り離しと再登録手順

https://zenn.dev/tokku5552/articles/aws-target-group-desc

<br>
いまさらですがLinuxで環境変数を設定したい

https://qiita.com/chihiro/items/bb687903ee284766e879

<br>
複数行の文字列をShell変数に格納して、forで回した時の挙動

https://qiita.com/taro-hida/items/552aa905d343f7395974
ショートカット集（Macターミナル編）

## 初めに
ターミナルでの作業を極限まで効率化したいと思う今日この頃です。
最強のコマンドを誰か教えてくれ

## 環境
| 開発環境   |バージョン    |
|-----------|------------|
| __Mac__ | M1 |

## ショートカット一覧
__タブ系__
| コマンド   |効果    |
|-----------|------------|
| __control__ __+__ __tab__ | タブ切り替え（右方向） |
| __control__ __+__ __tab__ __+__ __shift__ | タブ切り替え（左方向） |
| __command__ __+__ __t__ | 新規ウィンドウ作成 |
| __command__ __+__ __w__ | 現在のウィンドウ閉じる |

## 最後に
最後まで閲覧いただきありがとうございました。
ご意見、ご指摘ありましたら、コメントお願いいたします。
ショートカット集（Googleスプレッドシート編）

## 初めに
Googleスプレッドシートで詳細設計書を作ることがよくあるので、
効率アップのため、ショートカットを多用していきたい今日この頃です。

## 環境
| 開発環境   |バージョン    |
|-----------|------------|
| __Mac__ | M1 |

## ショートカットキー一覧

__行列系__
| コマンド   |効果    |
|-----------|------------|
| __command__ __+__ __option__ __+__ __「 - 」__ | 選択した行を削除する |
| __command__ __+__ __option__ __+__ __+__ __「 ^ 」__ | 新しい行を挿入する |

__切り替え系__
| コマンド   |効果    |
|-----------|------------|
| __option__ __+__ __「 ↑ 」__ __or__ __「 ↓ 」__ | シートの切り替え（移動） |

__テキスト系__
| コマンド   |効果    |
|-----------|------------|
| __shift__ __+__ __command__ __+__ __「x」__ | テキストに横線を引く |

__セル系__
| コマンド   |効果    |
|-----------|------------|
| __shift__ __+__ __command__ __+__ __「v」__ | コピーしたものの値のみを貼り付ける （超便利）|


## 最後に
最後まで閲覧いただきありがとうございました。
ご意見、ご指摘ありましたら、コメントお願いいたします。
いいコード悪いコードまとめ７章　コレクション〜ネストを解消する構造化技法〜

# 標準ライブラリに同じような機能のメソッドはないか
実は便利なメソッドがあったのに存在を知らずに自分で書いてしまった！なんてことは誰しも経験したことがあるのではないでしょうか。そうならないためにも、一度調べてみてから、なければ自分で書く癖をつけたいですねー。

# 早期nextで条件分岐のネストを解消できないか
例えば、以下のように多重分岐している場合、これは早期nextで解消できるかもしれません。
```
number = 5

if number == 1
  puts "number is 1"
elsif number == 2
  puts "number is 2"
elsif number == 3
  puts "number is 3"
elsif number == 4
  puts "number is 4"
elsif number == 5
  puts "number is 5"
end
```
以下のように書くとスッキリですね。
```
number = 5

next if number == 1
next if number == 2
next if number == 3
next if number == 4
puts "number is 5"
```

# 早期breakで条件分岐のネストを解消できないか
これも先ほどと同じですが、
```
number = 5

if number == 1
  puts "number is 1"
  break
elsif number == 2
  puts "number is 2"
  break
elsif number == 3
  puts "number is 3"
  break
elsif number == 4
  puts "number is 4"
  break
elsif number == 5
  puts "number is 5"
end
```
以下のように書き換えると可読性が上がりますね。
```
number = 5

break if number == 1
break if number == 2
break if number == 3
break if number == 4
puts "number is 5"
```
Salesforce:OAuth 2.0 ユーザ名パスワードフローでauthentication failureエラーが返るようになった

# 経緯

SalesforceへAPIアクセスするための認証方式として 「OAuth 2.0 ユーザ名パスワードフロー」を使用しており、最近（2023年7月）作成したDE組織で従来の手順で接続アプリケーション作成、認証しようとしたところ、エラーとなってしまいました。

結論としては、Summer '23のリリース以降はデフォルトでOAuth 2.0 ユーザ名パスワードフローがブロック、つまり利用できないように変更になっていることが原因でした。

# 確認と対処

## エラーになる状態

新規DE組織を作成し、接続アプリケーションを作成、下記curlコマンドでエラーを確認できます。

```sh:コマンド
curl https://login.salesforce.com/services/oauth2/token \
-d 'grant_type=password' \
-d 'username=username' \
-d 'password=password' \
-d 'client_id=3MV....' \
-d 'client_secret=98ABCDEF....'
```

```json:レスポンス
{"error":"invalid_grant","error_description":"authentication failure"}
```

設定→ユーザ→ログイン履歴を確認すると「ユーザ名-パスワードフローが無効になっています」と記録されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/53115/aee79eba-85e6-5676-07cf-115a082668bd.png)

## 設定を変更

設定→OAuth および OpenID Connect 設定を開き、[OAuth ユーザ名パスワードフローを許可] をオンに変更します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/53115/8c806084-4003-a746-1e29-19f98e35668b.png)

## 再度確認

最初にエラーになったcurlコマンドを実行すると成功しました。

```json:レスポンス
{"access_token":"00D....!.......","instance_url":"https://xxx-dev-ed.develop.my.salesforce.com","id":"https://login.salesforce.com/id/00D.../005...","token_type":"Bearer","issued_at":"1690...","signature":"...."}
```

ログイン履歴も「成功」表示となりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/53115/7e1ab5ea-6c95-afaf-b2bc-20a64ee9e68c.png)


# まとめ
下記のリリースページに記載の通りでしたが、チェックしておらず解決するために少し時間を使ってしまいました。



[新しい組織でデフォルトでブロックされる OAuth 2.0 ユーザ名パスワードフロー](https://help.salesforce.com/s/articleView?id=release-notes.rn_security_username-password_flow_blocked_by_default.htm&release=244&type=5&language=ja)

また、ユーザ名パスワードフローは非推奨と読み取れそうです。
本ポスト内容は暫定対応とし、別の方法へ移行を検討したほうが良さそうです。

[特別なシナリオの OAuth 2.0 ユーザ名パスワードフロー
](https://help.salesforce.com/s/articleView?id=sf.remoteaccess_oauth_username_password_flow.htm&type=5&language=ja)
【UiPath】「PowerShellを呼び出し」アクティビティを使って最新日付のファイルを取得する

# はじめに

仕事でUiPathのワークフロー内からPowerShellを使う機会があったので、
メモとして残します。

この記事はUiPathブログ発信チャレンジ2023サマーの22日目の記事です。

https://note.com/shumpei_w/n/nd082bdf28853


# 結論

「PowerShell」を呼び出しアクティビティ内でコマンドを組み合わせて
最新日付のファイルパスを取得します。

## 例

csvinfolder内に格納されているCSVファイルの最新ファイルパスを取得したい場合

~~~
"(Get-ChildItem " + Chr(34) + csvinfolder + Chr(34) + "-filter " + Chr(34) +"*.csv" + Chr(34) + "| Sort-Object -Descending LastWriteTime)[0].FullName"
~~~

# おわりに

二番煎じですが、いろいろなやり方があるよということでひとつ。。。

PowerShellを使用せずに実現するやり方も以前書きました。よろしければそちらも見ていただけると嬉しいです。

https://qiita.com/tansuke2021/items/728873b535f6e4286cd3
Llama2とlangchainでpdf読み込んでchatbotの例


好きなモデルとPDFを入れてください。質問すればチャットボットが答えます。
私は下記のモデルをダウンロードしました。
https://huggingface.co/TheBloke/Llama-2-7B-Chat-GGML/blob/main/llama-2-7b-chat.ggmlv3.q8_0.bin

```ptyhon.py
import os
from langchain.document_loaders import PyPDFLoader
from langchain.embeddings import OpenAIEmbeddings
from langchain.vectorstores import FAISS
from langchain.chains.question_answering import load_qa_chain
from langchain.chains import ConversationalRetrievalChain
import logging
import sys

from langchain.chains import RetrievalQA
from langchain.embeddings import HuggingFaceEmbeddings
from langchain.llms import LlamaCpp
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.vectorstores.faiss import FAISS
from pypdf import PdfReader

# PDFファイルの読み込み
reader = PdfReader(r"読み込みたいpdfのパス")

# テキストの抽出
text = page.extract_text()
print(text)

# ログレベルの設定
logging.basicConfig(stream=sys.stdout, level=logging.DEBUG, force=True)
# チャンクの分割
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=300,  # チャンクの最大文字数
    chunk_overlap=20,  # オーバーラップの最大文字数
)
texts = text_splitter.split_text(text)

# チャンクの確認
print(len(texts))
for text in texts:
    print(text[:10].replace("\n", "\\n"), ":", len(text))

# インデックスの作成
index = FAISS.from_texts(
    texts=texts,
    embedding=HuggingFaceEmbeddings(model_name="intfloat/multilingual-e5-large"),
)
index.save_local("storage")

import os
from transformers import AutoTokenizer, AutoModelForCausalLM
from transformers import AutoModelForCausalLM, AutoTokenizer, pipeline
from langchain.llms import HuggingFacePipeline

from langchain.llms import LlamaCpp
llm = LlamaCpp(
    model_path=r"Llama2のモデルを保存したパス",
    n_ctx=4096,
    temperature=0,
    max_tokens=640,
    verbose=True,
    streaming=True
)

qa = ConversationalRetrievalChain.from_llm(llm, chain_type="stuff",retriever=index.as_retriever(search_kwargs={"k": 4}))

# Chatbot loop
chat_history = []
print("Welcome to the State of the Union chatbot! Type 'exit' to stop.")
while True:
    query = input("Please enter your question: ")
    
    if query.lower() == 'exit':
        break
    result = qa({"question": query, "chat_history": chat_history})

    print("Answer:", result['answer'])
```
WSL環境でLivebookのインストールするためのelixirのバージョンアップの方法

こんにちは、rickyです。
ここではWSL環境においてLivebookのインストールをする際にこけてしまったのでその対処法を備忘録として残します。
結論から話すとasdfでelixirの別バージョンを管理して、そこから実行を行うという形になります。

環境
windows 10
Ubuntu 20.04
Elixir 1.13.4

https://qiita.com/nishiuchikazuma/items/b9d319732ddb540fd990
asdfのインストール方法については上記記事を参照にさせていただきました。
WSL環境においては以下のコマンドを活用されてください。

```
sudo apt-get update
sudo apt-get install -y coreutils automake autoconf openssl libyaml-dev libreadline-dev libxslt-dev libtool unixodbc-dev
```
```
git clone https://github.com/asdf-vm/asdf.git ~/.asdf --branch v0.12.0
```
```
bashの場合：
echo -e "\n. ~/.asdf/asdf.sh" >> ~/.bashrc
echo -e "\n. ~/.asdf/completions/asdf.bash" >> ~/.bashrc
source ~/.bashrc
```

```
zshの場合：
echo -e "\n. ~/.asdf/asdf.sh" >> ~/.zshrc
echo -e "\n. ~/.asdf/completions/asdf.bash" >> ~/.zshrc
source ~/.bashrc
```


asdfをインストールした後はelixir1.14.2をインストールし、その環境に動きます。
```
asdf install elixir 1.14.2
asdf global elixir 1.14.2
```

以上です。
TkinterのTextウィジェットで日本語入力中にレインボーカーソルになるのは仕様か

# 本稿で扱う情報
Python
Tkinter

# 環境
Mac OS
M1 MacBook Air
M1Pro MacBook Pro

# 症状
Textウィジェット、おそらくもしくはEntryで日本語入力中にレインボーカーソル（フリーズ）になる
強制終了しないといけない
エラーログは出ていない

# 症状分析
タイピングが早すぎる→Airだとあんまり関係なかったが、M1Proにしたところ多少改善。メモリ16GBモデルなので、もしかすると32GB以上のモデルだとより発生しにくい？
改行含むガチャガチャ入力だとM1Proでもほぼ発生。普通に入力するくらいなら大丈夫。
Airは普通の入力でも発生。

# 対策
スペックを上げる、OSを変える（未検証）、常識的な入力をする（Airは諦める）

# 雑結論
仕様というかスペックの問題か。
テキスト入力を伴うデスクトップアプリをMacで動かす方は注意。
Microsoft Teamsで基幹システムを爆速に構築・改修する

# はじめに

電子帳簿保存法、インボイス制度など法令改正によるシステム対応や分析ニーズの増加など基幹システムにまつわる改修要望は非常に多い。私が推進した経験になるがこれらの対応について基幹システムの本体を一切改修することなくTeamsやPower BIを連携させて対応した経験を共有しておく。Microsoftプラットフォームを使用している企業であればヒントになることもあるのではないかと思う。具体的には税額計算の変更、請求書の変更なども基幹システムを改修せずこれらのツールとクラウドサービスであるインフォマートB2Bプラットフォームや楽楽明細へアップロードデータを自動生成させることで達成している。また、これらのテクニックをうまく活用すると負荷に耐えられるのであれば基幹システムのデータベースの生データのみアクセスできればよくデータウェアハウス（DWH）やデータマートなども必要なくなる。それでもって必要なレポートがリアルタイムないしはタイムリーに見れるようにもなる。

# TeamsのExcel Onlineを活用する

品目や顧客などの分類コード、分析コード、送付先、等々基幹システムを改修せず管理する場所としてTeamsのExcel Onlineが考えられる。公開チャネルならTeamsにアクセスできる全員アクセスできるしプライベートチャネルにすればさらに限られた人に閲覧、編集権限を絞ることができる。
Excelをデータベースとして認識させるためにはセルに打ち込んだだけではダメでテーブル化する必要がある。ネットで検索したところ、以下のような参考となる記事がある。
https://support.microsoft.com/ja-jp/office/excel-%E3%81%A7%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%82%92%E4%BD%9C%E6%88%90%E3%81%99%E3%82%8B-bf0ce08b-d012-42ec-8ecf-a2259c9faf3f
テーブル化したExcelはPower BIに連携できる。ネットで検索したところ、以下のような参考となる記事がある。
https://qiita.com/ishiayaya/items/48cbd7fa40d6ed515713
https://community.fabric.microsoft.com/t5/Power-Query/Using-a-file-in-Microsoft-teams-as-a-data-source/td-p/629155

Teams上のExcel Onlineで必要なマスタデータをリアルタイム性を担保して管理し、基幹システムの生データとPower BIでがっちゃんこすることで新たに必要となるレポート、データ出力が可能となる。
Power BI上でリレーションを作成することで基幹システムのデータと連携できる。

# 楽楽明細やインフォマートB2B請求書や支払通知書発行プラットフォーム連携

サードパーティーのクラウドサービスを活用しFAX送信、メール送信、Webダウンロード、郵送代行やインボイス制度に対応した税額計算などを実現するためPower BIでこれらのクラウドサービスへのアップロードに必要なCSVファイルを自動出力できるようにした。顧客によってFAX送信有無、メール送信有無、郵送代行有無など要望が異なるのでそれらは基幹システムの顧客マスタでは管理する場所がないので、TeamsのExcel Online上に新たにマスタ（顧客コード、FAX送信区分、メール送信区分・・・）を定義して管理したことになる。

# 基幹システムの機能を捨てて（改修をあきらめ）爆速で新たな要件に対応したクラウドプラットフォームに移行しダウンサイズ

例えば納品書、納品書兼請求書、請求書やレポート出力は（基幹システムを改修するとなると莫大なリソースをかけないと困難であったので）従来の基幹システムの出力は使用しなくなりTeamsと連携されたPower BIの出力、その出力結果をクラウド事業者にアップロードすることで実現し、それに合わせて印刷や郵送、FAX対応などの社内の事務作業もクラウド事業者が全てやってくれるので無くなった。基幹システムを改修するとなると半年、1年がかりで考えてウォーターフォール的に外部委託で進めることが多く要件変更も大変だった経験があるし事務作業は何一つ減らない。上記のような仕組みであれば半日～1日あれば内製でトライアルができ本番稼働後に判明する新たな要件も基幹システム本体のプログラムは一切さわらずTeamsやBI、クラウド設定を触るだけで済むし生産性が著しく向上した。

# レポート作成やクラウドを使用するために手作業を増やすことはやめよう

基幹業務にまつわることでTeamsやBIを組み合わせるとかなりのことが自動化できる。
新たな分析レポート作成やクラウドサービスを導入している企業の多くがそれらのサービスに必要なデータを手作業で作成しているのではないかと思いますがそれでは生産性向上が悪化することにもなる。ぜひ自動化を考えてみてください。
iPhoneでAPN設定が不要なeSIMとAPN設定が必要な物理SIMの利用時に、物理SIMのAPNプロファイルをインストールするとeSIMが圏外になる問題を修正できたので解決方法をメモ

iPhoneでeSIM（楽天モバイル）と物理SIM（HISモバイル）を同時利用した時に、HISモバイルのAPN設定プロファイルをインストールすると、楽天モバイルが圏外になり通信できなくなる問題が発生し、試行錯誤して両方利用できるようになったので設定方法のメモを残そうと思います。

# 環境
このような環境で確認を行いました。

- iPhone 14 Pro iOS 16.5.1(c)
- 楽天モバイル最強プラン (eSIM)
- HISモバイル自由自在プラン (物理SIM)

ちなみに各SIMはこのように運用する予定です。
- HISモバイル: 通話専用・楽天が通信出来なくなった時のバックアップ
- 楽天モバイル: データ通信専用

# 症状
- HISモバイルのAPNプロファイルをインストールすると、楽天モバイルのアンテナピクトが立たず「圏外」表示になる
    - APNプロファイルを削除すれば、楽天モバイルが復活する

# 解決方法

解消方法は**最後にeSIMをインストール**するだけです。

次の手順で設定する事で問題を解消できました。

1. 楽天モバイルのeSIMを削除する
2. HISモバイルのAPNプロファイルをインストールする
3. 楽天モバイルのeSIMをインストールする

この方法で両方のSIMのアンテナピクトが立つようになりました。
問題が解決する保証はありませんが、同じような症状になったらこの方法を試してみると良いかもしれません。
pip install で発生する Cannot uninstall エラーの解決 

# はじめに

pip install <パッケージ名> でパッケージのインストールや更新を行う際、以下のように「アンインストールできない」という旨のエラーが表示される。

```
$ pip install paddlepaddle

Cannot uninstall 'blinker'. It is a distutils installed project and thus we cannot accurately　determine which files belong to it which would lead to only a partial uninstall.
```

# 環境
OS: Windows10

Dockerで以下の環境を作成。
Ubuntu: 22.04
Python: 3.7.1

# 原因
パッケージ依存のライブラリが対象となっていた、もしくはバージョンが古い。原因がどちらか特定することはできなかった。
エラー文の内容としては、「\<package>をアンインストールできない。 これは distutils がインストールされているプロジェクトであるため、どのファイルがそれに属するかを正確に判断できず、部分的なアンインストールしかできない」という内容。
なお、`pip check`というコマンドでパッケージ間の依存関係を確認できるため、チェックしてみるとよいかもしれない。


# 解決法 (It works for me)
今回、解決法が2つ見つかったため、どちらも紹介する。

- 強制インストール
パッケージを強制インストールする。-I / --ignore-installed オプションで、依存関係を無視してインストールする。--force-installed オプションとの違いは、前者は既存パッケージは上書きせず、不足分のみをインストール。後者は既存パッケージのものは上書きしてインストール。
ただし、今回は環境構築段階で Docker で順番に動かそうとしたところ、解決しなかった。ターミナルでコマンドを打つと解決したが、これだとコンテナをリビルドする度にこのコマンドと `pip install <package>`が必要となるため、別手法を模索。

```
pip install <package> --ignore-installed
```
システムコマンドとして実行する（pip の前に ! をつける）と成功するかも？
```
!pip install <package> --ignore-installed
```

- `apt remove <package>`でパッケージを削除
重複する不要なパッケージを削除する。このコマンドをエラーが出た `pip install <package>`コマンドの前に実行するよう Dockerfile を編集したところ、無事パッケージをインストールすることができた。
(なお、私の場合、パッケージ名は python3-blinker だった。各自
どのパッケージが不要なのかを確認してほしい。)

```
apt remove -y <package>
pip install <package>
```

コマンド実行後、`pip list | grep <package>`でそのパッケージが削除されているかどうかを確認するとよいだろう。


# 解決しない場合
解決しない場合は、以下のことを行うと解決する可能性がある。なお、私が直接試したわけではないため、詳細な内容は各自でさらに調査してほしい。

- パッケージのアップグレード
最初のタイミングでインストールした際のパッケージが、時間が経って古くなり、新しく別パッケージをインストールする際にその古いバージョンに対応していない、ということが考えられる。-U、もしくは --upgrade オプションでアップグレードできる。
　
```
pip install <package> --upgrade
```

- pip のバージョンを更新してから再インストール

pip のバージョンを下げる、下げたバージョンの pip でパッケージをアンインストールする、pip のバージョンを上げる、パッケージを再インストールするという流れ。

```
pip install pip==(version)
pip uninstall <package>
pip install --upgrade pip
pip install <package>
```

# blinker, distutils って結局なんだったの？
私の場合、OCRツールである PaddleOCR をインストールしようとして起こった。
blinker については、どうやらシグナルの送受信を行う、Flask などで使うパッケージだったらしい。Flask を使ったことがないため、どこからインストールしたか皆目見当がつかないこと以外は納得。

distutils については、Python の標準のパッケージ管理ツールだったようだ。どうやら、Python 3.12 で削除されていたらしい。
ということで、blinker というパッケージが distutils で既にインストールされていて、pip でインストールしようとしたから再インストールしようとしたけど、pip では distutils でインストールした blinker を追跡できないよ、ってことだった……のか？



# 参考文献
- [【Python】pipの使い方](https://www.task-notes.com/entry/20150810/1439175600)

- [Pythonのパッケージ管理システムpipの使い方](https://note.nkmk.me/python-pip-usage/#pip-check)

- [pythonライブラリをアンインストールできない時。Can't uninstall 'hogehoge'. No files were found to uninstall.](https://qiita.com/miyamotok0105/items/9d941bce79c26baecfee)

- [pipでパッケージの更新をしたらアンインストールエラーが出た話](https://note.com/junk_matsumoto/n/nc4f472ed0d80)

- [distutils の廃止予定（Python 3.12）](https://qiita.com/kkdd/items/dab5e1670b6859ce1f25)

- [Pip cannot uninstall <package> error in Python [Solved]](https://bobbyhadz.com/blog/python-error-pip-cannot-uninstall-package)
【SwiftUI】画像をインスタグラムにシェアする

# はじめに
インスタグラムへのシェア機能を作成する方法を学んだので記録しておきます。

# 実装
```swift
import UIKit

public final class ImageDownloadManager: NSObject {
    private var completion: (_ error: Error?) -> Void = { _ in }

    public func save(image: UIImage, completion: @escaping (_ error: Error?) -> Void) {
        self.completion = completion
        if let data = image.pngData(), let png = UIImage(data: data) {
            UIImageWriteToSavedPhotosAlbum(png, self, #selector(image(_:didFinishSavingWithError:contextInfo:)), nil)
        }
    }

    @objc
    private func image(_ image: UIImage, didFinishSavingWithError error: Error?, contextInfo: UnsafeRawPointer) {
        completion(error)
    }
}

```

```swift
import Photos
import UIKit

public final class InstagramShareManager {
    public init() {}

    public func share() {
        let fetchOptions = PHFetchOptions()
        fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: true)]
        let fetchResult = PHAsset.fetchAssets(with: PHAssetMediaType.image, options: fetchOptions)
        if fetchResult.firstObject != nil {
            guard let lastAsset = fetchResult.lastObject,
                  let urlScheme = URL(string: "instagram://library?LocalIdentifier=\(lastAsset.localIdentifier)")
            else {
                return
            }
            UIApplication.shared.open(urlScheme)
        }
    }
}
```

# 使い方
```swift
import SwiftUI

struct ContentView: View {
    private let imageDownloadManager = ImageDownloadManager()

    private let instagramShareManager = InstagramShareManager()

    var body: some View {
        Button {
            imageDownloadManager.save(image: UIImage(named: "sample")!) { error in
                if let error {
                    print(error.localizedDescription)
                } else {
                    instagramShareManager.share()
                }
            }
        } label: {
            Text("シェア")
        }
    }
}
```

# おわり
もっといいシェアの方法があったのですが、Facebook開発者アカウントが必要らしいです。
今回の方法は開発者アカウントなしでできます！
タスク管理　タスクの状態遷移

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457284/f5639b51-7fe9-edc2-26c1-9a0ff112decf.png)
　タスク管理はCPUを遊休させることなく働かせ続け、効率的に利用することを目的としています。タスク間を行うことによって、CPUが暇になったら、別の仕事（タスク）を与えることができるようになり、複数の仕事を同時に実行するマルチタスクが実現でます。

　あるタスクがCPUを使わなくなった時に、別のタスクを実行するようCPUに支持することが、タスク管理の基本的な役割です。

　指示を的確に行うためには、どのタスクがどのような状態にあるのかを正確に把握しなくてはなりません。そこで、「実行可能状態」「実行状態」「待ち状態」の３つの状態を定義し、どのタスクがどの状態にあるのかを管理します。

１：実行可能状態
　実行可能状態は、待合室で待っているのに相当する状態です。タスクを起動する（プログラムを実行する）と、起動したタスクは、自分順番がまわってきて、CPUが処理してくるのを待ちます。

２：実行状態
　実行状態のタスクは、今まさに処理されている最中のタスクです。CPUが１つしかないのであれば、実行状態になれるタスクも１つしかありません。実行状態のタスクは、次の景気によって実行可能状態や待ち状態に移ります。
　実行可能状態に移るのは、
①自分よりも最優先度の高いタスクが実行可能状態になった。
②自分の持ち時間（タイムスライス）が経過した。
③自らCPUを手放した
時です。

３：待ち状態
　待ち状態は、倉庫にタスクが収納されているような状態です。タスクが入出力へのアクセスというのは、我々の感覚で言うと数週間もの時間がかかる作業です。このような長時間、「待合室（実行可能状態）」に居座られたのではじゃまですから、一旦倉庫に移しておいて、用事があれば取り出すことにしようという考え方です。

　待ち状態に移されたタスクは、入出力装置から必要とするデータが到着すると（これを　入出力が完了する　と言います）、実行可能状態へ移されます。入出力装置から必要とするデータが到着したことを知らせる信号が、入出力割込みです。
【Xcode】簡単にファイルを複製する方法

# はじめに
Figmaなどの多くのデザイン系ツールでは、オブジェクトを選択してオプション＋ドラッグすると、複製することができます。
これをXcodeでやるとどうなるのか、気になったので試してみました。

# 結果
https://twitter.com/shota_appdev/status/1682714778698133505?s=61&t=UNkwFomrg2lUvy5_QEiDuw

なんと、Xcodeでもファイルの複製ができました！

# おわりに
テンプレートを作るのは面倒だけど、使い回しをしたいときに便利そうです！この記事が参考になったという方は、いいねとフォローよろしくお願いします。
ChromeDriverの公開方法がChrome 115から変更された

https://chromedriver.chromium.org/downloads
上記で公開されているChromeDriverについて、Chrome 115からその公開方法が変わりました。

>If you are using Chrome version 115 or newer, please consult the Chrome for Testing availability dashboard. This page provides convenient JSON endpoints for specific ChromeDriver version downloading.

この変更が原因でChromeDriverを自動で最新化する系のライブラリが正しく動作しない、CIツールが動作しないといった状況が起きているようです。

https://twitter.com/ut61z/status/1681624255530962944

https://twitter.com/jsakamoto/status/1682009804418715648

旧方式では特定のURL( `https://chromedriver.storage.googleapis.com/LATEST_RELEASE_114` など)で最新のバージョン文字列を取得し、それを元にダウンロード元URLを作成できたのですがそれらがAPIに置き換わり、また旧方式のバージョン文字列が更新されなくなりました。

これによりバージョン115以降のURL `https://chromedriver.storage.googleapis.com/LATEST_RELEASE_115` etcが用意されなくなり、旧方式のみ対応していたライブラリは機能しなくなりました。

## 各ライブラリの対応状況
### [webdrivermanager](https://github.com/bonigarcia/webdrivermanager) (Javaライブラリ)
6月時点で対応されていました。

https://twitter.com/boni_gg/status/1671790658883919874

最新版(5.4.1)のCLIをWindowsで実行すると取得できているのが分かります。
CLIのドキュメントはここにあります。 https://bonigarcia.dev/webdrivermanager/#webdrivermanager-cli
```
D:\temp>C:\devenv\java\jdk-20.0.1\bin\java -jar D:\temp\res\webdrivermanager-5.4.1-fat.jar resolveDriverFor chrome
[INFO] Using WebDriverManager to resolve chrome
[DEBUG] Detecting chrome version using online commands.properties
[DEBUG] Running command on the shell: [cmd.exe, /C, wmic, datafile, where, name="%PROGRAMFILES:\=\\%\\Google\\Chrome\\Application\\chrome.exe", get, Version, /value]
[DEBUG] Result: Version=115.0.5790.102
[INFO] Using chromedriver 115.0.5790.102 (resolved driver for Chrome 115)
[INFO] Reading https://chromedriver.storage.googleapis.com/ to seek chromedriver
[DEBUG] Driver to be downloaded chromedriver 115.0.5790.102
[DEBUG] Using URL built from repository pattern: https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/115.0.5790.102/win64/chromedriver-win64.zip
[INFO] Downloading https://edgedl.me.gvt1.com/edgedl/chrome/chrome-for-testing/115.0.5790.102/win64/chromedriver-win64.zip
[INFO] Extracting driver from compressed file chromedriver-win64.zip
[INFO] Driver location: D:\temp\.\res\chromedriver.exe
```

### [webdriver_manager](https://github.com/SergeyPirogov/webdriver_manager) (Pythonモジュール)
対応中。下記issueで上げられたPull Requestを検証中のようです。

https://github.com/SergeyPirogov/webdriver_manager/issues/536

07/23 PRはマージされましたが、新方式にのみ対応した事で今後はChrome114以前で正しく動作しなくなったようです
cscの作法 その421

# 概要
cscの作法、調べてみた。
練習問題、やってみた。

# 練習問題
automationでコマンドプロンプト、開いてhello.csをセーブしてコンパイルして実行せよ。

# サンプルコード

```

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Automation;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace App
{
	class Program {
		static void Main(string[] args) {
			AutomationElement aeForm;
			Process cmd = Process.Start(@"cmd");
			Thread.Sleep(2000);
			aeForm = AutomationElement.FromHandle(cmd.MainWindowHandle);
			aeForm.SetFocus();
			SendKeys.SendWait("echo using System; > hello.cs{ENTER}");
			SendKeys.SendWait("echo class Hello {{} >> hello.cs{ENTER}");
			SendKeys.SendWait("echo    static void Main{(}{)}    {{} >> hello.cs{ENTER}");
			SendKeys.SendWait("echo       Console.WriteLine{(}\"Hello, World\"{)}; >> hello.cs{ENTER}");
			SendKeys.SendWait("echo    {}} >> hello.cs{ENTER}");
			SendKeys.SendWait("echo {}} >> hello.cs{ENTER}");
			SendKeys.SendWait("C:\\Windows\\Microsoft.NET\\Framework\\v2.0.50727\\csc.exe hello.cs{ENTER}");
			SendKeys.SendWait("hello{ENTER}");
		}
	}
}


```

# 実行結果

```
>echo using System; > hello.cs

>echo class Hello { >> hello.cs

>echo    static void Main()    { >> hello.cs

>echo       Console.WriteLine("Hello, World"); >> hello.cs

>echo    } >> hello.cs

>echo } >> hello.cs

>C:\Windows\Microsoft.NET\Framework\v2.0.50727\csc.exe hello.cs
Microsoft(R) Visual C# 2005 Compiler version 8.00.50727.9149
for Microsoft(R) Windows(R) 2005 Framework version 2.0.50727
Copyright (C) Microsoft Corporation 2001-2005. All rights reserved.


>hello
Hello, World
```

以上。