OmniAICreator/Qiita-1.07M huggingface dataset:
カスタムボタン

[まとめページに戻る](https://qiita.com/Keiji_otsubo/items/60afc2a8d211b6f7d89f)
[まとめA～M](https://qiita.com/Keiji_otsubo/items/f3ddedee6793bf1576f8)




+ [High Velocity Salesライセンスがないと表示できないカスタムボタン](https://qiita.com/Keiji_otsubo/items/9fce65a2e7dd748a6126)
+ [関連リストのカスタム ボタンでクロスドメイン エラーが発生する](https://qiita.com/Keiji_otsubo/items/84fd902571c41a65d829)
+ [カスタムボタンで外部URLを呼ぶ時にIF関数を使う](https://qiita.com/Keiji_otsubo/items/aaf6e2cdf1d924bc9f9a)
+ [クイックアクションをカスタムボタン(aura コンポーネント)に配置したらモバイルでは動かない](https://qiita.com/Keiji_otsubo/items/a709ba2eb90a55cd75c0)
+ [GETRECORDIDS](https://qiita.com/Keiji_otsubo/items/e92c04e3cdfda2a19cf8)
+ [How to set the default record type when using ‘defaultFieldValues’ to set default values in Spring 20?](https://qiita.com/Keiji_otsubo/items/286d2a656f11dfe45023)

+ [カスタムボタンで新規ウィンドウに表示をしているにもかかわらず、同じタブで表示されてしまい、新規ウィンドウで表示されません。](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007LqKlD)

:::note
アイデアに上がっていますね。

Display in new window not working for button using a Salesforce URL in LEX 

https://ideas.salesforce.com/s/idea/a0B8W00000GdXhYUAV/display-in-new-window-not-working-for-button-using-a-salesforce-url-in-lex

Custom Button to open new window for creating new custom object record
https://trailhead.salesforce.com/trailblazer-community/feed/0D54S00000A7p5hSAB

URL  Hackを使ってクイックアクションと組み合わせるとモーダル（別画面）画面に表示することができそうです。 

Salesforce URL Hack in Lightning 
https://newstechnologystuff.com/salesforce-url-hack-in-lightning/
:::


# プロファイルによる表示非表示の制御

+ [カスタムボタンの参照権限について（管理者のみ使えるようにしたい）](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007RfQnY)
+ [レコードページのカスタムボタンを特定のユーザにのみ表示されるようにする](https://help.salesforce.com/s/articleView?id=000386498&type=1)

:::note
この問題を解決するための良い方法は、数式項目を作成し、HYPERLINK 関数 (ボタンに見えるようにハイパーリンクに画像を追加する) を利用してリンクを条件付きで表示することです。たとえば、次の数式では「システム管理者」ユーザのみへの Google ハイパーリンクが表示されます。

IF(CONTAINS($Profile.Name,"System Administrator"),HYPERLINK("http://www.google.com/" ,"Button name")," ")

他のどのユーザも「ボタン」(画像) を表示できません。
:::

# カスタムリストボタン

+ [カスタムリストボタンでのLWC使用について](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007cmHMe)

思考錯誤した結果、Visualforce→Apex経由でLWCが呼び出せる可能性が出てきた
Net Zero Cloud as CRM Analytics

[まとめページに戻る](https://qiita.com/Keiji_otsubo/items/60afc2a8d211b6f7d89f)
[まとめN～Z](https://qiita.com/Keiji_otsubo/items/92f92bb9f668ca9688be)


+ [Net Zero Cloud](https://qiita.com/Keiji_otsubo/items/6a95ef0226ae7e7b99d2)


+ [CSV Upload error for What-If Dashboard](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007MZtyI)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/0da6e454-8e77-5e8f-fa89-cce7112d5440.png)

:::note
 I typed that table again and it was uploaded successfully. 😅 I think there was something problem while I copied and pasted.
:::


+ [ロード参照データのロード - マーケットプレイスへの接続エラー](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007W85nc)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/9e088294-8832-6387-ca23-02ede21b4322.png)

:::note
明確にしておきたいのは、既製の排出係数を米国法人を有する組織に限定しているわけではないということです。それは正しくありません。新しいエクスペリエンスから、Net Zero Cloud に参照データをロードすることができます。「ネットゼロクラウドに含まれる」バッジが付いていないデータプロバイダーから入手できる排出係数は、米国の事業体のみが利用できるデータセットです。多くのデータセットがまだ Sandbox 組織に読み込まれているため、データセットが表示されません。これらは今週後半に組織で利用できるようになる予定です。  
:::

# CSVのテンプレート

+ [does anybody has some CSV templates ready to upload?](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007eqtSN)

:::note
you can actually download templates directly from NZC! Check out the below resources for more info

+ [Demo](https://org62.my.salesforce.com/sfc/p/?&_ga=2.97101149.372705855.1723751074-903395833.1723188411#000000000062/a/3y000002LDXj/djlv4ghJii6aDi9qRyBoeZS.ht3PEDsBTq.5BfTpj2o) 
+ H&T: [Upload NZC Data Using Data Upload Templates](https://help.salesforce.com/s/articleView?id=release-notes.rn_let_users_upload_netzero_cloud_data_using_csv_files.htm&release=244&type=5)
:::
This package can’t be installed. 

+ [Not able to install BOTanicals App in my playground.](https://trailhead.salesforce.com/en/trailblazer-community/feed/0D54S00000KfPHY)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/7b5ff56e-a637-a8a7-ef22-15b011ecdce1.png)

:::note
It worked for one of my orgs after I deactivated and deleted the "account_record_page" lightning record page for the Account object.

Account オブジェクトの「account_record_page」ライトニング レコード ページを非アクティブ化して削除した後、私の組織の 1 つで機能しました。
:::

よく分からんエラーだな。

[Unable to install package due to error - This app can't be installed.](https://trailblazer.salesforce.com/issues_view?id=a1p30000000eQVzAAM)

特定の管理/非管理パッケージには、特定のインスタンスでのインストールに問題があります。1 つを除くすべてのインスタンスにインストールできます。現在の問題は、パッケージのメタデータが特定のインスタンスに複製されていないことです。インストール時にエラーIDが表示されたり、「このアプリはインストールできません」と表示される場合があります。

**類似**

+ [【未解決】Set Up the BOTanicals App](https://trailhead.salesforce.com/en/trailblazer-community/feed/0D54S00000JeXFISA3)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/7beea069-5f23-03f4-ccb3-89e6e2c3f84f.png)


+ [【解決】Unable to install the managed package for field service](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007MbHsy)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/2793c504-049e-fe6a-553a-1a9c58c99d2d.png)

:::note
when doing the trailmix for field service in the beginning there is a module about getting your username and password reset. Be sure to have a look at that as well. I also made the mistake of loging in with my trailhead credits, but you have to login with the specific emailaddress and password for that playground. It is probably an emailaddress with some kind of animal in it, as it is created automatically :)

最初にフィールドサービス用の Trailmix を実行すると、ユーザー名とパスワードのリセットに関するモジュールがあります。ぜひそちらもご覧ください。また、Trailhead クレジットを使用してログインするという間違いを犯しましたが、そのプレイグラウンドの特定のメールアドレスとパスワードを使用してログインする必要があります。自動的に作成されるので、おそらく何らかの動物が含まれたメールアドレスです :)
:::
Flutter uni_linksを使っててもURL SchemeをiOSネイティブでハンドルする

FlutterでURL Schemeを扱う方法としてはuni_linksをよく使うと思います。
今回、FlutterアプリにFlutterのパッケージでなくネイティブのGoogle Sign Inを追加した所、uni_linksが動かないという状況になりました。

直接的な原因はAppDelegate.swiftに,GoogleSignInのコールバックを受けるために、以下の関数を追加してしまったことです。(公式ドキュメント通りの手順)

```swift:AppDelegate.swift
    override func application(
      _ app: UIApplication,
      open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]
    ) -> Bool {
      var handled: Bool

      handled = GIDSignIn.sharedInstance.handle(url)
      if handled {
        return true
      } else {
          return 
      }

      // Handle other custom URL types.

      // If not handled by this app, return false.
      return false
    }
```

しかし、この関数をオーバーライドしてしまうと、uni_linksが動かなくなります。
理由は`AppDelegate`のスーパークラスである`FlutterAppDelegate`の方の、関数が動かなくなってしまうからpluginで呼ばれるはずの、uni_links関数が実行されなくなってしまうからです。

正しく修正するには、`AppDelegate.swift` にこの関数を追加せずに、この関数自体をpluginで実行するようにします。

```Swift:MyAppDelegatePlugin.swift
public class AppDelegatePlugin: NSObject, FlutterPlugin {
    
    public static func register(with registrar: FlutterPluginRegistrar) {
        let instance = AppDelegatePlugin()
        registrar.addApplicationDelegate(instance)
    }
    
    public func application(_ application: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
        var handled: Bool
        
        handled = GIDSignIn.sharedInstance.handle(url)
        if handled {
            return true
        }
        
        // ここでハンドルしない場合はuni_linksでハンドルできるようにfalseを返す
        return false
    }
}
```

`application`関数の戻り値はGoogleSignInのURLを処理した場合のみtrueを返し、それ以外の場合はfalseを返します。これは複数のPluginからこの関数が登録された場合に、あとに実行される`application`関数を実行するためです。ちなみにuni_linksを使うとこの関数の戻り値は常にtrueになります。[参考](https://github.com/avioli/uni_links/blob/master/uni_links/ios/Classes/UniLinksPlugin.m#L55)。そのためプラグインの追加順は以下のようにする必要があります。

```swift:AppDelegate.swift
// uni_linksより先に実行させるためこの位置に追加
AppDelegatePlugin.register(with: registrar(forPlugin: "com.example.AppDelegatePlugin")!)

// uni_linksを含む追加されたライブラリのプラグインが追加される
GeneratedPluginRegistrant.register(with: self)
```

いかがでしたか？今回はやりたいことがニッチ過ぎましたが、Flutterプラグインの理解が少し深まりました。
例えばURLスキーマを扱うライブラリが複数追加された場合にも、片方が機能しないなどの問題が起きそうな気がします。その場合、プラグインの追加順を調整したり、`application`関数の戻り値を制御するなどの対応が取れるかもしれません。
TKinterでAzureOpenAIのchatGPTのネイティブアプリ（っぽいもの）を演出する

# TKinterとは
主要なOSに対応しているGUI作成用のPythonライブラリ。以前、画像認識のデモモックを作った際に、PC内臓カメラ＋GPUでアプリを作った際に使用したことがある。LLMであれば入出力内容もシンプルなので使い方のおさらいがてら整理してみる。

# インストール
TKinter自体はWindows, Mac, Linux各OSに対応している。
Macにおいて検証してみたので、以下インストール手順。

なお、下記のとおり、
https://log.dot-co.co.jp/tkinter-mac/
Tkinterをインストールするだけだとウインドウ表示がうまくいかないため、condaで新規のpython仮想環境を構築後にbrewでTKinterをインストールして実行した。

```bash
conda create -n py310 python=3.10
conda activate py310
brew install tcl-tk
```

# ネイティブウインドウでのAzure OpenAIチャットアプリを書いてみた。

langchainでAOAIを使うためのいつもの設定。会話型にしたいので、ConversationBufferMemoryを使用する。

```python
import sys
import tkinter
import os
from langchain.chat_models import AzureChatOpenAI
from langchain.chains.conversation.memory import ConversationBufferMemory
from langchain.chains import ConversationChain

# パラメータ
os.environ["OPENAI_API_KEY"]     = ""
os.environ["AZURE_DEPLOYMENT_ID"]= ""
os.environ["OPENAI_API_HOST"]   = "https://[].openai.azure.com/"
os.environ["OPENAI_API_VERSION"] = ""
```

```python
llm = AzureChatOpenAI(
        temperature=0,
        deployment_name=os.environ["AZURE_DEPLOYMENT_ID"],
        openai_api_base=os.environ["OPENAI_API_HOST"],
        openai_api_version=os.environ["OPENAI_API_VERSION"],
        openai_api_key=os.environ["OPENAI_API_KEY"],
        openai_api_type="azure",
        streaming=True,
        max_tokens=2000,
    )

conversation = ConversationChain(
    llm=llm,
    memory=ConversationBufferMemory(),
    verbose=True
)
```

TKinterによる画面、画面部品の定義部。
エントリー（テキストボックス）にチャット内容を入力し、ボタン送信。
ラベルにAzure OpenAIのチャットのやり取りをプロットするようにした。
- ラベル文字の配置基準位置。wはwest(anchor='w')
- 複数行の配置位置。leftは左寄せ(justify='left')
- ラベルの文字列が自動的に改行されるサイズ(wraplength=300)

```python
root=tkinter.Tk()
root.title(u"test")
root.geometry("400x300")

# ui
#エントリー
EditBox = tkinter.Entry(width=30)
EditBox.place(x=30, y=10)

#ボタン
Button = tkinter.Button(text=u'送信', width=25)
Button.bind("<Button-1>",AOAI_request)
Button.place(x=70, y=60)

#ラベル
lbl=tkinter.Label(text='', anchor='w', justify='left', wraplength=300)
lbl.place(x=30, y=100)

root.mainloop()

```

ボタン押下イベントで呼ばれる関数。ここでAOAIにリクエストを行う。
レスポンスをパースしてラベルに追記していく。

```python
def AOAI_request(event):
  response=conversation(EditBox.get())
  print(response)
  lbl["text"] += 'User:' + response['input'] + '\n' 
  lbl["text"] += 'AI:' + response['response'] + '\n'
```

# 実行結果
![スクリーンショット 2023-10-18 17.13.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3288299/02816595-c2a9-4814-b89f-a747514cccd2.png)

# まとめ
Webアプリではなく、ネイティブウインドウのアプリとしてLLMチャットのデモ紹介をできると、ちょっとできる感を演出できる。
PopUps

[まとめページに戻る](https://qiita.com/Keiji_otsubo/items/60afc2a8d211b6f7d89f)
[まとめN～Z](https://qiita.com/Keiji_otsubo/items/92f92bb9f668ca9688be)


+ [PopUps](https://appexchange.salesforce.com/appxListingDetail?listingId=a0N3A00000FYDyHUAX)

PopUps & Soft Validation Rules for Lightning
Lightning のポップアップとソフト検証ルール


+ サンドボックスにアプリをインストールし、連絡時に必須フィールドを更新するための要件を使用しています。スクリーンショットから、閉じるボタンの名前を変更する方法はありますか?

+ [We have installed app in our sandbox and using for of the requirement to update essential fields on contact. From the screenshot, is there way we can rename close button?](https://trailhead.salesforce.com/trailblazer-community/feed/0D54S00000A6u1DSAR)

残念ながら現在、ボタンの名前を変更することはできません。ただし、次のリリースでは削除や名前変更のオプションが含まれる予定です。

# 機能しない

+ [Optional criteria not working.](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007MbEXg)

+ [Some Users do not see certain notices](https://trailhead.salesforce.com/trailblazer-community/feed/0D54S00000PfCMzSAN)

+ [Permission For Users](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007OX6tMSAT)

+ [1ページに2つのポップアップを表示し、設定を編集できないようにすることはできますか？](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007ifnQ2)

# エラー

+ [I am being asked to contact appfire support on every page load.](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007YwFQT)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/96fe96b6-e85a-097b-1c39-a253ec4b369f.png)
レポート表示で「タグ」は円グラフ表示できない

ServiceNowでは、レコードにタグを付けることができます。
ユーザーは自由に設定でき、複数の種類のタグを適用することができる便利な機能です。
そのタグ付けを集計し、割合を表示したいというニーズがあります。
しかし、円グラフのインプット形式としてタグはサポートされていません。
その理由は、タグが一意ではなく自由な文字列であり、また複数の値を持つことが可能であり、
また別のテーブルに格納されているためです。
したがって、円グラフ（Pie Chart）は標準的にはサポートされていません。

ただし、円グラフを出力する方法はあります。一つの方法は、データベースビューを作成することです。インシデントテーブルのタグ付けをデータベースビューで表示するためには、以下の設定を行ってください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/190712/35b1f265-ec8d-fbc7-fb2e-5ba939a3c687.png)

引用：[I want to report the information counted by type of tag attached to the incident.](https://www.servicenow.com/community/developer-forum/i-want-to-report-the-information-counted-by-type-of-tag-attached/m-p/1387636)

または、以下のように別テーブルからレポート単体を作成することが可能です。
Table: label_entry
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/190712/9babb5fc-c147-e231-4a85-232680acab96.png)

group by : label
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/190712/add4766e-992f-cffb-bf3c-4c8bd87d9043.png)
タグ付けのソリューションが増えた際には上記の内容が役に立つ時が来るかもしれません。


### 引用
https://www.servicenow.com/community/developer-forum/unable-to-group-by-quot-tags-quot-in-reporting/m-p/1673546

https://www.servicenow.com/community/developer-forum/i-want-to-report-the-information-counted-by-type-of-tag-attached/m-p/1387636
【Docker】コンテナ間で通信する場合のネットワーク設定について

# 概要
- Railsのみで構成していたアプリケーションを、Next.js×Rails APIのSPA構成に変更した
- 本番環境のデプロイ先はAWS ECS Fargateを想定している
- 本番環境へのデプロイ前に、本番環境frontend用のコンテナが正常に動作するかを、ローカル環境で確認した
- その際にbackendへのAPI通信でエラーが発生したため、原因と対応をまとめる


# 環境
- backend
    - ruby 3.0.2
    - rails 6.1.4 (APIモード)
- frontend
    - react 18.2.0
    - next 13.1.6


# 関連ファイル
- 開発環境で利用していたAPI構成のdocker-compose.yml
```dockerfile:example-app/docker-compose.yml
version: '3'
services:
  db:
    image: mysql:8.0
    env_file: .env
    ports:
      - 4306:3306
    volumes:
      - db_data:/var/lib/mysql
  back:
    env_file: .env
    stdin_open: true
    tty: true
    build:
      context: ./back/
      dockerfile: Dockerfile
    volumes:
      - ./back:/back
      - gem_data:/usr/local/bundle
    ports:
      - '3000:3000'
    depends_on:
      - db
  front:
    build:
      context: ./front/
      dockerfile: Dockerfile
    volumes:
      - ./front/app:/usr/src/app
    command: 'yarn dev'
    ports:
      - "8000:3000"
volumes:
  db_data:
  gem_data:
```

- 新たに作成した本番環境frontend用Dockerfile
```dockerfile:example-app/front/docker/production/Dockerfile
FROM node:lts-buster-slim

WORKDIR /usr/src/app

COPY ../../app ./

RUN yarn install && \
    yarn build

EXPOSE 3000

CMD ["yarn", "start"]
```



# 問題発生までの手順
1. 本番環境frontend用のDockerfileを作成、ビルド、コンテナ起動
2. 開発環境用docker-compose.ymlの中で、dbとbackのみを起動
3. 1.のコンテナは起動はできているが、2.で起動したAPIとの通信ができない旨のエラーが発生

※APIエンドポイントを記載した.env.productionについては、ビルドコンテキストに含まれており、起動時ログからも読み込みに問題は無い。


# 原因
docker-composeで起動されるコンテナは自動的に同じネットワークに参加するが、手動で起動したコンテナはネットワークを指定する必要があるよう。

# 対応
- docker-composeで利用しているネットワークを確認

```console
example-app ❯❯❯docker network ls

NETWORK ID     NAME                 DRIVER    SCOPE
77bacbced6ed   bridge               bridge    local
a162dferji42   example-app_default  bridge    local
662dadfasdfs   host                 host      local
919sadfa68d2   none                 null      local
```
- frontendのコンテナを対象ネットワークに接続
```console
docker network connect example-app_default xxxxxxxxxxxx（frontendのimageのハッシュ）
```

これにより、ローカル環境にて、本番環境frontend用コンテナから、docker-composeで起動した開発環境用backendコンテナとの通信ができた。

> 参考

https://docs.docker.jp/compose/networking.html
Anacondaのcondaよりも高速でpackageをinstallできると噂のmambaを導入しようとしたらめちゃくちゃ苦労した末に見つけた解決策の話。

install方法を調べると全て「conda install -c conda-forge mamba」でinstallできると書いてあるが私の環境ではinstallに2度失敗した。

コマンドを実行してから良い感じに動作している風に見えている状態が１週間程度継続して、
最後に失敗した旨が表示されるという有様であった。

そもそも既存のinstall方法は推奨されないと書いてある。

https://mamba.readthedocs.io/en/latest/mamba-installation.html#mamba-install

それを踏まえて色々試した結果、
Miniforgeをinstallしたらmambaが搭載されていた。

https://github.com/conda-forge/miniforge

最初からこれをinstallしていたら苦労することはなかったであろう。

以上。
【3D Object Detection】3D Dual-Fusion

# 概要
- AGFNでLiDARの情報をCameraに付与
- Dual-QueryでLiDARとCameraのQueryを作る
- 3D Local AttentionでLiDARのqueryを近くの情報からupdate
- Dual-Query Cross AttentionでLiDARのQueryとCameraのQueryをFuseしてUpdateする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482094/6eb5bc05-fe1d-0bb3-98c8-93c3966357d6.png)

## AGFN(Adaptive Gated Fusion Network)
LiDARのfeatureをCameraにProjectionして、Cameraのfeature mapをupdateする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482094/a2452621-6f7f-d5cf-1e30-f99b4ed50471.png)

## Dual Query 
LiDARのVoxelが空でない数をQとする。
空ではないVoxelのqueryをQ個作る。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482094/2ddc0f51-8375-b254-8fc0-bebe53e14a86.png)
空ではないVoxelをImageにProjectしてCamraからQ個のqueryを作る
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482094/20114399-c9a6-c267-dec7-a33aa8cf75db.png)

## 3D Local Self-Attention
近傍のK個の点をSamplingして、Voxel queryをself attentionでupdateする。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482094/72a59d9f-63e0-7de5-cafa-799bd6e4ba00.png)

## Dual-Query Cross Attention
Cross AttentionをしてCamera queryをupdateする。(q'c)
Queryはqc(Cameraのquery)を使い、KeyとValueはFc'(CameraのFeature map)からLiner Layerで計算する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482094/88529c47-b16b-2ccb-176e-c689398965b7.png)

Gated Fusion Blockでupdateしたcamera query(q'c)とVoxel query(q'v)を重み付けしてFusionする。
重みを計算するのにConvolutionとSigmoidを使っている。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/482094/38554b09-839b-c349-15d0-0e2a7a6d6a75.png)
B2C Commerceで商品の並び替え

# はじめに
商品一覧ページで商品の並び替えをカスタマイズした。
RefArchのものを再利用しつつも、新規でルールを追加した。

# 並べ替えルール 
マーチャントツール >  検索 >  並べ替えルール
ルールを削除・追加できる
![スクリーンショット 2023-10-18 11.00.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2674841/948f50cb-40b3-e3dd-abc2-eea40ffb50cd.png)

best-matchesなどは、構成する属性が複数あるため、動的属性をカスタマイズする
![スクリーンショット 2023-10-20 8.56.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2674841/571cfcba-dc67-9007-0928-fe878cf127ff.png)



# 検索インデックスの再作成
マーチャントツール >  検索 >  検索インデックス
並び替えルールを追加したら、検索インデックスを再作成する必要がある

![スクリーンショット 2023-10-19 18.24.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2674841/40454e69-6e46-90e1-2f0a-196dc9d8ad8e.png)


# ストアフロント並べ替えオプション
マーチャントツール >  検索 >  ストアフロント並べ替えオプション
ストアフロントに表示する並び替えルールを作成する
既存の表示名や、表示する順番を変更できる
![スクリーンショット 2023-10-18 11.00.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2674841/a65bd27e-3b7a-9f3d-e9c0-6afe0c50a352.png)

# 並び替えルールのプレビュー
ストアフロントで並び替えが有効になるかをプレビューで確認できる

![スクリーンショット 2023-10-18 11.28.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2674841/438d1491-524e-73cf-7886-031e6923dc44.png)

# デフォルトの並び替えルール
マーチャントツール >  商品とカタログ >  カタログ > （指定のカタログ） > 並べ替えルール
![スクリーンショット 2023-10-19 18.37.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2674841/fede1d89-80a9-f789-623f-432cf0b33067.png)


# サイトデータ更新
sort.xmlが対象のファイル
以下がディレクトリ
sitedata/sites/(対象のサイト)/

ただし、sortの影響範囲をglobalに設定した場合は、ディレクトリがsitedata/になる

# 公式サイト

https://help.salesforce.com/s/articleView?id=cc.b2c_creating_sorting_rules.htm&type=5
zsh: ファイルをリロードするウィジェットを作っておくと便利

`~/.zshrc`に下記の設定を書いておくと `C-x .` で`./reload`というファイルがリロードされる。

```zsh
_reload-file() {
    local file='./reload'
    if [ ! -e $file ]; then
        zle -M "No such file: ${file}"
        return
    fi
    . "$file"
}
zle -N _reload-file
bindkey '^X.' _reload-file
```

補完関数やウィジェットを自作しているとき、これを使えば現在行を保ったままファイルをリロードできるので便利。
APIを使う前に.envファイルを追加してAPIkeyをリポジトリに含めないようにする

# 目的

APIを使う前にenvファイルを追加してリポジトリに含めないようにする


# 環境
* windows 11
* ruby 3.0.6p216
* Rails 6.1.7.6
* node v16.20.2

# いざ出陣

### .envファイル作成
ルートディレクトリに.envファイルを作成

```:.env
API_KEY=your_api_key_here
```

### .envファイルをリポジトリに含めないようにする

```:.gitignore
.env
```

# 余談
これで安心
（緊急報告）Microsoft 365 管理センター で「サービスを購入する」が無い。どーする？

夜な夜な、Qiita 記事を書いていたら、急に 「サービスを購入する」のメニューが消えました。
あれれ、どうやって M365 のライセンスを買えば良いんだ・・・となってしまい、焦りました💦

色々試した結果、なんと 作業中に 画面デザインが更新されたみたいです。
しかも、結構 解決策みつけるのに 灯台下暗しで 結構ハマると思います。
解決策を ご案内したいと思います。

:::note info
以下の記事を書いてました～。良ければ見てね（宣伝）
:::

https://qiita.com/carol0226/items/efbeb78c93d903403676

# 変更前の画面
今までは、左ペインのメニューで「課金情報」－「サービスを購入する」から 行けましたよね。
※記事用に編集していたキャプチャなので、色の枠は 深い意味はありません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1619637/aa9d0425-5cac-edd8-c40e-65a3164d91c6.png)

# 変更後の画面
以下の緑ライン のところを見てもらうとわかりますが、「課金情報」と「お使いの製品」の間にあったハズの「サービスを購入する」が見当たりません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1619637/d4356eb3-4a98-b603-7271-2384ee3a2259.png)

購入する権限の無い ユーザーだったかな？ と思って、サインアウト＆サインインしたり、ロールをチェックしても、問題ないはず（ちゃんとグローバル管理者）
10分くらい、探してみましたが ぜんぜん解決できない💦

# ん？ マーケットプレース？
以下のように「マーケットプレース」というのが増えていることに気が付きました。
いままで、こんなのは 無かったはず。
ちょうど、記事編集中で 画面キャプチャもあったので、新旧 比較ができましたが、そうじゃなかったら気づけないよ。コレ・・・
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1619637/5f1da0ae-06fa-b563-f3f1-5a5297f29ac0.png)

この画面で 上下スクロールしても、それっぽいものが見当たらない。

# やっとみつけた
そのあと、マーケットプレースに「すべての製品」というタブがあることに気が付きました。
これを押して、やっと 見つけることができました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1619637/6c93d5b3-3f58-8dd2-7a53-c709d0a1c7a7.png)

さらに、お気づきの人もいると思いますが、この画面のタイトル「Microsoft 365 管理センター」が表示されておらず、のっぺらぼう になっています。これは バグなのかな？ それとも 新仕様？
しばらく 様子見したいと思います。

# さいごに
私と同じように ライセンス が購入できなくてハマる人が必ずいると思います。
そんな人が、このサイトを見つけて、救われることがあれば 幸いです。
※すんなり 見つけられる人も居ると思うけど。どうでしょう？

# 宣伝 その２
ココ数カ月は、Azure Virtual Desktop (AVD) を集中的に検証して、Qiita記事に挙げています。
それらの記事のインデックスを 以下の記事にまとめています。
段々と歓声に近づいてきていますので、完成したら 初心者でも Azure や　Microsoft 365 を学びながら 高度な構成の AVD を構築できてしまうようなコンテンツに仕上がる予定です。
ぜひ、記事を ストック して 完成を楽しみにお待ちください。

https://qiita.com/carol0226/items/7318fdd7aff780f5177c
Red Hat Enterprise Linux 8.8の導入

## はじめに
Windows11にインストールしたVMware Workstation 17 Player（以下VMware）に個人利用のために無償でRed Hat Enterprise Linux 8.8（以下RHEL8.8）を導入したので、その手順を以下に記します。
無償でRHELを利用するために以前は60日間のトライアル版が用意されていましたが、現在は個人の開発者向けの開発者サブスクリプションが用意されています。

https://developers.redhat.com/articles/faqs-no-cost-red-hat-enterprise-linux

## 環境
・ホストOS：Windows 11 Pro（22H2）
・仮想化ソフト：VMware Workstation 17 Player（17.0.2 build-21581411）

## 手順
#### １．Red Hat Accountの取得
Red Hat Accountを持っていない場合、下記にて登録（Register）を行います。

https://access.redhat.com/

#### ２．開発者サブスクリプションのアクティベート
まだ開発者サブスクリプションをアクティベートしていない場合、下記にアクセスしてRed Hat Accountでログインし、Activate your subscriptionボタンをクリックして開発者サブスクリプションをアクティベートします。

https://developers.redhat.com/products/rhel/download

#### ３．ダウンロード
ここでは、Red Hat Enterprise Linux ISO for Server and WorkstationsからRed Hat Enterprise Linux 8.8.0のx86_64版DVD isoをダウンロードしました。

#### ４．インストール
VMwareを立ち上げ、新規仮想マシンの作成(N)をクリックしてウィザードでインストーラディスクイメージファイル(M)(iso):にダウンロードしたisoファイルを指定して次へボタンをクリックします。
![rhel8.8_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366126/28b2c64d-64b8-ab65-695f-e26e879cc1bc.png)
アカウント作成を促すダイアログが表示されますのでアカウント情報を入力して次へボタンをクリックします。
![rhel8.8_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366126/459fc098-41ff-ada3-25f0-9a4dcee393e0.png)
仮想マシン名と保存場所を聞かれるので、入力して次へボタンをクリックします。
![rhel8.8_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366126/17492dff-8e8f-d58d-8f33-638da61a7192.png)
ディスクサイズを聞かれるので、ここではデフォルトの20Gから40Gに変更しました。仮想ディスクを複数のファイルに分割(M)はそのままにして次へボタンをクリックします。
![rhel8.8_4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366126/86d491c1-335e-c57a-f347-2dff281ec78c.png)
デフォルトではメモリサイズが2Gしかないのでハードウェアをカスタマイズ(C)ボタンをクリックして、自分のPCの推奨最大メモリである13.4Gまで上げます。
![rhel8.8_5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366126/b5f5a8b0-946a-d277-4742-9013e3560be2.png)
ここで完了ボタンをクリックするとインストールが始まります。
![rhel8.8_6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366126/fb2966ce-f4f6-082f-a19c-145e4f4c0c93.png)
![rhel8.8_7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366126/f5ce245e-072f-2e11-92fc-0a65d22904e3.png)
インストールが完了しました。
![rhel8.8_9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366126/c45627d8-8960-2026-1571-b10bb3e3dae0.png)
ログインするとSystem Not Registeredと表示されますので、Register Systemをクリックしてシステムを登録します。
![rhel8.8_10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366126/47cda7b0-2503-2501-a42b-a50724663819.png)
![rhel8.8_11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366126/56b21a57-8f67-916d-9551-76d8212172d2.png)
Red Hat Accountを入力してRegisterボタンをクリックすると登録が完了します。
![rhel8.8_13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/366126/ebd1cc97-5860-aeef-5c89-e90c3e4ba053.png)

## 終わりに
VMware Workstation 17 Playerも無償で利用できますし、仕事で使っている環境と同等の環境を無償で利用できるのはエンジニアにとって素晴らしいことだと思います。
【SQL】複数テーブル間でのOR条件検索のアンチパターンと改善方法

## はじめに 
複数テーブル間にまたがるようなOR条件でレコードを抽出する際、パフォーマンス上適切でないテーブル結合を行っているケースにしばしば遭遇します。
ここでは、そのアンチパターンと改善方法を示します。

## TL;DR 
* 検索条件に関連するテーブルを一度に全て結合するべきでない
* 各条件に該当するレコードを個別に抽出し、最後にその和集合を取得すべき

## 例
社内SEのKさんが、人事部から時間外手当の支給実績者の抽出依頼を受け、以下のような要件が発生したとします。
* 在籍社員を管理する在籍社員テーブルがある
* 深夜残業履歴・法定休日出勤履歴・所定休日出勤履歴を管理する３テーブルがある
* 上記の３テーブルは、在籍社員テーブルと社員番号で紐づき、複数の実施年月日を持つ
というようなテーブル群に対し、
**深夜残業履歴または法定休日出勤履歴または所定休日出勤履歴のある社員番号を、在籍社員テーブルから抜き出す**

在籍社員テーブルの行数（在籍社員数）は10,000人（件）、1人あたりの深夜残業の平均件数は100件、法定休日出勤と所定休日出勤の平均回数はそれぞれ20件とします。

### ER図
![名称未設定ファイル.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/374350/8561766d-59c9-1412-1eaa-2b1890e9bee4.png)

在籍社員テーブル（参照元X）
| 社員番号 | 氏名 | 
|:-----------|:------------|
| 000001     | 田中　太郎   | 
| 000002     | 山田　花子   | 
| ・・・     | ・・・　     |

深夜残業履歴テーブル（参照先A）
| 社員番号 | 実施年月日 | 
|:-----------|:------------|
| 000001     | 20230405  | 
| 000001     | 20230406  | 
| ・・・     | ・・・　     |

法定休日出勤履歴テーブル（参照先B）
| 社員番号 | 実施年月日 | 
|:-----------|:------------|
| 000001     | 20230409  | 
| 000002     | 20230416  | 
| ・・・     | ・・・　     |

所定休日出勤履歴テーブル（参照先C）
| 社員番号 | 実施年月日 | 
|:-----------|:------------|
| 000001     | 20230408  | 
| 000001     | 20230415  | 
| ・・・     | ・・・　     |

## アンチパターン

以下のように、条件検索に必要なテーブルをすべて外部結合した上で、条件指定するクエリはパフォーマンスの観点から適切ではありません。

```SQL:SQL(SQLSERVER)
SELECT DISTINCT X.社員番号
FROM 在籍社員 X
LEFT JOIN　深夜残業履歴　A
 ON X.社員番号 = A.社員番号
LEFT JOIN　法定休日出勤履歴　B
 ON X.社員番号 = B.社員番号
LEFT JOIN　所定休日出勤履歴　C
 ON X.社員番号 = C.社員番号
WHERE A.社員番号 IS NOT NULL
 OR B.社員番号 IS NOT NULL
 OR C.社員番号 IS NOT NULL
```

テーブルXに対して、テーブルAは複数レコードがヒットする場合があります。
また、同様にテーブルBも複数、テーブルCも複数ヒットします。
そのため、内部的には、テーブルA×B×C分のレコードが作成されたのち、Xの社員番号の重複を排除する操作が走ることになります。

テーブルX1行に対してヒットするテーブルA～Cの行数が少ない場合は、パフォーマンス上大きな課題にはなりませんが、A～Cの行数が大きい場合、処理時間への影響が大きくなります。

テーブルXの行数（在籍社員数）が10,000人、1人あたりの深夜残業の平均回数が100回、法定休日出勤、所定休日出勤の平均回数がそれぞれ20回であるため、10,000×100×20×20=400,000,000と、約4億件のレコードに対して重複を除く操作が走ることなり、パフォーマンスは大幅に劣化します。（DISTINCTはソートを要するため、処理は重い）

また、仮に要件追加によって、参照するテーブルD（例えば、長時間残業実施者履歴、等）が追加されることになると、4億件のレコード×テーブルDのレコード数分、処理対象が増加するため、指数関数的に処理時間が増加することになります。

## どうすればよいか

各条件に該当するテーブルをそれぞれ個別に内部結合し、各結果の和集合をとる方が、多くの場合、パフォーマンスは良好になります。（テーブルXに対して、ヒットするA～Cのレコード数が多いほど、パフォーマンスの差が顕著になります。）

```SQL:SQL(SQLSERVER)
SELECT DISTINCT X.社員番号 INTO #T1
FROM 在籍社員 X
INNER JOIN　深夜残業履歴　A
 ON X.社員番号 = A.社員番号

SELECT DISTINCT X.社員番号 INTO #T2
FROM 在籍社員 X
INNER JOIN　法定休日出勤履歴　B
 ON X.社員番号 = B.社員番号

SELECT DISTINCT X.社員番号 INTO #T3
FROM 在籍社員 X
INNER JOIN　所定休日出勤履歴　C
 ON X.社員番号 = C.社員番号

SELECT 社員番号 FROM #T1
UNION　
SELECT 社員番号 FROM #T2
UNION　
SELECT 社員番号 FROM #T3
```

この場合、

①テーブルAに対する操作　10,000×100=100万件の重複排除処理
②テーブルBに対する操作　10,000×20=20万件の重複排除処理
③テーブルCに対する操作　10,000×20=20万件の重複排除処理

の操作が走った後、上記の処理結果の①～③それぞれ最大でも10,000件×3=30,000件と、高々3万件のレコードに対する重複排除処理が走ることになります。

メモリや一時テーブルへの格納コストや、複数回の重複排除の操作が必要になりますが、大量データに対する重複排除処理よりはコストが低い場合が多く、このように処理を分割した方が、パフォーマンスが良好となることが多いでしょう。
logger.infoを使ったログの出力方法

# 1.はじめに
- 開発中のrailsアプリに`OpenWeatherAPI`を使用して天気情報を取得して表示させるように変更を加えました。
- デプロイしたところ、開発環境では正常に動いていたのに、本番環境では動かないエラーが発生。
- 本番環境でデータ取得ができているかを確認したかったので`logger.debug`を使用して確認したので記録として残します。
- 結論、render側でAPIの設定をしていなかったことが原因でした。

# 2.環境
Ruby (2.6.4)
Ruby on Rails (6.1.7)

## 3.解決までにおこなったこと
### 1.ログを確認してみる
- 開発環境では動いていたのでAPIの取得がうまくいっていない可能性があると仮定
```
ActionView::Template::Error (undefined method `group_by' for nil:NilClass):
46:         <p id="text"><%= @post.text %></p>
47:         <% if @weather_data.present? %>
48:         <h2>5日間の天気予報</h2>
49:         <% daily_forecasts = @weather_data['list'].group_by { |forecast| Time.at(forecast['dt']).strftime('%Y-%m-%d') } %>
50:         <div class="daily-forecasts-container">
51:           <% daily_forecasts.each do |date, forecasts| %>
52:           <div class="daily-forecast">
```
### 2.logger.infoを使用して変数に値が入っているか確認
- logger.(ログレベルの名称)の引数にメッセージを渡すことで、そのログレベルを持ったメッセージを保存することができる。
- ログレベルについて
Railsのログには５段階のレベルがある
ログレベルは情報の必要度が低→高の順で、0→5の数値が充てられている。

|ログレベル|名称|内容|
|:---:|:---:|:--:|
|0|debug|デバッグ情報など|
|1|info|一般的な情報|
|2|warn|警告|
|3|error|制御可能なエラー|
|4|fatal|プログラムをクラッシュさせるような制御不可能なエラー|
|5|unknown|常に記録されるべき不明なエラー|

```diff_ruby
  def post_params
    params.require(:post).permit(:location, :text, :address, :latitude, :longitude, post_images_images: []).merge(user_id: current_user.id)
  end

  def get_weather_forecast(latitude, longitude)
    api_key = ENV['OPENWEATHERMAP_API_KEY']
+    logger.info "api_key: #{api_key}"

    api_url = "https://api.openweathermap.org/data/2.5/forecast?lat=#{latitude}&lon=#{longitude}&appid=#{api_key}&lang=ja&units=metric"
+    logger.info "api_url: #{api_url}"

    response = HTTParty.get(api_url)
+    logger.info "response: #{response}"

    weather_data = JSON.parse(response.body)

    return weather_data
  end
```

### 3.再度ログを確認
```
INFO -- : [914703b7-ba17-4260-95d0-d2e4c12596e7] api_key: 
INFO -- : [914703b7-ba17-4260-95d0-d2e4c12596e7] api_url: https://api.openweathermap.org/data/2.5/forecast?lat=32.8968001&lon=131.0053301&appid=&lang=ja&units=metric
INFO -- : [914703b7-ba17-4260-95d0-d2e4c12596e7] response: {"cod":401, "message": "Invalid API key. Please see https://openweathermap.org/faq#error401 for more info."}
```
ログをみると`api_key`に値が入っていないことが確認でき、この時点でrender側でAPIの設定をしていないことがわかり解決

# 4.終わりに
今まで開発環境ではbinding.pryを使用していたが、本番環境では`logger.info`を使用することでユーザー側での操作に影響を与えずアプリのデバッグを行えるので便利

# 5.おまけ
- デフォルトのログ出力レベルを変更する
config/environments/production.rb等でconfig.log_levelを指定することにより、環境ごとに表示するログレベルを変更できる。
development環境、production環境,test環境それぞれに設定をすることができる。

```ruby:config/environments/production.rb
# この場合だと本番環境ではログレベルがinfo以上のみ表示される
  config.log_level = :info
```

# 参考資料
[Railsのログを理解する-ログの基礎知識](https://qiita.com/sobameshi0901/items/b963e7046e2ae8b8e813)
Blenderで16bitのパラメーターを画像テクスチャー経由で使用する

BlenderのGeometryNodes上で機械学習モデルを動かしたりなど、外部のツールを用いて算出した大量のパラメーターをなんらかの方法で取り扱いたいケースで、TIFF形式で保存して画像テクスチャとして読み込む方法が便利です。

例えば次のように、0から65535までの65536段階のグレースケール色を各ピクセルに割り当てたTIFF画像を作成します。

```python
import numpy as np
from skimage import io

height = 256
width = 256

image = np.zeros((height, width), dtype=np.uint16)
for i in range(height):
    for j in range(width):
        image[i, j] = (i * width + j)

io.imsave('16bit_grayscale_image.tiff', image)
```

UV Editingワークスペースなどから作成したTIFF画像を開きます。
色空間はデフォルトでsRGBになっていますが、必ずリニアやRaw等に変更してください。
(ここで変更した色空間は、GeometryNodes上で値を読み取る際にも影響します。)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/494881/53538167-5a0c-7a42-4fd7-62ed73aa2d65.png)

あとは次のようなノードを組めば、各ピクセルから情報を拾えます。
このノードでは例としてZ座標に読み取った値を入れていますが、ちゃんと「0.000」「1.000」「2.000」…と、想定通りの値が取得できていることがわかります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/494881/e1b32ba9-9f99-a32f-a0e9-407c0b59a8ff.png)

画像テクスチャノードでは、余計な補間がかからないよう「近接」にしましょう。
プログラミングの原則　結果の局所化

:::note
業務の中で、関係の強いコードはまとめるというレビューをいただき、同じような内容が「プリンシプルオブプログラミング」にも記述があったので整理しました。
:::


## どういうこと？　変更の影響を抑える
「結果の局所化」とは、「変更の影響が、局所に留まるようにコードを構成する」ことを指す。
モジュール化もこのために生まれた技術の1つ。モジュールは、そのモジュールの変更の影響を、モジュール内に留めることを目標の1つとして生まれている。


## どうして？　修正と確認が容易に
結果の局所化がされていないと、ある部分の変更が、全く別の部分に影響して、変更コストが急増してしまう。
この時、どの部分に影響があるか明確に分かればまだ救われますが、たいていは不明瞭で、影響範囲を探す作業から開始する。

一方で、結果の局所化がされていれば、コードの読む範囲も修正の影響範囲も限られる。またコミュニケーションが円滑になる効果もあり、最初からコード全体を把握する必要がなくなる。

## どうすれば？　関係が濃密なコードをまとめる
関係性の高いコードを密集させ、関係性の低いコード同士が依存しないようなコードにする。そのために関係性の高いコードを集約してモジュール化する。

この時、お互いに頻繁に呼び出しあっているモジュールは要注意。つまり本来一緒にいるべき要素が、分散している可能性がある。この場合、適切なモジュールの方に機能を寄せるか、モジュール機能を統合してしまうなど、同一機能の密集性を高めるようにする。

---


https://www.amazon.co.jp/dp/4798046140?ref_=cm_sw_r_cp_ud_dp_0C637KV2ZJAP5TECFEK4_2
Obsidianの小技その12｜がしがしPDFにエクスポート

## はじめに

### この記事を読むとできること

全世界のObsidianユーザーの皆さん、こんにちは。今回は、ObsidianのPDFエクスポート機能をいい感じに活用し、素早く簡単に美しいPDFを作成するための実用的なアドバイスをお届けします。これらの小技をマスターすることで、プロフェッショナルな文書を手軽に共有できるようになります。

![SS 2023-10-19 23.54.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184128/c4f6d84d-a594-2b88-4241-cea4facfb2b7.png)


### 記事を書くにいたった背景

わたしたちがObsidianを愛用する最大の理由の一つは、その柔軟性です。しかしながら、ノートを他人と共有する際には、Markdown形式ではなく、より一般的で受け入れられやすい形式が求められることがあります。そこで登場するのが「PDFエクスポート」です。

この機能を日々の作業で頻繁に使うなかで、わたし自身いくつかの「あると便利だな」と思う点を発見しました。特に、忙しいときには、いくつかのキータイプだけで高品質なPDFを生成したいものです。また、文書が長くなると、改ページの挿入が重要になってきます。

これらの要望に応えるべく、今回はPDFエクスポートのプロセスを効率化するための小技、そして資料の見た目を改善するためのレイアウト調整技をご紹介します。これらのアドバイスを活用して、皆さんのObsidianでの作業効率と文書のプロフェッショナル度をさらに向上させてください。


## いちばん素朴なPDF出力方法

Obsidianの最も基本的なPDF出力方法は、ノートを開いた状態で「ファイル」メニューから「PDFとしてエクスポート」を選択することです。これは、現在のノートの内容をそのままPDFに変換します。

エクスポートの設定画面があらわれ、ページサイズや向き、余白など、基本的な設定をおこない、エクスポートできます。

![SS 2023-10-20 0.11.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184128/a02c16a2-30a7-ca7e-75f6-15bd67baae54.png)

これでじゅうぶんかもしれませんが、頻繁にPDFをエクスポートするなら、このマウス操作はめんどうです。


## PDF出力を気軽に行えるようにする方法

Obsidianでは、コマンドパレットを使って素早く操作を行うことができます。`Ctrl + P`（または`Cmd + P`）を押してコマンドパレットを開き、「PDFとしてエクスポート」を検索して選択すると、現在のページをPDFに変換できます。

コマンドパレットから検索するのもめんどうなので、さらに `設定 > コマンドパレット > ピン留めされたコマンド` で、`PDFにエクスポート`を上の方に持ってきます。

![SS 2023-10-20 0.15.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184128/1c902290-a52b-9a2a-015f-c474208a7241.png)

わたしの場合は、上から２番めに置いていますので、`Cmd + P → Ctrl + n`の2ストロークで「PDFにエクスポート」画面が出ます。


## 改ページ

長い文書では、特定のセクションや章を新しいページから開始したい場合があります。ObsidianではMarkdown内で改ページを制御する簡単な方法があります。

改ページを追加するには、`<div style="page-break-after: always;"></div>`というHTMLタグを文書の適切な場所に挿入します。このタグは、PDFエクスポート時に新しいページの開始を指示します。

例:

```
これがセクションの最後の文です。

<div style="page-break-after: always;"></div>

### 次のセクションのタイトル
```

上記のコードは、PDFエクスポート時に「次のセクションのタイトル」から新しいページが始まるように機能します。

## テーマの変更

Obsidianのテーマを変更することで、PDFの視覚的な体裁も変わります。プレゼンテーションのニーズに合わせ、様々なテーマから選ぶことができます。私のお気に入りは`Minimal`と`Things`で、これらのテーマはクリーンでプロフェッショナルなデザインを提供します。



![SS 2023-10-20 0.29.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/184128/c4f42df0-0a39-716a-71ce-57bbee5b1973.png)

【図：左がMinimal、右がThings】

## おわりに

ObsidianのPDFエクスポート機能は、プロフェッショナルな文書の作成に際しても非常に価値があります。今回紹介した改ページの技術やテーマの変更は、送り先の読者にとって一層魅力的な文書を作成するための有効な方法です。特に、テーマのカスタマイズは文書に独自の感性を反映させる素晴らしい方法です。

Obsidianユーザーは、これらの機能を用いて作業の質の向上と手間の削減を両立させ、よりプロフェッショナルでなアプローチで文書を作成・共有できるでしょう。日々の仕事や学びの中で、これらの技術をぜひお試しください。

### 参考リンク

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


### 環境

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

- Obsidian v1.4.16
- macOS Sonoma 14.0（23A344）
- MacBook Pro (14-inch, 2021)
AutoGenでマルチAIエージェントを試しました

AutoGenはこの前も一回紹介しましたが、先月microsoftが公開されたマルチAIエージェントのサービスとなります。
最近githubでコードを確認したところ、すでに10個以上のおすすめagentchat形があります。
![04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3556459/e480c9d0-b14a-c007-64ee-9cc537fbddfb.png)
ちょうど会社のコンサル研修で、「XXX百貨店の売り上げを上がるためのロジカルツリーを作る」というチームワークがありました。
同じ課題をAutoGenにも投げて、どうなるのかを試してみました。
今回は私含めて５人の構成のチームを作りました。（私、エンジニア、科学者、プランナー、評論家（Critic））という構成になっています。

まずplannerは計画を考えました。
![01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3556459/833e521d-9ad1-0494-4c2d-5db95cd1db13.png)


Criticは以下のようなFBをあげました。
![02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3556459/25d1a309-b814-46c3-1638-3d7d3e49e6f4.png)

何度か修正した後に、以下のようにプランの設計が完了しました。（私も会話に参加して、no problemの指示を出しました。）
![03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3556459/64e3e21a-cc14-4ea0-15d0-bfdf2de20d13.png)

その後は実際作業に入りましたが、GPT4の1分あたりの請求回数を超えてしまいましたので、途中で止まりました。GPT3.5などを追加したらいけると思いますが、面倒なので今回はいったんここで終わりにします。


興味ある方
https://github.com/microsoft/autogen
【Next.js】サーバーコンポーネントでCookieを使用する方法

以下のように記述することでサーバーコンポーネントでCookieが使用できます。

```tsx
import { cookies } from 'next/headers'

async function getData() {
  const res = await fetch("http//sample.com", {
    method: 'GET',
    headers: {
      Cookie: cookies().toString(),
    },
    cache: 'no-cache',
  })

  if (!res.ok) {
    throw new Error('Failed to fetch data')
  }

  return res.json()
}

export default async function Sample() {
  const data = await getData()
  return (
    <div>...</div>
  )
}
```

リクエストはできますが、HTTPではストリーミング開始後にCookieを設定することができないため、レスポンスのCookieをサーバーコンポーネントでセットすることはできません。

レスポンスのCookieをセットする場合には、Middleware、Server Actions、Route Handler、のいずれかを使用する必要があります。

https://nextjs.org/docs/app/api-reference/functions/cookies#cookiessetname-value-options

サーバーコンポーネントでCookieをセットする必要がある場合には以下を参照してください。

https://github.com/vercel/next.js/discussions/49843

https://github.com/moshest/next-client-cookies

上記のライブラリは`HttpOnly`は設定できないようです。
[iOS17] Precondition failed: Incorrect actor executor assumption; Expected 'UnownedSerialExecutor(executor: (Opaque Value))' executor.

## 現象
Realmを使ってCRUD処理をasync/awaitで非同期処理しようと思い、対応させてたら以下のエラーが起きた
`Precondition failed: Incorrect actor executor assumption; Expected 'UnownedSerialExecutor(executor: (Opaque Value))' executor.`
※iOS17だと上記のエラーが出たがiOS16代は、エラーが発生しなかった。

## 解決方法
`@MainActor`の付け忘れだった。

通常は、UIの更新はメインスレッドで行うのが決まりなのに、別スレッドで更新してしまったっぽい。
ただ、私の場合は、とある場所の`@MainActor`を付け忘れていた部分がありました。

それは、以下の部分でした。(実例)
```Model.swift
class Monday: Object, Weekday {
    // MARK: - Property Wrappers
    @Persisted(primaryKey: true) private(set) var _id: ObjectId
    @Persisted var scheduleList = List<String>()
    @Persisted var trainTime: Date?
}

extension Monday: ObjectKeyIdentifiable {}
```

```Weekday.swift
@MainActor
protocol WeekDay where Self: Object {
    // MARK: - Properties
    var _id: ObjectId { get }
    var scheduleList: List<String> { get set }
    var trainTime: Date? { get set }
}

extension WeekDay {
// 以下に関数を宣言して関数内で`scheduleList`と`trainTime`に代入などをして使っていました。
```


## まとめ
このように`@MainActor`を付与しなければならない場所がまだありました！

悪魔で今回は一例なので、コード見直して先程のアトリビュートの付与忘れを疑ってみてください！

以下の記事にもiOS17で起こると書かれていました

https://github.com/realm/realm-swift/issues/8267
laravel ルーティング周りで久々に詰まった

## 概要

- laravelのルーティング周りで久々にめっちゃ詰まったので教訓として残しておく。

## 前提

- api.phpに下記のようなルーティングが定義されていた。

    ```api.php
    Route::get('/user/{userId}', GetUserController::class)->name('user.get');
    Route::get('/profile/{userId}', GetProfileController::class)->name('profile.get');
    ```

- 下記の様なFeatureテストのテストコードを書いていた。（パスパラメーターがない状態でリクエストを投げると404が返ることを確認するテスト）

    ```FeatureTest.php
    use App\Models\Profile as ProfileModel;
    use App\Models\User as UserModel;

    public function setUp(): void
    {
        parent::setUp();

        $this->profileModel = profileModel::factory()->createOne();
        $this->userModel = UserModel::factory()->createOne(); // 認証用
        $this->path = parse_url(route('profile.get', ['userId' => $this->profileModel->user_id]), PHP_URL_PATH);
        $this->method = 'get';
    }

    public function test_プロフィール取得_パスパラメーター無し_異常系(): void
    {
        $trimmedUrl = dirname($this->path) . '/';
        $response = $this->sendRequest(path: $trimmedUrl, method: $this->method, userModel: $this->userModel);

        $response->assertStatus(Response::HTTP_NOT_FOUND);
        // TODO: レスポンスの中身の確認
    }
    ```

- このパターンだと正常にテストが通る。

## 最初の問題発生

- `/profile/{userId}`のURLを`/user/profile/{userId}`に変更したかった。
- 下記の様にルーティングを変更した。

    ```api.php
    Route::get('/user/{userId}', GetUserController::class)->name('user.get');
    Route::get('/user/profile/{userId}', GetProfileController::class)->name('profile.get');
    ```

- テストを実行したところ、下記の様なエラーが出た。

    ```
    development.ERROR: App\Http\Controllers\User\GetUserController::__invoke(): Argument #1 ($userId) must be of type int, string given, called in /app/vendor/laravel/framework/src/Illuminate/Routing/Controller.php on line 54
    ```

- `/user/{userId}`が先に定義されていたらそりゃGetUserControllerのルーティングが呼ばれてしまう。そのためエラーが出ていた。

## 次の問題発生

- 「最初の問題発生」で述べたようにルーティングの定義順番が悪いと思い下記のようにルーティングを変更した。

    ```api.php
    Route::get('/user/profile/{userId}', GetProfileController::class)->name('profile.get');
    Route::get('/user/{userId}', GetUserController::class)->name('user.get');
    ```

- テストを実行したところ、下記のようなエラーが出た。（エラーは内容は変わらず。）

    ```
    development.ERROR: App\Http\Controllers\User\GetUserController::__invoke(): Argument #1 ($userId) must be of type int, string given, called in /app/vendor/laravel/framework/src/Illuminate/Routing/Controller.php on line 54
    ```

- 落ち着いている今なら原因はすぐわかるが、このときはかなり焦っていて原因が分からなかった。
- 理由は簡単でテストコードでリクエストを投げているURLは`/user/profile`である。この「profile」フィールドが`/user/{userId}`のURL、すなわち`->name('user.get')`のパスパラメーターの`{userId}`と判定されてしまった。そのため404は出ず、本来intのみ許容されている`{userId}`に「profile」という文字列が入ってきたのでエラーになってた。（こういう事があるから引数の型指定はPHPでも絶対やったほうがいい気がする。）

## 問題解決

- ルーティングを下記のように修正することで問題を解決した。

    ```api.php
    Route::get('/user/hoge/profile/{userId}', GetProfileController::class)->name('profile.get');
    Route::get('/user/{userId}', GetUserController::class)->name('user.get');
    ```

- これなら`/user/hoge/profile/`にリクエストを送っても、存在しないURLなので404が返る。
MacBookAir Mid 2018 に T2-Ubuntu を導入する

# T2-Ubuntu とは?
T2-Ubuntu とは、T2 チップ搭載 Mac 向け Ubuntu の名称です。

[GitHub / T2-Ubuntu](https://github.com/t2linux/T2-Ubuntu)

:::note info
T2 チップとは 2018 年以降に販売された Mac に搭載されているセキュリティチップの名称です。
[Wikipedia / Apple T2](https://ja.wikipedia.org/wiki/Apple_T2)

[Apple / T2 チップ搭載 Mac 一覧](https://support.apple.com/ja-jp/HT208862)
:::

通常、公式が配布している iso ファイルから T2 チップ搭載機に Ubuntu をインストールしようとすると外部キーボードとマウスを必要とします。しかし、このプロジェクトが作成した iso ファイルからインストールするとそれらを使用することなくインストールを完了することが出来ます。

また、Linux 標準のドライバでは対応していない機能へのアクセスも提供しています。（ファンクションキーの動作等）

:::note warn
恐らく M1, M2 チップ搭載機には対応していません。これらの Mac に Linux を導入しようと考えている方は Asahi Linux の使用をお勧めします。
[Asahi Linux 公式](https://asahilinux.org/)
:::

# 導入理由
CPU が非常に貧弱 (Intel core i5-8210Y) であり、ブラウジングをしているだけで動作がカクつくので、その改善のため。

また、(恐らく)そろそろサポートが打ち切られセキュリティ上の問題が生じると予想されるので、最新のセキュリティ対応を受けるため。

# 導入

## 準備
導入した Ubuntu 上で Wi-Fi を使用するには事前にセットアップをしておく必要があります。
https://wiki.t2linux.org/guides/wifi-bluetooth/

:::note info
上記セットアップを行わなかった場合でも、Wi-Fi の USB ドングルや 有線 LAN アダプタ を使用することでネットに接続できます。
:::

うまくインストールできるか心配な方は事前にバックアップと macOS のブータブル USB を作成しておきましょう。
macOS 用ブータブル USB の作成手順は[こちら (Apple / macOS の起動可能なインストーラを作成する)](https://support.apple.com/ja-jp/HT201372)に記載されています。

:::note info
macOS 用ブータブル USB 作成に必要な dmg ファイルは Mac からのみ入手可能なので、T2-Ubuntu 導入前に済ませておきましょう。
:::

## iso ファイルのダウンロード
公式リポジトリのリリースで `iso.sh` というスクリプトファイルが配布されているので、ダウンロードし実行する。
（iso ファイルは `/home/[username]/Downloads` に配置されます。）

Windows を使用している場合は WSL からスクリプトを動かしてファイルを取得することが出来ます。(`zip`, `unzip` コマンドを使用できるようにしておいてください。)

## ブータブル USB の作成
Mac 以外にダウンロードするときと同じようにブータブル USB を作成します。

:::note warn
rufus 3.2.0 で作成したブータブル USB を使用したところ、
`/casper/vmlinuz file not found`
というエラーメッセージが表示されインストールすることが出来ませんでした。

Etcher で作成したブータブル USB ではインストールすることが出来たので、 ブータブル USB の作成には rufus ではなく Etcher を使うようにしましょう。
:::

## 外部ディスクからの起動を許可
T2 チップを搭載した Mac はデフォルトの状態では外部ディスクからの起動が出来ないようになっています。
そのため、macOS ユーティリティから起動セキュリティユーティリティに入り外部ディスクから起動できるよう設定する必要があります。

手順は[こちら (Apple / Apple T2 セキュリティチップを搭載した Mac の起動セキュリティユーティリティについて)](https://support.apple.com/ja-jp/HT208198)。

起動セキュリティユーティリティの
- 「安全な起動」を「セキュリティなし」
- 「許可する起動メディア」を「外部メディアまたはリムーバブルメディアからの起動を許可」

に変更します。

ファームウェアパスワードは設定しなくていいです。

## ブータブル USB から起動
外部ディスクからの起動を許可したら再起動し、Apple ロゴが表示されたら `Option` キーを長押しして起動ディスクの選択画面を開きます。
このとき `Macintosh` ではない黄色い起動ディスクをクリックします。
(黄色い起動ディスクが複数ある場合は一番右のものをクリックしてください。)

Try to Ubuntu などいくつかのオプションが表示されたらお好みのオプションを選択してください。
(選択をミスると MacOS のパーティションが吹っ飛ぶので注意してください。)

## Ubuntu のインストール
ここまでくればいつもの Ubuntu インストールと大きく変わらないのでポチポチ設定していってください。

# インストール完了後
## パッケージアップデート
ネットに接続して `apt update` と `apt upgrade` を実行します。


# 終わりに
タッチパッドの使用感が macOS でのものとかなり異なることや、一部ファンクションキーが効かないなど細かく見ていけば気になるところはありますが、大きくは変わらないのでサポートが切れかけている Mac を使い続けたい方にはお勧めです。

(音量調整や画面の輝度調整が macOS と同じキーで行えること、素の状態でBluetooth が使えることには驚きました。)
[JavaScript]date-fnsを使って日付をバリデーションする話


# 概要

JavaScriptでユーザーが送信した日付が、正しい日付かどうか確認したい時がありました。
今回はその方法と注意点を共有します。

# この記事で伝えたいこと

JavaScriptで日付のバリデーションをする際は、date-fnsのparseメソッドを使用することを推奨します。

# date-fnsで日付のバリデーションを行ってみる
### 実行環境

| 項目 | 環境 | 
|:-----------|:------------|
| OS       | Mac     |
| editor|   Visual Studio Code    |
| npm       | 5.6.0    |
| node.js        | 8.9.4          |
| date-fns    | `npm install date-fns`でインストール済み       |
## 試してみましょう

``` jsx
let parse = require('date-fns/parse')
const result = parse('2022-02-31', 'yyyy-MM-dd', new Date()) // 不適切な日付
console.log(result)
// Invalid Date
```
``` jsx
let parse = require('date-fns/parse')
const result = parse('2022-02-20', 'yyyy-MM-dd', new Date()) // 適切な日付
console.log(result)
// 2022-02-19T15:00:00.000Z 日本はUTC+9時間なので-9時間されている
```
date-fnsのparseメソッドに不正な値を入力するとInvalid Dateを返してくれます。
また、正常な値では問題なく(yyyy-MM-dd)型の日付を返してくれます。
### 補足
date-fnsのparseメソッドはうるう年にも対応しています
``` jsx
let parse = require('date-fns/parse')
const result = parse('2023-02-29', 'yyyy-MM-dd', new Date()) // 不適切な日付
console.log(result)
// Invalid Date
```
```jsx 
let parse = require('date-fns/parse')
const result = parse('2024-02-29', 'yyyy-MM-dd', new Date()) // 適切な日付
console.log(result)
// 2024-02-28T15:00:00.000Z // 
```

# 留意点
date-fnsにはvalid_date?というメソッドが用意されていますが、2023-02-31などの不適切な日付も許容してしまうため、parseメソッドを使用することを推奨します。

また、JavaScriptにはDate.parseというメソッドが用意されていますが、
>ブラウザーごとに動作が異なり一貫性がないため、 Date.parse で文字列を解釈しないことを強く推奨します。

とMDNに書いてあるようにDate.parseをバリデーションとして使うことは非推奨です。

# まとめ
JavaScriptで日付のバリデーションを行う場合はdate-fnsのparseメソッドを使用することを推奨します。

# 参考記事
[mdn date docs(MDN公式サイト Dateクラス)](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Date)
[date-fns-parse(date-fns公式サイト)](https://date-fns.org/v2.30.0/docs/parse)
シングルインスタンスにおけるサービスの自動起動

[前回の続き](https://qiita.com/d-same/items/574e8a2d7efc4a978d5a)

前回はPDBに独自のサービスをいくつか付与するところで終わってましたが、
実は`DBMS_SERVICE.CREATE_SERVICE`で付与したサービスはPDBの起動とは連動していません。

実際の運用を考えると、サービスを自動起動させたい場合もあると思うので、
今回はその方法について触れていきたいと思います。

# 本題
他の方法があるかもしれませんが、今回はトリガーを使った方法を扱いたいと思います。
トリガーを作る際には、対象となるPDBに切り替えたうえで、SYSユーザで実行ください。

```sql
alter session set container = pdb;
```

トリガーの名前は任意でよいです。

```sql:trigger
CREATE OR REPLACE TRIGGER pdb_service_trigger
 ALTER STARTUP ON DATABASE
BEGIN
  DBMS_SERVICE.START_SERVICE('new_service');
END pdb_service_trigger;
/
```

上記のトリガーによって、PDBがOPENした際に`DBMS_SERVICE.START_SERVICE`が呼び出されます。
サービスが複数ある場合は、`DBMS_SERVICE.START_SERVICE`を複数記述すればよいです。

トリガーを設定した後は、PDBをCLOSE⇒OPENして`v$active_serice`を確認すれば、自動起動していることが確認できます。

```sql: v$active_services
alter session set container = PDB;
shutdown immediate;
startup;

select name from v$active_services;

NAME
---------------------
PDB
new_service
```

# OS起動停止に合わせてDBも自動起動させたい場合
シングルインスタンスの場合、OCWによる自動起動が働かないのでどうしても自前で自動起動の準備が必要です。インスタンスは`$ORACLE_HOME/bin`にdbstartとdbshutが用意されていますので、これを用いて systemd にサービスを登録することで、OSの起動停止に連動してインスタンスを自動起動／停止させることができます。（リスナーも）

https://goodbyegangster.hatenablog.com/entry/2019/11/18/194107

PDBに関しては`alter pluggable database [all|<PDB_NAME>] save state`することで、インスタンス起動時に保存した状態を維持してくれます（＝READ WRITE (OPEN) でSAVEしておけば、自動的にOPENされます）

https://qiita.com/haborym777/items/9e26ccec54587781affe

で、今回のサービス起動トリガーを仕込んでおけば、OSを起動すると自動的にサービスまで起動してくれるようになります。

実際には、運用ポリシーによって自動起動させない場合もあるかと思いますが、こういう選択肢があるということも覚えておくと幅が広がってよいかなと思います。
UNIX時間について

# はじめに
毎週1本様々な技術に関する記事を投稿しています。
もし興味のある方は下のリンクから他の記事も見ていただければ幸いです。
 [@7_inai_](https://qiita.com/7_inai_)


# UNIX時間とは
UNIX時間はコンピューターシステムにおいて`日付と時刻を表現するための時間単位で、1970年1月1日午前0時0分0秒からの経過秒数を指します。`このシステムは広く利用され、様々なコンピューターシステムやプログラミング言語で採用されています。

# 用語解説
### ■UTC
UTC(Coordinated Universal Time)とは、__協定世界時__ のことで、世界各国の標準時の基礎となります。

### ■POSIX時間とUNIX時間
基本的には、どちらも同じ時間を表しますが、__UNIX時間は、地方時間が変わるとそれに連動__ して変わるのに対して、__POSIX時間はUTCを基準としているため、地方時が変わっても変化しません。__

### ■エポック秒とは
1970年1月1日 0時0分0秒 から経過した秒数を指すコンピュータシステム上での時刻表現の一種のことです。
ちなみに、現在時刻(2023年10月19日22:48分00秒)をエポック秒で表すと、1697755680(UTC)です。

# 2038年問題
UNIX時間は32ビットの符号付き整数で表現されており、これにより最大値を表現できる範囲が限られています。このため、__2038年1月19日3時14分7秒（UTC）を超えると、UNIX時間はオーバーフローし、負の値になります。__ これは、システムやアプリケーションに予期せぬ問題を引き起こす可能性があるため、対策が必要です。
対策としては、time_t型を符号付き64ビット整数型にする方法が一般的ですが、64ビットにできない環境では、32ビットの符号無し整数にする方法がとられています。

# 終わりに
UNIX時間は、コンピューターシステムで時刻を扱うための重要な概念であり、多くのアプリケーションで利用されています。しかし、2038年問題などの課題も存在し、今後の技術進化とともにその対処が求められています。UNIX時間は計算機科学の基本的な要素であり、その理解はプログラマーやシステムエンジニアにとって不可欠です。

最後までお付き合いくださりありがとうございました。