OmniAICreator/Qiita-1.07M huggingface dataset:
Capacitorプラグインのテストはどうあるべきかを考える

WebアプリをWebViewを使ったモバイルアプリにする「Capacitor」というライブラリがあります。Web制作の技術スタックでAppStore/Google Playで配信するモバイルアプリをつくれて便利なので、定期的に話題になるライブラリです。

https://capacitorjs.jp/

Capacitorには、WebViewとデバイス上のネイティブコード（SwiftやJava）がやりとりをするためのプラグイン機構が搭載されています。これを使うことで、Webだけでは実現できない機能やユーザ体験を提供できるので、Capacitorを使って作られたアプリは大体はプラグインを利用しています。

プラグインは、Capacitorチームが提供しているコアプラグインだけでなく自作することもできますが、”作り方”は解説されていてもテストというか動作確認についてあまり話題にしている記事がないので、3つの方法についてみていきましょう。

# 3つの方法
## アプリに組み込んでテストする

誰もがしている動作確認は、つくっているアプリに組み込んだ状態で行うテストでしょう。プラグイン開発後に、まずプラグインレポジトリで以下のコードを実行します。

```bash
% npm run build
% npm link
```

これにより、ビルド済みのパッケージを対象にシンボリックリンクが作成されます。

そのあと、アプリ側で以下を実行します。ここではつくったプラグインは `capacitor-hoge` というパッケージ名だとしましょう（ `package.json` の `name` フィールド）


```bash
% npm link capacitor-hoge
```

これでローカルでリンクされますので、 `import { capacitorHoge } from 'capacitor-hoge'` のようにプロダクト内で使うことができるようになります。

ただアプリに組み込んでるので、Expect / Unexpect を両方手動で最後までテストしないといけなくなります。リリース前の最終確認段階は別ですが、日常的にはあまりやりたくないテスト方法ですよね。


## プラグインにネイティブのテストを書く

プラグインは、Web / Swift / Javaでコードを書いてるわけですから、それぞれでテストコードを書けばいいんじゃない？という、とても正しいテストへの向き合い方です。例えば、 `@capacitor-community/admob` では、Bannerの表示に関わるテストは以下のようにテストを書いています。

https://github.com/capacitor-community/admob/blob/master/android/src/test/java/com/getcapacitor/community/admob/banner/BannerExecutorTest.java

ただ留意が必要なのは、これは1プラットフォームでの動作を担保するテストであり、プラットフォームごとのテストが必要になります。また、ほとんどのプラグインが「ネイティブライブラリのラッパー」であることを考えると、ライブラリのテストをプラグインで実行するのにほぼ等しくなるので、コストほどのリターンを得ることは難しいでしょう。

> 例えば、 `@capacitor-community/admob` は、AdMobライブラリをWebViewから実行できるようにしてるラッパーライブラリであり、独自機能を持たないのでこれに該当します。けれど、Modalを立ち上げてプロダクトのネイティブコードと統合するようなプラグインの場合はこの限りではありません

そう思うと、ネイティブレベルで行うべきは機能のテストより手前のビルドテストで十分なことがほとんどでしょう。Capacitorプラグインのテンプレートには最初から以下のコードが用意されているので、これをGitHubのCIで通せば最低限の確認はできます。

```json
"verify": "npm run verify:ios && npm run verify:android && npm run verify:web",
"verify:ios": "cd ios && pod install && xcodebuild -workspace Plugin.xcworkspace -scheme Plugin -destination generic/platform=iOS && cd ..",
"verify:android": "cd android && ./gradlew clean build test && cd ..",
"verify:web": "npm run build"
```

https://github.com/ionic-team/create-capacitor-plugin/blob/main/assets/plugin-template/package.json.mustache#L33-L36


## テストを半自動で実行するデモプロジェクトの作成

まずはこれをみてください。私はCapacitorプラグインは基本的にこのような自動実行のデモプロジェクトを用意するようにしています。

https://twitter.com/rdlabo/status/1386678109768880128

これはタブを切り替えたイベントで発火して、メソッドを順に実行しながら、期待した結果とイベントを取得するようにしています。この最も優れた点は、

1. プラグインのメソッドの使い方が実装コードレベルでわかる
2. 結果やイベントの値が、デバイスで異なる場合は検知できる


という2点です。まず1つめは自明ですよね。使い方聞かれた時に、「デモコードみておいて」といえるのはとても便利です。そして2つ目は、「iOSとAndroidで実装者が異なって返ってくる値が間違っていても、デモプロジェクトの実行段階で気付ける」というメリットがあります。いや、本当ひとりでプラグイン開発していても、iOSでは返り値の最初の文字が大文字なのに、Androidでは小文字だったり。そもそもイベント発火のタイミングが異なってたり。これをつくるまではこういう小さなミスに本当悩まされました。それがこれだけで解決！


# プラグインと開発者の特性にあわせて組み合わせよう

今のところ、私が開発しているプラグインは、この3つを組み合わせてテストするようにしています。個別的に「iOSのverifyが遅すぎる。GitHub Actionsの時間食い尽くすからこのテストはコメントアウトしよう」みたいなのはあったりはしますが、CIに組み込める「プラグインにネイティブのテストを書く」はプルリクエストをレビューする時には必須ですし、デモプロジェクトがないと開発者体験の落ちるプラグインになってしまいがちです。また、最終の組み込みテストはどちらにしても必須ですよね。

テストの必要性はわざわざ語るまでもないですが、できるだけ日常のプラグインメンテナンスのコストを下げるために、どこまで自動化できるか、また自動化しすぎたらテストメンテナンスのコストが大きくなるのでどうやってバランスをとるかを考えると、よりよいテストがみえてくるかと思います。

それではまた。
KubernetesとEKSの学習記録 Part 3

# 概要
仕事でKubernetes(AWSのEKS)を利用する機会が出てきたため学習します。

学習ステップとしては以下のようにしてみようと思っています。
1. Kubernetesの基本用語の理解
2. Kubernetes公式チュートリアルやってみる
3. EKSの基本用語理解
4. EKSでサービスを作ってみる

今回はステップ3 「EKSの基本用語理解」

この記事はそのメモやまとめです。
すでに設定済みの項目がいくつかある。
試行錯誤しながらやったので、手順として不要かもしれない。**あくまでメモ用。**

## ECSについて理解する。
AWSでContainerを使おうとするとECS or EKSになると思うので、まずはECSについて用語を含めて理解していく。

###  ECS
https://aws.amazon.com/jp/ecs/
> Amazon Elastic Container Service (ECS) はフルマネージドのコンテナオーケストレーションサービスであり、コンテナ化されたアプリケーションをより効率的にデプロイ、管理、スケールするのに役立ちます。AWS 環境と深く統合され、Amazon ECS Anywhere を使用した高度なセキュリティ機能を備えた、クラウドとオンプレミスでコンテナワークロードを実行するための使いやすいソリューションを提供します。

つまり前々回の用語で話したデータプレーンの部分をAWS側で用意したESCというフルマネージドなコンテナオーケストレーションが行ってくれるという感じですかね。(Kubernetesじゃないから厳密には違うかもだけど……)

Nodeで起動できるサーバー、Eコンテナを動かすための実行環境（データプレーン）をEC2、コンテナに特化したAWS Fargate、自分の所有するマシンとするAmazon ECS on AWS Outpostsの３つから選べる。

### ECR
https://docs.aws.amazon.com/ja_jp/AmazonECR/latest/userguide/what-is-ecr.html

Containerのイメージを格納する場所
タスク定義などはEKCのみなのでスキップします。
こちらも参考にしました。

https://dev.classmethod.jp/articles/re-introduction-2022-ecs/

## ESCとEKSって何が違うの？
こちらのページが非常にわかりやすかったです。

https://zenn.dev/yoshinori_satoh/articles/2021-02-13-eks-ecs-compare

コントロールプレーンをAWSが独自に開発したECSが担当するか、AWSにマネージドされたKubernetesが担当するか、の違いだと思っています。

また、この２つのどちらを利用してサービスを作成する場合運用面で違いはどうなるか？なども理解できました。
ECSは学習コストが低く、小さなシステムに向いているが、大きくなるに連れてそれに付随するサービスを自分で作成する必要があるのでどんどん管理が大変になっていく。
EKSはEKSだけではなくKubernetesの学習も必要なので学習コストが高い、コントロールプレーンに料金がかかる、定期的なKubernetes自体のアップデートが必要、といったところでしょうか。
EKSはコスト面や運用面など事前にいろいろ考える必要がありそうですね。

またEKSはクラスターを作成するとクラスターには 0.1USD/hour の料金が発生します。

## EKSの用語を理解する
いくつかEKS特有の用語があったので調べてします。
- ノードグループ

https://pages.awscloud.com/rs/112-TZM-766/images/202110_AWS_Black_Belt_Containers222_EKS_DataPlane.pdf

https://docs.aws.amazon.com/ja_jp/eks/latest/userguide/managed-node-groups.html

データプレーン、つまりNode部分について、以下の選択肢があるようで、それぞれ特徴があることがありました。
・ES2(セフル)
・EC2(マネージド)
・Fargate
EC2のマネージドの場合にノードグループという単語が登場します。
EC2(マネージド)は正式には「マネージド型ノードグループ」と呼びEKSによって管理されるEC2のASGを作成するといったものです。

- eksctl
EKSを構築/管理するためのコマンドラインツールのことです。

https://dev.classmethod.jp/articles/getting-started-amazon-eks-with-eksctl/

