OmniAICreator/Qiita-1.07M huggingface dataset:
IReadOnlyList<T>とIReadOnlyCollection<T＞とReadOnlyCollection<T>

たまに触ると[IReadOnlyList&lt;T&gt;](https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.ireadonlylist-1)と[IReadOnlyCollection&lt;T&gt;](https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.ireadonlycollection-1)と[ReadOnlyCollection&lt;T&gt;](https://learn.microsoft.com/en-us/dotnet/api/system.collections.objectmodel.readonlycollection-1)の関係を忘れてしまうので、メモです。

## ReadOnlyCollection&lt;T&gt;

そもそもReadOnlyCollection&lt;T&gt;クラスのネーミングが悪い気がしますが、これはIReadOnlyCollection&lt;T&gt;インターフェイスとセットのクラス<b>ではありません</b>。ドキュメントを見れば一目瞭然ですが、これはIReadOnlyCollection&lt;T&gt;だけでなく、IReadOnlyList&lt;T&gt;も実装しています。

IReadOnlyCollection&lt;T&gt;とIReadOnlyList&lt;T&gt;の違いはインデクサーの有無で、IReadOnlyCollection&lt;T&gt;にはインデクサーはないのに、ReadOnlyCollection&lt;T&gt;にはインデクサーがあるので混乱しますが、そもそもReadOnlyCollection&lt;T&gt;はIReadOnlyCollection&lt;T&gt;用とIReadOnlyList&lt;T&gt;用のクラスを兼ねていて、どちらのインターフェイスでアクセスするかでインデクサーへのアクセス可否が変わるというだけということです。

これはドキュメントに当たればすぐに分かる話ですが、得てしてコードをいじっているだけでは、ReadOnlyList&lt;T&gt;というクラスがないこと、List用のList&lt;T&gt;.AsReadOnly()メソッドも、Array用のArray.AsReadOnly&lt;T&gt;(T[])メソッドも生成されるのはReadOnlyCollection&lt;T&gt;ということの理由にたどり着かないのですよね。

## Dictionary&lt;TKey, TValue&gt;のReadOnly化

Dictionary&lt;TKey, TValue&gt;からReadOnlyDictionary&lt;TKey, TValue&gt;クラスをコンストラクターで生成した場合、TValueがListやArrayなどのコレクションの場合、そのままではコレクションの要素は当然ReadOnlyにはなりません。したがって、一旦TValueをReadOnlyCollection&lt;T&gt;に変換した上で、インデクサーの必要性に応じてIReadOnlyList&lt;T&gt;かIReadOnlyCollection&lt;T&gt;にキャストする必要があります。

Listの場合
```csharp
var d1 = new Dictionary<string, List<int>>();
...
IReadOnlyDictionary<string, IReadOnlyList<int>> d2 =
    new ReadOnlyDictionary<string, IReadOnlyList<int>>(d1.ToDictionary(
        x => x.Key,
        x => (IReadOnlyList<int>)x.Value.AsReadOnly()));
```
```csharp
var d1 = new Dictionary<string, List<int>>();
...
IReadOnlyDictionary<string, IReadOnlyCollection<int>> d2 =
    new ReadOnlyDictionary<string, IReadOnlyCollection<int>>(d1.ToDictionary(
        x => x.Key,
        x => (IReadOnlyCollection<int>)x.Value.AsReadOnly()));
```

Arrayの場合
```csharp
var d1 = new Dictionary<string, int[]>();
...
IReadOnlyDictionary<string, IReadOnlyList<int>> d2 = 
    new ReadOnlyDictionary<string, IReadOnlyList<int>>(d1.ToDictionary(
        x => x.Key,
        x => (IReadOnlyList<int>)Array.AsReadOnly(x.Value)));
```
```csharp
var d1 = new Dictionary<string, int[]>();
...
IReadOnlyDictionary<string, IReadOnlyCollection<int>> d2 = 
    new ReadOnlyDictionary<string, IReadOnlyCollection<int>>(d1.ToDictionary(
        x => x.Key,
        x => (IReadOnlyCollection<int>)Array.AsReadOnly(x.Value)));
```

やや面倒ですが、こんな感じかと思います。なお、TValueがNullの可能性がある場合は、ReadOnlyCollection&lt;T&gt;に変換する前にNullチェックも必要になります。
Google カレンダーにイベントを追加するURLの日時パラメータのフォーマット

Googleカレンダーに、新しいイベントを作るためのURLのパラメータです。
# はじめに
GoogleカレンダーのURL(https://www.google.com/calendar/event)にパラメータを付けて送る（ブラウザのアドレス欄に入れてEnter）とGoogleカレンダーの新しいイベントを作るダイアログが開きます。
基本的な使い方は、「google カレンダー イベント登録 URLパラメータ」などで、検索してみてください。たとえば[こちらの方のページ（Engineering Tech Dojo）](https://tech.fun-toy-life.com/entry/2022/08/28/180534 "APIを使わずにHTML「aタグ」で作成したリンクでGoogleカレンダーに予定を入れる方法")

# 日時のフォーマット
datesパラメータの書き方

| 記法（開始日時/終了日時） | 記述例 | 実際に入力される期間（JST） |
|---|---|---|
| YYYYMMDD<br>/YYYYMMDD (*1) | 20230520<br>/20230603 | 2023/5/20<br> - 2023/6/2 終日 |
| YYYYMMDDThhmmss<br>/YYYYMMDDThhmmss | 20230520T120000<br>/20230603T171500 | 2023/5/20 12:00<br> - 2023/6/3 17:15 |
| YYYYMMDDThhmmssZ<br>/YYYYMMDDThhmmssZ (*2) | 20230520T120000Z<br>/20230603T171500Z | 2023/5/20 21:00<br> - 2023/6/4 2:15 |

*1) 終了日はURLに記述した日の１日前の日になります。（開始日と同じ場合はならない）この記法の場合、イベントの終日チェックが入ります。
*2) 時刻の末尾にZを付けるとGMT（グリニッジ標準時）での指定となり、入力される日本時間は+9時間となります

# URLのサンプル
次のURLをブラウザのアドレスらのにコピペすると、あなたのGoogleカレンダーに新しいイベントを追加するダイアログが出ます。
```
https://www.google.com/calendar/render?action=TEMPLATE&text=楽しいイベント&dates=20240127T094000/20240320T150000&details=おやつは500円まで&location=ナイショの基地&sf=true&output=xml
```
＊動作を確認した後はダイアログをキャンセルするのを忘れないようにして下さい
Javascript：テンプレートリテラル

# テンプレートリテラル
文字列を結合する場合、テンプレートリテラルを使用することを推奨。  
テンプレートリテラルを使用すると、コードがより読みやすくなり、エラーを防ぎやすくなる。　　
下記のように、文字列をグレイヴ・アクセント（`）で囲み、変数を入れるときはドル記号と波括弧でくくることで+で文字列結合などを行わず簡潔に表示内容を記述することができる。
~~~ javascript
function replaceLastFourWithHint(stringInput) {
  return stringInput.length < 6
    ? "There is no Hint"
    : `Hint is: ${stringInput.slice(-4)}`;
}
~~~

以下のように、'\n'(改行コード)を記述せずとも直感的に記述できる。
~~~ javascript
console.log(`string text line 1
string text line 2`);
// "string text line 1
// string text line 2"
~~~

その他、便利な記法により読みやすくすることができる書き方があるので、MDNを参考に学んでいきたい。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Template_literals
【Python】pathlibとjson.load関数を使って、JSONファイル内の値を取得する方法

# 概要
* Pythonで`pathlib`と`json.load`を使って、JSONファイル内のキーとその値を取得する方法を記載します。

# 前提
* Python 3.10.9

# 実行方法
* Jsonファイルに以下のように記載します。

```foo/hoge_key.json
{
    "name": "hoge",
    "gender": "male",
    "age" : "29"
}
```

* 次に、`pathlib`関数を利用して以下のように記載します。

```foo/views.py
from pathlib import Path
import json

key_path = Path('./foo/hoge_key.json')

with open(key_path, 'r') as f:
    key_json: Dict = json.load(f)

name = key_json.get('name')
gender = key_json.get('gender')
age = key_json.get('age')
```

* 上記コードにより、以下が実施できます。

1. `pathlib.Path`クラスを使って、`hoge_key.json`のパスを表す`key_path`変数を定義。
2. `open()`関数を使ってファイルを開き、JSON データを読み込んで`key_json`変数に格納。
3. `key_json`変数から`name`、`gender`、`age`の値を取り出して、それぞれの変数に代入。
4. 上記により、変数`name`、`gender`、`age`を使うことで、JSONファイルで定義した値が使用できるようになりました。

### `json.load()`とは？
* JSON データを Python オブジェクトに変換するための関数。
* JSON 形式の文字列またはファイルオブジェクトを引数に取り、それを Python の辞書やリストなどのオブジェクトに変換します。
* 標準ライブラリの`json`モジュールを使用(`import json`)。
* 参考：
    * [【Python】JSONデータの扱い方の基本（jsonモジュール）](https://hibiki-press.tech/python/json/1633#:~:text=JSON%E3%83%87%E3%83%BC%E3%82%BF%E3%82%92Python%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E3%81%B8%E5%A4%89%E6%8F%9B%E3%81%99%E3%82%8B%E3%81%AB,loads()%E3%82%92%E4%BD%BF%E3%81%84%E3%81%BE%E3%81%99%E3%80%82)

### パース (parse)とは？
* JSON データを扱う際の「パース (parse)」とは、JSON 形式で書かれた文字列を解析して、Python のデータ構造に変換することを指しています。
* JSONをPythonの中で利用できるよう変換する、という意味ですね。
* ちなみに、`json.load()`の逆で、「Pythonの値をJSONデータに変換」する際は、`json.dumps()`関数を利用します。
* 参考：
    * [【Python】JSONデータ読み込み・パース・文字列変換・書き込み方法｜データ前処理コードの使い方徹底解説](https://di-acc2.com/programming/python/3726/#index_id4) 


### 例外処理について
* 上記の場合、`hoge_key.json`があり、中身も正しい前提ですが、以下のような例外処理を加えるべきという場合もあると思います。
    * `FileNotFoundError`: 該当のファイルが存在しない場合のエラー
    * `json.JSONDecodeError`: JSONデータが不正である場合のエラー
* 日本語で文字列がUnicodeエスケープされてしまう場合は以下を参照ください。
    * [【Python】JsonResponseでエンコードの文字化けが起きてしまう場合の原因と解決方法](https://qiita.com/Ryo-0131/items/20d6fbcfba5f438819d2)
Reactでインクリメンタルサーチを実装する。

Reactでインクリメンタルサーチを実装したので、備忘録として残します。

>インクリメンタルサーチとは：
文字を入力していく毎に検索結果が絞り込まれていく検索方式のこと
https://wa3.i-3-i.info/word13753.html


[![Image from Gyazo](https://i.gyazo.com/141ad6a5bcc0f54284702a0f9854a43f.png)](https://gyazo.com/141ad6a5bcc0f54284702a0f9854a43f)

[![Image from Gyazo](https://i.gyazo.com/c75ee1bedb6eb81159b8056defa254c7.png)](https://gyazo.com/c75ee1bedb6eb81159b8056defa254c7)

[![Image from Gyazo](https://i.gyazo.com/4f054de153805a0136aebde806fbf8c1.png)](https://gyazo.com/4f054de153805a0136aebde806fbf8c1)

処理の流れ
・絞り込み検索対象の一覧を取得する。
・INPUTに入力した値を保持するuseStateを用意する。
・INPUTに入力するたびhandleChangeファンクションを呼び出すようにする。
・handleChangeファンクションで入力した値をstateにsetさせる。
・stateが更新されたので、コンポーネントが再描画される。
・検索結果が表示される。

```jsx
  const [searchTerm, setSearchTerm] = useState("");
  const handleChange = (event) => {
    setSearchTerm(event.target.value);
  };

  const filteredCharacters = Object.values(characters).filter((character) => character.name.includes(searchTerm));

   return (
    < div >
      <input
        type="text" autoFocus
        placeholder="検索"
        value={searchTerm}
        onChange={handleChange}
      />

      <table>
        <thead>
          <tr>
            <th>ファイター番号</th>
            <th>ファイター名</th>
          </tr>
        </thead>
        {
          Object.keys(filteredCharacters).map((item) => {
            return (
              <>
                <tbody>
                  <tr>
                    <td>{filteredCharacters[item].no}</td>
                    <td>{filteredCharacters[item].name}</td>
                    <td>詳細</td>
                  </tr>
                </tbody>
              </>
            )
          })
        }
      </table>
    </div >
  )
}

