OmniAICreator/Qiita-1.07M huggingface dataset:
『アイの歌声を聴かせて』が21世紀だとしたら何年なのか、プログラミングで挙げてみる

## はじめに

2021年公開の映画、『[アイの歌声を聴かせて](https://ainouta.jp/)』。
私はこの作品が大好きでして、この半年近くプログラミングのネタにしています。
劇中では**6/9が月曜日**なのですが、「21世紀にあるとしたら何年なんだろう」と気になりました。
そこで、プログラミングでこの疑問をサクッと解消しちゃいます！

## 動作環境

- macOS 10.14.6
- Python 3.10.2

## 6/9が月曜日の年は21世紀に何回あるのか

疑問を解決するために、以下のプログラムを書きました。

```python
from datetime import date


def is_monday(a_date):
    return a_date.weekday() == 0


if __name__ == "__main__":
    for year in range(2021, 2100 + 1):
        test_start_date = date(year, 6, 9)
        if is_monday(test_start_date):
            print(year)
```

公開された2021年以降の**6/9の曜日を確認する**スクリプトです。
6/9が月曜日（`weekday()`メソッドが0を返す）場合、画面に出力します（下はメソッドのドキュメントへのリンクです）。

https://docs.python.org/ja/3/library/datetime.html#datetime.date.weekday

### 曜日の一致から『アイの歌声を聴かせて』の候補となる年（21世紀）

```shell
$ python3.10 search_year.py
2025
2031
2036
2042
2053
2059
2064
2070
2081
2087
2092
2098
```

これを候補に、劇中の月の満ち欠けと一致するか検証すれば年は特定できそうです！
（なお、ガチな考察はすでにされていて、辻褄は合わないらしいです）

## 『アイの歌声を聴かせて』について補足

[第45回日本アカデミー賞 優秀アニメーション作品賞](https://www.japan-academy-prize.jp/prizes/45.html#title02)にも選出されました！
"最後にきっと、笑顔になれる"作品です。

https://youtu.be/2j2CQBk8uWM

[劇場](https://eigakan.org/theaterpage/schedule.php?t=ainouta)でも[配信](https://ainouta.jp/ondemand.html)でも見られます。全人類見て！
Quest2で無線ルーターなしで簡単にAir Linkできるかもしれない方法

# 前提条件
5GHｚ帯対応 USB wifi adaptor（もしくはwifi内蔵PC）
Oculus Quest
各種ソフトウェア
Windows 10
# 準備
パソコンを有線接続にてルーターとつなぎます
タスクバーの右下のこちらをクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2609747/2a588753-e906-0fc5-cde1-08b4f3c134d4.png)
ネットワークとインターネットの設定を開きます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2609747/cd7fb68b-a89e-f331-0594-a89d72a867b0.png)
モバイルホットスポットを開きます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2609747/1dd40f68-a0ca-178b-d19c-83cc15db823a.png)
編集をひらきます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2609747/f3d9b690-1ec7-0c58-e7c7-8bb7380bcd5e.png)
5GHz帯であることを確認し、使用可能な接続or2.4GHz帯であれば5GHｚに変更し、保存します。
ネットワーク名とパスワードも合わせてメモもしくは変更するといいかもしれません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2609747/e60bc303-cad7-3df1-c778-baefe361e27b.png)
試しにオンにしてみましょう。省電力はオフにしておきましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2609747/1bdc3660-ca4d-611e-0529-fda3f661b3de.png)
ふだんはココをおして、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2609747/2a588753-e906-0fc5-cde1-08b4f3c134d4.png)
モバイルホットスポットをクリックでオンにできます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2609747/7485d749-3335-d4f2-fb4e-466f6986ffaf.png)

このあとはQuest2を起動し、Wifiの接続先を先ほど設定したネットワーク名（例：DESKTOP-XXXXX）に設定したのち、AirLinkの設定をオンにします。
PCではOculusLinkを起動 ~~し、β版のAirLinkをONに~~ すれば使えるようになるはずです。
ここら辺はたくさんの記事があるので別途参照してください。
https://support.oculus.com/articles/headsets-and-accessories/oculus-link/connect-with-air-link/?locale=ja_JP
https://www.moguravr.com/oculus-air-link/

ではよきVRライフを！
【初心者応援】先輩に聞く時に気をつける事

今回は新人プログラマ応援という事で分からない事を先輩に聞く時に気をつける事を書いていこうと思います。

この先自分一人で全てのことを解決できる人はいないと思います。

自分の質問したい内容を相手に的確に伝える事ができないと、そこでお互いに時間を使い、日々の業務が遅れてしまうかも知れません。

実際に自分も新人の時にそういう経験があった為、記事にしてみました。

# 文字でやり取りする場合は対面で話すような感覚で話さない
現在はリモートも進んでいると思いますので、文字でやり取りする事が多いと思います。
その際に実際に会って、頭で今思っている内容を、そのまま文字に起こす形で送ると伝わりにくいです。

解決策として、一度メモに書き出す事をお勧めします。
メモに書き出す事で、内容を整理する事ができます。

# 聞きたい内容を初めに持ってくる

例えばですが、新人プログラマから質問が来た時に
『ここで〇〇して、この先で〇〇してて、ここの変数が〇〇になっちゃうんですよ、だからわからないんです。』
と聞かれる事がありました。

この場合は『ここで〇〇して、この先で〇〇してて、』の所は、聞きたい内容がわからないと、その部分は何を目的に見て良いのかわからず、『ここの変数が〇〇になっちゃうんですよ』ここの変数の値が変わるのは何故なのかという目的で
『ここで〇〇して、この先で〇〇してて、』を再度見ることになります。

なので初めに聞きたい内容を持ってきましょう。
例
『ここの変数が〇〇になっちゃうのがわからないんです。ここで〇〇して、この先で〇〇してるので変わらないと思うんですが。』

# 自分なりのフォーマットを用意しておく
相手に伝わるように、フォーマットをメモなどに残しておくと良いと思います。
話したい事:

現状:

調べた内容：

自分の意見：

例として４つ挙げてみましたが、この４つの内容を埋めれば大体のことは伝わると思います。


うまく伝えられないと伝える側も、受け取る側も時間にロスが発生してしまうので、だんだん質問しにくくなってしまうかも知れません。なので、上手く伝えてお互い良い関係で仕事できるようにしましょう！
【JS】アコーディオンメニューの様なQandA【jQuery】

# きっかけ

アコーディオンメニューの様なQandAを作ってと言われた

## 下準備

省略してbodyだけ書きます！

```html
<body>
  <div class="qa-wrapper">
    <!-- ↓のdivをクリックすると開閉して欲しい -->
    <div class="qa-wrapper__qa">
      <div class="qa-wrapper__q">
        <p class="qa-wrapper__text">質問</p>
        <!-- ↓のdivの擬似要素をactiveクラスを追加して変更したい -->
        <div class="qa-wrapper__qButton"></div>
      </div>
      <!-- ↓のdivを展開格納したい -->
      <div class="a" style="display: none;">
        <p>回答</p>
      </div>
    </div>
  </div>
</body>
```

```scss
.qa-wrapper {
  &__q {
    /* 無駄に体裁… */
    display: flex;
    flex-flow: row nowrap;
    align-items: center;
  }

  &__qButton {
    /* プラスマイナス表示 */
    position: relative;
    min-width: 20px;
    min-height: 20px;

    &::before {
      /* 横棒 */
      content: '';
      position: absolute;
      left: 0;
      top: 9px;
      min-width: 20px;
      min-height: 2px;
      background: #333;
    }

    &::after {
      /* 縦棒 */
      content: '';
      position: absolute;
      left: 9px;
      top: 0;
      min-width: 2px;
      min-height: 20px;
      background: #333;
    }

    &.active::after {
      /* 展開されたら非表示 */
      display: none;
    }
  }
}
```

## よくあるjQuery

```javascript
$(function () {
  $('.hoge').click($(function () {
    // hogeクラスにactiveクラスを追加？
    $(this).toggleClass('active');
    // fugaクラスをスライドして開閉
    $(this).next('.fuga').slideToggle();
  });
});
```

しかしこのまま転用すると、hogeクラスでしかfugaクラスが開閉できない。
僕の望んだ動きをしてくれない。

## 検索

検索してみると、親子関係で開閉させるには```.find()```を使うみたいです。

## 実装

```javascript
$(function () {
  $('.qa-wrapper__qa').click(function () {
    $(this).find('.qa-wrapper__qButton').toggleClass('active');
    $(this).find('.a').slideToggle();
  });
});
```

これで指定した要素内のどこをクリックしても開閉できる。
やったー！