なんとeksctlを使うと
```bash
eksctl create cluster
```
だけでEKSの環境に必要なものすべてが一括で作成してくれるみたいです。す、すごすぎる……。

- Fargate プロファイル

https://dev.classmethod.jp/articles/outline-about-fargate-for-eks/

EKSでFargateを利用するための設定情報のようです。
これをEKSに設定した後にKubectlでPodを起動させると、Fargateが起動してFargate上でPodが実行される、といったようにしてFargateが起動するようです。

## EKS on Fargate
EKSでFargateを使って構築することを「EKS on Fargate」と呼ぶようです。
こちらについても概要などを学習します。

https://qiita.com/mumoshu/items/c9dea2d82a402b4f9c31

便利な反面、できないことやりにくいことも結構あるようですね。

## EKSを学習する
まずはblackbeltを見る。

https://aws.amazon.com/jp/blogs/news/aws-black-belt-online-seminar-con221-introduction-eks/

次はクラスメソッドさんの入門編を見る。

https://dev.classmethod.jp/articles/eks_basic/

## ログはどうするの？
特にFargateを利用する際はログの管理がかなり厄介なようです。
今回は深掘りしませんが、複雑だということだけ覚えておきます。

https://aws.amazon.com/jp/blogs/news/how-to-capture-application-logs-when-using-amazon-eks-on-aws-fargate/
取引先の所有者を変更する


# The new owner must have read permission

+ [The new owner must have read permission](https://trailhead.salesforce.com/trailblazer-community/feed/0D54S00000E9IepSAF)

現在の所有者はシステム管理者で、これをStandard Platform User licenseのユーザに変更します。

Standard Platform User licenseなので、取引先と取引先責任者にはアクセス権があります。
商談、ケースにはありません。

+ 商談、ケースと関連している取引先の所有者を変更する

おそらく、商談、ケースに対するアクセス権がないのでエラーになっているのかと...

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/fa18d167-c40e-4429-6b56-d4cbadda5ecd.png)

+ 取引先責任者だけと関連付けられている場合

問題なく所有者を変更できました。

この場合は、取引先責任者の所有者も自動で変わりました。