```
xdebugをdocker-composeでpeclではなくgitでインストールするサンプル

# 背景

PHPの環境をdocker-composeを利用して立ち上げる際に
デバッグ作業としてxdebugを用いていたのですが

```dockerfile
RUN pecl install xdebug-3.2.0 && docker-php-ext-enable xdebug
```

上記のようなコマンドを記載しても、peclサーバーにアクセスできなかったり
アクセスできても何故かxdebugがリポジトリに見つからないというエラーが多発していました。

この厄介なところはたまに上手くいくということで、今まで解決法の模索を放置していたのですが。
ChartGPT4と相談して対応策が見つかったので共有したいと思います

# 解決策

解決策としてはgitから直接xdebugのソースをダウンロードしてビルドし
稼働するやり方でした。

下記がサンプルになります

```dockerfile
# ベースイメージの指定
FROM php:8.1-apache

# 必要なパッケージのインストール
RUN apt-get update && \
    apt-get install -y --no-install-recommends \
        git \
        zlib1g-dev \
        libzip-dev \
        unzip && \
    docker-php-ext-install zip

# Xdebugのインストール
RUN git clone https://github.com/xdebug/xdebug.git \
    && cd xdebug \
    && git checkout xdebug_3_2 \
    && phpize \
    && ./configure \
    && make \
    && make install

# Xdebugを有効にする
RUN echo 'zend_extension=xdebug.so' >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini

# Apacheの設定
RUN a2enmod rewrite

# 必要に応じて他の設定を追加
...

```

git cloneの部分がそうですね。
php8.1を利用したいので、バージョンは3.2を指定しています

これで安定してビルドが通るようになるのではと期待しています
もしまた問題が発生したら、こちらに対応策を追記予定です
2023-05-14Git学習メモ

# ユーザー設定
自分が誰であるのかを登録する．
ユーザー名とメールアドレスを使う．

```Bash
# ""内は各々の情報にする
$ git config --global user.name "ユーザー名"
$ git config --global user.email "example@example.com"
```

# ローカルレポジトリの作成
### レポジトリとは
Gitがバージョン管理のためのファイルを保管する仮想的な場所．ゲームでいえばセーブデータの作成にあたる．

### 作成
```Bash
# 管理したいディレクトリまで移動してから以下を実行
$ git init
```

# バージョン管理をする
### インデックスに登録
コミット対象を選択する操作．いうなればバージョン管理システムに入れるファイルを選択するみたいな感じ．
```Bash
$ git add ファイル名
```

### コミット
インデックスに登録されているファイルを一つのバージョンとしてきろくする操作．先程インデックスに登録したものが記録される．ゲームでいえばセーブすることにあたる．
```Bash
# これがどんなことをしたバージョンなのかをメッセージに書く
$ git commit -m "メッセージ"
```
コミットメッセージを書いておくと，後々バージョンを戻すときに目印になりそう．

### コミット履歴を確認する
コミットした日時，人，コメントなどが表示される．

```Bash
$ git log
```

### コミット内容を確認する
```Bash
$ git show HEAD:確認したいファイル名
```
ちなみに，3個前にコミットしたときの内容を確認したいときは
`HEAD`を`HEAD~3`のように書き換える．
ABC301回答メモ

0.はじめに
　GW期間を経て久々のコンテスト。ゼルダをしてたらいつの間にか開始時間に
　なっていて慌ててスタート。D問題に苦戦していて時間ギリギリまで
　粘っていたら、会社から電話があってトラブル対応に・・・。
　バタバタしているうちに終わり３問正解で終了。
　レートは微増で終わりました。

1.A - Overall Winner
　TとAの数が同じ場合の解決法として、最後の勝利者でない方を
　総合勝者とすることで実装しました。

　https://atcoder.jp/contests/abc301/submissions/41352697

2.B - Fill the Gaps
　リストを先頭から見ていき、前の数字との差が2以上空いていたら
　間を埋める数字を入れていくという形で実装しました。

　https://atcoder.jp/contests/abc301/submissions/41358622

3.C - AtCoder Cards
　考え方としては、いかさまをすればカードの並び順は関係ないので
　単純にSとT内でアルファベット毎に出現数を比較し
　　・出現数に差異がある文字がa, t, c, o, d, e, r以外ならNo
　　・上記以外の差異数＝置き換えなければいけない文字数が@の数より多ければNo
　　・上記以外ならYes
　といった考えで実装しAC。

　https://atcoder.jp/contests/abc301/submissions/41372054

4.D - Bitmask
　コンテスト中はSとNをそれぞれ二進法で管理して
　桁をそろえ頭から比較していきNよりSを小さくするように
　調整していくと言った感じで実装をしていきました。
　結局、考慮の穴等も多く穴埋めてる間に時間が無くなってしまいました。

　コンテスト後に解説を見て根本のとこで勘違い(なぜか文字列Sを後ろから
　切り取ってよいと思っていました・・・)していたので
　素直に解説通りに実装しました。

　実装
　　1)文字列Sを数値SNに変換。その際"？"は”0”とし、とりうる最小値を
　　求める。(解説を見てreversedという書き方を知りました。)
```
for i in reversed(range(SL)):
    if(S[SL-i-1]=="1"):
        SN+=1<<i
```
　　2)SNがNより大きかったら-1を表示
　　3)上記以外の時はSを先頭から見ていき
　　　?を1に変えた場合のSNがNを超えなければ
　　　変えていく。
```
    for i in reversed(range(SL)):
        if(S[SL-i-1]=="?"):
            if(SN+(1<<i)<=N):
                SN+=1<<i
