OmniAICreator/Qiita-1.07M huggingface dataset:
Airflowの時間の謎

# Airflowの表示時間はおかしいと思います
## どうしてNext Run が過去の時間なんですか?おかしいと思います
Next Runは次の実行ということですよね、どうして過去の時間ばかりなのでしょう?
この後ちゃんと実行されるのかな...  
なんだかおかしい気がします

↓6/11 11:20時点でNext Runは全て過去の時刻になっている
![スクリーンショット 2023-06-11 11.21.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534203/ba0ee2fd-3068-03da-c1b8-c1fc46b66d68.png)

## Treeビューの順番がおかしいと思います
毎日20時に実行するDAGが、諸事情でやり直したくなってお昼にマニュアル実行しました。
翌日Treeビューで眺めていると...アレ?
マニュアル実行が一番右に表示 (最新?)にされてる! 昨日の夜は実行してないの!?
おや、右から２番めに昨日の夜のスケジュール実行がありました...
順番がおかしいのではないでしょうか?

↓スケジュール実行とマニュアル実行が混ざった場合に実行順に並ばないことがある
![スクリーンショット 2023-06-11 10.54.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534203/e57da561-a95a-cca4-92e8-f6704bb4a26f.png)



## start_dateをきっちり設定したのに実行されないんです、おかしいと思います
新しいDAGを作りました、毎日夜23時に動くDAGです!
今日の夜23時から実行させたいから、start_dateを今日の23時に設定して、と...

(翌日)

きっちり設定したのに!! なんで動いてないの!? おかしいと思います!!

↓start_dateを6/10昼に設定したのに6/10の夜23時に実行されなかった悲しいDAG
![スクリーンショット 2023-06-11 11.12.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534203/63cfbed6-bb10-68f1-f326-bc71f6095cee.png)


# おかしくなかった
Airflowは実行時間ではなくてData Intervalの最初の日時を表示している箇所が多いようです。  
Data Intervalというのは、実行と実行の間の期間のことです。  
例えば`schedule_interval="0 0 10 * *"` と定義したDAGは毎月10日に実行しますが、以下のようになります。
|  Data Interval | 実行時間 | Airflowが利用する時間 |
| ---- | ---- | ---- |
|  5月10日〜6月10日  | 6月10日 | 5月10日 |
|  6月10日〜7月10日  |  7月10日 | 6月10日 |
|  7月10日〜8月10日  |  8月10日 | 7月10日 |
|  8月10日〜9月10日  |  9月10日 | 8月10日 |
|  9月10日〜10月10日  |  10月10日 | 9月10日 |

直感的には実行時間の方を意識すると思うんですが、Airflowは違うんですね。
6月10日〜7月10日のData Intervalで、実行するのはその終わりの7月10日ですが、Airflowはその最初の6月10日を表示します。

## Next Runがなぜ過去なのか
現在が6月11日だとします。毎月10日に実行されるDAGでは、次に実行されるのは7月10日です。
Data Interval的には、今は6月10日〜7月10日の期間にいるのでNext Runはその最初の6月10日を表示しています。  
直感とは異なりますが、こういう理由だったのです。
Next Runが表示しているのは、次に実行される時間ではなく、次に実行するData Intervalの最初の時間ということになります。

## Treeビューの順番がなぜ実行順に並ばないのか
Treeビューでも同様です。
`Run:`, `Run Id: `の日時に採用されるのは、実行時刻ではなくData Intervalの最初の時刻です。
ところが、スケジュール実行ではなくマニュアル実行の場合は実際の実行時間が`Run:`, `Run Id: `の日時になります。
そのため手動で実行したタイミングによっては、実行時間が入れ替わることがあります。

## start_dateの設定について
Data Intervalの最初の日時より前にstart_dateを設定している必要があります。
今日の夜23時に実行させたいなら、Data Intervalは昨日の23時〜今日の23時なので昨日の23時に以前にすればいいですね。

# まとめ
Airflowの直感と違った日時表示、慣れれば特に不自由しないんですが、この表示にして何か嬉しいことがあるんでしょうか? 知っている方がいらしたら、ぜひ教えてください

(参考)[Airflowのドキュメント Data Interval](https://airflow.apache.org/docs/apache-airflow/stable/core-concepts/dag-run.html#data-interval)
TypeScript：ブルーベリー本写経してみたけど、力ついた？

## はじめに
TypeScriptの理解深めねばと思い、ブルーベリー本を購入。
ただ読んでいくのもな〜と思ったので、写経してみることにしました。

## 結論
**理解は深まる。初めてTypeScriptに触れる方は写経も1つの方法になりそう。**

#### 良かったこと
- 進んでいる感覚があるのが精神的には良かった
- TypeScriptについて一定話せるようにはなった気がする

#### 悪かったこと
- 分かっていたけど効率は悪い

## 進め方　と　期間
#### 進め方
- ブルーベリー本に書かれているコードを写経
- 進めたところまでの要約をcommitメッセージに追加

都度、実行してログ出してみたり、確認を挟みつつ、ひたすら進めました。

#### 期間
| 対象期間 | ページ数 | commit数 |
| ---- | ---- | ---- |
|2023/04/25~2023/6/4 | 387ページ | 61commit |

平日毎日がなかなか難しかったので、主に土日に20ページずつぐらい進めていました。

※「ブルーベリー本」は「プロを目指す人のためのTypeScript入門」を指しています

https://www.amazon.co.jp/%E3%83%97%E3%83%AD%E3%82%92%E7%9B%AE%E6%8C%87%E3%81%99%E4%BA%BA%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AETypeScript%E5%85%A5%E9%96%80-%E5%AE%89%E5%85%A8%E3%81%AA%E3%82%B3%E3%83%BC%E3%83%89%E3%81%AE%E6%9B%B8%E3%81%8D%E6%96%B9%E3%81%8B%E3%82%89%E9%AB%98%E5%BA%A6%E3%81%AA%E5%9E%8B%E3%81%AE%E4%BD%BF%E3%81%84%E6%96%B9%E3%81%BE%E3%81%A7-Software-Design-plus/dp/4297127474

## 良かったこと
> - 進んでいる感覚があるのが精神的には良かった

不具合調査や開発で詰まったとき、
**今日1日使ったのに何も進んでないのでは、、？** というときありますよね（あります）
![](https://storage.googleapis.com/zenn-user-upload/10ca296447a6-20230611.png)
（気持ち的にはこんな感じ）

こういう時にも、**「今日ブルーベリー本進めたから何も進んでないことはない」** という
メンタルになるので、ちょっとだけ心穏やかになります。
これは写経でなくても獲得できるものだと思うので、引き続き何か継続できればと思ったり。


>- TypeScriptについて一定話せるようにはなった気がする

実務で使ってはいたのですが、これまでは何となくの理解だったなと思いますが、
今はそれぞれ**理由も含めて一定は理解して話せる**ようになったのかなと思います。
やはり**手を動かすことは大きい**です。

例えばany型について
これまでは**any=型何でも許容しちゃうからダメ**ぐらいだったのが
なぜダメなのか、利用ケースはあるのかなど理解できたかなと
↓結局悪なのかどうか、自分なりにまとめてみたので見てみていただければと思います。

https://qiita.com/makky/items/d3cc0959b9d280d30727

その他、特に非同期、Promise型も今回を通して理解が深まったなと。
このあたりは、また言語化できればと思います。

## 悪かったこと
>- 分かっていたけど効率性は悪い

進める前から分かっていたことではありますが、勉強という意味での効率性は悪いなと思います。
既に知っていることや実務で出てくることはないので頭の片隅に、、というレベルの部分にも
頻繁に使うようなものと同じだけの時間をかける必要があったり。
**もうこのページとばしてしまうか、、** という悪魔のささやきが何度も聞こえてきました（危なかった）

## まとめ
興味本位＋半分趣味のような感じで始めましたが、楽しかったです。

初めて取り扱う言語に対して、
基本のきを理解のためにやってみるというのは良さそうかなと思いますが
効率的な面で、個人的には1冊まるごと写経することはもうなさそうです

次はブルーベリー本に書いていたことを思い出しながら
TypeScript使って自分で動くものを作ることで理解を深めていけたらなと思います


## 参考
進め方含め参考にさせていただきました、ありがとうございました。

https://zenn.dev/shava2c/articles/6fd5ed3e31fb82
Glue(Jupyter Notebook)を途中で終了させる

# はじめに
Glue(Jupyter Notebook)で、途中で処理を終了させたい場合、何を使えばいいのか調べましたので、記事にしました。


# 概要

- `os._exit(os.EX_OK)`で終了させるのがよさそう
    - `sys.exit(0)`では、Run statusがFailedになってしまいます。

# 参考

https://stackoverflow.com/questions/69281483/end-exit-a-glue-job-programmatically

https://stackoverflow.com/questions/67028388/how-to-stop-exit-a-aws-glue-job-pyspark

# 試したこと

## 前提
以下のように、「ある条件では、途中で終了させる」というのを例にします。
```python
import sys

# 続けるかどうかの分岐
is_continue = False

if not is_continue:
    # 処理を終了
    print('処理を終了します')
    sys.exit(0)

print('処理を続ける')
# とても長い処理

```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/f8892c7f-cf2f-da2a-fa8e-0dcd33feb6d7.png)


以下のようにしてもいいのですが、続ける処理がとても長い場合、1つのセルの中で記述しなければならず、Notebookの良さを損ねてしまいます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/f97a2c97-28a5-9685-8903-cfae29d72d35.png)