+ [Attempting to transfer account ownership to other user. Receiving the error below. I checked all permissions and am not able to determine the cause. Error: "The new owner must have "Read" permissions on this type of record."](https://developer.salesforce.com/forums/?id=906F0000000g26tIAA)

:::note
Please check new Owner's profile should have Read permission on Contact, Opportunity, Edit Events, Edit tasks.
:::

+ [取引先所有者を変更したときにその取引先に紐づく取引先責任者の所有者を変更しないようにする方法](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007SrH2QSAV)
+ [取引先所有者の変更時に進行中の商談所有者を前の状態にしておきたいです。](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007StVB6)

# 取引先の所有者を変更すると、商談の所有者も自動で変更される

これは標準の機能みたいです。

取引先の所有権を譲渡すると、新しいユーザーは以下の所有権を持ちます。

- 既存の所有者に属するメモ。 
- 既存の所有者に属するすべての取引先責任者。 
- 既存の所有者に属するすべての商談 (オプションで終了した商談を含む)。 
- 既存の所有者に割り当てられたすべてのオープン アクティビティ。完了したアクティビティは転送されないことに注意してください。 
- 新しい所有者は共有を編集する必要がある場合があります。

https://developer.salesforce.com/forums/?id=906F0000000g26tIAA

# トリガーしない？

+ [取引先所有者変更時「進行中の商談の所有者」が変更されますが、その際に商談のレコードトリガーフローは起動されない認識であっていますでしょうか？](https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007UrvsC)

:::note
ワークフロー ルール/プロセス ビルダーも起動しないようなことが説明されているのでフローでも起動しないのかもしれません

https://help.salesforce.com/s/articleView?id=000384985&type=1

取引先のフローの中にロジックを組むようなことが解説されています。関連するすべての商談を対象にした処理みたいです。

https://trailhead.salesforce.com/trailblazer-community/feed/0D54V00007OYvBnSAL
:::
【Rails】どちらか一方のデータ（カラム）のみを入力必須にするバリデーション

&emsp;

Railsを使ったWebアプリの開発中、「2つの入力欄のうち、片っ方だけが入力されていればOK、っていうバリデーション付けられたらかっけぇ...」と思い、実際にその機能をつけました。
&emsp;

用意された2つの入力欄のうち、どちらか一方のデータ（カラム）のみを入力必須にするバリデーションを付与することは、とてつもなく重要です。実際、「携帯電話番号か自宅などの固定電話番号のうち、どちらか一方だけは入力が必須」という場面はよく見かけます。
&emsp;

そこで、「2つのデータのうち、どちらか一方のデータのみが入力されれば保存される」＝「2つのデータ両方が入力された場合は保存されない」という、二者択一入力必須条件をRailsで実装する手順をまとめました。
&emsp;

二者択一入力必須条件をつける手順説明は、次の内容でまとめました。
* 開発環境
* 具体的な実装内容 《本編》
* 実装のポイント：『排他的論理和：＂^＂』
&emsp;

## 開発環境

| Category       | Value,Version       |
| :------------: | :-----------------: |
| OS             | MacOS Sonoma 14.1.2 |
| Ruby           | 3.2.0               |
| Ruby on Rails  | 7.0.8               |


## 具体的な実装内容 《本編》

バリデーションを実装したいテーブルと関連するモデルに、次の内容を記述します。
```ruby:models/x.rb

  # 「携帯電話番号か固定電話番号のうち、どちらか一方だけの入力が必須」という場面

class X < ApplicationRecord

  validate :required_either_mobile_number_or_landline_number

  private

  def required_either_mobile_number_or_landline_number
    return if mobile_number.present? ^ landline_number.present?
    # ＂^＂は『排他的論理和』という論理演算子の一種です。本実装のポイントになります。
  end

end

```
&emsp;
### 補足

「どちらか一方のデータのみが入力されれば保存される」という条件ですが、マイグレーションファイルのNOT NULL制約（テーブルの属性値に空の値（NULL）が入らない（NOT）ように制限するための制約）はどちらのカラムにも設定します。
```ruby:db/migrate/2023〜〜〜.rb
class CreatePersonalinformation < ActiveRecord::Migration[7.0]
  def change
    create_table :personalinformation do |t|
      t.string     :mobile_number,  null: false # NOT NULL制約
      t.string     :landline_number,  null: false # NOT NULL制約
      t.timestamps
    end
  end
end
```
&emsp;
## 実装のポイント：『排他的論理和：＂^＂』

今回の条件を満たすバリデーションを実装する際におさえるべきポイントは、次の点です。

:::note info
「どちらか一方のデータ（カラム）のみ入力必須」は『排他的論理和：＂^＂』という論理演算子で与える。
&emsp;
[「排他的論理和」とは？｜Ruby公式ドキュメント](https://docs.ruby-lang.org/ja/latest/method/TrueClass/i/=5e.html)
:::
&emsp;

具体的にどういう論理演算子なのか、「⭕️データを保存できるパターン」と「❌データを保存できないパターン」に分けて、それぞれ解説します。
&emsp;

まず、「⭕️データを保存できるパターン」として、次の場合が挙げられます。
&emsp;
> ⭕️パターン①：「2つのデータ（カラム）のうち、どちらか一方のデータのみが入力された」場合
> &emsp;
>「true ^ false（false ^ true）」の場合
> &emsp;
>↓ つまり...
> &emsp;
>「mobile_number.present?とlandline_number.present?のうち、どちらか一方がtrueかつどちらか一方がfalse」という場合

&emsp;

一方、「❌データを保存できないパターン」として、「2つのデータ両方が入力された」場合と、「2つのデータ両方とも入力されない」場合、というパターンが挙げられます。
&emsp;
> ❌パターン①：「2つのデータ両方が入力された」場合
> &emsp;
>排他的論理和が「true ^ true」の場合
> &emsp;
>↓ つまり...
> &emsp;
>「mobile_numberが入力された（true）かつ landline_numberが入力された（true）」という場合

&emsp;
> ❌パターン②：「2つのデータ両方とも入力されない」場合
> &emsp;
>排他的論理和が「false ^ false」の場合
> &emsp;
>↓ つまり...
> &emsp;
>「mobile_numberが入力されない（false）かつ landline_numberが入力されない（false）」という場合

&emsp;

ここまで挙げたパターンは、モデルの単体テストをする際にも重要です。
&emsp;
&emsp;
&emsp;

プログラミング学習のアウトプット、以上になります。
ご指摘あれば、お気軽にコメントください。
&emsp;
[参考記事：Railsで、どちらか一方のカラムを入力必須（二者択一）にするバリデーション](https://qiita.com/harashoo/items/6f5aaded7e0e00b02253)
PowerPoint 代替テキストの自動生成フリーズ → アプリケーションメモリが不足しています。

## 環境
- OS: macOS Sonoma

## 現象
PowerPointアプリにて代替テキストの自動生成したところ、アプリケーションがフリーズして「アプリケーションメモリが不足しています。」システムダイアログが出てきた。87"GB"というとんでもない量のメモリを使おうとしている。
![スクリーンショット 2023-12-01 15.48.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2898772/013b8c4a-eb37-095f-9f8a-8993736aaf54.png)

## 解決策
3分ほど待っても Activity Monitor で処理が走っている様子がなかったのでPowerPointを強制終了したところ治った。自動保存したところまでは復元できる。

慌てずしばらく放置して、自動保存が効くのを待った方が良さそう。

再度代替テキストを生成しても同様の現象発生した。
【育休中】統計検定準１級を取得したきっかけ

**はじめに**

こんにちは。memeと申します。閲覧頂きありがとうございます。
2023年1月第一子出産、現在育休を取得しており、子育ての合間を縫って統計検定準１級に合格しました。自身の振り返りとして、また、どなたかの参考になれば、という思いで合格体験記を記します！





**自己紹介**
大学までは一応理系ですが、遊びとバイトに追われて勉強した記憶はほとんどなし。
新卒でIT系の事業会社に入社し、5年目の後半から産休に入り現在育休中です。






**なぜ統計検定？**
Pythonを使ったデータ分析には、社内研修を通じて触れた経験が実はありました。
業務だけでも残業に追われる状態で、しっかり腰を据えて勉強できずじまい。当時教材で登場したコードの意味をググると、なんか言っている事が統計っぽかった。よし！統計学興味あったし、Pythonは横に置いて勉強してみよう！とノリで勉強を始めて、2022年8月統計検定2級に合格。（つわりと戦いながら結構キツかった）
会社も資格取得に前のめりな風土の為、その後G検定やTableau関係の資格を立て続けに取得。





そこから第一子が産まれ、更に夫の海外留学が決定。2年は日本に戻らない予定となりました。たっぷり時間はある！なんか挑戦したい！そういえば、2022年のM1グランプリを見てた時、得点データを使って「主成分分析」してみたいと思ってちょっとググったけど、あまり意味わからなかったなあ。統計検定準1級の範囲内らしいけど、ネットに乗っている体験記どれも頭良さそうすぎて、自分には無理かも…いや、無理かもしれないけどやってみようかな？（迷い中）





**統計検定の学習といえばとけたろう先生**
"とけたろう"先生をご存知ですか？
https://youtube.com/@toketarou?si=CkM0tNw5ZkXr9dnV
2級向けにはYoutubeとブログで無料の教材を提供しておられます。




息子が生後3ヶ月となる4月中旬、2級の時に視聴したYoutubeの講座を再視聴。確率から始めて重回帰分析まで全18回、1日1講座視聴してはブログの練習問題を解いていました。更にPBT時代最高難易度と言われる2021年の過去問を2級学習時以来解いてみた。
何と1問以外は正解！完全に自信がついた。

https://twitter.com/meme08157830/status/1653215473956454400

更にとけたろう先生のTwitterにて、準1級向けの有料講座準備中との情報をゲット。

とけたろう先生の指導があれば、死ぬ気で頑張れば、もしかして受かるかも？挑戦できるのは渡米まで。3~4ヶ月か。やってみようかな…

夫「ダメならダメでいいやん。やる前から考えすぎ」

という事で、恐る恐る「ワークブック」を購入し、受験を決意。

以上、受験のきっかけでした。
Rustのファイル分割に悩んだ話

# ファイル分割に悩んだ・・・

きれいにコードを書くためにファイル分割をしてモジュールとして使いたいって場面、どの言語でも多いですよね。
 RustでAPIを作ってみようと思って膨らむからファイル分割をしようとしたんだけど、やり方が分からなかった:rolling_eyes:

やりたい事としては以下のディレクトリ構成でAPIのグループごとに分けたかったということです。
```text
.
└── project/
    ├── src/
    │   ├── main.rs
    │   └── api/
    │       ├── hoge_api.rs
    │       └── fuga_api.rs
    ├── Cargo.toml
    ├── Cargo.lock
    └── target
```


とりあえずggrksということで調べてみました。

<strong>・・・わからん！:sweat:</strong>

なので、いろいろ試行錯誤することに

# 解決方法

>ディレクトリ
```text
.
└── project/
    ├── src/
    │   ├── main.rs
    │   └── api/
    │       ├── mod.rs
    │       ├── hoge_api.rs
    │       └── fuga_api.rs
    ├── Cargo.toml
    ├── Cargo.lock
    └── target
```
>結果

結論からいうと、分割したファイルを配置したいディレクトリにmod.rsを置いてこれを記述する

```rs:src/api/mod.rs
pub mod hoge_api;
pub mod fuga_api;
```

そして、main.rs（一番上のモジュール使うファイル）に以下を追記する

```rs:src/main.rs
use axum::{
	routing::get, 
	Router,
	body::Body
};
use std::net::SocketAddr;
use std::env;
use dotenv::dotenv;

mod api;

#[tokio::main]
async fn main() {
	// .envファイルから環境変数を読み出し
	dotenv().ok();

	// logを出力するシステム
	let log_level = env::var("RUST_LOG").unwrap_or("info".to_string());
	env::set_var("RUST_LOG", log_level);
	tracing_subscriber::fmt::init();

	// APIの作成
	let app:Router<Body> = create_app();
	// ソケットの確保
	let addr = SocketAddr::from(([127, 0, 0, 1], 8000));

	// デバッグ用の接続先を表示
	tracing::debug!("listening on http://{}", addr);

	// リスニング
	axum::Server::bind(&addr)
		.serve(app.into_make_service())
		.await
		.unwrap();
}


// APIを作成する関数
fn create_app() -> Router {
	Router::new()
		.route("/", get(root))
        // hoge_apiのapiを作成
		.nest("/hoge", api::hoge_api::create_router())
        // fuga_apiのapiを作成
		.nest("/fuga", api::fuga_api::create_router())
}


async fn root() -> &'static str {
	"Hello, World!"
}
```

# まとめ
これでファイル分割完了！
いろいろ調べたけど割と自分のやりたいことと少々違って、結構手探りでやってみたけど、きれいにまとまって満足 :relaxed:
AdobeXDとAkyuiUnityを使用し、ゲームUI制作を簡易化する

この記事は「Unity Advent Calendar 2023 その2」 1日目の記事ならびに2023/12/1に行いました「Unity UI 完全に理解した勉強会」で発表しましたLTの補足資料です。

はじめまして、ななのりと申します。
AdobeXDを活用し、趣味で制作中のゲームに使用するUIを作っているので、制作方法や技術などをデザイン制作の視点でご紹介していければと思います。
※本記事では、Unity 2021 LTSを使用し、検証しています。

## Adobe XDとは
WebデザインやアプリケーションのUIを作成し、プロトタイプとして動作させることができるソフトウェアです。
Photoshopと違い、細かい画像編集を行う機能は無く、インタラクティブなデザインを組むことに特化しています。
同様のことができるソフトウェアとしてFigmaなどがあります。

## AkyuiUnityとは
Adobe XDを使用し、UIのプロトタイプを組んだファイルをUnityに直接取り込み、デザインをUnity内にプレハブとして自動的に作成してくれるパッケージです。

https://github.com/kyubuns/AkyuiUnity

## UI作成
Adobe XD上で、Unityに取り込むUIを組み上げます。
この時点でオブジェクトにボタンのコンポーネントをつけるなどの処理を追加することも可能です。
詳細はAkyuiUnityのマニュアルをご確認ください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186928/02bccd98-a565-7626-ed12-ac120d023cc5.png)

## AkyuiUnity準備
UnityにAkyuiUnityで取り込めるように準備をします。
1.  マニュアルに記載のとおり、パッケージマネージャーを使用し、Gitからインストールします。
https://github.com/kyubuns/AkyuiUnity/blob/main/Manual/Manual_ja.md
2. `XDImportSettings`を作成します。作成すると、インスペクターに設定画面が表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186928/40229eaf-4f40-3c6b-9f49-80e430db442f.png)
3. 設定画面から、保存先を指定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186928/225a0bff-2268-d99d-5d8d-41e3b65754c9.png)

## 実践
1. 準備の際に設定したFontsフォルダにAdobe XDでファイルを作成した際に使用したフォントファイル(.otf)を入れます。
2. `Drop xd`にAdobe XDで作成したxdファイルをドラッグアンドドロップします。
3. 自動的に処理が行われ、プレハブとして作成されれば完了です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/186928/4ffb09e8-04e1-0d72-f27c-4db7b28b8604.png)


# まとめ
Unity以外のソフトを活用することで、デザイナーとやり取りが行いやすくなったりするメリットがあります。このようなメリットは、小規模開発においても時短に繋がっていきますので、取り入れられるところから初めてみるのもいかがでしょうか。
なお、同様のパッケージはFigmaにおいてもあるようです。お好みのソフトを活用し、より快適な制作環境を作るきっかけになれば嬉しいです。


## 参考文献
https://blog.kyubuns.dev/entry/2021/02/19/094825

https://www.youtube.com/watch?v=9kapwjYG1NY

https://qiita.com/Butterfly-Dream/items/4dd770bd2141974dc7c9

## (おまけ) アドベントカレンダーのご案内
明日は @nanaki_pg さんの予定です。アドベントカレンダー自体も様々な記事が予定されているので楽しんでいきましょう。
CIFS共有しようとしたら「mount(2) システムコールが失敗しました: No route to host.」というエラーが出た【Linux】

LinuxサーバーからWindowsの共有フォルダをマウントしようとした際に、`mount(2) システムコールが失敗しました: No route to host.`というエラーが発生し、マウントできず困りました。

`route`の文字に引っ張られてネットワーク設定やファイアウォールについて確認するも、ping、が通らないわけでも、ファイアウォールで特定のポートを塞いでるわけでもなく、原因が掴めませんでしたが、全然関係ない話だったので備忘がてら残しておきます。