```
　　4)3)の結果を表示して終了

　https://atcoder.jp/contests/abc301/submissions/41402835

以上
2023.4.21 プログラミングメモ

・Google Fontsでアイコンが使用できる。
①HTMLに下記コードを追加
<link href="https://fonts.googleapis.com/icon?family=Material+Icons"
      rel="stylesheet">

②Material Icons でアイコンを検索し、コードをコピペ
例：<span class="material-icons">close</span>

font-sizeにてサイズ変更が可能
colorなども変更できるので便利


・参考URL
https://developers.google.com/fonts/docs/material_icons?hl=ja
https://fonts.google.com/icons?icon.style=Filled&icon.set=Material+Icons&icon.query=close

・メソッドチェーン
$(() => {
  $('button').click(() => {
    // $('p').text('おはよう！');
    // $('p').addClass('red-text');

    // $('p').text('おはよう！').$('p').addClass('red-text');

    $('p')
      .text('おはよう！')
      .addClass('red-text');
  });
});

こうした書き方をメソッドをつなげていくという意味で、メソッドチェーンと呼びます。

・複数の要素を扱う
ボタンをクリックすると◯番目の文字列の色を変更する
HTML
  <button>Go!</button>
  <ul>
    <li>Item 0</li>
    <li>Item 1</li>
    <li>Item 2</li>
    <li>Item 3</li>
    <li>Item 4</li>
    <li>Item 5</li>
  </ul>

jQuery
・クリックすると上から3番目の要素が(Item 2)
$(() => {
  $('button').click(() => {
    $('li')
    .eq(2)
    .addClass('red-text');
  });
});

・クリックすると上から「奇数番目」と「最後」の要素が
(Item 0, Item 2, Item 4, Item 5)
$(() => {
  $('button').click(() => {
    $('li:nth-child(odd), li:last-child')
      .addClass('red-text');
  });
});
Power Automate DesktopとPower Automateは別物

# 結論
Power Automate DesktopとPower Automateは別物と考えたほうが良さそう。

# 私自身がしていた勘違い
Power Automate Desktopを使い始めた頃、「Power Automateのデスクトップ版がPower Automate Desktopで、どちらも同じものだろう」と勘違いしてました。
ただ、使っているうちに段々と違和感を感じるようになり、最終的にPower Automate DesktopとPower Automateは別物と考えたほうがいいという結論になりました。

# それぞれの違い
以下の記事が参考になるかと思います。

https://inhousese.break-employee.com/2023/01/19/powerautomate_powerautomatedesktop/#toc4

https://www.qes.co.jp/media/powerplatform/a149#:~:text=Power%20Automate%20Desktop%E3%81%AE%E6%93%8D%E4%BD%9C,%E3%81%8B%E3%82%89%E4%BD%9C%E6%88%90%E3%81%8C%E3%81%A7%E3%81%8D%E3%81%BE%E3%81%99%E3%80%82

私的には以下のようなイメージでおります。
|名称|説明|
|--|--|
|Power Automate Desktop|個々人のパソコンの自動操作を実現できるアプリ(おそらくRPAと聞いて多くの人が持つイメージのもの)|
|Power Automate|Power Platformのクラウド上でのアクションをトリガーにした処理を実装できるアプリ(サーバーのバッチ処理というイメージが近そう)|

# あとがき
Power Automate Desktop、Power Automateを使うときは2つは別物という認識をもっておいて損はないと思います。
Memo: Test push notification on iOS simulator

Step 1: Enable push notificaiton on certificate on Apple developer portal

Step 2: Request Push notification in iOS app

```swift
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .badge, .sound]) { success, error in
        if let error {
            print("Notification access not granted.", error.localizedDescription)
        }
    }
```

Step 3: Save this `test.apns`

```json
{
    "Simulator Target Bundle": "<bundle_id>",
    "aps":{
        "alert":"Test",
        "sound":"default",
        "badge":1
    }
}
```
Step 4: drag `test.apns` to iOS simulator

![Screenshot 2023-05-14 at 11.04.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96370/50b6b691-ce25-320d-2cfb-fa83eba91ac8.png)
LinuC Level1合格体験記

# はじめに
3月にLinuC Level1に合格したので、今更ですが当時のことを書こうと思います。


# 学習前の状況
- モチベーション
    - Javaエンジニアからインフラエンジニアに転職し、LinuCくらい勉強しないと業務にならないぞと言われたため渋々…くらいのモチベーションだった
- Linuxの知識
    - 研修で１か月やっただけなので、ほとんどなにもわからない状態。黒い画面になんか打つんでしょ？


# 使った教材
### 
- [Linux教科書 LinuCレベル1 Version 10.0対応(通称：あずき本)](https://www.shoeisha.co.jp/book/detail/9784798166162)
- [Ping-t](https://mondai.ping-t.com/)

# やったこと
#### 試験に申し込む
締め切りが先の仕事はやらないのと同じで、資格試験も締め切りがないと一生勉強しません。
なにはさておきとりあえず試験に申し込みましょう。
101と102どっちから受けてもいいらしいですが、特に理由がなければ101から受ければいいんじゃないかなと思います。

#### Ping-tの有料プランに登録する
~~お金を払うと否が応でも勉強せざるを得なくなります。もったいないですしね。~~
というかLinuC102の問題は有料でした
私はOSSDBを取るときに登録していたので、そのまま流れで利用しました。

#### 仮想環境を立てる
ぐぐればたくさん先達の記事が出てくるので、それに従って仮想環境を立てるといいと思います。参考書にも仮想環境が付いているみたいなので、それを使ってもいいと思います。
私はOSSDB Silverの勉強をしたときに立てた環境があったのでそれを使いました。

#### 参考書を単元に区切って読む
単元に区切って、一回読み切る→問題演習→次の単元へ→のやり方にしました。
参考書読みながら、出てきたコマンドは片っ端から叩いて出力結果を眺めるといいと思います。実際に画面が動いているのを見ながらやると理解しやすいと思います。

#### 読んだ単元の問題を解く
参考書を読み終わったらとりあえずPing-tを解きました。
単元ごとに問題を絞って、演習→正解した問題も含めて解説読む→正解した問題も含めて再演習を繰り返しました。
解説を読みながらコマンドを叩いて復習をしました。「こんなの参考書に載ってたか？？？」というものも出てきたので、かなり意味があったと思います。

#### 参考書の模擬試験を解く
Ping-tをあらかた解けるようになって、「合格できるな！」と思えるくらいになってから模擬試験を解きました。
Ping-tは本番や模擬試験より簡単なので、参考書の模擬試験や演習問題解くとしっかり間違えましたが、同様に解説や参考書を確認しながら復習をしました。

# 感想
- OSSDBのときよりしっかり勉強したため、余裕をもって合格できました。特に101で８割取れたのは嬉しかったです。反面、シェルとかNW周りとかの苦手意識あった単元は結局点数が伸びていないので要復習ですね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/616564/337677cb-eb73-c12e-4229-62948bdab7dd.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/616564/8d9af0b7-a3f0-e8c8-4aa0-acc3e290769c.png)

- 業務で実機を触る機会がかなりあるので、作業効率を高める意味でも勉強した甲斐があったと思います。毎回基本的なコマンドまでぐぐってたら仕事にならないですしね…
Gatsbyでビルドができない  [Problems with gatsby-source-microcms plugin options: "apiKey" is required]

## ブログ構成
- Jamstack
    - Gatsby
    - GraphQL
    - React
    - microCMS

## やりたいこと
ローカルで開発したブログ（ヘッドレスCMS） を久しぶりローカルで実行したい。

## 実行コマンド

```
npm run start
```

## 実行後のエラー
```
> 03-microcms@1.0.0 start
> gatsby develop

success open and validate gatsby-configs - 0.087s
success load plugins - 0.263s
success onPreInit - 0.069s
success initialize cache - 0.008s
success copy gatsby files - 0.072s

 ERROR 

Problems with gatsby-source-microcms plugin options:
"apiKey" is required

not finished onPreBootstrap - 0.053s
```

## 考えられること
- APIKeyの指定方法、記述方法がおかしい
- `"apiKey" is required` とあることからそもそも、keyを認識できていない
- gatsby-source-microcms のパッケージに問題がある

## APIKEYの設定ファイルを見てみる
```React:gatsby-config.js
module.exports = {
  siteMetadata: {
    title: "Blog",
  },
  plugins: [
    "gatsby-plugin-react-helmet",
    {
      resolve: "gatsby-source-microcms",
      options: {
        // microCMSのAPIキーを環境変数から参照する
        apiKey: process.env.MICROCMS_API_KEY,
        // microCMSのサービスID
        serviceId: "xxx",

        // 省略
      },
    },
  ],
};
```

## 解決策
npm run start する際にapiKeyを渡すのを忘れていた

```
env MICROCMS_API_KEY=[apiKey] npm run start
```

たとえばapiKeyが `abcdefghijklmn` だった場合、コマンドは以下となる
apiKeyを忘れた場合は、microCMS の管理画面にて確認できる
```
env MICROCMS_API_KEY=abcdefghijklmn npm run start
```

## 実行後
以下にアクセスして、ブログを確認できたらOK
```
  http://localhost:8000/
```
map()メソッドの処理

サイ本の勉強アウトプット。
map()メソッドは、配列の要素を1つずつ指定した関数に引数として渡し、この関数から返された値を配列に格納し、この配列を返します。
```js
const a = [1, 2, 3];
const b = a.map(function (x) {
  return x * x;
});
console.log(b); // [1, 4, 9]
```
map()a内のコールバック関数はこのようになっています。
第一引数(value) : 配列の要素を順番に取り出だす。
第二引数(index) : 配列のインデックス番号を順番に取り出す
第三引数(array) : 配列の内容
```js
const array = ["あ", "い", "う", "え",];

