OmniAICreator/Qiita-1.07M huggingface dataset:
引数sigvalのポインタを参照しようとするとコアダンプする

（備忘録）

### 現象

LINUXでタイマーを実装するため、下記のようにtimer_create()を使用しタイムアウト関数を設定した。
（タイムアウト時にtimer_callback()をコールし、その中でタイマを継続するかの判定等と、test_function()のコールを行いたい）

```c
    // 自作タイマ管理用構造体
    struct timer_member member =
    {
        .id = timer_1;
        .function = &test_function, // 最終的に呼びたい関数
        .repeat_flg = true,
    };

    // イベントを設定
    struct sigevent sev = {
        .sigev_notify = SIGEV_THREAD,
        .sigev_value.sival_ptr = &member,
        .sigev_value.sival_int = 0,
        .sigev_notify_function = &timer_callback,
        .sigev_notify_attributes = 0,
        // .sigev_notify_thread_id = 0,
    };

    // タイマーを作成
    timer_create(CLOCK_REALTIME, &sev, &id);
```

timer_callback()はコールされるのが確認できたが、
下記コメントのタイミングでコアダンプしてしまっていた。
```c
// タイマタイムアウトコールバック
void process_timer_callback(union sigval value)
{
    int posi = value.sival_int;
    struct timer_member member = *(struct timer_member*)value.sival_ptr;

    // 関数をコール
    member.function(); // +-- ここでコアダンプ発生 --+

    // 繰り返ししない場合
    if (member.repeat_flg == false)
    {
        timer_delete(member.id);
        member.function = NULL;
        member.repeat_flg = false;
    }
}
```