## `sys.exit(0)`で終了させた場合
以下のようにして処理を実行させます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/1ac9bdbe-ea77-8e51-905e-bf7066a9485f.png)

ステータスがFailedになってしまいます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/c7a4d070-c850-97a3-59e2-dadc2659724e.png)


## `os._exit(os.EX_OK)`で終了させた場合
終了のさせ方を変更します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/4549dec7-4483-af38-812b-2d8775ccf3d7.png)

今度はステータスがSucceededで終了しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553680/0d660c0c-9c3d-f85f-dd54-e2cf77707e6a.png)

# おわりに
今回はGlueを途中で終了させる方法を紹介しました。
Jupyter Notebookで利用することを想定していますが、おそらく普通のGlueでも問題ないかと思います。
どなたかのお役に立てれば幸いです。
統計検定2級、合格のふりかえり（会場選び、アプリを利用した勉強習慣の身につけ方）

勉強法はいくらでもあるので、自分に合ったものを見つけると良いと思います。ここでは、会場選びや勉強習慣を身につけるために使ったサービスなどについて、振り返ってみました。

### 受験会場選びの重要性

受験会場の選択は、受験生のパフォーマンスに大きな影響を及ぼします。集中できないなと思ったら、会場を変えてみるのはメチャクチャありだと思います。会場で気になった点をいくつか：

* イヤーマフ
* 計算用紙
* 隣席との間隔
* 駅からの距離

会場によってはイヤーマフや耳栓が用意されています。私はイヤーマフがあることにより、断然集中できました。特に隣席が数十センチしかないような会場では、"試験中"の会場運営の方と受験者との会話が気になって集中できないことが多々ありました。一度も使ってみたことがない方は、是非tryされることをお勧めします。耳栓は…

計算用紙も会場によって違いました。ある会場はラミネートされたA4の用紙を2枚渡されました。"片側のみ"に記述できません。しかもサインペンです。太い。たくさん書けない。すぐにページが埋まってしまい不自由を感じました。ところが、別の会場では、A4のコピー用紙を2枚。両面記述OK、しかもボールペンです。細かく書ける！心理的な負担が大きく減りました。思わず受付で、「両面に記述してもいいのですか？」と確認しました。単純に倍の面積に書けますからね。

隣席との距離、意外と気になりました。なぜかというと、複数の資格試験を同時に開催する会場もあるからです。制限時間も違うし、短い時間で終了する方も多い。結果、試験官との話し声が複数回近距離で行われることになり、ひそひそ声ですが気になってしまうのでした。

駅からの距離。これによって上の問題が解決されるのであれば、優先度を下げるのはアリです！私が受験した会場はGoogle Mapでの評価が低かったものの、実際には教室が広く、隣の受験生が気にならない環境でした。また、イヤーマフの使用や計算メモに紙を使うことができるなど、受験生に配慮された設備が整っていました。確かに駅からは少し距離がありましたが、その一点だけで会場を選ぶのは短絡的だと感じました。

### 様々なサイト・アプリを利用しての学習