array.map(function(value, index, array){
  console.log(value, index, array);
})
// あ 0 ["あ", "い", "う", "え",]
// い 1 ["あ", "い", "う", "え",]
// う 2 ["あ", "い", "う", "え",]
// え 3 ["あ", "い", "う", "え",]
```
map()メソッドに指定した関数は、forEach()の場合と同じように呼び出します。ただしmap()メソッドの場合は、指定した関数から値を返すようにしてください。map()は新しい配列を返すので、メソッドが呼び出された配列は変更しないです。
map()は主に配列内の要素をそれぞれ計算したり、特定の要素を書き換えたりするのに利用します。

#### 参考サイト
https://gxy-life.com/2PC/javascript/map20220705/

#### 勉強した本
https://www.amazon.co.jp/JavaScript-%E7%AC%AC7%E7%89%88-David-Flanagan/dp/4873119707/ref=pd_vtp_h_pd_vtp_h_sccl_1/355-2445868-3340539?pd_rd_w=WBQa4&content-id=amzn1.sym.cbe5b1af-8663-4a63-8153-1f9ef8eb65e4&pf_rd_p=cbe5b1af-8663-4a63-8153-1f9ef8eb65e4&pf_rd_r=3AHRNNG2838BPDJ6XJTJ&pd_rd_wg=CeNj7&pd_rd_r=5e9ae908-b4ed-4a73-a5d4-307326039e17&pd_rd_i=4873119707&psc=1
Houdiniで焼いたAmbientOcclusionが汚くなる問題の解決メモ

Houdiniを触り始めて宇宙船を作ってみたは良いものの、AmbientOcclusionが汚くて半日躓いたメモ

以下の手順でAmbientOcclusionを焼こうとしている時のメモ
- Houdini 19.0.531
- AutoUVを使っている
- BakeTextureで焼いている

## 原因
AutoUVで展開したUVが重なってしまうことが原因
重なると遮蔽度を共有してしまうので、片方が遮蔽濃い状態だともう片方も遮蔽が濃いとして認識される

ぶっ刺してるだけで繋がってないパーツとか、繋がってるけど縦横の比率が偏っているPrimitive、booleanでくり抜いただけの穴とかの付近がなりやすい
特に最後のbooleanでくり抜いただけの穴は、うまく展開するには凹部分の入り口でSeamを切らないといけないけどAutoUVではあんまり判別してくれない

### 解決方法
- DivideノードでBrickerPolygonsで縦横比がいい感じの分割をする
    - 雑だけど手っ取り早い
    - AmbientOcclusionのためにプリミティブを増やしたくないので、BakeTextureのHighResObjectに指定するだけのオブジェクトとして分けた方がいい
- 凹部分を浅くする
    - 画像には載せてないが機銃の部分もなってた
    - 大体これで解決はする
- AutoUVのisland paddingを上げる
    - 安牌
- AutoUVを使わずに手作業で頑張ってSeamを切る
    - すごくやりたくない

## 画像
### 問題があるやつ
コックピット周辺に黒い模様が表示されてしまっている

<img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154377/dc6cc03c-53d4-e4dc-16c2-1640b909a9f8.png">
<img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154377/703b3b13-de2b-bde0-e2bb-015a5933febf.png">
<img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154377/7e505f88-9491-d9f9-6eea-1f5927434c3c.png">

### 問題を解決したやつ
<img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154377/1a2e41d3-48c1-8cd2-c57e-22705981f044.png">
<img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154377/c838e2a7-d506-31fb-4aaf-7b051e158c1c.png">


### 問題のあるUV
よく見ると中央下段部分でUVが重なっているのがわかる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/154377/b279f0c6-c328-74bc-7822-169d60f5cc5a.png)

どうせ左右対称なのでUVもミラーリングしたいが、よくわからない

### 他
- このHoudiniバージョンだけかもしれないが、BakeTextureを実行してテクスチャを出力した後、MaterialがDirtyになっていないのかUVがRefreshされないバグがありそう？
 Houdiniを再起動するとBake後のテクスチャがちゃんと反映されて綺麗に治る。
 とっととアップデートしたほうが良さそう

- テクスチャが一生反映されなくて原因ずっと探してたら、1時間後Material表示ボタンがSceneViewのサイドバーにあることに気付いて非表示状態だったのを見つけてちょっとイライラした（ちょっとじゃない :rage:）
OSSDB-Silver合格体験記

# はじめに
2月にOSSDB Silverに合格したので、今更ですが当時のことを書こうと思います。


# 学習前の状況
- モチベーション
    - 業務でPostgres使うことになり、Silverくらい取れないと業務にならないぞと言われたため渋々…くらいのモチベーションだった
- DBの知識
    - SQLServer使った案件に入っていたことがあるので基本的なSQLはなんとなく書けると思っている（ストアドプロシージャとかやってた）
    - 応用情報処理受けたときは午後のDB問題が難しくて諦めた程度の知識しかない
    - RDBってなんだよ、とかの概要的な話はわかってる


# 使った教材
### 
- [OSS教科書 OSS-DB Silver ver.2.0対応(通称：緑本)](https://www.amazon.co.jp/OSS%E6%95%99%E7%A7%91%E6%9B%B8-OSS-DB-Silver-%E7%AC%A0%E5%8E%9F%E8%BE%B0%E4%BB%81-ebook/dp/B00G9QJTWO)
- [Ping-t](https://mondai.ping-t.com/)

# やったこと
#### 試験に申し込む
締め切りが先の仕事はやらないのと同じで、資格試験も締め切りがないと一生勉強しません。
なにはさておきとりあえず試験に申し込みましょう。

#### Ping-tの有料プランに登録する
~~お金を払うと否が応でも勉強せざるを得なくなります。もったいないですしね。~~
というかOSSDBの問題は有料でした
私はOSSDBのあとLinuCを取る予定だったので、最長の３年プラン（￥12,800（2023/05現在））にしました。

#### 仮想環境を立てる
"VirtualBox Postgres"とかでぐぐればたくさん先達の記事が出てくるので、それに従って仮想環境を立てました。

#### とりあえず参考書を一通り読む
とりあえず参考書を全部読むところから始めました。
一回で理解しながら読むと一生終わらなさそうだったので、よくわからなくてもとりあえず読み進めていきました。
参考書に出てきたコマンドは片っ端から仮想環境で実行しました。よくわからなくても、コマンドを叩いて、「わ！！出力返ってきた！！」って眺めてるだけでも効果あったと思います。

#### とりあえず問題を解く
参考書を読み終わったらとりあえずPing-tを解きました。
単元ごとに問題を絞って、演習→正解した問題も含めて解説読む→正解した問題も含めて再演習を繰り返しました。再演習しながらコマンドを叩くといいと思います。~~私はちゃんとやらなかったので反省…~~

#### 公式サイトの問題を解く
[公式サイトのサンプル問題](https://oss-db.jp/measures/sample)を解きました。問題難易度はPing-tより高めなので、Ping-tの内容をある程度理解してから挑戦して仕上げに使うとよさそうです。
試験前には、この問題が８割くらい解けるようになっていたと思います。

# 当日
- 大雨の中、びしょ濡れになりながら試験センターに向かいました
- 途中のコンビニでラムネを買おうとしたらコーラ味しかなくて仕方なくそれを買って食べました
- 実際の試験は、公式のサンプル問題よりも難易度が高かったのでかなり焦りましたが、無事合格できました。

# 感想
- 参考書の巻末の模擬試験は本番の形式とだいぶ異なっている気がしました。知識の確認という意味では解いて損はないと思いますが、問題に慣れる目的では非優先かと思います。
- 結果はかなりぎりぎりの合格でした。SQLは大体わかる（わかるとは言ってない）と油断したため、SQLが一番点数低いという結果に…
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/616564/c9a54a81-9aff-211d-58a1-0bfb5b21bf97.png)
- ぎりぎりではありましたが、業務に耐えうる最低限の知識は身に着いたかと思います。少なくとも、Postgres.confってなに？とかhba.confってなに？とかそういうレベルからは脱せたのは勉強した意味があったと思います。ないモチベーションを無理やりたたき起こして勉強した価値はあったと思いました。
Swiftの .onMove(perform:).onDelete(perform:)サンプルコード




```Swift
import SwiftUI

struct ContentView: View {

    @State private var numbers: [Int] = [1, 2, 3, 4, 5]
    @State private var selectedNumbers: Set<Int> = []

    var body: some View {

        VStack {

            List(selection: $selectedNumbers) {
                ForEach(numbers, id: \.self) { number in
                    Text(String(number))
                }
                .onMove(perform: moveRow)
                .onDelete(perform: removeRow)
            }

            EditButton()
                .padding()
        }
    }

    private func moveRow(from source: IndexSet, to destination: Int) {
        numbers.move(fromOffsets: source, toOffset: destination)
    }

