OmniAICreator/Qiita-1.07M huggingface dataset:
Pythonのスクリプトで見開きのPDFを半分に切る

# 背景
最近知ったのですが，中学受験にはA3対応のプリンタ/スキャナは必須だと言われているらしいです．確かにプリンタ，スキャナの使用頻度は高く，特にスキャンは面倒なのでA3/B4でできるといいなと思い，Amazonで人気のBrother MFC-6583CDWを購入しました．（品薄で，ポチってから届くまで約一ヶ月かかりました．）

今までA4とかB5の単位でスキャンしていたのが，A3とかB4の見開きでスキャンできて一見楽になったように思えましたが，印刷などを考えると見開きで1ページなのはあまり嬉しくないのでできれば見開きのページを半分に切って保存したいと思いました．

そこで，やりかたをいろいろ調べてみたのですが，意外と面倒くさそうということが分かりました．普段使っているMacだけでなくWindowsも含めてやり方のバリエーションとして調べてみたところ以下の通りいくつか見つかりましたが決め手に欠く状況でした．
- Adobe Acrobat DCを使う(mac,win) →有料
- Adobe Acrobat Reader DC ＋ VipRiser(mac) →ファイルサイズが大きくなるらしい
- Adobe Acrobat Reader DC(win) →Adobe PDFとポスター印刷で可能だが，順番が期待通りにならないのと回転して保存ができない?

もう少し調べると，[Pythonのライブラリである"PyPDF2"を使うとPDFファイルの操作ができそう](https://gammasoft.jp/blog/pdf-divide-by-python/)ということなので，ちょっと作ってみることにしました．

# やりたいこと
- 普通にスキャンすると左のようになるのを，右のようにしたい
    - 国語のように縦書きのものも，オプションできちんとした順番になるようにしたい
 
![tobe.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/681278/6d335096-c9a9-91a9-0bff-f534c9103ccd.png)

# 環境
- macOS: 12.4
- python: 3.9.9
- PyPDF2: 2.3.1


# 実装と使い方
まず，PDFを半分に切ったりするには座標系の知識が必要かと思い少し調べたところ，PDFでは左上ではなく左下が(0,0)らしいということがわかりました．図の中のx0とかy1とかはスクリプトの中に出てくる変数です．
![coordinate.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/681278/c974d536-7ec1-879a-18d0-bd958a70955b.png)

以下のスクリプトを適当な名前(facing_page_cutter.pyなど)をつけて保存して，
- `python3 facing_page_cutter.py <filename>.pdf`
もしくは実行権限(chmod u+x facing_page_cutter.py)をつけて
- `/path/to/facing_page_cutter.py <filename>.pdf`
とすると，実行したディレクトリに`<filename>_cut.pdf`というファイルが作成されます．
縦書きの時には`-v`をオプションとしてファイル名の前につけてください．

スクリプトの内容については見ていただければわかるかと思います．

```python:facing_page_cutter.py
#!/usr/bin/env python3
# Copyright (c) 2022, Kazuhiro FUJIHARA

import PyPDF2
from optparse import OptionParser
import sys
import re
import copy

ROTATE_ANGLE = 90

# オプションや引数の処理
usage = "usage: /path/to/%prog [options] <pdf filename w/ .pdf>"
parser = OptionParser(usage = usage)
parser.add_option("-v", "--vertical", action="store_true", dest="vertical", help="縦書き")

(options, args) = parser.parse_args()

if len(args) != 1:
    parser.print_help()
    sys.exit()

output_filename = re.match(r'(.*)\.pdf', args[0]).groups()[0] + '_cut.pdf'

# ファイルを開く
pdf_reader = PyPDF2.PdfFileReader(args[0])
pdf_writer = PyPDF2.PdfFileWriter()

# ページの大きさを取得する
page = pdf_reader.getPage(0)
(x0, y0) = page.mediaBox.getLowerLeft()
(x1, y1) = page.mediaBox.getUpperRight()

# 見開き1ページずつ処理をしていく
for i in range(pdf_reader.getNumPages()):
    # 半分のサイズを抽出する(p1が左，p2が右のページ)
    p1 = pdf_reader.getPage(i)
    p2 = copy.copy(p1)
    p1.cropBox.lowerLeft = (x0, y0)
    p1.cropBox.upperRight = (x1, (y0 + y1) / 2)
    p2.cropBox.lowerLeft = (x0, (y0 + y1) / 2)
    p2.cropBox.upperRight = (x1, y1)
    
    # 縦書きの時は右のページが先に来るようにする
    if options.vertical is True:
        p1, p2 = p2, p1
    
    # 時計回りに90度回転させる
    p1.rotateClockwise(ROTATE_ANGLE)
    p2.rotateClockwise(ROTATE_ANGLE)

    # PDFの再構成
    pdf_writer.addPage(p1)
    pdf_writer.addPage(p2)

# ファイルへの書き出し
with open(output_filename, mode='wb') as f:
    pdf_writer.write(f)
```


# 最後に
色々試行錯誤しているときには
- macで回転
- winで分割
- macで並べ替え

とやったりしてたのですが，とりあえずこのscriptで今のところ随分楽になりました．
やっぱり楽をするための努力は惜しまないように，と思った次第です．．．
cscの作法 その220

# 概要
cscの作法、調べてみた。
sslstreamと、キーストアを使って、serverとclientで、ssl通信してみた。


# 参考にしたページ

https://github.com/ohisama/Simple-TCP-Communication-SSLStream

# 実行結果

```

ending encrypted message
S
ending encrypted message
S
ending encrypted message
S
ending encrypted message
S
ending encrypted message
S
ending encrypted message
S
ending encrypted message
S
ending encrypted message
S
ending encrypted message
S
```


以上。
[JetpackCompose] ボタンの二度押し対策Composableなボタン

# はじめに

composeableでボタンを連続押しして、たとえば画面が二つ立ち上がるや、サーバにアクセスを2回行うなど場合によりありえます。それを防ぐために一度タップして数秒間ボタンを押せないようにするtipsのメモ

```
import android.os.SystemClock
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.RowScope
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Shape

@Composable
fun SingleButton(
    modifier: Modifier = Modifier,
    onClick: () -> Unit,
    clickDisablePeriod: Long = 2000L,
    enabled: Boolean = true,
    interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
    elevation: ButtonElevation? = ButtonDefaults.elevation(),
    shape: Shape = MaterialTheme.shapes.small,
    border: BorderStroke? = null,
    colors: ButtonColors = ButtonDefaults.buttonColors(),
    contentPadding: PaddingValues = ButtonDefaults.ContentPadding,
    content: @Composable RowScope.() -> Unit
) {
    var lastClickTime by remember { mutableStateOf(0L) }
    Button(
        onClick = {
            if (SystemClock.elapsedRealtime() - lastClickTime >= clickDisablePeriod) {
                lastClickTime = SystemClock.elapsedRealtime()
                onClick()
            }
        },
        modifier = modifier,
        enabled = enabled,
        interactionSource = interactionSource,
        elevation = elevation,
        shape = shape,
        border = border,
        colors = colors,
        contentPadding = contentPadding,
        content = content
    )
}
```

SingleButtonは通常のButtonをラップしているのであとは通常のButtonのように呼べばOK.
デフォルトのボタン待ちはclickDisablePeriodで2秒で設定。変更する場合はここにmillisecond指定すればOK
あとは良きに使ってください
cscの作法 その219

# 概要
cscの作法、調べてみた。
BouncyCastle.dll使ってみた。
キーストア(p12)を叩いてみた。

# サンプルコード

```

using System;
using System.Collections;
using System.Net;
using System.Net.Sockets;
using System.Net.Security;
using System.Security.Authentication;
using System.Text;
using System.Security.Cryptography.X509Certificates;
using System.IO;
using Org.BouncyCastle.X509;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.Asn1.X509;
using Org.BouncyCastle.Asn1.Pkcs;
using Org.BouncyCastle.Crypto.Operators;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Prng;
using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Pkcs;

namespace app
{
	public class test0 {
		public static int Main(string[] args) {
			string pfxPath = "test5.p12";
			if (args == null ||args.Length < 1)
			{
				Console.WriteLine("p2 .p12");
			}
			pfxPath = args[0];
			FileStream fs = File.OpenRead(pfxPath);
			char[] passwd = "password".ToCharArray();
			Pkcs12Store store = new Pkcs12StoreBuilder().Build();
			store.Load(fs, passwd);
			string alias = null;
			foreach (string str in store.Aliases)
			{
				if (store.IsKeyEntry(str))
					alias = str;
			}
			if (alias == null)
			{
				Console.WriteLine("alias is empty");
			}
			else
				Console.WriteLine(alias);
			AsymmetricKeyEntry keyEntry = store.GetKey(alias);
			RsaKeyParameters priKey = (RsaKeyParameters) keyEntry.Key;
			X509CertificateEntry certEntry = store.GetCertificate(alias);
			Org.BouncyCastle.X509.X509Certificate x509cert = certEntry.Certificate;
			RsaKeyParameters pubKey = (RsaKeyParameters) x509cert.GetPublicKey();
			x509cert.Verify(pubKey);
			byte[] certByte = x509cert.GetEncoded();
			X509Certificate2 cert2 = new X509Certificate2(certByte);
			Console.WriteLine(cert2.ToString());
			return 0;
		}
	}
}


```

# 実行結果

```
c>p2 pkcs12.p12
localhost
[Subject]
  CN=localhost

[Issuer]
  CN=localhost

[Serial Number]
  562BE42564875E964A04E8468651092B631782B82B7EF0E5D14249E7B28D1D01

[Not Before]
  2022/06/24 9:00:00

[Not After]
  2023/06/24 9:00:00

[Thumbprint]
  6A9E328D46074BBCBCE93EE72576D7434161D242

```

以上。
cscの作法 その218

# 概要
cscの作法、調べてみた。
BouncyCastle.dll使ってみた。
秘密鍵と証明書から、キーストア(p12)を作ってみた。

# サンプルコード

```
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.X509;
using Org.BouncyCastle.Asn1.Pkcs;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Operators;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Crypto.Prng;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Pkcs;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.X509;

namespace ConsoleExample
{
	class Program {
		static void Main(string[] args) {
			AsymmetricCipherKeyPair privateKey;
			Org.BouncyCastle.X509.X509Certificate readedCert;
			using (var reader = new StreamReader(@"privatekey.pem", Encoding.ASCII))
			{
				var pemReader = new PemReader(reader);
				privateKey = (AsymmetricCipherKeyPair) pemReader.ReadObject();
			}
			using (var reader = new StreamReader(@"certificate.crt", Encoding.ASCII))
			{
				var pemReader = new PemReader(reader);
				readedCert = (Org.BouncyCastle.X509.X509Certificate) pemReader.ReadObject();
			}
			var randGen = new CryptoApiRandomGenerator();
			var rand = new SecureRandom(randGen);
			var certEntry = new X509CertificateEntry(readedCert);
			var keyEntry = new AsymmetricKeyEntry(privateKey.Private);
			var p12 = new Pkcs12Store();
			p12.SetCertificateEntry("test16", certEntry);
			p12.SetKeyEntry("key", keyEntry, new X509CertificateEntry[] {
				certEntry
			});
			using (var stream = new FileStream(@"test16.p12", FileMode.Create))
			{
				p12.Save(stream, "password".ToCharArray(), rand);
				stream.Flush();
			}
			Console.WriteLine("OK");
		}
	}
}



```


以上。
【Swift】オープンデータのCSVファイルをURLから読み込む

# 開発環境
Xcode 13.4
iOS 15.5
Swift 5.0

# オープンデータ上のCSVファイルを読み込む
```swift:ViewController.swift
// 最終的にデータを格納する配列
var fileData:[[String]] = []

// ダウンロードしたCSVファイルを保存する変数
var csvString = ""

let pathURL = NSURL(string: "（保存したいCSVファイルのリンク）")

var lineIndex = 1

do {
   // ここでは文字コードをUTF8で指定
   csvString = try NSString(contentsOf: pathURL! as URL, encoding: String.Encoding.utf8.rawValue) as String
} catch let error as NSError {
   print(error.localizedDescription)
}

// ","区切りで配列に追加
csvString.enumerateLines { (line, stop) -> () in
   self.fileData.append(line.components(separatedBy: ","))
   self.lineIndex += 1
   if self.lineIndex == self.fileData.count {
       stop = true
   }
}

```
# encodingエラーが出る場合
読み込むCSVファイルのエンコードが異なる場合エラーが出ます。
その際はencoding: String.Encoding.utf8.rawValueの箇所を任意のエンコードに変更します。

（例）　エンコードをshiftJISに変更
encoding: String.Encoding.shiftJIS.rawValue
if user input number (bash)

~~~if_input_number.sh
    read -n 1 -p "Would you like to install 
                1. AAAA
                2. BBBB
                3. CCCC
                4. DDDD 
                
                Please select (1/2/3/4) " ans;

    echo " "
    case $ans in
        1)
            echo "install AAAA";;
        2)
            echo "install BBBB";;
        3)
            echo "install CCCC";;
        4)
            echo "install DDDD";;
        *)
            echo "Unknown"
            exit;;
    esac
