OmniAICreator/Qiita-1.07M huggingface dataset:
ECSでaws-sdkを使うときはTaskRoleを正しく設定すればアクセスキーは不要

# 概要
表題の通り。
ECSに限らないが、本番環境でaws-sdkを使うときはIAMユーザーのアクセスキーの設定は不要。
sdkはECSのタスクにattachされたRoleを自動で読み込むため、IAMユーザのアクセスキーを環境変数で渡す必要はない。
↓ sdkはとくに指定なけれattachされたroleを参照する。（EC2以外のリソースも同様）

>Here are the ways you can supply your credentials in order of recommendation:
1. Loaded from AWS Identity and Access Management (IAM) roles for Amazon EC2
2. Loaded from the shared credentials file (~/.aws/credentials)
3. Loaded from environment variables
4. Loaded from a JSON file on disk
5. Other credential-provider classes provided by the JavaScript SDK

https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/setting-credentials-node.html

# ECS(fargate)でSESからメール送信する例

ECSに関するRoleはいくつかあり、その中でもコンテナの権限はTaskRoleで制御する。
↓詳しくは下記参照

https://qiita.com/tmiki/items/25473b8975f8a1095c0a

ECSにattachするTaskRoleに下記policyを追加する。

```ses-policy.json
 {
      "Sid": "sendEmailFromSES",
      "Effect": "Allow",
      "Action": "ses:SendEmail",
      "Resource": "<arn of SES domain>"
 }
```


```ses.js
var AWS = require('aws-sdk');
AWS.config.update({region: 'us-east-1'}); //ここにSESを使うためのクレデンシャル情報の記載は不要

var ses = new AWS.SES();

var params = {
  Destination: {
    ToAddresses: [ 'ichiro@example.com' ]
  },
  Message: {
    Body: {
      Text: {
        Data: 'こんにちは SES',
        Charset: 'utf-8'
      }
    },
    Subject: {
      Data: 'こんにちは',
      Charset: 'utf-8'
    }
  },
  Source: 'jiro@example.com' // From
};

ses.sendEmail(params, function(err, data) {
  if (err) console.log(err, err.stack); // an error occurred
  else     console.log(data);           // successful response
});
```

```ecs-taskdefinition.yml
  TaskDefinition:
    Type: AWS::ECS::TaskDefinition
    Properties:
      Family: !Ref ServiceName
      Cpu: !Ref ContainerCpu
      Memory: !Ref ContainerMemory
      NetworkMode: awsvpc
      RequiresCompatibilities:
        - FARGATE
      ExecutionRoleArn: !Ref ExecutionRoleArn
      TaskRoleArn: !Ref TaskRoleArn #ここにSES権限を正しく設定する
      ContainerDefinitions:
        - Name: !Ref ServiceName
          Cpu: !Ref ContainerCpu
          Memory: !Ref ContainerMemory
          Essential: true
          Image: !Ref ImageUrl
          PortMappings:
            - ContainerPort: !Ref ContainerPort
          LogConfiguration:
            LogDriver: awslogs
            Options:
              awslogs-group: !Sub ${EnvironmentName}-service-${ServiceName}
              awslogs-region: !Ref AWS::Region
              awslogs-stream-prefix: !Ref ServiceName
```
# 参考
https://dev.classmethod.jp/articles/ecs_fargate_iamrole/
個人的に覚えておきたい集 tailコマンド

今回はtailコマンドについて覚えておくべきオプションを掲載します。
tailコマンドは、テキストファイルの最後方を表示するコマンドで、デフォルトではファイルの後ろ10行分表示します。
ちなみにtailの逆の動作をするコマンドとして、headコマンドもあります。

#ファイルが更新される度に表示し続ける
`-f`オプションを追加すると、対象ファイルが更新される度に、新たに追加された最下行の内容を表示し続けます。
「ctrl」 + 「c」で終了するまで表示され続けます。
tailコマンドの基本で、ログ監視の際によく使用されます。

#対象ファイル名が変更された場合も、変更後のファイルを表示し続ける
上記`-f`オプションに対して、`-F`オプションも存在していますが、これは表示対象ファイルの名前が変更された場合、名前を変更した後のファイルをそのまま表示し続ける事ができるオプションです。
例えば対象ファイルの名前にログローテートによって日付が追加された場合も、そのファイルを表示し続けることが出来ます。

#指定したワードが存在している行のみ表示する
tailコマンドの後ろに`| grep <対象ワード>`を追加すると、対象ワードと一致した単語が存在している行のみ表示します。
これはtailコマンドのオプションではありませんが、ログ監視時によく使われる手法として紹介しています。
例えば`tail /var/log/messages | grep err`とすると、「err」という単語がある行のみ表示します。
/var/log/messagesファイル内からエラー内容を調べる時に、「error」というワードが「err」と短縮されている場合もあるため、こういった指定をしています。
なお、単語になっているワードのみを抜き出してくれるわけではないので、上記コマンドの場合「err」というワードを含んだ単語も引っかかってしまいますので、誤検知する事もあります。

#表示する行数を指定する
`-n`オプションを追加すると、表示する行数を指定できます。
指定する際の書式は、`-n <数値>`です。

#表示する文字数を指定する
上記オプションは行数の指定ですが、`-c`オプションを使用すると、出力する文字数を指定できます。
書式は`-n`オプションと同様`-c <数値>`です。

#複数ファイル指定した場合、ファイル名を表示させない
tailに対して複数ファイルを指定した場合、デフォルトでは各ファイル内容毎に先頭にファイル名が表示されますが、これを無効にしたい場合は、`-q`を指定します。
なお、単体のファイルを直接指定した場合はファイル名は表示されませんが、指定した場合もファイル名を表示させたい場合は`-v`オプションを使用します。

#ファイルの内容を行を逆にして表示する
`-r`オプションを指定した場合は、内容を逆から出力します。
どういうことかと言いますと、以下の通り表示する順番が逆となります。

```
tail test.txt
aaa
bbb
ccc
tail -r test.txt
ccc
bbb
aaa
```
安心してforce pushしたい。

雑メモです。

### git で force push したいけど、操作を誤っていないか毎度ビクビクしてしまう。
そんな心労に少しでも楽になる方法を考えてみました。

私の事例で恐縮ですが、force push する際に怖いのは...
1. 誤ったブランチを指定してしまう
2. 共同開発してるブランチで, 相方のコミットを吹き飛ばしてしまう

この2点が代表的だと思います。