    private func removeRow(at offsets: IndexSet) {
        numbers.remove(atOffsets: offsets)
    }
}
```


このコードは、SwiftUIでリストビューを作成し、選択や移動、削除の操作を行うためのものです。

@State private var numbers: [Int] = [1, 2, 3, 4, 5]:
numbers は整数の配列を保持する状態プロパティです。この配列はリストビューに表示される項目のデータを表しています。

@State private var selectedNumbers: Set<Int> = []:
selectedNumbers は整数のセットを保持する状態プロパティです。このセットは選択された項目のインデックスを表しています。

List(selection: $selectedNumbers) { ... }:
List ビューを作成します。selection パラメータに $selectedNumbers をバインドすることで、選択された項目のインデックスが selectedNumbers に反映されます。

ForEach(numbers, id: \.self) { number in ... }:
numbers 配列内の各要素に対して反復処理を行います。id: \.self は、各要素を一意に識別するための識別子を指定しています。

onMove(perform: moveRow):
項目の移動操作を設定します。moveRow メソッドが呼び出され、指定されたソースのオフセットから指定された宛先のオフセットに項目が移動します。

onDelete(perform: removeRow):
項目の削除操作を設定します。removeRow メソッドが呼び出され、指定されたオフセットに基づいて項目が削除されます。

EditButton().padding():
編集ボタンを表示します。このボタンをタップすると、リストビューの編集モードが切り替わり、項目の移動や削除が可能になります。

このコードは、整数の配列をリストビューで表示し、選択や移動、削除の操作を実現しています。選択された項目のインデックスは selectedNumbers に格納され、移動や削除の操作によって配列が変更されます。
Hugging Face transformersドキュメントのまとめページ

絶賛勉強中なので、翻訳したドキュメントなどをこちらにまとめます。あとは実践です。

# 公式ドキュメントの翻訳

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

## クイックスタート

- [\[翻訳\] Hugging Face transformersのクイックスタート](https://qiita.com/taka_yayoi/items/f3c74c8a242368412615)

## チュートリアル

- [\[翻訳\] Hugging Face transformersの推論パイプライン](https://qiita.com/taka_yayoi/items/fe841afc78c27b153b44)
- [\[翻訳\] Hugging Face transformersにおけるAutoClassを用いた事前学習済みインスタンスのロード](https://qiita.com/taka_yayoi/items/af736dd515c0d12faaf7)
- [\[翻訳\] Hugging Face transformersにおける前処理](https://qiita.com/taka_yayoi/items/d6300140765b9b1406c5)
- [\[翻訳\] Hugging Face transformersにおける事前学習済みモデルのファインチューン](https://qiita.com/taka_yayoi/items/597c6b1c36abaf9c1b3c)

## タスク

- [\[翻訳\] Hugging Face transformersにおける質問応答](https://qiita.com/taka_yayoi/items/044caf839e83b210042b)

## PEFT(Parameter-Efficient Fine-Tuning)

- [\[翻訳\] Hugging faceのPEFT](https://qiita.com/taka_yayoi/items/67950183d32b112246ba)
- [\[翻訳\] Hugging faceのPEFTのクイックツアー](https://qiita.com/taka_yayoi/items/9196444274d6a63cda76)

## パフォーマンスとスケーラビリティ

- [\[翻訳\] Hugging FaceのマルチGPUにおける効率的なトレーニング](https://qiita.com/taka_yayoi/items/ecf3564d62b3c1d1e1cb)
【Docker初心者】Dockerの基本操作について　Part２（ポート公開、コマンド実行、削除等）

# １.はじめに
最近、山浦清透さんが運営されているプログラミング学習サービス「[独学エンジニア](https://dokugaku-engineer.com/)」にてDockerについて学び始めました(^o^)
講義内容とほとんど同じになりますが、備忘録も兼ねて自分なりにまとめていきたいと思います。
今回の内容は前回投稿した記事の続きになりますので、前回の内容を見たい方がいらっしゃいましたら[Part1](https://qiita.com/gon0821/items/2ab56df440e057f9d1b7)よりご覧ください。
![docker_logo_icon.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3117662/a84c3e21-c11a-3de6-aac8-378d66daa685.png)

（内容と関係ないけどDockerのクジラのアイコン、健気にコンテナ運んでるの可愛くて結構好き、、、）

# ２.Dockerの基本操作

# （１） コンテナのポートを公開する
コンテナ起動後、ブラウザからコンテナにリクエストを送り、Webページを開きたいとします。
しかし、コンテナは<font color=red>外部からの影響受けずに１つの独立した仮想マシンとして振る舞えるようにしているため、ネットワークは独立し、外部に対して閉じています。</font>このままではリクエストをコンテナが受け取れません(-_-;)

![コンテナ(3).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3117662/a7d8941a-cf90-a7e1-0b50-ac96c1b83853.jpeg)


そこで外部からコンテナと通信するには、**コンテナのポート番号をホストに対して公開し、ホストへの特定ポート番号への通信をコンテナの公開したポート番号へマッピングすること**が解決法となります。

コマンドは「docker container run」コマンド実行時に、**「-p」オプション**を付けます。
（余談ですが、最初の頃は「-p」がポート（port）の頭文字だと思っていましたが、公開する（publish）の頭文字でした、、、！！）

```zsh:コンテナのポートをホストに公開する
# ホストのポート番号9999とコンテナのポート番号８０をマッピングする
$ docker container run -p 9999:80 myapache:latest
```

:::note info
ポート番号とは？
一言で表すと、「どのアプリケーション宛の通信なのかを指定する番号」
よく例えられるのは、マンションの部屋番号ですね！
マンションの住所だけでは郵便物をどこに届けたらいいか分からないけど、部屋番号まであれば届けられる(^^)
下記は代表的なポート番号です。
| ポート番号 | アプリケーション・サービス |
|:-:|:-:|
| ポート８０ |　HTTP通信（クライアントとサーバー間で使用される通信） |
| ポート４４３  |  HTTPS通信（HTTP通信を暗号化した通信） |
|  ポート１４３ | IMAP通信（メールサーバ上で電子メールを閲覧する）  |　

:::

# （２） ログを確認する
コンテナ内に記録されているログの確認方法です。
コンテナ周りで問題が起きた場合にログを確認することがあるので、その際に使用します。

```zsh:docker container logsコマンド
# 書式：　docker container logs [オプション] コンテナ
$ docker container logs apache
```
# （３） コンテナでコマンドを実行する
コンテナ内でコマンドを実行したいときに以下のコマンドを使用します。
bash等のシェルを起動させて、コンテナから抜けずにコンテナ内で操作を続けたい場合は、**「-it」オプション**を付けることで可能になります。

```zsh:docker container execコマンド
# 書式：　docker container exec [オプション] コンテナ コマンド [引数]
$ docker container exec apache ls /

# -itオプション
# 標準出力とターミナルをアタッチする（interactive,tty）　→　シェルを終了させない
$ docker container exec -it apache /bin/bash
```

# （４） コンテナを停止・削除する
起動中のコンテナはいきなり削除できないため、**コンテナの停止 → コンテナの削除**
と段階踏んで、削除する必要があります。

![コンテナ(4).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3117662/ded6f6f6-c99a-b917-6cb8-2ef1895fb887.png)


これは「間違えてコンテナを消してしまった」などのヒューマンエラーを防止するためにあるのでしょう(^o^)
しかし、起動中のコンテナを強制削除するオプション「-f」も用意されています。

* **コンテナを停止する**
```zsh:docker container stopコマンド
# 書式：　docker container stop [オプション] コンテナ
$ docker container stop apache 
```
* **コンテナを削除する**
```zsh:docker container rmコマンド
# 書式：　docker container rm [オプション] コンテナ
$ docker container rm apache 

