OmniAICreator/Qiita-1.07M huggingface dataset:
C# で CurrentDirectory を取得する 検証してみた

## 背景
開発環境で作成したバッチプロジェクトを他環境で動かした際に、カレントディレクトリの取得方法に問題がありうまく動かなかったため、カレントディレクトリの取得メソッドの検証してみる。


### 検証コード
以下のような簡易的なバッチの作成
```
logger.Info(System.AppDomain.CurrentDomain.BaseDirectory);
logger.Info(Directory.GetCurrentDirectory());
logger.Info(Directory.GetParent(Assembly.GetExecutingAssembly().Location));
logger.Info(Environment.CurrentDirectory);
logger.Info(System.IO.Path.GetDirectoryName(System.IO.Path.GetFullPath(Environment.GetCommandLineArgs()[0])));
logger.Info(System.IO.Path.GetDirectoryName(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName));
```

### 検証方法
・タスクスケジューラで作成した簡易バッチの実行

### 検証結果
```
2022-07-13 12:31:59.2765 [INFO] C:\00_hata\PlayGound\Dirtest\bin\x86\Debug\
2022-07-13 12:31:59.2921 [INFO] C:\WINDOWS\system32
2022-07-13 12:31:59.3154 [INFO] C:\00_hata\PlayGound\Dirtest\bin\x86\Debug
2022-07-13 12:31:59.3154 [INFO] C:\WINDOWS\system32
2022-07-13 12:31:59.3274 [INFO] C:\00_hata\PlayGound\Dirtest\bin\x86\Debug
2022-07-13 12:31:59.3274 [INFO] C:\00_hata\PlayGound\Dirtest\bin\x86\Debug
```

以下は呼び出し元プログラムのルートディレクトリ
スケジューラの作業ディレクトリを取得する。
Directory.GetCurrentDirectory()
Environment.CurrentDirectory

以下は呼び出しプログラムのルートディレクトリを取得する。
System.AppDomain.CurrentDomain.BaseDirectory
Assembly.GetExecutingAssembly().Location)
System.IO.Path.GetDirectoryName(System.IO.Path.GetFullPath(Environment.GetCommandLineArgs()[0]))
System.IO.Path.GetDirectoryName(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName)


## まとめ
呼び出し元のルートディレクトリが必要か？
呼び出しバッチのルートディレクトリが必要か？
C# CurrentDirectory 取得と調べたら何かしら出てくるので違いを分かったうえで使うようにしよう
Rails で rake を追加したのに実行できない ( 拡張子が間違っていた )

rake の拡張子は rake です。

x `lib/tasks/example.rb`

o `lib/tasks/example.rake`

# エラー

```
Don't know how to build task 'example' (See the list of available tasks with `rails --tasks`)
```



<!-- Update From Qiita API -->

# チャットメンバー募集


何か質問、悩み事、相談などあればLINEオープンチャットもご利用ください。

https://line.me/ti/g2/eEPltQ6Tzh3pYAZV8JXKZqc7PJ6L0rpm573dcQ





# Twitter


https://twitter.com/YumaInaura


<!-- Update From Qiita API -->
Node-Postgres で大量データを bulk insert した時の備忘録

## 経緯

node-postgresを使用してbulk insertする時に苦労したので、備忘録を残す。

## 実行環境

- linux
- nodejs
- postgres

## 性能比較

1行ずつのINSERTとの性能比較については、こちら([1000万件のINSERTを映画1本分ぐらい時間節約できた話](https://datumstudio.jp/blog/postgresqlでinsert速度比較/))を参照。

## postgres の準備

下記サイトを参考に node-js から postgres に接続する準備をする。
[`Node-Postgres` を使ったときに、試行錯誤してできた Postgres クラス](https://qiita.com/masaks/items/3ee1b5a06a95315a7ae7)

## 大量データを 1000 行単位に分ける

paramsにはINSERT時のパラメータを配列で格納しておく。

```js:例
[
  ['001', 'hoge'],
  ['002', 'fuga'],
  ['003', 'piyo'],
]
```

※追記
上限1000件は他のSQL言語でした。
~~postgresのbulk insertは一度に1000件が上限とのことなので、~~ 処理したいデータを1000件ずつ詰め直す。

※もっといい方法があれば教えてください。

```js
const makeBulkArray = (params) => {
  let bulkArray = [];
  let remaining = params;

  // 残り件数が1000より少なくなるまで
  while (remaining.length > 1000) {
    // postgresのバルクインサートは1000件が上限
    let oneBulk = remaining.slice(0, 1000);
    bulkArray.push(oneBulk);
    // 処理配列に詰めたデータを取り除く
    remaining = remaining.slice(1000);
  }
  // 残り件数が1000件より少ない場合の余りデータを最後に詰める
  if (remaining.length > 0) bulkArray.push(remaining);

  return bulkArray;
};
```

## bulk insert する

参考にさせていただいたサイト([PostgreSQL に node-postgres モジュールを使って BULK INSERT をする方法](https://hirooooo-lab.com/development/postgresql-bulk-insert/))のとおりにやると、現在のpg-formatでは動かせないようで公式ドキュメントを見て調整した。

```js
const format = require('pg-format');
const insertData = async (params) => {
  // poolからクライアント接続
  const pg = await getClient();
  // pg-formatを使って、pgが実行できるSQLを生成
  const sql = format('INSERT INTO test_table (id, name) VALUES %L', params);

  await pg.query(sql); // SQL実行
  await pg.release(); // クライアントをpoolに返す
};
insertData(bulkArray);
```
CADSのレポジトリからデータ名などでストリームを探す

SPSSのCADSレポジトリには保存したストリームを検索する機能があります。
ストリームファイル名や作成者、日付だけではなく、以下のような項目での検索ができます。
・ノードラベル
・パラメーター名
・ラベル

* テスト環境
    * SPSS Modeler 18.3
    * CADS 8.3
    * Windows Server 2019

# 1 検索ウィンドウでの検索
CADSのDeployment ManagerをつかってCADSサーバーを右クリックして「検索」を選びます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/3f8591be-80fc-9faa-b50b-5a94dbc5052a.png)

ここでは「credit_６か月前.csv」を指定しました。「credit_６か月前.csv」というデータを読み書きしているストリームを検索したいという意図です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/a15d87ad-f20e-fc6a-518f-809d868b71ea.png)

以下のように検索されました。
確認したいストリームをえらんで右クリックすると「開く」と「コンテンツエクスプローラーで表示」が選べます。「開く」だとModelerが起動して開きます。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/2de2e8d1-c73b-a1a2-8905-6a056922cbd6.png)

開いてみると確かに「credit_６か月前.csv」というノードがありました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/1f138f05-9cae-6324-2bab-51f2c3ed9567.png)


「コンテンツエクスプローラーで表示」の場合はレポジトリ内のフォルダが開き、ストリームが選択状態になります。ストリームと一緒に保存されているジョブなどのオブジェクトを確認できます。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/6d480aeb-466e-e42a-39d4-574e485457b4.png)



# 2 詳細な検索

検索時に詳細を押すとプロパティや日付などをAND/OR条件で指定した検索ができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/f8689dc1-0856-923c-57e7-808874f35b9b.png)

## 2.1 ノードラベルからの検索

プロパティに「ノードラベル」を選び、値にノードのラベルを指定し、追加ボタンをクリックします。

ここでは先ほどの詳細ではない検索と同じ「credit_６か月前.csv」を指定しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/e9191404-1b67-977c-2d68-e30cfe6c7ef4.png)

検索条件に入りましたので、検索ボタンで検索をします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/44f73bd9-4610-6950-0489-898806fa5b6f.png)

先ほどの詳細ではない検索とは異なり、厳密にノードラベルで「credit_６か月前.csv」を使っているストリームだけが検索されます。ここでは、先ほどと同じ結果になりましたが、キーワードなどに「credit_６か月前.csv」が入っているだけのストリームは除外されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/166f4a12-0e8c-698f-19bb-28d92bf80ff1.png)

## 2.2 パラメーター名からの検索

プロパティに「パラメーター名」を選び、値にパラメータ名を指定し、追加ボタンをクリックします。ここでは「AGE」を指定しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/a9c2a114-9fdb-7e9a-10ba-462c1c50ddf6.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/b2df2e7f-ceb0-32e9-cffc-37cddb4b4a70.png)

確かに「AGE」のパラメーターをもったストリームが検索できました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/81faba7c-fe44-df26-dab7-3526b5561590.png)


## 2.3 ラベルからの検索

プロパティに「ラベル」を選び、値にラベル名を指定し、追加ボタンをクリックします。ここでは「Test1」を指定しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/f08c939a-546d-fa06-0c9b-9912d5df5fd5.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/5645e15e-6809-c5d6-f249-8abbdaf96680.png)