## 最後に

何度も忘れてしまっているのが…。
cssの適用
jsとjQueryの読み込み

コイツらを忘れて何度もリロードしてしまいました。
indexの複数形はindexesかindicesか

たびたび話題になるので調べました。詳細はOxfordなどの辞書でご確認ください。

|             | イギリス英語  | アメリカ英語 | 学術英語 |
|-------------|------------------|------------------|------------------|
| (本などの)索引      | indexes          | indexes, indices | indexes          |
| (物価などの)指数   | indexes, indices | indexes, indices | indexes, indices |
| (判断の)指針      | indices          | indexes, indices | indices          |
| 累乗などの指数 | indices          | indices          | indices          |
| (プログラミングにおいて)レコードの宛先リスト  | N/A              | N/A              | indexes          |
M5Stack用デュアルボタンユニットで、bleキーボード(onekey)を作成して、スイッチコントロールでiPadを操作 

https://twitter.com/shirox22/status/1512989409934655490?s=20&t=dtBeTFf63w9vxUvpWQ8M8A

M5Stack用デュアルボタンユニットで、bleキーボード(onekey)を作成して、スイッチコントロールでiPadを操作してみました。

たなかまさゆき氏のLang-shipのページを参考にさせてもらいました。
https://lang-ship.com/blog/work/m5stickc-iphone/

BleKeyboard.hをincludeして、M5stickCをBLEキーボードとして認識させることができます。

bleKeyboard.write(0x20);の部分で、
ASCIIコードから、青ボタンをスペースキー(0x20)、

bleKeyboard.write(0x68);も同様に、
赤ボタンをHキー(0x68)に設定しています。


http://www9.plala.or.jp/sgwr-t/c_sub/ascii.html

### M5stickCにプログラムをインストール
```
#include <M5StickC.h>
#include <BleKeyboard.h>

BleKeyboard bleKeyboard;
const int buttonred = 32;
const int buttonblue = 33;

double vbat = 0.0;
int8_t bat_charge_p = 0;

void show_battery_info() {
  // バッテリー電圧表示
  // GetVbatData()の戻り値はバッテリー電圧のステップ数で、
  // AXP192のデータシートによると1ステップは1.1mV
  vbat = M5.Axp.GetVbatData() * 1.1 / 1000;
  // バッテリー残量表示
  // 簡易的に、線形で4.2Vで100%、3.0Vで0%とする
  bat_charge_p = int8_t((vbat - 3.0) / 1.2 * 100);
  if (bat_charge_p > 100) {
    bat_charge_p = 100;
  } else if (bat_charge_p < 0) {
    bat_charge_p = 0;
  }
  M5.Lcd.setCursor(45, 2, 1);
  M5.Lcd.printf("Charge: %3d%%", bat_charge_p);
}
void setup() {
  Serial.begin(115200);
  Serial.println("Starting BLE work!");
  bleKeyboard.begin();
  M5.begin();
  M5.Lcd.setRotation(1);
  pinMode(33, INPUT);
  pinMode(32, INPUT);
}
void loop() {
  M5.update();
  if ( M5.BtnA.wasPressed() ) {
    M5.Axp.PowerOff();
  }
  show_battery_info();
  Serial.println(digitalRead(32), digitalRead(33));


  M5.begin();
  if (bleKeyboard.isConnected()) {
    M5.Lcd.drawCentreString("connected", 80, 60, 2);
  }
  // read the value of BUTTON
  if (digitalRead(32) == 0) {
    Serial.println("Button Status: red pressed");

    M5.Lcd.drawCentreString("   red pressed   ", 80, 20, 2);
    bleKeyboard.write(0x68); // Hキーに設定
    delay(100);
  } else if (digitalRead(32) == 1) {
    Serial.println("Button Status:red released");
    M5.Lcd.drawCentreString("   red released   ", 80, 20, 2);
    delay(20);
  }
  // read the value of BUTTON
  if (digitalRead(33) == 0) {
    Serial.println("Button Status: blue pressed ");
    M5.Lcd.drawCentreString("   blue pressed   ", 80, 40, 2);
    bleKeyboard.write(0x20); //スペースキーに設定
    delay(100);
  } else if (digitalRead(33) == 1) {
    Serial.println("Button Status:blue released");
    M5.Lcd.drawCentreString("   blue released   ", 80, 40, 2);
    delay(20);
  }
}
```
【Nuxt】Cannot use JSX unless the '--jsx' flag is provided.ts(17004)の解消法

# はじめに
![スクリーンショット 2022-04-10 18.30.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/167220/512af2d1-2f16-9c13-55d8-7ef1bdaf9059.png)

Nuxt2系 + Vscode

```
Cannot use JSX unless the '--jsx' flag is provided.ts
```

という謎のエラーでvueファイルが真っ赤になりました。。。。
試行錯誤してみた経緯をここに記録します:skull:

# 試したこと① TypeScriptのバージョンを変えてみる

https://qiita.com/NaotoNext/items/f8db28770761cbf33262

👆を参考に、VscodeでTypeScriptのバージョンをワークスペースの方に変更してみました！
![スクリーンショット 2022-04-10 18.11.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/167220/e5a80eb4-2995-74df-86ad-56403699e25b.png)

**しかし、何も変わりませんでした！**

# 試したこと② tsconfig.jsonを編集

https://exerror.com/cannot-use-jsx-unless-the-jsx-flag-is-provided/

👆を参考に、tsconfig.jsonを編集してみました。

```json:tsconfig.json
"compilerOptions": {
    "jsx": "react", // 追加
    "target": "ES2018",
    "module": "ESNext",
    "noImplicitAny": false,
    "resolveJsonModule": true,
    "moduleResolution": "Node",
    "include": [ // 追加
      "./src/**/*.ts"
    ],
    "lib": [
      "ESNext",
      "ESNext.AsyncIterable",
      "DOM"
    ],
    "esModuleInterop": true,
    "allowJs": true,
    "sourceMap": true,
    "strict": true,
    "noEmit": true,
    "experimentalDecorators": true,
    "baseUrl": ".",
    "paths": {
      "~/*": [
        "./*"
      ],
      "@/*": [
        "./*"
      ]
    },
    "types": [
      "@nuxt/types",
      "@nuxtjs/axios",
      "@types/node"
    ]
  },
```

が、`include`についてはなぜかエラーになってしまったので、削除しました。。。:sweat:
![スクリーンショット 2022-04-10 18.38.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/167220/a36e9536-8ce8-06d6-51a3-253404b9b2c8.png)

よって`compilerOptions`に👇を追加しただけです。

```json
 "jsx": "react",
```

## また別のエラーが・・

```
Cannot find name 'React'.ts(2304)
```

![スクリーンショット 2022-04-10 18.42.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/167220/0ce1592a-38bd-bb4b-05da-3d2b7eabadbe.png)

**「ってか、そもそもNuxt（Vue）のプロジェクトやのに、なぜにReactが登場する？？！！」**

と思った訳で、改めてしっかりと調べてみました。。

## jsxをpreserveにするとエラー消えた！

```json
 "jsx": "preserve",
```

https://js.studio-kingdom.com/typescript/handbook/jsx

jsxのオプションを調べてみた結果、よくわかりませんが`preserve`にすることでエラーを回避できました:sweat_smile:

**どなたかコメントで解説お願いします！！！:bow:**
deviseを使用時に名前を表示できない時の解決方法

## 困っていたこと


以下のコントローラ、ビューの記述でサインイン後ユーザのnameが表示されると思っていましたが表示されません。
rails cなどで調べるとそもそも新規登録時に名前が保存できていませんでした。

＊users_controller.rb
```ruby
def show
    @user = User.find(params[:id])
  
  end
```
*/users/show.html.erb
```ruby
<h1>Users#show</h1>

<%= @user.name %>
```



userテーブルにもnameの記述をしているしどこが原因を調べていました。

```ruby
create_table "users", force: :cascade do |t|
    t.string "email", default: "", null: false
    t.string "encrypted_password", default: "", null: false
    t.string "reset_password_token"
    t.datetime "reset_password_sent_at"
    t.datetime "remember_created_at"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.string "name"
    t.text "profile"
    t.boolean "is_deleted", default: false
    t.index ["email"], name: "index_users_on_email", unique: true
    t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
  end
```
-----
## 解決方法