# 起動中のコンテナを強制削除する
$ docker container rm -f apache
```
# （５） イメージを削除する
イメージやコンテナはずっと残っているとPCの容量を圧迫するので、必要がなくなれば削除するようにしましょう。


```zsh:docker image rmコマンド
# 書式：　docker image rm [オプション] イメージ
$ docker image rm practice/apache 
```

# ３．おわりに
最後まで見ていただき、ありがとうございました！
自分でイメージ図を作成しながらまとめることで、視覚的に理解でき、より理解が深まったと思います(^^)
次回は、イメージの基となる「Dockerfileの書き方について」まとめることができればと思います！


# ４.参考資料
* [独学エンジニア（Lesson34参照）](https://dokugaku-engineer.com/)
独学エンジニアとても分かりやすく、記事の内容は講義内容を参考に作成しております。
月額約1,000円で非常にオススメです！
Ruby技術者認定試験Silver 3.1を受験してみた

# はじめに
2023年5月上旬に[Ruby技術者認定試験Silver 3.1](https://www.ruby.or.jp/ja/certification/examination/version3.html)を受験し88点で合格したので、合格までに何をやったのかまとめてみます。
なお、前提として業務でRubyは使っていますが、受験するまでは体系的にはあまり勉強できていなかった状態です。

# 試験当日までにやったこと
Ruby Silver合格者に何をやったのかお聞きしたり、[初心者がRuby技術者試験Silver 3.1を受けてみた](https://qiita.com/Hiro_Twr_49/items/9bd5abe628d31839df50)を参考にして、やったことは基本的に↓の1～6です。

1. Ruby Silver受験の記事をざっと探す
1. [Ruby技術者認定試験合格教本](https://www.amazon.co.jp/gp/product/B0756VF9Y3/ref=ppx_yo_dt_b_d_asin_title_o00?ie=UTF8&psc=1)
    1. Silverの範囲をざっと1周通読
    1. 基礎力確認問題を解く
    1. 模擬試験を解く
1. [旧模擬問題](https://gist.github.com/sean2121/945035ef2341f0c39bf40762cd8531e0)を解く
1. [RubyAssociation公式の模擬問題(バージョン3)](https://github.com/ruby-association/prep-test/blob/version3/silver_ja.md)を解く
1. [Ruby2.0と3.0の違い](https://qiita.com/stogashi146/items/07ac6ed7e561211184ba)を確認
1. [REx](https://rex.libertyfish.co.jp/)（20問程）を解く

まず、1で合格者がどのような教材を使って勉強したかざっと探し合格までの道のりを頭に描きました（2022年8月頃）。

その後、合格者からアドバイスをいただき教本を購入することを勧められ購入し、2-1の通読しました（2022年8月-9月頃頃）。
しかし、2022年9月頃に体調を崩してしまいリズムも崩れて暫く試験勉強をしていませんでした。

それから2022年4月中旬頃に試験を申し込み試験日を決めて、周りの人に「合格します」等を伝え、試験日の三日前から本腰いれて勉強再開し（GW中だったので丸3日間勉強しました）2-2、2-3、3、4の順に解ける状態にしました。次に、5の2.0と3.0の違いを確認しました。

試験は夕方頃だったため、午前中これまでの学習内容を復習して、RExを解こうと思いましたが思ったよりも解けずに不安になりました...
時間もなかったので、RExは20問程しか解いていない状況でした。
そんな状態で試験を受けましたが、無事合格することができました。（RExは個人的に難しめな問題が出題されていた気がしたので、当日ではなく前もってやることをお勧めします...）

# 個人的なポイント
- 試験に申し込んで試験日を確定させる
- この日Ruby Silver受験して合格する！と誰かに伝える！！
- ↑の問題を解く際に、分からないことがあったりしっくりこない時はネットで関連記事を調べたり、実際にコードを書いて実行して理解していく

# 受験してみて
RExを20問程しか解いていないという不安もありましたが、実際に受験してみるとわりと解けました。
しかし、見たことがないメソッドが出題されることもありましたが、その際はメソッド名から雰囲気で回答していました。
また、3.0に関連する問題もぼちぼち出題されてた気がしました。

# おわりに
今回のSilver合格から波に乗って、Gold合格目指して頑張っていこうと思います。
Gold合格できたら記事にまとめていきたいなと考えています。

# 参考記事

https://qiita.com/Hiro_Twr_49/items/9bd5abe628d31839df50

https://qiita.com/stogashi146/items/07ac6ed7e561211184ba

https://www.ruby.or.jp/ja/certification/examination/version3.html
Splunk: カスタムコマンド入門(2/4) - イベントを入力してみる


###### 実施環境

CentOS 8-Stream

Splunk Free 8.2.2

Python 3.7.10

splunk-sdk-python 1.7.3

### 0. 概要

 Splunk のコマンドにはいくつかの種類があり、カスタムコマンドもそれぞれの種類のコマンドを作成することができます。
今回は各コマンドの作成方法を紹介していきます。

### 1. カスタムコマンドの種類

前回作成したカスタムコマンドのプログラムを見ると、コマンドの本体部分である「 test_class 」は「 GeneratingCommand 」というクラスを継承していることがわかります。

```python:test.py
class test_class(GeneratingCommand):
```

この継承元のクラスは、作りたいコマンドの種類によっていくつか存在します。
実際、この継承元となるクラスがあるファイルを確認すると、以下の通り似たような名前のファイルが複数あることがわかります。

```Linux:Linux
[root@testhost test]# ls -l /opt/splunk/etc/apps/search/lib/splunklib/searchcommands/*command.py
-rw-r--r--. 1 splunk splunk  5432  2月 13 14:59 /opt/splunk/etc/apps/search/lib/splunklib/searchcommands/eventing_command.py
-rw-r--r--. 1 splunk splunk  7872  2月 13 14:59 /opt/splunk/etc/apps/search/lib/splunklib/searchcommands/external_search_command.py
-rw-r--r--. 1 splunk splunk 18949  2月 13 14:59 /opt/splunk/etc/apps/search/lib/splunklib/searchcommands/generating_command.py
-rw-r--r--. 1 splunk splunk  9697  2月 13 14:59 /opt/splunk/etc/apps/search/lib/splunklib/searchcommands/reporting_command.py
-rw-r--r--. 1 splunk splunk 40702  2月 13 14:59 /opt/splunk/etc/apps/search/lib/splunklib/searchcommands/search_command.py
-rw-r--r--. 1 splunk splunk  6778  2月 13 14:59 /opt/splunk/etc/apps/search/lib/splunklib/searchcommands/streaming_command.py
```

前回使用した「 GeneratingCommand 」は、基本的に SPL の先頭で使用する、イベントの入力を受け付けないコマンドです。
今回は、 SPL の途中で使用する、イベントの入力を受け付ける種類のコマンド「 EventingCommand 」を紹介します。

基本的には「 GeneratingCommand 」「 EventingCommand 」の2つがあれば大抵のコマンドは作れるはずです。
他にもコマンドの種類はありますが、ここでは紹介しません。
気になる方は調べてみてください。

### 2. カスタムコマンド本体の作成

上記の通り、前回作成した「 GeneratingCommand 」は入力なしでイベントを生成し出力するコマンドでしたが、「 EventingCommand 」はそれとは異なり入力を加工して出力するコマンドです。

実際に作成してみました。
ファイルは前回作成したものをそのまま書き換えています。

```python:test.py
#!/usr/bin/env python

import sys

sys.path.insert(0, "/opt/splunk/etc/apps/search/lib")
from splunklib.searchcommands import \
    dispatch, EventingCommand, Configuration

@Configuration()
class test_class(EventingCommand):
    def transform(self, events):
        test_sum = 0
        for event in events:
            test_sum = test_sum + int(event["test_count"])
        return [{"test_result": test_sum}]

dispatch(test_class)
```

「 events 」が入力イベント全体、「 event 」が1つ1つの入力イベントです。
「 event 」は出力イベントと同様に辞書の形をとり、上記のようにフィールド名を指定することで値を取得することができます。

### 3. 実行

実際に SPL で使用してみました。

```Splunk:Splunk
| makeresults count=3
| fields - _time
| streamstats count AS test_count
| TestCommand
```

![WS000035.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1465018/76a8f8aa-1368-72d3-527b-0e7d15775533.jpeg "画面")

入力したイベントが加工されて出力されていることがわかります。

ここまで、カスタムコマンドの種類について紹介しました。
次回は、引数の指定や出力の分割など細かい機能を追加していきます。

[戻る](https://qiita.com/frozencatpisces/items/14e4de24c306502efcc8)
【Android】Realmのやり取りをコルーチンに置き換える方法

# はじめに
以前Realmのバージョンアップによるクラッシュに対しての暫定対応手順をまとめました。

https://qiita.com/YuukiYoshida/items/62a2203efea97eea2115

あくまで上記は暫定対応ですが、今回はしっかりと対応する方法をまとめておこうと思います。

# コルーチン化手順

まずコルーチン化するにあたり、CoroutineDispatcherを使用します。
こちらはDaggerなどでinjectしておくと楽ですね。

```RealmModule.kt
fun providesRealmDispatcher(): CoroutineDispatcher = Executors.newSingleThreadExecutor().asCoroutineDispatcher()
```

次に、Realmの処理を呼び出している部分で、executeTransactionしている箇所を、executeTransactionAwaitに変更します。

最後に関数をsuspend化して、上記Dispatcherを設定してあげるだけです。

```
viewModelScope.launch {
   withContext(realmDispatcher) {
   　　　// 先ほどのexecuteTransactionAwaitに置き換えた処理を呼ぶ
   }
}
```
以上になります。
注意点としては書き込み時だけではなく、読み取り時も上記のように呼び出す必要がある点ですね。

https://stackoverflow.com/questions/40344801/realm-access-from-incorrect-thread

こんな感じのエラーが出ている場合は上記を疑ってみてください。

# さいごに
最近時の流れのスピードがさらに加速している気がします、、、
PowerShellで参照渡しされたものをさらに参照渡しする方法



参照渡しの仕方は検索するとすぐわかるのですが、それをさらに参照渡しする方法がわからなかったので、試した結果です。

## まずは単なる参照渡し
おさらい的に、単なる参照渡しです。 「`([ref]$変数名)`」で渡します。
次の通りです。

```powershell
function test1([ref] $param){
    $param.value = "abc";
}

function main(){
    $variable = "";
    test1 ([ref]$variable);
    Write-Host $variable;
}

```

これで、mainを実行すると、abc が表示されます。

## 参照渡しされたものをさらに参照渡し
では、test1からさらに別の関数、たとえばtest2に渡す場合はどうなるでしょうか？

渡された側でvalueプロパティから代入してるということは、渡されたものを渡す場合は、valueプロパティを渡すのかもしれないなと考えて、
`([ref]$param)` なのか `([ref]$param.value)` なのか悩みましたが、試した結果、どちらでもありませんでした。　意外でしたので、他にも同じことを悩んでいる方がいらっしゃるかもしれないと思い、共有の投稿です。

**結論としては、$param をそのまま渡すでした。**　

以下が正解例となります。

```powershell
function test2([ref] $param){
    $param.value = "abc";
}