確かに「Test1」のラベルをもったストリームが検索できました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/4bc1f8eb-a022-b246-7fbb-688762e24d1d.png)


## 2.4 指定可能なプロパティ
指定可能なプロパティには以下のようなものがあります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/92052d36-1837-ffe8-8bc3-1f2cb2f462d3.png)
Angularコーディングスタイル・ルールまとめ

自分でコードを書く際のルールをまとめていきます。

基本的なスタイルガイドとして

https://qiita.com/baby-degu/items/d50afffd8a9dca9d380e

2016年執筆の記事だが

https://zenn.dev/okunokentaro/articles/01f9reeb0d6eszbxykqxav80q8


## `@Input`
- 契約として必ず値が渡されることを求めるプロパティについては、Non-null アサーションオペレータ !を使ってプロパティが undefined じゃないことを明示的に示す

```typescript
@Component({
  selector: "user-card"
})
class UserCardComponent {
  @Input() user!: User;

  ngOnInit() {
    if (this.user == null) {
      throw new Error("[user] is required");
    }

    this.someFunc(this.user); // no need `if` type guard
  }

  someFunc(user: User) {}
}
```

https://blog.lacolaco.net/2018/06/angular-strict-property-initialization-best-practice/


## `RxJs`

### `Observable`

#### 購読について

- Store との接続や、リアルタイム DB との接続など、コンポーネントが Observable を購読する必要があるときは、コンストラクタで Observable の初期化をおこなう
- そしてコンポーネント内ではsubscribeせず、テンプレート内でasyncパイプを使って非同期ビューを構築する。

```typescript
class UserListComponent {
  userList$: Observable<User[]>;

  constructor(store: Store) {
    this.userList$ = this.store.select(state => state.userList);
  }
}
```

- コンポーネント内でsubscribeする必要がある場合は、Observable の初期化だけをコンストラクタで行い、subscribeの開始はngOnInit以降にする。
- コンポーネントの初期化より先に値の解決が始まってしまい、変更検知のタイミング制御が困難なり、デバッグしにくくなるため。

https://blog.lacolaco.net/2018/06/angular-strict-property-initialization-best-practice/

#### `Observable`型の変数

末尾に`$`をつける

https://angular.jp/guide/rx-library#observables-%E3%81%AE%E5%91%BD%E5%90%8D%E8%A6%8F%E5%89%87

### `Subject`

#### `asObservable`

- `Service`等で宣言した`Subject`型の変数を他のコンポーネントで使う場合は`asObservable`を使用する。
- `Observable`型の変数では`next`が使えないため、意図せず値が流れることを防ぐことができる

https://moni1091.medium.com/why-asobservable-with-subjects-4ac0a572d93a


### 後々調べたいこと
- メソッド名にonをつけるかの基準

- 真偽値を判定するメソッド名

https://www.kyouikuteki.com/2019/03/bad-code-8.html
Piniaを使ったコンポーネントのテスト

# 環境
Vue3
TypeScript

# 導入

```
npm install --save-dev @pinia/testing
```

# 記述

```typescript
import { setActivePinia, createPinia } from 'pinia'
import { useHogeStore } from 'src/stores/hogeStore'
import { createTestingPinia } from '@pinia/testing'

discribe('hogeComponent', () => {
  beforeEach(() => {
    setActivePinia(createPinia())
  }

 it('hoge test', () => {
    const hogeStoreInit = {hoge: 'hoge', fuga: 'fuga'}
    const wrapper = mount(HogeComponent, {
      global: {
        plugins: [
          createTestingPinia({initialState: hogeStoreInit})
        ]
      }
    }
    const hogeStore = useHogeStore()

    expect(hogeStore.hoge).toBe('hoge')
    expect(hogeStore.fuga).toBe('fuga')
  }
}
```

# 参考
https://pinia.vuejs.org/cookbook/testing.html
社内部活制度でgemのコードリーディング会を実施した話

# 前置き

こんにちは。株式会社Relicのyamashitaというものです。
弊社にはさまざまな部活動がありまして、ruby部、php部、aws部…音楽部、お金部、などなど。。
社員は自由に部活動を選択でき、そのテーマに興味のある仲間と交流しながら技術を高め合う事ができます💡

あ、最後の2つは技術の話ではなかったですね…。失礼しました。


## ruby部について

私は参加してから1ヶ月ほどになります。

週に一度30分ほどの集まりが催され、rubyをテーマにしたお題について議論をするのがデフォルトです。
いまは3名のエンジニアが運営ですが、つよつよなruby大好き業務委託さんも、この勉強会に大いに貢献してくださっています。運営の皆さん、いつもありがとうございますｍｍ


## トライしてみたこと

部活動の話とは別件なのですが、プロジェクト内で既存のテーブルの命名を見直す会をしていたときのこと、
メンターに「たまにはOSSのコードも読んでみるとよいょ」と言われてmastodonのスキーマをほいっと渡されました。
（データの持ち方に応じてどんな命名をしているか勉強になったので、お時間あったら読んでみてください。）
（完全なる余談: IPアドレスを扱っているテーブルの命名が個人的気になりポイント👀）

https://github.com/mastodon/mastodon/blob/main/db/schema.rb

「たまにはGitLabのコードも読んでみるかあ。。」と
rubyを使った有名なOSSのコードを読んでみよう！と思ったのはこれが初めてではなく、それでも一人でやろうとするとちょっと億劫だなあという気持ちが勝ってしまう。。

今回はそういう気持ちをちょっとでも前向きにすべく、ruby部のみなさんにお付き合いいただくことにしました。
普段なかなか気にかけることのない、セッション周りの実装をしているgemを読んでみることにしました。

[request_store]
https://github.com/steveklabnik/request_store

## よかったこと

- rubyだけではなく、言語をまたいでも変わらない技術の背景だったり、仕様を知ることが出来た。
- 読み解けないところは、強い人に質問して読み進めることが出来る。
- 質問する前に自分の解釈を表明することも出来た。（もちろん認識違いについては質問をその場ですることで、解消するように努める）
- テストコードをお題にしたので、gemの仕様が把握しやすかった気がする。

## アジェンダ
だいたい45分程度になりましたが、ざっと以下のような流れです。

- gemのREADMEを読んで、このgemが開発されるに至った背景を知る
- 全ては流石に読み切れないので、一部の気になったファイルだけを読み解くことに集中する

英語についてはDeeplさんを駆使しました！

## 参加者
- 仕事でrubyを書いて1~3年くらいの人たち3人（運営側）
- ruby大好きつよつよ業務委託さん
- Go大好きつよつよさん

## request_storeについて（読み解いた内容の頭出し）
※主観が多く含まれるので、マサカリある方はコメントによろしくお願いします
### README.mdからわかること
- rubyでグローバル変数を使いたくなった時、先人たちはThreadを使用してその中にグローバル変数を定義していた。
- 昨今並行処理の出来るWebサーバーを取り入れることが多く、(ThinやPumaなど)それらとThread.currentの併用は非常に危険。なぜなら値が書き換わらないことがあるから…
- MRIでwebrickを使って実行すると1が出力されるけど、Thinを使うと1, 2, 3…と出力される。

```
def index
  Thread.current[:counter] ||= 0
  Thread.current[:counter] += 1

  render :text => Thread.current[:counter]
end
```
こういった背景があり、値の書き変わらない問題を解消したい！ということで生まれたのがrequest_storeだそうです。

### テストコードからわかること
- 例えばhttps://github.com/steveklabnik/request_store/blob/master/test/middleware_test.rb を例に取ってみる
- setupでは
    - 設定したい値を持っておいてくれる、Storeクラスや、ミドルウェアクラスを初期化している。

- call_middlewareでは
    - プロトコルらしく、設定したい値の状態によってステータスコードとセットにして返している。（これ一般的にはどういう作業なんでしょう…名前があるなら知りたい。）
    - ほかのテストに必要な内容の準備をしているっぽい。ミドルウェアのお仕事という所感。

- test_middleware_resets_storeでは
    - 2回呼ぶことで値の書き換わりのミスがないかテストしている。

- test_middleware_does_not_mutate_response_and_does_not_overflow_stackでは
    - 名の表すとおり、スタックが溢れないことと、設定した値を詰めたオブジェクトは不可変であることをテストしている。

（つづきは別の記事で投稿します💡）


## 課題点

- rubyのコードにそこまで馴染みがない人にとっては、少し苦痛だったかもしれない
    - メタプロ的なことをやっている箇所は、普段のコードの中からは見かけないので、「わからないことがわからない」状態に足を突っ込みかけたのかもしれない