~~~

result

~~~
hoshina@hoshina-ThinkPad-X1-Carbon-7th:~$ bash if_input_number.sh 
Would you like to install 
                1. AAAA
                2. BBBB
                3. CCCC
                4. DDDD 
                
                Please select (1/2/3/4) 2 
install BBBB
~~~

![Screenshot from 2022-06-28 10-53-07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/589906/0827a469-5ef2-4e0b-16ce-071ccfc0a34c.png)
Check Ubuntu Version (bash)


~~~check_lsb.sh
check_lsb() {

    echo "Checking your current ubuntu version..."
    VERSION=$(lsb_release  -rs)

    if [[ $VERSION == "18.04" ]]
    then
        echo "->Ubuntu Version $VERSION"
    elif [[ $VERSION == "20.04" ]]
    then
        echo "-> Ubuntu Version $VERSION"
    else

        echo "-> "
    fi
}
~~~
Googleの各サービスにさっさとたどり着く方法

## 思うのですよ
例えば、Gmailを使いたち時、どんな手順を踏むだろうか。

* ブラウザを起動する
* アドレスバーに "google"とか入力する
* それでGoogleのページが表示されればよいが、そうでなければ表示されたページでGoogleのページをクリックする
* 出てきたGoogleのトップページにある"Gmail"をクリックする

となる。長い！これを、

* ブラウザを起動する
* アドレスバーに"mail.google.com"と入力してエンターキーを押す

と短縮できる。こういう話を一覧にしてみよう。

## 原則

原則的には[サービス名].google.comにアクセスすると、それぞれのサービスに直接接続できる。

## 対応していると思われるサービス