# 環境
- [AlmaLinux](https://almalinux.org/) 8.7

# 結論（原因）
今回の私の場合は`cifs-utils`というパッケージが入っていないことによるものでした。

:::note warn
注意
あくまでイチ確認点としての参考としてください。
実際はネットワーク設定等が原因の場合もあると思います。
:::

> Red Hat Enterprise Linux では、カーネルの cifs.ko ファイルシステムモジュールが SMB プロトコルのサポートを提供します。ただし、SMB 共有をマウントして操作するには、cifs-utils もインストールする必要があります。

（[ポータルより](https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/7/html/storage_administration_guide/mounting_an_smb_share)）

[ここ](https://askubuntu.com/questions/1337493/no-route-to-host-when-mounting-cifs-share)でも似たような質問と回答がなされていました。

# 解決方法
パッケージをインストールして、cifsの設定をすれば良いです。

## 1.パッケージがインストールされているか確認
```
# dnf list installed | grep cifs-utils
```
入っていなければ何も表示されない。

## 2.パッケージをインストールする
```
# dnf install cifs-utils
```

## 3.cifsを設定
ここは各々のやり方で…。

### fstab修正
```
# vi /etc/fstab
```

```:fstab
//hogecifs01/hogelog /var/log/share_log cifs defaults,username=hage,password=hige,dir_mode=0777,file_mode=0777 0 0
```

### マウント
```
# mount -a
```

### 確認
```
# df
```

# おわりに
わりと初歩的な原因だったのですが、最初にネットワーク関連を確認して手こずってしまったので、同じ轍を踏む方がいなくなればと思います。

# 参考
- [SMB 共有のマウント - Red Hat Customer Portal（公式7系）](https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/7/html/storage_administration_guide/mounting_an_smb_share)
Pythonのpandasのサンプル

:::note info
自分勉強記録
:::

**基本動作**

```py:基本
import pandas as pd

# リストからデータフレームを作成する
data = {
    '名前': ['Alice', 'Bob', 'Charlie'],
    '年齢': [25, 30, 35],
    '性別': ['女性', '男性', 'その他']
}
df = pd.DataFrame(data)

# データフレームを表示する
print(df)

# データフレームの列を取得する
names = df['名前']
ages = df['年齢']

# 列を追加する
df['都市'] = ['東京', '大阪', '札幌']

# 条件に合うデータをフィルタリングする
filtered_df = df[df['年齢'] > 30]

# データフレームをCSVファイルに保存する
df.to_csv('output.csv', index=False)

```


```py:列名取得

import pandas as pd

# データフレームを作成する
data = {
    '名前': ['Alice', 'Bob', 'Charlie'],
    '年齢': [25, 30, 35],
    '性別': ['女性', '男性', 'その他']
}
df = pd.DataFrame(data)

# 列名を取得する
column_names = df.columns

# 列名を表示する
for column in column_names:
    print(column)

```

```py:列名変更

import pandas as pd

# データフレームを作成する
data = {
    '名前': ['Alice', 'Bob', 'Charlie'],
    '年齢': [25, 30, 35],
    '性別': ['女性', '男性', 'その他']
}
df = pd.DataFrame(data)

# 列名を変更する
df = df.rename(columns={'名前': 'Name', '年齢': 'Age', '性別': 'Gender'})

# 先頭の2つの列名を変更する
df.columns = df.columns.astype(str)
df.columns.values[:2] = ['New_Name1', 'New_Name2']

# 変更後のデータフレームを表示する
print(df)

```

```py:指定フォルダ配下のtxtファイルを一覧
import os

def list_files(directory):
    for root, dirs, files in os.walk(directory):
        for file in files:
            if file.endswith(".txt"):
                print(os.path.join(root, file))

# 指定フォルダのパスを指定
folder_path = "/path/to/folder"

# フォルダ内の.txtファイルを一覧表示
list_files(folder_path)
```
JSONataのシャッフル

Node-REDでランダムにデータを作りたいと思ってフローを書いていたら、簡単そうなことなのに、ちょっとつまずきました。
ことの顛末と解決方法について書きたいと思います。

# こんな事象

## やりたかったこと

> aからeまでの5つの文字からランダムに文字を取得したい。

そこで、こんな感じのJSONata式を書きました。

```
["a", "b", "c",　"d", "e"][$floor($random()*5)]
```

処理の意味としては、
`$random()`を使用して、0以上1未満のランダムな小数を生成して、配列の長さをかけ算します。
`$floor()`を使用して小数点以下を切り捨て、ランダムな整数のインデックスを得ます。
得られたインデックスを使用して、対象の配列からランダムな文字を取得します。

これでできそうと思ってフローを作り、実行してみました。



## やってみたら、うまくいかない

いざ、injectノードをクリックしてみると、うまく一文字だけ出力されたり、時折、`["a","d"]`といった風に2個でてきたり、*Undefined* になったりします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266424/80e5de25-de13-b7ed-6d06-7836deb376b6.png)

環境は、enebularで動いているNode-RED v3.0.2-n.1です。


# 解決方法

FunctionノードとJSONata式の2通りの方法を試したところ、うまくいきました。
いずれもChatGPT 3.5に聞きました😅

## Functionノードでの解決
FunctionノードでJavaScriptを書いて解決する方法です。いずれもChatGPTに聞いたところ、

```
// ランダムな文字を選択する配列
const characters = ["a", "b", "c", "d", "e"];

// ランダムなインデックスを生成
const randomIndex = Math.floor(Math.random() * characters.length);

// ランダムな文字を取得
const randomCharacter = characters[randomIndex];

// 結果を出力
msg.payload = randomCharacter;
return msg;
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266424/266d4b11-e293-5387-addc-7ae905c96008.png)

ちゃんとランダムな文字列が出てきました。
ですが、うまくいって当然な気もします。

## JSONataでの解決
次に、改めてJSONata式でやってみます。
今度は、`$random`ではなく、`$shuffle`を使います。

```
$shuffle(["a", "b", "c","d", "e"])[0]
```

処理の意味としては、
`$shuffle()`を使用して、配列の値の順番をごちゃまぜにします。
得られた配列の一番最初の値（0番目）を取得すれば結果的にランダムになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266424/a163caad-cec5-0cb8-44c8-1591ee2c2d85.png)

# まとめ

Node-REDでフローを分かりやすく書きたいときにJSONataを重宝しています。
シャッフルなんて知らなかったですが、もっと早く気がつけばよかったです。
教えてくれたChatGPTに感謝します。JSONata式は奥が深いです。
HTML メモ

## HTMLについて
### HTML 
- HTML 要素が一覧表示されています。
- [公式](https://developer.mozilla.org/ja/docs/Web/HTML/Element) 
- [HTMLタグリファレンス](http://www.htmq.com/html/indexm.shtml)
- [GitHub](https://github.com/whatwg/html)

### HTMLタグついて
- <p></p>要素: ブロックボックスで要素全体を1つの長方形にして表示します。
- <span></span>要素: インラインボックスで要素を行ボックスにして1行ずつ折り返して表示します。
- <style></style>要素: 文書内にスタイルシートを記述するための要素です。
- <tr></tr>要素: 表内でセルの行を定義します。
- <th></th>要素: 表のセルのグループ用の見出しであるセルを定義します。
- <td></td>要素: 表でデータを包含するセルを定義します。

### HTML5コンテンツモデル
- 「 〇〇要素の中には、△△要素が配置できる 」といった、各要素ごとに中に配置できる要素を定義した配置ルールの事です。
- HTML5から登場した概念で、HTML5より前にあった、ブロックレベル要素と、インライン要素をもっと細かく定義し直した概念になります。
- 題名でふれたコンテンツ・モデルとはHTML5からブロックレベル要素・インラインレベル要素を廃止し、新たに導入された定義のことです。
- [参考](https://breezegroup.co.jp/202006/html5-contents-model/)

### ブロックレベル要素
- ブロックレベル要素は、<body>要素内のみ現れます。見出し・段落・表など文章を構成する基本となる要素で1つのブロック（かたまり）として認識されます。 また、他のブロックレベル要素やインラインレベル要素を配置することができます。

### インラインブロック要素
- インラインブロック要素は、主にブロックレベル要素の内容として用いられる要素です。文章の一部のように扱われ、例えば<p>要素の中のstrong要素のように段落の中の一部を強調するような使われ方をする要素です。
- また、インライン要素の中にブロック要素を配置することはできません。

### メタデータ・コンテンツ
- 文書情報や他の文章との関係を定義します。
- 要素内で使用できる要素。表示や動作の指定をしたり、ドキュメントの関連性を指定したり、文章のメタ情報などを指定する。該当する要素が下記のものです。

### フロー・コンテンツ
- 文書の本体に現れる一般的なコンテンツ
- 要素内で使用できる要素。テキストや埋め込み要素を含みます。

### セクショニング・コンテンツ
- 見出しと概要を付けられるもの
- 明示的にアウトラインを生成する要素 。header見出しコンテンツのスコープの定義するアウトライン内のセクションを作成します。

### ヘッディング・コンテンツ
- セクションの見出しとなるもの
- 見出しコンテンツ自身によって明示的に定義されたセクションの見出し 。header要素は見出しを含みますが、見出し要素ではないので注意です。

### フレージング・コンテンツ
- 段落などの中に含まれる文節・語句など
- 従来のHTMLでインライン要素と呼ばれていた分類です。

### ヘンベッディッド・コンテンツ
- 文書に他のリソースを埋め込むものです。
- 画像やインラインフレーム 、また他のマークアップ言語などを挿入したりするものです。

### インタラクティブ・コンテンツ
- ユーザーによる操作が可能なものです。
- 対話型コンテンツ。ユーザーとのやり取りのために固有された要素です。

### Dom
- Document Object Model (DOM) は HTML や XML 文書のためのプログラミングインターフェイスです。
- ページを表現するため、プログラムが文書構造、スタイル、内容を変更することができます。
- [公式サイト](https://developer.mozilla.org/ja/docs/Web/API/)

### Xml 
- 主にデータのやりとりや管理を簡単にする目的で使われ、記述形式がわかりやすいとい 特徴があります。

### SSIについて
- SSIとはホームページのファイル（HTMLファイル）にプログラムを埋め込む技術です。
- HTMLファイルに特定の書式で処理を記述することで、サーバ側でその処理を実施してからクライアント側に応答を返す技術です。
- [公式サイト](https://wa3.i-3-i.info/word11962.html)

## 関連言語について
### Pug
- Pug(旧Jade)とは、HTMLを書くためのJavaScriptテンプレートエンジンです。 
- Pugの機能を一言で言うと、HTMLの記述を効率化してくれるということに尽きます。 
- 制作スピードが上げられます。
- 書き間違いが減ります。
- 不具合の削減につながる ・保守にかかる工数、コストが減らせます。
- [公式サイト](https://pugjs.org/api/getting-started.html)
- HTMLに変換するコマンド: $ pug index.pug
ViTのSAをMLPに変更するモデル【MLP-Mixer】


**原論文**
MLP-Mixer: An all-MLP Architecture for Vision
https://arxiv.org/pdf/2105.01601.pdf


**日本語解説**
【MLP-Mixer】MLPがCNN，Transformerを超える日
https://ai-scholar.tech/articles/image-recognition/mlp-mixer




# 結論
ViTのSAをMLPに変更しても精度はあまり変化なかった．



# 概要

画像認識分野ではスタンダードモデルとしてCNNとViTがある．しかし，成功の秘訣はCNNにあるのか？ViTにあるのか？それとも全く違う場所にあるのか？？そこで，CNNでもViTでもないMLPを使用するとどうなるのかを検証する．
そこで，ViTのSAをMLPに置き換える．これにより，十分な量のデータセットと正規化手法を用いることでViTを超える精度を達成した．これにより，成功の秘訣はCNNやViT,MLPには依存しないことが分かった．


# モデル構造
モデル構造を以下に示す．Mixer Layerの部分の具体図を上図に示す．
上図のMixer Layerでは，前半に特徴量の空間方向を認識する処理（Token-mixing MLP），後半にチャンネル方向を認識する処理（channel-mixing MLP）をする．上図のMLP1,2の具体的な構造は右下に示す．
また，空間認識の際，特徴量を転置してMLPを通している．これは，ViTのTransformer Encoderと似ており，SAは空間認識，FFNはチャンネル認識をする空間→チャンネル認識する構造であり，構造は変更せずに認識方法を変更している．



![スクリーンショット 2023-12-01 14.05.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457775/8c9660b3-3651-2f3d-3b63-699ef6cc1271.png)




以下を式で示す．上段がToken-mixing MLPであり，下段がchannel-mixing MLP）の式である．
```math
\begin{align}
U∗,i = X∗,i + W2 σ (W1 LayerNorm(X)∗,i), \\
Yj,∗ = Uj,∗ + W4 σ (W3 LayerNorm(U)j,∗),
\end{align}
```
入力がXであり，σはGELUを示す．各MLPはGELUを間に2層のMLPで構成され，各MLPにスキップ接続を使用する．


# 結果
様々なサイズのデータセットで検証する．ピンクがMLP系，青がViT系，黄色がCNN系のモデルであり，超大規模データセットのJFT-300MのMLP系精度はViT系と比較して高い傾向にある．


![スクリーンショット 2023-12-01 14.56.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457775/31a58511-3490-fc63-be27-ecc9cc7df42a.png)


入力画像のパッチ位置とパッチ内のピクセルをシャフルした場合の精度を示す．通常の画像での精度を青，シャッフルを緑で示す．MLP系のMixerは精度低下しない．反対にResNetは，青と比較して緑の精度が大きく低下する．これは，ResNetは位置による強い帰納的バイアスがあるため，パッチが入れ替わると著しく精度低下すると考える．
また画像全体をピクセル単位でシャフルした場合でも，オレンジのResNetは20%以下になるが，MLPは30%以上を保持している．これらにより，MLPはシャフルに強いことが分かる．


![スクリーンショット 2023-12-01 15.00.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457775/e470801c-787b-2ce3-d48f-e686b8d2d039.png)



# まとめ
今回は，MLP-Mixerについて説明した．ViTのSAではなく，MLPで空間認識しても精度はあまり変わらずに大規模データセットで高精度になることが分かった．CNN，ViT，MLPは空間認識でそれぞれの得意不得意タスクがあるので，適材適所で使用することが大切だと思う．
些細なことを試してみよう

この記事は [一分で読める小ネタのカレンダー | Advent Calendar 2023 - Qiita](https://qiita.com/advent-calendar/2023/raki) の１８日目

# 予習、復習

- 一度やったことでも普段やってないと忘れる
- まだ知らないことを調べて実装しないといけないことはよくある
- 脳のシナプスは関連付けによって活発になる（らしい）
- やらなきゃいけないけどやる気がでない時に、些細なことから始めるとノれることはよくある
- 些細なことを積み上げると（積み上げが大事）全部解消する
- 毎日でも毎週でも些細なことを調べて積み上げる癖を作ろう
- 一回五分とか時間を決めて調べてみるゲームにしちゃうと続けられるよ
- 調べたことは整理して til に上げるのを忘れないことｗ

本文はここまで。以下は時間外

# 例えば

## 頭の体操系

- 誕生日から年齢を算出する
    - （linux等の）コマンド類で
    - （自分の好きな）プログラム言語で
    - テストを書く
- 誕生日の曜日を算出する
- ２つの日付の経過日数（日にち差分）を算出する

## 普段使っているものを深掘りする系

- git のリポジトリの掃除
    - 不要なブランチが残っていないか
    - 不要なアクションが動いていないか
    - ラベルは適切に管理されているか
- 毎日叩くコマンドの alias の見直し
    - 面倒なオプションをコピペや補完で入力していないか（新しく作る）
    - 詰め込みすぎたせいでもっと便利なオプションを殺していないか（違うオプションを試す）

## 普段使っているものの代替を探す系

- コマンドラインでカレンダーを表示する `cal` コマンド
    - 類似に `ncal` がよく紹介される
    - 他のカレンダーコマンドを探してみる
    - github や sourceforge など
    - `brew search --desc calendars --eval-all` みたいにするとローカルで検索できる
    - `brew search --desc calendars --ubuntu` みたいにするとブラウザでパッケージ検索に飛べる（最近知った）

## 業界で話題の何かを調べる系

- クラウドプロバイダーや大手企業のイベントの新情報
- SNSで誰かが話題に挙げた何か
- 今はわからなくても流し読みしておくだけでもだいぶ違う

# いつかやろうと思っていることを issue にしておく

- 全然やる気が無い時に無理にがんばるのもアレなので、issue を立てておいて後まわしにする
- lint してないものはないか
- セキュリティ向上のための見直しはないか
- 新しく取得したい言語、フレームワーク、関連ツールはないか

# 改善依頼

- 頭の体操によさそうな小ネタ
- ここらへん深掘りすると面白いんだぜ、みたいなところ
WaybackProxyを使ってネットサーフィン

## はじめに
鹿児島県の在住者が主催する鹿児島らぐ、鹿児島Linux User  Groupで、「低帯域環境を楽しむ」シリーズの発表を行っています。

2023年10月のらぐでは「WaybackProxyを使ってネットサーフィン」と題して、期間縛りでネット検索を可能にする環境構築の話をしました。

Wayback ProxyはInternet Archive Wayback MachineやOoCitiesのページを取得するレトロマシン向けのHTTPプロキシーです。
ある期間に掲載されていた情報を検索したら、HTTPの書式でブラウザ上に検索した情報を表示してくれるサービスです。

## WaybackProxyのインストールと起動
WaybackProxyはpythonで動作します。
pythonがインストールされているかを確認してから、以下の操作を行います。
```
$ git clone https://github.com/richardg867/WaybackProxy
$ cd WaybackProxy
$ python waybackproxy.py
```
## ブラウザのproxy設定
次に使用するブラウザのproxy設定を行います。
古いバージョンのFirefoxでの例で紹介します。
「Automatic proxy configuration URL」に「http: //ip:port/proxy.pac」を入力します。
ipの部分には、WaybackProxyをインストールしたマシンのIPアドレスを入力します。
portには、利用するネットワークで入力する数字が違います。
デフォルトは8888です。

## 検索環境の設定
「http: //ip:port/proxy.pac」にアクセスすると、検索期間の設定が出てきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/693019/bb7da96a-877c-ab01-6f16-2b530ee3ef46.png)
「Data to get pages from」には、検索範囲の開始年を入力します。
「Data tolerance」には、検索期間を入力します。

## 検索例
例えば、2004年に設定すると、「apple.com」の表示は以下の様になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/693019/b49c5f32-4941-d6fe-d017-b185a21bfdc5.png)
検索期間の違いにより、フロントページが様々に変化します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/693019/eb5498e5-9ce0-0686-2721-7133f98b17a9.png)

ニュースサイトだと、その時期の大事件が表示されます。

色々試してみてください。

参考　https://github.com/richardg867/WaybackProxy
ネットワークアクセス不可からARPパケットキャプチャまで：あるネットワーク障害のトラブルシューティング

### 事象の発生

最近、社内ネットワーク上のあるサーバーにアクセスできないという奇妙な問題に直面しました。ローカルサーバーにはpingできるものの、ネットワーク経由で接続しようとするとどうしても繋がりません。さらに奇妙なことに、ネットワークアダプタを再起動すると一時的にサーバーにアクセスできるようになるのですが、その状態は長続きせず、すぐにまた同じ問題が発生します。

最初はサーバーに何らかの問題があるのではないかと思いましたが、社内ネットワークの転送は正常に動作しており、PCを再起動しても何の改善もありませんでした。

### 分析

基本的なトラブルシューティングを試した後、さらに深く原因を探ることにしました。これはネットワークの問題ではないかと疑い始め、診断を進めるためにARPキャッシュをクリアすることにしました。

```bash
arp -d
```

	

このコマンドはARPキャッシュのすべてのエントリをクリアします。このコマンドを実行した後、突然サーバーに一時的に接続できるようになりました。これは重要な手がかりです。この問題はARPアドレス解決と関係がある可能性があります。

> ARP（アドレス解決プロトコル）は、ネットワーク層のIPアドレスをリンク層の物理アドレス（MACアドレス）に変換するための重要なネットワークプロトコルです。ARPキャッシュに問題があると、物理的な接続に問題がなくても、デバイス間の通信が影響を受けることがあります。

そこで、Wiresharkを使用してパケットキャプチャを行いました。

```bash
2522	40.288508	SichuanA_c8:71:a8	Chongqin_a6:16:53	ARP	42	192.168.1.203 is at 40:24:b2:c8:71:a8
2521	40.283279	Chongqin_a6:16:53	SichuanA_c8:71:a8	ARP	42	Who has 192.168.1.203? Tell 192.168.1.187
2416	33.707043	TP-Link_93:3a:90	Broadcast	ARP	42	Who has 192.168.1.179? Tell 192.168.1.1
2415	33.290589	SichuanA_c8:71:a8	Chongqin_a6:16:53	ARP	42	192.168.1.203 is at 40:24:b2:c8:71:a8
2414	33.286865	Chongqin_a6:16:53	SichuanA_c8:71:a8	ARP	42	Who has 192.168.1.203? Tell 192.168.1.187
2410	32.666726	TP-Link_93:3a:90	Broadcast	ARP	42	Who has 192.168.1.179? Tell 192.168.1.1
2406	31.745045	TP-Link_93:3a:90	Broadcast	ARP	42	Who has 192.168.1.179? Tell 192.168.1.1
2361	29.082620	TP-Link_93:3a:90	Broadcast	ARP	42	Who has 192.168.1.179? Tell 192.168.1.1
2356	28.319732	Chongqin_a6:16:53	SichuanA_c8:71:a8	ARP	42	192.168.1.187 is at b4:b5:b6:a6:16:53 (duplicate use of 192.168.1.203 detected!)
2355	28.319710	SichuanA_c8:71:a8	Chongqin_a6:16:53	ARP	42	Who has 192.168.1.187? Tell 192.168.1.203 (duplicate use of 192.168.1.203 detected!)
2352	28.058744	TP-Link_93:3a:90	Broadcast	ARP	42	Who has 192.168.1.179? Tell 192.168.1.1
2174	27.034509	TP-Link_93:3a:90	Broadcast	ARP	42	Who has 192.168.1.179? Tell 192.168.1.1
791	17.693940	Chongqin_a6:16:53	TP-Link_93:3a:90	ARP	42	192.168.1.187 is at b4:b5:b6:a6:16:53
790	17.693907	TP-Link_93:3a:90	Chongqin_a6:16:53	ARP	42	Who has 192.168.1.187? Tell 192.168.1.1
35	3.073782	Chongqin_a6:16:53	12:5c:4c:7a:38:db	ARP	42	192.168.1.187 is at b4:b5:b6:a6:16:53
34	3.073760	12:5c:4c:7a:38:db	Chongqin_a6:16:53	ARP	60	Who has 192.168.1.187? Tell 192.168.1.203
16	1.328884	TP-Link_93:3a:90	Chongqin_a6:16:53	ARP	42	192.168.1.1 is at 00:5f:67:93:3a:90
15	1.326707	Chongqin_a6:16:53	Broadcast	ARP	42	Who has 192.168.1.1? Tell 192.168.1.187
```


重要な点は`duplicate use of 192.168.1.203 detected`、つまりIPアドレスの競合が発生しています。ARPキャッシュが誤った情報で汚染されたため、ネットワークアダプタがサーバーへの正しい経路を見つけられなくなっています。ネットワークアダプタの再起動やARPキャッシュのクリアを行うと、これらの情報が一時的にリフレッシュされ、短期的な接続が可能になります。

その後、デバイスを調べたところ 
![Pasted image 20231129103008.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2322984/332fb068-be56-53c1-a519-a161254730e0.png)


明らかに異常な2台のデバイスが見つかりました。調査の結果、192.168.1.185のデバイスはDHCPを使用せず、サーバーと競合する固定IPを使用していたため、この問題が発生していたのです。これにより問題が無事解決。
CSS  メモ

## CSSについて
### CSS 
- Webサイトのサイズや色、レイアウトなどを設定 するためのプログラミング言語です。 
- CSSは「シーエスエス」や「スタイルシート」などと呼ばれており、背景の色の変更や画像の設置、文字のフォントや色などの幅広いデザインを定義する際に使用されます。
- [公式サイト](https://developer.mozilla.org/ja/docs/Learn/Getting_started_with_the_web/CSS_basics)
- [CSSタグリファレンス](http://www.htmq.com/style/)
- [GitHub](https://github.com/topics/css)

### CSSタグについて
- margin: コンテンツの内側に余白を作成します。
  - margin: 10px 40px 20px 30px;
  - margin: 上の値 右の値 下の値 左の値;
- margin-top: コンテンツの内側の上側に余白を作成します。
- margin-right: コンテンツの内側の右側に余白を作成します。
- margin-bottom: コンテンツの内側の下側に余白を作成します。
- margin-left: コンテンツの内側の左側に余白を作成します。
- padding: コンテンツの外側に余白を作成します。
  - padding: 10px 40px 20px 30px;
  - padding: 上の値 右の値 下の値 左の値;
- padding-top: コンテンツの外側の上側に余白を作成します。
- padding-right: コンテンツの外側の右側に余白を作成します。
- padding-bottom: コンテンツの外側の下側に余白を作成します。
- padding-left: コンテンツの外側の左側に余白を作成します。
- flex-direction: row; 左から右に並べる
- flex-direction: row-reverse; 右から左に並べる
- flex-direction: column; 上から下に並べる
- flex-direction: column-reverse; 下から上に並べる

### 単位について
- Px: ユーザーでぃすプレイの画面解像度に依存します。
- Em: 親要素のfont-sizeに依存します。
- Rem: <html>要素のfont-sizeに依存します。
- %: 親要素のfont-sizeに依存します。
- Pt: 1pt = 1/72in = 0.3528mm

### レスポンシブデザインについて
- 画面の大きさに合わせてレイアウトを柔軟に調整するWebデザイン手法のことです。

### メディアクエリについて
- CSS3の仕様の一つで、表示された画面環境に応じて適用するスタイルを切り替える記載方法です。
`
@media screen and (min-width:500px) { 
  .test {
    color: blue;
  }
}
`
`
@media screen and (min-width:1025px) { 
  .test {
    color: green;
  }
} 
`

## CSSフレームワークについて
### BootStrap
- 開発時期: 2011年 
- オープン ソースの Webサイトを効率よく開発するためのCSSフレームワークです。 
- CSSファイルやjavascriptファイルが既に作成されており、それらの定義を呼び出すことで容量を軽くすることがて出来ます。 
- 公式サイト: https://getbootstrap.com/docs/4.5/components/forms/ 
 
### TaiwindCSS
- 開発時期:2017年
- オープン ソースの CSS フレームワークです。
- 他の CSS フレームワークとは異なり、ボタンやテーブルなどの要素に対して一連の定義済みクラスを提供しないことです。
- React, Vue.jsなどスタイルをコンポーネント化して画面を構築する際に使用します。
- 公式サイト: https://tailwindcss.com/ 

## 関連言語について
### Sass 
- CSSをより効率的に書けるように拡張した言語 
- Sassには「SASS」記法と、「SCSS」記法の2種類の記法がある。 メリット 
- セレクタやプロパティのネストで記述量が減る
- 一度定義したスタイルのセットを簡単に呼び出せる
- 複雑なコードも再利用できる
- 変数で値を使いまわすことができる
- 四則演算ができる
- 関数が使える
- 公式サイト: https://sass-lang.com/
- 参考サイト: https://qiita.com/m0nch1/items/b01c966dd2273e3f6abe 
 
### SASS記法 
- 名前の通り、Sassがもともと採用していた記法です。 
- 拡張子は.sassのファイル形式。 
- 記述が非常に簡素化されているため、コーディングがコンパクト、簡潔になります。
- rubyライクな書き方をするのでrubyに慣れている方は書きやすいかもしれません。
- SASS記法ではインデントで依存関係を示します。
- 「background-color: lightgray」の後ろのセミコロンも省きます。
- この時、 background-color:の後には、半角スペースを入力する必要があります。 
 
### SCSS記法 
- SCSSはSASSがCSSとの互換性が乏しかったために作られた記法です。
- 拡張子は.scssのファイル形式。 
- SCSSの最大のメリットは、CSSの書き方がそのまま使えることです。 
- SCSSの方が書き方がCSSに近いためコーディングしやすい。 
- SCSS記法では、括弧{}を使い入れ子構造にすることでCSSの依存関係を示します。
BoxShieldを利用してランサムウェアのファイル窃取に対抗する

## はじめに
以前の投稿でBoxはランサムウェア対策として活用できる点をご紹介しました。

https://qiita.com/Fumi-ayuki/items/41d6ec183271a031bb44

クライアント端末がランサムウェア感染し、その端末がBoxDriveを使用していた場合、BoxDriveからアクセスできるコンテンツについては暗号化や窃取のリスクが存在しています。
暗号化に対してはBoxのバージョン管理から復旧することで復元可能であることを上記の記事でもご紹介しましたので、本記事ではBoxShieldを利用したファイル窃取への対策をご紹介したいと思います。

## ファイル窃取に対抗する理由
ランサムウェアと言えば以前はファイルの暗号化を行い、復元に対して身代金を要求する手法が一般的でしたが、昨今では暗号化に加えてファイル窃取も同時に行い、ファイルをリークサイトで公開されたくなければ身代金を払えと要求する、いわゆる二重脅迫と呼ばれる手法が非常に増加しています。
またノーウェアランサムと呼ばれる、暗号化は行わずファイル窃取による脅迫のみを行う被害も報告されています。

## Boxのファイルがランサムウェアに窃取されるとしたら
BoxDriveを使用すると仮想的にドライブにマウントされた状態となり、エクスプローラーライクにBoxのファイルを扱うことができるようになります。
その為ファイルの変更や移動もローカルドライブ同様に操作を行うことができるようになります。
それは通常のオペレーションを行う上では非常に便利な部分ですが、一方でランサムウェアからのファイル変更や移動も行えるようになってしまうことがBoxDriveを利用する上でリスクとなってしまいます。
もし端末がランサムウェアに感染し、ランサムウェアが端末上にマウントされたBoxDriveのファイルを別の場所にアップロードを行った場合はファイル窃取が成立してしまうリスクがあるということになります。

## BoxShieldのダウンロード制限でファイル窃取に対抗する
ファイル窃取を行う際、端末上のオペレーションとしてはファイルをどこかのサーバーへアップロードすることになりますが、BoxDriveのファイルを窃取する場合、ファイル実体はBox上に存在するため実際にはBoxからファイルのダウンロードを行った上でファイルをアップロードする必要があります。
この点に着目し、BoxShieldのダウンロード制限機能を使ってファイルの窃取を制限してみたいと思います。

## BoxShieldの設定
BoxShieldのアクセスポリシーにてセキュリティコントロールの[ダウンロードと印刷の制限]で[Boxデスクトップ向け]を制限したポリシーを作成します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2991170/f88088df-2289-93e8-a735-289806c2bbc8.png)


ポリシー名は今回はわかりやすく[BoxDriveからダウンロード不可]とします。
適用する分類ラベルは事前に作成しておいた「ランサムウェア対策」に適用します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2991170/a56a3061-984d-45e6-5ba0-bfb68387953d.png)

ファイルに作成した分類ラベルを適用します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2991170/173130c3-1afb-7b2c-5a13-e249c0a8bdec.png)

## ファイル窃取検証
BoxDriveから先ほどのファイルを別サーバーへアップロードした場合、ダウンロードが制限されていることから操作はエラーとなり、ファイル窃取は失敗となりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2991170/44788d8c-ab8f-c2c9-bb07-e37fa41a9f79.png)


## 最後に
BoxShieldのダウンロード制限を活用してランサムウェアのファイル窃取への対応策をご紹介しました。
注意点としてこのポリシーを適用するとBoxDriveを利用している正規のユーザーによるダウンロードも制限されるため、BoxWebアプリの活用を推奨するなど、BoxDriveの利用範囲を事前に定義しておくことを推奨いたします。

上記のような制限ははありますがBoxShieldによるファイル窃取対策をご紹介いたしました。
ランサムウェア対策の一環としてご検討いただけますと幸いです。
API Gatewayで/{proxy+}メソッドを活用する方法

## はじめに
こんにちは、開発部の天津炒飯です。

CloudFormationのLambda Functionでパスごと、Eventsを一つずつ書くことで苦労した経験があるかもしれません。
API Gatewayの `` /{proxy+} `` メソッドを使用すると、異なるパスに対するルーティングを簡単に実現できますが、意外と日本語の情報が少ないです。
私はPythonのWebフレームワークであるFastAPIを使用したので、この記事ではFastAPIを使用してAPI Gatewayの `` /{proxy+} `` メソッドを活用する方法に焦点を当てます。

## 1. /{proxy+}メソッドとは
`` /{proxy+} `` メソッドは、ワイルドカードパスを表すもので、異なるパス構造のリクエストを同じAPIエンドポイントにルーティングするのに役立ちます。
例えば、 `` /products/{proxy+} `` は `` /products/item1 `` や `` /products/category1/item2 `` など、様々なパスに対応できます。


## 2. /{proxy+}メソッドの設定
### 2.1 SAMテンプレートの作成
SAMを使用してFastAPIアプリケーションをデプロイするためのtemplate.yamlを作成します。Lambda関数、API Gatewayのリソース、および必要な設定を定義します。

そして、冒頭で述べた通り、各パスごとに Events を一つずつ記述するのではなく、 `` /{proxy+} `` メソッドを使用して、 `` ItemApi1 `` および `` ItemApi2 `` を `` MyApi `` にまとめて記述します。
```diff_yaml:template.yaml
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31

Resources:
  MyApi:
    Type: AWS::Serverless::Api

  MyFunction:
    Type: AWS::Serverless::Function
    Properties:
      Handler: main.handler
      Runtime: python3.8
      CodeUri: ./path/to/your/fastapi/app
      Events:
-        ItemApi1:
-          Type: Api
-          Properties:
-            Path: /item1
-            Method: get
-        ItemApi2:
-          Type: Api
-          Properties:
-            Path: /category1/item2
-            Method: post
+        MyApi:
+          Type: Api
+          Properties:
+            Path: /{proxy+}
+            Method: any
```

### 2.2 FastAPIアプリケーションのLambdaへの統合
FastAPIアプリケーションをLambda関数に統合するために、Lambda関数内でFastAPIアプリケーションを呼び出します。
```python:main.py
from fastapi import FastAPI

app = FastAPI()

@app.get("/item1")
async def get_item():
    return "hello!"

@app.post("/category1/item2")
async def post_item():
    return "world!"
```
```python:handler.py
from mangum import Mangum
from main import app

def handler(event, context):
    api_handler = Mangum(app)
    return api_handler(event, context)
```

## 3. デプロイ
CloudFormationスタックを作成し、API Gatewayの設定とLambda関数をデプロイします。


## 4. サンプルリクエスト
これで、API Gatewayで `` /{proxy+} `` メソッドが有効なAPIが作成されました。クライアントは任意のパスでリクエストを送信できます。
例えば、 `` /products/item1 `` にGETリクエストを送信すると、Lambda関数が対応する処理を実行します。

```console
% GET https://your-api-url/products/item1
hello!
```

以上で、API Gatewayで `` /{proxy+} `` メソッドを使用する基本的な手順が完了しました。この柔軟なメソッドを使用することで、異なるパスへのリクエストを簡単に処理できます。

## 最後に
この記事では、FastAPIとSAMを使用して `` /{proxy+} `` メソッドを活用する基本的な手順を紹介しています。 
FastAPIの具体的な実装やSAMの詳細な設定については、FastAPIおよびAWS SAMの公式ドキュメントを参照してください。

はつかぜ株式会社では、IT学習や業務に役立つ情報を定期的にお届けしていきたいと思っています。
システム開発のお問い合わせ・ご相談はこちら
https://www.hatsukaze.co.jp/inquire/
GO メモ

## GOについて
### Go
- GoはGoogleでロブ・パイク、ケン・トンプソンによって設計されました。 
- Goは、静的型付け、C言語の伝統に則ったコンパイル言語、メモリ安全性、ガベージコ レクション、構造的型付けなどの特徴を持ちます。
- [公式サイト](https://golang.org/)
- [GitHub](https://github.com/golang)

## GOフレームワークについて
### Gin
- 比較的軽量なフルスタックWebアプリケーションフレームワークです。 
- MartiniのようなAPIを備えていますが、パフォーマンスはMartiniの最大40倍です。
- [公式サイト](https://gin-gonic.com/)

### Echo 
- RESTAPI向けのため、RESTの原則に沿った形で設計されたAPIを持っています。 
- [公式サイト](https://echo.labstack.com/)

### Revel
- JavaのPlay Frameworkを参考に設計されたフルスタックフレームワークです。 
- [公式サイト](http://revel.github.io/)

### Beego 
- フルスタックなWebアプリケーションフレームワークです。 
- 公式サイト: https://beego.me/
- [GitHub](https://github.com/beego/beego)

### Iris(アイリス)
- xpress.js ライクな、Go 言語フレームワークです。Node.js で開発を行ったことがある人ならば学習コストが低く最良なフレームワークです。
- 非常多機能で既にバンドルされている機能を利用することで、複数のパッケージを選択する時間を節約することでき、開発者の負担を減らしてくれます。
- 機能としては、以下が既に導入されており開発段階でそれらの機能をインポートし使用するだけです。また MVC フレームワークアーキテクチャを採用しています。
- [公式サイト](https://www.iris-go.com/)

### Goji
- Gojiはnet/httpと互換性を持っているフレームワークです。
- Ginについで高速処理が可能で、小・中規模開発に適しています。
- [公式サイト](https://goji.io/0

### Martini 
- モジュール形式のWebアプリケーションサービスフレームワークです。
- [公式サイト](https://pkg.go.dev/gopkg.in/martini.v0)
- [GitHub](https://github.com/go-martini/martini)

### Goa
- デザインコード(goa API Design Language) のファイルを作成するだけで、マイクロサービスのコアとなるファイルを生成してくれます。 
- [公式サイト](https://goa.design/)

### Go kit 
- 独自のloadbalancerパッケージが担う、DNSやconsulなど様々なプラグインを追加可能です。
- [公式サイト](https://gokit.io/)
データ収集後の加工や可視化まわりでよく使うSQL句

# 書いてあること

データレイクのデータを汎用的な構造に加工してデータウェアハウス化する部分であったり、BIや学習系などセマンティックなマート化する目的であったりによく使うSQL句の以下3つを紹介します。
- cross join
- full outer join & coalesce
- qualify

最近物忘れが増えてきまして、あれどう書くんだっけ？になりがちな自分向けだったりもします。

※SQLはBigQueryベースです

## cross join

いわゆる直積です。

`id`テーブル

```
 id
------
 1
 2
 3 
```

`name`テーブル

```
 name
------
 aaa
 bbb
```

cross joinさせて

```
 id   | name
------+------
 1    | aaa
 1    | bbb
 2    | aaa
 2    | bbb
 3    | aaa
 3    | bbb
```

というデータセットを作れるSQL句です。

これは日別データなどマート作るときに0実績の行を作るのに重宝します。

```
 日付   | 部署     | 販売数量
-------+----------+----------
 11-01 | 営業1課   |      10
 11-01 | 営業2課   |       5
 11-02 | 営業1課   |      13
 11-02 | 営業2課   |       9
 11-06 | 営業1課   |       3
 11-06 | 営業2課   |       6
```

このようなデータから11月の1日から6日までの日別販売数を出すとき、休日である3-5日の0実績レコードを作るような場面で使います。

```sql
WITH
  calendar AS (
    SELECT
      date_seq
    FROM
      UNNEST(GENERATE_DATE_ARRAY('2023-11-01', '2023-11-06')) AS date_seq
  )
SELECT
  calendar.date_seq AS sale_date
  , SUM(CASE WHEN calendar.date_seq = データ.日付 THEN データ.販売数量 ELSE 0 END) AS qty
FROM
  calendar
CROSS JOIN
  データ
GROUP BY
  calendar.date_seq
```

といった具合で書いたりします。

```
 sales_date   | qty
--------------+------
 11-01        |  15
 11-02        |  22
 11-03        |   0
 11-04        |   0
 11-05        |   0
 11-06        |   9
```

後続の可視化や学習などへデータ提供する際、欠損を0として解釈することを委ねずにマート作成時に0と明示的に定義すべきケースにはぜひ使いましょう。

## full outer join & coalesce

こちらはセットでよく使い、複数のデータソースからマージしたり、差分データのマージによる積み上げに使ったりします。

```
-- 決済方法その1（◯◯店の実績から引用データ）
 id | name
----+------
  1 | 現金
  2 | クレカ
  3 | 交通系

-- 決済方法その2（△△店の実績から引用データ）
 id | name
----+------
  1 | 現金
  2 | クレカ
  4 | paypay
```

idの一意性が担保されることを確認したうえでこのような2つのPOSデータからの引用で決済方法マスタを作るとして、

```sql
SELECT
  COALESCE(決済方法その1.id, 決済方法その2.id) AS id
  , COALESCE(決済方法その1.name, 決済方法その2.name) AS name
FROM
  決済方法その1
FULL OUTER JOIN
  決済方法その2
ON
  決済方法その1.id = 決済方法その2.id
```

のように書いて出力します。

```
 id | name
----+------
  1 | 現金
  2 | クレカ
  3 | 交通系
  4 | paypay
```

左右の属性項目に差異が存在して、ロジックを組んで名寄せするパターンなどではCASE文を用いたりもします。

## qualify

window関数を使った絞り込みでサブクエリを書いて条件指定をしていたものが、簡潔な書き方を可能にするとても便利なSQL句です。

```
 計測日時               | 商品   | 在庫数量
----------------------+-------+-----------
 2023-12-01 12:01:45  | みかん |       10
 2023-12-01 19:55:17  | りんご  |       25
 2023-12-01 23:32:09  | みかん |       18
 ```

 このようなデータから供給量の意思決定向けに日別の最新在庫データを使いたい場合

 ```sql
WITH
  stock_with_rownum AS (
    SELECT
      計測日時
      , 商品
      , 在庫数量
      , ROW_NUMBER() OVER (PARTITION BY DATE(計測日時), 商品 ORDER BY 計測日時 DESC) AS rownum
    FROM
      在庫データ
  )
SELECT
  計測日時
  , 商品
  , 在庫数量
FROM
  stock_with_rownum
WHERE
  rownum = 1
```

と書いていたものが

```sql
SELECT
  計測日時
  , 商品
  , 在庫数量
FROM
  在庫データ
QUALIFY
  ROW_NUMBER() OVER (PARTITION BY DATE(計測日時), 商品 ORDER BY 計測日時 DESC) = 1
```

と書けてデータが出力されます。

```
 計測日時               | 商品   | 在庫数量
----------------------+-------+-----------
 2023-12-01 19:55:17  | りんご  |       25
 2023-12-01 23:32:09  | みかん |       18
 ```

便利なqualify句ですが、where句無しでのview作成ではエラーとなるらしく、```where true```を追記するなどして回避が必要とのことです。
Python で Word 文書をマージする方法

## はじめに
大量の文書を処理する際に、関連する文書を 1 つにマージできる場合があります。この操作により、作業効率が向上し、文書の整理が容易になります。手動でのコピー＆ペーストに加えて、プログラミングを使用してこのタスクを実行することも可能です。特にバッチ処理には非常に便利です。以下では、Pythonを使用してWord文書を結合する方法について説明します。
## 環境
* Python 3.12.0
* [Spire.Doc for Python](https://www.e-iceblue.com/Introduce/doc-for-python.html)ライブラリ

このライブラリは有料ですが、[30 日間の無料試用版](https://www.e-iceblue.com/TemLicense.html)も提供されています。
もっと多いサンプルコードについて、[Spire.Doc for Python](https://www.e-iceblue.com/Download/Spire-Doc-Python.html)をダウンロードして参照してください。
## 準備
まず、[Spire.Doc for Python](https://www.e-iceblue.com/Introduce/doc-for-python.html) と plum-dispatch v1.7.4を VS Code にインポートします。
1.[Python](https://www.python.org/downloads/) をダウンロードしてインストールします。
2.VS Codeで「Extensions」をクリックし、「Python」を検索してインストールします。
3.「Explorer」-「NO FOLRDER OPENED」-「Open Folder」
4.フォルダーを選択し、そこに「.py」ファイルを追加します。
5.「Terminal」-「New Terminal」
6.次のコマンドを入力します。
**pip install Spire.Doc**
## コード：
### 文書全体を挿入する
この方法では、完全なドキュメントを挿入することで複数のドキュメントがマージされます。
まず、**Document**インスタンスを作成して、Sample1をロードします。 次に、**Document.insertTextFromFile(fileName:str,fileFormat:'FileFormat')** メソッドを呼び出して、Sample1にSample2を挿入します。 最後に、結果ドキュメントを保存します。
```python
from spire.doc import *
from spire.doc.common import *

# Documentクラスのオブジェクトを作成し、Word文書を読み込みます
doc = Document()
doc.LoadFromFile("Sample1.docx")

# 別の Word 文書のコンテンツをこの文書に挿入します
doc.InsertTextFromFile("Sample2.docx", FileFormat.Auto)

# 結果ドキュメントを保存します
doc.SaveToFile("output/InsertDocuments.docx")
doc.Close()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2811193/6807e5c3-e82e-54f9-beb0-d46951dbe390.png)
### 文書のコンテンツのみを結合する
まず、**Document**インスタンスを作成し、2 つのサンプル文書をロードします。 次に、Sample2のすべてのセクションのサブオブジェクトをループします。 そして、これらのサブオブジェクトをSample1の最後のセクションに追加します。 最後に、結果ドキュメントを保存します。
```python
from spire.doc import *
from spire.doc.common import *

# Document クラスのオブジェクトを 作成し、2 つの Word 文書をロードします
doc1 = Document()
doc1.LoadFromFile("Sample1.docx")
doc2 = Document()
doc2.LoadFromFile("Sample2.docx")

# Sample1の最後のセクションを取得します
lastSection = doc1.Sections.get_Item(doc1.Sections.Count - 1)

# Sample2のセクションをループします
for i in range(doc2.Sections.Count):
    section = doc2.Sections.get_Item(i)

    # セクション内のサブオブジェクトをループします
    for j in range(section.Body.ChildObjects.Count):
        obj = section.Body.ChildObjects.get_Item(j)

        # Sample2のサブオブジェクトをSample1の最後のセクションに追加します
        lastSection.Body.ChildObjects.Add(obj.Clone())

# 結果ドキュメントを保存します
doc1.SaveToFile("output/MergeByCloning.docx")
doc1.Close()
doc2.Close()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2811193/e09b3b65-1154-0e45-d1f7-c79625ab68b8.png)