OmniAICreator/Qiita-1.07M huggingface dataset:
よく使うNPMモジュール

# jQuery
https://www.npmjs.com/package/jquery

# picture
https://www.npmjs.com/package/picturefill

# object-fit
https://www.npmjs.com/package/object-fit-images

# スムーススクロール
https://www.npmjs.com/package/vue-scrollto

# スクロールバー
https://www.npmjs.com/package/vue2-perfect-scrollbar

# カルーセル
https://www.npmjs.com/package/vue-slick-carousel

# 開発サーバー
https://www.npmjs.com/package/http-server

# envファイル
https://www.npmjs.com/package/dotenv

# cli-confirm
https://www.npmjs.com/package/cli-confirm
【デザインパターン】JavaScriptで学ぶFacade

#はじめに
現在デザインパターンについて勉強中です。
今回はFacadeついてまとめました。

https://qiita.com/suzuki0430/items/d44a83c500993a763c1d

#Facade
Facadeはサブシステムを利用するユーザーの用途に合わせたインターフェースを提供するための、構造に関するデザインパターンの一つです。
サブシステム間の独立性を高めることを目的としたデザインパターンであり、ユーザはFacadeを経由することで、内部の実装を意識せずにサブシステムを利用することができます。

#実装例
入力したテキストを保存`write()`したり、指定したテキストを取り出す`getCharAt()`ような機能をもった`Console`クラス(Facadeクラス)を考えます。
これらの操作を行うにあたってはテキストの表示分の領域を確保してあげる必要などがあります。
新しく`Viewport`クラスと`Buffer`クラスをつくることで、ユーザがそのような内部の実装を意識せずに`Console`クラスを利用することができるようになります。

```js
class Buffer extends Array
{
  constructor(width=30, height=20)
  {
    super();
    this.width = width;
    this.height = height;
    this.alloc(width*height);
  }

  write(text, position=0)
  {
    // write to the buffer
  }
}

class Viewport
{
  constructor(buffer=new Buffer())
  {
    this.buffer = buffer;
    this.offset = 0;
  }

  append(text, pos)
  {
    this.buffer.write(text, pos + this.offset);
  }

  getCharAt(index)
  {
    return this.buffer[this.offset + index];
  }
}

class Console
{
  constructor()
  {
    this.buffer = new Buffer();
    this.currentViewport = new Viewport(
      this.buffer
    );
    this.buffers = [this.buffer];
    this.viewports = [this.currentViewport];
  }

  write(text)
  {
    this.currentViewport.buffer.write(text);
  }

  getCharAt(index)
  {
    return this.currentViewport.getCharAt(index);
  }
}
```

#参考資料

https://www.udemy.com/share/101Bpe3@Wapeed1JE99zGyDGeFWUwPUAL8i7H6iKQ0y-TtL-LINIEnzqVstotj7Ap-XFh22W/
【Unity】Rigitbody.Velocityが0になる現象

####### ハマったのでメモ

オブジェクトの速度を取得するために、FixedUpdateで下記のようにRigidbody.VelocityをLogで出してみたところ、

```c#
    void FixedUpdate () {
        Debug.LogFormat("velocity:{0:0.0}", _rigidbody.velocity);
    }
```

なぜか実際の速度と0が交互に出力される現象が発生した。
![スクリーンショット 2021-09-04 14.29.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30218/57a750cf-90af-1a6b-9393-fb31548d7800.png)

調べたところ、RigidbodyはSleepするタイミングがあり、その時はVelocityが0になるらしい。
Sleepしているかどうかは、IsSleeping()で取得できる。

```c#
    void FixedUpdate () {
        Debug.LogFormat("velocity:{0:0.0}, {1}", _rigidbody.velocity, _rigidbody.IsSleeping());
    }
```

![スクリーンショット 2021-09-04 14.27.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/30218/acf12bd5-b35f-c8a4-e16f-eb44d3bcc863.png)

このSleepのタイミングは設定で変更できるらしい。

参考
https://stackoverflow.com/questions/54790695/rigidbody-velocity-is-zero-sometimes-while-the-rigidbody-is-moving
https://qiita.com/lycoris102/items/475893166b2840cf8c99
apollo cliで起きたすごい勘違い（2に渡り格闘した泣）

apollo cliにて

```
npx apollo client:codegen
```

という便利なコマンドをためそうとして2日格闘していた。
このコマンドは
graphqlのクエリを勝手に作ってくれて、そのクエリに対して
typescriptでは型を付けてれる... ...
<h3><font color="Red">なんてすごい勘違いをしていた!!</font></h3>