* Gmail: [mail.google.com](https://mail.google.com)
* カレンダー: [calendar.google.com](https://calendar.google.com)
* 連絡先: [contacts.google.com](https://contacts.google.com)
* チャット: [chat.google.com](https://chat.google.com)
* 翻訳: [translate.google.com](https://translate.google.com)
* ドキュメント: [docs.google.com](https://docs.google.com)
* スプレッドシート: [sheets.google.com](https://sheets.google.com)
* スライド: [slides.google.com](https://slides.google.com)
* ドライブ: [drive.google.com](https://drive.google.com)

などなど。

## おまけ

Googleは、.newというトップレベルドメインの一部を所有している。これを利用して、"docs.new"とアドレスバーに入力すると、新規のドキュメントを素早く作成できる。対応していそうなのは以下。

* ドキュメント: [docs.new](https://docs.new)
* スプレッドシート: [sheets.new](https://sheets.new)
* スライド: [slides.new](https://slides.new)
* カレンダーの予定: [cal.new](https://cal.new)
* 新規メモ: [keep.new](https://keep.new)
* フォーム: [form.new](https://form.new)

いかがだろうか？
React: State の使い方

こちらを参考にしました。

[React State](https://www.w3schools.com/react/react_state.asp)

プロジェクトの作成

```bash
create-react-app re02
cd re02
yarn start
```

src/App.js を次で置き換えます。

```js:src/App.js
import './App.css';
import React from 'react';

class Car extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      brand: "Ford",
      model: "Mustang",
      color: "red",
      year: 1964
    };
  }

  changeColor = () => { this.setState({color: "blue"}); }
  changeGreen = () => { this.setState({color: "green"}); }
  changeRed = () => { this.setState({color: "red"}); }

  render() {
    return (
      <div>
        <h1>My {this.state.brand}</h1>
        <p>
          It is a {this.state.color}
          {this.state.model}
          from {this.state.year}.
        </p>
        <button type="button" onClick={this.changeColor} >Change color</button>
	&nbsp;
        <button type="button" onClick={this.changeGreen} >Change Green</button>
	&nbsp;
        <button type="button" onClick={this.changeRed} >Change Red</button>
      </div>
    );
  }
}

function App() {
  return (
    <div className="App">
      <header className="App-header">
	<p>Hello World!</p>
	<Car />
	<blockquote>
	<p>Jun/28/2022</p>
	</blockquote>
      </header>
    </div>
  );
}

export default App;
```

ブラウザーで、　http://localhost:3000/　にアクセス
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/0d4a5925-3ae2-2d53-8740-2677c9ce2952.png)
個人開発で変数名に日本語を使ったら快適だった話

## 変数名に日本語を使おうと思った経緯
こんにちは。秋になると柿を200個食べるWebエンジニア、すずきゆーだい([@szkyudi](https://twitter.com/szkyudi))です。

最近、個人開発としてリアルタイムで変更を確認できる多機能な割り勘電卓「ばりわるくん」を作りました。
このアプリケーションでは、似たような性質の変数が多く存在するため、英語でどのような区別をつけていけばよいかわからなくなりました。

そこで、いっそのこと変数名を日本語にしてしまった方が楽になるのではないかと考え、導入に至りました。

https://warikan-dentaku.vercel.app

## 必要な変数と使った変数名たち
まずは、このアプリケーションでどのような変数が必要になったかを紹介して、実際の変数名を見ていだければと思います。
実際にスマートフォンなどでアプリケーションを触っていただきながら見ていただくと、より理解していただけると思います。

### 必要になった変数たち
- お会計の金額
- 支払人数の合計
- 普通に払う人（自動で計算される）
    - 支払金額
    - 支払人数
    - 支払金額の合計
- 固定の金額で払う人（任意で追加できる）
    - 支払金額
    - 支払人数
    - 支払金額の合計
- 普通に払う人に対する比率で払う人（任意で追加できる）
    - 比率
    - 支払金額
    - 支払人数
    - 支払金額の合計
- 切り上げ単位
- 支払金額の合計
- お釣り

日本語を見ただけでも「支払」や「金額」、「人数」がゲシュタルト崩壊しそうです。
最初はこれらを `bill` や `payment` 、 `payerNum` などを使って表現しようと思ったのですが、英語力が底を突きました。

### 日本語で定義した変数名
※実際には Recoil の `atom()` や `selector()` で定義しています。
```ts
const お会計 = 30000
const 支払人数 = 8
const 一般請求額 = 3200
const 一般支払人数 = 3
const 一般請求総額 = 9600
const 固定支払金額 = 3000
const 固定支払人数 = 2
const 固定支払総額 = 6000
const 割合支払人数 = 3
const 割合支払比率 = 1.5
const 割合支払金額 = 4800
const 切上単位 = 100
const 支払総額 = 30000
const お釣り = 0
```
こんな感じで日本語で定義しました。
また、一般支払金額を自動計算させるためには、お会計と固定支払総額の差額が必要だったりもしたので、こんな変数も作りました。
```ts
const お会計と固定支払総額の差額 = お会計 - 固定支払総額
```
日本語をそのまんま変数にすることで快適になりました。

## 変数名に日本語を使った感想
最初、英語で実装していたときは、コードを見返したときに「この変数ってどんな変数だっけ？」とコードを読み返す必要があり不便だったのですが、日本語変数に切り替えると、変数名から直感的に中身がわかるので、快適にコーディングすることができました。

『これぞリーダブルコードでは？』と思ったりもしました。

ひとつだけ微妙な点を挙げるとすると、1文字目を入力しないとエディタの補完が効かないので若干不便でした。変数名のプレフィックスとして `jp` などをつけてもいいのかなと思ったりしました。

## どういった場面で変数名に日本語を使うか
チーム開発の現場やグローバルな現場であれば、英語の変数名を使いつつ変数の上にコメントを記述して説明するのがセオリーのような気もします。
また、変数名に日本語を使って発生したトラブルを解決する情報というのはインターネット上に少ないので、未知のバグが発生したときに困ります。

そのため、日本語変数は個人開発にとどめて使うのが無難かと思います。

## まとめ
ぜひ「ばりわるくん」を使ってみてください！

https://warikan-dentaku.vercel.app
【受験記録】AWS Certified Advanced Networking – Specialty(ANS-C00)

## 注意
- 受験した現バージョン(ANS-C00)は2022/7/11で受験不可になりますので、ご了承ください。

## 前提
- 6年目エンジニア
- アプリケーション開発メイン
- インフラは少しだけ
- AWS　CLF,　Associate3つ, AWS SAP, DASは保持
- 受験日 2022/6/25

##試験結果
点数:807点/750点/1000点(取得スコア/合格ボーダー/満点スコア)
スコアパフォーマンス: 分野1, 6を除くセクションは"コンピテンシーを満たしている"

## 試験感想
- DAS受験後、次に受ける試験を選んでいたら、ANS試験のバージョンが7月で切り替わり、内容が大きく変わりそうだったので、駆け込み受験をしようとANSに決めました。
- 対象サービスが比較的絞られていたことと対策本が出ていることもあって、前回のDASほどの勉強のしにくさはなかったです。
- 実際に試験を受けてもDirectConnect, AWS VPN, Route53についての問題が多かったように感じます。

## 勉強方法
1. [AWS公式](https://aws.amazon.com/jp/certification/certified-advanced-networking-specialty/?ch=sec&sec=rmg&d=1)の試験ガイド、サンプル問題で試験範囲、問題の雰囲気を確認する。
1. [書籍](amazon.co.jp/dp/B09T2B93NY/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1)を一通り読んで、対象サービスや出てくる単語について把握する。
1. [AWS BlackBelt](https://www.youtube.com/watch?v=mEtluVrgXlk&list=PLzWGOASvSx6FIwIC2X1nObr1KcMCBBlqY&index=68)で理解できなかったサービスについて理解する。
1. Udemy, Whizlabs, koiwaclub, 書籍の模擬問題を使ってひたすら問題演習を行う。
CSVを読み込もう

CSVファイルを読み込んでデータ化してほしいんだよね。

前回、前々回とCSVファイルを読み解いた私には何も怖いものはない！
[CSVを読み込もう](https://qiita.com/chobirinu/items/a6fe3d2f6821b1aa5b06)
[[続] CSVを読み込もう](https://qiita.com/chobirinu/items/cfe47ab20323990a7f92)
かかってこいやー！！

と意気込んで、もらったCSVをエディタで開いてみると
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1909386/28af338b-3eeb-684c-487d-4e21cf6f0c85.png)

な・ん・で・す・か？こ・れ？

先頭行に無数のNULL文字が付与されているのね。
なのでこんな感じで実装しました。

```C#
public DataTable ToDataTable()
{
    try
    {
        var dataTable = new DataTable();

        // なんか知らんけどもNULLが含まれているのでそれを良しなにする
        var fileContents = new System.IO.StreamReader(TargetPath, encoding).ReadToEnd().Replace("\0", "");

        using (var stream = new System.IO.MemoryStream(encoding.GetBytes(fileContents)))
        using (var reader = new System.IO.StreamReader(stream, encoding))
        using (var csv = new CsvHelper.CsvReader(reader, System.Globalization.CultureInfo.InvariantCulture))
        using (var dr = new CsvHelper.CsvDataReader(csv))
            dataTable.Load(dr);
        return dataTable;
    }
    catch
    {
        return null;
    }
}
```


CSVファイルってこんなに処理するのって難しかったっけ・・・・？
【切替器なし】windowsとmacで同じサブディスプレイを使う【入力切替】

# １．はじめに
（要点だけ知りたい方は2から読んでください）  
  
 こんにちは、ijykです。  ドケチです。
普段はリモートワークをしながら仕事用でwindows、私用でmacと2台のノードPCを使っています。  
最近、モニターを増設したくなり、duetやwindowsのリモート接続などを使ってノートPC間でのサブディスプレイ化を試してみました...が、小さなストレスが多く、諦めて有線接続するタイプのサブディスプレイを買ってしまいました（ネットワーク環境が貧弱...）。  
2台のノートPCで共通のサブディスプレイを使う方法って以下2つくらいしか調べても出てこず、ハード的にボタンポチポチしか無いし、配線増えるなあ、これ以上お金使いたくないなあ...とかで悩んだ末にたどり着いた方法をつらつらと書きました。  
ただ、スマートではないので有識者の方ご意見ください！！  
  
【サブディスプレイの入力切替の方法】  
* 切替器にそれぞれのPCのHDMIを接続して、ボタンやスイッチで切り替える
* サブディスプレイのボタンを押して切り替える
+ __ショートカットキーなどを駆使してキーボードやカーソル操作だけで切り替える__　← New

# ２．この記事の目的と対象者
## ２−１．目的
2台のノートPCで共有しているサブディスプレイを、キーボードやカーソル操作だけで切り替える
## ２−２．対象者
+ 切替器なしでサブディスプレイの画面を切り替えたい方  
特に __切替器買って配線増えるのやだな__ 、とか __ボタンいちいち押すために手をのばすの面倒だな__ とか思っているそこのアナタ！

# ３．内容
## ３−１．配線
windowsとmacをそれぞれサブディスプレイに接続します。  
図はHDMIでつないでいますが、bluetooth接続も同じだと思います（違ってたらすみません）。

![スライド2.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/350979/c37c8647-8d4e-ce17-c064-00de3f2a22bb.jpeg)


## ３−２．ショートカットキー設定
### windows側
特に無いです
### mac側

1. 左上のAppleロゴ　⇨「システム環境設定」⇨「キーボード」  
2. 「ショートカット」⇨「アプリケーション」⇨「+」  
3. 「メニュータイトル」に __スリープ__ を入力  ⇨「キーボードショートカット」に任意のショートカットキーを入力  ⇨追加
　　※今回は「shift」+「control」+「Q」としています  

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/350979/17f1af8a-1e2c-0306-bab9-c022cdbcee62.jpeg" width = 500>



## ３−３．テスト
### windowsを2画面にする
1. windows側：「windowsキー」+「p」 を押す
2. windows側：「拡張」を選択
3. mac側：ショートカットキーを押してスリープ

![スライド3.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/350979/9e378cd8-827f-d468-9757-66612d7b5a71.jpeg)



### macを2画面にする
1. mac：スリープを解除
2. windows：「windowsキー」+「p」 を押す
3. windows：「PC画面のみ」を選択

![スライド4.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/350979/7544ffb0-eca5-afeb-cb50-242c6bb38b49.jpeg)


# ４．最後に
キーボードとカーソル操作だけでサブディスプレイの入力を切り替える方法をご紹介しました！  
コードの抜き差しやボタンを駆使する必要がなくなったので楽にはなりましたが、もっとスマートな方法があるはず...というところで妥協していしまいました。  
有識者の方、もっとスマートな方法があればご教授ください！
（できればお金のかからない方法で・・・）
ハードリンクとシンボリックリンク

# iノード
主にUNIX系で使われる***ファイル（やディレクトリ）の属性情報がまとめられたデータ***のことです。
***ファイルがどこに書かれているかが記録***されています。

そしてファイルにはそれぞれ```iノード番号```というファイルなどを判別するための番号が割り振られています。

# iノード番号を確認する
iノード番号の確認方法です。
```
% ls -li
total 8
35405271 drwxr-xr-x  2 taro  staff   64  6 27 17:47 cat
35405268 drwxr-xr-x  2 taro staff    64  6 27 17:47 dog
```
35405271がcatディレクトリのiノード番号で、35405268がdogディレクトリのiノード番号です。


# シンボリックリンクとハードリンク
```ハードリンク```は***見た目は違うファイルでもiノードが共通している***ものです。
同じファイルの実体につながっています。

```シンボリックリンク```はiノードを持つリンク元のファイルにつながり、ファイルの実体とはつながりを持ちません。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1748789/70471bd5-b63d-c63b-d894-30583864b662.png)

>引用　　　https://www.infraeye.com/study/linuxz28.html


# リンク作成方法
```lnコマンド```でリンクが作成できます。```-s```をつけるとシンボリックリンクが作成できます。
引数は　```リンク元ファイル　　　リンクファイル名```の順です。

```
$ ln リンク元ファイル　　　リンクファイル名
```

実際にハードリンクを作成していきます。
```
Animal % ln dog dog_hardlink
Animal % ls
dog		dog_hardlink
```

次にシンボリックリンクを作成します。
```
Animal % ln -s dog dog_symlink
Animal % ls
dog		dog_hardlink	dog_symlink
```

# ハードリンクとシンボリックリンクの確認

次にiノード番号を確認します。
```
Animal % ls -i
35416969 dog		35416969 dog_hardlink	35416980 dog_symlink
```
シンボリックリンクだけiノード番号が違います。

次にリンク元ファイルのdogの中にファイルを書き込みます。
```
Animal % echo ‘test’　>>dog  　#書き込み              
Animal % ls
dog		dog_hardlink	dog_symlink
Animal % cat dog　　　　#ファイルの中身確認
‘test’　
Animal % cat dog_hardlink
‘test’　
```
dogとdog_hardlinkのファイルの中身が同じですね。

この後リンク元ファイルのdogを消します。
```
Animal % rm dog
Animal % ls
dog_hardlink	dog_symlink
Animal % cat dog_symlink
cat: dog_symlink: No such file or directory
```
シンボリックリンクの中身は何もなくなっていますが、
```
Animal % ls
dog_hardlink	dog_symlink
Animal % cat dog_hardlink
‘test’　
```
ハードリンクの中身は見れます。


# リンクのコピー
リンクのコピーのやり方です。

```
$ cp -d リンク元ファイル  　リンクファイル名
```
-dをオプション指定しないとリンクではなくリンク元ファイルがコピーされます。


# 資料
https://www.udemy.com/course/linuc-lv1-101/

https://wa3.i-3-i.info/word14804.html
AWS re:Post のアカウント作成に AWS SSO の認証情報は使用しない方がいいという話

:::note warn
2022/6/28 時点の情報です。今後仕様が変わる可能性があります。
:::

## 事象
AWS SSO の認証情報を使用して AWS re:Post に登録済みのユーザーとしてサインインしようとすると、新規アカウント登録画面 (rePost-User-XXXXXX) に遷移してしまう。

あれ、自分のアカウントどこいった？
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/125105/6aecff56-62bc-240e-4c5e-524036809b74.png)

## 原因
* AWS re:Post のアカウントは特定の AWS アカウントの IAM 認証情報と紐づいている (と思われる)
* AWS SSO でアクセス許可セットの再割り当てが行われた結果、アカウントに接続する際の IAM ロールが再作成された
    * `AWSReservedSSO_AdministratorAccess_xxxxxxxxxxxxxxxx` が削除され、`AWSReservedSSO_AdministratorAccess_yyyyyyyyyyyyyyyy` が新規作成された
* AWS re:Post には再作成された IAM ロールの認証情報に紐づくユーザーが存在しないため、新規ユーザー登録画面が表示された

AWS SSO ユーザーが使用する IAM ロールは AWS SSO が自動的に管理するため、ユーザー自身で復旧することができません。よって既存の AWS re:Post アカウントにサインインすることができなくなってしまいました。

特定の IAM 認証情報と紐づくということは IAM ユーザーでも同じことが起こり得るかと思います。しかし AWS SSO はその仕組み上、IAM の認証情報が変わってしまう頻度や可能性は高いと言えます。

そのため AWS SSO の認証情報を使用して AWS re:Post アカウントを作成するのは (少なくとも現時点では) 避けた方がよいです。

ちなみに私のケースでは AWS サポートに問い合わせた結果、AWS re:Post 側でアカウントの復旧作業を実施いただけました。圧倒的感謝っ...!


## 参考: AWS re:Post とは
AWS re:Post は、AWS が管理する Q&A サービスです。従来の AWS Developer Forums の後継サービスにあたります。

https://aws.amazon.com/jp/blogs/news/aws-repost-a-reimagined-qa-experience-for-the-aws-community/

無料で利用可能ですが、質問や回答を行うにはアカウント登録が必要です。アカウント登録の際に AWS アカウントが必要になります。参照だけであればアカウント登録は不要です。

簡単ですが、以上です。
参考になれば幸いです。
【Vue.js】主要なディレクティブ一覧

## ディレクティブとは

Vue.jsでは、HTMLに対して独自の属性を追加することでDOM操作を行うことができます。

この独自の属性のことをディレクティブと呼んでいます。

ディレクティブ名は全て```v-```から始まります。

## 主要なディレクティブ

### v-ifとv-show

要素の表示と非表示を切り替えたい場合、`v-if`もしくは`v-show`を使います。

どちらも属性値が真の場合は要素を表示し、偽の場合は非表示にします。

```vuejs
<p v-if=”値”>
</p>
```

```vuejs
<p v-show=”値”>
</p>
```

どちらも表示と非表示を切り替えることができますが、その実現方法が異なります。

属性値の判定結果に応じて、`v-if`はDOM要素の追加と削除、`v-show`はdisplayプロパティの値の変更によって実現しています。

一般的にスタイルの変更よりもDOM要素の操作のほうがレンダリングコストが高くなります。

そのため属性値の判定結果が頻繁に変わる場合は`v-show`、ほぼ変わらない場合は`v-if`、というように使い分けます。

### v-for

v-forで、配列もしくはオブジェクトのデータをリストレンダリングできます。

属性値は`変数名 in 配列`という構文が使われます。

```vuejs
<li v-for="変数名 in 配列">
</li>
```

配列のindexが必要な場合、`(変数名, index) in 配列`と記述できます。

### v-on

`v-on`はchangeやinputなどのイベントが起きた時に、属性値の式を実行します。

DOM APIのaddEventListenerのようなものです。

```vuejs
<input v-on:イベント名=”実行したい式”>
```

`v-on`はよく使われるため、以下のように省略して記述できます。

```vuejs
v-on:change → @change
```

### v-model

`v-model`は双方向データバインディングを実現するディレクティブです。

DOMで変更があった時、その値をVueインスタンスのデータとして更新します。

逆にVueインスタンスのデータに変更があった時、DOMを更新します。

```vuejs
<input v-model=”値”>
```

`v-model`を使用できるのは、inputタグ、selectタグ、textareaタグです。

ユーザーが入力した内容を、値として保持できるようになります。

### v-bind

`v-bind`はHTML要素の属性に、特定のデータを渡す際に利用できます。（データバインディング）

```vuejs
<p v-bind:属性名=”値”>
</p>
```

例えばclass属性をバインディングして、特定の条件の時にclassを付与する、といった使い方ができます。

`v-on`同様、よく使われるため以下のように省略して記述できます。

```vuejs
v-bind:class → :class
```

## 終わりに

本記事で紹介したディレクティブの使用例を作成しました。

https://jsfiddle.net/yuki05/Lj64rb3f/150/

## 参考文献
https://jp.vuejs.org/v2/api/#%E3%83%87%E3%82%A3%E3%83%AC%E3%82%AF%E3%83%86%E3%82%A3%E3%83%96

https://prograshi.com/language/vue-js/list-of-main-directives/

https://rightcode.co.jp/blog/information-technology/vue-js-introduction-directive
Pythonで標準入出力

覚書です。

# 入力
## 1行にひとつ

```python
# 文字列
s = input()

# 整数
n = int(input())
```

## 1行に複数（空白区切り）

```python
# 文字列
str_list = input().split()      # 配列
s1, s2, s3 = input().split()    # 分解

# 数列
num_list = list(map(int, input().split()))  # 配列
n1, n2, n3 = map(int, input().split())      # 分解
```
## 複数行にひとつ

```python
cnt = 3     #取得する要素数。今回は3つとする

# 文字列
str_list = [input() for _ in range(cnt)]

# 数列
num_list = [int(input()) for _ in range(cnt)]
```

## 複数行に複数
```python
cnt = 3     #取得する行数。今回は3つとする

# 文字列
str_list = [input().split() for _ in range(cnt)]

# 数列
num_list = [list(map(int, input().split())) for _ in range(cnt)]
```

# 出力
## 一行に一つ
```python
print(out)
```

## 一行に複数（スペース区切り）
```python
print(f"{o1} {o2} {o3}")
print(*out)     # outは配列
```

## 複数行にひとつ
```python
for i in out:     # outは配列
    print(i)
```

## 複数行に複数
```python
for i in out:     # outは二次元配列
    print(*i)
```
Dynamics 365　一覧画面上でレコード更新する（プログラミング不要設定のみ）

## はじめに
詳細画面を開かずに、一覧画面でレコードを更新したい。
そんなときは、編集グリッド機能でできる

毎度詳細画面に遷移してから情報を更新するのは面倒だなっといったときに便利。

## 一覧画面で更新
Dynamics 365 Salesアプリで一覧画面上で更新する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/367026/4670492f-7b58-dfb5-7450-4cb0bc6cd844.png)

表示切替→編集グリッドで可能。新規登録はビュー切り替えて＋ボタンで!
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/367026/29686a49-6129-1687-22f1-39b0484f413d.png)



## 設定方法
プログラミング不要
コントロールタブで設定を追加。編集グリッドを追加することで、一覧画面上で更新ができるようになる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/367026/d44df7ad-c3f1-2cdb-dd96-05acbdb6120e.png)


https://docs.microsoft.com/ja-jp/power-apps/developer/model-driven-apps/use-editable-grids

## 類似機能
一覧画面上からWebExcel開いて、一括更新等もできる。

https://docs.microsoft.com/ja-jp/power-apps/user/export-to-excel-online
相対日付検索条件(Relative Date Filter Reference)の参照


[まとめページに戻る](https://qiita.com/Keiji_otsubo/items/60afc2a8d211b6f7d89f)
[まとめN～Z](https://qiita.com/Keiji_otsubo/items/92f92bb9f668ca9688be)

いやぁ、同じところに２つも条件を設定しないだろうと思っていたが、まさかの.... 思いもよらないです。何でこんな設定できるんだろう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/ec402a78-6692-6b09-950d-04ef19e6fa77.png)


それが問題です。機会：作成日とアクティビティ：日付は2つの異なるフィールドであるため、2つのダッシュボードフィルターが必要になります

[ダッシュボードフィルターの日付](https://trailhead.salesforce.com/ja/trailblazer-community/feed/0D54S00000HDxZV)


# 相対日付検索条件の参照 の資料

[相対日付検索条件の参照](https://help.salesforce.com/s/articleView?id=sf.filter_dates_relative.htm&type=5)
Create and Train the Dataset not working

[Trailhead関係　個別の課題別 に戻る](https://qiita.com/Keiji_otsubo/items/56eb7a90bb72138ece1f)


最終的には解決したみたいですが、意味が分からない。

[Create and Train the Dataset not working](https://trailhead.salesforce.com/ja/trailblazer-community/feed/0D54S00000HnLLLSA3)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328136/3c6296b6-653a-c1e2-35fa-a92dd6055a71.png)


# 関連しそうな質問/回答

[SSalesforce Einstein - Create and Train the Dataset - Trailhead Challenge](https://salesforce.stackexchange.com/questions/256230/salesforce-einstein-create-and-train-the-dataset-trailhead-challenge)
Power Auotomate の HTTP アクションが 302 エラーで失敗する

Power Automate の HTTP アクションはステータス コード 302 を受け取ると失敗します。

![l_1517737_1977_1e7d0d83352bd19cc460f92c3b883cf3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396107/baed4373-e977-510f-8d8d-196fed89c897.png)

このため、フローの実行はここで終了され、以降のアクションは実行されません。

302 エラーの際に、リダイレクト先に指定された URI のコンテンツを取得してフローを続けるには、次のアクションで 「実行条件の構成」の設定を行います。

![l_1517737_1978_cab8a444b1ca4f7137182dde52ad47bf.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396107/92bf703a-93fc-fe19-86ed-4d4218e105d7.png)


既定は、[に成功しました] ですが、これを [に失敗しました] に変更します。

![l_1517737_1979_c47fdc24cccf2cb4dba68be5ac261982.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396107/1dfd15ae-9d0c-e06d-dee2-4d0456e54093.png)

この設定で、ステータス コード 302 でアクションが失敗した際に、次のアクションが実行されます。

次のアクションでリダイレクト先の URI にアクセスするには、[URI] に式で

```
outputs('HTTP')['headers']['Location']
```
を指定します。

![l_1517737_1980_fd887547a057766b4a30b0851d5fbbd4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396107/89c5ee09-a7f4-7b80-59b2-1800aee7e1da.png)

以上の設定で、302 エラーの際にもフローを続行することが可能です。

![l_1517737_1981_a29a94f423bce367e93d941ebf6ca6e4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396107/5f7218a6-2b6f-8938-03bb-ef295bbcc52a.png)
Pythonでエクセルに二次元配列を書き込む

Pythonを使って99×99の掛け算をエクセルに書き込んでみる
今回は2パターン示す

# 環境
- OS
    - Windows10
- Python
    - Python3.9.6
- Excel
    - Microsoft 365

# 準備
今回はwin32comでエクセルに対して操作を行うため、pywin32のインストールを行う
#### pipのアップグレード
```
pip install --upgrade pip
```

#### pywin32のインストール
```
pip install pywin32
```

# 実装
99×99の二次元配列を用意する
sample.xlsxを開いて、Sheet1を取得する
```py
from pathlib import Path
import win32com.client

# 99×99の二次元配列
twoDArray = [[i * j for i in range(1, 100)] for j in range(1, 100)]

# エクセルを開く
app = win32com.client.Dispatch("Excel.Application")
abspath = str(Path(r"sample.xlsx").resolve())
book = app.Workbooks.Open(abspath)
sheet = book.Worksheets("Sheet1")
```
### パターン1（ループで頑張る）
セルの始まりは(0,0)ではなく(1,1)であるため、インデックスに+1している
```py
for y, array in enumerate(twoDArray):
    for x, element in enumerate(array):
        sheet.Cells(y+1, x+1).Value = twoDArray[y][x]
```
### パターン2（一括で貼り付ける）
99×99の範囲に値を張り付ける
```py
sheet.Range(sheet.Cells(1,1),
            sheet.Cells(len(twoDArray),
                        len(twoDArray[0]))
            ).Value = twoDArray
```
# 結果
パターン1,2で結果は変わりません
99×99の二次元配列が書き込まれます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/303274/fa79d02a-3702-99f7-c70a-de1148b2c62d.png)


# 速度
それぞれのパターンにおける値書込みの実行時間を比較する(10回平均)
- パターン1
    - 42.97[sec]
- パターン2
    - 0.046[sec]

# 結論
ループで処理しない分、圧倒的にパターン2が早いですね

# 参考
[Python pywin32(win32com) Excel 操作備忘録](https://qiita.com/feo52/items/150745ae0cc17cb5c866)
[Excel using win32com and python](https://stackoverflow.com/questions/18575043/excel-using-win32com-and-python)
OpenSearch （ ElasticSearch ） の利用料を最適化する　〜円安ドル高にちょっと抵抗してみる〜

# はじめに
円安が止まりません。20数年ぶりの円安水準だそうです。ガソリン代も高騰していますが、ドルベースのAWS利用料も影響を受けてしまいます。AWS利用料には補助金は導入されませんので、自助努力するしかないですね。仕事の効率が落ちない程度に、コスト最適化を考えてみます。

# OpenSearchの費用について
OpenSearchのデータノードは、マルチAZにすると2（または3）の倍数が必要で、シャード数も考慮すると、両方の公倍数にした方が良いです。となると、必然的にデータノード数はある程度多くなり、それに伴い費用もかさみがちだと思います。

# OpenSearchの運用コストを最適化
商用環境には手をつけにくいので、検証環境（開発環境）にフォーカスします。コストを無視すれば、検証環境はできる限り商用環境と同じ環境であることが理想ではあると思いますが、ほとんどの時間で性能を持て余します。そこで、性能が必要な場合（性能テスト時など）のみ、商用レベルの性能を付与する（動的に設定変更する）ことにします。

# 最適化の方針
とはいえ、手間は増やしたくありません。データ量に依存するデータノード数やEBSサイズは据置とします。インスタンスタイプ、EBSタイプ（汎用 or IOPS）の変更によって性能を下げることで、単価を減らす方向性にします。これらの設定変更は30分程度（環境依存）かかりますが、基本的にダウンタイムなしなので業務を妨げることもないです。設定変更は楽にしたいので、lambda実行で済むようにします。

# lambda実装
性能縮退する実装例。データノードのインスタンスタイプを小さく、EBSタイプを汎用にしています。API一本で済みます。
```py    
import json
import boto3
client = boto3.client('opensearch')

def downgrade():
    response = client.update_domain_config(
        DomainName='your domain name',
        ClusterConfig={
            'InstanceType': 't3.medium.search'
        },
        EBSOptions={
            'EBSEnabled': True,
            'VolumeType': 'gp2',
            'VolumeSize': 35
        }
    )
```
性能拡張する実装例。縮退時よりデータノードのインスタンスタイプを大きくし、EBSタイプをProvisioned IOPS（IOPSも指定）にしています。
```py
import json
import boto3
client = boto3.client('opensearch')

def upgrade():
    response = client.update_domain_config(
        DomainName='your domain name',
        ClusterConfig={
            'InstanceType': 'm5.xlarge.search'
        },
        EBSOptions={
            'EBSEnabled': True,
            'VolumeType': 'io1',
            'VolumeSize': 35,
            'Iops': 1000
        }
    )
```

:::note warn
* lambdaの実行ロールにOpenSearchのアクセス権限が必要
* API実行に数秒かかるので、lambdaのタイムアウトは5〜10秒程度にしておくと良い
:::

[参考:Boto3Docs](https://boto3.amazonaws.com/v1/documentation/api/1.18.51/reference/services/opensearch.html)

# おわりに
縮退するのを忘れてしまう場合は、EventBridgeから定期的にlambda実行しておけば良いと思います。設定変更中はブルーグリーンのためにインスタンスがむしろ増えるので、あまり頻繁に変更するのはおすすめできませんが、昼間・夜間で変更する、休日・平日で変更する程度であればアリだと思います。
CloudFormationでS3実装に挑戦①

:::note info 
今回やったこと
1. S3バケットの作成
コンソールで設定項目を確認てから、テンプレート作成
1. AWS CLIでの、スタック作成・スタック削除・テンプレートの検証

* 次回申し送り事項
EC2からの接続設定
[参考]（https://aws.amazon.com/jp/premiumsupport/knowledge-center/connect-s3-vpc-endpoint/)
:::

### 1. S3バケットの作成
一度コンソールを確認する。
* 一般的な設定
  - バケット名
  - リージョン
* オブジェクト所有者
  - ACL無効
* ブロックパブリックアクセス設定
  - ブロックしない
* バージョニング
  - 無効
* デフォルトの暗号化
  - 無効

次に公式のサンプルテンプレートを見る。
```yml
Resources:
  S3Bucket:
    Type: 'AWS::S3::Bucket'
    DeletionPolicy: Retain
    Properties:
      BucketName: DOC-EXAMPLE-BUCKET
```

…あれ、作るだけなら簡単なのでは?
と思ったけど、EC2からの接続設定とかCORS設定とか、そのあたりで難儀しそう。
リソース同士の関係性の記述は難しい。RDSのときも苦労した。

### 2. AWS CLIでの、スタック作成・スタック削除・テンプレートの検証
本当はEC2からの接続までやりたかった。時間的に、今回はCLI操作でスタックの作成をやってみる(今まではGUIでポチポチやってた)。
公式ドキュメントを確認。CLI自体はインストール済。
[AWS Command Line Interface の使用](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/cfn-using-cli.html)

#### スタック作成

```
 % aws cloudformation create-stack \
--stack-name myfirsts3 \
--template-body file:///Users/わしの名前/Desktop/firsts3.yml
{
    "StackId": "arn:aws:cloudformation:ap-northeast-1:********:stack/myfirsts3/********"
}
```
改行して入力するときは` \`(スペースが必要)なんですね。。。

#### 作成できたか確認
`aws s3 ls`コマンドを打つ。出てこない。以下も確認してみる。
```
% aws cloudformation describe-stacks
{
    "Stacks": [
        {
            "StackId": "arn:aws:cloudformation:ap-northeast-1:********:stack/firsts3/********",
            "StackName": "firsts3",
            "CreationTime": "2022-06-27T22:36:58.883000+00:00",
            "DeletionTime": "2022-06-27T22:37:05.014000+00:00",
            "RollbackConfiguration": {},
            "StackStatus": "ROLLBACK_COMPLETE",
            "DisableRollback": false,
            "NotificationARNs": [],
            "Tags": [],
            "DriftInformation": {
                "StackDriftStatus": "NOT_CHECKED"
            }
```

失敗。どうしてだろうと思ったら,バケット名の命名規則とかユニーク性に引っかかっていた。こんなしょうもないところで…

`aws cloudformation delete-stack --stack-name`でスタックを削除し、再度作成。今度は成功。

### テンプレートの検証
検証機能ないのかなと思ったら、どうやらあるらしい。
`aws cloudformation validate-template --template-body file://ファイル名`


検知できるのは構文エラーだけみたいです。リソースタイプの誤り、プロパティの誤りは検知してくれたが、バケット名のユニーク性、インデント等はチェックされなかった。
そのへんのエラーはコンソールで確認するしかないのだろうか？
React: Props の使い方

こちらを参考にしました。
[React Props](https://www.w3schools.com/react/react_props.asp)

コマンドのインストール

```bash
sudo npm install -g create-react-app
sudo npm install -g yarn
```

使ったバージョン

```text
$ node --version
v18.4.0
$ yarn --version
1.22.19
$ npx create-react-app --version
5.0.1
```

プロジェクトの作成

```bash
create-react-app re01
cd re01
yarn start
```

src/App.js を次で置き換えます。

```js:src/App.js
import logo from './logo.svg';
import './App.css';

function Car(props) {
  return <h2>I am a { props.brand }!</h2>;
}

function App() {
  return (
    <div className="App">
      <header className="App-header">
	<p>Hello World!</p>
	<Car brand="Honda" />
	<Car brand="BMW" />
	<blockquote>
	<p>Jun/28/2022</p>
	</blockquote>
      </header>
    </div>
  );
}

export default App;
```

ブラウザーで、　http://localhost:3000/　にアクセス
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/179446/f01fca05-9461-b211-ac27-5820ca46f07b.png)
【Tableau】定数線について

# 今回の解消したい課題
- アナリティクスの定数を選んだ際の表現について
        - ドラッグアンドドロップして置く際の種類について
        - 一番最初、選んだ際の差が分からなかったため備忘録として記載
# 環境
Tableau Desktop 2022.1.3
データソース：サンプル - スーパーストア
***
【テーマ】：四半期ごとの売上をサブカテゴリごとに可視化する
■まずは四半期ごとの売上を可視化してみる
![01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2707779/a38b72ff-a765-cf1b-0ab6-68363c7d129b.png)
Tableauではおなじみのサンプル - スーパーストアを利用
データの右隣にあるアナリティクスを選択
![02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2707779/fbe5b33c-3e20-e1b0-ca7e-a8ace7d09ee7.png)
ドラッグしてグラフ側に持っていくと３つの選択肢を選ぶことができる

 1.リファレンスラインの追加
![03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2707779/99adae67-d489-98bd-c5c4-ea7e1763f0d1.png)
__縦と横__ それぞれに定数線が入る
 2.四半期(オーダー日)
![04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2707779/f0fbbb18-d9f7-a5e9-9af0-80e3e1f38720.png)
__縦(オーダー日)__ に線が入る
 3.合計(売上)
![05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2707779/5f93d701-cbab-c91a-b5bb-bf46c71f82b3.png)
__横(売上)__ に線が入る

考えてみれば至って普通だが、最初は違いが分からなかったため備忘録として記載
当然ながら定数線は右クリックして、希望の数値へ値を変更することが可能

***
あくまで個人的な可視化方法なので参考になれば...
Tableauの操作は奥が深い。
laravel unitテストconfig()が使えない

# 概要

- laravelのunitテストにて`config()`関数を用いているコードのテストを実行するとconfigクラスが存在しない旨のエラーが出るので解消方法をまとめる。

# エラー内容

- `Target class [config] does not exist.`

# 解消方法

1. 当該のテストコードを開く
1. 下記のように`CreatesApplication`トレイトをテストクラスの外で名前解決、テストクラス内でuse宣言、setUp()関数を用意して`$this->createApplication()`を実行する。

    ```FooTest.php
    <?php
    
    namespace Tests\Unit;
    
    use PHPUnit\Framework\TestCase;
    use Mockery;
    use Tests\CreatesApplication;
    
    class FooTest extends TestCase
    {
        use CreatesApplication;
    
        public function setUp(): void
        {
            parent::setUp();
        
            $this->createApplication();
        }
    }
    ```

PHPUnitのunitテストのライフサイクルはlaravelの外で行われていることが原因かな・・？

# 参考文献

- [https://sakamata.hateblo.jp/entry/2020/07/01/160035](https://sakamata.hateblo.jp/entry/2020/07/01/160035)
- [https://techacademy.jp/magazine/18805](https://techacademy.jp/magazine/18805)
- [https://blog.baseball.tokyo/archives/9](https://blog.baseball.tokyo/archives/9)
- [https://qiita.com/sandabu/items/f5ed672c39ccd2f959cb](https://qiita.com/sandabu/items/f5ed672c39ccd2f959cb)
- [https://readouble.com/laravel/8.x/ja/providers.html](https://readouble.com/laravel/8.x/ja/providers.html)
プライベートサブネットからNATゲートウェイを経由して、インターネットに接続する

# NATゲートウェイを作成する
AWSマネジメントコンソールの「VPCダッシュボード」を表示してください。
「NATゲートウェイ」をクリックしてください。
「NATゲートウェイの作成」をクリックしてください。
![スクリーンショット 2022-06-28 6.13.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14202/1e3d8926-7474-b544-28b7-08ed02df3e16.png)

「NATゲートウェイの作成」ページが表示されます。
「サブネット」で、パブリックサブネットを選択します。
「接続タイプ」で、パブリックを選択します。
「ElasticIPの割り当て」ボタンをクリックします。
「NATゲートウェイを作成」ボタンをクリックします。
![スクリーンショット 2022-06-28 6.20.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14202/e24ba7c7-8ef6-034d-65c7-145a4889091b.png)

# ルートテーブルを更新する
プライベートサブネットからインターネットに対して通信するとき、NATゲートウェイに流れるように、ルートテーブルを更新します。

AWSマネジメントコンソールの「ルートテーブル」を表示してください。
プライベートサブネットを選択します。
ルートテーブルを編集し、「送信先」に「0.0.0.0/0」を入力してください。
「ターゲット」に、作成したNATゲートウェイを選択してください。
「変更を保存」をクリックしてください。
![スクリーンショット 2022-06-28 6.28.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14202/9b6b4ff8-d74b-85e8-3404-c2c38d6550d0.png)

# インターネットへの接続を確認する
プライベートサブネットのEC2インスンスにログインしてください。
以下のコマンドを実行してください。
```
% curl www.yahoo.co.jp
```

NATゲートウェイは稼働時間と転送バイト単位で課金されます。
NATゲートウェイを使う必要が無くなったら、すぐに削除してください。
以上です。
【Tableau】セットを用いてTop10とWorst10を同時に可視化する方法

# 今回の解消したい課題
- Top10とWorst10を __同時__ に表現する際の可視化方法を実現する
        - セットを利用して表現する
# 環境
Tableau Desktop 2022.1.3
データソース：サンプル - スーパーストア
***
【テーマ】：顧客ごとの売上のTop10とWorst10を同時に可視化で表示したい
1. まずは顧客ごとの売上を可視化する
顧客ごとの売上を可視化し、降順にソート
![01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2707779/af8734ba-6d36-9ecd-38f6-2b8035d3b91d.png)
Tableauではおなじみのサンプル - スーパーストアを利用

2. Top10/Worst10をフィルター
![02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2707779/df4fa319-bc82-2c06-80cf-1e81d1ac9378.png)
顧客名をフィルターにドロップし
全般タブ→「すべて使用」→上位タブ→「フィールド指定」→上位10を選択
![03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2707779/7f1e07b2-dc77-e17e-7b84-416635b9a77e.png)
すると
![04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2707779/fe31051f-b922-92a3-d7ac-28e62ae85494.png)
期待どおりにTop10を抽出することができた
同様に上記の上位タブで選んだ上位10を下位10に変更することで選ぶことが可能
しかし同時にTop10とWorst10を出すことはこのままでは不可能である。

そこで今回利用するのが __セット__ である。
フィルターの顧客名を右クリックし、「セットの作成」を選択する
![05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2707779/105c70b5-7f7b-79ea-5e23-a46712dac7e2.png)
この作成方法でTop10とWorst10の両方のセットを作成する
3. 結合セットの作成
![06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2707779/9d68e320-db1b-4a68-27aa-a20522992e81.png)
Top10とWorst10の両方を選択した上で右クリックし
「結合セット」を選択する
![07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2707779/53cced3f-0896-22cf-37d9-d0ea9fbb1c8a.png)
今回はTop10とWorst10の両方を含みたいので
「両方のセットのすべてのメンバー」を選択
すると新しいセットが作成される
![08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2707779/640200d4-0dab-3459-f78f-2ba4d05bdfdd.png)
新しく作成されたセットをフィルターに置くと希望通りに
Top10とWorst10を可視化することができる



***
あくまで個人的な可視化方法なので参考になれば...
Tableauの操作は奥が深い。
laravel Mockeryを使ってテストを書く（インストール準備編）

# 概要

- laravelの環境にMockeryをインストールして使えるところまで持っていく方法をメモ的にまとめる。

# 方法

1. 下記コマンドを実行してMockeryをcomposerでインストールする。

    ```terminal
    $ composer require --dev mockery/mockery
    ```

1. composer.jsonを確認し、require-devにMockeryの情報が追記されていれば準備完了である。

    ```composer.json
    "require-dev": {
        "mockery/mockery": "^1.5",
    }
    ```

1. tinkerにて下記を実行し、エラーがでないことを確認する。

    ```php
    $mock = \Mockery::mock('foo');
    ```

# 参考文献

- [https://readouble.com/mockery/1.0/ja/index.html](https://readouble.com/mockery/1.0/ja/index.html)
- [https://packagist.org/packages/mockery/mockery](https://packagist.org/packages/mockery/mockery)
- [https://readouble.com/laravel/8.x/ja/mocking.html](https://readouble.com/laravel/8.x/ja/mocking.html)
新人さんにすすめるふりかえり 2022夏

すっかり夏です... 
研修も大詰めを迎える頃に読んでほしい「ふりかえり」手法をまとめておきました。

## ふりかえり色々

[ふりかえりを拡張する「ふりかえりカタログ」 - Qiita](https://qiita.com/viva_tweet_x/items/cc3bad3bd298406b6cc7)

<script async class="speakerdeck-embed" data-id="7244ead3883a4f519c13a80ae712ad8c" data-ratio="1.44428772919605" src="//speakerdeck.com/assets/embed.js"></script>

```md
## 立ち止まる
- 「みんなで」立ち止まって、視野を広げる

## チームを成長させる
- 関係の質を高めて、全体最適を目指す

## プロセスをカイゼンする
- 問題点を解決する改善
- 仕事のやり方を継続的に良くしていくカイゼン
```

**成長・場・学び**

大事なのは、インプットだけではない、学びのアウトプットだと言います。ふりかえりはアウトプットの絶好のチャンスでもあります。
参考: [教えることで自分がいちばん学ぶ、「ファインマンテクニック」を使って複雑な概念をよりよく理解する - Qiita](https://qiita.com/e99h2121/items/833b34ed6c34020af8f9)



## Fun Done Learn

- ふりかえり手法はたくさんあることがわかります
    - [「ふりかえりの手法をたくさん学ぼう」で紹介された手法まとめ - Qiita](https://qiita.com/98lerr/items/423a3e8ee44e118091bf)
- 代表的な2つといえば以下です
    - KPT (Keep Problem Try)
    - YWT (やったこと・わかったこと・つぎやること)
        - [KPTとYWTの違いは？～KPTがうまくいかない理由と、YWTの特性を考える - Qiita](https://qiita.com/viva_tweet_x/items/bab769c190508c4808be)
        - どちらが良い悪いではなく、場に応じて使い分けると良い

そんな中、 **Fun Done Learn (ファン・ダン・ラーン)** はどうでしょうというのが本題です。簡単なやり方は以下です。タイトルから楽しそうな印象を持ってもらえたら嬉しいです。
[ファン・ダン・ラーン(FDL)ふりかえりボード - Qiita](https://qiita.com/yattom/items/90ac533d993d3a2d2d0f)

1. ホワイトボードや模造紙に、上のFun/Done/Learnの図を描く。
2. 1人ひとりで、やったことを付箋に書き出す。
3. 付箋の内容を共有して会話しながら、図上の当てはまる領域に付箋を貼っていく。

参考: 
- [ふりかえりでFun! Done! Learn! | オブジェクトの広場](https://www.ogis-ri.co.jp/otc/hiroba/others/ActivityPocket/FunDoneLearn.html)
- [新しいふりかえり手法「ファンダンラーン」の紹介｜Jun Ishitsuka｜note](https://note.com/ij_spitz/n/n7fb8de4d2540)
- [Fun/Done/Learnで振り返りをやってみる. Fun/Done/Learnとは？ | by Masato Ishigaki | Masato Ishigaki | Medium](https://medium.com/i35-267/fun-done-learn%E3%81%A7%E6%8C%AF%E3%82%8A%E8%BF%94%E3%82%8A%E3%82%92%E3%82%84%E3%81%A3%E3%81%A6%E3%81%BF%E3%82%8B-e74eeb978b51)
- [オンラインでFun/Done/Learnふりかえりをしてみました](https://zenn.dev/issei126/articles/546d0d89e1be1c)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/93824/8848e54b-d55f-faca-d0e3-7952b40e20a8.png)

## テンプレート
[Yasui Tsutomu's Fun Done Learn Retrospective template | Miroverse](https://miro.com/miroverse/fun-done-learn-retrospective/)
[Fun Done Learn ふりかえりシート](https://pm-notes.com/wp/wp-content/uploads/2019/04/76daa97a1b31596dd6ab906c808d853b.pdf)


## 以上

ぜひふりかえろう！
新人さんにすすめる色々

[新人さんにすすめる有益なツール達 2022春 - Qiita](https://qiita.com/e99h2121/items/f70db44e7f69901f0141)
[新人さんにすすめる有益な技術書達 2022春 - Qiita](https://qiita.com/e99h2121/items/1b243efb1499527f0701)
[新人さんにすすめる (弊社の) 有益な記事達 2022春 - Qiita](https://qiita.com/e99h2121/items/d9c6c28d472f263d590a)
[新人さんにすすめるさいきょうの読書術 2022年初夏 - Qiita](https://qiita.com/e99h2121/items/fd4e6404d46f3d849282)
[新人さんにすすめる「もくもく会」 2022年初夏 🍧 - Qiita](https://qiita.com/e99h2121/items/a66255cd6d68115a7694)

以上です～
Webデザイン用語集メモ

Webサイト制作の時の配色について悩むことが多いので各色の説明についてメモをしておきます。
感覚ではなく理論で配色をとらえられるようになりたい。

**赤**
特徴：熱く、エネルギッシュで生命力にあ溢れる。勝者や成功者、リーダー、ヒーロー、正義のイメージ
短所：危険や警告のイメージ

**青**
特徴：清潔感、爽快感を想起、信頼や誠実さ、平和を象徴
短所：冷たさや不安を想起
**緑**
特徴：自然やエコ、環境などの植物にちなんだイメージ。穏やかさや安らぎなど。
短所：あまりない。無難
**黄**
特徴：明るさ、温かさ、幸福、親しみやすさを表現する
短所：警戒色として使われる
**紫**
特徴：高貴さを示す。女性的、優雅さ、神秘を感じる色
短所：不良、水商売、自信過剰、不遜さを連想
**橙**
特徴：エネルギッシュ、元気、ビタミン豊富といったイメージ。食欲をそそる色
短所：安っぽく大衆的な印象になる
**黒**
特徴：硬質、重厚、権威、気高さ、プロフェッショナリズム、伝統の象徴として使われる
短所：闇や死を想起させる
**灰**
特徴：先進的でスタイリッシュな印象、鋭く知的なイメージを作る
短所：無機質、不安、薄暗さ
**白**
特徴：純粋さ、けがれなさを表し、クリーン、公正、神聖、平和の象徴の色
短所：空虚さや味気無さを感じる
Jetpack Compose TextField フォーカスでキーボードを開閉する



### フォーカスを当てる

FocusRequester を使います。

```kotlin
val focusRequester = remember { FocusRequester() }
```

focusRequester を TextFiled に仕込みます。

```kotlin
TextField(
  modifier = Modifier.focusRequester(focusRequester)
)
```

それを Button クリックでフォーカスします。

```kotlin
Button(
  onClick = { focusRequester.requestFocus() }
) {
```

同時に、キーボードは開きます。


### フォーカスを外す

同様に、FocusRequester でやれると思ったら、できません。

LocalFocusManager を使います。

```kotlin
val focusManager = LocalFocusManager.current
```
フォーカスを外してくれます。

同様に、ボタンに仕込みます。

```kotlin
Button(
  onClick = { focusManager.clearFocus() }
) {
```

これも、フォーカスを外すと同時にキーボードが閉じます。


![screencapture-1656359742016.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/588914/4ab52970-b113-aef1-b4e4-82bde90f728a.gif)

[👉 【Jetpack Compose】TextField の フォーカス と IME 開閉 と カーソル位置](https://android.benigumo.com/20220628/jetpackcompose-textfield-focus-ime/)