- rubyや技術的な背景に詳しい人が参加してくれなかったら、誤った解釈のまま進んでしまった可能性がある…
    - 今回だと、セッションとはプロトコルである、という前提の知識がなければ読み解けなかったところもあった。
    - 具体例: https://github.com/steveklabnik/request_store/blob/f79bd375e88f434428b876dbb5c8a51b569712aa/test/test_helper.rb#L11
    - この行はなぜAPIチックにレスポンスを返却しているのか、？だらけになっていたと思う。
    - OSIモデルを覚えたときに、セッション層が存在することは知っていたものの、今回の知識に結び付けられなかった無念さがある（個人的反省）

## 改善案
- 部活動の当日に思いついてほいっと始めてしまったので、数日取ってあらかじめコードリーディングしておく。
    - （ざっくりコードのレベルを見積もれるようにする）

- 解釈した内容を書き留めていただけるような、書記さんはいてくれたほうがいいかも？
    - （社内のナレッジ共有ツールで展開して、わからなかったことの復習ができそう）

## おまけ
- 次は実際に読んだgem request_storeの内容を濃い目に共有したいっす
【初学者向け】ディレクトリ構成の基本

:::note info
記事の対象者
プログラミングを学習したての初学者
:::
アプリケーションを作るときに、どのようなディレクトリ構造にすればいいのか、全く分からず困りませんか？
僕はいつも困ってました💦
ググってもググってもあんまりいい回答が得られず、、、
困っていたときに会社の先輩に聞いたところ、基本のキを分かりやすく教えてもらえましたので、今回の記事でまとめてみたいと思います。
なお、僕は機械学習エンジニアを目指しているので、ややその分野よりの話になりますがご承知ください。

## まずは実際のプログラムがどのようなディレクトリ構成になっているかを知る
Windowsであれば、`ローカルディスク> Program Files`の中にインストールした様々なソフトウェアが保存されています。
こちらはGitのディレクトリ構造
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108046/42047179-e8fa-04d6-dfa4-ea2cd619bd29.png)
こちらはPycharmのJetBrainのディレクトリ構造
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108046/1373297e-8408-0db3-d5bb-92cffe65ef8e.png)
こちらはPostgreSQLのディレクトリ構造
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/108046/85a35632-404f-de3a-d430-7e7bd9c0da9c.png)
binとかlibとか、なんだか似たようなものがいくつかあることに気づくと思います。
このように、自分でインストールしたソフトウェアのディレクトリ構造を見てみることで、だいたいどのような構造になっているのかをなんとなく知ることができます。
## ディレクトリ構成の基本
教わったディレクトリ構成の基本を書きます。
```
root
    /bin/
    /src/module/
        /app.py
    /test/
    /config/
    /resources/
    /data/
    /scripts/
    /templates/
    /static/css/
           /js/
```
`bin`
Windowsなら.bat(バッチファイル)、.sh, .bash(シェルファイル)などのプログラムの実行ファイルを置くところ。
`src`
ソースコードを配置するディレクトリ。この直下にコードを置き、自作のパッケージはmodule配下に機能ごとにまとめる。
`test`
テストコードを置くところ。中の構成はsrcと合わせた方が良いらしい。
`config`
アプリケーションの設定ファイルを置くところ、yaml, xmlなど
`resources`
コード以外に利用する画像などを置くところ
`data`
学習用の画像などを置くところ
`scripts`
アプリケーションの動作とは無関係なファイルを置く。データセットを集めるためのスクリプトとか、モデルを学習するためのスクリプトとか。
`templates`
アプリケーションのデザインのためのファイルを置くところ
`static`
CSSやJSファイルを置くところ


言語やウェブアプリケーションフレームワークによってはお作法が決まっているものもあります。
また、様々な考え方があると思いますので、この基本構成が正解、というわけではありません。

ただ、初学者だと何の指針もなくて途方にくれてしまうことがあると思いますので（僕はそうでした💦）
参考にしていただければと！
ONLYOFFICE DocsのLinux版をスナップパッケージからインストールする方法

## はじめに

コミュニティエディションでは、ONLYOFFICE Docsをローカルサーバーにインストールし、オンラインエディタをONLYOFFICEコラボレーションプラットフォームや他の一般的なシステムと連携することができます。

ONLYOFFICE Docsは、テキスト、スプレッドシート、スライドのビューアとエディタからなるオンラインオフィススイートで、Office Open XMLフォーマットと完全な互換性があります。.docx、.xlsx、.pptxに完全対応し、リアルタイムでの共同編集を可能にします。

### 機能概要

* ドキュメントエディタ
* 表計算エディタ
* スライドエディタ
* モバイルWebビューアー
* 共同編集機能
* すべての一般的な形式をサポート：doc, docx, txt, odt, rtf, odp, epub, ods, xls, xlsx, csv, pptx, html

**ONLYOFFICE Groups**と連携することで、以下のようなことが可能になります。

* ファイルの共有
* ドキュメントへのアクセス権管理
* Webサイトにドキュメントを埋め込む
* ONLYOFFICEに接続されたDrive、Box、Dropbox、OneDrive、OwnCloudに保存されたファイルの閲覧・編集

:::note warn
ONLYOFFICE DocsとONLYOFFICE Groupsを併用する場合、2つのマシンにインストールする必要があります
:::

本ガイドでは、**ONLYOFFICE Docsコミュニティエディション**のLinux版を、スナップパッケージからお使いのマシンにインストールする方法をご紹介します。

## SnapcraftコマンドラインツールによるONLYOFFICE Docsのインストール