deviseでは新規登録時にはメールアドレス、パスワードしか保存できない状態になっており必要な情報はapplication_controller.rbに追加してあげなくてはいけないのでした。
よって以下の記述になりました。
*/application_controller.rb
```ruby
class ApplicationController < ActionController::Base
  protect_from_forgery with: :exception
  before_action :configure_permitted_parameters, if: :devise_controller?

  def after_sign_in_path_for(resource)
    user_path(current_user.id)
  end

  def after_sign_out_path_for(resource)
    root_path
  end

  def after_sign_up_path_for(resource)
    user_path(current_user.id)
  end

  protected

  def configure_permitted_parameters
    devise_parameter_sanitizer.permit(:sign_up, keys: [:name])
  end
end

```
```ruby
before_action :configure_permitted_parameters, if: :devise_controller?
```
こちら↑の記述でdeviseの機能が行われる前にconfigure_permitted_parametersメソッドが実行されるという意味。
```ruby
protected

  def configure_permitted_parameters
    devise_parameter_sanitizer.permit(:sign_up, keys: [:name])
  end
```
こちら↑の記述でユーザー登録に際にnameを保存できるということでした。


この内容は過去に一回勉強している内容で実践に生かされていないことが身に染みました。
復習も兼ねて理解できたのでよかったです。
間違っている内容などございましたらご教授お願いします。
Cloudformation基礎



# はじめに

Cloudformationを触る機会があったので型をメモとして残しておきます。


### まずはこれ

```yaml  
AWSTemplateFormatVersion: 2010-09-09
Description: XXXXX
```

### VPC

```yaml
myVPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16 
      EnableDnsSupport: true
      Tags:
        - Key: Name 
          Value: vpc
```


### Subnet

- AZとVPCの指定をする

```yaml
PublicSubnet:
    Type: AWS::EC2::Subnet
    Properties:
      AvailabilityZone: ap-northeast-1a 
      VpcId: !Ref myVPC 
      CidrBlock: 10.0.0.0/24 
      Tags:
        - Key: Name 
          Value: public-subnet 
```

### InternetGateway

- IGWの作成とVPCにアタッチする作業

```yaml 
myigw:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name 
          Value: igw-cfn 

AttachGateway:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref myVPC 
      InternetGatewayId: !Ref myigw
```


### Natgateway

- NATを経由するとプライベートIPをパブリックIPに変換するからEIPが必要になる？
- NatgatewayはEIPとサブネットを紐付ける
- `!GetAtt` : テンプレートの属性からリソースを返す
　　　　-　ex ) !GetAtt myELB.DNSName 
　　　　-　 !GetAtt logicalNameOfResource.attributeName


```yaml
NATGatewayEIP:
    Type: AWS::EC2::EIP
    Properties:
      Domain: vpc

NATGateway:
    Type: AWS::EC2::NatGateway
    Properties:
      AllocationId: !GetAtt NATGatewayEIP.AllocationId
      SubnetId: !Ref PublicSubnet
      Tags:
        - Key: Name
          Value: test-natgw

```


### RouteTable


- VPCに紐付けたルートテーブルを定義
- `Route`を追加する際は、`RouteTableId`を指定する
- `SubnetRouteTableAssociate`で定義したルートテーブルをサブネットに紐付け

```yaml 
routeTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref myVPC 
      Tags:
        - Key: Name 
          Value: routetable 
RouteIgw:
    Type: AWS::EC2::Route
    Properties:
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref myigw 
      RouteTableId: !Ref routeTable 
 
RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      RouteTableId: !Ref routeTable
      SubnetId: !Ref PublicSubnet 
```


### EC2

```yaml 
myEC2Instance:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: ami-09ebacdc178ae23b7 
      InstanceType: t2.micro
      SubnetId : !Ref PublicSubnet
      SecurityGroupIds:
        - !Ref SSHSecurityGroup
        - !Ref HTTPSecurityGroup
      Tags:
        - Key: Name 
          Value: ec2-based-on-cfn  
```

```yaml 
SSHSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
        GroupDescription: Enable SSH access via port 22
        GroupName: test
        VpcId: !Ref myVPC
        SecurityGroupIngress:
            - IpProtocol: tcp
              FromPort: 22
              ToPort: 22
              CidrIp: 0.0.0.0/0

HTTPSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
        GroupDescription: HTTP access port 80
        GroupName: test1
        VpcId: !Ref myVPC
        SecurityGroupIngress:
            - IpProtocol: tcp
              FromPort: 80
              ToPort: 80
              CidrIp: 0.0.0.0/0
```

# 終わりに

触って慣れるしかないですね、、
今後この記事は更新していきたいと思います。
Enum.product/1 を楽しむ（Elixir）

**恋すてふわが名はまだき立ちにけり人知れずこそ思ひそめしか**


---