1点目に関しては、大切な main (master) や, topic といったマージコミットのみを集合とするようなブランチは、そもそも git push による直接更新をできないようにしておくべきでしょう。 ブランチ保護機能を有効にします。
[Github の設定方法](https://docs.github.com/ja/github/administering-a-repository/defining-the-mergeability-of-pull-requests/managing-a-branch-protection-rule)
[Gitlab の設定方法](https://gitlab-docs.creationline.com/ee/user/project/protected_branches.html)

2点目に関しては, force push する場合のオプション指定でほとんどの場合をカバーすることが出来るでしょう。 *1
具体的には, `git push --force-with-lease --force-if-includes branch名` とするようにします。
長いので alias 貼っておきましょう。

```shell
git config --global alias.pushf 'push --force-with-lease --force-if-includes'

...
# git pushf <ブランチ名>
```

--force-with-lease オプションについて
[git push -f をやめて --force-with-lease を使おう](https://qiita.com/wMETAw/items/5f47dcc7cf57af8e449f)
しかし, git fetch を行った後だと 誤ったforce push が出来てしまう点が課題でした。

--force-if-includes について
[Git Reference](https://git-scm.com/docs/git-push#Documentation/git-push.txt---no-force-if-includes)
[When should I use "git push --force-if-includes"](https://stackoverflow.com/questions/65837109/when-should-i-use-git-push-force-if-includes)
--force-with-lease　の課題である fetch後の誤ったforce push を回避するオプションになります。

上記の設定をしておくことで、少しでも安心して作業ができるのではないでしょうか。

### fishシェル特有の悩み

余談ですが、 fishシェルはありがたいサジェッションのおかげで過去に入力したコマンドを素早く再入力できるのですが、
force push を行う際に異なるブランチ名がサジェストされがちで、気をつけないと行けません。
(作業してるブランチと異なる別ブランチにpushしてしまう可能性がある)

回避策として以下のコマンドを自作しました。

特徴はとしては2点。
1. push先のブランチ名が作業ブランチと異なると怒ってくれる。
2. force push オプションに --force-with-lease --force-if-includes を付けていること。

あえてブランチ名を要求することで、脳死で打たせないようにしています。

```shell:$HOME/.config/fish/functions/gpf.fish
function gpf --wraps='git push origin' --description 'gpf is git push origin force'
  set -l targetBranch $argv
  set -l currentBranch (git branch | grep -E "^\*" | cut -c 3-)

  if test $currentBranch = $targetBranch
    git push --force-with-lease --force-if-includes origin $targetBranch
    echo "done 👍"
  else
    echo ""
    echo \
"""   Careful!!
   Make sure you push to the same branch you are checking out now."""
    echo "   you: $currentBranch , push to: $targetBranch"
  end
end
```

上記の関数を $HOME/.config/fish/functions に保存します。
git repository 配下で以下のようなコマンドで実行出来ます。
gfpじゃないのはご愛嬌ということで...

```console
gpf <ブランチ名>
```


*1 コメントで頂いた内容を反映しました。
廃棄PCのantix上にrubyonrails環境構築テスト

# rubyonrails-test

* 家の廃棄予定のノートPC（Pentium）にantixをいれて、rubyonrails+node.js環境構築のテスト
* rubyは新しいものがいれられなかったため、2.6.3をビルドしている
* 結論：nodeがうまくいれられずに断念

## 環境構築 mac

* VSCode拡張
  * Ruby
  * HTML Snippets

* Rubyのインストール

```zsh
# update
brew update

# rbenv 
brew install rbenv ruby-build
echo 'eval "$(rbenv init -)"' >> ~/.bash_profile
source ~/.bash_profile

# readline
brew install readline
brew link readline --force

# ruby
RUBY_CONFIGURE_OPTS="--with-readline-dir=$(brew --prefix readline)"
# install ruby
rbenv install 2.6.3
# use ruby
rbenv global 2.6.3
rbenv rehash
# check ruby version
ruby -v



```

## 環境構築 antiX

* antiX install
  * 基本デフォルトでインストール CDにやいてCDからブート`cli-installer`
  * 参考 https://antixlinux.com/forum-archive/install-using-the-cli-installer-t3041.html
  * 時刻設定だけ東京に変更
* 設定終わってログインしたら`sudo apt update && sudo apt upgrade`
* grubの更新がされているので全てのディスクにインストールをする（BIOSありの場合）
* 必要あればネットワークとかの設定を行う`antiX-cli-cc`

## 環境構築 antiX

* rbenv ruby gem bundler 

```bash

sudo apt update

sudo apt install -y gcc make bzip2 git libssl-dev libreadline-dev zlib1g-dev

sudo apt update

git clone https://github.com/rbenv/rbenv.git ~/.rbenv

echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bashrc
echo 'eval "$(rbenv init -)"' >> ~/.bashrc
# reload bash
source ~/.bashrc

mkdir -p "$(rbenv root)/plugins"
# rbenv プラグインをインストール
git clone https://github.com/rbenv/ruby-build.git "$(rbenv root)/plugins/ruby-build"
# rbenv install 後に ~/.rbenv/default-gems に記載の gem をインストールしてくれる
git clone https://github.com/rbenv/rbenv-default-gems.git "$(rbenv root)/plugins/rbenv-default-gems"
echo bundler > "$(rbenv root)/default-gems"
# $ rbenv update すると、~/.rbenv/plugins 以下を全部 git pull してくれる ruby-build も対象となる
git clone https://github.com/rkh/rbenv-update.git "$(rbenv root)/plugins/rbenv-update"

sudo apt update

rbenv install 2.6.3
rbenv global 2.6.3
rbenv rehash

# check version
ruby -v
gem -v
bundler -v

```

* node.js npm

```bash
# get setup.sh
# execute setup.sh
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.37.2/install.sh | bash

source ~/.profile

     curl -sL https://dl.yarnpkg.com/debian/pubkey.gpg | gpg --dearmor | sudo tee /usr/share/keyrings/yarnkey.gpg >/dev/null
     echo "deb [signed-by=/usr/share/keyrings/yarnkey.gpg] https://dl.yarnpkg.com/debian stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
     sudo apt-get update && sudo apt-get install yarn


```
C# Enviroment.NewLineが信頼できない場合の改行コード判定

### 文字列に改行コードが存在する場合のみ。それ以外は`Environment.NewLine`を信じる。
```C#
    class Program
    {
        public static string GetNewLine(string s)
        {
            //using System.Text.RegularExpressions;
            var c = Environment.NewLine;
            if (Regex.IsMatch(s, "\r\n")) c = "\r\n";
            else if (Regex.IsMatch(s, "\r")) c = "\r";
            else if (Regex.IsMatch(s, "\n")) c = "\n";
            return c;
        }

        static void Main(string[] args)
        {
            var rn="aaa\r\nbbb";
            var n="aaa\nbbb";
            var r="aaa\rbbb";
            var not="aaabbb";

            var _rn=GetNewLine(rn);//\r\n
            var _n=GetNewLine(n);//\n
            var _r=GetNewLine(r);//\r
            var _not=GetNewLine(not);//\r\n

            Console.WriteLine("Hello World!");
        }
    }

```
【Vue】親子での表示タイミングのズレを修正する

#環境
Vue.js 2.6.11
Rails 6.1.3

#修正する部分

![status_check.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1110285/3d54164d-b9d7-7dbd-e0f2-47cec2050347.gif)


質問の解決ステータスを表すステータスブロックと回答数が周りに比べて少し遅れて表示されてしまっています。
このままだと少し気持ち悪いので同タイミングで表示されるように修正します。
また、ページネートの< >もちらついているのでそれも解消しようと思います。 


##構成
質問カードの構成は、
QuestionBase.vue
---QuestionCommetnsCount.vue
---QuestionStatus.vue
とステータスブロックと回答数の部分は周りに対して子要素となっています。

また、ステータス部分の判定は、
①axiosでそれぞれの質問にベストアンサーがあるかをaxiosで取得
②あればbestAnswerに代入、なければエラーに分岐
③v-ifでbestAnswerがあれば解決済み、なければ回答受付中を表示
となっています。

```vuejs:QuestionStatus.vue
<template>
  <div>
    <div
      v-if="bestAnswer"
    >
      解決済
    </div>
    <div v-else>
      回答受付中
    </div>
  </div>
</template>

<script>
import axios from "axios";
export default {
  props: ["question"],
  data: function () {
    return {
      bestAnswer: "",
    };
  },
  created() {
    axios
      .get(`/api/v1/bestanswer/${this.question.id}`)
      .then((response) => {
        this.bestAnswer = response.data;
        console.log(response.data);
      })
      .catch((error) => {
        console.log(error);
      });
  },
};
</script>
```

##なぜ表示タイミングがずれているのか？

ライフサイクルを確認してみます。

![lifecycle.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1110285/4280223a-124e-f231-8c25-cc4a393bf883.png)

親要素のmountが終わってから、子要素のcreatedが始まっているのが確認できました。
これが原因で表示の時間差が起こっているようです。

#解決方法
##周りに比べて表示が遅れる

**emit**を使って、子要素のcreatedが終わったタイミングで親要素にそれぞれtrueを渡しています。
両方揃ったタイミングで、同時にレンダリングされるようになります。

またここで、v-ifを使うとそもそも子要素のcreatedが行われず表示がされなくなるので注意です。
(内部の子要素も動作しないため)

```vuejs:QuestionCommetnsCount.vue
<script>
...
created() {
    axios.get(`/api/v1/comments_count/${this.question}`).then((response) => {
      this.count = response.data;
      this.$emit("isCountCreated", true);
    });
</script>
```

```vuejs:QuestionStatus.vue
<script>
...
created() {
    axios.get(`/api/v1/bestanswer/${this.question.id}`).then((response) => {
      this.bestAnswer = response.data;
      this.$emit("isStatusCreated", true);
    });
</script>
```

```vuejs:QuestionBase.vue
<template>
  <div v-show="isCountCreated && isStatusCreated">
...
</template>
```

##ステータスが表示されてから切り替わる
質問ステータスが、解決済のものも一瞬「解答受付中」が表示されてから「解決済」に切り替わっていました。
これに関しても、上記の解決方法と同様にaxiosに

```vuejs
this.isStatusCreated = true
```

を仕込んでおき

```vuejs
<div v-if="isStatusCreated">
```

としておけば解決です。

![render2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1110285/8b9da285-ed8f-e0f3-5ac0-05a6fa8032b9.gif)
Unity いい感じに設定したUI.Textの使い回し。


### 1.Extensionをセット
```C#
using UnityEngine;
public static class GameObjectUtils
{
    public static GameObject Clone(this GameObject go,string newname=null)
    {
        var clone = GameObject.Instantiate( go ) as GameObject;
        clone.transform.parent = go.transform.parent;
        clone.transform.localPosition = go.transform.localPosition;
        clone.transform.localScale = go.transform.localScale;
        if(newname!=null) clone.name=newname;
        return clone;
    }

}

public static class ColorStringExtension
{
    public static Color ToColor(this string self)
    {
        var color = default(Color);
        ColorUtility.TryParseHtmlString(self, out color);
        return color;
    }
}

```

### 2.```UI.Text```を適当に作成。いい感じに設計。
```C#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class baseText : MonoBehaviour
{
    [SerializeField]Text m_text;
    void Awake(){
        gameObject.name="BaseText";//
        gameObject.transform.localPosition=Vector3.zero;
        m_text=gameObject.GetComponent<Text>();
        m_text.fontSize=16;
        m_text.color="#0f0".ToColor();
    }

    public void SetText(float x,float y,string text){
        m_text.text =text;
        gameObject.transform.localPosition = new Vector3(x,y,0);
    }
    public void SetText(string text)=>m_text.text=text;
}

```

### 3.使い回す。Canvasの直下あたりで
```C#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class texttest : MonoBehaviour
{
    // Start is called before the first frame update
    GameObject a;
    GameObject b;
    void Start()
    {
        a=GameObject.Find("BaseText").Clone("test1");
        a.GetComponent<baseText>().SetText("test1");
        //
        b=GameObject.Find("BaseText").Clone("test2");
        b.GetComponent<baseText>().SetText(0,16,"test2222222");
    }

    // Update is called once per frame
    void Update()
    {
        if(Input.anyKey){
            GameObject.Destroy(a);
            GameObject.Destroy(b);
        }        
    }
}
```
2021-09-12 Godot Engine > ボードゲーム 41ゲームの実装 > TileMapのセルの練習 (world_to_map(), get_cellv(), set_cellv()など)

### 動作環境

```
Windows 10 Pro v21H1
Godot Engine v3.3.2.stable.official
```

## 41ゲームの説明

https://www.4181games.com/4181games-com/41game/

## Godot実装

### 構成

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32870/9ee07c06-f77d-3de7-57e7-f13700fcfa07.png)

TileMapにTileMap.gdをアッタッチする。

TileMapには下記の画像を使用する(64x64の画像を四つ)。
実際に使うのは二つ目と四ツ目だけではあるが。。。

![fortyOne_210909.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32870/47fed053-f47f-26e6-9f3b-4a12f862fb8b.png)

### 実装 (TileMap.gd)

```python:TileMap.gd
extends TileMap

enum {
	CELL_TILE = 0, # タイル
	CELL_BALL, # ボールが置かれている
	CELL_NOT_USED, # 不使用
	CELL_PICKED,  # 配置できる
}

enum {
	STS_DROP = 0, # ボールが置かれている
	STS_PICKED, # ボールを持ちあげている
}

onready var s_state = STS_DROP
onready var label = get_node("../Label")
var s_picked

func _input(event):
	if event is InputEventMouseButton:
		if event.pressed == false:
			return
		if event.button_index != 1:
			return		
		
		var mouse_tile = world_to_map(get_global_mouse_position())
		var tile_id = get_cellv(mouse_tile)
		print(tile_id)
		
		if s_state == STS_DROP:  # Pickup
			# ボールが配置されたセルか
			if tile_id != CELL_BALL:
				return

			set_cellv(mouse_tile, CELL_PICKED) # セル画像の変更 (Pickupした状態)
			s_picked = mouse_tile # Drop時の処理に使う

			# 状態とラベルの変更
			s_state = STS_PICKED
			label.text = "Picked"
			pass
		else:  # Drop
			# 配置できる(ボールがない)かどうか
			if tile_id != CELL_PICKED:
				return

			# 飛び越すセル位置
			var middle = (s_picked + mouse_tile) / 2
			print(middle)

			# 配置は縦方向か横方向のボールを飛び越すものだけ
			var diff = s_picked.distance_to(middle)
			print(diff)
			if diff == 0:
				set_cellv(mouse_tile, CELL_BALL)
				s_state = STS_DROP
				label.text = "Dropped"
			if diff < 1 || diff > 1:
				return

			# 飛び越すところにボールがあるかどうか
			var middle_ball = get_cellv(middle)
			if middle_ball != CELL_BALL:
				return

			# セル画像の変更
			set_cellv(mouse_tile, CELL_BALL)
			set_cellv(middle, CELL_PICKED)
			
			# 状態とラベルの変更
			s_state = STS_DROP
			label.text = "Dropped"
			pass
				
```

### 実行例

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32870/ccbbb6c9-84b1-257d-dd7d-1d778f1c9f9c.png)

- 青丸 : ボールが置かれている
    - このいずれもがPickupできる
- 黒の円 : ボールを配置可能

左上のラベルは現在の操作の状況(PickedかDropped)。

Pickupしたボールを縦か横方向にボールをまたぐ方に移動できる。
Pickupした場所にDropもできる（操作のキャンセル）。

最後にボールが一つだけにできればゲームクリア。

### 配置

デザイン画面で配置を変更すれば、任意のパターンの41を遊べる。


### 画像を変えてみた

参考: [【Level2】ボタンをドット絵で色々な形にする方法【ドット絵講座】](https://moshi-nara.com/18149/)

![fortyOne_210909.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32870/26e5abb3-06e7-c60a-4a97-7779d32dd324.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/32870/b21e6c8d-2ed0-c478-c889-9ea5182c2914.png)
クッキーとセッションの違いをポンコツ販売員の俺で例える

こんにちは！
今回はクッキーとセッションの違いについて、アウトプットしていきたいと思います。


# HTTP通信はステートレスなプロトコルらしい。


ステートレスとは状態がないを意味しています。
HTTPプロトコルではリクエストを送り、レスポンスを受け取った時点でその通信は終了してしまうんです。

つまり、一度目の通信でクライアントからいくつかの情報を受け取ったとしても、2度目の通信は前の状態は引き継ぎがない全く関係のない通信になるんです。

僕、前職でアパレル販売員やってました。
当時の僕は記憶力に乏しく（⚠︎今もです。）、
一度接客したお客さんが再来店された際に全くその情報を覚えていないというポンコツっぷりを発揮していました。
僕が覚えていないということは、
お客様側から僕に情報を再びお教えいただかなければいけません。
客「トップスのサイズは普段はMでズボンのウェストは２８インチ、足のサイズは27.5で〜〜（これ全部前回来店した時お前にいうたやんけ！！！なんでもう一度言わなあかんねん！！！）」
顧客ファーストに考えられないとかマジありえん‥。
僕も常にステートレスな状態と言えるでしょう。

しかし、実際はHTTP通信がステートフルな通信がされいるかの如く、僕もお客様情報を覚えていられる方法があるんですよ！！

# cookieとsessionとは

## cookie
cookieとはHTTPヘッダーに格納できるテキストデータで、このデータはクライアントのブラウザに保存されます。
cookieを利用しブラウザに値を格納することで、HTTPプロトコルの値を保持できない問題を解決できますね！

でもこれってめっちゃ危険な状態なんです。
重要な機密性の高い情報をクッキーに保存すれば、サーバーと通信するたびにそれらをHTTPヘッダーに設定することになります。
また、クライアント側で保持できることで改ざんの可能性も出てきますよね。
よってクッキーだけでステートフルな通信を作ることはセキュリテイ上あんまり好ましくないですよね。

ポンコツアパレル販売員の僕で例えてみましょう。
なかなか顧客情報が覚えられない僕はこう考えました。
「そうや！お薬手帳みたいに顧客手帳(クッキー)を作成して、来店時に顧客情報を俺が書き込むんや！それを顧客一人一人に
持っておいてもらって再来店時に俺に渡してくれたらええんや！！顧客手帳を来店時にいただくことでその人の情報を取得することができる！！」

いざこの方法を試してみるとある顧客様が再来店時に顧客手帳の情報を書き換えられていました。
「おい！50000円のズボンを購入したって顧客手帳に書いてあるのに袋開けたら入ってへんやんけ！！」
これは大変です！顧客手帳(クッキー)をお客さん側が保持することでデータを改竄されてしまいました。
（本当はレシートとかで調べようあるんやけどね。）

余談ですけど、まじでまじでこんなことやっちゃ販売員としてだけじゃなく人として失格ですよ。
お客さんへの愛情が感じられないですし、顧客情報はお店が管理するものです。
因みに僕は本当に覚えられないことが悔しかったので、当時来店された際にメモ取るようにしていました。

## session

クッキーはHTTPヘッダーに書くのできるテキストデータで、これはクライアントのブラウザに保存されるものでした。

セッションはクライアントとサーバの通信の状態を保持することができます。
セッションを利用して様々なHTTP通信一つのまとまりとして扱うことを***セッション管理***と言います。

じゃあクッキーとの違いはなんでしょうか？
それはセッションはクライアントのブラウザではなくサーバー側に保存されるということです。
サーバーではあるセッションと紐付いたキーであるセッションIDを保存しておいて、
セッションIDのみをクライアントに渡します。
セッションIDをクライアントに渡す手段として一般的にクッキーを利用します。
セッションIDを受け取ったクライアントはクッキー経由でサーバーに渡すことで,
以前の通信の状態を保持したセッションを取り出すことができるんです！

これを再びポンコツで例えてみましょう。
来店されたお客様にID付きのポイントカードを作成してもらいます。
顧客情報ファイルをお店で保管し、顧客一人一人の情報をポイントカードのIDとともに管理。
再来店された顧客はポイントカードをポンコツに渡すだけでいいんです。
ポイントカードをお預かりしたポンコツは顧客情報に紐付けられたIDから
情報を引っ張ってくることができるので、セキュリティ面の観点から
セッションで顧客情報を管理する方がいいのではとポンコツは気付きました！！

# まとめ
HTTP通信はステートレスなプロトコルです。
クライアントの一度のリクエストからレスポンスを返すと通信が終了してしまいます。
そこでHTTPヘッダーに格納できるデータであるクッキーを利用して、セッションIDをクライアント側に送信します。
セッションIDを受け取ったクライアントはクッキー経由でサーバーに渡すことで以前の通信の状態を保持したセッションを取り出すことができる！！
[TypeScript] typeof type guardsについて

TypeScriptで個人的に一番役に立っているtype guardsの一つ、typeof type guardsについて書きます✍️


## 結論
typeof演算子により型が一致すると、条件分岐ブロック内部で型の絞り込み推論が適用される機能。

## 解説

例えば下記コードのような、引数に`number`又は`string`又は`boolean`の型が入る関数があったとする。

```typescript
export const TypeofTypeGuard = (value: number | string | boolean) => {
  if (typeof value === 'number') {
    console.log('typeof:', typeof value)
  }
  if (typeof value === 'string') {
    console.log('typeof:', typeof value)
  }
  if (typeof value === 'boolean') {
    console.log('typeof:', typeof value)
  }
}
```

この関数内部では条件分岐でtypeof演算子を使い、型を絞り込んでいるため、`console.log('typeof:', typeof value)`では、それぞれ絞り込んだ型が表示されます。

下記は実行結果👇

```typescript
import { TypeofTypeGuard } from './typeofTypeGuards'

const num = 5
const str = "Hello TypeGuard"
const bool = true

TypeofTypeGuard(num)
TypeofTypeGuard(str)
TypeofTypeGuard(bool)
```

```bash
typeof: number
typeof: string
typeof: boolean
```

## まとめ
typeof type guardsを利用すると、動的に型が変わってもそれぞれの処理を記述することが出来るので、非常に便利です。
使い方もそんなに難しくないのが嬉しいですね😆
【初学者向け】JavaScriptのmapとfilterについて

##はじめに
今回はJS勉強し始めた方向けにmapやfillterの解説をしていきます。(※Mapオブジェクトの方ではないです)
後半の【レベルUP】は少し難しく感じるかもしれないので飛ばしてもらって構いません


##mapとfilterとは
２つとも配列に関して使用できる関数です。
配列処理でfor文を使わなくて済みます。

ぞれぞれの**イメージ**を記号を使って表すと

<font color="OrangeRed">map: 配列に同じ処理をして新しい配列を生成</font>
[ 🔴 , 🔵 , 🟡  ].map(○ → □) → [ 🟥 , 🟦 , 🟨  ]


<font color="MediumSeaGreen">filter: 条件を満たす要素のみ取り出し新しい配列を生成</font>
[ 🔴 , 🟦 , 🟨 , 🔺 ].filter(□) → [ 🟦 , 🟨  ]


##mapの使い方
今回はある配列にmapを使って『２倍にする』という処理をしていきます。

```js
//まずは配列arryを用意
const arry = [1, 2, 3, 4];

//配列arryにmapを使用して新しい配列arry2として定義
const arry2 = arry.map((num) => {
   return num * 2;
})

console.log(arry2);  // [2, 4, 6, 8]
```
上の流れを見ていきましょう。
①引数に配列の要素が順番に入ってくる(引数のnumに配列arryの要素が入っていきます ※引数の名前は任意です。)
②順番に同じ処理をする(今回はreturn num * 2なので値を2倍して返す)
③新しい配列が生成される(今回はarryからarry2が生成)　


##filterの使い方
今回はある配列にfilterを使って『偶数だけ取り出す』処理をしていきます。

```js
//配列を用意
const arry = [1, 2, 3, 4, 5];

//新しい配列arry2を用意。右辺でarryにfilterを使用。
const arry2 = arry.filter((num) => {
   //2で割ってあまりが0となるものだけ返す
   return num % 2 === 0;
});

console.log(arry2);   //[2, 4] 
```

①引数に配列の要素が順番に入ってくる
②return文で条件式を書く
③条件式を満たすものだけ取り出して新しく配列を生成

##【レベルUP編】##
**①引数を複数使用**
mapもfilterも引数を3つ持つことができます。(第2引数はindex。第3引数は配列自体を表します)
**第二引数とテンプレートリテラルを使用すると**

```js
const nameArry = ["近本", "中野", "マルテ"];

nameArry.map((name, index) => console.log(`${index + 1}番は${name}です`));
//1番は近本です
//2番は中野です
//3番はマルテです
```
と表すことができます。

**②map + if文**
mapの中でif文を使用し、条件分岐(※処理を行う要素、行わない要素を分けること)ができます。

```js
const nameArry = ["近本", "中野", "マルテ"];
const newNameArr = nameArr.map((name) => {
    if(name === "マルテ") {
     return name
    } else {
     return `${name}君`
    }
})
console.log(newNameArr);
//近本君
//中野君
//マルテ
```

**③map + filter**
今回はある配列に**filter**で『奇数のみ取り出す』処理を行い、その後**map**で『＋１０する』処理を行います。

```js
const arry = [1, 2, 3, 4, 5, 6];

const answer = arry.filter(num => num % 2 === 1).map(num => num + 10);
console.log(answer);      // 11 13 15
```

ちなみに[reduce](https://qiita.com/yasu-hoshi/items/90e26fef58b36c1fcfc6)を使用して同様の処理も可能。

```js
const answer = arry.reduce((acc, cur) => {
  if (cur % 2 === 1) {
    const plusNum = cur + 10;
    acc.push(plusNum);
  }
  return acc;
}, []);

console.log(answer); 
```
※reduceの初期値として空配列を使用しています。詳しくは参考記事をご覧ください。

##参考記事

reduceの初期値について

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce

https://kde.hateblo.jp/entry/2018/10/13/065738

https://iwb.jp/javascript-reduce-howto-use/
Pandasのapplyの使い方！

# 執筆の経緯

pandasでapplyを使うときにやり方忘れがちなので、個人的メモとしてまとめておきます。

# 無名関数の場合

```python
df['dessert'] = df['dessert'].apply(lambda x : x.lower())
```

**apply**関数は**replace=True**を使えないので、applyしたものは代入して上書きが必要です。
ここも忘れがちなので注意。

# 宣言された関数を利用する場合

```python
def make_dessert_name_lower(x):
    return x.lower()

df['dessert'] = df['dessert'].apply(make_dessert_name_lower)
```

()内は関数名のみの指定で通常の関数宣言のように**make_dessert_name_lower(x)**としなくても大丈夫です。

# おまけ　applyしないでseriesに一括処理を加えたい場合

```python
desserts = []

for dessert in df['desert']:
    lower_dessert = dessert.lower()
    
    desserts.append(lower_dessert)

df['desert'] = dessert
```

必要になるケースがあるか分かりませんがよく見かける書き方です。



ここまで、お付き合いいただきありがとうございました。
M1 Mac環境でTensorFlowを使う


M1 MacでTensorFlow環境を構築するには、Anacondaを利用するのが簡単です

Anaconda Individual Editionをインストール

https://www.anaconda.com/products/individual

Apple Developerサイトそのままの情報ですが、

https://developer.apple.com/metal/tensorflow-plugin/

miniforge3環境をダウンロードする

```
$ wget https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-MacOSX-arm64.sh
$ chmod a+x Miniforge3-MacOSX-arm64.sh
$ . Miniforge3-MacOSX-arm64.sh
```

miniforge3環境を起動する

```
$ source ~/miniforge3/bin/activate
```

Tensorflow関係のツールをインストールする

```
$ conda install -c apple tensorflow-deps
$ python -m pip install tensorflow-macos
$ python -m pip install tensorflow-metal
```

おわり
リストから名前指定remove()したときに同じ名前の要素が複数あったらどうなるか

# 気になったこと
python3のリスト操作で、remove()関数を使って指定した要素を削除することがありますが、リストの中に同じ要素があった場合にどのような消え方をするのかふと心配になったので確認しました。

# 確認結果
「apple」の文字列から「p」をremove()しましたが、消えた「p」は1個だけでした。安心しました。

``` python3
>>> test_list = list("apple")
>>> print(test_list)
['a', 'p', 'p', 'l', 'e']

>>> test_list.remove("p")
>>> print(test_list)
['a', 'p', 'l', 'e']
```
Kotlin Parcelable の独自実装の方法

## はじめに

Parcelable の独自実装の方法について調べたことを記事として残します。

## インストール方法

プロジェクトのテンプレートで「Empty Compose Activity」を選択した場合、次のコードを build.gradle に追加するだけで設定が完了します。

```gradle
plugins {
    id 'kotlin-parcelize'
}
```

## 自作クラスを Parcelable にする方法

次のコードは、`Foo` クラスを Parcelable にするコードです。

```kotlin
@Parcelize
class Foo : Parcelable {
  private companion object : Parceler<Foo> {
    override fun create(parcel: Parcel): Foo {
      TODO()
    }
    override fun Foo.write(parcel: Parcel, flags: Int) {
      TODO()
    }
  }
}
```

`create` はデコード時に呼ばれるメソッド、`write` はエンコード時に呼ばれるメソッドだと思います。

## 既存クラスを Parcelable にする方法

`Parceler<T>` を実装したシングルトンオブジェクトを作成し、型を `@WriteWith<*>` で装飾すると Parcelable になります。

```kotlin
// Bar クラスは既存クラスという想定
class Bar

object BarParceler : Parceler<Bar> {
  override fun create(parcel: Parcel): Bar {
    TODO()
  }
  override fun Bar.write(parcel: Parcel, flags: Int) {
    TODO()
  }
}

typealias ParcelableBar = @WriteWith<BarParceler> Bar

// 次のように使用する
@Parcelize
data class Baz(val bar: ParcelableBar) : Parcelable
```

`@WriteWith<*>` が複数並ぶ場合は `@TypeParceler<*, *>` を使うことで簡潔に書けます。

```kotlin
@Parcelize
data class MyData(
  val instant1: @WriteWith<InstantParceler> Instant,
  val instant2: @WriteWith<InstantParceler> Instant,
  val instant3: @WriteWith<InstantParceler> Instant,
) : Parcelable

// ↑ と ↓ は等価

@Parcelize
@TypeParceler<Instant, InstantParceler>
data class MyData(
  val instant1: Instant,
  val instant2: Instant,
  val instant3: Instant,
) : Parcelable
```

## 参考

[Parcelable 実装生成ツール | Android デベロッパー | Android Developers](https://developer.android.com/kotlin/parcelize?hl=ja)
【Project Euler】P294: Sum of digits - experience #23のメモ（その１）

### 23の倍数で各桁の和が23の数を11<sup>12</sup>まで数える

## 再帰関数＋lru_cache

[P294: Sum of digits - experience #23] (https://projecteuler.net/problem=294) は表題のように簡単そうな問題ですが、数がとんでもなく大きいのでギブアップでした。

まず普通に再帰関数で書くとこんな感じですが時間がかかって問題外。

```python
def S(nd,m,ds): #桁 10**nd, m: 23で割った余り, ds: 桁の和
  if nd == 0:
    return 1 if (m % 23 == 0) and ds == 23 else 0
  ret = 0
  for d in range(min(23-ds+1,10)):
    ret += S(nd-1,(m*10+d)%23,ds+d)
  return ret

ND = 42
print((f"ND = {ND}, answer = {S(ND,0,0)})
```

そこでお約束のlru_cacheを設定すると劇的に改善して11<sup>4</sup>までは何とか1分以内で終了。でも先は遠い、、、

```python
from functools import lru_cache

@lru_cache(maxsize=None)
```

## 動的計画法（1条件）

この手の問題は動的計画法かなと思いましたが、あまり得意ではないので、まず条件の１つの各桁の和が23のみを書きました。

```python
import numpy as np
n, D = 9, 23
dp = np.array([0] * (n+1)*(D+1)).reshape(n+1,D+1)
dp[0, 0] = 1

for i in range(n):
  for j in range(D+1):
    for k in range(min(D-j+1,10)):
        dp[i+1,j+k] += dp[i,j]

print(dp[n,D])
```

## 動的計画法（2条件）
この問題では以下の2つの条件があるので、

* 各桁の和が23
* 23で割り切れる

DP tableを(23+1 x 23+1)の2次元mapにして、X軸で23で割った余り、Y軸で桁の数の合計を、各桁ごとにカウントするようにしました。計算には一つ前の桁の値しか使わないので、2つのmapを交互に使うようにしました。(使った後で0でクリアしてます)
でもこれも1分で解けるのはk=11<sup>4</sup>までで、今回はちょっとお手上げでした。

```python
import numpy as np

def clearMap(map):
  for i in range(len(map[0])):
    for j in range(len(map)):
      map[i,j] = 0  # clear next table for reuse 

def dpMap(n, D, M):
  BF, D1, D1 = 2, D+1, D+1   # 桁、桁の和、余り、
  dp = np.array([0] * BF*D1*D1).reshape(BF, D1, D1)
  dp[0, 0, 0] = 1
  for i in range(n):  # 桁
    clearMap(dp[(i+1)%2]) # 次のmapを0でクリア
    for d in range(D1):  # 桁の和
      for m in range(D1):  # 余り
        for k in range(min(D-d+1,10)):  # i+1番目の桁の数 (d+k<=D)
          dp[(i+1)%2,d+k,(m*10+k)%D] += dp[i%2,d,m]
          dp[(i+1)%2,d+k,(m*10+k)%D] %= M
  return dp[(i+1)%2,D,0]

n = 42
ans = dpMap(n, 23, 10**9)
print(f"n = {n}, ans = {ans}")
```
【Flask】５分で仮想環境構築と「Hello World!」の表示

## 環境
+ Microsoft Windows 10.0.19042.1165
+ Python 3.9.4
+ Flask 1.1.2

## ディレクトリ構成

```
flask_test/
  ├─ venv/
  └─ app.py
```

## 手順
Pythonはインストール済みとする

https://www.python.org/

仮想環境用ディレクトリ `flask_test` を作成（ `mkdir [フォルダ名]` ）

```
mkdir flask_test
```
`flask_test` に移動（ `cd [フォルダ名]` ）

```
cd flask_test
```

仮想環境を作成（ `python -m venv ./[フォルダ名]` ）

```
python -m venv ./venv
```

仮想環境を有効化（ `[フォルダ名]\Scripts\activate` ）

```
venv\Scripts\activate
```
→ 先頭に `(env)` が付く

:::note
無効化するときは「deactivate」と入力
:::

仮想環境の中にFlaskをインストール

```
pip install Flask
```

`flask_test` フォルダの中に `app.py` を作成

```python:app.py
from flask import Flask
app = Flask(__name__)

@app.route("/")
def index():
    return "Hello World!"

if __name__ == "__main__":
    app.run(debug=True)

```
実行する

```
Flask run
```

http://localhost:5000/ にアクセスすると"Hello World!"と表示される

## ちなみに

以下のように入力すると `requirements.txt` に現在の環境（設定）を書き出すことができる

```
pip freeze > requirements.txt
```
全株式の20年分の値動きを取得する

# はじめに
<!-- 発端や概要を記載 -->
株式運用を始めるにあたって長期的な値動きを把握したいと思ったので。
それだけならYahoo!株式とか見てりゃいいんですけど、
データの加工なんかを想定するとAPIで色々操作したほうが良さそうだよね
ということでYahoo Finance API を使った上場株式の値動きを一気に取得できるプログラムを作りました。

# 目次
<!-- タイトルとアンカー名を編集 -->
1. [APIから元データを取得する](#Chapter1)
1. [元データから日付と終値のみを取得する](#Chapter2)
1. [Github](#reference)

<!-- 各チャプター -->
<a id="#Chapter1"></a>
# APIから元データを取得する
```Python:main.py
def get_symbol_data(share_code):
  my_share = share.Share(share_code)
  symbol_data = None

  try:
      symbol_data = my_share.get_historical(share.PERIOD_TYPE_YEAR,
                                            20,
                                            share.FREQUENCY_TYPE_DAY,
                                            1)
  except YahooFinanceError as e:
      print(e.message)
      sys.exit(1)
  return symbol_data
```

share_codeには "1570.T"のような文字列が入ります。

```Python:main.py
symbol_data=get_symbol_data("1570.T")
print(symbol_data.keys())
>>dict_keys(['timestamp', 'open', 'high', 'low', 'close', 'volume'])
```

各Keyには1日毎に日時や株価を取得した配列が入っています。

```Python:main.py
  prices = symbol_data["close"]
  print(prices)
>>[100,101,99...]
```

<a id="#Chapter2"></a>
# 元データから日付と終値のみを取得する
```Python:main.py
def return_dates_prices(symbol_data):
  dates=symbol_data["timestamp"]
  formated_dates = [datetime.utcfromtimestamp(int(dates[i]/1000)) for i in range(len(dates))]
  formated_dates_only_dates=[formated_dates[i].strftime("%Y-%m-%d") for i in range(len(formated_dates))]
  prices = symbol_data["close"]
  return formated_dates_only_dates,prices

formated_dates,prices=return_dates_prices(symbol_data)
>>formated_dates=["2000-01-01","2000-01-02","2000-01-03"...]
>>prices=[100,101,99...]
```

みたいな感じで 日付と終値を約20年間くらい取得することが出来ます。

<a id="#reference"></a>
# GitHub
https://github.com/GitHubYucky/get_stock_data_with_Yahoo_API
[環境構築] Pythonのバージョン切り替えができない

##はじめに
pythonを使ったアプリ開発に挑戦しようとしたところpythonのインストールの時点でつまづいたので記事にしておきます。

##つまった時の状況
使用しているのはmacOSのCatalina10.15.7
シェルはzsh
homebrewを用いてpyenvをインストール(pyenv 2.0.6)

```shell:ターミナル
brew install pyenv
```


下記のコマンドを順に実行（.zshrcにpyenv設定を書き込んでいくコマンド)

```shell:ターミナル
echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.zshrc

echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.zshrc

echo 'eval "$(pyenv init -)"' >> ~/.zshrc

source ~/.zshrc
```

pyenvを用いてPythonをインルトール(Python 3.9.7)

```shell:ターミナル
pyenv install 3.9.7
```

標準で搭載されているPythonからインストールしたPythonに切り替え

```shell:ターミナル
pyenv global 3.9.7
```

切り替わっているか確認

```shell:ターミナル
python --version
Python 2.7.16
```

ファッ！？

##解決した方法
.zshrcの記述を疑う

公式のgitのreadmeと他の方の記事を参考にこの部分を修正↓

```shell:.zshrc(修正前)
# ~省略~
eval "$(pyenv init -)"
```

```shell:.zshrc(修正後)
# ~省略~
eval "$(pyenv init --path)"
```

あとは、念のため```~/.python-version```が生成されたりするとよろしくないらしいので、削除するコマンドを実行しておきました。いろいろ試していると知らず知らずに生成されていたりするらしいです。


```shell:ターミナル
rm ~/.python-version
```

.zshrcを読み込ませます。

```shell:ターミナル
source ~/.zshrc  
```

再度切り替えのコマンド

```shell:ターミナル
pyenv global 3.9.7  
```

確認

```shell:ターミナル
python --version    
Python 3.9.7
```

わーーい！！

##最後に
公式のドキュメントやgitを確認するのはほんと大切だなと感じました。

参考:
https://github.com/pyenv/pyenv#installation
https://qiita.com/myy/items/a526bdb43982cf82f96a
GASでスプレッドシートに初回アクセスする際の対処法

GASで何かしら処理を書きます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/143255/da016a2e-793c-5e8d-d8c2-f08d2f75072f.png" width="500">

デバッグするにはこのボタンを押します。
 <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/143255/9c394545-2d01-697e-af55-710c7fda27e4.png" width=80>

この時、処理の内容がGoogleDriveやスプレッドシートにアクセスする場合は、
初回だと下記の警告が表示されます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/143255/ebe38ae3-aff8-1edd-5518-cc2085650bc2.png" width="500">


`権限を確認`を押します。すると下記のウィンドウが表示されます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/143255/c394d9eb-9990-67a4-870e-2c87ada1ccc2.png" width="400">

対象になるアカウントを選択します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/143255/8cdaf1e9-218d-45c4-210c-c85156edbf5c.png" width="400">


左下の`詳細`を押します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/143255/83c483e0-7325-ccb4-23cc-7aebb9694c2a.png" width="400">

内容をよく読み問題なければ `xxx（安全でないページ）に移動` を押します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/143255/5e5bfc73-f156-84d1-36fb-eba5ecf45449.png" width="400">


内容をよく読み問題なければ `許可` を押します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/143255/8d65f012-8d91-3c79-4949-840936d13090.png" width="500">

これで無事実行でき、スプレッドシートの内容を読み込むことが出来ました。
PythonのImageFontで使うフォントファイルをコード内に記述する

Qiitaの初投稿記事です
調べても出てこず、結構苦戦したので記事にしてみました

### 追記
試してないですが、リソースを使えば同じようなことが簡単にできそうです - 2022/03/06

# 概要
pyinstallerというpythonをexeに変換するソフトを使用する際にフォントのパス設定で困ったので、インラインで書けないかと試行錯誤した話
# 元となるコード
font.ttfというフォントを読み込んでfont_testと書いた画像を作るプログラム

```python:image.py
from PIL import Image, ImageDraw, ImageFont
from io import BytesIO

im = Image.new('RGB', (900, 600), "#ffffff")
draw = ImageDraw.Draw(im)
font = ImageFont.truetype("./font.ttf",200)
draw.text((50,50), "font_test", fill="#000000", font=font)
im.save("./test.png")
```

# 使用するライブラリ
PillowとBytesIOを使用します
インストールされていない場合はインストールしてください

# 方針
### 準備
バイナリのフォントファイルをよみこむ
### メインのコード
読み込んだデータをPythonに記述する
BytesIOを使ってメモリ上にフォントファイルを保存する
ImageFontでメモリ上のフォント

# 完成したコード
### 準備

```python:read_font.py
from io import BytesIO

path = "./font.ttf" #　ここに読み込むフォントファイルのパス

with open(path,"rb") as f:
    s = f.read() # フォントの読み込み

with BytesIO() as bs:
    bs.write(s)
    content = bs.getvalue()

with open("./font.txt","a") as s:
    s.write(str(content)) # font.txtに出力
```

### メインのコード

```python:image.py
from PIL import Image, ImageTk, ImageOps, ImageDraw, ImageFont
from io import BytesIO

font = b'\x00\x01\x00\x00\x00\...' # ここにfont.txtの中身を貼り付け

im = Image.new('RGB', (900, 600), "#ffffff")
draw = ImageDraw.Draw(im)
font = ImageFont.truetype(BytesIO(font),200) # フォントの読み込み
draw.text((50,50), "font_test", fill="#000000", font=font) # 画像に文字を追加
im.save("./test.png") # 画像をtest.pngに出力
```

# 使い方
1. 上のコードをコピペ
2. read_font.pyの中の`path = "./font.ttf"`の部分を読み込むフォントファイルのパスに書き換える
3. read_font.pyを実行する
4. font.txtができるのでimage.pyの`font = b'\x00\x01\x00\x00\x00\...'`をfont.txtの中身に書き換える
5. image.pyを実行する

# まとめ
したかったことはできました
内容に不足や誤りがあれば補足します
[Python] 行列 ABC218C

#[ABC218C](https://atcoder.jp/contests/abc218/tasks/abc218_c)

S と T に含まれる # の個数が異なる場合、答えは明らかに No です。そうでない場合を考えます。

S に対して 90 度回転を何回行うか 4 通りを全探索します。回転操作を施したあとのものを改めて S と呼ぶと、平行移動で S と T を一致させられるかどうかを判定すればよいです。

両者が一致するためには、S の最も左上のマスと T の最も左上のマスが一致することが必要であり、そのようなマスを求めることで平行移動量は一意に決まるため、平行移動により実際に一致するか判定すれば十分です。

以上により $O(N^2)$ で求めることができました。


```python:サンプルコード
def rot(S):
	return list(zip(*S[::-1]))

def find_left_top(S):
	for i in range(N):
		for j in range(N):
			if S[i][j]=='#':
				return i,j

def is_same(S,T):
	Si,Sj = find_left_top(S)
	Ti,Tj = find_left_top(T)
	offset_i = Ti-Si
	offset_j = Tj-Sj
	for i in range(N):
		for j in range(N):
			ii = i+offset_i
			jj = j+offset_j
			if 0<=ii<N and 0<=jj<N:
				if S[i][j]!=T[ii][jj]: return False
			else:
				if S[i][j]=='#': return False
	return True

N = int(input())
S = [input() for _ in range(N)]
T = [input() for _ in range(N)]

cntS = sum(1 for i in range(N) for j in range(N) if S[i][j]=='#')
cntT = sum(1 for i in range(N) for j in range(N) if T[i][j]=='#')

if cntS != cntT:
	print("No")
	exit()

for _ in range(4):
	if is_same(S,T):
		print("Yes")
		exit()
	S = rot(S)
print("No")

```

解法は相応の時間で思い付いたのだが、実装が難しかった。
配列での行列回転処理が未熟なのが原因である。
Herokuの500エラーへの対応(Django)

Djangoで作成したアプリを2つHerokuにデプロイしたところ、
それぞれ500エラーが発生してしまったので、
その対応方法とエラーの内容について忘備録として残しておきます。

##対応方法
結論から申し上げますと次のURLの通りの対応を行い、
Heroku上でもローカルと同じ方法でエラーの内容を確認できるようにしました。

- [Django Server Error (500)攻略法【2019 アドカレ】](https://qiita.com/yuu-eguci/items/a1e4b0a2f238d5ccc985/)

- [アニメ一覧サイト「らごインフォ」作ってみた](https://qiita.com/penguinz222/items/e02f78a66cabab3a902c/)

具体的にはviews.pyとurls.pyに次の内容を加えます。

```python:views.py

from django.views.decorators.csrf import requires_csrf_token
from django.http import HttpResponseServerError

@requires_csrf_token
def my_customized_server_error(request, template_name='500.html'):
    import sys
    from django.views import debug
    error_html = debug.technical_500_response(request, *sys.exc_info()).content
    return HttpResponseServerError(error_html)
```

```python:urls.py
from [アプリ名] import views

handler500 = views.my_customized_server_error
```
このようにすると下の画像のようにエラー内容が表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/638565/58aa3723-0e82-d3ea-97c2-99a7a242ce1e.png)

##エラー内容

###1つ目のアプリ
上の画像のエラーが発生したアプリになります。
データベース関係のエラーでした。

herokuのデータベース設定を行った際に

```
heroku run python manage.py makemigrations 
heroku run python manage.py migrate
```
としていましたが、これだけではアプリ内に記述したmodels.pyの内容が何故か反映されていなかったため、

```
heroku run python manage.py makemigrations [アプリ名]
heroku run python manage.py migrate
```

としたところ、データベースの設定を無事に完了することができました。

###2つ目のアプリ
1枚目と同じくデータベース関係のエラーでした。

500エラーの中身を検証したところ、
登録フォームからデータベースへの登録を行うと、
models.pyに記述した覚えのない列についてnull制約が発生し
登録できないエラーが発生していました。

```
heroku pg:reset DATABASE_URL
```
と打ち込み、データベースの内容を全てリセットし、
再度設定したところ、無事に登録できました。
Rails + React 画像読み込み方法


## 手順

1. 画像ファイルを app/assets/images へ配置
2. config/webpacker.yml に追記
3. jsx ファイルに Component を作成


### 1. 画像ファイルを app/assets/images へ配置

適当な画像ファイルを```app/assets/images```へ配置します。


### 2. config/webpacker.yml に追記

```ruby:config/webpacker.yml
  # Additional paths webpack should lookup modules
  # ['app/assets', 'engine/foo/app/assets']

  # resolved_pathsを下記のように変更
  resolved_paths: ["app/assets/images"]
```


### 3. jsx ファイルに Component を作成


```jsx:test.jsx
import Image from 'test.png';

export default function TestComponent(props) {
    // ImageComponent 作成
    const ImageComponent = p => <img src={Image} />
    return (
        // ImageComponent 読み込み
        <ImageComponent></ImageComponent>
    );
}
```

# 参考
* Rails × React で画像を読み込む方法
    * https://forestbook-freelance.com/2021/04/12/rails-x-react-%E3%81%A7%E7%94%BB%E5%83%8F%E3%82%92%E8%AA%AD%E3%81%BF%E8%BE%BC%E3%82%80%E6%96%B9%E6%B3%95/

---
### 会社紹介

**株式会社 Mosaica**  
最先端テクノロジーで社会課題を解決し、持続可能な未来を創造する IT カンパニー。
AI ソリューション、クラウド統合、DX 推進、経営コンサルティングなど包括的なサービスでビジネス変革を支援しています。  

詳しくは [公式サイト](https://mosaica.co.jp/) までお気軽にご相談ください。
公式サイト： https://mosaica.co.jp/
Powershellでgit stash showすると「Too many revisions specified: 'stash@' 'MAA=' 'xml' 'text'」と表示される

Gitのstash内容を表示しようとすると「Too many revisions specified: 'stash@' 'MAA=' 'xml' 'text'」とエラーが表示されます。

```powershell
> git stash show stash@{0}
Too many revisions specified: 'stash@' 'MAA=' 'xml' 'text'
```

原因は`{}`が構文解析されているためです。
stash名を文字列扱いとさせれば正常に動きます。gitの問題ではなくpowershellの問題です。
解決方法は3つあります。

１．エスケープする。

```powershell
git stash show stash@`{1`}
```

２．文字列にする。

```powershell
git stash show "stash@{1}"
```

３．構文解析対象外にする。
[about_Special_Characters Stop-parsing token (--%)](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_special_characters?view=powershell-7.1#stop-parsing-token---)

```powershell
git --% stash show stash@{0}
```
エラー【Module not found: Error: Can't resolve '@popperjs/core'】が分からんかった

Rails6でwebpackerを起動したときに出たエラー

```ruby
% bin/webpack-dev-server
...
ERROR in ./node_modules/bootstrap/dist/js/bootstrap.esm.js
Module not found: Error: Can't resolve '@popperjs/core' in '/Users/username/hoge_app/node_modules/bootstrap/dist/js'
```
入れているBootstrap5とpopperjsを使っている場合、入れ方の問題のよう。
yarnでBootstrapを入れているときは確認しておきたい

`% yarn add @popperjs/core`

Bootstrap5でpopperjsを使うときは上のコマンドで入れてからwebpackerを立ち上げたら無事立ち上がった。

https://yarnpkg.com/package/@popperjs/core
サクラエディタのGrep機能を複数ワードまとめて実行できるVSBファイルつくってみた

#はじめに
大量のフォルダ・ファイルから必要なワードを検索するのに**サクラエディタのGrep機能**はとても重宝しますよね。
ただ、Grepしたい検索ワードが複数存在する場合に、１回１回手動でGrepするのは手間だなと思っていたので、複数ワードまとめてGrepできるプログラムを作成してみました。
~~正規表現で検索条件を指定すればいいのではという指摘はNGで~~

#作ったもの
* **VBScript**でサクラエディタをコマンドラインで実行させるスクリプト
* Grep検索条件リストファイルに定義した検索ワードを１行ずつ取得しGrepを実施
　例えばGrep検索条件リストファイルに以下が記載されていれば、「ワード１」、「ワード２」、「ワード３」の順で３回Grep処理を実行してくれます。
> ワード１
ワード２
ワード３

* 実行結果は指定したファイルにまとめて出力する

コマンドラインが利用できるようになるといろいろ便利ですね・・・。

#ソースコード

```vb:Grep一括実行.vbs
'*********************************************************
'[概要]
' Grep検索条件リストファイルに定義した検索ワードを１行ずつ取得しGrepを実施する
' Grep結果は指定したファイルにまとめて出力する
'*********************************************************
Option Explicit

Dim strLine
Dim WshShell: Set WshShell = Wscript.CreateObject("Wscript.Shell")
Dim objFIleSys: Set objFileSys = Wscript.CreateObject("Scripting.FileSystemObject")

Dim strReadFilePath: strReadFilePath = "C:\Users\xxxxx\Desktop\work\input.txt"'Grep検索条件リストファイル
Dim inputPath: inputPath = "C:\Users\xxxxx\Desktop\work\Grep対象フォルダ"'Grep対象フォルダ
Dim outputFilePath: outputFilePath = "C:\Users\xxxxx\Desktop\work\OutputFile.txt"'Grep結果出力先
Dim charCode: charCode ="99" '文字コードのオプション
Dim searchOption: searchOption = "SU" '検索条件のオプション

Dim objReadStream: Set objReadStream = objFileSys.OpenTextFile(strReadFilePath, 1)

WshShell.CurrentDirectory = "C:\Program Files (x86)\sakura"

Do Until objReadStream.AtEndOfStream = True
	'Grep検索条件リストの用語を1行ずつ取得し、Grepを実行
	strLine = objReadStream.ReadLine
	WshShell.Run("cmd /c sakura.exe -GREPMODE -GCODE=" & charCode & " -GKEY=" & """" & strLine & """" & " -GFOLDER=" & inputPath & " -GOPT=" & searchOption & " >>" & outputFilePath)
	WScript.sleep(1500)
LOOP

objReadStream.Close

Set objFileSys = Nothing

msgbox "end"
```

#参考サイト
https://sakura-editor.github.io/help/HLP000109.html
MAMPでtimezoneの変更

デフォルトでは日本の時間で表示されないので、日本の時間で表示する変更方法を書いてみました。

大きくわけて
1.MAMPでPHP versionを確認。
2.timezoneを書き換える。
3.MAMPを再起動してtimezoneが変更されているか確認。
すれば変更できます。


1.MAMPでPHP versionを確認。
MAMPを起動する（stratを押す)。
WebStartをおして、phpinfoをクリック。
![SuperScreenshot 2021-9-12 16-2-48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1720571/be073581-ef73-f4d6-c880-820ec82613ae.png)

PHP versionが書いてるので確認する。
![SuperScreenshot 2021-9-12 17-38-55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1720571/833deb1e-9ede-f021-acfd-5055218e36b7.png)


2.timezoneを書き換える。
Applications>MAMP>bin>php>php7.4.16>conf>php.ini
php.iniのtimezoneを変更する。(php7.4.16は先ほど確認したversionのものを選択する)
デフォルトは"Europe/Berlin"になっている。

![SuperScreenshot 2021-9-12 16-9-43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1720571/6a5674c2-0d61-e245-5792-853accec7e31.png)

今回は日本にしたいので"Asia/Tokyo"と書き換え保存する。
(date.timezoneの前についている[；]を削除する。削除しないと変更されない。)
![SuperScreenshot 2021-9-12 17-29-34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1720571/ba0fc185-1d27-9999-1bc2-99b064a573e8.png)


3.MAMPを再起動してtimezoneが変更されているか確認。
MAMPを一度Stopして、またStratする。Webstratをおしてphpinfoをみる。timezoneがAsia/TokyoになっていたらOK。
![SuperScreenshot 2021-9-12 17-59-44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1720571/995fb32e-31fa-2a0f-2223-e2e31e46e10c.png)

これで日本の時間に変更されると思います。
土地利用・土地被覆データを地形図とともに三次元表示

JAXA 高解像度土地利用土地被覆データ(HRLULC)をベクトルタイルに変換するという特殊な作業を先日していましたが、これに標高タイルを組み合わせて三次元表示したら面白いだろうと思って開発していました。

# 三次元表示
https://github.com/optgeo/hrlulc3d

# 地理院標高タイルを WEBP に
上記の hrlulc3d は Mapbox から供給されている標高タイルを使っています。この標高タイルはグローバルカバレッジがあるのが素晴らしいですが、日本領域については少しもの足りません。

以前、地理院PNG標高タイルをMapbox式WEBP標高タイルに変換する試行をしていました。今、私は Raspberry Pi を使って 1GB 越えのコンテンツをインターネットに出すことができます。

そこで、改めて、地理院PNG標高タイル（DEM10B）をMapbox式WEBP標高タイルに変換するコードを書いてみました。今度はすべて Ruby で書いて、また GNU Parallel を活用して平行処理するように組んでいます。

https://github.com/optgeo/et10b

このエントリの執筆時点で、256x256 WEBP タイルを z=13 で生産中です。この後、z=14 まで生産し終わったら、256x256 タイルを4枚つなぎ合わせて 512x512 WEBP　タイルにしていきます。

# 三次元表示の標高タイルを地理院標高タイルに換装
hrlulc3d　の標高タイルを生産中の地理院WEBP標高タイルに換装したものを次の場所に置いています。

https://github.com/optgeo/hrlulc3d256
ABC217D-Cutting Woods 解説

# 問題
[https://atcoder.jp/contests/abc217/tasks/abc217_d](https://atcoder.jp/contests/abc217/tasks/abc217_d)

# 考えたこと
- クエリ$c_i$=2のとき，線$x_i$の左右それぞれについて一番近い切り目がわかれば良い
- 切り目をsetで持てば，upper_bound(lower_boundでも可)で$x_i$の右にある一番近い切り目がわかる

# コード(テンプレートは省略)
```cpp
int main()
{
    //cout << fixed << setprecision(10)
    cin.tie(0);
    ios::sync_with_stdio(false);
 
    ll L, Q;
    cin >> L >> Q;
 
    set<ll> st;
    st.insert(0);
    st.insert(L);
 
    rep(_, Q)
    {
        ll c, x;
        cin >> c >> x;
 
        if (c == 1) {
            st.insert(x);
        } else {
            auto itr = st.upper_bound(x);
            ll M = *itr;
            ll m = *(--itr);
 
            cout << M - m << endl;
        }
    }
}
```
Chrome Extensionでオブジェクトの配列をCSVとして保存する方法

```typescript:background.ts
// オブジェクトの配列(例)
const data = [
  { title: 'aaa', published_at: '2021-09-12T06:24:12.175882' },
  { title: 'bbb', published_at: '2021-09-11T07:12:14.174731' },
];

const convertJsonToCsv = <T>(json: T[]): string => {
  const header = `${Object.keys(json[0]).join(',')}\n`;
  const body = json.map((d) => Object.values(d).join(',')).join('\n');
  return header + body;
};

// ダウンロードを実行
const downloadCsv = () => {
  const csv = convertJsonToCsv(data);
  const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
  const url = URL.createObjectURL(blob);
  chrome.downloads.download({
    url,
    filename: 'filename.csv',
  });
};
```

manifest.jsonのpermissionに `'downloads'` を追加するのをお忘れなく！
一発で、現在のrepoのremote urlとpathをブラウザで開く方法



## TL;DR

```
% [sudo] gem install git-browse-remote 
% git browse-remote .
```

https://github.com/motemen/git-browse-remote

## その他の方法

### 1. 自作

```

% sudo cat >> /usr/local/bin/gitremote << 'END'
git remote -v | awk -v P="$(git rev-parse --show-prefix | sed 's/\/$//g' | nkf -WwMQ | sed 's/=$//g' | tr = % | tr -d '\n')" '/origin.*push/ { sub(/\.git$/, "", $2); newvar=$2"/tree/master/"P; print newvar}' | xargs open
END

% sudo chmod +x /usr/local/bin/gitremote

% gitremote
```

https://gist.github.com/thunderz99/3621ba78b2e734c15d1261f500ce03a7

### 2. git-open

```
% git open
# 残念なことに、現在のpathはサポートされていない
```

https://github.com/paulirish/git-open


### 3.  git-browse-remote （おすすめ）

```
% git br
% vi ~/.gitconfig

# This is Git's per-user configuration file.
[pull]
        ff = only
[init]
        defaultBranch = master
[web]
        browser = open
[alias]
        br = browse-remote .
        pr = browse-remote --pr

```

https://github.com/motemen/git-browse-remote


### 4. hub

多機能で、開くだけなら git-browse-remote

https://hub.github.com/#developer
Homebrewをuninstallして詰みかけた話

## 発端
普段自分はGoのコードばかり書いていて、インフラっぽいことはなんとなくで迂回してきた。

プライベート学習をしようと古いMacを引っ張り出してきて、開発環境を諸々Upgradeしていた。
その最中に、使わない言語のFormuraが多そうなことに気づき、軽い気持ちで一度全部消して再インストールを試みた。

というわけで
https://t-cr.jp/memo/1e317a89fa9f18c3
こちらの通りに実行。

## 詰んだ状態
消した後のターミナルの挙動が何かおかしい。
再起動してみよう！(アホ)
まだ何も打ち込んでいないのにプロセスが完了してしまう。何もできない。
よく見てみると`/usr/local/bin/zsh`が無いと怒られている。

そこで私は全てを悟った。
**Homebrew...**

相変わらず理解が浅い自分だが、`/usr/local/bin`下には確かにzshは無かった。
ターミナルが起動しないので`chsh`コマンドも使えず、どうしようも無かった。

青ざめながらネットを彷徨って、なんとか
https://blog.officekoma.co.jp/2020/05/macos-catalinabash.html
こちらにたどり着き、
ターミナルのログインシェルをGUI上から切り替える方法を発見。

ディレクトリをターミナルから見ることもできないのでchromeでディレクトリを見つつ、どこにbashがあるのかを探した。

普通に`/bin/bash`にあった。いつもdockerで`exec`コマンドを使うときにお尻につけていたアレだ。そりゃそうだよな。。。と。

何はともあれGUIでログインシェルを`bin/bash`に切り替えてHomebrewをインストールし直すことができた。

なお自分は普段ターミナルではなくiTermを使っているので、そちらのログインシェルを変更する方法を探していたら、同志がおられた。
https://qiita.com/weakboson/items/399882f8422c9afb5f9d

実際にはiTermの方はGUIから変更せず、ターミナルの方で
`chsh -s /bin/zsh`で設定したらiTermも起動できるようになった。
参考: https://rcmdnk.com/blog/2015/05/25/computer-mac-bash-zsh/
RaspberryPiのVNCのパスワードを忘れたとき...

我が家では、ラズパイを無線LANにつなげて
メインPCからVNCで接続して運用していました。
長らくアクセスしない間に、VNCのパスワードを忘れていしました...

# パスワードの保存場所
設定ファイルは以下の階層に入っているようです。

```
~/.vnc
```
隠しフォルダーになっているので通常は見れません。
暗号化されていて、ファイルを開いてもパスワードはわかりません。

# パスワードの再設定方法
.vncフォルダを消してしまう。
"端末"で以下のコマンドを打つ。

```
$ rm -r ~/.vnc
```

再起動すると
古いパスワードを聞かれること無く、新しいパスワードに変更できました。



# パスワードを忘れないために
ハードウェアにマジックで書いておくのもいいかも。
（我が家には漏れて困ることもないので）