### 結論
原因は[これ](https://stackoverflow.com/questions/51130245/sigevent-sival-ptr-segmentation-fault)
使用しようとしていたsigevent構造体の.sigev_value（sigval）は[union型](http://www.itsenka.com/contents/development/c/union.html)の為、下記のタイミングでポインタが上書きされていただけだった。
```c
    struct sigevent sev = {
        .sigev_notify = SIGEV_THREAD,
        .sigev_value.sival_ptr = &member,        // ポインタ設定
        .sigev_value.sival_int = 0,              // ここで.sival_ptrを上書きしてしまっている
        .sigev_notify_function = &timer_callback,
        .sigev_notify_attributes = 0,
        // .sigev_notify_thread_id = 0,
    };
```

### 解決策
.sival_intへの代入の個所をコメントアウトした
```c
    struct sigevent sev = {
        .sigev_notify = SIGEV_THREAD,
        .sigev_value.sival_ptr = &member,        // ポインタ設定
        // .sigev_value.sival_int = 0,
        .sigev_notify_function = &timer_callback,
        .sigev_notify_attributes = 0,
        // .sigev_notify_thread_id = 0,
    };
```

### 備考
sigeventについて

https://linuxjm.osdn.jp/html/LDP_man-pages/man7/sigevent.7.html

timer_create()について

https://man7.org/linux/man-pages/man2/timer_create.2.html


https://linuxjm.osdn.jp/html/LDP_man-pages/man2/timerfd_create.2.html
nvim + vim-plug でAn unknown element "" was received. This can happen if the remote process closed or ended abnormally.

備忘録なので簡単に。
# 使用環境
` PowerShell 7.2.6 `
` nvim (NVIM v0.9.0-dev-71-gd9a80b8e2) `
` → NVIM v0.7.0`でも発生
`vim-plug`

未確認ですがこれ以外の環境でも発生する可能性があります。

# 問題
PlugUpdateをすると、以下のようなエラーが発生してアップデートが失敗する。
```
An unknown element "" was received. This can happen if the remote process closed or ended abnormally.
```

# 原因と解決策
根本的な原因は不明ですが、nvim+vim-plugでshell=powershellやpwshにしていると発生する・・・？
ShellをPowerShellにしていたので、それを外すと一応大丈夫になるっぽい？
PowerShellが使えなくななりますが・・・。

あまり時間かけてられないので、とりあえずShellをPowerShellからデフォルトを使うように変更しました。
原因等まだはっきりしてないのですが、治せるなら後でパッチ作成してプルリク送りたいです。（nvim?vim-plug?どっちだろう・・・）
私のinit.vimではvim用のvimrcと共用なので以下のようにnvimではpwshに設定されないようにした。
```vimscript:initi.vim
if has('win32') && !has('nvim') "Windows
    if executable('pwsh')
        set shell=pwsh
    elseif executable('powershell')
        set shell=powershell
    endif
endif
```

# 参考
https://www.reddit.com/r/neovim/comments/gbb2g3/wierd_vimplug_error_messages/
ITエンジニアを採用しよう～人が先？制度が先？問題～

シリーズ：最近のトレンドで「セキュリティ強化」や「内製化」が挙げられます。私の会社のようにIT会社ではない会社がどうやってIT人材を集めるのかを考えていきたいと思います。
※私の個人的意見です。

## 鶏が先か、卵が先か
　弊社でぶつかっている大きな壁です。

　ある方は「**人をそろえてチームを作ってからだ！**」

　別のある方は「**いやいや、制度を整えないとその人が来ないだろう！**」

　なんてやり取りをしています。個人的には後者派です。
　前回の求人票の話でも書きましたが、魅力的な求人票は(人気のある)良い待遇が載っています。先に制度ができれば人もおのずと集まってくるという意見です。

## 制度を先に整えることは可能なのか
　ここで、「そもそも人がいないのに制度を整えることは可能なのか」について考える必要があります。
　
　前提として、どういうチームを作りたい。こうしていきたいというビジョンはあるはずです。
　
　しかし、**どんな人が、どんなモチベーションで仕事をしたいのか**はチームができないと分からないことです。

　例えば、「**週40時間自由に働けます！**」という制度が先にあった場合、MTGが多いチームだったらどうでしょうか。
　「MTGの時間が合わせにくい」「コアタイムがないと全員が集まらない」と不具合が生じます。

## 制度の線引き
　上記の例はあくまで一例なので、給与面など予め設定できるものやチーム単位で勝手に決めてもよいルールもあります。
　どこまで許容するかなど考え出したらキリがないですが、最近流行りの制度は一つでも取り入れておいた方がよいです。(そもそも導入できる柔軟性が欲しいですが)
　そこをうまいこと「***決めておく***」と「***作り上げる***」の2つを提示し、同じ志を持った人と仕事ができるとハッピーパターンです。

## どっちも同じくらいのぱわ～で
　四の五の言う前に手を動かしましょう。考えることも悪いことではないですが、考えすぎはよくないです。
　「ある程度」方針固めて求人票を出しつつ、「よしなに」制度を整えていきましょう。
　最近はそのぐらいが丁度良い気がしてます。


一旦この採用シリーズの前段は以上です。
次は実際に面接やらイベントの様子などを書いていこうと思います。

https://qiita.com/Waddy675/items/d394698fd0810835a135

https://qiita.com/Waddy675/items/bdfceda843f909831bdb
Android開発でRetrofit2初心者がつまずいたところ

# Android開発初心者がRetorofit2でつまずいたところ
## 結論
エンドポイントの指定の仕方が間違っていた

## 状況
Retrofit2のPUTメソッドで処理を実行したら文字列を返すように実装したが、なぜか404が返ってくる

## 解決策
指定したエンドポイント文頭の/を削除した

```変更前hoge.kt
@PUT("/fuga/{fugi}")
    fun func(
        @Path("fugi")
    ):Call<Unit>
```

```変更後hoge.kt
@PUT("fuga/{fugi}")
    fun func(
        @Path("fugi")
    ):Call<Unit>
```

## まとめ
どこが違うのか見つけるのに3時間くらいかけてエンドポイントの指定方法が違っていることに気づいた。同じようにつまずいている人の解決につながってほしいのと、自分の備忘録としてqiitaに残しておくことにする。
英文の数学問題「2022京都府立大学推薦生命環境学部総合問題【４】問２」をDeepL翻訳してみた。

実行例1,実行例2があります。


オリジナル

https://mathexamtest.web.fc2.com/2022/202211546/2022115460200mj.html#s-0202

deepl翻訳サイト

https://www.deepl.com/ja/translator


# 実行例1

問２　Five fair coins are tossed. What is the probability that exactly three heads and two tails turn up?

上の英文に日本語で答えなさい．



↓

問2 公正なコイン5枚を投げる。3枚の表と2枚の裏が出る確率は何％か？

上の英文に日本語で答えなさい。



# 実行例2

Five fair coins are tossed. What is the probability that exactly three heads and two tails turn up?

↓

5枚の公平なコインを投げる。ちょうど3枚の表と2枚の裏が出る確率は？
networkxで重み付きグラフを描画する方法

# はじめに

networkxはネットワークの処理には便利ですが、頂点の位置決め (レイアウト) はあまり上手ではないため、通常は他のツールを併用することが多いと思います。以下ではnetworkxだけで枝の重みに応じた頂点配置を持つグラフを描画する方法の一つを説明します。

ポイントは、枝に'weight'という名前の属性を付けることです。負の値があっても構いません。

# 主な手順

以下では重み行列Wが既にあると仮定して説明します。

1. networkxのGraphオブジェクトを作ります。
    ```Python
    G = nx.Graph()
    ```
2. Gに枝を追加します。属性名は'weight'として下さい。枝を追加すれば頂点も一緒に追加されます。
   ```Python
    for i, j in zip(*np.triu_indices_from(W, 1)):
        G.add_edge(i, j, weight=W[i,j])
    ```
3. ネットワークを描画します。枝の重みに応じて枝の色を変えたい場合は、edge_colorオプションに重みの配列を入れて下さい。重みの配列は`nx.get_edge_attributes()`関数で取得できます。
    ```Python
    weights = nx.get_edge_attributes(G, 'weight').values()
    nx.draw_networkx(G, edge_color = weights)
    ```

# スタイルの調整

`nx.draw_networkx()`のオプションでスタイルを適宜調整して下さい。一部紛らわしい名前のものもあります。

| 名前 | 意味 |
|--|--|
|node_size|頂点の大きさ|
|node_color|頂点の色|
|edgecolors|頂点の輪郭の色 (枝の色ではない)|
|linewidths|頂点の輪郭の線の太さ (枝の太さではない)|
|with_labels|頂点のラベルを書くかどうか|
|font_size|フォントの大きさ|
|font_color|フォントの色|
|edge_color|枝の色、または、枝の重みの数値が並んだ配列|
|edge_cmap|枝の色のカラーマップ|
|width|枝の太さ|


# サンプルコード

以下はサンプルコードです。重み行列は適当に作った人工データの相関行列としました。
```Python
import numpy as np
import pandas as pd
import networkx as nx
import matplotlib.pyplot as plt
import seaborn as sns

def plot_weighted_network():

  # generate a sample weight matrix
  n1 = 10
  n2 = 20
  n = n1 + n2
  np.random.seed(12345)
  X  = np.random.randn(n, 20)
  v = 0.6 * X[0]
  X[:n1] += v
  X[n1:] -= v
  W = np.corrcoef(X)

  # plot heatmap
  fig, (ax,ax2) = plt.subplots(figsize=(8,4), ncols=2)
  sns.heatmap(W, cmap='RdBu_r', ax=ax)
  ax.set_aspect('equal')


  # ---------- draw weighted network ----------

  # Step 1: generate a 'Graph' object
  G = nx.Graph()

  # Step 2: add edges to G
  for i, j in zip(*np.triu_indices_from(W, 1)):
    G.add_edge(i, j, weight=W[i,j])

  # Step 3: draw network
  weights = nx.get_edge_attributes(G, 'weight').values()
  np.random.seed(12345)
  nx.draw_networkx(G,
                   node_size = 150,
                   node_color = 'w',
                   edgecolors = 'k', # node border color
                   linewidths = 1, # node border width
                   with_labels = True,
                   font_size = 8,
                   font_color = 'k',
                   edge_color = weights,
                   edge_cmap = plt.cm.RdBu_r,
                   edge_vmin = -1,
                   edge_vmax = 1,
                   width = 0.5, # edge width
                   ax = ax2)

  # show
  fig.tight_layout()
  fig.show()
  fig.savefig('tmp.png')

if __name__ == '__main__':
  plot_weighted_network()
```

# 出力例

![fig_weighted_network.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2787764/42bee14e-5d4b-79d1-f78f-fb56bc95b9e2.png)

正の結合をしている頂点同士が近くに配置され、負の結合をしている頂点同士は遠くに配置されました。非負重みの場合も同様で、強い結合では近く、弱い結合では遠くに配置されます。

alpha (透過度) は設定していませんが、枝を細くすると同様の効果が得られるようです。

問題点としては、一部の頂点の位置が近過ぎてラベルが読めなくなっていることが挙げられます。また、上側のグループが横方向に広がり過ぎており、本来のネットワークコミュニティ構造がやや分かりづらくなっています。

# おわりに

やはりnetworkxでは限界があるようですので、きちんとした図を作りたい場合はCytoscapeやpyvisを使った方が良いと思います。あまり時間をかけずに重み付きグラフを視覚化したい場合に利用して下さい。
日々意識したいコミュニケーションについて

# はじめに
エンジニアって意外とコミュニケーション能力は必須ですよね。
個人的に人に教える場面も増えてきて、考え直す機会があったので簡単にまとめてみました。
（今回は主に社内向けのコミュニケーションを書いています）

# 目次
1．コミュニケーション能力とは
　1-1　伝える力
　1-2　聞く力
　1-3　非言語コミュニケーション能力
2．対面時に気を付ける事
3．テレワーク時に気を付ける事
4．まとめ

# 1．コミュニケーション能力とは
「対人間での情報共有や意思の疎通」のことであり、コミュニケーション能力は、それらををスムーズに行うことができる力のことです。
また、ざっくり大きく分けて、「伝える力」「聞く力」「非言語コミュニケーション能力」の3つに分けられます。

## 1-1　伝える力
「書く」「話す」などの手段を用いて、自分の伝えたいことを相手に「正確に」「効果的に」伝える力のこと。
単に用件を相手に伝えれば良いわけではなく、*分かりやすく簡潔にまとめて伝える*ことが大切です。
「結局何が知りたいの？」「で、どうしてほしいの？」とならないように、知りたい事ややってほしい事をまず最初に挙げ、その後に必要な情報を箇条書き等出来る限り簡潔にまとめて伝えると、相手に伝わりやすくなるのと同時に、自分の中でも整理しやすくなります。

## 1-2　聞く力
「読む」「書く」などの手段を用いて、相手が伝えたいことや相手の意図を理解する力のこと。
相手からの情報や意見、提案などを受け取るだけでなく、相手の立場になって考えたり、その内容をくみ取る為にこちらから質問をする等して*理解を深める*ことも大切です。
例えば、相手からの依頼がざっくりしていた場合、必要な情報をこちらから聞き出し、認識に相違が無いようにすることで、後々無駄な時間を割くことや問題の発生を防ぐことができます。

## 1-3　非言語コミュニケーション能力
字の通り言語に頼らないコミュニケーションで、表情や声のトーン、話す速度やジェスチャー等のこと。
特に対面の時などはこの非言語コミュニケーションも相手へ情報を伝えるためには重要かと思います。

# 2．対面時に気を付ける事
対面の場合は、全て言葉だけで説明すると相手に伝わりにくかったり、後々内容を失念してしまう可能性も考えられるため、事前にメールやチャットでも内容を送ったり資料としてまとめておくと良いでしょう。（エビデンスにもなります）
また、お互いの顔が見えることもあり、相槌を打ったり表情を意識することも大切です。

# 3．テレワーク時に気を付ける事
TeamsやSlack等のチャットツールでのやりとりが多いかと思います。
文章では冷たい印象を与えやすくなってしまうため、時には感情を言葉にして伝えたり記号を用いると柔らかい印象にもなります。
自分が伝える側の場合は、主語を付けたり改行や句読点をうまく使い読みやすさを意識すると良いでしょう。

# 4．まとめ
その他にも、声をかけるタイミングを意識したり、相手の気持ちを汲み取ったり、コミュニケーションって奥が深いですね…！
伝える側、聞く側、どちらの立場になっても相手への思いやりが大事だなとまとめていて感じました。
Power Query workout - Excel workbook

Power Query を介して Excel ワークシート上のデータを取得できる値は、ワークシート上で確認できる値と異なることはよくあること。Excel ワークブックをデータソースとして利用するなら、これを当然踏まえた上でデータとして利用すべきだと思う。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193509/35db0626-4920-a019-9096-c25c23b61a5d.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/193509/2ec81924-eea3-1a43-0ec1-b11fbeabb614.png)

データモデルにそのままロードした場合、
```text
EVALUATE
GROUPBY(
	Table1,
	Table1[Column1],
	"Count", SUMX( CURRENTGROUP(), 1 )
)
```
|Column1|Count|
|--:|--:|
|1763.8600000000001|1|
|1763.86|1|
|110|1|
|110.00000000000001|1|
|0.30000000000000004|1|
|0.3|1|

# 思ったこと🙄
人が手に触れた時間が長ければ長いほど、信頼性が低下するデータソースだと考えている。Power Query で ユーザによる手作業を制御できないから、こういうこともあるっていう前提でロジックを考えておけばよい。
なんども言ってるけど、Excel で Power Query を利用できるけど、Power Query は Excel じゃぁないですからね🤪

# その他
https://powerbi.connpass.com/

- [Power BI 勉強会 - connpass](https://powerbi.connpass.com/)
- [Power BI Desktop を使い始めるには](http://qiita.com/PowerBIxyz/items/6c4735cb5b5712e70981)
- [Excel で Power Query を使い始めるには](http://qiita.com/PowerBIxyz/items/52e563037b855a099ca9)
【Dreamweaver】ワークスペースを極限までスッキリさせる（Mac）

こんにちは。E-kan株式会社の岡田です。

特定の業務で月に２回だけDreamweaverを使うのですが、先日PCを移行して新しくセットアップした際にワークスペースのカスタマイズを忘れて地味に苦労したので備忘録。

## やりたいこと
デフォルトで表示されている以下の要素を消したい
- 関連ファイルツールバー
- 一般メニューバー
- 右パネル

![スクリーンショット 2022-10-13 15.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2656687/d52cf4c0-612d-903b-7df6-c2744113696d.png)

### 「一般メニューバー」「右パネル」の消し方
この内の「一般メニューバー」は、上部メニューの「ウィンドウ　＞　ツールバー　＞　一般」で消え、「右パネル」は各パネル右上の「≡」内の「タブグループを閉じる」で消せますが、「関連ファイルツールバー」がどこで消せるのか分からず、調べ回ること数十分（そもそも関連ファイルツールバーという名称も今回初めて知った）。
環境設定から消せるとのこと。

### 「関連ファイルツールバー」の消し方
上部メニュー、から「環境設定」を選択。
![スクリーンショット 2022-10-13 15.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2656687/730c2e1a-3450-a73d-1894-a3c65d45385c.png)

左カテゴリ「一般」から「関連ファイルを有効にする」のチェックを外し、「適用」してからアプリを再起動。
![スクリーンショット 2022-10-13 15.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2656687/db220b57-e8d9-cea0-3e80-1bfe205f901c.png)

ファイルメニューとか表示されていないと不便って場合は、右パネルから切り離した後に最小化したアイコンをウィンドウ右端にドラッグすると吸着してくれ、クリックした時だけ表示されるようになります。

これでワークスペースがめちゃくちゃすっきりしました。
![スクリーンショット 2022-10-13 15.55.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2656687/40ff815b-e791-a04c-b222-68ee05f3637f.png)
GitHubで他の人に書き込み権限を付与する方法

自分の作成したリポジトリへ他の人が書き込み権限を付与するやり方の説明

歯車のマークの【Setting】から【Collaborators】を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/330568/e7095f4e-92d1-3db7-bd20-9cd914d1a1b0.png)

【Add people】から追加したい人を選択する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/330568/fdf9a4ef-4202-5b7e-e924-4d783f079eec.png)

これで終わり

最近UIが変わったのかManage accessがGeneral配下にある記事しかヒットしなくてちょっと迷った
なので情報として残しておく
Salesforce上級アドミニストレーター試験の公式サンプル問題解説してみた-02


こんにちは
本橋孝昭です


今回の内容は動画でも解説しています

https://www.youtube.com/watch?v=mSmuSIgvEms

<iframe width="560" height="315" src="https://www.youtube.com/embed/mSmuSIgvEms" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>


Salesforce上級アドミニストレーター試験の公式サンプル問題があるのはご存じでしょうか

こちらの受験ガイドからサンプル問題を確認することが可能です

https://quip.com/dyBMAO1z6pJ9/SALESFORCE-

https://tandc.salesforce.com/credentials



今回は
Salesforce上級アドミニストレーター試験の公式サンプル問題2問目をご紹介します

なお、
以下の問題は、Salesforce 認定上級アドミニストレーター試験のサンプル問題です。問題はあく まで出題形式に慣れていただくためのものであり、試験に合格するかどうかを判断するための問題ではありません。実際の問題の難易度は、以下のサンプル問題とは異なる場合があります。

と書いてありますのでご確認ください

問題はこちらです


2） 
営業担当者が、見積を関連する商談に同期しようとして問題が発生したと報告しています。 
どのような理由が考えられますか？答えを 2 つ選んでください。

A.  添付されている通貨が現在有効ではない 
B.  見積にアーカイブ済みのリスト価格が含まれている 
C.  見積が完了した商談に添付されている 
D.  ユーザに見積に対する編集権限がない 


正解はAとBです




見積同期のトラブルシューティングがありますのでご確認ください



SALESFORCE ヘルプ
ドキュメント
SALES CLOUD の基本
見積の同期のトラブルシューティング

https://help.salesforce.com/s/articleView?id=sf.quotes_sync_troubleshooting.htm&language=ja&r=https%3A%2F%2Fwww.google.com%2F&type=5
sortを使って、連想配列の特定のオブジェクトを最後にする

### やりたいこと
オブジェクトの配列で、特定のキーを参照して、`'-1'`だったら最後に並び替えたい。
それ以外の順序は保持。

いろいろ調べたけど、全体的に並べ替えて、昇順降順にするというのばかりで、
`特定の値を場合だけ抽出して先頭や最後に回す`という処理をsortでやっているものが見当たりませんでした。

一回抽出して、push とか unshiftとかすればいいかもしれませんが、sortでもできるだろうと思っていろいろ試して一応できました。

いろんなパターンで試したりしていないので、動作保証はできません。
とりあえず以下のような例ではうまく行きました。

逆にいい方法をご存知の方がいましたら教えてください！！

### 実際のコード
```javascript:並び替えのコード
// 真ん中にある、-1だけ最後にしたい
const fix = [
    {id: 'A00', name: '名前1'},
    {id: '-1', name: '最後にしたい'},
    {id: 'A01', name: '名前2'},
    ];
fix.sort((a,b) => {
    if(b.id === '-1') return -1;
    if(a.id === '-1') return 1;
    return 0;
});
console.log(fix)
```

```console:出力結果
[
  { id: 'A00', name: '名前1' },
  { id: 'A01', name: '名前2' },
  { id: '-1', name: '最後にしたい' } // こんな感じで、これだけ最後に回したかった
]
```

### 詰まった箇所

```javascript

fix.sort((a,b) => {
    if(b.id === '-1') return -1;
    if(a.id === '-1') return 1;
    return 0;
});
```

`if(b.id === '-1') return -1;`で、ずっと`if(a.id === '-1') return -1;`というふうにしていましたが、これではダメ。
~~理由はわかりません！！~~

~~いまでも、aの方じゃないのかと思っていますが、アルゴリズムをちゃんと理解したらわかる・・・？~~

~~わかる方教えてください。。。~~

#### a,bは隣接する要素だとは限らない
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
> 生成される配列はエンジンによって異なります。例えば、V8（Chrome、Node.js などで使用）や JavaScriptCore（Safari で使用）は配列を全くソートせず、 [3, 1, 4, 1, 5, 9] を返しますが、SpiderMonkey（Firefox で使用）は [1, 1, 3, 4, 5, 9] のように昇順に並べた配列を返すことになります。

要はブラウザとかのjavascriptの動作環境によって、ソートアルゴリズムが異なる。

・バブルソート
・クイックソート
・マージソート

などの種類があるが、エンジンによって違うようです。

なので、**a,bは、配列のある位置の前の要素、後ろの要素**という考えていると一生正しく理解できない。

#### 押さえるべきこと
* a,bは比較したい要素（隣接と限らない、前後関係もない）
* -1を返す場合は、 a,bにする
* 1を返す場合は、b,aにする
* 0を返す場合はそのまま

ここで、a,bが配列のどの要素の位置はアルゴリズムに依存するので、前後関係も配列要素順とは限らないし、隣接するとも限らない。とにかく、比較対象として抽出された二つの要素同士の順序をどう並べ替えるかの指定を、正負０で指定してやる必要がある。

より詳しくはソートアルゴリズム自体の理解をする必要があるが、そこまでは触れないでおく。
（奥が深い...）

### 実装上の注意
#### 守るべき5つの制約
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#%E8%A7%A3%E8%AA%AC
こちらの`解説`の部分から引用↓↓

>* 無害: 比較関数は比較されるオブジェクトや外部の状態を変更しません。（これは重要です。比較関数がいつ、どのように呼び出されるかは保証されていないので、特定の呼び出しが外部に見える影響を及ぼしてはいけません）。
>* 安定的: 比較関数は、同じ組の入力に対して常に同じ結果を返します。
>* 反射的: compareFn(a, a) === 0 となります。
>* 反対称的: compareFn(a, b) と compareFn(b, a) はともに 0 であるか、逆の符号でなければなりません。
>* 推移的: compareFn(a, b) と compareFn(b, c) がともに正、0、負のいずれかであれば、 compareFn(a, c) は前の 2 つと同じ符号になります。

特に
```
return a > b ? -1 : 0
```

という実装はやりたくなるけど気をつけないといけない。
これが`反対照的`になっていないため、安定性が保証されない。
なので、-1, 1を返すパターンはちゃんと対照的にいずれの記述も漏れてはいけない。

#### sortはミュータブル
sortは元の配列を変更してしまうのでミュータブル。
基本的にミュータブルな実装は避けるべきなので、コピーしてから使うとよい。

```
[...array].sort() //シャローコピー
structuredClone(array).sort() // ディープコピー
```

など。
RaspberryPiにSoftEtherでVPN接続

# SoftEtherでのVPN接続を実現する忘備録

## 前提
今回はSoftEtherを使って、一般的なリモートアクセスVPNを実現する。
VPN Serverに仮想HUBを作成、ローカルブリッジ接続でVPN内のLANとリモートアクセス可能な環境を構築した。　
　・リモートLANは1つでIPルーティングは使用しない
　・VPN Server とクライアントはNATがある

##### Raspi側(Server）
　・グローバルIPアドレス・ドメインを使用しないために、ダイナミックDNS機能を使用。
　・ネットワーク管理はNetworkManagerを使用。

## 環境
Server：RappberryPi4（Debian 10）／　Client：Windows 11

## インストール
https://www.softether-download.com/ja.aspx?product=softether

https://ja.softether.org/4-docs/1-manual/7/7.3

#### [VPN Server のインストール]

**注意**
・Debian用のVPNServer起動デーモンを作成・登録 
　　[/etc/systemd/system/vpnserver.service] 
    
    [Unit]
    Description=SoftEther VPN Server
    After=network-online.target

    [Service]
    Type=forking
    ExecStart=/usr/local/vpnserver/vpnserver start
    ExecStop=/usr/local/vpnserver/vpnserver stop

    [Install]
    WantedBy=multi-user.target

#### [VPN管理アプリケーションのインストール]
**条件（Server）：** 
　SoftwareVPN(Freeware) , Software VPN Server , Linux, ARM EABI(32bit)
**条件（Client）：**
　SoftwareVPN(Freeware) , Software VPN Client, Windows
　（※Windows 標準のVPN接続機能を使う場合は必要無し）


# 設定
### L2TPの有効化
今回は[L2TP over IPsec、EtherIP over IPsec] を使用するためにルータのフォワーディング・マッピングを以下で設定する

　　[UDPポート]　500, 4500
 
https://ja.softether.org/4-docs/2-howto/L2TP_IPsec_Setup_Guide/1

### 仮想HUB
https://ja.softether.org/4-docs/1-manual/3/3.4

### ローカルブリッジ
・今回はローカルブリッジ用の物理LANカードは使用せず（LANカード1枚のみ）仮想的なTapデバイスを作成しローカルブリッジに使用した。
ローカルブリッジを作成する前に以下でNetworkManagerでtabデバイスの登録を行う。
    
    nmcli c add type bridge ifname br0
    nmcli con modify bridge-br0 bridge.stp.no
    nmcli con modify bridge-br0 ipv4.method manual ipv4.addresses xxxx ipv4.gateway xxxx ipv4 dns xxxx
    nmcli con add type bridge-slave ifname eth0 master bridge-br0
    nmcli c del eth0
    reboot

    brctl show
      ⇒　ブリッジ接続状態を確認しbr0がeth0に設定されていればOK。

以下で上記で作成したserverのtabデバイスと仮想HUBをブリッジ接続する。
（※新しいtabデバイスとのブリッジ接続を選択）
設定終了後、server内で[nmcli device] 確認で上記tap_xxxが追加されていればOK。

https://ja.softether.org/4-docs/1-manual/3/3.6

また、VPN Server 起動時にtapデバイスを自動で追加するために 最初に作成したvpnserver.serviceに以下のシェルを追加する。
設定終了後、server内で[brctl show] 確認でブリッジに上記tap_xxxが追加されていればOK。

>引用


    #!/bin/bash
    
    sleep 5
    tap_dev=`/sbin/ip tuntap | awk -F: '{print $1}'`
    if [ -n "$tap_dev" ]; then
        /sbin/brctl addif br0 $tap_dev
    fi

※注意
・ExecStart 項目の[vpnserver start]を変更し以下を含めたバッチを作成し指定した
・作成したshも実行権（chmod +x）を追加することを忘れずに・・

# 結果
遠隔（または別インターネットより）VPNクライアントまたはWindows標準のVPN接続ツールで上記で取得したダイナミックDNSのドメインにアクセスし接続できればOK。

# 考察
今回は最もシンプルなネットワーク環境で実験しました。
それでもローカルブリッジ設定には特に注意が必要、ちょっとしたミスでLANが無限ループを起こすなどネットワーク全体が全く機能しないという恐怖の状態にもなってしまった。
このように実環境のネットワーク環境によって様々な注意点や設定事項が発生するので実環境で利用するためには単にマニュアルに沿って設定するだけでなく、SoftEtherがL2TPなどVPN接続がどのように実現されているかなど回り道でも根本的な理解から始めた方が良さそう。
SoftEtherプロジェクトのドキュメントが非常に簡潔で分かりやすいものなのでまず一通り目を通すことで理解が深まるかなと。
高価なVPN用のルータや固定IPアドレスなど利用しないでここまで簡単にセキュアなVPN環境がソフトウェアで実現できるという素晴らしいプロジェクトだと思いました。

### 参考文献

- [SoftEther VPN プロジェクト]　https://ja.softether.org/
- [VPNサーバー構築(SoftEther VPN Server)] https://centossrv.com/softethervpnserver.shtml
- [Create bridge and add TUN/TAP device using NetworkManager nmcli under CentOS 8] https://ahelpme.com/linux/centos-8/create-bridge-and-add-tun-tap-device-using-networkmanager-nmcli-under-centos-8/
[GAS] 簡単になったGAS実行環境のタイムゾーン設定

# はじめに
主にカレンダーやGmailと連携するプロジェクトにおいて、`Date`関連の処理を行った場合、意図した結果を得られない事がありました。原因はGASプロジェクトにデフォルト設定されているタイムゾーンの影響を受けるためでした。

GASプロジェクトのタイムゾーンを日本時間（実行環境のタイムゾーン）に変更することで回避できるのですが、以前までは**マニュフェストファイル（`appsscript.json`）** を開いて編集する必要がありました。

執筆時現在では、スクリプトエディタの **プロジェクトの設定** より、プルダウンにて簡単に設定変更ができるようになり、合わせてスクリプトプロパティの編集もできるようになっています。

> April 13, 2022\
> You can now perform the following actions in the new Apps Script integrated development environment (IDE):
> 
> Create test deployments for Editor Add-ons.\
> Add, edit, and delete script properties from the project settings page.\
> Sort files alphabetically in the editor.\
> Debug Rhino functions without migrating to the V8 runtime. If your code isn't V8 compatible, you might receive errors.\
> Set the time zone for a script project.

# タイムゾーンの変更手順
[2022年4月の機能追加](https://developers.google.com/apps-script/guides/projects#set_the_time_zone_for_a_project)まではアメリカのニューヨーク時間になっている事がほとんどでしたが、現在はLocale設定に準じていると思いますので、基本的には変更する必要はないと思います。`Date`関連の処理を行うプロジェクトの場合は、念のため確認しておきましょう。

## 1. スクリプトエディタよりプロジェクトの設定画面を開く
左側のメニューより、ギアのアイコン（プロジェクトの設定）をクリック。

![set_locale01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1111613/cecd144b-2f76-8b74-29bb-feacfebb43b4.png)

## 2. タイムゾーンを変更する
初期状態で日本時間が選択されていると思いますが、別のタイムゾーンが選択されていた場合など、 **(GMT+09:00) 日本標準時 – 東京** を選択して日本時間に合わせましょう。

※実行環境によっては他のタイムゾーンに設定してください。

![set_locale02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1111613/805d00b4-de75-c75a-5347-7fe87c94d06d.png)

# 最後に
以前より簡単になったタイムゾーン設定の手順ですが、むしろ意識しないで済むようになったと言えます。

とは言うものの、カレンダーやGmail連携のプロジェクトで、なにか結果がおかしいぞ、というときには、プロジェクトの設定にあたりをつけられるよう、頭の片隅には置いておく必要はありますね。

特に古いプロジェクトをコピーして流用しようとした際には注意が必要です。また、スプレッドシートの場合には、スプレッドシート自体の設定も確認してみましょう。[^1]

[^1]: Magicodeからの記事移動後、加筆を行いました。

# [参考・引用]
- [Set the time zone for a project](https://developers.google.com/apps-script/guides/projects#set_the_time_zone_for_a_project)
Rubyで所定の期間内のX曜日の数を計算する

# TL;DR

```rb
# 2022-10-11 ~ 2022-12-13 の間、火曜日の個数を計算する
require 'date' # Rails環境では不要

(Date.parse('2022-10-11')..Date.parse('2022-12-13')).select(&:tuesday?).size
# または
(Date.parse('2022-10-11')..Date.parse('2022-12-13')).select{ |d| d.wday == 2 }.size
=> 10
```

# はじめて
最近はイタリア語講座に参加しました、案内ではこう書いていました。


> 曜日・時間: 火曜日 19:30 ~ 21:00
受講期間: 2022-10-11 ~ 2022-12-13
授業回数: 10回


しかし私は途中参加なので、果たして案内に書かれた期間に１０回の授業が完了できるのか？また、休講があるのか?を懸念していました。
私は算数があんまり得意ではないので、カレンダーで数えてみましたが、なかなか正確な結果出ませんでした。
そこで、Rubyのチカラを借りたいと考えました。

# 解説
Rails環境で解説いたしますが、純Rubyの環境では `require 'date'` でライブラリーを導入すれば同じ結果になります。

## 日付の区間の取得
始まりの日付と終わりの日付を、`..`で[範囲オブジェクト](https://docs.ruby-lang.org/ja/latest/class/Range.html)を作ります。

```rb
(Date.parse('2022-10-11')..Date.parse('2022-12-13'))
=> Tue, 11 Oct 2022..Tue, 13 Dec 2022
```

範囲オブジェクトは一種のイテレーター(iterator)であり、配列と同じように、`.each`や`.map`とかが使えます。ただし、イテレーションを行うまでは展開しません。
どうしても展開したい(配列として扱いたい)場合は、`.to_a`で配列に転換することもできます。

```rb
(Date.parse('2022-10-11')..Date.parse('2022-12-13')).to_a
# または
[*(Date.parse('2022-10-11')..Date.parse('2022-12-13'))]
=> [Tue, 11 Oct 2022,
 Wed, 12 Oct 2022,
 Thu, 13 Oct 2022,
 Fri, 14 Oct 2022,
 ...
```

## 所定の曜日のピックアップ
RubyのDate Classは、インスタンスメソッドで `.monday?` 〜 `.sunday?` が実装されています。所定曜日のメソッドを使うか、`.wday`で数字化した曜日を算出して比較します。

```rb
(Date.parse('2022-10-11')..Date.parse('2022-12-13')).select(&:tuesday?)
# または
(Date.parse('2022-10-11')..Date.parse('2022-12-13')).select{ |d| d.wday == 2 }
=> [Tue, 11 Oct 2022, Tue, 18 Oct 2022, Tue, 25 Oct 2022, Tue, 01 Nov 2022, Tue, 08 Nov 2022, Tue, 15 Nov 2022, Tue, 22 Nov 2022, Tue, 29 Nov 2022, Tue, 06 Dec 2022, Tue, 13 Dec 2022]
```

これで、`.size`をつけば、2022-10-11~2022-12-13の間火曜日は10個あることがわかります。

## `.wday`と`.cwday`の仕様
余談ですが、RubyのDateオブジェクトの曜日番号を取得するには、`.wday`と`.cwday`２つのメソッドがあります。その違いは以下になります。

- `.wday`は**日曜日**をから、**0~6**の数字で表示します(0は日曜日)
- `.cwday`は**月曜日**をから、**1~7**の数字で表示します(7は日曜日)

# 参考
- [範囲オブジェクト](https://docs.ruby-lang.org/ja/latest/class/Range.html)
- [class Enumerator](https://docs.ruby-lang.org/ja/latest/class/Enumerator.html)
- [class Date](https://docs.ruby-lang.org/ja/latest/class/Date.html)
React 子コンポーネントのChildrenから親コンポーネントに変数を返す 備忘録

Reactを触っていて、基本的には子から親に値を返す場合Propsの中からSetterの様な関数を子を呼び出す時にセットするしかないなと思ってましたけど
別の方法もあったので忘れないように記事に起こします。


今までこれしか無いと思ってたやり方
```
const ParentComp = () => {
    const [state, setState] = useState('');
    return <>
        <ChildComp setter={setState} />
        <div>{state}</div>
    </>
}
// ------------------------------
const ChildComp = (props)=>{
    return <input onChange={(e)=>props.setter(e.target.value)}>
}

```


Childrenを介して値を返すやり方
```
const ParentComp = () => {
    return <ChildComp>
        {(test)=>{
            <div>{test}</div>
        }}
    </ChildComp>
}

// ------------------------------
type Props = {
  children(test: any): React.ReactElement<HTMLElement>;
};
const ChildComp: React.FC<Props> = (props) => {
  const testObj = { test: 'test' };
  return <>{props.children(testObj)}</>;
};
```

下のやり方だと何かWrapperのようにChildrenをまとめ上げて、Wrapperの中のロジックで出た変数などをChildrenに入れたい時なんかは利用できると思います。

このやり方の名称みたいなのがあれば有識者の方、教えていただけたらと思います。
CPLEX Optimization StudioのIDEを英語インタフェースで起動する

CPLEX Optimization Studio(COS)のIDEを英語で起動したい場合は、コマンドプロンプトで以下のようにoplide.exeを -nl en_USで起動します。

```cmd:英語インターフェース起動
"C:\Program Files\IBM\ILOG\CPLEX_Studio221\opl\oplide\oplide.exe" -nl en_US
```

以下のように英語インタフェースでCOSのIDEが起動します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/223763/f65952cd-bd0d-5d2c-0c62-7e384a0ac5fd.png)
macOS MontereyでSMBをマウントする

macOS Monterey 12.6でSMBマウントした時のメモ
CPU: M1 MAX

## Finderを使う場合
- Finderを使ってマウントする場合は、「サーバへ接続」で`smb://<アドレス>`を入力すれば可能。
- 起動時に自動的にマウントする場合は、「設定」-> 「ユーザとグループ」-> 「ログイン項目」で`smb://<アドレス>`を入れると可能。

上記の方法では起動時には自動でマウントしてくれるが、スリープから復帰後は手動でマウントしてあげなければならない。

ターミナルからファイルを触るのにも操作性が良くない。
そこで、きちんとマウントポイントを指定してマウントする。

## mountコマンドを使う場合
macではfstabが使えないため、マウントを行うスクリプトを作成しログオン時にこのスクリプトが実行されるようにする。


まず、シェルのpathを確認する
```bash
$ echo $SHELL
/bin/zsh
```
-> 必要に応じてシェルスクリプト1行目(シバン)を書き換えてください

スクリプトの作成
※ スクリプト中にパスワードをハードコードしているため、運用時は必要に応じて環境変数や1passwordを参照するようにしてください。

※ マウントしたいフォルダが日本語の場合はURLエンコードをしてください。
※ zshの場合は配列インデックスは1から始めないと`invalid subscript range`エラーが出る

```bash
$ vim ~/mount-test.sh
```
```~/mount-test.sh
#!/bin/zsh

#== ベタ打ちの場合 ==#
USER="<SMBユーザ名>"
PASSWORD="<SMBユーザパスワード>"
HOST="<SMBサーバIPアドレス>"
#-- ベタ打ちの場合 --#

#== 1passwordを使う場合 ==#
eval $(op siginin)
_user="op://Personal/file_server/username"
_password="op://Personal/file_server/password"
_host="op://Personal/file_server/host/URL"

USER=$(op read ${_user})
PASSWORD=$(op read ${_password})
HOST=$(op read ${_host})
#-- 1passwordを使う場合 --#

# マウントポイント (ルート)
MNT_ROOT="${HOME}/mnt/srv"

# マウントしたいフォルダが複数ある場合は配列を増やしていく
## 例として Shareとdownloads をあげている
# zshの場合はインデックス1から始める
TARGET_ARRAY[1]="Share"
TARGET_ARRAY[2]="downloads"

for target in ${TARGET_ARRAY[@]}
do
    # マウントポイントがなければ作成する
    if [[ ! -d "${MNT_ROOT}/${target}" ]]; then
        echo "create directory: ${MNT_ROOT}/${target}"
        mkdir -p "${MNT_ROOT}/${target}"
    fi
    echo "mount ${MNT_ROOT}/${target}"
    # マウントする
    mount -t smbfs //${USER}:${PASSWORD}@${HOST}/${target}/ ${MNT_ROOT}/${target}/
done
```

実行権限を与える
```bash
$ chmod +x mount-test.sh
```

起動時にスクリプトが実行されるようにする
1. 「設定」 -> 「ユーザとグループ」を開く
2. 「ログイン項目」を開く
3. `+`ボタンを押して、作成したシェルスクリプトを登録する

![スクリーンショット 2022-10-17 11.31.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192800/bc03ea95-8825-b928-a9be-af6a1d741748.png)

再起動してスクリプトが実行、マウントされていればOK
社内に技術調査グループを立ち上げた話

## 要約

HEROZの中井です。  
社内勉強会のための活動として技術調査グループを立ち上げたのでその紹介をすることで、現時点での備忘録だったり知見共有になるかと思い投稿します。３行で言うと  
- 社内勉強会を活性化させたい、もっと深いテーマでもやりたい
- 技術ごとの調査グループを作ってエンジニアはどれかに所属するようにした
- 半年に１度の発表をすることにして活動中

という感じです。

## 背景

弊社では社内勉強会を月一で行っていましたが継続的に行うにあたって以下のような問題というか停滞感が生じていました。  

- 社内勉強会のテーマが集まらない
- 発表者が固定されてしまう
- 知らない人向けになり技術の深い話題について話す機会がない

聴講者が40人くらいには盛況になるのですが、準備の手間をかけつつみんなの前で発表するというハードルを越えて発表してくれるのは慣れた人になりやすく、テーマが集まらなかったり発表者が固定されてるなあと感じていました。  
あとは勉強会がLT的な形になっていって、あるテーマの技術について深く話すという形にならなく、社内のメンバーが持っているいろんな技術領域について深堀できてないなあというのもありました。  

## 技術調査グループ

そこで技術調査グループという集まって定期的に話したり調査するグループを作って、勉強会で調べた内容を発表してもらう仕組みを作りました。  

### 目的
技術調査グループの目的としては  

- 最新技術のキャッチアップ
- 活動を通しての技術共有
- 調査結果を社外に公表することにより業界でのプレゼンス向上

としました。HEROZとして技術を調査・共有しながら各自のレベルアップを図りつつ公開することで業界の役にも立てたらなと。  

### 活動内容

活動の内容としては

- エンジニアは全員どれかのチームに参加
- 最新技術を調査して発表(基本的には半年に1度は発表してほしい)
- 技術を試行してみて実例作成もしたい
- 発表内容をブログなどにアップ
- 活動頻度は任せる(月1, 2回集まるグループが多い)
- 興味によってチームは変更可能、半年に一度全体として取りまとめ

としました。交流だったり専門の作成のため基本的に全員どれかには所属することとしました。
半年に1度の発表を目標としているのは、発表をする機会を作ることで調査した内容をまとめるというモチベーションになるという考えからです。  
単純に集まって話すだけでも社内の情報共有としては効果はありますが、それでもより深い知見のためには発表も大事だと感じます。  
定期的に興味のあるグループに移動することもありとの考えです。大きく取りまとめしなおしたほうが移動しやすいかなと。

## グループ例

どんなグループを作るかはアンケートを取って決めました。どこに入るかも同時に決めてます。
各チーム1人より複数人だと安定感あっていいかなとは思いますが、希望もあるので1人グループも存在してます。  
  
画像、自然言語、強化学習、最適化・探索、テーブルデータ、3DCAD、インフラ(全社横断)、DevOps, MLOps、Web3.0(4.0, 5.0)、Webフロントエンド、Rust、クラウドGPU..etc

## 今後

今月から各グループ発表を始めていく予定です。  
うまく回るか不安ですが、みんなの協力のもとうまく進めて行けたらなあという感じです。
oplrunコマンドでCPLEXのmodファイルを実行する

CPLEXのoplプログラムはCPLEX Optimization Studio(COS)のIDEで開発、テスト実行することが多いと思いますが、自動実行はoplrunというコマンドで行うことができます。

ここでは以下の記事でも紹介されているproductionのサンプルを実行してみます。

CPLEX Optimization Studioのチュートリアルで最適化を体験してみる - Qiita 

https://qiita.com/ttsuzuku/items/a8f3a45aef72d50dc55b

* テスト環境
    * Windows 11 64biy
    * CPLEX 22.1.0.0

oplrunのパスにcdしてmodファイルとdatファイルを指定して実行します。

```cmd:oplrun
cd /d C:\Program Files\IBM\ILOG\CPLEX_Studio221\opl\bin\x64_win64
oplrun "C:\Program Files\IBM\ILOG\CPLEX_Studio221\opl\examples\opl\production\product.mod" "C:\Program Files\IBM\ILOG\CPLEX_Studio221\opl\examples\opl\production\product.dat"
```

以下のように結果を得ることができます。

```:結果
C:\Program Files\IBM\ILOG\CPLEX_Studio221\opl\bin\x64_win64>oplrun "C:\Program Files\IBM\ILOG\CPLEX_Studio221\opl\examples\opl\production\product.mod" "C:\Program Files\IBM\ILOG\CPLEX_Studio221\opl\examples\opl\production\product.dat"

<<< setup


<<< generate

Version identifier: 22.1.0.0 | 2022-03-09 | 1a383f8ce
CPXPARAM_Simplex_Display                         2
CPXPARAM_Preprocessing_Presolve                  0

Iteration      Dual Objective            In Variable           Out Variable
     1              90.000000   Inside("fettuccine")ctDemand("fettucc slack
     2             250.000000    Inside("capellini")ctDemand("capelli slack
     3             286.666667  Outside("fettuccine") ctInside("eggs") slack
     4             350.000000       Inside("kluski")ctDemand("kluski" slack
     5             363.333333   Outside("capellini")ctInside("flour") slack
     6             370.000000 ctInside("eggs") slack    Inside("capellini")
     7             372.000000      Outside("kluski")   Inside("fettuccine")

<<< solve


OBJECTIVE: 372

<<< post process


<<< done


C:\Program Files\IBM\ILOG\CPLEX_Studio221\opl\bin\x64_win64>
```

詳細なコマンドの構文やオプションは以下にあります。
* oplrunコマンド構文 - IBM Documentation 

https://www.ibm.com/docs/ja/icos/20.1.0?topic=interface-syntax
検証用 Azure VM のパスワードを忘れたとき　Active Directory アカウントのパスワード初期化

# おわった…
Azure上に検証環境を立てたあと、しばらく"停止済み (割り当て解除)"で寝かせておくことがあります。
しばらく立って、再度起こしたときなどに、「パスワード忘れた。終わった・・・」と思うことも稀によくあります。
ので、そんなときに役立つことをメモしておきます。
※ あくまで検証環境用の手順。当然ですが、リセットには大きな影響があります。実施前によく調べ、よく検討する必要があります。作業ミスも注意。

# 基本
ローカル管理者アカウントのパスワードのリセット は簡単です。
Azure Portal 上からパスワードのリセットを試すことができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1461633/6f736ab6-848a-c1dc-aa6d-35e1824c79a2.png)

- https://learn.microsoft.com/ja-jp/troubleshoot/azure/virtual-machines/reset-rdp#reset-the-local-administrator-account-password-1



また、Azure VM の OS(Windows / Linux)それぞれに、パスワードをリセットする Learn のページがあります。
- Windows: https://learn.microsoft.com/ja-jp/troubleshoot/azure/virtual-machines/reset-local-password-without-agent
- Linux  : https://learn.microsoft.com/ja-jp/troubleshoot/azure/virtual-machines/reset-password

これでも失敗する場合には一般的にRDPのトラブルシューティングを参照します
- https://learn.microsoft.com/ja-jp/troubleshoot/azure/virtual-machines/troubleshoot-rdp-connection
> ユーザーの資格情報をリセットする。 このトラブルシューティングの手順では、資格情報が明確でないか、覚えていない場合に、指定したローカル管理者アカウントのパスワードをリセットします。
> 最初に、次のように資格情報を $cred 変数に割り当てて、ユーザー名と新しいパスワードを指定します。
> ```powershell
> $cred=Get-Credential
> ```
> ここで、VM の資格情報を更新します。 次の例では、WestUS 内と myResourceGroup という名前のリソース グループ内にある myVM という名前の VM で資格情報を更新します。
> ```powershell
> Set-AzVMAccessExtension -ResourceGroupName "myResourceGroup" `
>     -VMName "myVM" -Location WestUS -Name "myVMAccessExtension" `
>     -UserName $cred.GetNetworkCredential().Username `
>     -Password $cred.GetNetworkCredential().Password
> ```


# Active Directory アカウントのパスワード初期化がしたい
こちらが本題です。
Azure Portal 上から Azure VM 内の 検証用Active Directory環境のアカウントのパスワードを初期化します。
以下に、役に立ちそうな PowerShell のサンプルを置いておきます。

Azure VM 自体にログインせずとも、PowerShellの実行が可能ですので、ここから初期化を行えます。
操作したい Azure VM を開き、[実行コマンド] -> [RunPowerShellScript] で実行できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1461633/521fa506-da2a-88bc-d813-0dc94483476e.png)


# PowerShell サンプル

●ユーザー一覧を取得する
```powershell
Get-WmiObject Win32_UserAccount
```

●Active Directory アカウントの情報を取得する
```powershell
Get-ADUser -Identity <username>
```

●Active Directory アカウントのパスワードを初期化

- 指定されたユーザーのパスワードを設定する
```powershell
Set-ADAccountPassword -Identity <username> -Reset -NewPassword (ConvertTo-SecureString -AsPlainText "!QAZxsw23edc" -Force -Verbose)
```

- 識別名を使用してユーザー・アカウントのパスワードを設定する
```powershell
Set-ADAccountPassword -Identity 'CN=<username>,CN=Users,DC=contoso,DC=local' -Reset -NewPassword (ConvertTo-SecureString -AsPlainText "p@ssw0rd" -Force -Verbose)
```


# 参考

https://learn.microsoft.com/en-us/powershell/module/activedirectory/get-aduser?view=windowsserver2022-ps

https://learn.microsoft.com/en-us/powershell/module/activedirectory/set-adaccountpassword?view=windowsserver2022-ps

https://learn.microsoft.com/ja-jp/powershell/module/microsoft.powershell.management/get-wmiobject?view=powershell-5.1

https://learn.microsoft.com/ja-jp/windows/win32/cimwin32prov/win32-useraccount
[Django] migrate しようとしたら MySQL Error 1050 ではまった話。

## Error 内容
```terminal
django.db.utils.OperationalError: (1050, "Table 'django_admin_log' already exists")
```
migrations 履歴を閲覧
```python
python3 manage.py showmigrations

# output
admin
 [ ] 0001_initial
 [ ] 0002_logentry_remove_auto_add
 [ ] 0003_logentry_add_action_flag_choices
api
 [X] 0001_initial
auth
 [X] 0001_initial
 [ ] 0002_alter_permission_name_max_length
 [ ] 0003_alter_user_email_max_length
 [ ] 0004_alter_user_username_opts
 [ ] 0005_alter_user_last_login_null
 [ ] 0006_require_contenttypes_0002
 [ ] 0007_alter_validators_add_error_messages
 [ ] 0008_alter_user_username_max_length
 [ ] 0009_alter_user_last_name_max_length
 [ ] 0010_alter_group_name_max_length
 [ ] 0011_update_proxy_permissions
 [ ] 0012_alter_user_first_name_max_length
contenttypes
 [X] 0001_initial
 [ ] 0002_remove_content_type_name
sessions
```

## 解決方法

単純に問題となるテーブルを一個ずつ削除しながらmigrateを進めると良いと。
migrationsフォルダーにあるファイルを適宜書き換え、削除するとさらに良いかも。
自分は下記でErrorをノックアウトしました。


```sql
drop table django_admin_log;
```

```python
python3 manage.py migrate

# output
Operations to perform:
  Apply all migrations: admin, api, auth, contenttypes, sessions
Running migrations:
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying admin.0003_logentry_add_action_flag_choices... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying auth.0010_alter_group_name_max_length... OK
  Applying auth.0011_update_proxy_permissions... OK
  Applying auth.0012_alter_user_first_name_max_length... OK
  Applying sessions.0001_initial... OK

```

Good bye Errors
Android StudioでRunした際にアプリがLaunchしないときの対策

# 事象
通常、Android　Studio(AS)からアプリをRunするとビルドからアプリ起動まで実行されるが、
実行後にLaunch　Succeedのポップアップが表示される（端末にインストールはされている）もののアプリの起動まではされなくなった

# 対策
RunメニューのEdit Configrationsを開く
Launch　OptionsのLaunchをDefault Activityに変更する
日本語を含む OpenAPI ドキュメントをPDF出力したかった

表記の件やった際の覚書。

### PDFジェネレータ
- RapiPdfを使用
　　しばらく更新されてないけど、まぁそんな変わるもんでもないのでヨシ。

https://github.com/mrin9/RapiPdf


#### (2024-12-06追記)
RapiPdfが古いんで、nodeのバージョンアレする必要があります  
とりあえず
- Node 16.13.2 使用

```
npm install
npm run build
npm run serve
```
で動くのは確認。
(追記ここまで)

### 準備
```sh
# とりあえずインストールして
yarn install 
yarn build

# packageでpdfmakeが入るのでフォント追加の準備
cd ./node_modules/pdfmake
mkdir -p examples/fonts

# フォント定義ファイル(vfs_fonts.js)生成
node build-vfs.js "./examples/fonts"

# 移動
cd {RapiPdfのルート}

# 生成したフォント定義ファイルをコピー
cp ./node_modules/pdfmake/vfs_fonts.js ./src/

# ソースを少々変更
vi ./src/pdf-gen.js

# --- 差分 ---
L.41 -    mono: { font: 'RobotoMono', fontSize: 10 },
L.42 -    monoSub: { font: 'RobotoMono', fontSize: 8 },
L.41 +    mono: { font: 'IPAPGothic', fontSize: 10 },
L.42 +    monoSub: { font: 'IPAPGothic', fontSize: 8 },

L.96    pdfMake.fonts = {
-    Roboto: {
-      normal: 'Roboto-Regular.ttf',
-      bold: 'Roboto-Medium.ttf',
-      italics: 'Roboto-Italic.ttf',
-      bolditalics: 'Roboto-Medium.ttf',
-    },
-    RobotoMono: {
-      normal: 'RobotoMono-Regular.ttf',
-      bold: 'RobotoMono-Regular.ttf',
-      italics: 'RobotoMono-Regular.ttf',
-      bolditalics: 'RobotoMono-Regular.ttf',
+    IPAPGothic: {
+      normal: 'ipagp.ttf',
+      bold: 'ipagp.ttf',
+      italics: 'ipagp.ttf',
+      bolditalics: 'ipagp.ttf',
     },

L.111 -  // pdfMake.vfs = pdfFonts.pdfMake.vfs;
-  pdfMake.vfs = pdfFonts;
+  pdfMake.vfs = pdfFonts.pdfMake.vfs;
+  // pdfMake.vfs = pdfFonts;
# -----

# ビルドする
yarn build

```

- font変更参考
https://pdfmake.github.io/docs/0.1/fonts/custom-fonts-client-side/vfs/

- IPAフォント
https://moji.or.jp/ipafont/ipa00303/


### とりあえずの使い方

##### ファイルおいてサーバ起動
``` sh
# PDF化したいopen api ファイルを設置(json or yaml)
# {RapiPDFルート}/docs/spec/

# RapiPDFサーバ起動
yarn serve
```

##### PDF出力

- ブラウザで開く
  http://localhost:8080/

- PDF化したいファイルを指定して `GENERATE PDF` を押下

![スクリーンショット 2022-10-17 10.31.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/590344/be87bef6-459d-a7e2-5794-cad7323616a0.png)


これで日本語含むOpenAPIドキュメントもPDF出力できる。はず。
もともと入ってたROBOTOフォントも残したい場合はフォントをDLしてフォントファイルを生成すると良い。
https://fonts.google.com/?query=roboto
Azure Fundamentals(AZ-900)：Azure の基礎: Azure のアーキテクチャとサービスについて説明する「Azure仮想ネットワーク(VNet)」

Microsoft Learnを用いたMicrosoft Azure Fundamentals(AZ-900)の試験内容をまとめる投稿です。
この投稿ではMicrosoft Learnで学ぶ内容をできるだけ簡潔にまとめております。
Azureの勉強を一から始める方の参考になれば幸いです。

## 今回の学習内容
**◆「Azure仮想ネットワーク(VNet：Virtual Network)」**
◇対応するMicrosoft Learn ラーニングパス
[Azure の基礎: Azure のアーキテクチャとサービスについて説明する](https://learn.microsoft.com/ja-jp/training/paths/azure-fundamentals-describe-azure-architecture-services/)
◇対応するモジュール
[Azure 仮想ネットワークについて説明する](https://learn.microsoft.com/ja-jp/training/modules/describe-azure-compute-networking-services/8-virtual-network)

※前回の投稿は下記から確認できます。
[Azure Fundamentals(AZ-900)：Azure の基礎: Azure のアーキテクチャとサービスについて説明する「Azure Functions / Azure App Service」](https://qiita.com/fsd-jume/items/8675b9945ad6a01ff0be)

## Azure仮想ネットワーク(VNet：Virtual Network)
**Azure内のプライベートネットワークの基本的な構成要素**
⇒AzureリソースをVNet内に配置することでAzure内外との通信が可能になる
⇒VNetはパブリック/プライベートどちらのIPアドレスも持つことができる

### 分離とセグメント化
・他とは分離された仮想ネットワークを複数作成可能
・VNetを名前付きのサブネットに分割して、セグメントを分けることが可能
※名前解決にはAzure組み込みの名前解決サービスや内部/外部のDNSサーバを使うことも可能

### Azureリソース間の通信
**◆仮想ネットワーク経由 = VNet内通信(サブネット内、サブネット間)**
・VMや他のAzureリソース(Azure App Service Environment、AKSなど)をデプロイ可能
・デフォルトで送受信可能
※NSG(ネットワークセキュリティグループ)を介して通信しているため、フィルタリングすることも可能

**◆仮想ネットワークサービスエンドポイント経由**
・VNetに直接デプロイできないサービス(Azure StorageやAzure SQL Databaseなど)に対して通信可能
・VNetからAzureバックボーンネットワークを介してAzureサービスへ通信

**◆VNetピアリング経由**
・仮想ネットワークピアリング：同一リージョン内の異なるVNet間で通信可能
・グローバル仮想ネットワークピアリング：異なるリージョン間のVNetで通信可能
・トラフィックはプライベートでありMicrosoftバックボーンネットワーク上で経由するため、パブリックインターネットには入らない
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2851723/3738336b-7bb1-9379-ff82-3eca2933ca74.png)

### インターネット通信
・送信：VNet内のすべてのリソースがデフォルトで送信可能
・受信：リソースにパブリックIPアドレスかパブリックロードバランサを割り当てることで可能

### オンプレミスリソースとの通信
**◆ポイント対サイト仮想プライベートネットワーク(P2S VPN)**
・個々のクライアントPCとVNet内のVPN GatewayがVPN接続

**◆サイト間仮想プライベートネットワーク(S2S VPN)**
・オンプレミスのVPNデバイス/ゲートウェイとVNet内のVPN GatewayがVPN接続
※オンプレミス側の指定はローカルネットワークゲートウェイで行う

**◆Azure ExpressRoute**
・接続プロバイダが提供する専用の回線で直接接続
・インターネット回線を利用しないため、高い通信品質とセキュリティが得られる

※VPN(Virtual Private Network)
ネットワーク上に別のプライベートなネットワークを仮想的に作る技術
⇒送信/受信側の機器で暗号化し、仮想的なトンネルを形成して通信
⇒信頼されてないネットワークを通過する際にセキュリティが担保される
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2851723/0586ce74-d81a-9994-bfe0-c26ed0009337.png)

### ネットワークトラフィックのルーティング
・デフォルトでサブネット/インターネットとの間でルーティング(既定のシステムルート)
・VNetのサブネットごとにルートテーブルが自動的に作成され、既定のシステムルートが追加される
・システムルートは作成/修正/削除ができないが、下記のカスタムルートで上書き可能

**◆ユーザ定義ルート(UDR：User Defined Route)**
・Static Route(静的ルート)をサブネットのルートテーブルに追加する
( =カスタムルートテーブルを作成)

**◆BGP(Border Gateway Protocol)ルート**
・BGPを使用してVNetにルートを反映させる(動的ルート)
・Azure VPN GatewayやExpressRoute接続を使用してVNetをオンプレ環境と接続する際などに使用

### ネットワークトラフィックのフィルター処理
・下記のオプションを使用してサブネット間のトラフィックをフィルター処理可能

**◆ネットワークセキュリティグループ(NSG)**
・受信と送信のセキュリティ規則を複数設定できるAzureリソース
・送信元IPアドレス、送信元ポート、宛先IPアドレス、宛先ポート、プロトコルの5要素に基づいてトラフィックの許可/拒否を定義

**◆ネットワーク仮想アプライアンス**
・ファイアウォール(FW)やWAN最適化などの特定のネットワーク機能を実行するVM

## 次の学習内容
**◆Azure仮想プライベートネットワーク(VPN)**

https://qiita.com/fsd-jume/items/7d5b49c320035a5a28b3

## 学習内容をまとめたページの一覧

https://qiita.com/fsd-jume/items/e4ec76959adb547ac5e8
流通BMSのorder(発注)データを読み込む

## 概要
流通BMSのOrder(発注)データを読み込む処理をやってみた。
注)このプログラムは大まかな処理部分のみを記述しています。

```vb:VB.NET
Dim document As New XmlDocument
'読み込むXMLファイルのパスを指定する
document.Load(path)

'orderデータで使われている名前空間を定義する
Dim nm As New XmlNamespaceManager(document.NameTable)
nm.AddNamespace("sh", "http://www.unece.org/cefact/namespaces/StandardBusinessDocumentHeader")
nm.AddNamespace("common", "urn:SecondGenEDI:common:Japan:1")
nm.AddNamespace("order", "urn:SecondGenEDI:order:Japan:1")

'名前空間shのエレメントを参照する例
Dim sh_Sender_Identifier As XmlElement = document.SelectSingleNode("//sh:StandardBusinessDocumentHeader/sh:Sender/sh:Identifier", nm)
Dim sh_Receiver_Identifier As XmlElement = document.SelectSingleNode("//sh:StandardBusinessDocumentHeader/sh:Receiver/sh:Identifier", nm)
Dim sh_InstanceIdentifier As XmlElement = document.SelectSingleNode("//sh:StandardBusinessDocumentHeader/sh:DocumentIdentification/sh:InstanceIdentifier", nm)
Dim sh_Type As XmlElement = document.SelectSingleNode("//sh:StandardBusinessDocumentHeader/sh:DocumentIdentification/sh:Type", nm)
Dim sh_CreationDateAndTime As XmlElement = document.SelectSingleNode("//sh:StandardBusinessDocumentHeader/sh:DocumentIdentification/sh:CreationDateAndTime", nm)

'名前空間orderのエレメントを参照する例
Dim buyerCode As XmlElement = document.SelectSingleNode("//order:listOfOrders/buyer/code", nm)
Dim buyerCode23 As String = buyerCode.InnerText
Dim buyerName As XmlElement = document.SelectSingleNode("//order:listOfOrders/buyer/name", nm)
Dim buyerName25 As String = buyerName.InnerText
Dim buyerNameKana As XmlElement = document.SelectSingleNode("//order:listOfOrders/buyer/name_sbcs", nm)
Dim buyerNameKana26 As String = buyerNameKana.InnerText

'orders(複数伝票)情報を参照する
Dim orders As XmlNodeList = document.SelectNodes("//order:listOfOrders/order", nm)

'orders(複数伝票)内のorder(１伝票)分の処理を行う例
For Each order As XmlElement In orders
    '121 取引番号（発注・返品）＝ 伝票番号
    Dim tradeNumber121 As String = order.SelectSingleNode("tradeID/tradeNumber").InnerText
    '27 直接納品先コード
    Dim code27 As String = order.SelectSingleNode("parties/shipTo/code").InnerText
    '29 直接納品先名称
    Dim name29 As String = order.SelectSingleNode("parties/shipTo/name").InnerText

    'order(１伝票)内の明細行データを参照する例
    For Each child As XmlElement In order.ChildNodes
        If child.Name = "lineItem" Then
            '123 取引明細番号（発注・返品）＝　伝票行番号
            Debug.WriteLine(Integer.Parse(child.SelectSingleNode("lineID/lineNumber").InnerText))
            '73 商品コード（発注用） JANコードをセット
            Debug.WriteLine(child.SelectSingleNode("itemID/orderItemCode").InnerText)
            '77 商品名
            Debug.WriteLine(child.SelectSingleNode("itemID/name").InnerText)
        End If
    Next
Next

nm = Nothing
document = Nothing
```
Falco Ruleを紹介するシリーズ - Program run with disallowed http proxy env


:::note info
10/28（金）コンテナクラウドセキュリティで訊かれる「ランタイムセキュリティ」とは？と題してFalcoをSysdigが徹底解説するウェビナーを開催します。ご興味ある方はこちらから
https://go.sysdig.com/20221028JapanWebinar1.html
:::
本シリーズでは、ランタイム脅威検知のデファクトスタンダードである<a href=https://falco.org/ target=new>Falco</a>の検知Ruleを、１つの記事で１つ簡単に紹介していきます。
ランタイムセキュリティやFalco自体の概要を知りたい方は<a href=https://sysdig.jp/blog/intro-runtime-security-falco/ target=new>こちらのブログ記事</a>をご参照ください。
今回ご紹介する検知Ruleは<b>「Program run with disallowed http proxy env」</b>です。
# Rule記述
```
- rule: Program run with disallowed http proxy env
  desc: An attempt to run a program with a disallowed HTTP_PROXY environment variable
  condition: >
    spawned_process and
    http_proxy_procs and
    not allowed_ssh_proxy_env and
    proc.env icontains HTTP_PROXY
  enabled: false
  output: >
    Program run with disallowed HTTP_PROXY environment variable
    (user=%user.name user_loginuid=%user.loginuid command=%proc.cmdline env=%proc.env parent=%proc.pname container_id=%container.id image=%container.image.repository)
  priority: NOTICE
  tags: [host, users]
```
# Rule概要
許可されていないHTTP_PROXY環境変数を使用したプログラム起動を検知します。
プロキシサーバーを設置することで、通信先のチェックや不正通信の遮断、ログの監視などを実施できますが、攻撃者はこれを回避するために、許可されていないHTTP_PROXY環境変数を使用する場合があります。
また、不正に暗号通貨を発掘するクリプトマイナーの中には、通信先となるマイニングプールのIPアドレスを隠蔽するために独自のプロキシを利用するマルウェアも存在します。

# Condition（条件）
`spawned_process and`
新たに起動したプロセスで、

`http_proxy_procs and`
curl、wgetなどのHTTP Proxyを使用するプロセスで、

かつ

`not allowed_ssh_proxy_env and`
許可されたプロキシ環境変数ではなく、

`proc.env icontains HTTP_PROXY`
プロセスの環境変数がHTTP_PROXYを含む場合
※icontainsオペレーターは大文字小文字を区別しません

# Output（出力）
許可されていないHTTP_PROXY環境変数を伴うプログラムが起動しています

`%user.name`
ユーザー名

`%user.loginuid`
ユーザーのログインUID

`%proc.cmdline`
コマンドライン

`%proc.env`
プロセス環境変数

`%proc.pname`
親プロセス名

`%container.id`
コンテナID

`%container.image.repository`
コンテナイメージリポジトリ
SEO対策の基本を考えてみた

以前SEO対策を前職で行っていて、久々にSEOにふれる機会があったのでSEO対策の振り返りと再理解（整理？）のために記載してみました

# SEO対策とは
SEOは Search Engine Optimization：検索エンジン最適化 で検索サイトの検索結果の上位にくるようにする対策のことである

# ターゲットとする検索サイト
日本の検索サイトはGoogleとYahoo!の上位2社で95%ぐらいを網羅できる
Yahoo!はGoogleの検索エンジンを採用しているのでGoogleに向けた対応をおこなえば良い

# SEO対策にて行うこと
目指すべき対策と行ってはいけない対策があり、前者を「ホワイトハットSEO」、後者を「ブラックハットSEO」と言う
なお、SEO対策は確立したものはなく、検索エンジンのアップデートにより日々更新が行われているので、頻繁にキーワードの順位の確認と対策を行っていく必要がある

## ホワイトハットSEO
以下の2つの要素がもっとも影響が大きいと言われている
- 検索者の検索意図を満たしていて内容が最新で充実している
- 外部の人気が高いサイトから多数のリンクを得ている

他にもあるので少し具体的に記載していく

### キーワードの選定
ターゲットとしたいユーザがどのようなキーワードを使用して目的とするサイト（商品）に到達するかを考える

### コンテンツ
- 内容に精通した専門家によって記載され、かつ詳細で充実していること
- Googleはユーザがサイトを検索する可能性が高いキーワードをサイト内に含めることを推奨している
- 製品の固有名詞ではなく一般名称を検索したり、機能名も同様に一般的な名称が検索されることもあるのでこれらも含めて盛り込む

### HTMLによる最適化
- title、meta、strong、hnの各要素などを重要視すると言われている
- titleが同じだと同一ページと認識されるため地域名などをいれ、差別化する
- 別サイトであっても同じtitleの場合は類似サイトとみなされることがあり、対象とならないことがあるのでサイト名を追加する
→ title：「メインテーマ」「サブテーマ」｜「サイト名」
- 中でもtitleとh1は最重要、キーワードを盛り込んでスタイルシートで修飾すると検索エンジンにも重要と判断される
- HTMLファイルの15MB以上は対象外となる
- ページの読み込み後、レイアウトが大きく変わることはないか（画像の読み込みなどで位置が変わる場合はペナルティの対象となることがあるらしい→サイズ指定するなど対策を講じる）
- 画像ALT内は正しく設定されているか

### 最新の情報に更新する
- 新しい情報を優遇する QDF(Query Deserves Freshness)と言うらしい

更新が頻繁なサイトほど上位に来る

### タイトル、説明文、見出しと内容の一貫性
botから閲覧されるときにテキストの内容に基づいて整理され
- 何が書かれているページか
- あるキーワードにどのくらい関連性があるか判断している
- 一貫性がないと支離滅裂なコンテンツとして評価されなくなる

### 被リンク
対象のページにどのくらいの被リンクがあるか
- 有名サイトであれば効果倍増
- キーワードと関連性が高いと更に良い
- 数が多いほど上位に来やすい

対策としては以下が考えられる
- 他の関連するサイトにリンクを求めたり、自己が運営する既存サイトから適切なリンクを入れたりするような対策を行う
- ユーザに役立つページを作成することにより、ユーザから被リンクを得ることを目的することも対策
- SNSの投稿ボタンを追加する対応も有効
- リダイレクトすると効果がなくなるので、リンク元のURLを変更する（してもらう）こと

### ページの表示速度
遅いとGoogleから警告が来て改善できなければペナルティの可能性
- サイトの応答速度
- ページの軽量化

### クローラー（Bot）対策
- robots.txtの設定
- sitemap.xmlを最新に更新
- サイトマップページの作成
・Botはハイパーリンクを辿って巡回を行うのでサイトマップを作成することでインデックスされやすくなる
・すべてのページを網羅するとそのサイトにたどり着いたときに全体がインデックスされやすくなる

### SSLの推奨
SSLを公式に優遇するとしている。なお、非SSLサイトは別サイトと認識されるため使用していない場合は効果が分散しないようにリダイレクトしておく
なお、以下に注意が必要
- セキュアでない依存関係が含まれていない
- HTTP ページへの rel="canonical" リンク
- 「noindex robots」やrobots.txtの取り扱い
- TLS証明書が有効

### 検索結果ページのクリックが多いほど有利
- 同一のページと認識されるためタイトルは普遍的なものがよい
・変更した場合は新たなサイトと判断されて以前の優位性が引き継がれない事がある
※タイトルの変更に関しては他で記載もされていないし、テストもできなかったのでファクトがないですが、以前身近なところで話題があったので記載しました

### モバイル向けインデックス
- 検索結果はPC向けとモバイル向けで異なる
モバイル対応でないページはモバイル向けインデックスでは順位が下る

## ブラックハットSEO
- 検索順位を上げるだけの目的で好ましくない手法
- 結果から削除などのペナルティがある

### 好ましくないサイトからのリンク
- 検索スパムサイトからのリンク
- リンクの売買

もし、ブラックリストサイトに含まれている場合は再審査リクエストとリンク拒否ツールから申請する

### 好ましくないコンテンツ、HTML
- ユーザには見えない文字（隠し文字）を埋め込む
- 見えない隠しリンクを入れる
- Googlebotとユーザが見るページが違うような対応、クローキング
- 複製されたサイトが複数ある

# 振り返ってみて
こんなのあったなとか思い出しながら書いていました。パンダアップデート以降はあまり大きく変わっていないようにも思いましたが、基本方針がぶれていないからですね（素晴らしい！）。しかし、検索エンジンのアップデートは時々行われているので、実際にサイトのSEO対策を行うと日々試行錯誤しながら改善を行っていくようになり、想定通り順位が上がったときはめっちゃ嬉しいですよね。。。。。（逆はつらい）

読んでいただきありがとうございました。

出筆時に以下のページを参考にさせていただきました
- [ウェブマスター向けガイドライン - Google](https://developers.google.com/search/docs/advanced/guidelines/webmaster-guidelines?hl=ja)
- [検索エンジン最適化 - wikipedia](https://ja.wikipedia.org/wiki/%E6%A4%9C%E7%B4%A2%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%B3%E6%9C%80%E9%81%A9%E5%8C%96)
- [SEO - e-words](https://e-words.jp/w/SEO.html)