* [Udemy「統計検定 2級対策講座」](https://www.udemy.com/course/toukei-kentei/)
* [BellCurve「統計学の時間」](https://bellcurve.jp/statistics/course/)
* [みんチャレ](https://minchalle.com)
* [Studyplus](https://www.studyplus.jp)



教科書を読み進めながら、練習問題・過去問を解いていましたが、深く理解できていないと感じていました。しかし、このUdemyの講座を受講したことで、その不安が解消されました。内容が非常に明快に解説されており、私にとっての「aha！」の瞬間をもたらしてくれました。セールになる時があるので、タイミングを狙って購入するのも良いと思います。

BellCurveさんの「統計学の時間」にもお世話になりました。一つ一つの項について丁寧に解説されているので、困った時の神頼み的に利用していました。

1人では挫折する可能性もあるなと心配だったので、Studyplus・みんチャレのアプリを使って伴走する戦友を見つけることにしました。特にみんチャレは、学習リズムを作るのに役に立ったなと思います。メンバー間で会話をするということはなく、作業負担も大きくないのに、「勉強したら投稿する」という一連の勉強のサイクルが完成したときに小さな達成感が得られるのはよいものでした。それがまた積み重なると自信になる感じです。Studyplusは作業時間が分ります。自分がどれだけ、どの教材に時間を費やしたのか。グラフを見て、ニマニマするのも良いものです。
レガシーなcallbackをpromisifyを使って書き直す

こんにちは。@Esperna です。

# 背景
[レガシーなcallbackをasync/awaitで書き直す](https://qiita.com/drafts/2e37fce54cf2c5b8085f)を書いた後に[promisify](https://nodejs.org/api/util.html#utilpromisifyoriginal)というものがあることを教えてもらったので、今回も車輪の再発明ながらいじってみました。

# callbackのコード例（再掲）
```javascript:callback.js
function asyncTask(callback) {
    const TIMEOUT = 10;
    setTimeout(() => {
        var data = 0;
        if (Math.random() > 0.5) {
            data = 1;
            callback(null, data);
        } else {
            callback(new Error("Invalid Data"), data);
        }
    }, TIMEOUT);
}

asyncTask((err, data) => {
    if (err === null) {
        console.log(`successfully finished task. Data: ${data}`);
    } else {
        console.error(`error occured: ${err}: ${data}`);
    }
});
console.log("called asyncTask");
```

# Promise, async/awaitを使った例（再掲）
```javascript:async_await2.js
function asyncTask() {
    return new Promise((resolve, reject) => {
        const TIMEOUT = 10;
        setTimeout(() => {
            var data = 0;
            if (Math.random() > 0.5) {
                data = 1;
                resolve(data);
            } else {
                reject(new Error(`Invalid Data: ${data}`));
            }
        }, TIMEOUT);
    });
}

async function doAsyncTask() {
    try {
        const data = await asyncTask();
        console.log(`successfully finished task. Data: ${data}`);
    } catch (err) {
        console.error(`error occured: ${err}`);
    }
}

doAsyncTask();
console.log("called asyncTask");
```

# promisifyを使って書いてみた例

```asyncTask_promisify.js
const util = require("util");

function _asyncTask(callback) {
    const TIMEOUT = 10;
    setTimeout(() => {
        var data = 0;
        if (Math.random() > 0.5) {
            data = 1;
            callback(null, data);
        } else {
            callback(new Error("Invalid Data"), data);
        }
    }, TIMEOUT);
}

async function doAsyncTask() {
    const asyncTask = util.promisify(_asyncTask);
    try {
        const data = await asyncTask();
        console.log(`successfully finished task. Data: ${data}`);
    } catch (err) {
        console.error(`error occured: ${err}`);
    }
}

doAsyncTask();
console.log("called asyncTask");
```

# 所感

* new Promise((resolve, reject)をreturnする部分を書かなくて楽ということですね
* promisifyを知らないと読みづらいのかも
* これまでのお勉強でcallback hellは回避できるようになった気がする

# promisifyを使う時の注意事項

* promisifyに渡す関数がerror-first callbackになっていること
* classのメソッドをpromisifyに渡すときはクラスのインスタンスをbindしてあげないと意図通りに動かないことがありる
Sambaの設定ファイル「/etc/samba/smb.conf」　ホストのアクセス制限を行う設定項目

●Sambaの設定ファイル「/etc/samba/smb.conf」には3つの特別なセクションである[global]、[homes]、[printers]セクションと、個々の共有の設定を行う任意の名前のセクションがあります。

ホストのアクセス制限を行う設定項目は、
接続許可を「hosts allow」で、接続拒否を「hosts deny」で行うことが出来ます。globalセクションに記述した場合は、Sambaサーバ全体のアクセス制限を行い、それ以外のセクションの場合は、共有ごとにアクセス制限を行うことが出来る

書式
hosts allow = IPアドレス
hosts deny = IPアドレス

なお、複数のホストを指定する場合は、「,」やスペース、タブで区切って行います。hosts allowに指定されていないホストは自動的に接続を拒否され、hosts denyに指定されていないホストは自動的に接続を許可。ただし、2つの内容が矛盾している場合は、hosts allowの内容が優先。
【Kotlin】K2 Compilerを有効にする方法

# はじめに
最近はAndroidの開発がメインですが、サーバーサイドも忘れないよう個人での開発も進めています。
そんな中で今回は試験的に導入したK2コンパイラに関して、導入方法などを備忘録的に残しておこうと思います。

# K2コンパイラとは？
そもそもK2コンパイラとはなんぞやというお話なのですが、簡単に申し上げると【安定性やパフォーマンス向上を目的とした次世代のコンパイラ】になります。

K2コンパイラは、旧コンパイラに比較して大幅に高速化されているとのことで、JetBrainsのベンチマークによると2倍のスピードアップが期待できるとの事。

また、すべてのプラットフォームでこの最適化の恩恵を受けられるような仕組みを新たに導入しているようです。
この事から多様化していくKotlinの動きを見据えた調整であるということが見て取れますね。

# 導入方法
導入方法は非常にシンプルで、以下をgradleに追加する形になります。

```build.gradle.kts
kotlin {
   sourceSets.all {
       languageSettings {
           languageVersion = "2.0"
       }
   }
}
```
注意点としては、現段階ではアルファ版なので、Kotlin/Nativeやマルチプラットフォームはまだサポートされていないとのことです。
今回のコンパイラの仕組み上、現状はサポートされていなくてもどこかのタイミングで必ずサポートされるはずなので、続報を要チェックですね。

導入手順は以上になります。

# さいごに
ついに三十路になってしまいました、、、
投稿したのにidがnilになる

自分のメモ用です。
わかりにく個所があると思います。

# Createアクションで作成したidがnilになる
記事作成の中で、以下のようにもともと書いていた。
 
![スクリーンショット (39).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3250201/5f2e8c54-fdd7-4a29-ab71-7c0fd1cd0d67.png)

構文に間違いはなく、ただただ投稿するとページが遷移しないので困っていた。

## コンソールで確認
コンソールで確認すると下記のように表示され、idやcreate_atといった本来自動で作成されるものが作成されないことが判明。
![スクリーンショット (41).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3250201/6c0c3c18-0074-9a24-470a-d0efbc59c6b7.png)

なので、以下のことを確認。
➀AIに聞く
➁viewでの表示確認（newページとshowページ）
➂データベースの確認

### データベースの確認
結果的に言うと、ここが間違っていました。
GenderモデルでUserとGenderをアソシエーションしていました。
さらにcreateアクションでUserと紐づけているにも関わらず、
データベース上で『**Userと紐づけていない**』ということが発覚！

なので、Addを使用し、下記のように追加しました。

➀rails generate migration AddUserIdToGenders user_id:integer
➁ファイルを確認
➂rails db:migrate

見事紐づけ成功！！
投稿できるようになりました！！

アソシエーションするときは、データベースでの紐づけもしっかり考えてくださいね！

というか、ER図や設計書もしっかり作ればこんなことにはならなかったんだよ。
[Git] 動作を試す 実行例55：remote・fetchでローカルリポジトリ間同士でも同様に履歴取得が可能

Gitの動作を理解するために、Gitのコマンドを実際に試して、結果を見てみました。

1つの記事内で一連のGitコマンドが完結しているので、これら一連のコマンドを順に実行させて結果を見ることで、一連のGitの動作を実際に体感でき、一通り独習することが可能です。

※前回記事のリポジトリ状態からの続きになっています。
| [前回記事へ](https://qiita.com/dl_from_scratch/items/c232b02e9970a477525a) | [目次へ：Git関連記事のまとめページ](https://qiita.com/dl_from_scratch/items/597bc28a4787a7901d21) | [次回記事へ](https://qiita.com/dl_from_scratch/items/c898d7cc2ef7c3e9ce8a) |
|:-:|:-:|:-:|

# 実行例

```
(※試行用にlocal-repo3を作成)

cd /test-space
mkdir local-repo3
cd /test-space/local-repo3

git init
git remote add origin "D:/test-space/remote-repo1.git"

git log
↓
結果: 
fatal: your current branch 'master' does not have any commits yet

-----

(※リモートリポジトリからmasterブランチのみを取得して環境準備)
git fetch origin master
git log --oneline --graph --all
↓
結果: 
* 1247fa9 (origin/master) message R4
* fab68d8 message R3
* c69a305 message R1
* 94996a0 message4
* 20bbab7 message3
* 00cad71 message2
* 4ace194 message1

-----

(※--bareでリモートリポジトリを作成せず、2個のローカルリポジトリの間でも同様にやり取り可能)

※ローカルリポジトリ(非ベアリポジトリ)へのアクセスを追加登録
git remote add origin-L2 "D:/test-space/local-repo2"

git remote -v
↓
結果: 
origin  D:/test-space/remote-repo1.git (fetch)
origin  D:/test-space/remote-repo1.git (push)
origin-L2       D:/test-space/local-repo2 (fetch)
origin-L2       D:/test-space/local-repo2 (push)

※ローカルリポジトリからmasterブランチの履歴情報を取得
git fetch origin-L2 master
↓
結果: 
From D:/test-space/local-repo2
 * branch            master     -> FETCH_HEAD
 * [new branch]      master     -> origin-L2/master

git log --oneline --graph --all
↓
結果: 
* 1247fa9 (origin/master) message R4
* fab68d8 message R3
* c69a305 (origin-L2/master) message R1
* 94996a0 message4
* 20bbab7 message3
* 00cad71 message2
* 4ace194 message1

(※origin/masterの他に、同じ履歴の系列にorigin-L2/masterが追加される)
```

# 環境

Windows 10、PortableGit-2.40.0-64-bitを使用、全てローカルPC上で実施、GitHub等は不使用。
ifと配列の練習

今日の曜日（day of week）を表示するコードをDateクラスを使用して書く。

Dateクラス使いたい時は
```ruby
require"date"
```
この一文を記述する。

Dateクラス使って今日の曜日を表現したいときは
```ruby
Date.today.wday
```

wdayは曜日を0(日曜日)から6(土曜日)の整数で取得することができるDateクラスに用意されているメソッド。

Fridayだった場合だけ表示内容を変えたい。

出力内容は、

「Today is Monday.」

「♪Today is Friday♪」

にしたい。

```ruby
require "date"
day = Date.today.wday
days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"]

if day == 5
  puts "♪Today is #{days[day]}♪"
else
  puts "Today is #{days[day]}."
end
```

となる。
【Java】文字列のユニーク性を判定するアルゴリズムの実装方法

# はじめに
Javaで文字列を扱う際、ある文字列が重複する文字を含んでいるかどうかを判定したい場合があります。
この記事では、文字列が全てユニークであるかどうかを判定するアルゴリズムを学習したのでアウトプットしました。

## 例題
```java
trueの場合
value = ABC123

falseの場合
value = AABBCC

```
## アルゴリズムの概要
アルゴリズムは以下の手順で実装されます。

- ASCII文字の範囲(0から127)の要素数を持つ配列 count を作成します。初期値はすべて0とします。
- 入力された文字列の各文字を順番に取り出し、その文字のASCIIコードをインデックスとして count 配列の要素をインクリメントします。
- count 配列の要素が1より大きい場合、重複する文字が存在するため、文字列はユニークではありません。その場合は false を返します。
- 全ての文字について処理が終了したら、重複する文字が存在しないため、文字列はユニークです。その場合は true を返します。

## 実装したコード
```java:文字列に重複文字が無いか比較
public class UniqueStringChecker {

    public static boolean isUniqueChars(String str) {
        if (str.length() > 128) {
            // ASCII文字は全部で128種類なので
            // それ以上の文字が存在する場合どこかに重複した文字があるということになります
            return false;
        }

        int[] count = new int[128];
        // int型の配列を用意することで数字のみが入る配列を用意します
        for (int i = 0; i < str.length(); i++) {
            char ch = str.charAt(i);
        // charAt()メソッドは指定した文字列を1文字取得します
            count[ch]++;
        // int型で指定した配列にインクリメントすることで
        // カウントを1増やします
        // count[a]の場合、aという文字が1文字あるという構図になります
            if (count[ch] > 1) {
        // 繰り返し処理でcountの配列が1以上のものが見つかった場合、
        // 重複が見つかったとしてfalseを返します
                return false;
            }
        }

        //　上記の条件に当てはまらなかった場合、重複なしとしてtrueを返します
        return true;
    }

    public static void main(String[] args) {
        String input = "abcdefg";
        boolean isUnique = isUniqueChars(input);
        System.out.println("入力文字列 '" + input + "' はユニークですか？ " + isUnique);
    }
}
```
```java:実行結果
入力文字列 'abcdefg' はユニークですか？ true
```
## まとめ
この記事では、Javaで文字列のユニーク性を判定するアルゴリズムを実装しました。ASCII文字に限定し、配列を使用することで効率的に処理を行いました。重複する文字が存在しない場合は true を、存在する場合は false を返す仕組みです。
Microsoft ExcelからDatabricksに接続する

[Connect to Databricks from Microsoft Excel \| Databricks on AWS](https://docs.databricks.com/integrations/excel.html) [2023/6/1]の翻訳です。

:::note warn
本書は抄訳であり内容の正確性を保証するものではありません。正確な内容に関しては原文を参照ください。
:::

本書では、Microsoft ExcelからDatabricksに接続するためにどのようにDatabricks ODBCドライバーを使用するのかを説明します。接続を確立すると、ExcelからDatabricksのデータにアクセスできるようになります。また、さらにデータを分析するためにExcelを活用することができます。

# 準備

- [ワークスペースを作成します](https://docs.databricks.com/administration-guide/workspace/index.html#create-a-workspace)。
- Databricksクラスターを作成し、クラスターを用いて関連データを作成します。[Databricksで初めてのETLワークロードを実行する](https://qiita.com/taka_yayoi/items/e27fd8b44308ea4ec8d8)をご覧ください。
- [お使いのOSの64-bitバージョンのODBCドライバーをダウンロードします](https://docs.databricks.com/integrations/jdbc-odbc-bi.html#download-the-odbc-driver)。
- ODBCドライバーをインストール、設定します([Windows](https://docs.databricks.com/integrations/jdbc-odbc-bi.html#odbc-windows) | [MacOS](https://docs.databricks.com/integrations/jdbc-odbc-bi.html#odbc-mac) | [Linux](https://docs.databricks.com/integrations/jdbc-odbc-bi.html#odbc-linux))。このセットアップでは、DatabricksとMicrosoft Excelを接続するために使用するデータソース名(DSN)のセットアップを行います。
- [トークン管理API](https://docs.databricks.com/api/workspace/tokenmanagement)。
- Microsoft Excelのインストール。[トライアルバージョンを使用](https://products.office.com/excel)することもできます。

# Microsoft Excelから接続するステップ

このセクションでは、準備ステップで作成したDSNを用いて、どのようにDatabricksからMicrosoft Excelにデータを取り出すのかを説明します。

:::note info
**注意**
このセクションのステップは、Excel for Microsoft 365 for Mac version 16.70を用いてテストされました。
:::

1. Microsoft Excelで空のワークブックを開きます。
1. **Data**リボンで、**Get Data (Power Query)** の隣の下向きキャレットをクリックし、**From database (Microsoft Query)** をクリックします。
1. **ODBC Data Source Chooser**で、準備ステップで作成したDSNを選択し、**OK**をクリックします。
1. **Username**には`token`を入力します。
1. **Password**では、準備ステップで取得したパーソナルアクセストークンを入力します。
1. **Microsoft Query**ダイアログでは、ExcelにロードしたいDatabricksのテーブルを選択し、**Return Data**をクリックします。
1. **Import Data**ダイアログでは、**Table**と**Existing sheet**を選択し、**Import**をクリックします。

Excelワークブックにデータをロードした後は、そのデータに対する分析オペレーションを実行することができます。

### Databricksクイックスタートガイド

[Databricksクイックスタートガイド](https://www.amazon.co.jp/dp/B09V1YXFVQ/)


### Databricks無料トライアル

[Databricks無料トライアル](https://databricks.com/jp/try-databricks)
discord Bot開発 Permission(権限)を確認する方法

# はじめに
discord Botを開発していて、チャンネルからメッセージが取得できないため、Permissionを取得する方法を調べました。


# Permission取得方法
※TOKEN情報は.envなどに持たせて使用してください。

```python
import discord  # DiscordのAPIライブラリをインポートします
import os  # OSの機能にアクセスするためのライブラリをインポートします

# デフォルトのIntentsオブジェクトを取得します。IntentsはDiscordから受け取るイベントのタイプを制御します
intents = discord.Intents.default()
intents.messages = True
intents.guilds = True

# Discordクライアントを初期化します。このクライアントはDiscordサーバーとの通信を処理します
client = discord.Client(intents=intents)

# 環境変数からDiscordのBotトークンを取得します。このトークンはBotをDiscord APIに認証するために使用されます
my_secret = os.environ['TOKEN']

# メッセージが送信された際に、呼び出されます。
@client.event
async def on_message(message):
  # メッセージがギルドからのものかどうかを確認します
  if message.guild is not None:
    permissions = message.channel.permissions_for(message.guild.me)

    # permissionsオブジェクトのすべての属性と値を出力します
    for attr in dir(permissions):
      if not attr.startswith("__"):
        print(f"{attr}: {getattr(permissions, attr)}")

# 取得したBotトークンを使用して、クライアントをDiscordに接続します
client.run(my_secret)



```

上記のソースを実行して取得したものをきれいにしました。
|Permission |Value|
|------------------------------- |------|
|add_reactions |True|
|administrator |False|
|attach_files |True|
|ban_members |False|
|change_nickname |True|
|connect |False|
|create_instant_invite |True|
|create_private_threads |True|
|create_public_threads |True|
|deafen_members |False|
|embed_links |True|
|external_emojis |True|
|external_stickers |True|
|kick_members |False|
|manage_channels |False|
|manage_emojis |False|
|manage_emojis_and_stickers |False|
|manage_events |False|
|manage_guild |False|
|manage_messages |True|
|manage_nicknames |False|
|manage_permissions |False|
|manage_roles |False|
|manage_threads |False|
|manage_webhooks |True|
|mention_everyone |True|
|moderate_members |False|
|move_members |False|
|mute_members |False|
|read_message_history |True|
|read_messages |True|
|request_to_speak |True|
|send_messages |True|
|send_messages_in_threads |True|
|send_tts_messages |False|
|speak |False|
|use_application_commands |True|
|use_external_emojis |True|
|use_external_stickers |True|
|use_voice_activation |False|
|view_audit_log |False|
|view_channel |True|
|view_guild_insights |False|

# 最後に
うまくいかなかったら、Permissionを調べてきましょう

# 参考
https://docs.nextcord.dev/en/stable/api.html

https://youtu.be/SPTfmiYiuok

https://docs.nextcord.dev/en/stable/api.html
ChatGPT、なぜかうまく動かない

# コードですら嘘を書く
しかもVBAで。
できないならできないと言ってくれれば。。。
# UMAは知らない（フリ？）
おそらくUMAみたいなオカルトなことは知らないふりをするらしい。
Bingはそんなことはしない。
Wikiとかにあれば拾う。

## AIが知らない時
1. もっともらしい嘘をでっち上げる
2. 知らない（フリ）をする

という2つのパターンがあるが、どういう基準でこうなるかはわからない。
このため、余計混乱する。

## AIが無効な時
Bingはお昼ご飯検索には強い。
しかし、この有効性は
1.車で移動しており、交通機関で移動する必要がない
2.店が無限にある（完全競争市場）
3.平日で満席にはならないか、少し待てば席が空く
という場合には食べログなどのランキングを検索するので強い。
反対に
1.実態は食べログとRetty。
2.夕ご飯のように酒が入ると、車で移動できないのでジャンルが限られる。よって夕ご飯は有効性がおちる。
3.店が少ないか、存在しないと検索が効かない

　例えばビヤガーデンを探すとする。5月の中旬には開いていない。そうするとBing検索は平気で車で30分かかる店を見つけ出す。遠すぎるという結果になる。
　次に店がないと検索できない、一見すると当たり前のようだが、焼肉店などはその近辺にないとは思わない。
　つまりあると思って探すと焼肉定食を出す店のような変な検索結果が出る。

# 礼儀やマナーはわからないけど、とりあえず挨拶文は強い
 この前書いたときからそうだけど、真偽判定が必要なことはChatGPTは丸投げしている部分があるので、信頼性がない。
　よほど定番で何処かにソースがあれば別だが、そのレベルだとChatGPTを使わなくて良い。
　そちらはBingが強い。複数のソースを取りまとめる能力がある。
 しかし、正確な語句の使い回しは別として、さももっともらしい文章は極めてChatGPTは強い。
　Bingはそういうのはいまいち。クリエイティヴって適当な文章。
 あと毒にも薬にもならない文章はChatGPT臭い文章になる。

# ChatGPTが知らないことはChatGPTに学習させない
　AIの信頼度が上がるわけでもないし時間の無駄。
　お金を払って時間をかけてなぜChatGPTの学習をさせる必要があるのか。
　CEO対策なのかもしれないが、一般人には関係がない。
　聞いて一発で答えられないなら、それで終わり。
　ただし、それは自分の聞き方が客観的に正確である必要がある。なにしろ、自分が悪いのにAIのせいにする人間がいるから。

## AIで作った文章って本当にAI？
　再現できないものが多い。ある程度結果を加工しているか、自分で回答を入れているか、そうしないとうまくいかなさそう。

# 結論が繰り返しになるが、
引き続き使用してみるが、両者とも

 - 結果に再現性がない。
 - 結果に検証が必要。
  
 という問題がある。ただ、Bingは引用元がわかるので検証しやすい。

個別だと、
ChatGPTは挨拶文を生成させるのに向いている。
平気で間違ったコードを書く、コードは検証が必要（New）

Bingはお昼ごはん検索に強いが、それは食べログのランキンが正確な程度に店が存在する場合。
ということがわかった。
Android Autoに組み込むと強そうだ。答え方はドライブ用に特化する必要があるが。
Obsidianのマリアージュ技その4｜ChatGPTの出力を美しく管理する方法

## はじめに

便利メモツール[Obsidian](https://obsidian.md)。さらにラクして使うコツ、なかでも練度のあがってきたものをご紹介します。

Obsidianは、自分だけのナレッジベースを作るためのノートテイキングアプリであり、非常に人気があります。その一方で、AIによるテキスト生成エンジン、ChatGPTも非常に注目を浴びています。


## 概要

ObsidianとChatGPTを同時に使用すると、知識の取り込みと整理がとても簡単になります。しかし、ChatGPTとのチャットの結果を直接Obsidianのノートに貼り付けると、フォーマットが崩れてしまうことがあります。たとえば、箇条書きの順序が消えたり、一部のテキストが正しく表示されなかったりします。これは、せっかくのナレッジを整理しておく際に、大きな障害になります。

![SS 2023-06-11 8.18.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184128/a8e5b03d-9bc1-1802-25f5-4c0c17474996.png)

上のスクリーンショットは、ChatGPTからの出力をObsidianに直接貼り付けたときの例です。箇条書きが消えてしまっており、テキストが読みにくくなっています。

これを解決する方法として、Chromeの機能拡張であるMarkDownloadを使う方法をご紹介します。MarkDownloadを使えば、ChatGPTのウェブ画面から任意の範囲を簡単にObsidianのノートに貼り付けることができます。

![SS 2023-06-11 8.00.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184128/9c69ef23-8af3-ee74-9d6c-e5c07d6f1eb6.png)


上のスクリーンショットが、MarkDownloadを用いたときの例です。箇条書きやコードブロックなどの要素が維持されており、読みやすく、再利用も容易です。


以下に、具体的な手順を説明します。



## 機能拡張の準備

まず、ChromeまたはVivaldiを使用している場合、以下のリンクから[MarkDownload](https://chrome.google.com/webstore/detail/markdownload-markdown-web/pcmpcfapbekmbjjkdalcgopdkipoggdi?hl=ja
)のページを開き、機能拡張をインストールします。

https://chrome.google.com/webstore/detail/markdownload-markdown-web/pcmpcfapbekmbjjkdalcgopdkipoggdi?hl=ja


## コピペ操作

### ChatGPTとのやりとりを部分的にコピペしたい場合

まず、ChatGPTのウェブ画面で、コピーしたい部分を選択します。次に、ブラウザの上部にあるMarkDownloadのアイコン（機能拡張ボタン）をクリックします。新しいウィンドウが開き、選択したテキストが表示されます。ここで`Selected Text`タブをクリックし、そのテキスト全体を選択（ctrl/cmd + Aが便利です）してコピーします。最後に、Obsidianのノートに貼り付けます。


![SS 2023-06-11 8.27.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184128/fe0c07b5-1c3c-f380-4195-98bbe0b0b5ce.png)

上記画像は、操作の流れを示しています。灰色になっているのがChatGPTのウェブ画面で選択した部分、紫色がMarkDownloadのウィンドウでコピーするために選択した部分です。


### ChatGPTの一連のやりとりを全てコピペしたい場合

全てのテキストをコピーしたい場合は、以下の2つの方法があります。まず一つ目、ChatGPTのウェブ画面でテキストを選択した状態でMarkDownloadのアイコンをクリックし、開かれたウィンドウで`Entire Document`タブを選択します。二つ目、ChatGPTのウェブ画面で特にテキストを選択せずにMarkDownloadのアイコンをクリックします。この場合、デフォルトで全文が選択されます。

## Markdownload以外の選択肢

ChatGPTとのチャットの結果を効果的にObsidianに移す方法は、いくつか存在します。たとえばObsidianのChatGPT用のプラグインをインストールし、Obsidian上でChatGPTを直接操作することも可能です。しかし、これにはそれなりの設定が必要であり、また課金体系が変わってしまうという副作用も存在します。

ChatGPTの最近のアップデートでは、一つの回答を直接コピーできる新機能が追加されました。これは便利な機能ではありますが、一連のチャットのやり取りをObsidianのノートに貼り付けることはできません。

それに対し、Chromeの機能拡張MarkDownloadを使用すると、通常通りChatGPTをウェブ画面から利用しつつ、簡単な手順で任意の範囲をObsidianのノートにコピペできます。操作の手軽さと、ユーザのニーズに応じて柔軟にコピペが可能な点から、MarkDownloadの使用をお勧めします。

また、MarkDownloadの開発者はObsidianコミュニティにも貢献しており、自身もObsidianのヘビーユーザーであるということも、このツールを信頼する大きな理由です。

## おわりに

この記事では、ObsidianとChatGPTを一緒に効果的に使うための手法、特にChromeの機能拡張MarkDownloadの使い方について解説しました。

このツールを使用することで、ChatGPTから得た知識を手軽にObsidianのノートに移すことが可能となります。学んだり、知識を整理したりするにあたって、ChatGPTとObsidianが相乗効果を発揮し、学習や知識管理のプロセスをより効率的で、より楽しいものになることを願っています。


### 参考リンク

[Obsidian｜使いかたとコツ（目次）](https://qiita.com/hann-solo/items/ac8fa75394813e8adcf4)


### 環境

ここで書いていることは、下記のバージョンで実施しました。

- Obsidian 1.3.5
- macOS Ventura 13.3.1 (a)
- MacBook Pro (14-inch, 2021)
ROS2講座02 環境のセットアップ

# 環境
この記事は以下の環境で動いています。

| 項目 | 値 |
|:-:|:-:|
| CPU | Core i5-8250U |
| Ubuntu | 22.04 |
| ROS2 | Humble |

# 概要
ROS2を始めるための環境構築手順を解説します。

# PCの準備
x86_64系のPCを前提とします。

# Ubuntuのインストール

* Ubuntuではリリースした年・月をバージョンとして記載されます(18.04,20.04,22.04等)。バージョンによって使えるROS2のバージョンが異なります。ここでは22.04を使います。マイナーバージョン(22.04.5等)が記載されますが、これの影響はほぼないです。
* UbuntuにはDesktop/Severの種類の違いがあります。ServerはGUIが入っていないものです。Desktop版を使います。
* 日本版のサイトではUbuntuの日本語ローカライズバージョン（日本語Remix）がありますが、ここでは本家のバージョンを使います。

[ダウンロードページ](https://ubuntu.com/download)よりubuntu-22.04.2-desktop-amd64.isoをダウンロードします。

* 仮想マシンを使う場合はこのisoファイルを直接読み込んでインストールします。
* 実マシンに書き込むときは、上記のisoファイルをUSBメモリに書き込みます。[refus](https://rufus.ie/ja/)が便利です。

# ROS2のインストール
Ubuntuが起動できたら以下を行います。
参考[Installation](https://docs.ros.org/en/humble/Installation/Ubuntu-Install-Debians.html)

## パッケージの更新
```shell:パッケージの更新
sudo apt update && sudo apt upgrade
```

## ロケールの設定

```shell:ロケールの設定
sudo apt install locales
sudo locale-gen en_US en_US.UTF-8
sudo update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8
export LANG=en_US.UTF-8
```

## aptでのROSのリポジトリの登録

```shell:ROSのリポジトリの登録
sudo apt install software-properties-common
sudo add-apt-repository universe

sudo apt update && sudo apt install curl -y
sudo curl -sSL https://raw.githubusercontent.com/ros/rosdistro/master/ros.key -o /usr/share/keyrings/ros-archive-keyring.gpg

echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/ros-archive-keyring.gpg] http://packages.ros.org/ros2/ubuntu $(. /etc/os-release && echo $UBUNTU_CODENAME) main" | sudo tee /etc/apt/sources.list.d/ros2.list > /dev/null
```

## インストール

```shell:ROS2のインストール
sudo apt update && sudo apt upgrade
sudo apt install ros-humble-desktop
```

# 動作確認

```shell:動作確認
source /opt/ros/humble/setup.bash
ros2 run demo_nodes_cpp talker
```

# 目次ページへのリンク
[ROS2講座の目次へのリンク](https://qiita.com/srs/items/5f0d765343ca78f524ed)
ROS2講座01 ROS1との主な相違

# 環境
この記事は以下の環境で動いています。

| 項目 | 値 |
|:-:|:-:|
| CPU | Core i5-8250U |
| Ubuntu | 22.04 |
| ROS2 | Humble |

# 概要
ROS1を使っていた方向けにROS1とROS2との相違についてまとめます。
両者は全く別ともいわれますが、最大の違いはCoreのライブラリで、周辺ツールは同じライブラリを使っている等、共通資産をつかっている部分も多いです。
相違点をまとめてみます。

# ROSライブラリ本体

* ros masterの有無
    * ROS1ではROS Masterが必ず最初に起動して、他のROSノードは起動時にROS Masterに通信をして、他のROSノードとの接続を行います。
    * ROS2ではmaster的なものはなくROSノード同士はDDSのアルゴリズムで互いを発見します。DDSでの発見をしやすくするための物としてros2 daemonがありますが、これは起動が必須のものではないです。またROS1では一度ROS Masterが落ちると、例えばrostopic echoのコマンドも次に接続する時には再起動しないといけませでしたが、ROS2ではそのような制約はないです（地味にデバックで便利）。
* パラメーター
    * ROS1ではROS Masterがパラメーターサーバーの役割を持っていて、ROSノードはそこにアクセスしていました。
    * ROS2ではROS Masterが廃止されたために、パラメーターの仕組みが大きく変わっています。個別のノード毎にパラメーターサーバーを持ちつ設計に変わっています。これに伴いlaunchでのパラメーターの指定などの仕様も変更になっています。 
* ネットワーク越しの別ホスト(=マシン)との接続
    * ROS1ではROS_MASTER_URIを設定すると、そのマシンのROSノードと接続することが出来ます。
    * ROS2ではDDSが別ホストのROSノードも自動的に発見されるので、同一ホスト・別ホストを意識する必要がありません。逆にROS_DOMAIN_IDという環境変数を設定することで、別ホストと混ざらないようにできます。
* msgの型
    * ROS2ではmsgの定義ファイルには互換性がありますが、c++でインクルードする時のファイル名のルールや型名のルールが変わっています。
* ROSTime 
    * ROS1ではROS時刻はROS::Time、実時刻はROS::WallTimeと別れています。
    * ROS2ではrclcpp::Timeの1つの型で、オプションとしてRCL_ROS_TIME, RCL_SYSTEM_TIME,RCL_STEADY_TIMEの3つから選べます。違うオプションのTime同士の演算を行うとexceptionが起きます。
* seviceの非同期call
    * ROS1のcppライブラリではserviceのclient側でのcallでは同期処理（responseが返ってくるまでブロック）のAPIしかありませんでした。
    * ROS2のrclcppでは非同期APIもあります。これによってROS Srviceの使い勝手が大幅に上がりました。
* use_sim_time
    * ROS1では1つのパラメーターを変えればシミュレーション時間への切り替えが出来ました。
    * ROS2ではパラメーターの仕組みが変わったことで、すべてのROSノードのuse_sim_timeを書き換える必要があります。launchでは特別な記述が必要になります。

# ビルド
* install
    * ROS1ではdevelディレクトリが作成されて、`source devel/setup.bash`によりdevelのファイル/srcのファイルで実行をすることが出来ました。installディレクトリの作成は必須ではありませんでした。
    * ROS2ではinstallディレクトリの作成が必須です。`source install/setup.bash`をするしかないです。これにともないCMakeListでlaunchファイルやパラメーターファイルなどもすべてinstallディレクトリへのコピーの記述を書く必要があります。

# ROS周辺機能
* launchシステム 
* action_lib

# 主なパッケージ
* 個別パッケージの対応
* navigation stack
* slam系
    * gmapping
* rviz plugin

# コメント
逆に言うとこれ以外に大きな違いはないです。食わず嫌いをせずにROS2に乗り換えてみませんか?

# 目次ページへのリンク
[ROS2講座の目次へのリンク](https://qiita.com/srs/items/5f0d765343ca78f524ed)
[picoCTF] Operation Orchid Write Up

# picoCTF Forensics Operation Orchid

400点問題が解けてうれしかったので書きます。

## 復元
disk imageファイルが配られるので復元してみます。
```
gzip -d disk.flag.img.gz
```

## Autopsyでデータの閲覧
autopsyで見てみると、File TypesにPlain textがありました。
怪しいので見てみると```flag.txt```が！

しかし、```vol_vol4/root/flag.txt```は削除されています。
加えて、searchでpicoやCTFで調べたり、バイナリファイルを見てみてもそれらしいものはなかったので別の方法を試します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2261812/1503bd11-89ec-abc6-8213-d298454bcd57.png)


## binwalkで抽出

```
binwalk -e disk.flag.img
```

先ほどのrootが怪しいので、ディレクトリを見てみます。

```
cd _disk.flag.img.extracted/ext-root-0/root
ls -la
```

```:結果
flat.txt.enc
.ash_history
```

なにやら暗号化されたtxt.encがありました。おそらくこのファイルがフラグでしょう。
また、隠しファイルで.ash_historyがあります。

.ash_historyをcatして中身を見ます。

```:ash_history
touch flag.txt
nano flag.txt
apk get nano
apk --help
apk add nano
nano flag.txt
openssl
openssl aes256 -salt -in flag.txt -out flag.txt.enc -k unbreakablepassword1234567
shred -u flag.txt
ls -al
```

どのアルゴリズムで、どのキーで暗号化されているかがわかりました。

## 復号
どうやらこのファイルのようですね。
opensslで復号します。こちらの記事が参考になりました。

https://qiita.com/Yarimizu14/items/49690c141b62507e00d9


```
openssl aes256 -e -in flag.txt.enc -out output.txt -pass pass:unbreakablepassword1234567

*** WARNING : deprecated key derivation used.
Using -iter or -pbkdf2 would be better.
bad decrypt
4047394FD17F0000:error:1C800064:Provider routines:ossl_cipher_unpadblock:bad decrypt:../providers/implementations/ciphers/ciphercommon_block.c:124:
```
WARNINGが出ていますがいったん無視で

```
cat output.txt

picoCTF{h4un71ng_p457_0a710765}
```

フラグが取得できました！！
cscの作法 その358

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

# 練習問題
MDIコンテナでボタンでフォームを一つだけ表示せよ。

# サンプルコード

```
	public partial class formMain: Form {
		form1 f1;
		form2 f2;
		form3 f3;
		public formMain() {
			Text = "formMain";
			ClientSize = new Size(120, 300);
			Button btn1 = new Button();
			btn1.Location = new Point(10, 50);
			btn1.Text = "Gasket";
			btn1.Click += btn1_Click;
			Button btn2 = new Button();
			btn2.Location = new Point(10, 100);
			btn2.Text = "Koch";
			btn2.Click += btn2_Click;
			Button btn3 = new Button();
			btn3.Location = new Point(10, 150);
			btn3.Text = "Ray";
			btn3.Click += btn3_Click;
			Controls.AddRange(new Control[] {
				btn1,
				btn2,
				btn3
			});
		}
		void btn1_Click(object sender, System.EventArgs e) {
			if (f2 != null)
			{
				f2.Dispose();
			}
			if (f3 != null)
			{
				f3.Dispose();
			}
			f1 = new form1();
			f1.MdiParent = MdiParent;
			f1.Show();
		}
		void btn2_Click(object sender, System.EventArgs e) {
			if (f1 != null)
			{
				f1.Dispose();
			}
			if (f3 != null)
			{
				f3.Dispose();
			}
			f2 = new form2();
			f2.MdiParent = MdiParent;
			f2.Show();
		}
		void btn3_Click(object sender, System.EventArgs e) {
			if (f2 != null)
			{
				f2.Dispose();
			}
			if (f1 != null)
			{
				f1.Dispose();
			}
			f3 = new form3();
			f3.MdiParent = MdiParent;
			f3.Show();
		}
	}

```

以上。
【Linux】cronを設定する方法

## cron とは
cron を使用することで指定した時間や期間で自動的にコマンドを実行してくれます。

## 設定方法

cronの設定をするにはターミナルで`crontab -e`を実行します。

```zsh:ターミナル
crontab -e
```

するとエディタが開きますので設定ファイルを編集します。

このとき開くエディタは以下のように`EDITOR`変数で設定できます。

```.zshrc
export EDITOR=vim
```

設定ファイルは以下の形で記述します。

```:crontab〜
*  *  *  *  *  実行するコマンド
```

`*`の箇所にコマンドを実行する時間を記述します。

指定できる値は下記のようになります。

左から　分　時　日　月　曜　に対応します。
それぞれ以下の範囲を指定できます。

|指定対象|指定範囲|
|:-:|:-:|
|分|0〜59|
|時|0〜23|
|日|1〜31|
|月|1〜12 または jan〜dec|
|曜日|0〜7 または sun〜sat|

※曜日の0~7のうち0と7が日曜日になります。


ユーザーごとに設定でき、実行ユーザーは設定したユーザーになります。

他のユーザーの設定をしたい場合には`crontab -e`を実行する際にユーザーを指定します。

```zsh:ターミナル
crontab -u ユーザー名 -e
```


またコマンドの実行場所は実行ユーザーのホームディレクトリになります。
ディレクトリ移動が必要な場合には以下のように記述して移動します。

```
* * * * * cd 移動先ディレクトリ; 実行するコマンド
```

cronでコマンドが実行されると実行ユーザーにコマンドの標準出力、標準エラー出力がメールされるようになっています。
メールの宛先を変更したい場合には`MAILTO`変数で設定します。
```:crontab〜
MAILTO="sample@example.com"
*  *  *  *  *  実行するコマンド
```
またメールを送信しないでほしい場合には空にします。
```:crontab〜
MAILTO=""
*  *  *  *  *  実行するコマンド
```
Jetson Orin Nanoで YOLOv5 v7.0を動かす

* Jetson Orin Nano 8GB
* logicool C270N
* micro SDXC 128GB
* M.2 SSD PCIe Gen3 500GB
* JetPack 5.1.1 (Ubuntu 20.04.5 LTS, Python 3.8.10, OpenCV 4.5.4)

## Ubuntuの初期設定
☑I accept the terms of these licenses
Welcome：日本語
キーボードレイアウト：Japanese、Japanese
無線ネットワークに接続する
どこに住んでいますか？：Tokyo
あなたの名前：ubuntu
コンピューターの名前：JetsonOrinNano
ユーザー名：ubuntu
パスワード：ubuntu
自動的にログインする
Do not install Chromium Browser

## rootOnNVMeの実行
参考：https://www.youtalk.jp/2023/04/26/jetson-orin-nano-m2-ssd.html

$ ./copy-rootfs-ssd.sh
※確実に /dev/nvme0n1p1を /mntにマウントしておきます。

$ ./setup-service.sh

## パッケージ一覧やnummpyの更新等
sudo apt update
sudo apt install nano
sudo apt install python3-pip
sudo apt remove python3-numpy
sudo pip3 install numpy==1.24.4

## torchのインストール
参考：https://wiki.seeedstudio.com/YOLOv8-DeepStream-TRT-Jetson/

sudo apt install libopenblas-base libopenmpi-dev

wget https://developer.download.nvidia.com/compute/redist/jp/v50/pytorch/torch-1.12.0a0+2c916ef.nv22.3-cp38-cp38-linux_aarch64.whl

pip3 install torch-1.12.0a0+2c916ef.nv22.3-cp38-cp38-linux_aarch64.whl

## torchvisionのインストール
sudo apt install -y libjpeg-dev zlib1g-dev

git clone --branch v0.13.0 https://github.com/pytorch/vision torchvision

cd torchvision
python3 setup.py install --user

## その他ライブラリのインストール
sudo pip3 install tqdm==4.65.0
sudo pip3 install seaborn==0.12.2
>Successfully installed contourpy-1.1.0 fonttools-4.41.0 importlib-resources-6.0.0 matplotlib-3.7.2 packaging-23.1 pandas-2.0.3 python-dateutil-2.8.2 pytz-2023.3 seaborn-0.12.2 tzdata-2023.3 zipp-3.16.2

sudo pip3 install psutil==5.9.5
sudo pip3 install ultralytics==8.0.157

>Successfully installed MarkupSafe-2.1.3 charset-normalizer-3.2.0 contourpy-1.1.0 filelock-3.12.2 fonttools-4.42.0 importlib-resources-6.0.1 jinja2-3.1.2 matplotlib-3.7.2 mpmath-1.3.0 networkx-3.1 opencv-python-4.8.0.76 packaging-23.1 pandas-2.0.3 pillow-10.0.0 py-cpuinfo-9.0.0 python-dateutil-2.8.2 pytz-2023.3 requests-2.31.0 scipy-1.10.1 sympy-1.12 torch-2.0.1 torchvision-0.15.2 typing-extensions-4.7.1 tzdata-2023.3 ultralytics-8.0.157 zipp-3.16.2

## YOLOv5 v7.0のインストール
git clone https://github.com/ultralytics/yolov5.git
cd yolov5/

```:requirements.txt（全行、無効にしておきます。）
# Base ------------------------------------------------------------------------
# gitpython>=3.1.30
# matplotlib>=3.3

途中略

# albumentations>=1.0.3
# pycocotools>=2.0.6  # COCO mAP
```

## YOLOv5の動作確認
python3 detect.py --source 0 --imgsz=256 --nosave

:::note info
Jetson Orin Nano：1 frame：22.45ms（44.5fps）
:::

## こちらも参考にどうぞ
https://qiita.com/ez_tera/items/e62987c66113c2e9d85e
chatgptを使って、スマホのカメラでシューティングゲームができるwebアプリを作った。

chatgptを使って、スマホのカメラでシューティングゲームができるアプリを作りました。
アプリの概要です。
[概要]
スマホのカメラで、PCの画面を連動させて、シューティングゲームをするアプリです。
[showページ]
* PCなどで表示する。
* 画面中央にQRコードが表示される。
* 赤マークが的
* 青いマークが、スマホ側のカメラの中心を表す
* 青いマークが赤いマークに当たると当たり判定で、赤いマークが破壊される。

[indexページ]
* スマホなどのカメラの付いた機器でアクセスする。
* indexのQRコードを読み込むと、QRコードの位置を取得する。
* 取得した位置座標をindexへ送信し、PC上の青い的を動かす。
# アプリURL
https://ajaxtest.onrender.com/
https://ajaxtest.onrender.com/messages/show
# イメージ図
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/948501/c68a6e11-ba47-55af-3c97-39282d3d6d05.png)
# デモ画面
![IMB_oAgn6s.GIF](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/948501/a5ab2f98-76b5-d166-1041-4412f50efad8.gif)
RailsにMaterial Design for Bootstrapを導入する

## はじめに
* エンジニア転職用のRailsポートフォリオにMDBootstrapを導入した際の手順の記録です。
* MDBootstrapがどういうものかについては[こちら](https://shizuka-na-kazushi.style/2020/06/25/use-mdbootstrap-with-material-design-and-bootstrap/)や[こちら](https://souken-blog.com/2016/11/17/material-design-bootstrap/)、[公式](https://mdbootstrap.com/)などが参考になります。マテリアルデザインをBootstrapと変わらない使用感で導入できます。

## 導入手順の参考
* 公式（https://mdbootstrap.com/docs/standard/getting-started/installation/）
* https://zenn.dev/ryouzi/articles/2aa98e32f4ece6
* https://qiita.com/kcsan/items/5bcd1f62b37861d97d15

## 環境
* Ruby 3.1.2
* Rails 6.1.7.3
* AWS Cloud9で開発

## 手順
※rails newでアプリケーションを作成した後を想定しています。

**1\. Bootstrapの導入** 
MDBootstrapを使用するにあたり、まずはBootstrap本体やjQuery等、通常のBootstrapの動作に必要な準備を整える必要があります。

まずはyarnで以下の通りインストール。
```
$ yarn add jquery bootstrap@4.6.2 popper.js
```
<br>

次にconfig/webpack/environment.jsを追記。
```javascript:environment.js
const webpack = require('webpack');
environment.plugins.prepend(
  'Provide',
  new webpack.ProvidePlugin({
    $: 'jquery/src/jquery',
    jQuery: 'jquery/src/jquery',
    Popper: 'popper.js'
  });
);
```
<br>

次にapp/javascript/packs/application.jsに以下を追記。
```javascript:application.js
import "jquery";
import "popper.js";
import "bootstrap";
import "../stylesheets/application"; 
```
<br>

次にapp/views/layouts/application.html.erbの中を以下のように変更します。
```erb:application.html.erb
<%= stylesheet_pack_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
```
<br>

**2\. MDBootstrapの導入** 
yarnでMDBootstrapをインストール。
bootstrap-material-designパッケージではなくmdb-ui-kitをインストールしないとなぜか動作しませんでした。
```
$ yarn add mdb-ui-kit
```
<br>

次にapp/javascript/stylesheets/application.scssに以下を追記。
※ない場合は作成
```scss:application.scss
@use "~mdb-ui-kit/src/scss/mdb.free";
```

次にapp/javascript/packs/application.jsに以下を追記。
※mdb.jsファイルはこの後作ります。
```javascript:application.js
import * as mdb from 'mdb-ui-kit'; 
import './mdb';
```
<br>

最後にapp/javascript/packs/mdb.jsを作成し、以下の内容を記述。
```javascript:mdb.js
import * as mdb from "mdb-ui-kit/js/mdb.min.js"

// Function to refresh input element style when necessary
var mdbInputUpdate = function () {
  document.querySelectorAll('.form-outline').forEach((formOutline) => {
    new mdb.Input(formOutline).init();
  });
  document.querySelectorAll('.form-outline').forEach((formOutline) => {
    new mdb.Input(formOutline).update();
  });
}

document.addEventListener('turbolinks:load', () => {
  mdbInputUpdate();
});

document.addEventListener('turbolinks:render', () => {
  mdbInputUpdate();
});
```
<br>
以上で、Bootstrapにマテリアルデザインを取り入れられます。
各種パーツやコンポーネントは基本的に公式からコピー＆ペーストで使用できます（一部有料版の購入が必要なものも）。
Elixirの対話モードでシギルの動作を確認してみた

# 概要
Elixirの対話モードでシギルの動作を確認してみました。以下のページを参考にしました。

https://elixirschool.com/ja/lessons/basics/sigils

# 対話モードで実行
以下のコマンドを実行しました。
```
$ iex
Erlang/OTP 24 [erts-12.2.1] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [jit]

Interactive Elixir (1.12.2) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> ~c/2 + 7 = #{2 + 7}/
'2 + 7 = 9'
iex(2)> ~C/2 + 7 = #{2 + 7}/
'2 + 7 = \#{2 + 7}'
iex(3)> re = ~r/elixir/
~r/elixir/
iex(4)> "Elixir" =~ re
false
iex(5)> "elixir" =~ re
true
iex(6)> re = ~r/elixir/i
~r/elixir/i
iex(7)> "Elixir" =~ re
true
iex(8)> "elixir" =~ re
true
iex(9)> string = "100_000_000"
"100_000_000"
iex(10)> Regex.split(~r/_/, string)
["100", "000", "000"]
iex(11)> ~s/the cat in the hat on the mat/
"the cat in the hat on the mat"
iex(12)> ~S/the cat in the hat on the mat/
"the cat in the hat on the mat"
iex(13)> ~s/welcome to elixir #{String.downcase "SCHOOL"}/
"welcome to elixir school"
iex(14)> ~S/welcome to elixir #{String.downcase "SCHOOL"}/
"welcome to elixir \#{String.downcase \"SCHOOL\"}"
iex(15)> ~w/i love elixir school/
["i", "love", "elixir", "school"]
iex(16)> ~W/i love elixir school/
["i", "love", "elixir", "school"]
iex(17)> ~w/i love #{'e'}lixir school/
["i", "love", "elixir", "school"]
iex(18)> ~W/i love #{'e'}lixir school/
["i", "love", "\#{'e'}lixir", "school"]
iex(19)> NaiveDateTime.from_iso8601("2015-01-23 23:50:07") == {:ok, ~N[2015-01-23 23:50:07]}
true
iex(20)> defmodule MySigils do                             
...(20)> def sigil_u(string, []), do: String.upcase(string)
...(20)> end                                               
{:module, MySigils,
 <<70, 79, 82, 49, 0, 0, 5, 8, 66, 69, 65, 77, 65, 116, 85, 56, 0, 0, 0, 163, 0,
   0, 0, 16, 15, 69, 108, 105, 120, 105, 114, 46, 77, 121, 83, 105, 103, 105,
   108, 115, 8, 95, 95, 105, 110, 102, 111, ...>>, {:sigil_u, 2}}
iex(21)> import MySigils
MySigils
iex(22)> ~u/elixir school/
"ELIXIR SCHOOL"
iex(23)> 

```

# まとめ
何かの役に立てばと。
vpsのUbuntu Serverのフルバックアップ

バックアップの取り方はいくつかあるが、ここではUbuntuに標準搭載されたtarによる圧縮を用いた方法を示す。

## バックアップファイルの作成
まず、バックアップを保存するためのディレクトリを作成する。

```
mkdir /home/<username>/backup
```

今後バックアップするときに実行しやすいように、バックアップスクリプトを作成する。

```
vi /home/<username>/backup/backup.sh
```

バックアップスクリプトには以下のコマンドを追加する。

```
#!/bin/bash
BACKUP_DIR="/home/<username>/backup"
TIMESTAMP=$(date +"%Y%m%d%H%M%S")
tar -czvfp $BACKUP_DIR/backup_$TIMESTAMP.tar.gz --exclude=$BACKUP_DIR --exclude=/proc --exclude=/tmp --exclude=/mnt --exclude=/dev --exclude=/sys /
```

ここでtarは圧縮コマンドで指定したオプションは

>`-c`	新しいアーカイブを作る
`-z`	アーカイブをgzip形式で圧縮する
`-v`	処理したファイルを詳しく出力する。
`-f`	アーカイブファイル名を指定する
`-p`	所有者などのファイル属性を保持する。
`—exclude`　除外するディレクトリやファイルを指定する

である。
また、除外したディレクトリは以下である。

>`/proc`はプロセスの情報があるディレクトリで、普通のファイルシステムと違い、ハードディスクやSSDなどのストレージ上ではなく、メモリの中に作られる。
`/tmp`は一時的（temporary）なファイルを置くディレクトリで、プログラムが動作する際に一時的に利用するファイルを保存しておくなどの用途で利用される。
`/mnt`は新たに追加したストレージ装置などにアクセスできるようにしたマウントポイントが入った仮想的なディレクトリである。
`/dev`はハードウェアや仮想デバイスがファイルとして表現されたディレクトリである。
`/sys`はデバイスやドライバーの設定ファイルなどが置かれている。

最後にアーカイブするディレクトリが指定でき、`/`としてrootディレクトリ下の全てを指定している。

バックアップスクリプトを実行する。すべてのファイルにアクセスできるようにroot権限で行う。

```
sudo /home/<username>/backup/backup.sh
```

## バックアップファイルの転送

アーカイブファイルが作成されたらscpを用いてバックアップを保存したいマシンに転送する。
ローカルマシンに転送する場合は、ホストマシンに接続していないクライアントマシンのターミナル上で、

```
scp -P <ポート番号> -i <認証鍵のパス> <username>@<ipアドレス>:/home/<username>/backup/<backupfile> <保存先のパス>
```

とする。sshと違ってポートの指定は`-P`と大文字でなければならない。ipv6の場合はipアドレスを`\[ \]`で囲って記述しなければならない。



## リストア

リストア用の新しいUbuntuサーバーをセットアップし、新しいサーバーにUbuntuをインストールし、SSH接続を確立する。
バックアップファイルをリストアするためのディレクトリを作成する。例えば、`/home/<username>/restore`というディレクトリを作成する。

```
mkdir /home/<username>/restore
```

バックアップファイルを新しいサーバーに転送する。ローカルマシンから新しいサーバーにSCPコマンドを使用してバックアップファイルを転送する場合は以下のようになる。

```
scp -P <ポート番号> -i <認証鍵のパス> <バックアップファイルの送信元のパス> <username>@<ipアドレス>:/home/<username>/restore 
```

ホストマシンでrootディレクトリにバックアップファイルを展開する。

```
cd /
```
```
sudo tar -xzvf /home/<username>/restore /<backup_file>.tar.gz
```

`-x`は展開オプションである。

展開する際、同じ名前のファイルは上書きされるので、これでリストアが完了する。リストアが完了したら再起動する。

```
sudo reboot
```

新しいサーバーが再起動したら、バックアップから復元されたシステムが利用可能になる。

### ipアドレスに依存した設定の変更
元のシステムのipアドレスが記述されたファイルがある場合はipアドレスを変更する必要があるので、ipアドレスを検索する。例えば`/etc`内に前のipアドレスが記述されていないか確認する場合、

```
grep -r <ipアドレス> /etc
```
とすれば良い。
Vim 9.0 patchダイジェスト (2023/05)

[Vim](http://www.vim.org/)のリリースされた[patch](https://github.com/vim/vim/commits/master)の説明です。
([9.0.1504](https://github.com/vim/vim/commit/17b695190d63b2de745499cb40a383c2672e275e) ～ [9.0.1595](https://github.com/vim/vim/commit/e84c773d42e8b6ef0f8ae9b6c7312e0fd47909af))
**新機能、大幅な仕様変更には、:four_leaf_clover:が付いています。**

* [patch 9.0.1588](https://github.com/vim/vim/commit/9cf6ab133227ac7e9169941752293bb7178d8e38): コマンドラインでクリップボードレジスタからペーストした時に、incsearchがトリガーされない件を修正しました。
* [runtimeファイル更新](https://github.com/vim/vim/commit/b7398fe41c9e1e731d058105a34158871ee83e3f): [Todo](https://github.com/vim/vim/commit/b7398fe41c9e1e731d058105a34158871ee83e3f#diff-fb7eed53e3f2993f9d82c748206eaca82fd1d054a417c6de477bb54373d85643)更新。helpファイル更新。他。
* [patch 9.0.1546](https://github.com/vim/vim/commit/54be5fb382d2bf25fd1b17ddab8b21f599019b81): :four_leaf_clover:いくつかのコマンドを `'switchbuf'` の設定を参照して動作するようにしました。
* [patch 9.0.1515](https://github.com/vim/vim/commit/03ff1c2dde7f15eca5c9baa6dafbda9b49bedc3b): :four_leaf_clover:`reverse()`が文字列をサポートしました。(関連patch: [patch 9.0.1540](https://github.com/vim/vim/commit/f9dc278946d52235a0025fd347bd9ff571258470))

---
#### 凡例

|表記|意味|
|:------|:------|
|:four_leaf_clover:|新機能、大幅な仕様変更|
|:alien:|Vim開発者向けの追加、変更|
|`'hoge'`|オプション (`:h options`参照)|
|`:hoge`|Exコマンド (`:h :index`参照)|
|`hoge()`|組み込み関数 (`:h functions`参照)|
|`v:hoge`|Vim定義済変数 (`:h v:`参照)|
|`+hoge`|feature (`:h +feature-list`参照)|

---
#### 方針
[こちら](http://qiita.com/h_east/items/23cd0d10932505072e6b#%E6%96%B9%E9%87%9D)を参照。
JAVAで十進数から二進数変換

Decimal⇒十進数　　Binary⇒二進数　
class名　DecimalToBinary

    import java.util.Scanner;

    public class DecimalToBinary {
    public static void main(String[] args) {
      　Scanner scanner = new Scanner(System.in);//scannerインスタンス化

        System.out.print("10進数を入力して: ");
        int decimal = scanner.nextInt(); // 10進数を入力

        // 10進数を2進数変換メソッド
        String binary = decimalToBinary(decimal);
        System.out.println("2進数: " + binary);

        scanner.close();
    }

    // 10進数を2進数に変換するメソッド
    public static String decimalToBinary(int decimal) {
        if (decimal == 0) {
            return "0"; // 10進数が0の場合は2進数は0
        }

        StringBuilder binary = new StringBuilder();

        while (decimal > 0) {
            int remainder = decimal % 2; // 2で割った余りを求める
            binary.insert(0, remainder); // 余りを2進数の先頭に追加
            decimal = decimal / 2; // 10進数を2で割る
        }

        return binary.toString();
    }
}

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3293109/3ef51750-b475-3de0-c625-dd86f1bc0549.png)

問題なく動いてくれました。