だが[公式](https://github.com/apollographql/apollo-tooling)では
>Apollo CLI brings together your GraphQL clients and servers with tools for >validating your schema, linting your operations for compatibility with your >server, and generating static types for improved client-side type safety.

と書いてある。
自分のつたない翻訳が正しければ、
自分で書いたクエリに対して、型をつけてくれるという機能だった... ...
公式をちゃんと読めばわかるのに... ...
うげぇぇぇぇ。
公式のドキュメントを最初から読めるような英語力がほしい！！
と思った今日このごろ。
この記事の内容が間違っていた場合は教えてくれると
とても喜びます！！
【Firebase / Flutter Web】Firestore本番環境のドキュメントをエミュレーターにインポートしてテストデータを作成する。

環境：Mac Catalina 10.15.7
開発対象：Flutter Web

fsrplのインストール

```
brew tap matsu0228/homebrew-fsrpl
brew install fsrpl
```

Firebaseの秘密鍵を作成する。

```
→コンソールへアクセス
→設定（歯車マーク）クリック
→「プロジェクトを設定」をクリック
→「サービスアカウント」をクリック
→「新しい秘密鍵を生成」をクリック
```
ドキュメントのエクスポート

```
ターミナルからダウンロードフォルダ(ファイルを移動させた場合はそのフォルダに）に移動

fsrpl dump <コレクション名/ドキュメント名> --cred=<先ほどダウンロードした秘密鍵> --path=エクスポートするファイルの保存先>

例）
fsrpl dump "users/zkareaweUdkLjErjdsau" --cred=./myApp-firebase-adminsdk-t***da-b*****bc83.json --path="./"


```
エミュレーターにインポート

fsrpl restoreコマンドでなぜかインポートできなかったので手動でインポートする。

```
エミュレーターを起動する。
検証ツールを開く。
検証ツール→コンソールで下記を実行する。

firestore.doc(<保存したいドキュメントpath>).set({<インポートしたデータの中身をペースト>})

例）
firestore.doc('users/aaaaaa').set({"name":"Taro","age":"19"})
```

テストデータをエミュレータで永続化する

```
保存したいディレクトリを指定して起動。
firebase emulators:start --only firestore --import <保存したいディレクトリ> --export-on-exit

例）
firebase emulators:start --only firestore --import emulator_data --export-on-exit
```

参考
https://github.com/matsu0228/fsrpl/blob/master/README_ja.md#setup
https://qiita.com/mokichi/items/4b2fdfeda78fa3f28cdd https://zenn.dev/mtskhs/articles/fsrpl-replication-tool-for-testing
https://qiita.com/mokichi/items/4b2fdfeda78fa3f28cdd
TrueNASに幾つかアプリケーションを入れて使ってみた：Plex Media Server編

参照元：[TrueNASにアプリを幾つか入れて使ってみた
](https://qiita.com/exthnet/items/523396d4bfedf04674b5)

Plex Media ServerはいわゆるDLNAサーバであり、無料公開されている動画をLAN内に配信できるのみならず、ローカルに蓄積された動画や音楽なども配信できる。ここではTrueNASに蓄積されたコンテンツをLAN内に流すためのサーバとして使うことを考える。

インストールは超絶簡単で、Plugins画面からINSTALLを選ぶだけ。インストールが終了すると管理画面のURLが表示される。

![2021-09-04 14_18_09-Window.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199517/8c876f83-5b0d-9cf9-3d96-799ca319b14b.png)

アクセスするとアカウント認証的な画面が出るが、蓄積されたコンテンツをLAN内に配信するだけならスキップしてしまって良い。（「これはなんですか？」からスキップできる。）

問題はコンテンツ、つまりTrueNASのコンテンツが蓄積されたディレクトリを指定する段階。jailからはjail用のディレクトリ以下しか見えないので、Plexの外にあるコンテンツが参照できない。

![2021-09-04 14_19_23-Window.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199517/11a25f28-a851-a5b7-2f9a-1d69905819ae.png)

![2021-09-04 14_21_03-Window.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199517/2f6013e0-de25-099a-54c9-08a0b8143c51.png)

というわけで、お約束であるがディレクトリをマウントする。
jailを停止し、「Mount Points」から「Add」を選択、Sourceとしてメディアファイルのあるディレクトリ（例えば`/mnt/storage/share`）を、Destinationとして適当なディレクトリ（例えば`/mnt`、jailが`/mnt/extra/iocage/jails/plex2`にあるなら`/mnt/extra/iocage/jails/plex2/root/mnt`に相当）を選ぶ。

![2021-09-04 14_22_56-Window.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199517/a20ab1af-484d-3dd4-4385-aa9b57b2de34.png)

この状態でjailを起動し直して設定画面にアクセスしなおし、画面右上の工具アイコンを選択、「管理」の「ライブラリー」を選択し、「ライブラリーに追加」。あとは例えば「動画」を選び、「メディアフォルダーを見る」から`/mnt`を選んで「ライブラリーに追加」を選ぶ。これでメディアファイルのスキャンが始まるが、ファイルが多いとスキャンに時間がかかるため、「スキャンをキャンセルする」で後回しにしても良い。

また、設定の「DLNA」から「DLNAサーバーを有効にする」を選べばLAN内のDLNAクライアントからアクセスして動画等の再生が可能になる。

サムネイル作成の最適化とかいろいろ弄る部分はありそうだが、とりえずDLNAサーバとしてコンテンツを配信させるだけならこれだけでOK。とても簡単。
sRGBの値をxy色度図にプロットする(Python)

Pythonのcolourライブラリを使用して、sRGBの値をxy色度図(chromaticity_diagram_CIE1931)にプロットする方法です。

事前準備として、次の3つのライブラリ(colour-science, numpy, matplotlib)をpipなどでインストールしておく必要があります。

## ソースコード

```python
import colour
import numpy as np
import matplotlib.pyplot as plt
colour.plotting.colour_style()

def deGumma(data):
    sdata = data / 255;
    if (sdata <= 0.04045):
        sdata = sdata / 12.92;
    else:
        sdata = ((sdata + 0.055) / 1.055)**2.4
    return sdata;

def scale_sRGB(sRGB):
    return np.array([deGumma(sRGB[0]), deGumma(sRGB[1]), deGumma(sRGB[2])])

def plot_sRGB_to_chromaticity_diagram_CIE1931(sRGB_list):
    # colour.plotting.plot_chromaticity_diagram_CIE1931(standalone=False)
    colour.plotting.plot_RGB_colourspaces_in_chromaticity_diagram_CIE1931(['sRGB'], standalone=False, diagram_opacity=0.5)

    for i, _ in enumerate(sRGB_list): 
        sRGB = scale_sRGB(sRGB_list[i])
        XYZ = colour.sRGB_to_XYZ(sRGB)
        xy = colour.XYZ_to_xy(XYZ)
        x, y = xy
        plt.plot(x, y, 'o-', color='white')

        # Annotating the plot.
        plt.annotate("sRGB"+str(i+1),
                    xy=xy,
                    xytext=(-50, 30),
                    textcoords='offset points',
                    arrowprops=dict(arrowstyle='->', connectionstyle='arc3, rad=-0.2'))

    # Displaying the plot.
    colour.plotting.render(
        standalone=True,
        limits=(-0.1, 0.9, -0.1, 0.9),
        x_tighten=True,
        y_tighten=True)
```

### 実行方法

```python
sRGB1 = [255, 0, 0]
sRGB2 = [0, 127, 0]
sRGB3 = [0, 0, 1]
sRGB4 = [1, 1, 0]
sRGB5 = [0, 1, 1]
sRGB6 = [1, 0, 1]
sRGB_list = [sRGB1, sRGB2, sRGB3, sRGB4, sRGB5, sRGB6]
plot_sRGB_to_chromaticity_diagram_CIE1931(sRGB_list)
```

### 実行結果

![xy_sRGB.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/204935/28f262a6-1838-a0b5-eef0-eca1e1ac58b9.png)

## 参考

- https://www.colour-science.org/
  - https://colour.readthedocs.io/en/develop/colour.plotting.html
  - https://colour.readthedocs.io/en/develop/generated/colour.sRGB_to_XYZ.html
  - https://colour.readthedocs.io/en/develop/generated/colour.XYZ_to_xy.html
  - https://colour.readthedocs.io/en/develop/tutorial.html#convert-to-chromaticity-coordinates
ショートカット使わないと仕事は速くなりません

## はじめに

新卒として現場に配属されて早３ヶ月。ウィンドウの切り替えをマウスでポチポチやっていた自分に、上司から一言。「ショートカットキーを使わないと仕事は速くならないですよ。」

※以下、ショートカットキーをショトカと表記する

## なぜショトカを使っていなかったのか

結局、ショトカを使ったときに受けられる恩恵を分かっていなかったのだと思います。自分は指摘されたときに、上司の操作画面を見せてもらえたので、今までの自分の操作がどれだけ無駄だったのかを痛感することができました。

今どき、ショトカの記事なんて腐るほどありますし、ショトカの本だって沢山出版されています。それでも、あなたがショトカを使っていなければ「恩恵を理解していない」以外の理由はないでしょう。


## ショトカの恩恵を理解する

ここまで読んで、ショトカをあんまり使ってないなと思ったあなたは、すぐにこの記事を閉じて周囲の作業が速い人の画面を覗きましょう。

最近はリモート会議が増え、画面共有で他人の操作画面を見る機会も増えました。そういうときに意識して他人の操作スピードを見てみるのもいいでしょう。

その際に、「あえてショトカを使わない場合、この人よりキー操作の速度が落ちるわけだが、自分は他の何で挽回するのか？」と考えると、ショトカくらい体得しよう…となるはずです。

どうしても、今すぐその恩恵を理解したいあなたは、以下の動画がおすすめです。

https://youtu.be/Yo1IWySlAG8

パワポのショトカに関する動画ですが、操作スピードが劇的に速くなることを見せつけられます。また、「ショトカを使い始めてから最初の二週間は慣れないので作業が遅くなる。しかし、その後は劇的に速くなる。」といった話もあり、ショトカに慣れない期間の支えになります。


## 今すぐショトカを調べたくなったあなたへ

ここまで記事を読んだあなたは、ショトカの恩恵を理解し今すぐ体得したくなったに違いありません。

しかし、勢いに任せてイチから調べると、ショトカで浮く時間をショトカ調査で相殺してしまいます。

そんなあなたに朗報です。様々なショトカを分かりやすく紹介しているチャンネルがあります。それなりの本数の動画があるので、まずはこのチャンネルの中で自分に合った情報を探すようにしましょう。

効率アップコンサルタント【みや】
https://www.youtube.com/channel/UCSNIr_KmbN-VKYt3tkcTA4A

余力があれば、キーの配置を変えたり、自分だけのショトカを作ったりすると更に効率が上がります。

https://qiita.com/riekure/items/49b941fa5159f9948313



## 終わりに

ショトカ操作がまだ慣れなくて、絶賛作業速度低下中…
Shareオブジェクトについて

レコードレベルのセキュリティの設定を行う場合、大体は共有設定やロール階層の設定で設定する側の作業は終わりで、後は使う側が直接共有をすることがほとんどだと思います。こういったレコード共有の情報はどこで管理されているのでしょうか？

#Shareオブジェクト
Salesforceには、レコードの共有を管理するオブジェクトとして、**各オブジェクトごとに**Shareオブジェクトなるものが存在しています。ShareオブジェクトのAPI名は以下のようにされています。

標準オブジェクトの場合：AccountShare, OpportunityShare, ContactShare, etc...
カスタムオブジェクトの場合：CustomObject名__Share

項目は以下の通りです。詳しくは[こちら](https://developer.salesforce.com/docs/atlas.ja-jp.apexcode.meta/apexcode/apex_bulk_sharing_creating_with_apex.htm)を参照してください。

| 項目 | データ型 | 説明 |
|:-:|:-:|:--|
| ParentID  | 参照  | 共有するレコードのIDです。  |
| UserOrGroupId  | 参照  | 共有先のユーザ・グループのIDです。  |
| AccessLevel  | picklist  | レコードへどの程度アクセスできるのかを指定します。<br> 値は以下の通りです。<br>Read:参照可能<br>Edit:編集可能<br>All:すべて可能 |
| RowCause  | picklist  | 共有の理由です。主な値は以下の通りです。<br>Manual<br>Owner<br>Rule<br>...<br>以上の値以外の独自の理由も設定することができるらしいです。（Apex共有の理由）  |

:::note
通常はレコードの所有者が変更されれば、共有は解除されてしまいます。
しかし、RowCauseに独自の理由を設定した場合は、所有者の変更では共有が解除されません。
:::

このオブジェクトのレコードをどうにかして作成すれば、個人に対するレコードの共有ができるわけです。
このレコードを作成する方法はいくつか考えられます。

+ Data Loaderなどで、Shareオブジェクトのレコードを作成する。
+ Apexトリガを用いて、Shareオブジェクトのレコードを作成する。（これなら、個人レベルの共有も自動化できます。）
+ フローを用いて、Shareオブジェクトのレコードを作成する。（後述）

#フローを使って共有を自動化する
レコードトリガーフローを使用して、Shareオブジェクトのレコードを作成することで、特定の状況におけるレコードの共有を自動化することができます。~~なんでもできるなフロー君~~
8/31に開催された[Salesforceの共有設定をマスターしよう！ 〜 Sharing & Visibility〜](https://cs.salesforce.com/events/7013y000002hMB7AAM)にて示された例を借りて、実際にやってみます。

####シチュエーション
応募者に対して面接官（Salesforceユーザ）を設定した際、その面接官も応募者レコードを参照できるようにしたい。
####解決
レコード保存後のトリガーフローをします。
トリガー条件としては、「面接官項目が空白ではない・条件に一致する度にトリガ」でいいと思います。
キャンバスに配置する要素は「レコードを作成」要素だけでいいでしょう。面接官の変更とかを考慮すると、他の要素も検討したほうがいいんじゃないかなって思いますが。~~面倒なので今回はスルーしますが。~~

実際に作成した要素がこちらです。
![レコード作成要素](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1261412/eba6e5bb-df22-511b-3244-1f0100503ced.jpeg)

後は、この要素と開始要素を結んでフローを保存・有効化でOK！

:::note warn
フローを実際に動かす前に、応募者オブジェクトの組織の共有設定を「非公開」にしておきましょう。
組織の共有設定で付与したアクセス権限以下のアクセス権限は付与できません。（すでに組織の共有設定で付与されている為。）
:::
####動作確認
実際に動かしてみましょう。まだ面接官を設定していない応募者・クックさんのレコードがあります。
![クック](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1261412/9d260596-2276-907e-aa05-da635e9cdd7b.jpeg)
共有階層から、アクセスできる人を確認できます。アクセスできる人は下画像の通りです。（モザイクは私自身の名前が入っています。）
![ベネット・NoAccess](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1261412/0f924a10-13e8-5cb1-d87a-70e9ab8906cc.jpeg)
では、面接官をベネットさんに設定しましょう。
![ベネットを設定](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1261412/b677a83d-d316-f09c-c144-0096a213bbdf.jpeg)
共有階層から、アクセスできる人を確認すると…
![bandicam 2021-09-04 13-49-54-114.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1261412/147c5870-c3e8-becf-c07d-24bb8dca594f.jpeg)
このレコードにアクセスできる人にベネットさんが追加されました。うまく共有をかけられたようですね。

#あとがき
[Salesforceの共有設定をマスターしよう！ 〜 Sharing & Visibility〜](https://cs.salesforce.com/events/7013y000002hMB7AAM)に参加して、初めて共有オブジェクトなるものの存在を知り、フローでもレコード共有の設定ができると聞いて、早速試してみました。いやはやこんなことまで出来るのか、と感心までしてしまいましたね。

記事に書くための検証をしていた時に、フローを組んで有効化していざ動作確認！って動作させたら、「INSUFFICIENT_ACCESS_ON_CROSS_REFERENCE_ENTITY: insufficient access rights on cross-reference id」
ってエラーが出たんですよね。

ちょうどSalesforce Saturdayに参加していたのでSOSを投げたのですが、その後に新しくPlaygroundを立ち上げてもう一回やりなおしたら、うまくいきました。Salesforce Saturdayに参加していた皆様、お騒がせして申し訳ありませんでした。
TrueNASにアプリを幾つか入れて使ってみた

前身のFreeNASを遅くとも2010年初頭には使っていて、当時からjailに対応していた気もするのだが、データ置き場として以外の使い方をあまりしてこなかった。最近になっていくつかTrueNAS向けに用意されているアプリ（プラグイン、実装的にはjail）を動かしてみたので、気がついたことなどを書いておこうと思う。
TrueNASのインストールについては省略。解説記事はそこそこあるし、とりあえずデータ置き場として使うだけなら正直困ることはない。
TrueNAS本体はいわゆるPCサーバ、Pentium N3700が搭載されたN3700Mマザーボードを使った自作PCを使っている。家庭用ルータ下にぶら下げてありIPアドレス利用に不自由はなし。192.168.1.102を割り当ててある。


以下、アプリを入れたらリンクを追加する。
- [Nextcloud編](https://qiita.com/exthnet/items/49cb2229a256feb1db52)
- [Plex Media Server編](https://qiita.com/exthnet/items/409b5cdccd9324a681e1)
- [gitlab編](https://qiita.com/exthnet/items/cf9871fa24ce23ba940f)
- FAMP ……LAMP (Linux, Apache, MySQL, PHP)のLinuxをFreeBSDに変えた版。インストールしてアクセスしたら「It works!」が出る時点で特に書くことないんじゃね？
Vue3のComposition APIにおけるpropsの型注釈

## String

```html:
export default defineComponent({
  props: {
    value1: {
      type: String,
      required: true,
    }
  }
});
```

## Number

```vuejs:
export default defineComponent({
  props: {
    value1: {
      type: Number,
      required: true,
    }
  }
});
```

## Array

```vuejs:
import { defineComponent, PropType } from "vue";
export default defineComponent({
  props: {
    value1: {
      type: Array as PropType <number []>,
      required: true,
    }
  }
});
```

## Object

```vuejs:
import { defineComponent, PropType } from "vue";
export default defineComponent({
  props: {
    value1: {
      type: Object as PropType <{value: string, value2: number}>,
      required: true,
    }
  }
});
```

## Function

```vuejs:
import { defineComponent, PropType } from "vue";
export default defineComponent({
  props: {
    value1: {
      type: Function as PropType <() => Number>,
      required: true,
    }
  }
});
```
【Laravel】Trying to get property '〇〇' of non-object(View: /〜/views/menu/index.blade.php) の解決方法

#エラー概要
このエラーは、〇〇に値が入っていないのに、プロパティを参照しようとしてるよっていうエラーです。

#エラー発生時のコード

```php:menu/index.blade.php
@foreach ($items as $item)
    <tr>
        <td>{{$item->time}}</td>
        <td>{{$item->user->name}}</td>
    </tr>
@endforeach
```

```php:MenuController.php
public function index(Request $request)
{
    $items = Menu::with('user')->get();
    return view('menu.index',['items' => $items]);
}
```


#解決方法
値がなくてもnullを返してくれるようにヘルパー関数`optional()`を使います。

```php:menu/index.blade.php
@foreach ($items as $item)
    <tr>
        <td>{{$item->time}}</td>   
        <td>{{optional($item->user)->name}}</td>
    </tr>
@endforeach
```
[参考文献](https://qol-kk.com/wp2/blog/2018/12/19/post-992/)

#おわりに
結構苦戦したけど、案外簡単な方法でした。
Linuxのuniqコマンドに相当するコードをPythonで実装してみた

Linuxの[uniqコマンド](https://atmarkit.itmedia.co.jp/ait/articles/1611/14/news021.html)に相当するコードをPythonで実装してみました。オプションは-c、-u、-d実装しました。

```
.
├── uniq.py
├── test.txt
```

```uniq.py
import sys


def uniq(f):
    previous_line = ""
    for line in f.readlines():
        if previous_line == line:
            continue

        print(line, end="")
        previous_line = line


def uniq_c(f):
    previous_line = ""
    count = 1
    for line in f.readlines():
        if previous_line == "":
            previous_line = line
            continue

        if previous_line == line:
            count += 1
            continue

        print("{} {}".format(count, previous_line), end="")
        previous_line = line
        count = 1

    print("{} {}".format(count, previous_line), end="")


def uniq_u(f):
    previous_line = ""
    is_unique = True
    for line in f.readlines():
        if previous_line == "":
            previous_line = line
            continue

        if previous_line == line:
            is_unique = False
            continue

        if is_unique:
            print(previous_line, end="")

        previous_line = line
        is_unique = True

    if is_unique:
        print(previous_line, end="")


def uniq_d(f):
    previous_line = ""
    is_repeated = False
    for line in f.readlines():
        if previous_line == "":
            previous_line = line
            continue

        if previous_line == line:
            is_repeated = True
            continue

        if is_repeated:
            print(previous_line, end="")

        previous_line = line
        is_repeated = False

    if is_repeated:
        print(previous_line, end="")


func_dictionary = {"-c": uniq_c, "-u": uniq_u, "-d": uniq_d}
try:
    if len(sys.argv) > 1:
        f = open(sys.argv[-1], "r")
        if len(sys.argv) == 2:
            uniq(f)
        elif len(sys.argv) == 3:
            if func_dictionary.get(sys.argv[1]):
                func_dictionary.get(sys.argv[1])(f)
            else:
                print("args:[-c|-u|-d]")
    else:
        f = sys.stdin
        uniq(f)
except FileNotFoundError:
    print('Error: File {0} is not found.'.format(sys.argv[1]), file=sys.stderr)
    sys.exit(1)
```

```test.txt
aaa
bbb
aaa
aaa
AAA

```

以下が出力結果です。

```
$ python uniq.py test.txt
aaa
bbb
aaa
AAA
```

```
$ python uniq.py -c test.txt
1 aaa
1 bbb
2 aaa
1 AAA
```

```
$ python uniq.py -u test.txt
aaa
bbb
AAA
```

```
$ python uniq.py -d test.txt
aaa
```
SPFレコードにドメインとIPアドレスを登録する方法

## 設定方法

`include:ドメイン`と`ip4:IP4アドレス`を使って記載します｡

たとえばAWS-SES経由とサーバ（IPアドレス=`12.34.56.78`）から直接送信する場合は以下のように記載します｡

```
"v=spf1 include:amazonses.com ip4:12.34.56.78 ~all"
```

## 検証方法

以下のツールで設定がちゃんと認識されているか確認できます｡

[SPF Check & SPF Lookup - Sender Policy Framework (SPF) - MxToolBox](https://mxtoolbox.com/spf.aspx)

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

## 参考サイト

[送信ドメインを認証するためのSPFレコードに詳しくなろう](https://sendgrid.kke.co.jp/blog/?p=3509)
[Amazon SES における SPF を使った E メールの認証 - Amazon Simple Email Service Classic](https://docs.aws.amazon.com/ja_jp/ses/latest/DeveloperGuide/send-email-authentication-spf.html)
[SPF（Sender Policy Framework） : 迷惑メール対策委員会](https://salt.iajapan.org/wpmu/anti_spam/admin/tech/explanation/spf/)
IBM Cloudの新認定試験IBM Cloud Technical Advocate v3を受けてみた

# IBM Cloud Technical Advocate v3とは

IBM Cloudの認定技術者の1つで、2021年8月中旬から受験可能になりました。レベル感としては、エンジニア向けの最も入門的な試験となります。

IBM Cloud Technical Advocate v3に合格すると、**IBM Certified Technical Advocate - Cloud v3**の認定資格を得ることができます。もちろんOpen Badgeももらえます。

<img width="160" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/241424/7671d101-7abe-4d98-2ed6-8558687ee733.png">

さて、IBM Cloud認定資格マニアなら、あれっ、と思うかもしれません。似たような資格が最近できたのではないか、と。はい、過去記事で書いているとおり、非常に似た名前の資格がすでにあります。

https://qiita.com/teruq/items/1bb67c516dd73c7a1ef8

とてもややこしいのですが、もともとIBM Certified Solution Advisor v2と呼んでいた試験は2021年9月末で終了し、後継としてIBM Cloud Technical Advocate v3という名称になりました。一方、それとは別に2021年7月からIBM Cloud Advocate v1という試験ができました。似ていますが別試験なので注意ください。

試験の概要はこちら。

> https://www.ibm.com/certify/exam?id=C1000-125

認定資格の概要はこちら。

> https://www.ibm.com/certify/cert?id=C0002202

# 学習方法

IBM Cloudを利用したシステム構築をしているエンジニアであれば目を半分瞑っても合格可能なレベルです。一から学習する、または自信のない方は、下記サイトでラーニングパスが公開されています。

> https://www.ibm.com/training/path/ibmcloudtechnicaladvocate

# 受験方法

PearsonVUE社のサイトで予約して受験してください。

https://www.pearsonvue.co.jp/Clients/IBM.aspx

以前は最寄りのテストセンターでしか受験できなかったのですが、最近はカメラ付きPCがあれば自宅でも受験可能になりました。こういうご時世ですので、可能であれば自宅での受験をお勧めします。ただし部屋の片づけはきちんとしておいてください。

# 合格点

64問中42問以上の正解で合格です。正答率は65%です。IBMの認定試験では甘い方だと思います。

# 出題内容

試験規約により具体的な問題文は書けませんので、雰囲気になりますが、いくつか問われそうな箇所を書きます。

* Cloudとは
* Cloud Nativeとは
* Kubernetesとは
* IBM Cloud Pakとは
* VPCとネットワークコンポーネント
* VPCとセキュリティ
* VMwareソリューション
* クラウドストレージ3種の特性
* Watson関係のサービス
* IAM、権限とリソースの関係
* IBM Cloudのサポート

このあたりを抑えておけば合格できると思います。

# 感想

前バージョンのv2は少々難易度が高めだったのですが、その反省からか、難易度が大幅に下がった印象です。ようやく入門者向け資格になったかなと思います。

https://qiita.com/teruq/items/b36655d0b31ddc8861fe
AWS DBサーバーの起動からMySQLのインストール


*[WEBサーバー用EC2の起動からWEBページの表示まで](https://qiita.com/ebtiag/items/c75140c59d59a620f89e)の続き

アプリケーションデプロイ用の基本構成のEC2インスタンス起動方法についてメモ
簡単なことですが、たまに不安になるので。

VPC内に、パブリックサブネットにWEBサーバー用のEC2と
プライベートサブネットDBサーバー用のEC2を構成していきます

##事前準備
###VPC
WEBサーバーのインスタンスを起動したときVPCを用意（何用かわかりやすい名前を付けましょう）

###サブネット
WEBサーバーのインスタンスがるVPCにプライベート1aを用意
（冗長構成用にプライベート1cがあってもなくても）

##DBサーバー用のインスタンス起動設定
###インスタンスタイプの選択
無料利用枠のt2.micro

###インスタンスの詳細設定
ネットワーク：事前に用意したデフォルトのものではないVPC
サブネット：プライベートサブネット1a
自動割り当てパブリックIP：無効

###タグの追加
キー：Name
値：[アプリ名]-DBserver-1a

###セキュリティグループの設定
セキュリティグループの割り当て：新しいセキュリティグループを作成する
セキュリティグループ名:[アプリ名]-DBserver-sg
説明：[アプリ名]-DBserver-sg
ルールの追加：MySQL/Aurora 0.0.0.0/0

##ファイルを更新するためにNATゲートウェイを作成
VPC→NATゲートウェイ　を選択
NATゲートウェイを作成　を押す
名前：わかりやすいもの
サブネット：パブリック1a
ElasticIPを割り当てる
作成　を押す

##プライベートのルートテーブルを通す
サブネット→プライベート1a→ルートテーブルタブ→ルートテーブル→
ルートタブ→ルートを編集　を選択
（バックホールになっているものがあったら削除）
ルートを追加　を選択
送信先：0.0.0.0/0
ターゲット：つくったNATゲートウェイ

##MYSQLをインストール

###インスタンスにSSHで接続する

*パブリックサブネットのインスタンスからプライベートサブネットのインスタンスに入る
*WindowsはTeraTermなどを起動
*パブリックサブネットにあるインスタンスのパブリックIPv4アドレスをコピー
*ホスト(T)：[インスタンスのIPv4アドレス]
*ユーザー名：ec2-usr
*RSA/DSA/ECDSA/ED25519鍵を使う
*インスタンスを起動したときにダウンロードしたキーペアを選択

###プライベートサブネットのインスタンスに入っていく
```sudo su
vi myprivatekey.pem```
*キーペアの内容を入力し保存
```chmod 400 myprivatekey.pem
ssh ec2-user@[プライベートインスタンスのIPアドレス] -i myprivatekey.pem
yes```

###MYSQLをインストールする
```sudo su
yum update -y
yum localinstall https://dev.mysql.com/get/mysql80-community-release-el7-1.noarch.rpm -y```
↑[公式サイト](https://dev.mysql.com/downloads/repo/yum/)でOS等を確認

```yum install mysql-community-server -y```

##MYSQL起動
```systemctl start mysqld```
インスタンスが起動されるとmysqldも起動させるようにする
```systemctl enable mysqld```


###データベースを作成してみる
MySQLにアクセスするパスを作成する
```cat /var/log/mysqld.log | grep localhost```
一時ユーザーのパスワードが発行される（赤字の右）
```mysql -u root -p```
発行されたパスワードを入力しエンター

*パスワードを変更
```alter user root@localhost identified by '一時発行パスワード';
create database test;
show databases;```

###NATゲートウェイを削除
MySQLの設定が終わったらNATゲートウェイを削除して、
ElasticIPも削除する
Node.jsでDiscordBotを作るのに苦戦した話

# 導入
私はしばらくの間、Discord Botを開発していました。
私はPythonの経験があるのではじめはDiscord.pyを使ってBotを開発していましたが、どうやらDiscord.pyのサポートが終了するということで今回Discord.jsに乗り換えることにしたわけです。

:::note
**追記**
discord.pyのサポートは一旦打ち切られましたが、結局[継続することになった](https://gist.github.com/Rapptz/c4324f17a80c94776832430007ad40e6)らしいです。まあ、サポートされるなら無理に乗り換える必要はなさそうです。 
これは余談ですが、PythonでDiscord Bot作るならdiscord.pyの派生ライブラリである、pycordを使うのをおすすめします。discord.pyはスラッシュコマンドに対応していませんが、pycordは対応しています。discord.pyから乗り換える場合でもコードの書き換え量はそこまで多くないです。 
:::



Node.jsとDiscord.jsの記事は比較的少なく、２つのポイントで***大変苦戦***しましたので備忘録として残しておきます。

# 1. 環境構築で苦戦

まず私がDiscord.jsを動かす環境をつくるにあたって、Qiitaのこちらの記事[「Discord.js でボットを作る ～発言させるまで～」](https://qiita.com/yuto0214w/items/1ecee25efca6b5b7445b)を参考にしました。
これをコピペしてLinux上で実行すれば移行なんて簡単。と思っていたのですが…

これ、***うまくはいかない***んですよねぇ。

## エラーに悩む
記事通りにNode.js,npm,discord.jsをインストールしたのにエラーが出るんです。しかも調べてもよい記事がありません！これは困った。。。

悩みに悩んで[かかぽ鯖](https://mwindows99.com/discordserver?utm_source=qiita&utm_medium=web)で質問しました。

...すると衝撃的な事実が発覚しました。それはなんと、、、

***discord.jsはnode.jsはv14以上、npmはv7以上必要***

だったのです！！discord.jsの仕様書を見ればよかったのかもしれませんが、これはトリックですよね。

## Linux標準リポジトリのものは最新バージョンではない

私は、Ubuntu Serverに

```bash
sudo apt install node.js npm
``` 

と実行し、最新版を入れていたつもりでした。

しかしこれでインストールされるのは***Nodeはv10、npmはv6***なんです（2021/09/04時点）。

2021/09/04時点での最新バージョンは***Nodeはv16.8、npmはv7.21***です。

__Linuxの標準リポジトリのものは最新バージョンであるとは限らない__ので注意してください。

||Discord.js<br>動作環境|標準リポジトリ<br>最新バージョン|公式リポジトリ<br>最新バージョン|
|:-:|:-:|:-:|:-:|
|**Node.js**|v14以上|v10|v16.8|
|**npm**|v7以上|v6|v7.21|

:::note
動作環境が適切か確認することが大切です。
:::

## 解決策: 公式のリポジトリから最新のNode.jsとnpmを入れる

では、以下のようにコマンドを実行して最新版をいれていきましょう！

```bash
# 公式のリポジトリを追加
$ curl -sL https://deb.nodesource.com/setup_16.x | sudo bash -

# パッケージの更新
$ sudo apt update

# インストール
$ sudo apt install -y node npm
```

これで最新バージョンが入りました。

```bash
$ node -v
16.8.0

$ npm -v
7.21.0
```

ここまでが***初めに***躓いた部分です。

# 2. 再度エラーに悩む
正直原因は上記のものだと思っていたのでこれで解決するだろうと思い、[この記事](https://liginc.co.jp/370260)を参考に以下のコードを保存しました。

```main.js
const Discord = require('discord.js');

const client = new Discord.Client();

const token = 'アクセストークン';

client.on('ready', () => {
    console.log('ready...');
});

client.login(token);
```

...エラーが出ました。またか。。。今度も何が原因なのかわかりません。

ということで再度[かかぽ鯖](https://mwindows99.com/discordserver?utm_source=qiita&utm_medium=web)にて質問すると[りすりす氏(@TwoSquirrels)](https://twitter.com/twosquirrels)から

```javascript
new Discord.Client();
```

を以下のように変更するとよいとアドバイスをいただきました。

```javascript
new Discord.Client({ intents: [Discord.Intents.FLAGS.GUILDS] });
```

:::note warn
Intentsを指定していなかったことが原因でした
:::

## 結果
なんと動きました！！！！！

感動です。
Node.jsとDiscord.jsでBotがログインできました。

 - 追記

あとは[こちら](https://qiita.com/gaato/items/55b32bc4777905ac162a)の記事を参考にすればDiscord.pyからDiscord.jsへの移行は簡単です。自分の環境でも動作することを確認しました。かなり詳しく書かれているのでわかりやすいと思います。

# まとめ
今回は以下の２点で見事躓きました。

- Node.js, npm の導入
- Intentsの指定

これは備忘録として残します。

助けていただいた方には本当に感謝しています。ありがとうございました。
delegateを使って、カスタムviewから画面遷移する

# はじめに
業務でカスタムviewから画面遷移を行いたい場面がありました。
その時に今まで理解が曖昧だったデリゲートを使う機会があり、
理解が少し明確になったので紹介します。

# 環境
`macOS Big Sur 11.5.2`
`Xcode 12.5.2`
`Swift 5.4.2`

# ゴール
画面Aには、カスタムビューで実装されたボタンがあります。
今回は、カスタムビューで実装されたボタンがタップされたタイミングで画面Bに遷移したいです。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/551042/f18d28f4-c37e-1e59-4b03-897dde5d5acf.gif" width="300" />

# 概要
デリゲートを使ってゴールを実現します。
ざっくり次のような手順で実装を進めます。
まず、CustomViewにプロトコルを定義します。
ボタンがタップされたタイミングでデリゲートメソッドが実行されることを定義します。
そして、デリゲートメソッドの実装は`ViewController`へ委譲します。


# 具体的な実装
1. カスタムビューにプロトコルを定義します。

```swift:CustomView.swift
protocol CustomViewDelegate {
  didTapButton()
}
```

2. ボタンがタップされた時にデリゲートメソッドが実行されることを定義します。

```swift:CustomView.swift
@IBAction func tapButton(_ sender: UIButton) {
  delegate?.didTapButton()
}
```

3. 処理の中身の実装を`ViewController.swift`に委譲します

```swift:ViewController.swift
override func viewDidLoad() {
  super.viewDidLoad()
        
  let customView = CustomView()
  customView.delegate = self
}
```

4. デリゲートメソッドの中身を実装します。

```swift:ViewController.swift
extension ViewController: CustomViewDelegate {
  func didTapButton() {
    guard
      let nav = navigationController,
      let secondVC = storyboard?.instantiateViewController(identifier: "second")
    else { return }
    nav.pushViewController(secondVC, animated: true)
  }
}
```

# まとめ
メソッドを実行するタイミングを`CustomViwe`で定義して、
実装は`ViewController`に委譲(デリゲート)する。
今まで曖昧だったデリゲートという概念を少し掴めた感じがしました。
【Python】seleniumなどでWebスクレイピングする際に入力するIDとパスワードをローカルPCのテキストから読み込む方法

#はじめに
seleniumなどのライブラリを使ってwebサイトに自動ログインする際に
プログラムに直接IDやPWを記載していませんでしょうか。
これはハードコーディングと言って、セキュリティ的に推奨されていません。
そこでローカルPC上にIDやPW情報をおいて、それを読み込む方法を記載します。
簡単なので参考になれば幸いです。

#前提
pyrhon3.7
macOS Catalina(10.15.7)
(Windowsでもほぼ同じ手順です。)

#事前準備
1.まずIDとPWを記載したtxtを作成します。
![スクリーンショット 2021-09-04 12.20.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1966337/dc93d731-7ad8-b77f-48b1-14b60dea293c.png)

2.IDの内容は以下にし、任意の場所に保存します。
　/Users/Hiroki/Info/ID.txt
![スクリーンショット 2021-09-04 12.24.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1966337/ed1ff5ce-88bf-ef7d-fe3a-9e51b37ef81e.png)

3.PWの内容は以下にし、任意の場所に保存します。
　/Users/Hiroki/Info/PW.txt
![スクリーンショット 2021-09-04 12.25.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1966337/4c9232e0-5d83-eec5-968f-15cf5134fd8a.png)

#プログラム

```python:ID_PW.py
ID = open("/Users/Hiroki/Info/ID.txt", 'r', encoding='UTF-8')
IDdata = ID.read()
print(IDdata)

PW = open("/Users/Hiroki/Info/PW.txt", 'r', encoding='UTF-8')
PWdata = PW.read()
print(PWdata)
```
#実行結果
![スクリーンショット 2021-09-04 12.32.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1966337/5be4f60a-7a73-8abf-00e8-da2c2950a013.png)

記載したテキストの内容がprintされました。
WEBスクレイピングでIDやPWの入力に利用される場合は、
定義した"IDdata"や"PWdata"で読み出せばOKです。
printを残すと実行結果に出力されますので、削除かコメントアウトしましょう。

以上ご参考になれば幸いです。
1から123の約数の和 python


####numを1から36までの自然数で割り算し、余りが0の場合に出力していきます。

```
num = 123
a = []
for i in range(1, num+1): #1~123まで
    if num % i == 0:
      a.append(i)　#配列に入れる

b = sum(a) #配列の総和
print(b)
```
Codeforces Rond #739 (Div. 3)　解いた感想

## A. Dislike of Threes
https://codeforces.com/contest/1560/problem/A
### 考えたこと
3で割り切れる整数と一の位が3の数を除いて，それ以外の整数を配列に入れました．配列の一番最初に適当な数を入れておくと，添え字とkが一致します．

```c++
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
#define rep(i,n) for(ll i=0; i<(n); i++)

int main() {
    int t; cin >> t;
    vector<ll> v;
    v.push_back(0);
    for(ll i=1; i<=100000; i++){
        if(i%3 == 0 || i%10 == 3) continue;
        v.push_back(i);
    }
    rep(i,t){
        ll k; cin >> k;
        cout << v[k] << endl;
    }
    
    return 0;
}
```

## B. Who's Opposite?
https://codeforces.com/contest/1560/problem/B?locale=en
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/610684/cea826e3-198a-62d0-f3fb-28ae1c007cdd.png)

$c \leq N$ のとき，答えは$c+N$
$c>N$のとき，答えは$c-N$
答えが存在するための条件は，$1\leq a, b, c \leq 2N$

```c++
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
#define rep(i,n) for(ll i=0; i<(n); i++)

int main() {
    ll t; cin >> t;
    rep(i,t){
        ll a, b, c;
        cin >> a >> b >> c;
        ll n = abs(a-b);
        if(a>2*n || b>2*n || c>2*n) cout << -1 << endl;
        else if(c<=n) cout << c+n << endl;
        else cout << c-n << endl;
    }
    return 0;
}
```
## C. Infinity Table
数字の配置は下の図のようになっています．バームクーヘンの層みたいに考えたとときに，与えられた数字が最初から何番目の層なのか？を変数$k$を使って表しています．この$k$を二分探索を用いて予め求めておきます．下図の2つ目のような，（添え字番号）＾２の配列を用意して，lower_boundを使って求めます．kが求まったら，入力された数字から$(k-1)^2$を引くと，層の中でその数字が何番目に位置しているかが分かります．その後は，頑張って答えを出します．

https://codeforces.com/contest/1560/problem/C

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/610684/2e220f5f-4f26-31f9-bccf-eda3746f9d60.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/610684/676c02a5-61ff-0fe9-e755-2d9ecf6fdda1.png)

```c++
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
#define rep(i,n) for(ll i=0; i<(n); i++)
#define all(x) (x).begin(), (x).end()
#define lb(c, x) distance((c).begin(), lower_bound(all(c), (x)))

int main() {
    ll t; cin >> t;
    vector<ll> v;
    for(ll i=0; ; i++){
        if(i*i>1000000000) break;
        v.push_back(i*i);
    }
    rep(i,t){
        ll n; cin >> n;
        ll k = lb(v, n);
        ll sum = k*k-(k-1)*(k-1), h = n-(k-1)*(k-1);
        ll I, J;
        if(h<=(sum+1)/2){
            I = h;
            J = k;
        }else{
            I = k;
            J = k-(h-sum/2)+1;
        }
        cout << I << " " << J << endl;

    } 
    return 0;
}
```
S3内のZIPファイルをAPI経由でダウンロードする方法

## はじめに
ZIPファイルをAPI経由でダウンロードする方法について、意外とやり方が分からず手こずったため、メモとして残しておく。

## 事前準備
・S3にバケットを作成し、直下に任意のZIPファイルを格納しておく。
・ローカルPCにPython3系のインストール（ダウンロードファイルをデコードするために使用）

## 流れ

**１．ダウンロード用のAPIの準備**
　　1-1)．Lambdaの作成
　　1-2)．API Gatewayの作成


**２．ダウンロード後の変換**


## １．ダウンロード用のAPIの準備

### 1-1)．Lambdaの作成（Node.js 14.x）

```js:index.js
var AWS = require('aws-sdk')
var s3 = new AWS.S3()

exports.handler = async (event) => {
    
    
    var params = {
        Bucket: "バケット名", 
        Key: "ZIPファイル名"
    };

    const zip_data = await s3.getObject(params).promise()
    
    const response = {
        statusCode: 200,
        "headers": {
            "Content-Disposition": 'attachment; filename="download_filename.zip"',
            "Content-Type": 'application/zip'
        },
        // base64でテキストに変換している。
        body: zip_data.Body.toString('base64')
    }

    return response;
}
```

### 1-2)．API Gatewayの作成

・REST APIを構築
・GETメソッドの "統合リクエスト"内の『Lambda プロキシ統合の使用』のチェックを付ける。
　※このチェックを忘れると、URLを叩いた際`return`の中身がそのまま`JSON`形式で表示されてしまい、ファイルダウンロードが走らない。
![Qiita-no054_img01.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/654767/d1b8b838-ca15-2ec4-bd88-3fb466ea6ec3.jpeg)

このAPIから上記Lambdaを実行できる様にしたら、APIをデプロイしてURLを叩いてダウンロードできるか確認。（その他、特別な設定は不要。）


## ２．ダウンロード後の変換

１の手順によりAPI経由で（URLを叩くと）ZIPファイルがダウンロードできる様になったが、中身は元のZIPファイルの状態ではないため展開ができない。

そこで、以下の様にデコードして元の形に戻す必要がある。（Pythonで記載）

```py:
import base64

# ダウンロードしたZIPファイル
from_file_path = '【ダウンロードファイルが置いてあるパス】/download_filename.zip'

# base64でデコードして元の状態に戻したZIPファイル（作成場所）
to_file_path = '【出力したい場所のパス】/zip_decode_filename.zip'

with open(from_file_path, 'r') as f_file:
    data = f_file.read()
    print(data)
    
decoded_zip = base64.b64decode(data.encode())

with open(to_file_path, 'bw') as t_file:
    t_file.write(decoded_zip)
```

**上記を実行して作成されたZIPファイルは、展開もできて中身も元の状態となっている。**
【ざっくり理解】MVCモデルとは

#はじめに#
　プログラミングの設計モデルの一つに、MVCモデルというものがあります。初心者がぶつかる壁の一つです。（笑）
　今回はMVCモデルについて勉強してきましたので、そもそもMVCモデルってなに？処理を分けると何が良いの？どうやって分割すればいいの？といった観点からざっくりまとめていきたいと思います。


#MVCモデルとは#
　MVCモデルとは、プログラムをM(モデル)V(ビュー)C(コントローラー)に分割することです。それぞれの役割を見ていきます

####モデル####
　モデルでは、実際に処理を行う部分を担当しています。データベースへデータを保存したり、取り出したりといったことをやります。

####ビュー####
　実際にブラウザを通して、ユーザー側へ表示される部分を担当しています。

####コントローラー####
　モデルとビューを制御する部分になります。ユーザーからの入力に基づいて、モデルからデータを取得、または保存を指示し、ビューへと渡す、といったことをやっています。


#MVCモデルのメリット#
　では、処理を分割することでどんなメリットが得られるのでしょうか。一つずつ見ていきます。


####高い保守性####
　それぞれ役割分担されているので、保守性が高くなります。例えば、モデルに変更があった場合、ビューやコントローラーとは切り離されているのでモデルのみ変更するだけでOKです。MVCモデルを使用していない場合だと影響範囲が大きくなり、思わぬところでバグが出たりします。

####効率の良さ####
　MVCモデルでは、どこにどんな処理が書かれているかが分かりやすいです。複数人で開発する場合でも、どこにどんな機能があって、どこを修正すればいいか、といったことが共有しやすいので、非常に効率よく開発を進めることができます。

####コードを再利用しやすい####
　プログラミングで意識しなければならないことは、処理を共通化してなるべく少ない記述で済ませるということです。MVCモデルの場合、モデルに処理が細分化されて記述されている上、すでに機能しているものが多いので信頼性が高いので再利用しやすいです。


#MVCモデルの書き方#
　まずはコントローラーについてです。プログラムの一連の流れを記述します。あくまで処理はモデルに任せて、コントローラーではモデルとビューに指示を出すという部分のみ記述します。この時、モデルに記載する一つ一つの関数名がどんな処理を行う関数名か分かりやすいものだと、コントローラーの流れもわかりやすくなります。　
　
　次にビューについてです。こちらは主にHTMLを記述していくことになるかと思います。処理は書かずに、あくまでコントローラーから指示された内容を表示するという役割に徹します。
　
　最後にモデルについてです。モデルにはコントローラーから指示される処理内容を書いていきます。先ほども言いましたが、関数名はなるべくわかりやすく書くことを心がけましょう。また、処理はなるべく細分化して、一つの関数に一つの処理、といった形で書いていきましょう。こうすることで保守性が高まり、少ない行数で関数がかけるので可読性も上がります。


#まとめ#
　MVCモデルの書き方についてまとめてきました。いきなりは難しいので、少しずつ書き方に慣れていくのがいいでしょう。さまざまなフレームワークで使われているスタイルなので、しっかり理解できるように頑張りましょう！
[tmux] 分割したペインをtmux hooksで自動でリサイズする

# はじめに

tmuxを使って分割したペインで作業画面を一発で立ち上げているとターミナルウィンドウをリサイズした時にペインの比率が崩れてしまい、これが非常にストレスだった。
今回,tmux hooksなるもので解決できたのでまとめてみた。

#方法
すでに分割したことのある人は以下を `~/.tmux.conf` に以下を追加するだけでOK!

```
set-hook -g client-resized 'select-layout tiled'
```

以上。

tiledでは均等になるように自動配置されるが水平に均等分割、垂直に均等分割することもできる。(一部を抜粋)

```
select-layout even-horizontal // 水平均等分割
select-layout even-vertical //　垂直均等分割

```

トリガーにも他にも以下のようなものがある。(一部を抜粋)

```
     pane-died : paneで実行中のプログラムが終了した時。

     pane-exited :paneをexitした時。

     session-created :sessionを作った時。

     session-closed :sessionを閉じた時。
```

詳しくは以下をどうぞ
[tmux hooks 公式](https://man7.org/linux/man-pages/man1/tmux.1.html#HOOKS)



# 分割方法、分割したペインでのコマンド実行方法から知りたい人向け
## Pane４分割の方法

```
tmux new -t hoge\; \
split-window -h \; \
select-pane -t 0\; \
split-window -v \; \
select-pane -t 2\; \
split-window -v \; \
```
tmux コマンドを複数繋げるときは ; で繋げる。ターミナルではエスケープさせる必要があるため`\;`にする

## Pane 4分割 & それぞれのPaneで指定したコマンドを実行

```
tmux new -t hoge\; \
split-window -h \; \
select-pane -t 0\; \
split-window -v \; \
select-pane -t 2\; \
split-window -v \; \
send-keys -t 0 "echo hoge0" C-m\; \
send-keys -t 1 "echo hoge1" C-m\; \
send-keys -t 2 "echo hoge2" C-m\; \
send-keys -t 3 "echo hoge3" C-m\;
```

# 参考
- [How do I tell tmux to automatically resize panes after I kill a pane?](https://stackoverflow.com/questions/43181621/how-do-i-tell-tmux-to-automatically-resize-panes-after-i-kill-a-pane)
- [tmuxのペインを自動でセットアップしてもらうスクリプト](https://www.lisz-works.com/entry/tmux-pane-setup)
- [tmux hooks 公式](https://man7.org/linux/man-pages/man1/tmux.1.html#HOOKS)
LDAP とは

## 勉強前イメージ

認証系のプロトコル？

## 調査

### LDAP とは

Lightweight Directory Access Protocol の略で、
ディレクトリサービスというユーザや部署についてなどの情報を管理するサービスに
接続するためのプロトコルです。
LDAPは389ポートを使用し、
LDAPS(LDAP overSSL)は636ポートを使用します。

### ディレクトリサービス とは

ユーザやその人に関する組織情報、また人だけでなくサーバやプリンターなど
ネットワーク上の資源の属性や設定などを一元管理しているサービスになります。
現在は下記のような製品が普及している。

- Apple の Open Directory
- Microsoft の Active Directory

要するに、
Active Directoryを利用する際に内部ではLDAPプロトコルを使用して通信している、
ということになります。

## 勉強後イメージ

プロトコルなのかー
なにかでLDAP見たけどなんやろなぁって思ってスルーしてたけど
再度読み直さないと

## 参考

- [LDAPとは何をするもの？](https://thinkit.co.jp/free/tech/18/1/1.html)
- [LDAPとは？初心者でも理解できるLDAP入門レベルの内容をご紹介](https://www.fenet.jp/infla/column/server/ldap%E3%81%A8%E3%81%AF%EF%BC%9F%E5%88%9D%E5%BF%83%E8%80%85%E3%81%A7%E3%82%82%E7%90%86%E8%A7%A3%E3%81%A7%E3%81%8D%E3%82%8Bldap%E5%85%A5%E9%96%80%E3%83%AC%E3%83%99%E3%83%AB%E3%81%AE%E5%86%85%E5%AE%B9/)
anthy set up

```
# anthy
cd /usr/local/arch/
mkdir anthy
cd anthy/
curl -L https://ja.osdn.net/projects/anthy/downloads/37536/anthy-9100h.tar.gz/ -o anthy-9100h.tar.gz
cd /usr/local/src/
tar zxvf ../arch/anthy/anthy-9100h.tar.gz
cd anthy-9100h/
./configure 2>&1 | tee configure.log
make 2>&1 | tee make.log
sudo make install 2>&1 | tee make-install.log
vi .emacs
---add .emacs---
;; anthy
(setq load-path (cons "/usr/local/share/emacs/site-lisp/anthy/" load-path))
(load-file "/usr/local/share/emacs/site-lisp/anthy/leim-list.el")
(load-library "anthy")
(setq default-input-method 'japanese-anthy)
(define-obsolete-variable-alias 'last-command-char 'last-command-event)
(define-obsolete-function-alias 'string-to-int 'string-to-number)
----------------
```
almalinux8 setup log

```
# date
sudo date MMDDhhmm
timedatectl
timedatectl list-timezones
timedatectl set-timezone Asia/Tokyo

# selinux
sudo vi /etc/selinux/config
sudo reboot

#
sudo groupadd -g xxx xxx
sudo useradd -u xxx -g xxx -G wheel -c 'xxx' xxx
sudo passwd xxx

# nw
cd /etc/sysconfig/network-scripts
sudo mkdir OLD
cp -p ifcfg-ens192 OLD/ifcfg-ens192.202106040
sudo nmcli d show ens192
sudo nmcli c mod ens192 connection.autoconnect yes
sudo nmcli c mod ens192 ipv4.addresses xxx.xxx.xxx.xxx/xx
sudo nmcli c mod ens192 ipv4.gateway xxx.xxx.xxx.xxx
sudo nmcli c mod ens192 ipv6.method ignore
sudo nmcli c mod ens192 ipv4.dns xxx.xxx.xxx.xxx
sudo nmcli c mod ens192 ipv4.dns xxx.xxx.xxx.xxx
sudo nmcli c mod ens192 ipv4.method manual
sudo nmcli c down ens192; sudo nmcli c up ens192

# hostname
sudo vi /etc/hostname
sudo reboot

# yum
sudo yum -y update
sudo yum -y install open-vm-tools
sudo yum -y install gcc
sudo yum -y install make
sudo yum -y install sysstat
sudo yum -y install net-tools
sudo yum -y install python3
sudo yum -y install emacs
sudo yum -y install lsof
sudo yum -y install strace
sudo yum -y install nmap-ncat
sudo yum -y install tcpdump
sudo yum -y install binutils
sudo yum -y install epel-release
sudo yum -y install screen
sudo yum -y install perl

# rsyslog
sudo yum -y install rsyslog

# sudoers
cd /etc/
sudo cp -p sudoers OLD/sudoers.2021060501
sudo visudo
sudo diff OLD/sudoers.2021060501 sudoers
=====
88c88
< Defaults    secure_path = /sbin:/bin:/usr/sbin:/usr/bin
---
> Defaults    secure_path = /sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin
=====

# rsyslog
cd /etc/
sudo b rsyslog.conf
sudo vi rsyslog.conf
--- diff rsyslog.conf OLD/rsyslog.conf.2021062001 ---
28,30d27
< $umask 0000
< $DirCreateMode 0755
< $FileCreateMode 0644
---
sudo systemctl restart rsyslog

# logrotate
cd /etc/
sudo b logrotate.conf
sudo vi logrotate.conf
=====
6c6
< rotate 4
---
> rotate 12
9c9
< create
---
> create 0644 root root
15c15
< #compress
---
> compress
=====

# sysstat
cd /usr/lib/systemd/system
sudo b sysstat-collect.timer
sudo b sysstat-collect.service
sudo systemctl edit sysstat-collect.timer
# /etc/systemd/system/sysstat-collect.timer.d/override.conf
---
[Unit]
Description=Run system activity accounting tool every 1 minutes

[Timer]
OnCalendar=*:00/1

[Install]
WantedBy=sysstat.service
---

sudo yum install clamav
sudo yum install clamav-update
sudo freshclam
leetcord python3 9. Palindrome Number(回文数)

###整数xが与えられた場合、xが回文整数の場合はtrueを返します。という問題

・回文数 「しんぶんし」のようにさかさに読んでも同じ文になる文を回分といいますが、12321のように逆さから読んでも同じ数になる数を回文数といいます。

####問題（翻訳）
整数は、前方と後方で同じように読み取られる場合、回文です。 たとえば、121は回文ですが、123はそうではありません。
例1：

入力：x = 121
出力：true
例2：

入力：x = -121
出力：false
説明：左から右に、-121と表示されます。 右から左に、121-になります。 したがって、それは回文ではありません。
例3：

入力：x = 10
出力：false
説明：01を右から左に読み取ります。 したがって、それは回文ではありません。
例4：

入力：x = -101
出力：false
 

制約：

-231 <= x <= 231-1


####回答
文字を反対にしてもマイナスじゃないかを判定するということ。
一番重要なのは、[::-1]で後ろからに変換してくれる。

```
class Solution:
    def isPalindrome(self, x: int) -> bool:
        return str(x) == str(x)[::-1]
```

```
a = str("-10")[::-1]

print(a)
```

出力
01-
PowerShellでlsやgrepを使う（風）

1.profileファイルを作る。

```powershell
New-Item -type file -force $profile
```

2.エイリアスを登録する。
C:\Users\\(username)\Documents\PowerShell\Microsoft.PowerShell_profile.ps1

```powershell:Microsoft.PowerShell_profile.ps1
Set-Alias lss mylssort
function mylssort(){
  $order = @(
    @{ Expression = 'LastWriteTime'; Descending = $true }
    @{ Expression = 'Name'; Ascending = $true }
  )
  gci $args | sort $order
}

Set-Alias grep mygrep #Select-String
function mygrep {$input | findstr /n /i $args}
```
3.試す。
[PowerShell](https://docs.microsoft.com/ja-jp/powershell/scripting/learn/ps101/01-getting-started?view=powershell-7.1)を起動する。

```powershell
PS C:\Users> lss

    Directory: C:\Users

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d----          2020/12/30    21:59                Administrator
d-r--          2020/12/30    21:32                Public

PS C:\Users> lss | grep pub
8:d-r--          2020/12/30    21:32                Public
PS C:\Users>
```

追記：2021/09/29
文字化け対応、その他エイリアス追加しました。

```powershell
# New-Item -type file -force $profile

Set-Alias bake mybake #pipe bad encoding
function mybake {
  $OutputEncoding = [Console]::InputEncoding = [Console]::OutputEncoding = [System.Text.UTF8Encoding]::new()
}

Set-Alias lss mylssort
function mylssort(){
  $order = @(
    @{ Expression = 'LastWriteTime'; Descending = $true }
    @{ Expression = 'Name'; Ascending = $true }
  )
  bake
  gci $args | sort $order
}

Set-Alias grep mygrep #Select-String
function mygrep {
  $OutputEncoding = [Console]::InputEncoding = [Console]::OutputEncoding = [Text.Encoding]::GetEncoding('sjis')
  $input | findstr /n /i $args
}

Set-Alias wgrep mywgrep #> wgrep 'MessageBoxA'
function mywgrep {
  Select-String .\*.txt -Pattern $args -Encoding shift_JIS
}

Set-Alias uclip myclip_u #clip to clipboard with utf8
function myclip_u {
  bake
  $input | clip
}

Set-Alias fh256 myfilehash256 #> fh256 'index.jpg'
function myfilehash256 {
   Get-FileHash -Algorithm SHA256 $args
}
```
sshdをGoogle Authenticatorで


```
# cat /etc/redhat-release
# AlmaLinux release 8.4 (Electric Cheetah)
# google auth
sudo yum install epel-release
sudo yum install google-authenticator
# for user
cd
google-authenticator
全てy


# sshd
cd /etc/ssh
sudo chmod 644 sshd_config
sudo b sshd_config
sudo cp -p sshd_config sshd_1234_config
sudo vi sshd_1234_config
diff OLD/sshd_config.2021060301 sshd_1234_config
=====
17a18
> Port 1234
32c33,34
< SyslogFacility AUTHPRIV
---
> #SyslogFacility AUTHPRIV
> SyslogFacility LOCAL1
38a41
> PermitRootLogin no
65c68
< PasswordAuthentication yes
---
> PasswordAuthentication no
68,69c71,72
< #ChallengeResponseAuthentication yes
< ChallengeResponseAuthentication no
---
> ChallengeResponseAuthentication yes
> #ChallengeResponseAuthentication no
=====
cd /usr/lib/systemd/system
cp -p sshd.service sshd_1234.service
sudo vi sshd_1234.service
diff sshd.service sshd_1234.service
=====
10c10
< ExecStart=/usr/sbin/sshd -D $OPTIONS
---
> ExecStart=/usr/sbin/sshd_1234 -f /etc/ssh/sshd_1234_config -D $OPTIONS
=====
sudo systemctl enabled sshd_1234.service
sudo systemctl start sshd_1234.service

sudo vi sshd_config
=====
32c32,33
< SyslogFacility AUTHPRIV
---
> #SyslogFacility AUTHPRIV
> SyslogFacility LOCAL0
38a40
> PermitRootLogin no
=====
sudo systemctl restart sshd


# pam
cd  /usr/sbin
sudo cp -p sshd sshd_1234
cd /etc/pam.d/
sudo /usr/local/bin/b sshd
sudo cp -p sshd sshd_1234
sudo vi sshd_1234
diff OLD/sshd.2021060301 sshd_1234
=====
4a5
> auth       required     pam_google_authenticator.so echo_verification_code
=====


# syslog
cd /etc/
sudo b rsyslog.conf
sudo vi rsyslog.conf
diff OLD/rsyslog.conf.2021060501 rsyslog.conf
=====
74a75,76
> local0.*                                              /var/log/sshd.log
> local1.*                                              /var/log/sshd_1234.log
=====
sudo systemctl restart rsyslog


# logrote
cd /etc/logrotate.d/
sudo vi sshd
=====
/var/log/sshd.log
/var/log/sshd_1234.log
{
    ifempty
    rotate 150
    missingok
    sharedscripts
    postrotate
        /bin/kill -HUP `cat /var/run/syslogd.pid 2> /dev/null` 2> /dev/null || true
    endscript
}
=====


# firewalld
cd /etc/
sudo chmod 755 firewalld
cd firewalld
sudo chmod 755 zones
cd zones
sudo b public.xml
sudo vi public.xml
$ diff OLD/public.xml.2021060401 public.xml
===
5,6c5,11
<   <service name="ssh"/>
<   <service name="dhcpv6-client"/>
---
>   <port protocol="tcp" port="1234"/>
>   <rule family="ipv4">
>     <source address="210.172.51.0/24"/>
>     <port protocol="tcp" port="22"/>
>     <accept/>
>   </rule>
===
sudo systemctl restart firewalld
sudo firewall-cmd --list-all

```
オフラインどう書くE04の解答

問題はこちら->http://mtsmfm.github.io/2016/06/04/doukaku-e04.html

con/2は問題の数字を横路の両端からなるリストのリストに変換しています。
clos/4で通行止めの道を通らなければならない登山者、すなわち、
落石が落ちた登山口の人と登山途中で落石の経路に出会う人をfindallで集めます。
具体的には、最初落石の開始位置を起点（closの第二引数）に横路を調べていって、
両端のどちらかが起点と同じ横路に来たら、その位置の麓側で落石のない経路を調べ、
更に横路の反対側を起点に、その麓側で落石の経路をしらべます。
落石のない経路の探索で横路に来たら、横路の反対側の麓側で落石のない経路を探します。
横路がなくなった時の起点が登頂できない人の位置です。
closの第一引数がsが落石のある経路、nが落石のない経路の探索です。
最後に登山者のリストから、登れない登山者を除きます。

```Prolog
%swi-Prolog  version 7.4.2,7.6.4
%start.
%:-initialization(start).   % ideone

bri(X,[F,T]):-
     Y is (X-1) mod 8+65,atom_codes(F,[Y]),Y1 is X mod 8+65,atom_codes(T,[Y1]).

clos(_,X,[],X).
clos(s,X,[H|T],R):-
     (H=[Y,X];H=[X,Y]),!,(clos(s,Y,T,R);clos(n,X,T,R)).
clos(n,X,[H|T],R):-
     (H=[Y,X];H=[X,Y]),!,clos(n,Y,T,R).
clos(C,X,[_|T],R):-
     clos(C,X,T,R).

solve(X,L,R):-maplist(bri,L,L1),findall(Y,clos(s,X,L1,Y),R),!.

start:-
     str(S),split_string(S,"\n","",L),maplist(split,L,L1),
     findall(Y,(between(65,72,X),atom_codes(Y,[X])),D),pre(L1,D).

split(S,L):-split_string(S,"\s","\s",L).

pre([],_).
pre([[_,A|B]|T],D):-             % B ga nai baai ga aru tame
     concat_atom([N,S],':',A),atom_chars(N,L),maplist(atom_number,L,L1),
     solve(S,L1,R),subtract(D,R,R1),sort(R1,R2),disp(R2,B),pre(T,D).

disp(R,B):-
     (R==[]->S="";atom_string(R,S)),(B=[]->B1="";B=[B1]),
     (B1==S->Str=" pass ";Str=" fail "),write(Str),writeln(S).

str("0       2512:C  DEFGH
1       1:A     CDEFGH
2       :C      ABDEFGH
3       2345:B  AGH
4       1256:E  ABCDH
5       1228:A  ADEFG
6       5623:B  AEFGH
7       8157:C  ABDEFGH
8       74767:E ABCFGH
9       88717:D ABCEFGH
10      148647:A        ACDEFH
11      374258:H        BCDEFH
12      6647768:F       ABCDEH
13      4786317:E       ABFGH
14      3456781:C
15      225721686547123:C       CEF
16      2765356148824666:F      ABCDEH
17      42318287535641783:F     BDE
18      584423584751745261:D    FGH
19      8811873415472513884:D   CFG
20      74817442725737422451:H  BCDEF
21      223188865746766511566:C ABGH
22      2763666483242552567747:F        ABCG
23      76724442325377753577138:E       EG
24      327328486656448784712618:B
25      4884637666662548114774288:D     DGH
26      84226765313786654637511248:H    DEF
27      486142154163288126476238756:A   CDF
28      1836275732415226326155464567:F  BCD
29      62544434452376661746517374245:G G
30      381352782758218463842725673473:B        A").

```