Advent Calendar 2022 92日目[^1]の記事です。
I'm looking forward to 12/25,2022 :santa::santa_tone1::santa_tone2::santa_tone3::santa_tone4::santa_tone5:
私の[Advent Calendar 2022 一覧](https://docs.google.com/spreadsheets/d/1HQvFjagQLRPjOYAjDVzWp9S4b8dKixxvvaz_TtbZWto/edit#gid=1723448955)。

[^1]: @kaizen_nagoya さんの「[「@e99h2121 アドベントカレンダーではありますまいか Advent Calendar 2020」の改訂版ではありますまいか Advent Calendar 2022 １日目　Most Breakthrough Generator](https://qiita.com/kaizen_nagoya/items/49ebebee3a0377f3b59b)」から着想を得て、模倣いたしました。 

---



# はじめに

[Elixir](https://elixir-lang.org/)を楽しんでいますか:bangbang::bangbang::bangbang:

[Enum.product/1](https://hexdocs.pm/elixir/Enum.html#product/1)を楽しんでみます。

# [Enum.product/1](https://hexdocs.pm/elixir/Enum.html#product/1)

引数に指定された数値のEnumerableの各要素を掛け算してその答えを返してくれます。
[Elixir](https://elixir-lang.org/) 1.12 or laterで使用できます。

公式の説明をそのまま貼っておきます。

![スクリーンショット 2022-04-10 19.15.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/131808/bdb1cf76-668d-9c33-3ca3-c285d69e504b.png)


引数はEnumerableであればよいのでたとえばRangeもいけます。

```elixir
iex> Enum.product(1..5)
120

iex> Enum.product(1..8//2)
105
```

# 空のリスト [] を指定した場合は`1`です

```elixir
iex> Enum.product([]) # (イ)
1

iex> Enum.product(100..1//1) # (ロ) 
1
```

(イ)は公式ドキュメントにも書いてある例です。
(ロ)は、「[first..last//step を楽しむ（Elixir）](https://qiita.com/torifukukaiou/items/7db73fdfabf4445ac65b)」で紹介した**なんにもないRange**です。

おそらく下記の実装があるものと予想しました。

```elixir
  def product([]), do: 1
```

果たして、そんなものはありませんでした。

https://github.com/elixir-lang/elixir/blob/v1.13.4/lib/elixir/lib/enum.ex#L3251-L3255

```elixir
  def product(enumerable) do
    reduce(enumerable, 1, &*/2)
  end
```

accumulatorの初期値に`1`を指定して、`reduce`が呼び出されていました。
`&*/2`ははじめてみたときはぎょっとするとおもいます。
働きとしては `fn v, acc -> v * acc end` とおなじです。
[*](https://hexdocs.pm/elixir/Kernel.html#*/2)を[Function capturing](https://elixir-lang.org/getting-started/modules-and-functions.html#function-capturing)しているわけです。

`[]`の中にある要素（実際にはない）をすべてかけ合わせると`1`になるというのは、なんとなく神秘のようなものを感じます。
数学に疎くさっぱりわかりませんが、[Elixir](https://elixir-lang.org/)の実装がたまたまそうなっているだけなのか数学的に意味のあることなのかとても興味があります。

ご存知の方はぜひお便り（コメント）をください :pray::pray_tone1::pray_tone2::pray_tone3::pray_tone4::pray_tone5: 



---

# Wrapping up :lgtm::lgtm::lgtm::lgtm::lgtm:

Enjoy [Elixir](https://elixir-lang.org/):bangbang::bangbang::bangbang:
<font color="purple">$\huge{Enjoy\ Elixir🚀}$</font>

[Enum.product/1](https://hexdocs.pm/elixir/Enum.html#product/1)を楽しみました。


以上です。
CSVデータをExcelに貼り付ける方法

csvをシステムに取り込んだ後、またそのデータをシステムからcsv形式で出力してちゃんとシステムに取り込まれているかどうかExcel上で確認しなければならないことがありました。
その時に先輩エンジニアから聞いた方法をメモしておきます。

①比較したいデータをコピーする。
ここではcsvを開くためにサクラエディタを使用していますが、メモ帳でもいいです
（csvファイルをExcelで開くのは前０が消えるため業界初心者と思われるそうです、私は一度やってしまいましたが）。
![サクラエディタ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/690469/19747cb1-5892-62b2-625d-44859d8fab84.png)
②コピーしたものをExcelのシートのA1セルを選択しながらそのままctrl+vでペースト。
すると画像のように(Ctrl)と下に出るためそれに従いCtrlキーのみ押すと、
今度はテキストウィザードを使用（U)と出るためUキーを押す。
![貼り付け直後.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/690469/fd718998-b317-a566-6484-c452018deef5.png)
![ctrlouka.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/690469/6dad8684-6411-215b-4260-11befd87cd86.png)
③テキストファイルウィザードがでるためこれはこのまま次へ（N）。
![tekisutowizard1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/690469/e4a6bb5d-4555-0f1b-c583-dd0a41323d45.png)
④文字列の引用符は今回ダブルクォーテーションがついているためこのまま。
区切り文字は初期表示だとスペースにチェックがついているため外し、csv形式のためカンマを選択する。
そして次へ。
![tekisutowizard2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/690469/44c1c6b7-c0a1-6fc9-a9f2-4fc8c680a337.png)
⑤この時は列のデータ形式も変えたかったため、初期状態だとデータのプレビューで一番左の列（ここでは商品ID）のみ黒く選択されているので、列の右端までShiftを押しながら選択。
また、上部の列のデータ形式をG/標準から文字列に変更。そして完了（F)。
![textwizard3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/690469/838a034a-9b37-858f-eb76-8c6831b5c402.png)

![haritukego.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/690469/cbe449dc-f61b-0b44-0b94-5f78cf889df7.png)

無事にExcelのセルに貼り付けました。
csvファイル同士を比較する時、これなら比較しやすいですね。
Next.jsでnext/imageで最適化した画像を背景画像として出力する（スクロールしても背景画像を固定で表示する）

## ご注意：
理解が甘いので語尾は全部 `っぽい` です。
何卒よろしくお願いします。

※タイトルが background-image として出力するように勘違いされるかもしれませんが違います。imgタグとして出力されるので勘違いされないようにご注意ください。

## next/image について

Next.jsには画像最適化してくれる `next/image` があります。
便利な next/image ですが、欠点としてはbackground-image で適用することができません。

画像最適化をしなければbackground-imageで適用はできます。
しかし、どうせならNext.jsにお任せして画像の最適化をしたいですよね。

`next/image` は画面サイズが小さいときは容量の小さいデータをくれるし、画面サイズが大きいときは大きいなりのデータをくれます。

公式ドキュメントにもbackground-imageとして使うためのサンプルが用意されています。（この記事を書いた後に気づきました...。） - https://github.com/vercel/next.js/blob/canary/examples/image-component/pages/background.js

※公式ドキュメントは https://nextjs.org/docs/api-reference/next/image からご覧ください。

※欲を言えば Tailwind CSS で最適化した背景画像を Theme に入れて使いたかったですが、解決策っぽいのは見つかりませんでした。ご存知の方、コメントからお待ちしています。

---

## 背景画像をスクロールしても固定されるようにする

※CSSはTailwind CSSを使ってます。

```tsx
import Image from 'next/image'

const Home = () => {
  return (
    <div>
      <div>
        <p>hogehogeだよ！</p>
        <p>hogehogeだよ！</p>
        <p>hogehogeだよ！</p>
        <p>hogehogeだよ！</p>
        <p>hogehogeだよ！</p>
        <p>hogehogeだよ！</p>
        <p>hogehogeだよ！</p>
        <p>hogehogeだよ！</p>
        <p>hogehogeだよ！</p>
        <p>hogehogeだよ！</p>
        <p>hogehogeだよ！</p>
        <p>hogehogeだよ！</p>
        <p>hogehogeだよ！</p>
        <p>hogehogeだよ！</p>
        <p>hogehogeだよ！</p>
        <p>hogehogeだよ！</p>
        <p>hogehogeだよ！</p>
        <p>hogehogeだよ！</p>
        <p>hogehogeだよ！</p>
        <p>hogehogeだよ！</p>
        <p>hogehogeだよ！</p>
        <p>hogehogeだよ！</p>
        <p>hogehogeだよ！</p>
        <p>hogehogeだよ！</p>
        <p>hogehogeだよ！</p>
        <p>hogehogeだよ！</p>
        <p>hogehogeだよ！</p>
        <p>hogehogeだよ！</p>
        <p>hogehogeだよ！</p>
        <p>hogehogeだよ！</p>
        <p>hogehogeだよ！</p>
        <p>hogehogeだよ！</p>
        <p>hogehogeだよ！</p>
        <p>hogehogeだよ！</p>
        <p>hogehogeだよ！</p>
        <p>hogehogeだよ！</p>
        <p>hogehogeだよ！</p>
        <p>hogehogeだよ！</p>
      </div>

      <div className={`fixed top-0 left-0 w-full h-screen z-[-1]`}>
        <Image src={`/images/bg-hoge.jpg`} layout={`fill`} objectFit={`cover`} />
      </div>
    </div>
  )
}

export default Home
```

`position: fixed` で固定化し、
`top:0; left:0;` で左上を基準にし、
`width: 100%; height: 100vh;` で画面いっぱいにひろげ、
`z-index: -1` でレイヤーを一番下にしています。

これでスクロールしても常に背景画像が表示された状態になります！

## 表示例：
![be6ae2ccfccec478af51971a4cfd734c.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/35783/3711ef9f-f63a-bcea-0436-77c4b5152a14.png)

余談： next/image でobject-fit: cover なスタイルを出力してくれてるので、positionの値もfixedに変更するようなオプションが入ってたら最高なのになぁ、と思いました。
私のAdvent Calendar 2022 ーー 3月のふりかえり

**忍ぶれど色にいでにけりわが恋はものや恩ふと人の問ふまで**


---

Advent Calendar 2022 91日目[^1]の記事です。
I'm looking forward to 12/25,2022 :santa::santa_tone1::santa_tone2::santa_tone3::santa_tone4::santa_tone5:
私の[Advent Calendar 2022 一覧](https://docs.google.com/spreadsheets/d/1HQvFjagQLRPjOYAjDVzWp9S4b8dKixxvvaz_TtbZWto/edit#gid=1723448955)。

[^1]: @kaizen_nagoya さんの「[「@e99h2121 アドベントカレンダーではありますまいか Advent Calendar 2020」の改訂版ではありますまいか Advent Calendar 2022 １日目　Most Breakthrough Generator](https://qiita.com/kaizen_nagoya/items/49ebebee3a0377f3b59b)」から着想を得て、模倣いたしました。 

---



# はじめに

[Elixir](https://elixir-lang.org/)を楽しんでいますか:bangbang::bangbang::bangbang:

10日遅れです。
えっ！？　何のことって？

私の[Advent Calendar 2022](https://docs.google.com/spreadsheets/d/1HQvFjagQLRPjOYAjDVzWp9S4b8dKixxvvaz_TtbZWto/edit#gid=1723448955)です。

この記事を書いている今日は2022/04/10(日)です。
私の[Advent Calendar 2022](https://docs.google.com/spreadsheets/d/1HQvFjagQLRPjOYAjDVzWp9S4b8dKixxvvaz_TtbZWto/edit#gid=1723448955)では、2022/04/01(金)の回に該当します。

# ペースが乱れたワケ

外に理由を求めれば、大きく２つです。

- [AWS Certified Solutions Architect – Associate](https://aws.amazon.com/jp/certification/certified-solutions-architect-associate/) の再認定を受けようと受験勉強をしていた
    - 受験勉強の甲斐あって、2022/03/27に再認定されました :tada: 
        - 世の中には全冠制覇される方がいらっしゃるようで、たいしたことはないのだとおもいますが、まずは受かってよかったです
        - 人それぞれのペースでいいのだとおもいます
    - [公式ページ](https://aws.amazon.com/jp/certification/certified-solutions-architect-associate/)で紹介されているコンテンツに一通り目を通しました
        - 独特の問題文のいいまわしに慣れておきました
        - 3年前に合格したときからいろいろ増えている(? 前からあった?)、サービスの知識の整理ができました
    - 1,000点満点で合格する予定でしたが、790点くらいでした
- 新型コロナウイルスワクチン接種３回目以降、ぐったりしていた日が続いた

理由を探せば他にいくらでもでてきます。

一番の理由は、 **もういいかなあ** と怠け心がでてしまったことです。
己に克つというのが一番六ヶ敷い[^2]。

[^2]: むつかしい。 https://blog.goo.ne.jp/iries333/e/6a0d950fb159ce4d2b141c1744c26ab7

# 大西郷先生の言葉

**あやまちを改むるには、みずからあやまりを思わばそれにて可なり。**
**その事をば捨ててかえりみずして、ただちに一歩踏み出すべし。**
**あやまちを悔い、とりつくらわんとして、心を苦しむるは、たとえば茶碗を割り、その破片をあわせみるも同然にて、無用のことなり。**

# ポエム

自分との約束を破りはじめると、だんだんといろいろなことがどうでもよくなってきます。
そんな週末を過ごしておりました。

津本陽先生の『巨眼の男』:book:という本を読んでおりまして、上記の西郷南洲遺訓に収められている文章にでくわしました。

私の場合は、遅れてしまってはいるけど、また一つずつ記事を書いていこうとおもいました。
一つ一つ記事を書くことを楽しみたいとおもいます。

一つ書くとまた楽しくなってきました。



---

# Wrapping up :lgtm::lgtm::lgtm::lgtm::lgtm:

**案ずるより産むが易し。**

私の[Advent Calendar 2022](https://docs.google.com/spreadsheets/d/1HQvFjagQLRPjOYAjDVzWp9S4b8dKixxvvaz_TtbZWto/edit#gid=1723448955) 3月のふりかえりを書きました。
改めて、記事を書くことを楽しんでいきたいとおもいます。

吾方将処事。必先於心下自下数鍼、然後従事。

以上です。
SSH接続時にWARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! になった時の対処

SSH接続をした時に、以下のようなエラーが出てリモートホストに接続できないことがある
```
% ssh user@192.168.1.1
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
The fingerprint for the ED25519 key sent by the remote host is
XXXXXXXXXXXXXXXXX.
Please contact your system administrator.
Add correct host key in /Users/username/.ssh/known_hosts to get rid of this message.
Offending ED25519 key in /Users/username/.ssh/known_hosts:XX
ED25519 host key for 192.168.1.1 has changed and you have requested strict checking.
Host key verification failed.
```
これは、known_hostsに登録されているホストの公開鍵と、接続先ホストの公開鍵が一致しない時に発生するエラー
具体的には
1. IP: 192.168.1.1を持つリモートホストAにローカルXからSSHする
1. IP: 192.168.1.1をリモートホストBに付け替える
1. リモートホストBにローカルXからSSHする

というようなことをすると発生する。
検証用にIPを使い回してるとやりがち
なので、known_hostsから対象のホスト情報を消せば良い。
具体的には以下
```
% ssh-keygen -R 192.168.1.1
# Host 192.168.1.1 found: line XX
/Users/username/.ssh/known_hosts
Original contents retained as /Users/username/.ssh/known_hosts.old
```
first..last//step を楽しむ（Elixir）

**浅茅生の小野のしの原忍ぶれどあまりてなどか人の恋しき**


---

Advent Calendar 2022 90日目[^1]の記事です。
I'm looking forward to 12/25,2022 :santa::santa_tone1::santa_tone2::santa_tone3::santa_tone4::santa_tone5:
私の[Advent Calendar 2022 一覧](https://docs.google.com/spreadsheets/d/1HQvFjagQLRPjOYAjDVzWp9S4b8dKixxvvaz_TtbZWto/edit#gid=1723448955)。

[^1]: @kaizen_nagoya さんの「[「@e99h2121 アドベントカレンダーではありますまいか Advent Calendar 2020」の改訂版ではありますまいか Advent Calendar 2022 １日目　Most Breakthrough Generator](https://qiita.com/kaizen_nagoya/items/49ebebee3a0377f3b59b)」から着想を得て、模倣いたしました。 

---



# はじめに

[Elixir](https://elixir-lang.org/)を楽しんでいますか:bangbang::bangbang::bangbang:

[first..last//step](https://hexdocs.pm/elixir/Kernel.html#..///3)を楽しんでみます。

# [first..last//step](https://hexdocs.pm/elixir/Kernel.html#..///3)

`first`から`last`までのRangeを作ってくれます。
刻みは`step`で指定します。
[Elixir](https://elixir-lang.org/) 1.12 or laterです。

公式の説明をそのまま貼っておきます。

前半の3件で使っている[left in right](https://hexdocs.pm/elixir/Kernel.html#in/2)は、leftがhandの一員であるかどうかを返すマクロです。
Rangeの中にメンバーとして存在しているかどうかを確かめています。

後半の3件でつかっている[Enum.to_list/1](https://hexdocs.pm/elixir/Enum.html#to_list/1)はRangeをListに変換しています。
ここではRangeを引数にとっています。
引数はEnumerableなものであればよく、たとえばMapも引数にとれます。
この記事とは外れるし、私はこのくらいしか説明できないのでこのへんでやめておきます。

![スクリーンショット 2022-04-10 17.57.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/131808/312af077-c477-5189-e4ce-24e9e5156d3c.png)




最後の例のようにありえない`first`から`last`へのありえない刻み方を指定した場合には、なんにもないRangeということになります。

別の例を書いてみます。

```elixir
iex> Enum.to_list(1..-3//-1) # (イ)
[1, 0, -1, -2, -3] 

iex> Enum.to_list(1..-3//1)  # (ロ) 
[]
```

`1`から`-3`に減っていくので(イ)の例のように`-1`ずつ減らすというのはあり得るわけです。
ところが(ロ)のように、Rangeが減っていく方向に進んでいるのに対して`+1`の刻みはあり得ないわけです。



---

# Wrapping up :lgtm::lgtm::lgtm::lgtm::lgtm:

Enjoy [Elixir](https://elixir-lang.org/):bangbang::bangbang::bangbang:
<font color="purple">$\huge{Enjoy\ Elixir🚀}$</font>

[first..last//step](https://hexdocs.pm/elixir/Kernel.html#..///3)の説明を書きました。
私は未だ実践で使ったことはありません。
実例ありましたらぜひお便り（コメント）をお寄せください。



以上です。
【超簡単】RubyonRails 投稿時間をInstagramのようにする 〜 ◯日前,◯時間前,◯分前 〜

#  はじめに
とっても雑な記事ですが、少しでも誰かに役に立てばと思い記事にしました。

## 前提
簡単な投稿機能が実装済みであること
Railsの基礎的な知識を身につけていること


## 実装方法

### コントローラー
投稿時間を計算するために、コントローラーで今日の日付や、現在時刻を取得します。

```tweets_controller.rb
class TweetsController < ApplicationController

  def index
    @today = Date.today #今日の日付を取得
    @now = Time.now     #現在時刻を取得
    @tweets = Tweet.all #tweeetsテーブルの全レコードを取得
  end

(略)
  ・
  ・
  ・

end
```


### ビュー
投稿時間に関するところの解説は下に記載しております。

```erb:tweets/index.html.erb
<div>
  <% @tweets.each do |t| %>
    <div class="tweet">
      <%= t.body %>
    　　<% if (@now - t.created_at) <= 60 * 60 %>
　　　　　　　　　　　　<%=((@now - t.created_at) / 60).to_i.to_s + "分前" %>
　　　　　　　　　　<% elsif (@now - t.created_at) <= 60 * 60 * 24 %>
　　　　　　　　　　　　<%=((@now - t.created_at) / 3600).to_i.to_s + "時間前" %>
　　　　　　　　　　<% elsif (@today - t.created_at.to_date) <= 30 %>
　　　　　　　　　　　　<%= (@today - t.created_at.to_date).to_i.to_s + "日前" %>
　　　　　　　　　　<% else %>
　　　　　　　　　　　　<%= t.created_at.strftime('%Y-%m-%d') %> 
　　　　　　　　　　<% end %>
    </div>
  <% end %>
</div>
```

解説(日本語訳)

```erb:tweets/index.html.erb
<div>
  <% @tweets.each do |t| %>
    <div class="tweet">
      <%= t.body %>
    　　<% もし、( 現在時刻 - 投稿時間 ) が 3600秒以下(60分以下)だったら %>
　　　　　　　　　　　　<%= 〇〇"分前" %> と表示
　　　　　　　　　　<% もし ( 現在時刻 - 投稿時間 ) が 86400秒以下(24時間以下)だったら %>
　　　　　　　　　　　　<%= 〇〇"時間前" %> と表示
　　　　　　　　　　<% もし (今日の日付 - 投稿日) が 30日以下だったら %>
　　　　　　　　　　　　<%=  〇〇"日前" %> と表示
　　　　　　　　　　<% もしそれ以外だったら(投稿日が30日を超過していたら) %>
　　　　　　　　　　　　 投稿時間を yyyy-mm-dd と表示
　　　　　　　　　　<% end %>
    </div>
  <% end %>
</div>

```


### 最後に
いかがでしたでしょうか。
とても雑な記事なので編集リクエストなどドシドシお待ちしております。
少しでも開発の手助けとなれば幸いです。
以上、ここまで読んでいただきありがとうございました(^^)
【Spring】Cookie操作

# 概要

当記事では、Cookieの
　　・保存
　　・取得
の実装方法について説明します。
※実装自体難しくないため、
　実装例を先に挙げ、後半で解説します。

# 実装例

```/CookieDemo/src/main/java/com/example/demo/CookieController.java
package com.example.demo;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.CookieValue;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
@RequestMapping("cookie")
public class CookieController {

	/**
	 * 登録アクション
	 */
	@RequestMapping(value = "/registration", method = RequestMethod.GET)
	public String registrationAction(
		@RequestParam(required = false) String cookieValue,
		HttpServletResponse response,
		Model model) {

		Cookie cookie = new Cookie("id", cookieValue); // オブジェクト作成（キー、バリューを指定）
		cookie.setMaxAge(3600); // 有効期間（単位：秒）
		response.addCookie(cookie);

		model.addAttribute("cookieValue", cookieValue);

		return "registration";
	}

	/**
	 * 参照アクション
	 */
	@RequestMapping(value = "/show", method = RequestMethod.GET)
	public String showAction(
		@CookieValue(value = "id", required = false) String cookieValue,
		Model model) {

		model.addAttribute("cookieValue", cookieValue);

		return "show";
	}

}
```

```/CookieDemo/src/main/resources/templates/registration.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>CookieDemo - registration</title>
</head>
<body>
cookieを保存しました。
[[${cookieValue}]]
</body>
</html>
```

```/CookieDemo/src/main/resources/templates/show.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>CookieDemo - show</title>
</head>
<body>
[[${cookieValue}]]
</body>
</html>
```

# 解説
## CookieController 
### registrationAction
Cookieを保存するアクションです。

下記の実装でCookieオブジェクトを作成／設定し、
保存するCookieの情報を生成しています。
```
Cookie cookie = new Cookie("id", cookieValue); // オブジェクト作成（キー、バリューを指定）
cookie.setMaxAge(3600); // 有効期間（単位：秒）
```
その後の
```
response.addCookie(cookie);
```
でCookieの保存をしています。

### showAction
Cookieの内容を表示するアクションです。

「CookieValue」のアノテーションを付与することで、
Cookieの情報を取得しています。

# 動作検証
Cookieを保存するため、
下記のURLをブラウザでアクセスします。
http://localhost:8080/cookie/registration?cookieValue=test12345
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33640/747250ab-2d3b-2e7e-3ac1-fca74f4b2d1e.png)


Cookieの保存内容を確認するため、
下記のURLをブラウザでアクセスします。
※registrationで保存したCookieの値「test12345」が表示されます。
http://localhost:8080/cookie/show

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/33640/7a6c02d2-60db-1212-3a47-2efe2472f151.png)

# 補足
## Cookieの削除について
registrationActionで記載した
```
cookie.setMaxAge(3600); // 有効期間（単位：秒）
```
の秒数部分にゼロをセットすることで削除と同等の実装をすることができます。

## Cookieの保存時の各設定について
サーバのパス（setPath）やドメイン（setDomain）を設定することも可能です。
必要に応じて適切に設定してください。
ec2のリストを取得する

# はじめに
ec2のリストを取得します。lambdaで取得したリストをs3に出力します。
# 内容

## s3バケットの準備
ファイルを作成するためのs3バケットを作成します。```my-resource-list```としました。

## lambda関数の設定
lambda関数に下記のポリシーをアタッチします。
* ```AmazonEC2ReadOnlyAccess``` ec2を参照するため
* ```my-resource-list```バケットへの```s3:PutObject``` ファイルを出力するため

また、タイムアウト時間をデフォルトの3秒から10秒にしました。これは```ec2.describe_instances```の実行時間が3秒を超えたためです。

## lambda関数を作る
pythonでboto3を利用してec2情報を取得します。関数```ec2.describe_instances()```で取得したdictから必要な情報をcsvにして保管するようにしました。

```python:
import json
import boto3

BUCKET_NAME='my-resource-list' #ファイルを保管するs3バケット名
FILE_NAME = 'ec2_resources' #s3バケット内のファイル名

def lambda_handler(event, context):
    ec2 = boto3.client('ec2')

    #ec2情報の取得
    ec2_data = ec2.describe_instances()
   
    #ec2情報の必要な項目を抽出
    my_ec2_list = ''   
    for ec2_reservation in ec2_data['Reservations']:
        for ec2_instance in ec2_reservation['Instances']:
            ec2_instance_id = ec2_instance['InstanceId']
            ec2_instance_type = ec2_instance['InstanceType']
            ec2_instance_state = ec2_instance['State']['Name']
            ec2_instance_IP = ec2_instance['PrivateIpAddress']
            ec2_instance_SubnetId = ec2_instance['SubnetId']

            my_ec2_list += ec2_instance_id + ',' + ec2_instance_type + ',' + ec2_instance_state + ',' + ec2_instance_SubnetId + ',' + ec2_instance_IP + '\n'

    #s3へのアップロード
    response = upload_s3(my_ec2_list, FILE_NAME + '.csv')

    return {
        'statusCode': 200,
        #'body': jd
        'body': json.dumps(my_ec2_list)
    }

#upload to s3
def upload_s3(naiyou, filename):
    client = boto3.client('s3')
    response = client.put_object(
        Body = naiyou,
        Bucket = BUCKET_NAME,
        Key = filename,
    )
    return response
```

下記のようなec2の情報を取得することができます。ヘッダは付きません。

| InstanceId | InstanceType | State | SubnetId | PrivateIpAddress |
|:-:|:-:|:-:|:-:|:-:|
| i-0cb686b49c8c81b27 |t3a.nano|running|subnet-0a9dc7996b385f5e3|10.0.0.22|
| i-0399498a701b49fba |t4g.nano|running|subnet-0a9dc7996b385f5e3|10.0.0.105|


# おわりに
```ec2.describe_instances()```からは他にも様々な情報を取得することができます。

# 参考文献

https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/ec2.html#EC2.Client.describe_instances

https://blog.serverworks.co.jp/boto3-ec2data
PHPerKaigi 2022に参加してきました。

## はじめに

PHPerKaigiとは

>PHPerによるPHPerのためのお祭り

2022/04/09, 10, 11開催です。

https://phperkaigi.jp/2022/

## PHPerチャンレンジ

開催期間中に公式ページ、スポンサーブログ、会場、twitterなどにシャープから始まる文字列が記載されており、それを探し出して専用のフォームに投稿して点数を稼いで準備を競うゲームです。
過去にも開催していて大変盛り上がりました。
僕も過去に参加したことがありましてその時の記事はこちらです。

https://qiita.com/yamamoto_hiroya/items/d60846f1837e94d059d9

今年は健闘し4位まで上がることができました！
PHPerチャンレンジについては別記事を書きましたのでこちらをご覧ください。

https://qiita.com/yamamoto_hiroya/items/e139250298e3f94bdc8c

![スクリーンショット 2022-04-11 18.51.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67471/89c4a0cc-d119-2565-76ff-fa3c22f69869.png)


## 気になったセッション

### 予防に勝る防御なし - 堅牢なコードを導く様々な設計のヒント

安定のt_wadaさんでした。
テストコードを書くとか以前に落ちにくくバクりにくいコードを書いて予防しようねというお話。

https://speakerdeck.com/twada/growing-reliable-code-phperkaigi-2022

### チームの仕事はまわっていたけど、メンバーはそれぞれモヤモヤを抱えていた話──40名の大規模開発チームで1on1ログを公開してみた

僕もそれなりの数1on1をやっていますが、1on1のログを公開するという発想はなかったので新鮮でした。

https://speakerdeck.com/vaccho/opened-1on1-logs

### マイクラスクラムワークショップ

安定のGMOさんでした。
マインクラフトっていうキャッチーなテーマでスクラムを分かりやすく解説してくれていてとてもおもしろかったです。
丸1日使ったワークショップとのことでなかなか真似はできないですが、機会があればやってみたいなと思いました。

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

### 今まで生き残ってきたRDBMSとこの先10年戦えるデータストア戦略

安定のそーだいさんでした。
DBの寿命は長いのでしっかり設計する必要がありますね。

https://speakerdeck.com/soudai/database-now-and-in-the-past

### 本当にあった怖い脆弱性の話

怖すぎて聞いててずっと震えてました。
証券サービスでもこういう話あるんだなーと恐怖しました。
x URLを知らなければ見れないので問題ない
○ URLさえ知っていれば見れてしまう

https://speakerdeck.com/ad5jp/ben-dang-niatutabu-icui-ruo-xing-falsehua

### その他

今回は弊社Hameeから5名も登壇がありました。
ご興味ありましたがご覧ください！

https://speakerdeck.com/o0h/phperkaigi-2022-composer-plugin-b

https://speakerdeck.com/asumikam/huremuwakudejian-ruobserverpatan-number-phperkaigi-2022-c30ed553-7ab3-4efc-8176-fd711a63bfe6

https://docs.google.com/presentation/d/1qUTg62Q_GaBb7NvztOH7YEPJ_MBxL5VK/edit#slide=id.p1

https://speakerdeck.com/na_it_o/phperkaigi-2022

https://speakerdeck.com/o0h/phperkaigi-2022-cs2pr

## ベストフィードバッカー賞

実は前回ももらっていて2冠達成しました！
そして殿堂入り扱いになりましたｗ
今回は42個のフィードバックを書いていたようです。
基本的には

* 聞いていて学びがあった部分
* 知れてよかった部分
* もう少し知りたかった部分
* よく分からなかった部分
* 共感した部分

をフィードバックしていました。
聞いた講演全てにフィードバックを書いたらもらえますのでみんなもフィードバックを書こう！

![スクリーンショット 2022-04-12 9.55.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67471/dbd0ec34-f563-da9a-72d5-db5aa6c7ddc3.png)

![スクリーンショット 2022-04-12 9.56.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/67471/99048d8f-e44b-ddeb-e515-d77ccc70bfc3.png)

https://speakerdeck.com/yamamotohiroya/kanhuarensuhahuidobatukugada-shi

## まとめ

今回も非常に楽しめました！
運営の皆様、スピーカーの皆様本当にありがとうございました！
次回はPHPerチャンレンジ上位入賞目指すぞー！

（開催中にトークン追加されるかどうかテスト）
（結局追加されませんでした）
#フィードバックは大事
python動画編集モジュールmoviepy 解説

この記事は自分の学習・思い出すために書くものです。随時追記していきます。
# Moviepy
<a href= "https://moviepy.readthedocs.io/" >公式ドキュメント</a> 
動画編集用のpythonモジュールです。OpenCV2と異なり、動画特化のモジュールで動画像と音声を同時に編集することが得意です。反対にあまり最適化されていないのかエンコードには時間がかかるので、YouTubeの切り抜きの自動化みたいな感じで使うとき以外は、ほかのモジュールを使った方がよいかもしれません。（あまり他のモジュールを知らないのであれですが、動画像ならOpenCV、音声ならtorchaudioあたりを使った方がいい感じがします。）
MoivePyは動画編集用のPythonモジュールで、一般的な操作（カット・結合・タイトル挿入）、ビデオ合成（非線形編集）、CG合成を使用することが可能です。また、一般的なビデオフォーマットによる読み書きが可能です。
# モジュールの説明
### Clip
Moviepyの基本的なクラスです。ほかのクラスはこのクラスをオーバーライドしています。
#### クラス変数
<pre><code>start #クリップ開始時間
end #クリップ終了時間
duration #クリップの長さ</code></pre>
#### クラス関数
<pre><code>close()　return None #リソース開放
copy() return Clip #浅いコピーの作成
cutout(ta,tb) return Clip # ta[s]とts[s]間を切り落としたClipを返す
subclip(t_start=0,t_end=None) return Clip # t_start[s]とt_end[s]間だけを切り取ったClipを返す
...その他関数は公式ドキュメント参照
</code></pre>
### VideoClip
動画はこのクラスに集約されます。このクラスをインスタンスする関数はいくつかあります。https://moviepy.readthedocs.io/en/latest/ref/VideoClip/VideoClip.html#
<pre><code>VideoClip(make_frame=None, is_mask=False, duration=None, has_constant_size=True) #新しく動画を作るときに使います。
VideoFileClip(filename, decode_file=False, has_mask=False, audio=True, audio_buffersize=200000, target_resolution=None, resize_algorithm='bicubic', audio_fps=44100, audio_nbytes=2, fps_source='fps', pixel_format=None) #既にある動画を読み込むときに使います。
ImageClip(img, is_mask=False, transparent=True, fromalpha=False, duration=None) #一枚の画像を読み込むときに使います。
ColorClip(size, color=None, is_mask=False, duration=None) #一色で塗りつぶした動画を作成するときに使います。
TextClip(text=None, filename=None, size=None, color='black', bg_color='transparent', font_size=None, font='Courier', stroke_color=None, stroke_width=1, method='label', kerning=None, align='center', interline=None, tempfilename=None, temptxt=None, transparent=True, remove_temp=True, print_cmd=False) #テキストのみの動画を作成するときに使います。
CompositeVideoClip(clips, size=None, bg_color=None, use_bgclip=False, is_mask=False) #クリップを重ね合わせた動画を作成するときに使います。
</code></pre>
### AudioClip
音声はこのクラスに集約されます。Video.audioにこのクラスを指定することで動画に音声を含ませることができます。このクラスにもインスタンス化する関数がいくつかあります。
<pre><code>AudioClip(make_frame=None, duration=None, fps=None) # 新しくオーディオクリップを作成します。
AudioFileClip(filename, decode_file=False, buffersize=200000, nbytes=2, fps=44100) # ファイルから音声を読み込みます。
CompositeAudioClip(clips) # 音声を合成するときに使用します。
</code></pre>
# 基本的な構造について
既に存在する動画ファイル、音声ファイルをVideoFileClipまたはAudioFileClipで読み込んだ場合、そのファイルのパラメータ(fps等)も読み込みます。
<pre><code>#サンプルコード
import moviepy.editor as mp
filename="video1.mp4"
videoclip=VideoFileClip(filename)
print(videoclip.fps)
print(videoclip.audio.fps)
----
30
44100
</code></pre>
常用・人名漢字とその画数のCSVデータを自作

常用・人名漢字(ひらがなも)とその画数のCSVデータが取得できるCSVオープンデータを作りました
↓こちらです↓
<a href="https://ktu.iinaa.net/kanji-kakusu.csv" target="blink">kanji-kakusu.csv</a>
漢字は、「kanji」列
画数は、「kakusu」列
となっています。
あとオマケ程度にひらがなの画数もまとめました
データサイズは20.4KB
テキストはUTF-8です

一応間違いないように作っていますが、あったら言ってください。
Ruby から Google Custom Search API を叩く

# ゴール
以下を Ruby から叩く

https://developers.google.com/custom-search/v1/overview

# まず REST API を呼ぶまで
- [参考記事](https://webbigdata.jp/what-is-bigdata/google-custom-search-api)を確認しながら事前準備
    - プロジェクトの作成
        - `https://console.cloud.google.com/home/dashboard?project=[プロジェクト名]`にアクセス出来れば OK
    - [該当 API の有効化](https://console.cloud.google.com/apis/library?project=oldnews-natural-language-api)
    - [API キーの発行](https://cloud.google.com/docs/authentication/api-keys?hl=ja)
    - [Custom Search Engine の作成](https://cse.google.com/create/new)
        - 検索するサイトは適当に
        - 「ウェブ全体を検索する」を ON
    - 検索エンジン ID の取得
- [REST API](https://developers.google.com/custom-search/v1/using_rest) を呼んでみる
    - フォーマットは、`GET https://www.googleapis.com/customsearch/v1?key=[APIキー]&cx=[検索エンジンID]&q=[検索内容]`
    - 検索結果（the URL, title and text snippets）は、items に入っている
    - [その他リクエストとレスポンスの仕様](https://developers.google.com/custom-search/v1/reference/rest/v1/Search)は随時確認しながら

# Gem から API を叩く
- [google-api-client](https://developers.google.com/custom-search/v1/libraries) を使う
- [無料枠や結果](https://qiita.com/zak_y/items/42ca0f1ea14f7046108c#%E7%84%A1%E6%96%99%E6%9E%A0%E3%81%A8%E5%9B%9E%E6%95%B0%E3%81%AE%E3%83%AA%E3%82%BB%E3%83%83%E3%83%88%E3%82%BF%E3%82%A4%E3%83%9F%E3%83%B3%E3%82%B0)については随時確認しながら

```ruby
require 'google/apis/customsearch_v1'

# Doc: https://googleapis.dev/ruby/google-api-client/latest/Google/Apis/CustomsearchV1/CustomSearchAPIService.html
searcher = Google::Apis::CustomsearchV1::CustomSearchAPIService.new
searcher.key = 'APIキー'

# Doc: https://googleapis.dev/ruby/google-api-client/latest/Google/Apis/CustomsearchV1/Search.html
results = searcher.list_cses(cx: '検索エンジンID', q: '検索内容')

# Doc: https://googleapis.dev/ruby/google-api-client/latest/Google/Apis/CustomsearchV1/Search/SearchInformation.html
results.search_information.total_results

# Doc: https://googleapis.dev/ruby/google-api-client/latest/Google/Apis/CustomsearchV1/Result.html
items = results.items
items.first.title
items.first.snippet
items.first.link
# Doc: https://developers.google.com/custom-search/docs/structured_data#pagemaps
items.first.pagemap['cse_image'].first['src']
```
Node.js - ES6のimportを使ったスクリプトサンプル

# 概要

* node.jsでの開発で、テキストエディタによって`require()`ではなく`import()`の利用を強制する。
* Googleの検索結果で、意外と`import()`を使ったコードサンプルが見つからなかった。
* なので、自分がわかった範囲で`import()`によるサンプルコードをまとめていく

# 注意
* ファイル名の拡張子は`.mjs`とする

# コードサンプル

## JSONファイルの入出力

### 事前準備
* fsモジュールのインストール
```console
# npm install fs
```

### コード
```javascript
import fs from 'fs'; // const fs = require('fs') と同じ

const SRC_FILE = "./src.json";
const RESULT_FILE = "./result.json";

// ファイルの読込
const data = JSON.parse(fs.readFileSync(SRC_FILE, 'utf8'));

// ファイルの出力
fs.writeFileSync(RESULT_FILE, JSON.stringify(data));
```

## CSVデータの入出力

### 参考
* https://moewe-net.com/nodejs/node-csv

### 事前準備
* csv関連モジュール（とfsモジュール）のインストール
```console
# npm install fs
# npm install csv-parse
# npm install csv-stringify
```

### コードサンプル
```csvs:サンプルデータ
名前,年齢,電話番号,都道府県
太郎,30,090-1111-2222,東京都
花子,28,080-2222-3333,埼玉県
田中,25,080-3333-4444,神奈川県
```

```javascript:1行ずつ読込
"use strict";

import fs from 'fs';
import { parse } from 'csv-parse/sync';

const data = fs.readFileSync('test.csv');
const records = parse(data);
for (const record of records) {
    console.log(record);
}

// 結果
// [ '名前', '年齢', '電話番号', '都道府県' ]
// [ '太郎', '30', '090-1111-2222', '東京都' ]
// [ '花子', '28', '080-2222-3333', '埼玉県' ]
// [ '田中', '25', '080-3333-4444', '神奈川県' ]
```

```javascript:先頭行をカラム名にして出力
"use strict";

import fs from 'fs';
import { parse } from 'csv-parse/sync';

const data = fs.readFileSync('test.csv');
const records = parse(data, {
  columns: true,
});

console.log(records);

// 結果
// [
//   { '名前': '太郎', '年齢': '30', '電話番号': '090-1111-2222', '都道府県': '東京都' },
//   { '名前': '花子', '年齢': '28', '電話番号': '080-2222-3333', '都道府県': '埼玉県' },
//   { '名前': '田中', '年齢': '25', '電話番号': '080-3333-4444', '都道府県': '神奈川県' }
// ]
```

```javascript:CSVの書出
"use strict";

import fs from 'fs';
import { stringify } from 'csv-stringify/sync';

const data = [
    { Music: '六兆年と一夜物語', Artist: '和楽器バンド' },
    { Music: '天樂', Artist: '和楽器バンド' },
    { Music: '流星', Artist: '和楽器バンド' },
];

const csvString = stringify(data, {
    header: true,
});

fs.writeFileSync('out.csv', csvString);

// 結果ファイル
// Music,Artist
// 六兆年と一夜物語,和楽器バンド
// 天樂,和楽器バンド
// 流星,和楽器バンド
```

## ログ出力

### 参考
* https://dev.classmethod.jp/articles/node-js-log4js/
* https://github.com/log4js-node/log4js-node

### 事前準備
```console
# npm install log4js
```

### サンプルコード
```javascript
"use strict";

import log4js from 'log4js'

const logger = log4js.getLogger()
logger.level = 'all'

logger.info('Some info messages')

// 結果 
// [2022-04-10T22:43:26.386] [INFO] default - Some info messages
```

## fetch

### 事前準備
```console
# npm install node-fetch
```

### コードサンプル

```javascript
"use strict";

import fetch from "node-fetch";

(async()=>{
    const response = await fetch("https://www.example.com/",{
        method: "GET"
    })

    const html = await response.text();
    console.log(html)
})()
```

## 設定ファイルの管理

### 事前準備

```console
# npm install config
```

```json:config/default.json
{
    "aa": {
        "bb": "cc"
    }
}
```

### コードサンプル
```javascript
"use strict";

import config from "config"

const aa_bb = config.aa.bb;
console.log(aa_bb ); // cc
```
Dockerでnginxのdefault.confやapacheのhttpd.confだけをホストにマウントしてみる

## 概要
Dockerを使ったローカル環境構築をするにあたって、nginxやapacheなどサーバーの設定ファイルをいじりたい場合があります。
Dockerの基本思想は使い捨てなので、こういった設定ファイルはホスト側で持っておいてコンテナにマウントして使えるようにしておくといいですね。
というわけで早速取り出してみましょう。

## 準備
ディレクトリ構成は以下のようにします。
```text:ディレクトリ構成
docker-sample
├── nginx
└── apache
```

## confの取り出し
### nginxのdefault.confを取り出す
手順は
1. nginxのコンテナを立ち上げてコンテナに入る
2. nginxコンテナ内でdefault.confをマウントポイントにコピー

これだけです。
nginxのdefault.confファイルは`/etc/nginx/conf.d/default.conf`にあります。

まず手順1では以下のコマンドを実行します。
```bash:コマンドライン
docker run --rm -v /$PWD/Desktop/docker-sample/nginx:/tmp -it nginx bin/bash
```
これでnginxのコンテナに入った状態になると思います。
続いて手順2で以下のコマンドを実行します。
```bash:コマンドライン
cp /etc/nginx/conf.d/default.conf /tmp/
```
これでマウントしている`docker-sample/nginx`下に`default.conf`が出てきます。
コンテナは以下で終了させましょう。
```bash:コマンドライン
exit
```

#### 少し解説

一応、基本形を見ておきます。
```
docker run [オプション] [イメージ名] [コマンド] [引数]
```

- `--rm`
[オプション]
コンテナ終了時に自動的にコンテナを削除するコマンドです。
今回はconfファイルを取り出すためだけなので取り出した後は用済みということで削除します。

- `-v ~/Desktop/docker-sample/nginx:/tmp`
[オプション]
マウントするコマンドです。
`-v ホスト側ディレクトリ:コンテナ側ディレクトリ`
これでホスト側の`/Desktop/docker-sample/nginx`の中身が
コンテナ側の`/tmp`にマウントされた状態になります。

- `it`
[オプション]
コンテナに入ってシェルコマンドを使うための標準入力と標準出力です。
手順2でコピーコマンドを使うのに必要ということですね。

- `nginx`
[イメージ名]
nginxのイメージですね。
イメージがなければ勝手にDocker Hubからpullしてイメージを作ってくれます。

- `/bin/bash`
[コマンド]
コンテナ内を操作するのにbashを使うためのコマンドです。

### apacheのhttpd.confを取り出す
手順は
1. apacheのコンテナを立ち上げてコンテナに入る
2. apacheコンテナ内でhttpd.confをマウントポイントにコピー

nginxのときと同じですね。
apacheのhttpd.confファイルは`/usr/local/apache2/conf/httpd.conf`にあります。
というわけで先と同じように
```bash:コマンドライン
docker run --rm -v ~/Desktop/docker-sample/apache:/tmp -it httpd /bin/bash
// httpdコンテナに入って
cp /usr/local/apache2/conf/httpd.conf /tmp/
// コピーできたら終了
exit
```

これで以下のようなディレクトリ構成になったはずです。
```text:ディレクトリ構成
docker-sample
├── nginx
│    └── default.conf
└── apache
     └── httpd.conf
```

「ネットに転がってるファイルをコピペしてくりゃいいだけじゃん」
書いててそんな気もしました笑

ただこれはconfに限らず特定のファイル・ディレクトリだけをマウントしたいとか
そういうことにも使えるのでDockerに慣れる意味でもよいかと思います。