ONLYOFFICE Docsは、スナップパッケージとして[Snapcraftストア](https://snapcraft.io/onlyoffice-ds)で入手可能です。

スナップは、アプリケーションを実行するためのすべての依存関係を含んでいます。これを利用するために必要なのは、スナップをインストールし管理するシステムである**snapd**です。**Snapd**は、最近のディストリビューションのほとんどに含まれています。**Snapd**を有効にするか、インストールするかのどちらかだけです。**Snapd**のインストール方法については、snapプロジェクトの[公式ページ](https://docs.snapcraft.io/core/install)を参照してください。

１．例えば、Ubuntuで**snapd**をインストールするには、以下のコマンドを実行する必要があります。
```
sudo apt update
sudo apt install snapd
```
２．これでONLYOFFICE Docsは、以下のコマンドで簡単にインストールできるようになります。
```
sudo snap install onlyoffice-ds
```
## ONLYOFFICE Docsのアンインストールについて

ONLYOFFICE Docsを含むスナップを削除するには、以下のコマンドを使用します。
```
sudo snap remove onlyoffice-ds
```
input type="date" iOSの日付入力のクリアボタンが機能しない

<h2>初めに</h2>

<p>

webアプリをReactで作成していまして、` input type ="date" `を使用して日付の値を取得していたのですが、PCだと削除ボタンが機能し、iosだと機能しないという現象がおこりました。
解決するのに時間がかかりましたので忘記録です。
</p>

<h2>解決したコード</h2>


```react:app.jsx

import React,{useState} from 'react';

export default function App(props) {
  // 日付の値を格納する 
  const [inputDate, setInputDate] = useState({ date: "" });

  // 日付の値を取得する処理
  const handleOnChange = (e)=>{
    const target = e.target;
    const { name } = target;
    const { value } = target;
    //日付のセット
    setInputDate({
      ...inputDate,
      [name]: value,
    });
    
    // ios時に削除を押下された時に機能させる処理 
    // 機能するにはsetTimeoutが必要で、少しの遅延が必要です
    setTimeout(()=>{
      target.defaultValue = "";
    }, 100);
  }
  
  return (
     <div>
        <input 
          type="date" 
          name="date"
          value={inputDate.date} 
          onChange={handleOnChange}
          />
      </div>
  );
}




```


<p>

上記のコードで削除機能は動きます。大事な部分は`onChange`イベント処理の`setTimeout`を使用しているところです。

</p>

<h2>まとめ</h2>

<p>

実際にconsole.logで確認してないのではっきりとわかりませんが、iosで削除機能が機能しない理由は`value`を書き換える処理の時に`defaultValue`も書き換えられたのではないかと思います。(defaultValueのがvalueよりも優先して見られる。)
また`value`と書き換えタイミングが一緒なので、遅延で削除処理をいれないと機能しないのかもしれませんね。
ただ、解決して何よりです！
</p>

参考:[iOSの日付入力のクリアボタンが正しいイベント値を返さない](https://github.com/facebook/react/issues/8938)
Dockerfileのコマンドでjupyter labを起動する方法

dockerを用いてJupyterLabを起動させる際のコマンドについて調べたため、記述しておく。


```
CMD ["jupyter", "lab", "--ip=0.0.0.0", "--port=8888", "--allow-root", "--LabApp.token=''"]
```

# コマンドの説明
"jupyter", "lab",　・・・JupyterLabの起動。
"--ip=0.0.0.0",　 ・・・IPアドレスをローカルホストに指定。
"--allow-root",　・・・JupyterLabはデフォルトではrootユーザでの実行はNGのため、rootで実行できるよう設定。
"--LabApp.token=''"　・・・通常は、JupyterLabを起動する際にパスワードを設定するが、その際にトークンを必要とする。今回は必要なかったため、トークンを指定していない。
あるファイルが更新されたか調べて通知する

他人が管理してるあるファイルで、更新されたら連絡もらってあれこれ対応する、という仕事がある。頻度は高くない。が、更新されたらやらなければならない。

連絡もらってやりとりるすのがめんどくさい。更新チェックを自動化しよう。

# 必要な要素
- 更新されたかどうかの判断…タイムスタンプ。
- 通知方法…無難にメール。
- 定期チェックの方法…Windowsのタスクスケジューラでいいか。

## ファイル情報取得
```powershell
# 更新をチェックしたいファイルの情報取得
$Target_Property = Get-ItemProperty ".\Target.txt"
```
`$Target_Property.LastWriteTime.ToString()`でタイムスタンプをテキストで取得できる。

## 前回の更新日を取得
これは別ファイルに持っておく。
```:Target_Update_Record.txt
2022/07/10 00:00:00
2022/07/11 11:11:11
2022/07/12 22:22:22
2022/07/14 10:00:00
```

```powershell
# 前回の更新日を読み込む
$Target_PreviousUpdateDate = Get-Content ".\Target_Update_Record.txt" -Tail 1
```
`Get-Content -Tail 1`は最終行が空行だった場合無視してその1行前を読んでくれるのでありがたい。

## タイムスタンプと前回の更新日を比較
```powershell
if( $Target_Property.LastWriteTime.ToString() -eq $Target_PreviousUpdateDate ){
    # 更新されてない
}else{
    # 更新されてる
}
```

# 完成
```powershell
# あるファイルの更新をチェックして通知する

# スクリプトフォルダへ移動
$ScriptPath = Split-Path -Parent $MyInvocation.MyCommand.Path
Set-Location $ScriptPath

# 更新をチェックしたいファイルの情報取得
$Target_Property = Get-ItemProperty ".\Target.txt"

# 前回の更新日を読み込む
$Target_PreviousUpdateDate = Get-Content ".\Target_Update_Record.txt" -Tail 1

# 更新されているかチェック
if( $Target_Property.LastWriteTime.ToString() -eq $Target_PreviousUpdateDate ){
    # 更新されてない
    # 更新されてないことをログ記録したり通知したり 省略
}else{
    # 更新されてる
    # メール通知する
    $MailParam = @{
      from     = "checker@example.com"
      to       = "me@example.com"
      smtp     = "mailserver.example.com"
      subject  = "ターゲットが更新された"
      body     = "T/O"
      Encoding = ([System.Text.Encoding]::UTF8)
    }
    Send-MailMessage @MailParam

    # 更新された日付を書き込む
    $Target_Property.LastWriteTime.ToString() | Out-File -LiteralPath ".\Target_Update_Record.txt" -Encoding default -Append

    # 対応するあれこれ、が自動化できるならそれも記述
}
```

# 最も良い解決は…
管理してるそいつにすべての対応をしてもらうよう政治的な解決を図る。
できないので、現状を追認する…。
LINE Notify で天気予報を通知する

## LINE Notify アクセストークンを発行する

次のページを参考に「アクセストークン」を取得する。

https://firestorage.jp/business/line-notify/


## API を確認する

**通知系**

https://notify-bot.line.me/doc/ja/


## Python実装

token = "アクセストークン" のところは、先ほど取得した自身のアクセストークンに変える。

```python3
!pip install BeautifulSoup4
from bs4 import BeautifulSoup
import requests
import datetime
import locale

## 日付取得 
locale.setlocale(locale.LC_TIME, 'ja_JP.UTF-8')
today_date = datetime.date.today()
tomorrow_date = today_date + datetime.timedelta(days=1)
today_date_format = "{0:%Y年%m月%d日}".format(today_date)
today_strftime = today_date.strftime('%a')
tomorrow_date_format = "{0:%Y年%m月%d日}".format(tomorrow_date)
tomorrow_strftime = tomorrow_date.strftime('%a')

## 天気のページを取得
weather_url = "https://weather.yahoo.co.jp/weather/jp/13/4410.html"
response = requests.get(weather_url)
html = BeautifulSoup(response.text, "html.parser")
forecastcity = html.find_all("div", attrs={"class":"forecastCity"})[0]

## 今日の天気
today = forecastcity.find_all("div")[0]
today_weather = today.find_all("p", attrs ={"class" :  "pict"})[0].text.replace("\n","").replace(" ","")
today_high = today.find_all("li")[0].text
today_low = today.find_all("li")[1].text
today.find_all("td")
today_rain_06 = today.find_all("td")[4].text
today_rain_12 = today.find_all("td")[5].text
today_rain_18 = today.find_all("td")[6].text
today_rain_24 = today.find_all("td")[7].text

## 明日の天気
tomorrow = forecastcity.find_all("div")[1]
tomorrow_weather = tomorrow.find_all("p", attrs ={"class" :  "pict"})[0].text.replace("\n","").replace(" ","")
tomorrow_high = tomorrow.find_all("li")[0].text
tomorrow_low = tomorrow.find_all("li")[1].text
tomorrow.find_all("td")
tomorrow_rain_06 = tomorrow.find_all("td")[4].text
tomorrow_rain_12 = tomorrow.find_all("td")[5].text
tomorrow_rain_18 = tomorrow.find_all("td")[6].text
tomorrow_rain_24 = tomorrow.find_all("td")[7].text

## 今日の天気のメッセージ
today_message="""
今日{}({})の天気は{}
最高気温は{}、最低気温は{}
降水確率は、0-6時:{}、6-12時:{}、12-18時:{}、18-24時:{}
""".format(today_date_format, today_strftime, today_weather, today_high, today_low, today_rain_06, today_rain_12, today_rain_18, today_rain_24)

## 明日の天気のメッセージ
tomorrow_message="""
明日{}({})の天気は{}
最高気温は{}、最低気温は{}
降水確率は、0-6時:{}、6-12時:{}、12-18時:{}、18-24時:{}
""".format(tomorrow_date_format, tomorrow_strftime, tomorrow_weather, tomorrow_high, tomorrow_low, tomorrow_rain_06, tomorrow_rain_12, tomorrow_rain_18, tomorrow_rain_24)

token = "アクセストークン"
url = "https://notify-api.line.me/api/notify"
auth = {"Authorization":"Bearer "+token}
content = {"message" : today_message + tomorrow_message}
requests.post(url, headers=auth, data=content)
```
GitHub ActionsでPersonal Access Tokenを使って他のリポジトリにpushする

## はじめに
- Github Appsでtoken発行した方が安全でイケてる
https://dev.classmethod.jp/articles/getting-an-access-token-with-only-the-necessary-permissions-on-github-appsgithub-actions/

全力で首を縦に振るのですが、その前にGithub Actions自体のテストや、
単純な最小構成でとりあえず他リポジトリにpushしたいと思った時に、
何故かPersonal Access Tokenでのやり方が全然見つからなかったのでこの記事を書きました。
英語はちゃんと読んでいません。

## 筆者のスキルレベル
Github Actions触り始めて3日。
Githubは半年くらい弄ったけどよく知らない。
Gitコマンドは3年くらい触ってる。

色々と勘違いしている可能性があります。
よろしくお願いします。

## Github Actionsで他のパブリックリポジトリ操作（失敗まで）
Github Actionsを動かすリポジトリ「testrep」から、別のリポジトリ「pulltestrep」を操作したい。

### clone
ここではactions/checkout@v2を利用します。

``` wftest.yaml
      - name: Checkout other repo
        uses: actions/checkout@v2
        with:
          repository: ridia/pulltestrep
          path: pulltestrep
```

### commit, push
そのままgitコマンドでコミットユーザを指定し、コミットします。

``` wftest.yaml
      - name: pull test result
        run: |
          touch newfile.txt
          git config --local user.email "ridia@eario.jp"
          git config --local user.name "ridia"
          git add .
          git commit -m "auto commit test"
          git push
```

### Github Actionsの実行結果でエラーが出る
怒られた。403なので権限がないらしい。つまり権限があればpushできる。

```
[main e17a5bf] auto commit test
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 newfile.txt
remote: Permission to ridia/pulltestrep.git denied to github-actions[bot].
fatal: unable to access 'https://github.com/ridia/pulltestrep/': The requested URL returned error: 403
Error: Process completed with exit code 128.
```

## Personal Access Tokenで権限を付ける
今回はタイトル通り、Personal Access Tokenを利用します。

### 発行
ここで Generate new tokenして作ります。
https://github.com/settings/tokens
Settings -> Developer Settings -> Personal access tokens

Noteはトークンの名前、Expirationは有効期限です。
無期限も指定できますが強く推奨されないのでやめておいた方がいいでしょう。

Select scopesは、リポジトリ操作を行うのでrepoにチェックを入れておきます。
※細かい権限設定はきちんと理解していません

### 登録
作ったトークンはリポジトリに登録します。
登録するのはGithub Actionsを動かすリポジトリ、つまり「testrep」です。
testrepのSettings、Secrets、Actionsと辿ってNew Repository Secretsから登録します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/367481/59da53e5-f309-8afb-5238-faef35f0f500.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/367481/29ebfb31-31cd-4001-eb99-ca738523cc9b.png)
↑画像のValueは適当

### トークンの利用
どこで登録したトークンを利用するかというと、Github Actionsで利用します。
簡単なのはactions/checkout@v2の利用時に指定します。

``` wftest.yaml
      - name: Checkout other repo
        uses: actions/checkout@v2
        with:
          repository: ridia/pulltestrep
          token: ${{ secrets.PERSONAL_ACCESS_TOKEN }}
          path: pulltestrep
```

パブリックリポジトリへのpushは以上です。

## Github Actionsで他のプライベートリポジトリ操作
プライベートだと何が違うのかと言うと、適切な権限を持つPersonal Access Tokenを
利用するのであれば何も変わりません。
ただ、Personal Access Tokenを登録する前に出るエラーが変わります。
プライベートリポジトリなので、アクセストークンがなければリポジトリが見つからず、
Not Foundエラーが出ます。

## 最後に
これはあくまでPersonal Access Tokenを利用した場合のHow toですので、
初めに書いた通り、Github Appsを利用した方がセキュアであると思われます。
私はこれから試す予定です。
画像のデータセットを最も楽に作る方法【Pytorch】

Pytorchの学習の大まかな学習の流れは、
1. Datasetを作る
2. DatasetをDataloaderに取り込む
3. 学習する

Datasetさえできていれば2はかなり簡単で1行で完結します。
```python
dataloader = torch.utils.data.DataLoader(dataset=dataset, batch_size=10000, shuffle=True)
```

一方、Datasetの作り方は記事を検索してもなかなか出てこず苦労しました。
そんなわけで、Pytorchで『最も簡単に』データセットを作成する方法を解説します。
ものすごく簡単でした。簡単すぎるからあまり記事が出てこなかったのかもしれません。
## ImageFolderで一発で作れる
Datasetは`torchvision.datasets.ImageFolder`で一発で作れます。
猫の画像と犬の画像を分類したい場合を考えます。以下のようにディレクトリを作ります。
### ディレクトリ構成
```
root/
├ data/
│   ├ train/
│   │   ├ cat/
│   │   │   ├ cat01_train.jpg
│   │   │   ・・・
│   │   └ dog/
│   │       ├ dog01_train.jpg
│   │       ・・・
│   └ val/
│       ├ cat/
│       │   ├ cat01_val.jpg
│       │   ・・・
│       └ dog/
│           ├ dog01_val.jpg
│           ・・・
model.py
```
train用のフォルダとvalidation用のフォルダを作り、その中に、分類したい画像を格納します。
準備はこれだけ！
あとはmodel.pyでデータセットを作るコードを定義します。

```model.py
import torch
import torchvision
from torchvision import transforms

# image_sizeやmean, stdはデータに合わせて設定してください。
image_size = 224
mean = (0.485, 0.456, 0.406)
std = (0.229, 0.224, 0.225)

# trainデータとvalidationデータが入っているディレクトリのパスを指定
train_image_dir = './data/train'
val_image_dir = './data/val'

# trainデータ向けとvalidationデータ向けに、transformを用意します。
# 皆さんのやりたいことに合わせて適宜変更してください。
data_transform = {
    'train': transforms.Compose([
        transforms.RandomResizedCrop(
            image_size, scale=(0.5, 1.0)
        ),
        transforms.RandomHorizontalFlip(),
        transforms.RandomRotation(degrees=[-15, 15]),
        transforms.ToTensor(),
        transforms.Normalize(mean, std),
        transforms.RandomErasing(0.5),
    ]),
    'val': transforms.Compose([
        transforms.Resize(image_size),
        transforms.CenterCrop(image_size),
        transforms.ToTensor(),
        transforms.Normalize(mean, std)
    ])
}

# torchvision.datasets.ImageFolderでデータの入っているディレクトリのパスと
# transformを指定してあげるだけ。
train_dataset = torchvision.datasets.ImageFolder(root=train_image_dir, transform=data_transform['train'])
val_dataset = torchvision.datasets.ImageFolder(root=val_image_dir, transform=data_transform['val'])

# Datasetができたら、dataloaderに渡してあげればOK
batch_size = 32
train_dataLoader = torch.utils.data.DataLoader(
    train_dataset, batch_size=batch_size, shuffle=True
)
val_dataLoader = torch.utils.data.DataLoader(
    val_dataset, batch_size=batch_size, shuffle=False
)

# 以降はモデルを設定して学習・・・（割愛）
```
データセットを作っているのはこの数行です。
```python
train_dataset = torchvision.datasets.ImageFolder(root=train_image_dir, transform=data_transform['train'])
val_dataset = torchvision.datasets.ImageFolder(root=val_image_dir, transform=data_transform['val'])
```
たったこれだけで画像のデータセットを自作できます。

ImageFolderを使わないと、Datasetクラスを自分で定義してうんぬんかんぬん、、、とかなり手間のかかることをやらなければいけません。
ですが、この方法だと一発で作れるのでぜひ試してみてください。
AWS SDKのListObjectsV2でxmlParseCharRefエラー

タイトルだけ見てもさっぱり何のことかわからないかもですが、S3のオブジェクト一覧をとるAPIであるListObjectV2での出すこのエラーでえらいハマったので誰かのお役に立てばと思い投稿しました。

以下、コードはrubyです。

# 基本的な使い方
まず、sampleバケットに下記のようなオブジェクトがあるとします。
```
sample/
     ├ aaa/
         ├ aaa1/
         └ aaa2.txt
         └ aaa3.txt
     ├ bbb
         ├ bbb1
         └ bbb2
     └ ccc.txt
```
この時、バケットだけを指定するとsampleバケットのすべてのオブジェクト一覧が取得できます。
```
# s3はAws::S3::Clientのオブジェクト
res = s3.list_objects_v2({bucket: 'sample'})
res.contents.each do |k|
  p k.key
end

出力
aaa/
aaa/aaa1
aaa/aaa2.txt
aaa/aaa3.txt
bbb/
bbb/bbb1/
bbb/bbb2/
ccc.txt
```
では、aaaフォルダのオブジェクト一覧を取得するためにprefixを指定してみましょう。
```
res = s3.list_objects_v2({bucket: 'sample', prefix: 'aaa'})
res.contents.each do |k|
  p k.key
end

出力
aaa/
aaa/aaa1
aaa/aaa2.txt
aaa/aaa3.txt
```
S3ではフォルダという概念はないのですが、aaaフォルダ以下のオブジェクト一覧が取得できました。
逆に、拡張子がtxtのオブジェクト一覧を取得するためにdelimiterを指定してみましょう。
公式の文書の例だと「/」とかで、区切り文字じゃないとダメなのかと一瞬思いますが、「.txt」のように文字列を指定しても大丈夫です。
```
res = s3.list_objects_v2({bucket: 'sample', delimiter: '.txt'})
res.contents.each do |k|
  p k.key
end

出力
aaa/aaa2.txt
aaa/aaa3.txt
ccc.txt
```
このように拡張子を指定してオブジェクトの一覧を取得できます。
もちろん両方をあわせて「aaaフォルダのtxtファイル」という指定もできます。
```
res = s3.list_objects_v2({bucket: 'sample', prefix: 'aaa', delimiter: '.txt'})
res.contents.each do |k|
  p k.key
end

出力
aaa/aaa2.txt
aaa/aaa3.txt
```

# 唐突にエラーが...
以上、なんの問題もなく基本的な操作はできたのですが、なぜかとある検索をした時に「xmlParseCharRef: invalid xmlChar value 8」というエラーが出ました。
今回、不思議だったのはここでエラーだけ見ると何かXMLのパースに失敗している様子。
ただ、どんなにググっても有力な情報が見つからないので自力でエラーになっているオブジェクトを特定したところ、**機種依存文字**が含まれたキーを持つオブジェクトがありました...
しかも、S3の画面上では表示されず特定にものすごい時間がかかりました。

というわけで、どなたが同じエラーで困った時に参考になれば幸いです。

**参考にしたサイト**
・ListObjectV2のAPIドキュメント
https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListObjectsV2.html#API_ListObjectsV2_RequestSyntax
・機種依存文字チェッカー
https://form.submitmail.jp/tools/check/
anacondaの仮想環境が切り替わらない


環境

conda 4.11.0
Python 3.9.7
Windows 10


## 事象：Anacondaで作成した仮想環境に入れない

```powershell
> conda create --name venv python=x.x
> conda info -e 
# conda environments
# 
base                  *  C:\Users\xxxx\anaconda3
venv                     C:\Users\xxxx\anaconda3\envs\venv

> conda activate venv
# conda environments
# 
base                  *  C:\Users\xxxx\anaconda3
venv                     C:\Users\xxxx\anaconda3\envs\venv
```
このように、エラーが何も出ないにも関わらず、仮想環境が切り替わらない。
[この記事](https://qiita.com/nabehide/items/097553ccd51543ee31fb)を参考に以下のコマンドを試してみたが駄目だった。

```powershell
conda install -n root -c pscondaenvs pscondaenvs
```

解決策：コマンドプロンプトをターミナルに設定
解決策と言っていいのかは不明ですが、Powershellではなく、コマンドプロンプトに切り替えたら、うまくできました。

```powershell
> conda activate venv

> conda info -e
# conda environments:
#
base                     C:\Users\Kohei Okamoto\anaconda3
venv                  *  C:\Users\Kohei Okamoto\anaconda3\envs\venv
```

powershellで切り替えられるようにする方法もそのうち試したい。
ロググループ > ログストリームのDatadog MonitorをTerraformで作成

## What's This
ログストリーム単位でDatadog MonitorをTerraformコードで作成した時があったので、その時のメモです。
あくまでメモなので、参考にされる場合は、公式ドキュメント等の副読的な感じで読まれると幸いです。

## バージョン情報

```
$ terraform version
Terraform v0.12.0
+ provider.datadog v2.25.0
```

## コード

自分が構築時に気になっていたのは、以下でした。

```
・クエリをどう書くか
・記載が必須なものは何か
```

ダウンタイムの設定や、タグの設定、閾値など、ご希望の値に置き換えていただけたらいいのかなと思います。

```
resource "datadog_monitor" "ec2-error-test" {
  name                = "ec2-error-test"
  new_host_delay      = 0
  no_data_timeframe   = 0
  notify_audit        = false
  notify_no_data      = false
  priority            = 0
  query               = "logs(\"@aws.awslogs.logStream:ec2-error-test\").index(\"*\").rollup(\"count\").by(\"@aws.awslogs.logGroup,@aws.awslogs.logStream\").last(\"5m\") \u003e= 1"
  renotify_interval   = 0
  require_full_window = false
  restricted_roles    = []
  silenced = {
    "*" : 0
  }
  tags              = []
  threshold_windows = null
  thresholds        = null
  timeout_h         = 0
  type              = "log alert"
  validate          = null
  message           = "message"
}
```

## 備考①
ちなみに、

```
\"@aws.awslogs.logStream:ec2-error-test\"
```

についてですが、ここのログストリームの指定は、AWSで作成していないログストリームも指定することができます。

## 備考②
ちなみに、

```
\"@aws.awslogs.logStream:ec2-error-test 検知したい文字列\"
```

とすることで、ログストリームec2-error-test内で、検知したい文字列が発生した場合、それのみを検知するモニターにすることができます。

検知したい文字列:crit
![スクリーンショット 2022-07-13 16.18.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1740345/267b6279-5f2d-5fd2-64a4-76605ce4fcbb.png)

検知したい文字列:emerg
![スクリーンショット 2022-07-13 16.18.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1740345/ca41f093-8a17-8620-ebea-69b467d4af8b.png)

## Reference
・https://docs.datadoghq.com/ja/logs/logs_to_metrics/
・https://www.datadoghq.com/ja/blog/amazon-cloudwatch-metric-streams-datadog/
・https://registry.terraform.io/providers/DataDog/datadog/latest/docs/resources/monitor
【Swift】UIの階層を確認する

# はじめに
めっちゃ最近知った便利な機能「View UI Hierarchy」をちょっと調べてみました。

最近作った[こちら](https://github.com/SNQ-2001/FontAwesome-Swift)のサンプルアプリで試してみます。

# 表示方法
アプリをビルドします。
![スクリーンショット 2022-07-14 16.38.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/8f90c2d8-6d9c-13d3-5f28-a5e800b91c62.png)
① スプレーのようなアイコンを選択します。
② 縦３本線のアイコンを選択します。
![スクリーンショット 2022-07-14 16.39.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/26ae0722-b489-3bfe-8ed0-f5394cad5b2e.png)
「View UI Hierarchy」を選択します。
![スクリーンショット 2022-07-14 16.41.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/6c55387d-6ee4-6ee0-2991-e703d13bf5b1.png)

表示されました。
![スクリーンショット 2022-07-14 16.43.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/11fff337-3757-7594-0bc8-1ec2bd70599b.png)

# 立体にする
## 自動
立方体アイコンのボタンを押すと自動で立体になります。
![スクリーンショット 2022-07-14 16.50.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/6ac92c80-a06c-239d-d6e2-b34c10f9e5b5.png)

## 手動
左下のスライダーを右にスライドすると立体になります。
![スクリーンショット 2022-07-14 16.45.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/1ca3782c-0c00-894b-540a-448bf1d8374b.png)

# 階層ごとに表示
右下のスライダーを左にスライドすると上位の階層が非表示になります。
![スクリーンショット 2022-07-14 16.47.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/80bd9b8b-9055-25f4-b72a-6b21c80d7ef0.png)

# おわり
他にも機能がありますがよく理解してないので紹介するのはやめておきます笑
Rubyのバージョン管理とアップグレード時の注意点

# Ruby のバージョン管理やアップグレード

Ruby のバージョンは毎年 12 月 25 日に新しいバージョンが公開される（3.0.1 → 3.1.0 みたいなアップデートバージョンの公開。もっと細かいバージョンは都度出ている）

その時に Ruby のバージョンアップをするが、そのままアップグレードしてしまうと今まで書いたプログラムが急に動かなくなったりすることもある

なので、 `rbenv` というものを使って、使用する Ruby のバージョンを管理する必要がある

まず brew の rbenv をインストールする

```zsh
$ brew install rbenv
```

既にインストールしているときは、Ruby のバージョンを上げるのに新しい rbenv が必要になるので、以下のコマンドで rbenv （ インストールしてる brew 全部）のアップデートをする

```zsh
$ brew update
```

インストールできる Ruby のバージョンを確認する

```zsh
$ rbenv install -l
```

Ruby のアップデートを install するために、 `ruby-build` のアップデートをする

```zsh
$ brew upgrade ruby-build
```

Ruby のアップデートをする（Mac 上で選択できる ruby のバージョンを install）

```zsh
$ rbenv install 3.0.3
```

使用する Ruby のバージョンを変更する

```zsh
$ rbenv global 3.0.3 # Mac上で動かすリポジトリ全部でdefaultで動かすバージョンの指定
$ rbenv local 3.0.3 # コマンドを打った時にいたリポジトリで使うバージョンの指定
```

これで Ruby の version が適用できたかどうかは、いつも通り `$ ruby -v` で今いる Ruby の version の確認をすれば OK！

バージョンアップがあることとかを考えると、test が書いてあった方が、test を実行するだけですぐに動作の保証ができて楽

また、 Ruby の version up 後はその version の Ruby は gem の内容を知らないので、改めて `$ bundle install` をしてあげる必要がある

## ローカルでの Ruby バージョン指定のされ方と変更の仕方

`$ rbenv local 3.0.3` を打つと、そのコマンドを打ったルートに `.ruby-version` が作成され、その中に version 情報が書かれる

また、 `$ rails new` した時でも、今は default で `.ruby-version` が作成されるようになっている

![CleanShot 2021-12-10 at 08 03 39](https://user-images.githubusercontent.com/80931544/145489565-76746219-c204-4748-946d-198f7e758360.png)

このファイルのあるリポジトリを動かそうとすると、rbenv がその version の Ruby を有効化して、その version の Ruby でそのプログラムを実行してくれる

Gemfile の中にも、Ruby や Rails の version 情報を書くことができる

![CleanShot 2021-12-10 at 08 09 44](https://user-images.githubusercontent.com/80931544/145490211-ad25f437-b5cb-4e69-a5c0-941b0fdf2411.png)

こうやって version を指定して書いておけば、 `$ bundle install` で以下のように読み込むことができる

![CleanShot 2021-12-10 at 08 08 42](https://user-images.githubusercontent.com/80931544/145490037-cca537f1-b359-451d-b292-5779bd708750.png)

![CleanShot 2021-12-10 at 08 09 23](https://user-images.githubusercontent.com/80931544/145490168-b9abaf55-baf4-4110-9380-2e244712808b.png)

`.ruby-version` に Ruby の version が 2.7 系って書いてあるのに Gemfile には Ruby の version は 3.0 系って書いてあると、Gemfile で指定している version（= これを使うと宣言している version）と使っている version が違うっていうエラーが起こる

![CleanShot 2021-12-10 at 08 15 53](https://user-images.githubusercontent.com/80931544/145490668-ceb13e8a-36cd-4756-a8bf-0927af25e536.png)

複数人で開発を行うときは、Gemfile に version を明記しておいた方がいい（Gemfile に書いてあれば、そこを見るだけで使っている様々なものの version がすぐにわかる）

# Ruby の version を上げる際に、version を固定しておいた方がいいもの

rails と postgresql は特にちゃんと明記しておくべき

Rails は version が変わると仕様が大きく変わるので動作チェックしながら慎重に version up すべきだし、仕様が大きく変わるのでちゃんと誰でもわかる状態にしておくべき

postgresql は自分の手元に入っている brew の version とリポジトリで使う postgresql の version が合わないと動かなくなるので、これもちゃんと誰でもわかるように書いておくべき

また、rails と postgresql に関しては、そういった理由もあるので Ruby の version を上げる時に影響しないように、Gemfile にそもそも version を書いておいて固定するべき

carrierwave とか、あとから自分で入れた上であえて version を指定してるものはそのまま version 指定しておく

なるべくならあえて version 指定するものに関しては version 指定する理由をわかるように書いておくべき

その他の gem は、特に指定せずに Gemfile に書いておき、 `bundle update` する
【JavaScript】ヘッダー position:fixed 要素が下に入り込んでしまう件


headerをfixedで固定すると、header以下の要素が下に入り込んでしまいます。
今回はスタイルシートにmargin-topをベタ書きするのではなく、JSで書いてみました。

```js
const header = document.querySelector('header');
const headerHeight = header.offsetHeight;
const main = document.querySelector("main");
main.style.marginTop = `${headerHeight}px`;
```
Rails バリデーションと制約の違い（初心者向け）

# 結論
制約とバリデーションの違いは __空文字が許されるか否か__ 。
`Not null制約`     :空文字 :o:
`presence: true`   :空文字 :x:

`Not null制約`だけでは、データベースに空文字が保存されてしまう。

# Q:制約とかバリデーションって何？
A:_アプリ制作で投稿フォームからの`空文字`や未記入`null`を防ぐため必要なシステムのこと。_
データベースにおいて`null`は __特殊な扱い__ を受けるらしく不要なトラブルを避けるためにもこのシステムが採用されることが多いらしい。

https://style.potepan.com/articles/21972.html

__Q:そもそも制約（constraint）とはどんな意味？__
A:_`constraint`:制約、ある条件を付けて完全な自由にさせないこと、窮屈、強制　という意味
`Rails`においては、`テーブルのカラム`や`データ`に制限を加え、 __想定通りの値__ が入るようにすること。_

__Q:そもそもバリデーション(validation)とはどんな意味？__
A:_`validation`:確認、検証　という意味
`Rails`においては、ある`データ`を本当に`データベース`に保存していいのか検証するシステムのこと。_
PowerAutomate「ファイル メタデータの取得」でエラー「BadRequest - Invalid URL」

PowerAutomateのワークフローからSharePoint上のファイルを操作する際、しばしば利用することになるのが「ファイル メタデータの取得」アクションです。
この「ファイル メタデータの取得」アクションはSharePointサイト上のファイルを指し示す識別子（Identifier）を引数にして、ファイルの表示名その他各種のメタデータを取得するものです。
今回はそのアクションの利用中に起きた問題のトラブルシューティングです。

# Problem

「ファイル メタデータの取得」を利用してファイルのメタデータを取得しているワークフローがあり、
あるファイルについては問題なく動いていたのですが、特定のファイルについてはエラーになってしまいました。
引数に指定している識別子はエンコーディング済みのものなので、不正な文字の混入が原因ではないと判断しました。

エラーのステータスコードは400。
メッセージは「Bad Request - Invalid URL」。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50571/04fea81e-7009-bcf0-49e9-da1368559355.png)

```html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
<HTML><HEAD><TITLE>Bad Request</TITLE>
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
<BODY><h2>Bad Request - Invalid URL</h2>
<hr><p>HTTP Error 400. The request URL is invalid.</p>
</BODY></HTML>
```

```json
{
    "statusCode": 400,
    "headers": {
        "Connection": "close",
        "Date": "Thu, 14 Jul 2022 06:56:00 GMT",
        "Content-Length": "324",
        "Content-Type": "text/html; charset=us-ascii"
    },
    "body": "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\"\"http://www.w3.org/TR/html4/strict.dtd\">\r\n<HTML><HEAD><TITLE>Bad Request</TITLE>\r\n<META HTTP-EQUIV=\"Content-Type\" Content=\"text/html; charset=us-ascii\"></HEAD>\r\n<BODY><h2>Bad Request - Invalid URL</h2>\r\n<hr><p>HTTP Error 400. The request URL is invalid.</p>\r\n</BODY></HTML>\r\n"
}
```

# Solution

この問題はファイルの識別子（Identifier）の文字数が一定数以上になると起きる問題のようです。
別のアクションについて[同様の問題が発生したことを報告](https://qiita.com/baku2san/items/cc374b14372e6da27bfc)してくださっている記事があります。

実際に問題になった識別子とそれ以外の識別子を比べるとたしかに文字数が異なっています：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/50571/fda5b0d1-096b-33e6-6b60-8d15c41b0a15.png)

この問題の対策としては：
* 「パスによるファイル メタデータの取得」アクションに差し替える
* ファイル名を短くする（ファイル名を短くすると識別子も短くなる） 

今回は1つ目を採用。
「パスによるファイル メタデータの取得」アクションを利用するようにワークフローを修正してエラーを解消させました。
Excel複数シートを指定した倍率設定

Excel複数シートを指定した倍率設定、かつ、A1セルにカーソルを移動する
```vb
Sub formatDisplay100AndGotoA1()
    Dim s As Object
    For Each s In ActiveWorkbook.Sheets
        s.Activate
        ActiveSheet.Range("A1").Select
        ActiveWindow.Zoom = 100
    Next s
 Sheets(1).Select
 MsgBox (Sheets.Count & " Sheets" & vbCrLf & " done")
End Sub
```
Pythonのisnumeric()の挙動を知らなかった件

# はじめに

https://twitter.com/pythonist19/status/1547055524427878400?s=21&t=PNr_cYPm_ym3VMViniYtDA

え！知らなかったデス😨
というわけで、いろいろな文字を調べてみました。

# 試した数値 
|式|真偽|備考|感情|
|----|----|----|----|
|"1".isnumeric()|True|半角数字|😇|
|"1.2".isnumeric()|False|半角数字小数|😇|
|"１".isnumeric()|True|全角数字|😲|
|"一".isnumeric()|True|漢数字|🧐|
|"壱".isnumeric()|True|大字|🧐|
|"①".isnumeric()|True|丸数字|🥹|
|"❶".isnumeric()|True|丸数字（塗りつぶし)|🥹|
|"⑴".isnumeric()|True|カッコ数字|🥹|
|"Ⅰ".isnumeric()|True|ローマ数字|🥹|
|"¼".isnumeric()|True|1/4|😱|
|"٧".isnumeric()|True|アラビア数字|😱|


# 最後に
こんな文字もisnumeric()がTrueを返すよっていうのがありましたら、コメントで教えてください🤗
PythonのloggingモジュールでシスログにNOTICEレベルのログを出力する方法

PythonをLinux環境で使用していて、ログをLinuxのシステムログに出力したいと思ったことがありました。
しかし、Linuxで使用できるNOTICEレベルのログを出力できない等、実環境で使うのに少し不便に思うことがあったので、使いやすいようカスタマイズすることにしました。

この記事では、loggingモジュールを使ってログをLinuxのシステムログに出力する方法と、ログレベルNOTICEを追加する方法を紹介します。

# Python Logger Class

printでコンソールにメッセージを出力してもいいけれど、システムログに出力したい時や、レベルによって出力を絞りたい時等、色々便利です。

基本的な使い方はドキュメントにも書いてある通りになります。
<pre>
import logging

logging.warning('出力したい文字列')
</pre>

https://docs.python.org/ja/3/howto/logging.html

# Linuxのシスログにログを出力する方法

handlersの設定を行い、出力先をLinuxのログデバイスに設定します。

サンプルコード：
<pre>
import logging
from logging import handlers

LOG_DEVICE = "/dev/log" #LinuxOSのログデバイス
LOG_LEVEL = "debug" #実際に出力されるログはシスログプロセスが管理するので、debugにして全てのログを出力するようにします。

logger = logging.getLogger(name)
logger.setLevel(LOG_LEVEL)
logging.handlers.SysLogHandler(LOG_DEVICE)　#出力先をLinuxのログデバイスに設定します。大体/dev/logになっています
ch.setLevel(LOG_LEVEL)
formatter = logging.Formatter('%(name)s [%(process)d]: %(message)s')　#シスログの出力メッセージの形式に合わせて調整します
ch.setFormatter(formatter)
logger.addHandler(ch)

logger.debug('debug message')
logger.info('info message')
logger.warning('warn message')
logger.error('error message')
logger.critical('critical message')
</pre>

これでログがシステムログに出力されるようになりました。
システムログに出力されるログのレベルはシステムログ側の設定で絞ることができますので、Python側のレベル設定はdebugにしておきます。

https://docs.python.org/ja/3/howto/logging.html#loggers

# Loggerのログレベルについて

現在loggingモジュールに用意されているログレベルは下記の５つだけ。
DEBUG
INFO
WARNING
ERROR
CRITICAL

Linuxのシステムログを使用するにあたって、もう少しログレベルを調整できるようにします。サンプルではNOTICEレベルを追加します。
ログレベルを追加するには、既存のloggerクラスを継承したクラスを作成してログレベルを追加していきます。

サンプルコード：
<pre>
import logging
from logging import handlers

LOG_DEVICE = "/dev/log" 
LOG_LEVEL = "debug"
NOTICE = 25 # ログレベルinfo(20), warning(30)の間の数にします

class UnixLogger(logging.Logger):　# Loggerクラスを継承したクラスを作成
    def __init__(self, name, level=logging.NOTSET):
        super().__init__(name, level)
    
    def notice(self, msg, *args, **kwargs):　# noticeメソッドを定義
        """
        Log 'msg % args' with severity 'NOTICE (25)'.
        To pass exception information, use the keyword argument exc_info with
        a true value, e.g.
        logger.notice("Houston, we have a %s", "thorny problem", exc_info=1)
        """

        if self.isEnabledFor(NOTICE):
            self._log(NOTICE, msg, args, **kwargs)

# 追加部　ログレベルを追加してメソッドを追加したloggerクラスをセットする
logging.addLevelName(NOTICE, "NOTICE")
logging.handlers.SysLogHandler.priority_map.update({"NOTICE" : "notice"})
logging.setLoggerClass(UnixLogger)

logger = logging.getLogger(__name__)
logger.setLevel(LOG_LEVEL)
logging.handlers.SysLogHandler(LOG_DEVICE)　
ch.setLevel(LOG_LEVEL)
formatter = logging.Formatter('%(name)s [%(process)d]: %(message)s')
ch.setFormatter(formatter)
logger.addHandler(ch)

logger.debug('debug message')
logger.info('info message')
logger.notice('notice message') # 追加したログレベルのメッセージを出力
logger.warning('warn message')
logger.error('error message')
logger.critical('critical message')
</pre>

これでnoticeレベルのログを簡単に出力できるようになりました。
他のレベルや、独自にログレベルをカスタマイズしたい場合でも同様に設定することができます。

https://docs.python.org/ja/3/howto/logging.html#logging-levels

# サンプルコード公開
本記事のサンプルコードは、Github上に公開しています。

https://github.com/kt-tsuchi/python-tips/tree/main/logging
php imagick 背景画像を繰り返す

タイトルの通り
laravel を利用。


```hoge.php
        //背景画像を用意
        //576 x 320
        $bg = new \Imagick(public_path('/img/twitter-bg2.png'));
        
//        背景画像を繰り返し描写
        $x = 0;
        $y = 0;
        $i = 0;
        $s = 0;
        while($s < 50){

            //        リモート画像でもOK
            //64 x 64 で リピートさせたい画像を用意
            $icon = new \Imagick(public_path('/img/bk3.png'));
            $bg->compositeImage($icon, $icon->getImageCompose(), $x, $y); //画像を重ねる x , y

            $i++;
            $x += 64;

            if($i == 9){
                $i = 0;
                $x = 0;
                $y += 64;
            }

            $s++;
        }


        $title = "本日は晴天なり";
        $body = "いつもDMありがとうございます。\nいま大学生で、奨学金で通っていて金欠です。\n切実にカバーしていただける方と出会いたいです。\nまじでよろしくお願いします。\n早めにによろしくお願いします。";
        $water = "いつもDMありがとう\n@ma7ma7pipipi♡";

//        タイトルを描写
        $text = new \ImagickDraw();
        $text->setFont(resource_path("/any/font/SourceHanSansHW-Bold.otf"));
        $text->setFillColor('#000'); // black

        //テキスト描画設定を含む ImagickDraw オブジェクト。x,y,角度,描画するテキスト
        $text->setGravity(\Imagick::GRAVITY_NORTH);//文字トップ 上寄せ
        $text->setFontSize(24);
        $bg->annotateImage($text, 0, 22, 0, $title);


//        本文を描写
        $text->setFontSize(16);
        $text->setTextInterlineSpacing(10);//行間
        $bg->annotateImage($text, 0, 88, 0, $body);

        $text2 = new \ImagickDraw();
        $text2->setFont(resource_path("/any/font/SourceHanSansJP-VF.otf"));

        $text2->setFillColor('#000'); // black
        $text2->setFontSize(12);
//        $text2->setTextInterlineSpacing(10);//行間
        $text2->setGravity(\Imagick::GRAVITY_SOUTHEAST);//文字トップ 上寄せ
        $bg->annotateImage($text2, 15, 20, 0, $water);
        $bg->writeImage(public_path('new_sample3.png'));

        $text->clear();
        $text->destroy();
        $text2->clear();
        $text2->destroy();
        $bg->clear();
        $bg->destroy();


```

とりあえず、コピペで動くでしょう。

![new_sample3 (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/31338/54093244-fb40-93bd-7a7c-5c460e262424.png)
イベントカレンダーをスライサーで処理しやすくするためのPower Queryを用いた展開

# 背景
よく見かけるイベントカレンダー(下記(1)）は、人が管理・修正するので、おそらくこの形式が多いかと思います。
一方で、このままの形式ではスライサーなどで処理することが出来ません。

なので、日付テーブルとリレーションしやすい形式（下記(2)）に変換する必要があるのですが、実装まで少し苦労しましたので、記事化しました。
今回はPower Queryを用いていますが、DAXでテーブルを記述することも可能ではないかと思います。

##### よくあるイベントカレンダー(1)
| 開始日| 終了日| イベント名 |
| --- | --- | --- | 
| 2022/5/15 | 2022/5/18 | イベント１| 
| 2022/7/1 | 2022/7/5 | イベント２ |

##### 日付テーブルとリレーション可能な形式(2)
| イベント名 | 日付| 
| --- | --- |
| 2022/5/15 |イベント１|
| 2022/5/16 |イベント１|
| 2022/5/17 |イベント１|
| 2022/5/18 |イベント１|
| 2022/7/1 |イベント２|
| 2022/7/2 |イベント２|
| 2022/7/3 |イベント２|
| 2022/7/4 |イベント２|
| 2022/7/5 |イベント２|

# 具体的な手法
 日付範囲のリストを返すカスタム関数を記述し、イベントカレンダーのテーブルにAddColumnsし、それを展開するだけで済みます。

### 1.カスタム関数の作成
  空のクエリーを作成し、下記カスタム関数を「DateRange」などという名前で作成します。
  
~~~Python
(dStartDate as date, dEndDate as date)=>
let
    DateRange = List.Generate(() => dStartDate, each _ <= dEndDate, each Date.AddDays(_,1))
in
    DateRange
~~~

### 2.イベントテーブルにカスタム関数の列を追加
「列の追加」→「カスタム関数の呼び出し」で上記の関数を呼び出します。
この時、引数の対象を忘れずに「列名」にしてから日付範囲の列名を選択します（ちょっとはまった）。
<img src = "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2599035/7b13f9e7-5c20-bee9-1819-ce59fca985dc.png" width=500>

正常に関数が追加されると、日付列が現れます。
| 開始日| 終了日| イベント名 | 日付 |
| --- | --- | --- | --- | 
| 2022/5/15 | 2022/5/18 | イベント１| List |
| 2022/7/1 | 2022/7/5 | イベント２ | List |


### 3.追加したカスタム列を展開
日付列は「List」になっていますので、これを展開すれば完了です
最終的な本体のコードはこのようになります。

~~~Python
let
    ソース = Excel.Workbook("EventCalendar.xlsx"), null, true),
    tblEventTable_Table = ソース{[Item="tblEventTable",Kind="Table"]}[Data],
    変更された型 = Table.TransformColumnTypes(tblEventTable_Table ,{ {"イベント名", type text}, {"開始日", type date}, {"終了日", type date}}),
    呼び出されたカスタム関数1 = Table.AddColumn(変更された型, "日付", each DateRange([開始日], [終了日])),
    展開されたDateRange1 = Table.ExpandListColumn(呼び出されたカスタム関数1, "日付")
in
    展開されたDateRange1
~~~