function test1([ref] $param){
    test2 $param;
}

function main(){
    $variable = "";
    test1 ([ref]$variable);
    Write-Host $variable;
}

main

```

これで、mainを実行すると、abc が表示されます。
IBMi Tips スプール・ファイルを1コマンドでコピーする（環境設定原則不要）(How to duplicate SPLF easily on IBMi)

(English follows)
IBMi(AS400)でスプールファイルをコピーしたいという要件があったとする。

で、その実行方法の一例についてこちらで紹介されている。
https://www.e-bellnet.com/category/technology/2304/2304-03.html

とくにこれで問題なく実行できるのだが、このためにSNADSのセットアップをするのはダルい。
TCP/IP全盛の今どき、もっと簡単な方法がある。

キーワードは SNDTCPSPLF そして LOCALHOST/LOOPBACK だ。

前提：TCP/IPが開始されていること。ローカル・ループバック・インターフェースが開始されていること。 

例えば、WRKACTJOBのスプールを出力待ち行列 QGPL/QDKTにコピーしたい場合は以下を実行する。



```
WRKACTJOB OUTPUT(*PRINT)
SNDTCPSPLF RMTSYS(LOOPBACK) PRTQ(QGPL/QDKT) FILE(QPDSPAJB) SPLNBR(*LAST) TRANSFORM(*NO) SEPPAGE(*NO)
```


SNDTCPSPLFコマンドは、TCP/IPネットワーク経由でスプールファイルを送信するものだ。
通常は相手システムを解決可能なホスト名もしくはIPアドレスで指定し、送信先OUTQを指定してそこにスプールファイルを送り込む。

対象範囲としてASCIIベースのプリンターもカバーしているため、多くの引数が用意されているが、IBMi間でやり取りするだけならコード変換無しでよい。

そして、今回のポイントは、自分に送ること。

自分と言っても、いちいち有効なIPアドレスを覚えておく必要はない。
ローカル・ループバックアドレス(127.0.0.1 IPV6なら::1)を使おう。

これはデフォルトで構成され、活動化されている。
さらに対応したLOOPBACK/LOCALHOSTというホスト名もHOSTSに定義されている。

ちなみに、loopback/localhost はUNIX/Windowsなど他プラットフォームでも共通。
参考になりますように。


以上

If you like to duplicate spooledfiles on IBMi, an example is illustrated on follwing URL
  https://www.e-bellnet.com/category/technology/2304/2304-03.html

This procedure gives you the right way to perform the request. But most people might think it's a little bit bothersome to configure SNADS environment.

But you have a very simple way to do it on TCP/IP environment.
 
In this case the Keywords are CPYTCPSPLF and LOCALHOST/LOOPBACK.

Prerequisite: TCP/IP and the local-loopback interface have been started.

For example when you like to duplicate the output from the command WRKACTJOB, do the followings;


```
WRKACTJOB OUTPUT(*PRINT)
SNDTCPSPLF RMTSYS(LOOPBACK) PRTQ(QGPL/QDKT) FILE(QPDSPAJB) SPLNBR(*LAST) TRANSFORM(*NO) SEPPAGE(*NO)
```

SNDTCPSPLF provides the function to send spooled-files between TCP/IP network.
Generally, to perform this function, we execute this command specifying the target system onformation in short the host name or IP address, the name of the output queue(OUTQ). 

As this command supports the ASCII printers, many parameters with this, but to perform it between IBMis we simply specify TRANSFORM(*NO).

And the point of this article is <<to send my self>>.

Even if I say "myself" you don't have to remember the valid physical/logical IP address.
All you have to do is; to use local loopback address(IPV4->127.0.0.1 IPV6-->::1).

These are configured and activated by default. 
And the valid host names(LOOPBACK/LOCALHOST) are also configured.

FYI loopback/localhost are also valid on other common platforms (e.g. UNIX/Windows).
Hope this article helps.
nvimが（引数で指定しなかった場合に）デフォルトで開くファイル・ディレクトリを設定する

日記や作業中のメモを取るのにneovimを使っているのだが、
- いちいちメモ帳のフォルダのパスを指定するのが面倒に感じてきた
- nvim-qtなどのGUIアプリの場合そもそも引数の指定をしないで開くのが自然
  開いてから改めてパスを指定する必要があって二度手間[^gui]
- 引数にパスを指定しない場合のデフォルトの空バッファは自分は使っていない


と言うことで、空バッファの代わりにメモ用のリポジトリを開くようにしたい。

## やること

- neovimでパスを指定しない際に空バッファの代わりにメモ用のディレクトリ（もしくはファイル）を開くようにする

## 結論
引数を指定しない場合、（`:ls` で取得できる）バッファは無名の１つだけなので、これを判定する。
具体的には
`len(getbufinfo({'buflisted':1}))`でバッファの数を
`getbufinfo({'buflisted':1})[0].name`でアクティブなバッファの名前を取得できる。（vim scriptの場合）

自分は`init.lua`で設定しているので、luaに直して条件分岐など追加したのが以下。

```lua:~/.config/nvim/init.lua
local default_dir = "path/to/default"
local bufinfoargs = {}
bufinfoargs['buflisted'] = 1
local bufinfo = vim.fn.getbufinfo(bufinfoargs)

if (#bufinfo == 1 and bufinfo[1]["name"] == '') then
  vim.cmd("cd " .. default_dir)
  vim.cmd("e " .. default_dir)
end
```

今日の日記など、日別のファイルを開くのであればこのような感じ

```lua:~/.config/nvim/init.lua
if (#bufinfo == 1 and bufinfo[1]["name"] == '') then
  vim.cmd("cd " .. default_dir)
  vim.cmd("e " .. default_dir .. '/'.. os.date('%Y/%m/%d') .. '.md')
end
```
## 参考
- [Programming in Lua : 2.5](https://www.lua.org/pil/2.5.html)
- [vim - Vimscript: Number of listed buffers - Stack Overflow](https://stackoverflow.com/questions/17931507/vimscript-number-of-listed-buffers)

[^gui]: 言うてGUIアプリはWindowsでしか使わないが。LinuxやMacだとGuakeやiTermのショートカットキーで開けるターミナルの方がメモ用には都合がいいので。
スプレッドシートの最終変更日時と最終編集者を表示するGAS

スプレッドシートの最終変更日時と最終編集者を自動表示するGASについて紹介します。

このGASは、最終編集者のメールアドレスと最終編集日時を自動で取得し、指定したセルに表示します。

シート名を指定するだけで、簡単に使うことができます。

スプレッドシートの編集履歴を把握したい場合や、複数人で共同作業を行う場合などで便利です。

初心者でも簡単に使えるので、ぜひ活用してみてください。

```
function showLastEditorAndEditTime() {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = ss.getSheetByName('シート1'); // 編集対象のシート名を指定
  var user = Session.getActiveUser().getEmail();
  var date = new Date();
  
  // 最終編集者と最終編集日時を表示するセルを指定
  var lastEditorCell = sheet.getRange('A1'); // 例: A1セル
  var lastEditedDateCell = sheet.getRange('B1'); // 例: B1セル

  // セルに情報を表示
  lastEditorCell.setValue(user);
  lastEditedDateCell.setValue(date);
}

```
入茶から4カ月、中2でついに入緑！！+ABC301解説(A～D)

こんにちは。昨日のABC301で入緑しました！![スクリーンショット 2023-05-14 080308.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2987396/916c8e4c-1984-c0a2-5e57-72f38bac5d45.png)
コンテストでは3ペナ4完でパフォーマンスは<font color="00c0c0">1333</font>、レートが<font color="804000">785</font>→<font color="008000">857</font>となりました。入茶したのが今年の1月7日、それから4カ月です。いろいろなアルゴリズムを勉強しましたが、特にコンテスト中に使ったと思ったのはUnion FindとBFS、DFS、素数列挙、DP、RLE圧縮です。

## A問題
https://atcoder.jp/contests/abc301/tasks/abc301_a

問題を読み取るのに時間がかかったと思います。最初にTとAの個数を数えて、どちらかが多い場合はそれを出力しました。個数が同じ場合は、先にその個数にたどり着いた方が勝ちなので、for文で計算しました。
02:31

https://atcoder.jp/contests/abc301/submissions/41345111

## B問題
https://atcoder.jp/contests/abc301/tasks/abc301_b

隣接する要素が大きいか小さいかで、rangeを使って足していきました。反例があると思いましたが、ACになりました。
04:24

https://atcoder.jp/contests/abc301/submissions/41347814

## C問題

https://atcoder.jp/contests/abc301/tasks/abc301_c

C++で解きました。mapを使って文字の種類を数え、a～zまで調べて、@で変えられるのはa,t,c,o,d,e,rだけなのでそれ以外の文字で個数が一致しない場合はNoです。a,t,c,o,d,e,rに入っている場合でも、@の個数が足りなくなるとだめなのでその場合もNoにしました。反例があると思いましたがACになりました。
16:56

https://atcoder.jp/contests/abc301/submissions/41357219

## D問題

https://atcoder.jp/contests/abc301/tasks/abc301_d

変えると変化が大きい上の桁から決めていきました。?になっている場所を管理して、採用するかしないかを決めて最終的な答えがNより小さいかどうかで決めました。
4ペナ30:24

https://atcoder.jp/contests/abc301/submissions/41364506
Pythonのfindメソッドで部分一致文字を避けて文字列の位置を取得したい

# 前書き
リスト内にある各文字列の開始位置と終了位置を取りたい！ってときにfindメソッドを用いたのですが、部分的に一致するものが文章の先にきてしまうと正確な位置ではない値が取れてしまいました。

そこで自分なりに改善してみた結果を以下に書いておきます。

（記事にするようなことでもないですが、アウトプットの癖をつけるためにも、自分の気づきになったことはどんなに小さなことでも残していこうかなと）


# 問題となった動作

例えば、以下のような文章から「カモシカ」の後に続く、「シカ」という語句の位置を取りたい場合

```text:sample
    カモシカもシカも確かに鹿だが、アシカは確か鹿ではない
```

<br>
以下のようなコードを実行します。

```Python:code
    word_list = ["カモシカ", "シカ", "アシカ"]
    text = "カモシカもシカも確かに鹿だが、アシカは確か鹿ではない"
    for word in word_list:
        start_pos = text.find(word) # 開始位置
        end_pos = text.find(word) + len(word) # 終了位置
        print(word, start_pos, end_pos) # (リスト要素, 開始位置, 終了位置)
```

<br>

出力された結果を見ると、「シカ」の文字位置が「カモシカ」と被っていることがわかります。

```text:出力結果
    カモシカ  0 4
    シカ 2 4
    アシカ 15 18
```

「シカ」の開始位置が`5`、終了位置が`7`というのが本来欲しい出力結果ですが、このコードでは前述した通り、そうなっていません。

# 解決法

スライスを利用することで、改善することができました。

以下にコードを記しておきます。

```Python:code
    word_list = ["カモシカ", "シカ", "アシカ"]
    text = "カモシカもシカも確かに鹿だが、アシカは確か鹿ではない"

    #変数を用意して繰り返しの都度、検索する範囲を変更する
    next_search_spos = 0
    for word in word_list:
        start_pos = len(text[:next_search_spos]) + text[next_search_spos:].find(word) # 開始位置
        end_pos =  len(text[:next_search_spos]) + text[next_search_spos:].find(word) + len(word) # 終了位置
        print(word, start_pos, end_pos) # (リスト要素, 開始位置, 終了位置)
        next_search_spos = end_pos
```

<br>

変数を用意して初期値を0に設定し、その後はfor文の最後にそのループ回の語句の終了位置を代入する一文を挟むことで、文字位置の被りを避けることができました。

<br>

```text:出力結果
    カモシカ 0 4
    シカ 5 7
    アシカ 15 18
```


# 終わりに
今回のやり方が最善なのか、少し不安ながらも存外早くに解決できてよかったです。

研究活動でPythonを使ってはいるものの、プログラムをいじることが少ないのでまだまだ勉強が足りていないと痛感しています。

これからも頑張る:D

# 追記(2023/05/15)　コードに関する注意
この記事に書いたコードではその仕様上、リスト内の要素の順序が文中における出現順でなければならず、仮に「シカ」のみを対象に位置を取りたい場合は正確な出力が得られないことに気づきました。

```Python:具体例1
    word_list = ["アシカ", "カモシカ", "シカ"]
```

```Python:具体例2
    word_list = ["シカ"]
```

上記に挙げたような形態では出力が正確ではなくなります。<_(._.)_>

コメントでご指摘下さりありがとうございます。
精進します！
vieditorでの全置換

# vimの全置換って

Google検索すると、一行の中の全置換は、`g`だよって出てくるけど、
ファイル内全置換ではないのだろうか？


シンタックスは、以下の通りです。これでvimの全置換つかいこなせるぞ。

```
:%s/fuga/hoge/g
```

コロンは、コマンドでよく使われるので、これは記憶しやすい。
置換が`s`っていうのは正直もうして違和感。ふつうは、`f` or `h`ではないのだろうか？

最後のタグが全部という意味で、`g`？これも違和感しかない。`a`ならわからないわけでもないが・・・正規表現由来か？

おそらく当該エディターで全置換する場合は、かならずといっていいくらい、検索かけることになると思う。その時にこのブログがなるべく上の方にきてほしい。そうでないと、知りたいことがズバリ書かれてないのが少なくないから。最初のほうにvimのヘルプのスクショとか出してくるブログがあるけど、正直なところ、これはツラミしかない。
Azure AppServiceプランとAppServiceの関係

# AppSercviceとは
AppServiceとはMicrosoftのAzureで提供されているPaaSのコンピューティングサービスです。
詳しく書くと
・Web Apps
・Azure Function
・mobile Apps
などが含まれます。

さらにオートスケールなども使用できます。すでにロードバランサーがついている感覚です

現在、AzureのPaaSのサービスといえばApp Serviceがあげられます。ひと昔まえまではクラウドサービスが使われていましたが、今はAppServiceが主流です。
ただ、このAppServiceを初めて使うとAppServiceプランたるものが付属されます。これがはじめての人だと戸惑うと思うので少し説明しようと思います。

# AppServiceはアプリでAppServiceプランはVMインスタンスと思えばいい
基本はこの認識でよいと思います

# スケールアップはAppServiceプラン
AzurePortalでAppServiceとAppServiceプランの設定画面にいくと、両方の画面にスケールアップ（インスタンスを増やす）の項目があります。ですが、スケールアップ対象はAppServiceプラン（VMインスタンス）のみとなります。

ここでひとつ重要なのは、AppServiceプラン上のAppServiceはすべてのインスタンスで稼働することです。
インスタンスを増やすと、増えたインスタンスにもすべてのAppServiceが動作します。
たとえば、AppSeriveプラン上で3つのAppService
・AppService-A
・AppService-B
・AppService-C
があるとします。
以下をご覧ください。

#### AppServiceプランのインスタンスが１つのとき
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3373520/d20c3a36-b33e-4f6c-1fe9-39b48334c68e.png)

#### AppServiceプランのインスタンスが２つのとき
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3373520/5b044c1f-92df-3943-d39e-7242429338ba.png)

この感覚は少しわかりづらいと思いますが、これを覚えておくとよいかもしれません。

# たまにインスタンス名が変更することがある
Azure側の物理サーバーのOS更新などで、AppServiceプランのVMインスタンスの名前が変わることもあるので、少し気に留めておくとよいかもしれないです
lazeの作法 その3

# 概要
lazeを見つけたので、やってみた。
ライントレース、やってみた。

# サンプルコード

```
function: main() => () {
	captureMouse();
	linetraceSimulation: robot("Easy");
	robot.leftMotorON = 1;
	robot.rightMotorON = 1;
	robot.leftMotorSequence = 1;
	robot.rightMotorSequence = 1;
	robot.leftMotorSpeed = 13;
	robot.rightMotorSpeed = 13;
	loop
	{
		if (robot.rightSensorValue < 130)
		{
			robot.leftMotorSpeed = 8;
			robot.rightMotorSpeed = 13;
		}
		else
		{
			robot.leftMotorSpeed = 13;
			robot.rightMotorSpeed = 8;
		}
		robot.update();
	}
}
```


以上。
lazeの作法 その2

# 概要
lazeを見つけたので、やってみた。
sin波、やってみた。

# 写真

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/18104/b5ba0241-414f-c157-ae15-f08b580e63c7.png)

# サンプルコード

```
function: main() => () {
	captureMouse();
	Scene: world;
	Vector3D: color(1.0, 0, 1.0);
	double: PI = 3.14159265398979315;
	Array<int>: cubeIDlist;
	int: numberOfTimes = 100;
	Vector3D: initialPosition(0.0, 0.0, 0.0);
	repeat(numberOfTimes)
	{
		cubeIDlist.push(world.addCube(0.100000000000000006, color, initialPosition));
	}
	loop
	{
		double: w = 0.100000000000000006;
		repeat(cubeIDlist.length())
		{
			double: x = w * counter - 5.0;
			double: y = sin(x + getTime() / 300.0);
			Vector3D: position(x, y, 0.0);
			int: id = cubeIDlist.get(counter);
			world.sprites.get(id)->setPos(position);
		}
		world.draw();
	}
}
```


以上。
【personal-study】check palindrome

this is personal study
if setting a text, please check palindrome pattern.
please output True or False.

### input

```text
TactCoa
```

### output
```
True
```



### How do you terms palinedrome pattern??

**Except to center string, String have to even number.**
Center String allow odd number


### solution

```python


def countCharFrequency(text:str):
    hashed ={}
    for str in text:
        str = str.lower()
        if hashed[str]:
            hashed[str] +=1
        else:
            hashed[str] =1
    return hashed

#Is there more than one odd number?
def checkMaxOdd(hashed) -> bool:
    foundOdd = False
    for key in hashed:
        if hashed[key] % 2 ==1:
            if foundOdd:
                return False
        return True

if __name__ == '__main__':
    input = 'TactCoa'
    hashed_count_char_frequency = countCharFrequency(input)
    is_check_max_odd = checkMaxOdd(hashed_count_char_frequency)
    print(is_check_max_odd)
    
```