OmniAICreator/Qiita-1.07M huggingface dataset:
レガシープロダクトで始める仕様化テスト_コミット履歴の作り方の工夫

# 仕様化テスト作成の弊害
仕様化テストを書く際に唯一避けて通れないデメリットがあります。
それはソースコードの修正量が増えることです。
テストコードが増えるのは当然ですが、プロダクトコードへの修正も増加します。

- クラスやメソッドのスコープを広げる
- 既存ロジックをクラスやメソッドに切り出す
- 変数名、メソッド名、クラス名を変更する
- final修飾子を除去する
- 不要であることが判明したロジックを削除する

などなど、仕様化テストを書いたりさらにその後にリファクタリングを行うと
プロダクトコードにもたくさんの修正が入ります。
コードの改善活動は積極的に行うべきことですが、
コードを変更するということはそこに不具合が発生するリスクが生じます。
また変更をレビューするレビュアーの負担も増加します。

# コミット履歴を工夫する
不具合発生のリスクやレビュアーの負担を低減するために
私が実行しているコミット履歴の作成方法の工夫を紹介します。

## 基本原則
- リファクタリングは可能な限りIDEの機能を利用する
- 小さい作業でコミットを分ける
- 作業の種類でコミットを分ける
- 作業内容をコミットコメントに書く

レビュアーが重点的に確認したい箇所をコミット差分から選択できるようにします。

## 作業例
実際にレガシープロダクトに不具合修正を行った際のコミット履歴を見ながら説明します。
（時系列は下から上）

![](https://storage.googleapis.com/zenn-user-upload/i03qjzkc8dsqmw2fq8wmjho67802)

以下の手順で作業しています。
- テスト追加をしやすいようにプロダクトコードにリスクの低い修正をする
- 仕様化テストを書く
- 不具合修正とそれに合わせたテストの修正
- テストで保護した箇所への大胆なリファクタリング
- メソッド名の変更など微調整

それぞれ作業内容とコミット履歴を作る際の工夫を説明します。

### テスト追加をしやすいようにプロダクトコードにリスクの低い修正をする

テストを書くための下準備として細心の注意を払いながらリスクの低い修正を行います。

- 読みづらいコードの修正（無駄にスコープが広い、変数名・メソッド名が嘘など）
⇒スコープの変更、変数名・メソッド名の修正
- Mockにしたいメソッドがstaticになっている
⇒ staticをやめる、instanceメソッドでラップする
- Mockにするのが面倒な構造体が引数で渡ってきている
⇒Mockにしやすい引数に変更する

これらの作業を以下のような基準で分けるようにしています。
- IDEによる修正（変数名・メソッド名の変更、メソッドの抽出など）
- 手動の修正だがほぼリスクなし（スコープの変更、利用していない引数の削除など）
- 手動の修正で少しリスクあり（引数の変更など）

今回はIDEでの修正はなかったので手動の修正でほぼリスクのないものを一つ目のコミットにまとめ、手動の修正で若干リスクがあるものを二つ目のコミットに入れています。

コメントに内容も記載しているので、レビュアーは一つ目のコミットはリスクが無い内容なので軽く見て、二つ目のコミットは少しリスクがあるのでじっくり見る、というような見方ができるようになります。

### 仕様化テストを書く
三つ目のコミットで実施しています。

今回は対象のメソッドが小さかったので一つのコミットで書ききっています。
テストコードが大きくなる場合は区切りの良いところでコミットを分けて書きます。

その際プロダクトコードにも修正を入れている場合はそれを明示するようにしています。
プロダクトコードにも修正が入っていればそこで不具合が発生する可能性があるためです。

### 不具合修正とそれに合わせたテストの修正
四つ目のコミットで書いています。
アプリケーションの挙動を意図して変える部分なので必ずコミットは分けるようにしています。
仕様化テストを書かずに不具合修正を行う場合、コードの修正はこのコミットのみになります。

### テストで保護した箇所への大胆なリファクタリング
五つ目のコミットです。
仕様化テストを書いてコードを読み切ると、リファクタリングをしたい箇所が少なからず出てくると思います。
仕様化テストでメソッドの分岐網羅ができていれば、大胆な修正を行ってもある程度JUnitで動作を担保できます。
また仕様化テストがかけていれば、リファクタリングの内容に問題が無いかを仕様と照らし合わせて判断することもできます。
そういった理由から大胆なリファクタリングはこのフェーズまで我慢するようにしています。

### メソッド名の変更など微調整
六つ目のコミットです。
ここではレビューでクラス名が適切ではないと指摘を受けて修正しています。
レビュー指摘の修正を行う場合も

- IDEによる修正（変数名・メソッド名の変更、メソッドの抽出など）
- 手動の修正だがほぼリスクなし（スコープの変更、利用していない引数の削除など）
- 手動の修正で少しリスクあり（引数の変更など）
- 追加の挙動修正（不具合が直りきっていないと指摘を受けた時）

といったところを意識してコミットを分けると良いと思います。  
  
※この記事は[zennで書いてた記事](https://zenn.dev/gengen0719/articles/87a527a031ed71)の転記です
【Mac】アプリのBundle Identifierを取得する方法

## `Bundle Identifier`の取得方法

次のコマンドを実行することでアプリの`Bundle Identifier`を取得できます。

```terminal
lsappinfo info -only bundleid "アプリ名"
```

```terminal
$ lsappinfo info -only bundleid "Google Chrome"
"CFBundleIdentifier"="com.google.Chrome"
```

また次のコマンドでも取得できます。

```terminal
osascript -e 'id of app "アプリ名"'
```

```terminal
$ osascript -e 'id of app "Safari"'
com.apple.Safari
```
Reactで、大規模なCSSの問題

以下はフFacebookチームでreactを作りながら直面したCSS問題について悩んだ内容になります。
https://speakerdeck.com/vjeux/react-css-in-js


以下は、上のURLから引き上げられた問題を整理した内容になります。
<h2>RReactで、大規模なCSSの問題点</h2>
<b>Global Namespace：グローバル変数を避けるべきjsと対峙。</b><br>
JavaScriptはグローバルな変数の使用を控えるが、
cssはグローバルな変数を使用しています(class Name)
上記の2つは相反します。
<br>
<b>Dependencies：css間の依存管理</b>

<br>
<br>

<b>Dead Code Elimination：使用しないcss について認知が難しい。</b>
使用しなくなったcssファイルを削除しなかった場合、それによって削除されなかったcssファイルが蓄積された場合、
ファイルをproductにする場合、jsファイルにスタイル情報もすべて入ります。
そのような結果物の中に使用しないファイルが入ることは、サービス全体のサイズを増加させる不要な要素になります。

<b>Minification：css クラス名を最小化</b>
クラス名を私たちが理解しやすいように長くネーミングしたことを無意味だが、コンピュータが理解できる短い名前に変えることがファイルのサイズを小さくする役割をするが、リアクトではminificationをサポートしなかったという点。

<b>Sharing Constants：JSのコードと値を共有したいですが...</b>

<b>Non-deterministic Resolution：cssファイルロードタイミングイシュー</b>
どのcssファイルを先にロードしたかによってスタイルが上書きされる場合があります。
同じスタイルのファイルをインポートしたにもかかわらず、あるコンポーネントを描くときはAという形で表示されますが、
他のコンポーネントを描くときは、Bという形で出てくる場合があります。
そのため、ロードタイミングさえも定義しておかなければならない形でコンポーネントが描かれる問題があります。

<b>Isolation：隔離</b>
スタイルとコンポーネントが分離され、そのように管理されてこそコンポーネント単位で開発されるリアクトのパラダイムと一致しますが、
スタイルが共有され続け、cssファイルの中にあるクラス名が他のコンポーネントにも影響を与えると、コンポーネントを再利用する過程でも困難があります。
[Chakra UI]カスタムサイズのボタンを作ってみた

# カスタムサイズのボタンの作り方

## 公式ドキュメント

[公式ドキュメント](https://chakra-ui.com/docs/styled-system/customize-theme)

基本的に公式ドキュメント通りにすると作成できる。

## 前提
Next.jsで作成する前提とする。

## themeの作成

### 構造

今回、必要な部分のみを抽出

```
your_project
├── pages
│   └── _app.tsx
├── theme
│   ├── components
│   │   └── button.ts
│   └── index.ts
...
```

### 作成するファイル

```index.ts
import { extendTheme } from '@chakra-ui/react'

import Button from './components/button'

const theme = extendTheme({
  components: {
    Button,
  },
})

export default theme
```

今回は```xl```と```2xl```サイズを作成する。

```button.ts
const Button = {
  sizes: {
    xl: {
      h: '56px',
      fontSize: 'lg',
      px: '32px',
    },
    '2xl': {
      h: '64px',
      fontSize: '2xl',
      px: '36px',
    },
  },
}

export default Button

```

## themeの適用
```_app.tsx
import '@/styles/globals.css'
import type { AppProps } from 'next/app'
import { ChakraProvider } from '@chakra-ui/react'
import theme from '@/theme'

export default function App({ Component, pageProps }: AppProps) {
  return (
    <ChakraProvider theme={theme}>
      <Component {...pageProps} />
    </ChakraProvider>
  )
}
```

## 使用方法
```size```に作成した```xl```や```2xl```を指定すれば良い。

```
<Button
  size={{ base: 'md', sm: 'xl', md: '2xl' }}
  boxShadow="xl"
  px={6}
  colorScheme={'green'}
  bg={'green.400'}
  _hover={{ bg: 'green.500' }}
>
  ボタン
</Button>
```
paizaラーニング レベルアップ問題集 paizaの森練習問題コンテスト過去問題8 JavaScript タスクスケジューリング

タスクスケジューリング (paizaランク B 相当)

https://paiza.jp/works/mondai/forest_contest_008/forest_contest_008__task_scheduling

# 解答例
できるだけ多くの仕事に参加したいところがポイントです。

そのためには、仕事の終了時刻に注目し、早い順に並べ替えます。
順に仕事を調べていき、前の参加した仕事の終了時刻より、調べている仕事の開始時刻が遅ければ参加するようにします。
これを最後まで繰り返すと、できるだけ多くの仕事をした時の仕事の個数が求まります。

図でイメージすると、理解しやすくなります。以下の問題が参考になります。

参考：paizaラーニング レベルアップ問題集 ソートメニュー応用編 JavaScript スケジューリング

https://paiza.jp/works/mondai/sort_advanced/sort_advanced__problems_speedup_step6

```javascript
const fs = require("fs");
const input = fs.readFileSync("/dev/stdin", "utf-8").trim();
const lines = input.split("\n");

const n = Number(lines[0]);
const works = lines.slice(1).map(line => line.split(" ").map(Number));

works.sort((a, b) => a[1] - b[1]);//終了時刻が早い順に並べ替え

let ans = 0;//参加できる仕事
let last_t = 0;//前の参加した仕事の終了時刻

for (let i = 0; i < n; i++) {
  const [s, t] = works[i];//時刻 s_i から始まり、t_i に終わり
  if (last_t < s) { //ある仕事が終わる時刻より、始まる時刻が遅ければ
    ans++;//参加できる
    last_t = t;//参加した仕事の終了時刻を更新
  }
}

console.log(ans);
```
enPiT BizSysD分野のワークショップに行ってきました


授業の関係で、先日盛岡で開催された enPiT BizSysD分野のワークショップに参加させていただきました。この記事はその体験記になります。

## 参加したよ

ワークショップは2023年2月21日。大学の出張という名目で向かったのは岩手県立大学アイーナキャンパスで行われました。全国のBizSysD連携校代表14チームのうちの一つ「判断が遅い！ズ（仮）」のPOとして参加しました。

ここだけの話チームメンバー４人が対面で会うのは今回が初めてでした。出張代を出してくれた方本当にありがとうございました！

ポスターセッションを行ったり合間でプレゼンテーションを教員の前で行いながら楽しいひと時を過ごしました。

## 気づいたことたち

同じBizSysD分野の授業を受けつつも全く交流がなかった大学の人々と関わることができとても刺激的でした。特に以下の2点が興味深かったです。

### 進め方はかなり異なるものの、大事だと学んだことは似ている

本当に同じBizSysD分野だったのかと疑うほど各大学での取り組みは異なっていました。実際の開発期間や手法についても、週2回3時間の授業内の大学もあれば、授業として明確に定めない大学もありました。
そのため開発の工夫についても「全員でモブプロを行う」「機能ごとに分担して実装する」など正反対の工夫を行っていることも珍しくありませんでした。

一方、チーム開発を通して大事だと学んだことはとても似ていました。セッションの最後でお互いの学びを共有する時間があり、どのチームも口を揃えて認識をあわせる難しさについて言及していました。それが顧客との認識合わせであればレビューの難しさであったり、日程の認識合わせであれば進捗管理の難しさであったりするのかなと感じました。

### プロダクトの多様性

作ったプロダクトも全く違いました。
アプリの種類としても、モバイルアプリやWebアプリ、中にはIoTを利用しているチームもありました。

またプロダクトを通して外部の企業や自治体と連携をしているチームも見受けられました。授業の一環でやり取りを行ったり、中には自ら企業を尋ねるチームもいたり、とても刺激的でした。またそうした外部のステークホールダーが絡むことでプロダクトの完成度や要望も視点が全然違うものが得られているように感じとても興味深かったです。

## 総じて

何より北は北海道、南は沖縄に至るまで全国の同世代と対面でお互いのプロダクトについて話せたことはとても良い経験となりました！本当にありがとうございました！！
AWSのクロスアカウント（別アカウントリソースへのアクセス）の方法

## この記事に書いてあること
AWSでとあるアカウントで作ったリソースに別アカウントのユーザからアクセスする方法です。  
リソースAを所有するアカウントをアカウントA、リソースAにアクセスしたいアカウントをアカウントBとします。  

## 用語の理解
|用語|意味|
|:--|:--|
|アカウント|AWSの請求単位|
|IAMユーザ|AWSアカウント内のアイデンティティ。パスワードやアクセスキーにより認証される。|
|IAMユーザグループ|ユーザの集団を定義。グループに対してログインはできない。|
|ロール|リソースに１つだけ結び付けられるポリシーのグループ|
|ポリシー|各リソースに対するアクションの許可・拒否のルール|

関係はこんな感じでしょうか。
```
アカウント-1---n-ユーザ-n---n-グループ
リソース-n---1-ロール-1---n-ポリシー
```

## 事前準備
1. AWSにアカウントAを作成　→　アカウントIDをメモ  
2. アカウントAでリソースAを作成  
3. AWSにアカウントBを作成  →　アカウントIDをメモ

## アカウントBからリソースAへアクセスするためのロールを作成
1. アカウントAにサインイン
1. サービス > Identity Access Management(IAM) を選択
1. アクセス管理 > ロール を選択
1. ロールを作成
  4.1.信頼されたエンティティタイプで「AWSアカウント」を選択
  4.2.AWSアカウントで「別のAWSアカウント」を選択
  4.3.アカウントIDに【アカウントBのアカウントID】を入力して「次へ」
  4.4.リソースへのアクセス許可ポリシー（例：Lambdaであれば「AWSLambda_FullAccess」）を追加して「次へ」
  4.5.ロール名を入力して「ロールを作成」
1. 作成したロールのARNをメモ

## リソースAにアクセスするIAMユーザの作成
1. AccountBでマネージドコンソールにサインイン
1. サービス > Identity Access Management(IAM) を選択
1. アクセス管理 > ユーザ を選択
1. 「ユーザーを追加」
  4.1. ユーザ名（例：UserB）を入力して「次へ」
  4.2. 許可のオプションで「ポリシーを直接アタッチする」 を選択
  4.3. ポリシーの作成 > サービス「sts」, アクション「書き込みのAssumeRole」, リソースは指定で【先程メモしたロールのARN】
  4.4. タグを追加はそのままで「次のステップ：確認」 > 名前をつけて「ポリシーの作成」
  4.5. 作成したポリシーをアタッチ  

## UserBでリソースAにアクセス
1. AccountBのUserBでマネージドコンソールにサインイン
1. 画面右上のアカウント名 > 「ロールの切り替え」（ > 初回はもう一度「ロールの切り替え」）
1. アカウントに【アカウントAのアカウントID】、ロールに【アカウントAで作成したロール名】を入力。表示名は任意。 > ロールの切り替え

以上です。
AWSのリソースへのアクセス制御の概念を学ぶ良い機会でした。
paizaラーニング レベルアップ問題集 paizaの森練習問題コンテスト過去問題8 JavaScript OPS - その 2

OPS - その 2 (paizaランク C 相当)

https://paiza.jp/works/mondai/forest_contest_008/forest_contest_008__OPS2

# 解答例
```javascript
const fs = require("fs");
const input = fs.readFileSync("/dev/stdin", "utf-8").trim();
const lines = input.split("\n");

const n = Number(lines[0]);
//OPS 「出塁率と長打率を足し合わせた値」
const OPS = lines.slice(1).map(line => line.split(" ").map(Number).reduce((a, b) => a + b));
//最も高いOPS
const max = OPS.reduce((a, b) => Math.max(a, b));
//同率トップがいた場合は番号の早い方を出力
console.log(OPS.indexOf(max) + 1);
```
Python演習問題_カードゲーム編②　【Baccarat（バカラ）問題編】

# はじめに
## Baccaratはどんなゲーム？？？
Baccarat（バカラ）は『運』のゲームとして世界中で高い人気を誇ります。
バカラは優雅なゲームとして知られており、特に大金を賭ける人やアジア人プレーヤーに愛されているゲームです。実は、カジノのテーブルゲームの中で日本人に人気No.1のカジノゲームでもあります。
ルールは少し複雑ですが、プレーヤーとバンカー、どちらが勝利するかというシンプルなものです。
ではルールの詳細を見てみましょう！

## ルール
### バカラの勝敗の決め方
バカラを簡単に説明すると、参加者であるあなたが、「Banker」と「player」の勝敗または引き分けの「TIE」を予想するゲームです。
勝敗の決め方としては、2～3枚あるカードの合計の下一桁が、9の範囲内で9に近いほうが勝ちで、自分で何かを操作することはありません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2915564/c10af0ea-6052-58ca-0ee8-b7b1c8b44f97.png)

### 進め方
参加する人は、「バンカー」・「プレーヤー」・「タイ(引き分け)」のどこかにかけるのがゲームです。
・A～9までは、数字通りにカウント。10～Kまでは、すべて「0」とカウント。
・２or３枚の合計値の１の位をみる。その１の位が大きいのはどちらかで、バンカーとプレーヤーの勝敗を決める。
・バンカー・プレーヤーで配られたカードの合計（１の位のみ）が8または9の場合は```ナチュラル・ウイン```として勝ちとなる。どちらもナチュラル・ウインの場合は値が高い方が勝利となる
例）バンカー８とプレーヤー９だと、プレーヤーの勝利
・プレーヤーがカードをひかないのは２枚のカードの合計が6か7の場合。
　０〜５の場合はプレーヤーはもう一枚引くことになる。

もう一枚引くかどうかは…。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2915564/c00e01bf-176c-9ac7-5365-3d97d96df094.png)

３枚目が配布される場合は、バンカーの配布された2枚の合計と、3枚目に配布されたプレーヤーのカードの目によって引くか引かないかが決まる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2915564/7174efac-5927-8bff-862a-b6810895ad25.png)

## 【まとめ】
1. ゲームの流れ
    1. プレーヤー・バンカーの順番で２枚ずつ交互に配布
    1. プレーヤーの合計(１の位のみ)がどれに当てはまるかを見て２枚または３枚のプレーヤーの値を決める。
　　０～５　もう一枚引く　/　６・７　もう引かない　/　８・９　勝利　
1. プレーヤーが２枚目で終了の場合、
　　バンカーが、０～５の場合はバンカーにもう一枚引く。
1. プレーヤーが３枚目で終了の場合、
　　バンカー０～２	バンカーがもう一枚引いて合計を出す。
　　バンカー３		プレーヤーの３枚目が０～７のときはもう一枚引く。
　　バンカー４		プレーヤーの３枚目が２～７のときはもう一枚引く。
　　バンカー５　 	プレーヤーの３枚目が４～７のときはもう一枚引く。
　　バンカー６		プレーヤーの３枚目が６・７のときはもう一枚引く。
　　バンカーの手を確定して勝敗を決める。


## オマケ 　
ゲームの勝率
バンカー	45.86％　　／　　プレイヤー	44.62％　　／　　タイ（引き分け）	9.52％


## 処理条件

1. 掛けるもの（「バンカー」・「プレーヤー」・「タイ」）、価格を選ぶ。
1. カードが配布される（２枚ずつ）
1. ルールに従って３枚目を配布（ナチュラル８・９の場合はなし）
1. 勝敗がわかり配当がもらえる。
1. 制作に関して
    - カードクラスを用意すること。
    - 同様の処理が多いので関数をできる限り用いること。
    - 200行前後で制作すること。




以上を用いて、コンソールで動くBaccaratを作成してみよう！！
paizaラーニング レベルアップ問題集 paizaの森練習問題コンテスト過去問題8 JavaScript 乗客人数 - その 2

乗客人数 - その 2 (paizaランク C 相当)

https://paiza.jp/works/mondai/forest_contest_008/forest_contest_008__passenger2

# 解答例

```javascript
const fs = require("fs");
const input = fs.readFileSync("/dev/stdin", "utf-8").trim();
const lines = input.split("\n");

const n = Number(lines[0]);
const a = lines[1].split(" ").map(Number);//降りる人
const b = lines[2].split(" ").map(Number);//乗る人

let max = 0;//最大乗車人数
let bus = 0;//バスの乗車人数
for (let i = 0; i < n; i++) {　//i番目のバス停
  bus -= a[i];//降りる
  bus += b[i];//乗る
  max = Math.max(max, bus);//最大更新
}
console.log(max);
```
ActiveStorageついて

# 初めに
Rails使いの皆さん、こんばんは！
ActiveStorageってご存じですか？？
簡単に説明すると、
Railsで画像の投稿や表示を行うための物です。
画像は通常のカラムとして保存できないので、特別な保存方法が必要です。
それを行うのがActiveStorageです。

早速学んでいきましょうか！


# ActiveStorage導入の流れ

ActiveStorageをインストールします。ターミナルにこちらを入力
```
rails active_storage:install
```
そうすると、db/migrateディレクトリ内に
ActiveStorageのマイグレーションファイルが追加されます。

その次に
以下のコマンドをターミナルに書き込みます。
```
rails db:migrate
```


これで導入完成です！


# 終わりに
今回はActiveStorageについて学びました。
今後も、理解を深めるためにガンガン投稿していきます！
paizaラーニング レベルアップ問題集 paizaの森練習問題コンテスト過去問題8 JavaScript 通貨レート

通貨レート (paizaランク C 相当)

https://paiza.jp/works/mondai/forest_contest_008/forest_contest_008__currency_rate

# 解答例
買う日と売る日で全探索する。売る日は買う日より必ず後になる。
利益＝売値ー買値を計算し、最大利益を超えたら、買う日と売る日を記録する。
利益が出たら、買う日と売る日を出力、出なかったら、Noを出力する。

```javascript
const fs = require("fs");
const input = fs.readFileSync("/dev/stdin", "utf-8").trim();
const lines = input.split("\n");

const n = Number(lines[0]);

let buyDay = 0, sellDay = 0, profitMax = 0;//買う日、売る日、最大利益
//買う日buyと売る日sellで全探索
for (let buy = 1; buy < n; buy++) {　//買う日は1~n-1
  for (let sell = buy + 1; sell <= n; sell++) {　//売る日は買う日+1~n
    const buyPrice = Number(lines[buy]); //買値
    const sellPrice = Number(lines[sell]); //売値
    const profit = sellPrice - buyPrice; //利益

    if (profit > profitMax) {　//利益が最大更新してたら
      profitMax = profit; //利益更新
      [buyDay, sellDay] = [buy, sell];//買う日売る日更新
    }
  }
}
//利益が出たら買う日売る日、出なかったらNoを出力
console.log(profitMax > 0 ? [buyDay, sellDay].join("\n") : "No");
```
Laravel – storageに保存したファイルのURLの公開

以下階層に画像ファイルなど配置
```
"storage/app/public"
```

公開領域にシンボリックリンクstorageが作成
"public"ディレクトリにある"storage"ディレクトリにアクセスしたら、"storage/app/public"ディレクトリへアクセスできるようなショートカットを貼る
```php
php artisan storage:link
```
配置場所
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592268/29615468-5f4b-666a-be9e-151549318fef.png)

公開となる場所。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/592268/46741f99-fece-839e-37ee-92157d617799.png)
PythonでPDFテキストを抽出して、クリップボードにコピーする

# PDFの表データをコピーしたい
Excelに張り付けても残念な風になってしまう。

不完全ではあるが、表として取り出せるようになりつつあるので、忘れないうちにメモしとく
tabulaというライブラリを使う。裏ではJavaアプリみたい。

ざっくりいうと
引数でPDFファイル名与えて動かして成功したら
~クリップボードにTSVデータが自動的？（強制的）に保存されてるので、Excel開いて何も考えずCtrl-V~
標準出力に出すようにした。（Tkだとちょっと怪しかったため）

複数PDFファイルを一気に読み込ました場合は
--- ファイル名 ---
というセンテンス区切りな感じで全部まとめて
クリップボードへ入る的な、、

本当にどうしようもないデータは改行とかスペースが入っちゃうけど、もう限界

```python
import sys
import re
import tabula
from io import StringIO

def unicode_escape(x):
    return x.encode().decode("unicode_escape")

def load(f, sep="\t"):
    dfs = tabula.read_pdf(f, lattice=True, pages="all", silent=True)
    sio = StringIO()
    cnt = 0

    for df in dfs:
        df = df[df.notnull().any(axis=1)]
        is_head = df.columns[0] != "Unnamed: 0"
        if df.size > 0:
            df.to_csv(sio, index=False, header=is_head, sep=sep)
        elif is_head:
            print(sep.join(df.columns), file=sio)
        elif cnt < 2:
            print(file=sio)
            cnt += 1

    print(re.sub("\r?\n", "\n", sio.getvalue()))
    return sio.tell()

def main():
    from argparse import ArgumentParser
    ps = ArgumentParser(prog="info",
                        description="pdf to text\n")
    padd = ps.add_argument

    padd("files",
         metavar="<files>",
         nargs="+", default=[],
         help="pdf file path")

    padd('-s', '--sep', type=unicode_escape, default="\t",
         help='output separater (default `\\t`)')

    args = ps.parse_args()
    done = True
    kw = dict(sep=args.sep)
    if len(args.files) == 1:
        done = load(args.files[0], **kw)
    else:
        print(f"-- {args.files[0]} --\n")
        for f in args.files:
            print(f"\n\n-- {f} --\n")
            done += load(f, **kw) and done

    if done:
        print("Success! Saved Clipboard from Pdf Text.", file=sys.stderr)
    else:
        print("Failed? Nothing text..", file=sys.stderr)


if __name__ == "__main__":
    main()

```

オープンデータをPDFでドヤ顔公開するイカれた政府のおかげで生まれました。
草莽Erlang ── 43. lists:concat



口で言うより行うことがErlang習得への近道と信じています。

https://qiita.com/mnishiguchi/items/9237780e849d80a85e11

## lists:concat/1

```erlang
concat([atom | integer | float | string]) -> string
concat(リスト) -> 「テキスト表現」が連結された文字列
```

[lists:concat/1](https://www.erlang.org/doc/man/lists.html#concat-1)は各リスト要素の「テキスト表現」を連結します。リスト要素は、アトム、整数、浮動小数点数、文字列のいずれかである必要があります。

```erlang
> lists:concat([1, 2, 3]).
"123"

> lists:concat(["1", 2, '3']).
"123"

% 浮動小数点数には使いにくいかも？
> lists:concat([123.0, " USD"]).
"1.23000000000000000000e+02 USD"
```

[listsモジュール](https://www.erlang.org/doc/man/lists.html)には他にもリスト処理のための関数がたくさんあります。

https://www.erlang.org/doc/man/lists.html

## Elixirにも挑戦したい

闘魂ElixirシリーズとElixir Schoolがオススメです。

https://qiita.com/torifukukaiou/items/3b65e5c04fa8c55f526e

https://elixirschool.com/ja

https://qiita.com/piacerex/items/09876caa1e17169ec5e1
Typescript + Vue + BalmUI による Chrome拡張機能開発

# Typescript + Vue + BalmUIでChrome拡張の見た目をモダンにしたかったので備忘録。
TS + Vueのテンプレート作成は以下を利用して作成
[guocaoyi/create\-chrome\-ext](https://github.com/guocaoyi/create-chrome-ext)
READMEに従う。

プロジェクトの作成
```bash
npm create chrome-ext
```
使うフレームワークを問われるので vue を選択。
Languageを問われたら ts を選択。

---
本題のBalmUIのインストール
※Vuetifyを使いたかったけどよくわからなかった・・(TS+Vue+Vuetifyの拡張機能雛形の作り方求む)

BalmUIのインストール
`npm install balm-ui --save`

BalmUIのインポート
```index.ts
import { createApp } from 'vue'
import App from './Options.vue'
import "balm-ui/dist/balm-ui.css";
import BalmUI from "balm-ui";
import BalmUIPlus from "balm-ui/dist/balm-ui-plus";
import './style.css'

createApp(App)
  .use(BalmUI)
  .use(BalmUIPlus)
  .mount("#app");
```

表示
```options.vue
<script setup lang="ts">
import { ref } from 'vue'
const crx = ref('create-chrome-ext')
</script>

<template>
  <main>
    <h3>Options Page!</h3>
    <ui-textfield input-type="textarea" rows="8" cols="40">
      ここにテキストが入れられる
    </ui-textfield>
    <h6>v 1.0.0</h6>
  </main>
</template>

<style>
main {
  text-align: center;
  padding: 1em;
  margin: 0 auto;
}

h3 {
  color: #42b983;
  text-transform: uppercase;
  font-size: 1.5rem;
  font-weight: 200;
  line-height: 1.2rem;
  margin: 2rem auto;
}

h6 {
  font-size: 0.5rem;
  color: #999999;
  margin: 0.5rem;
}

a {
  font-size: 0.5rem;
  margin: 0.5rem;
  color: #cccccc;
  text-decoration: none;
}

@media (min-width: 480px) {
  h3 {
    max-width: none;
  }
}

@media (prefers-color-scheme: light) {
  a:hover {
    color: #747bff;
  }

  h6 {
    color: #333333;
  }
}
</style>
```

結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/263877/9163c8ad-8c07-49fa-d251-2d7056920889.png)

QuickStartがわかりやすくて良かったです.

# 参考
https://qiita.com/sengoku/items/8f5313214c1159bfe660
Azure Remote Rendering Showcase App で コンパイルエラー: Exception: IL2CPP error for method 'System.Void POpusCodec.OpusDecoderAsync が発生した際の回避策

Azure Remote Rendering の Showcase App を試そうと、公式 GitHub リポジトリからソースコードを Clone して試していたんですが、Unity Editor でビルドを実行すると、以下のコンパイルエラーが発生しました。

# エラー内容

```
Exception: IL2CPP error for method 'System.Void POpusCodec.OpusDecoderAsync`1::DataCallbackStatic(System.IntPtr,System.IntPtr,System.Int32,System.Boolean)' in C:\Users\horio\src\tutorials\azure-remote-rendering\Unity\Showcase\App\Assets\Photon\PhotonVoice\PhotonVoiceApi\Core\POpusCodec\OpusDecoder.cs:154
System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values.
```

コンパイルエラーの発生箇所。

``Assets\Photon\PhotonVoice\PhotonVoiceApi\Core\POpusCodec\OpusDecoder.cs:154``

Photon Voice SDK 内の OpusDecoder.cs 内の 154 行目

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180432/4c262707-6fb7-5b5d-2644-dc1153b299f0.png)

Photon Voice 2 の公式ページの Known Issues を見ても、  
エラー内容は載ってないようでした。

そこで Azure Remote Rendering の公式リポジトリの Issue を確認すると、
19時間前に Close したばかりの Issue を発見しました。

- [Failing to compile Showcase app #93](https://github.com/Azure/azure-remote-rendering/issues/93)

# 解決策
解決策は、エラーの該当メソッドをコメントアウトすることです。  
今回のコンパイルエラーの原因は Azure Remote Rendering SDK 側ではなく、  
Photon Voice SDK 内のソースコードが原因なので、回避策としてはこれくらいしかないとのこと。

以下、2つの Photon Voice スクリプトのファイルを修正します。

Assets\Photon\PhotonVoice\PhotonVoiceApi\Core\POpusCodec\OpusDecoder.cs

```Showcase\App\Assets\Photon\PhotonVoice\PhotonVoiceApi\Core\POpusCodec\OpusDecoder.cs
//[AOT.MonoPInvokeCallbackAttribute(typeof(Action<IntPtr, IntPtr, int, bool>))]
static public void DataCallbackStatic(IntPtr handle, IntPtr p, int count, bool endOfStream)
{
	//if (handles.TryGetValue(handle, out var obj))
	//{
	//    obj.dataCallback(p, count, endOfStream);
	//}
}
```

Assets\Photon\PhotonVoice\PhotonVoiceApi\Core\POpusCodec\OpusEncoder.cs

```Showcase\App\Assets\Photon\PhotonVoice\PhotonVoiceApi\Core\POpusCodec\OpusEncoder.cs
//[AOT.MonoPInvokeCallbackAttribute(typeof(Action<IntPtr, IntPtr, int>))]
static public void DataCallbackStatic(IntPtr handle, IntPtr p, int count)
{
	//if (handles.TryGetValue(handle, out var obj))
	//{
	//    obj.dataCallback(p, count);
	//}
}
```

修正後、Unity Editor でビルドを実行すると、  
エラーは発生せずにビルドが成功しました👏
【Jinja】Includeブロック内で変数を展開する

# Goal

- JinjaのIncludeブロックで指定するファイル名を変数で指定する

Includeブロック内では、Jinjaの構文では変数が展開されず、文字列として認識されてしまう。

```html
<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="utf-8">
    </head>
    <body>
        {% include "{{ variable }}" %} <!-- これだと Template not found error となってしまう-->
  </body>
</html>
```


# Environment

- Jinja 3.1.2

# Resolve

Jinja2 2.7.1 以降では、下記で展開可能。

```html
<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="utf-8">
    </head>
    <body>
        {% include "%s" % variable %}
        {% include "/files/%s" % variable %}
  </body>
</html>
```

Jinja2 2.7.1 以前でも、理論上は下記で回避可能。

```html
<!DOCTYPE html>
<html lang="ja">
    <head>
        <meta charset="utf-8">
    </head>
    <body>
        {% include "templates/case/"+variable+"/intro.html" %}
        {% include "/files/"+cid %}
  </body>
</html>
```

# Reference

https://stackoverflow.com/questions/12233971/using-include-to-dynamically-point-to-html
草莽Erlang ── 42. lists:join

口で言うより行うことがErlang習得への近道と信じています。

https://qiita.com/mnishiguchi/items/9237780e849d80a85e11

## lists:join/2

```erlang
join(term, [term]) -> [term]
join(挿入したい値, リスト) -> 新しいリスト
```

[lists:join/2](https://www.erlang.org/doc/man/lists.html#join-2)はリストの各要素の間に指定された値を挿入します。

```erlang
> [1,0,2,0,3] = lists:join(0, [1, 2, 3]).

> [1] = lists:join(0, [1]).

> [] = lists:join(0, []).
```

Erlangの文字列はリストですので、要素が全て文字列の場合、文字列の連結することになります。

```erlang
> Kakegoe = ["1", "、", "2", "、", "3", "、", "ダー"] =
>   lists:join("、", ["1", "2", "3", "ダー"]).
["1",[12289],"2",[12289],"3",[12289],[12480,12540]]

> io:put_chars([Kakegoe, $\n]).
1、2、3、ダー
ok
```

[listsモジュール](https://www.erlang.org/doc/man/lists.html)には他にもリスト処理のための関数がたくさんあります。

https://www.erlang.org/doc/man/lists.html

## Elixirにも挑戦したい

闘魂ElixirシリーズとElixir Schoolがオススメです。

https://qiita.com/torifukukaiou/items/3b65e5c04fa8c55f526e

https://elixirschool.com/ja

https://qiita.com/piacerex/items/09876caa1e17169ec5e1
PythonでのAPIの叩き方

#  初めに

PythonでAPIを叩く際に, HeaderやBodyの指定の仕方でハマった記憶があり、知識の整理も兼ねて, 

- Headerの指定方法
- Bodyの指定方法

について整理します。

基本的にAPIを叩く際には、Headerで認証がおり、Bodyでパラメータを指定してAPIを叩く形式が基本です。

叩くAPIによって若干HeaderやBodyの作成方法が異なるかもしれませんが、筆者が最近使用した事例ベースを一般化させた形式で記述します。

# Sampleコード

```python
# import module
import requests

# アクセストークンの定義
token = hogehoge

#Headerの作成
headers = {
        'Content-Type' : 'application/json',
        'Authorization': 'Bearer {}'.format(token),
        }

# bodyの作成
body = {
         "param1": hogehoge,
         "param2": hogehoge,
         "param3": hogehoge,
         "param4": hogehoge,
         }
     
# URLの定義
url = 'https://hogehoge.com'

# getメソットでAPIを叩く
res = requests.get(
            url = url,
            json = body,
            headers = headers,
            )
```

# 各コードの説明

#### Headerの作成について

```python
# アクセストークンの定義
token = hogehoge

#Headerの作成
headers = {
        'Content-Type' : 'application/json',
        'Authorization': 'Bearer {}'.format(token),
        }
```

上記コードがHeaderの作成コードになります。
Headerとは主にAPIを叩く際に、クライアント(ユーザー)を認証するために必要になるものです。

作成の仕方については、仕様書に従うとしか言えないのですが、Content-Type, AuthorizationについてがどのAPIでも求められるが基本です。
形式はjsonの形式で指定します。

#### bodyの作成方法について
```python
# bodyの作成
body = {
         "param1": hogehoge,
         "param2": hogehoge,
         "param3": hogehoge,
         "param4": hogehoge,
         }
```

URLでbodyを指定する方法もありますが、そちらについては別記事を参照ください。
bodyを作成するのは極めて簡単です。json形式で各パラメータを指定するだけで良いためです。
ただ、私がハマったポイントとしては、bodyの指定の仕方です。
headerはheaders = で指定するのに, bodyはjson= で指定する点です。

筆者は最初にbody = bodyと指定していて、ずっとエラーが返ってきていました。

```python
# getメソットでAPIを叩く
res = requests.get(
            url = url,
            json = body,
            headers = headers,
            )
```

以上がpythonでのAPIの叩き方になります。
[備忘録]システム開発の流れの把握とプロジェクトに参画して感じたこと

### はじめに

###### V字モデルとはシステム開発の工程を図式化したものですが、当時の実務未経験者の立場では、言葉からイメージはできても、実際に何をしているか理解できていませんでした。今回は、実際に少しの開発経験と少しのテスト経験を経て感じたことや重要だと思ったことを殴り書きしていきます。


下記画像は、V字モデルを元に当方で作成したものになります。（フリー画像としてお使いください。）
![スクリーンショット 0005-02-28 21.04.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1263502/3ca70fef-7e75-4013-d5e6-763b80674576.png)

V字モデルでは、上記の画像のように左側の工程が←→繋いでいる右側の工程が対応している図となっています。

## 工程概要とプロジェクトに参画して感じたこと

[V字モデルはシステム開発の基本！概要やメリットを解説](https://kaopiz.com/ja-news-system-development-v-model-advantages/#2)を参考に記載しております。

##### 要件定義とシステムテスト
>V字モデルでは最初に要件定義を行います。
要件定義では、どのような仕様にするか、必要な機能は何かを洗い出す作業です。
開発内容をより明確にし、開発計画を立てやすくする大切な工程のため、きっちり行いましょう。
要件定義に対応するテストは、V字の最後に位置するシステムテストです。
システムテストは総合テストとも呼ばれ、要件定義の内容に沿った開発ができているかをチェックします。
機能的な要件はもちろん、運用やセキュリティなどの機能以外の部分もチェックし、プログラム全体でおかしいところがないかを総合的に確認する段階になります。

上記のように記載されています。

要件定義で重要なのが、お客様の要望を全て実現してしまうのは単なる要求であり、要件定義では本当に必要な要件のみの開発をお客様と合意した上で定義している必要があります。

例えば、お客様に「本当にこの機能は必要ですか？」と質問した際に、「どちらかと言えば欲しい」というような返答の場合は、必要ではない可能性が大きいと考えられます。

開発には膨大なコストと時間を要するため、流行るサービス・売れる製品なのか分からない段階で充実した機能を盛り込むのはリスクを伴います。経験豊富な先輩からのアドバイスと個人的な意見ですが、できるだけシンプルかつ最小限で開発を進めていくのが良いと考えています。

##### 基本設計と結合テスト
>基本設計とは、要件定義の内容を実際の機能に落とし込む作業です。
具体的には、画面に表示する内容やレイアウト、画面遷移などを決めていきます。
ただし、スピード感を重視するアジャイル開発を行っている場合は詳細な設計書を作成せず、作成したらすぐに動作テストという形で開発を進める場合もあります。
基本設計はいくつかのプログラムが組み合わさっている場合が多いため、結合テストでは複数のプログラムが「結合」していても基本設計通りに動くかどうかをテストします。

当方では基本設計には関わったことがありませんが、以前に結合テストの工程に関わったことがあります。その中で特に強く感じていたことは、基本設計時に作成される成果物である設計書の重要性です。

テスト設計書を作成するには、そのテスト結果が正しいと言える**根拠**が必要です。根拠の元となる設計書が作成されない段階で開発が進み結合テストとなると、テスト仕様書の作成時に**根拠**となる資料がなく、設計書の作成を待つ時間コストや曖昧な根拠を元にテストをしてしまい製品の品質を担保することができなくなってしまいます。

そのため、個人的な意見ですが、プロジェクトに入った際に設計書がない場合は、どのロールの人物でも早めに設計書作りを周りに呼びかけることが良いと考えています。

##### 詳細設計と単体テスト

>詳細設計では、基本設計で明確にした情報や機能を達成するために、どのようなプログラムを書けばよいか決定します。
単体テストは、詳細設計で決めた各プログラムがきちんと動作をするか、文字通り単体で確認するテストです。
操作方法や条件など考えられるパターンをできる限り数多くシミュレーションして、ロジック通りに作動するか否かを確認します。

この工程については、当方の経験が無くあまり言えることがないのですが、詳細設計と単体テストがしっかり成されていることで、結合テストでのバグは圧倒的に減るものであると感じております。

つまりは、詳細設計で機能の処理や動作、エラーハンドリングなどについて細かく考えられていると、単体テストで抜け漏れが少なくなり、結合テスト時には結合の観点でテストを実行できるからです。

当たり前のことを言っているかと思われますが、プロジェクトによっては単体テストが実施されておらず、結合テスト時に単体レベルのバグが見つかることが多々ありました。経験談からしても、基本設計同様に詳細設計が十分になされていることがテスト工程を問題なく流せるコツだと感じております。

## まとめ
実際にプロジェクトに参画することでシステム開発の全体の流れを掴むことができ、それぞれの工程の重要性を少しずつ理解できるようになりました。まだまだ半人前の未熟者ですが、精進していきたいと思っています。開発経験の多い先輩方、厳しいご指摘の程よろしくお願い致します。

## 参考文献
この記事は以下の情報を参考にして作成しております。

- [V字モデルはシステム開発の基本！概要やメリットを解説
](https://kaopiz.com/ja-news-system-development-v-model-advantages/#2)
Elixir Livebook で地図にポイントと一緒にデータを描画出来ないものだろうか

# はじめに
位置と紐づいたデータをゴニョるのに、場所と一緒に文字データを表示したいのです。
そこで「Elixir Livebook で地図にポイントと一緒にデータを描画出来ないものだろうか」です。

# 実行環境
* Mac Ventura 13.1
* Livebook app

Livebookはデスクトップアプリを使ってます。

https://livebook.dev/


# ポイントを地図に描画する

過去1週間で起こった地震のデータらしい?ものを使って試してみたいと思います。

https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_week.geojson

セッティング。
```elixir
Mix.install([
  {:explorer, "~> 0.5"},
  {:geo, "~> 3.4"},
  {:kino, "~> 0.8"},
  {:kino_maplibre, "~> 0.1.3"},
  {:download, "~> 0.0.4"},
  {:jason, "~> 1.4"} # これがないとエラーになることがあるらしいです
])
```
エリアス設定。
```elixir
alias MapLibre, as: Ml
```

データを読み込んでGeoJSONデータにします。
```elixir
geo_json =
  "https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_week.geojson"
  |> HTTPoison.get!()
  |> Map.get(:body)
  |> Jason.decode!()
  |> Geo.JSON.decode!()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3657/80ee383c-2b39-4c3a-19e4-b23a5c6cb89a.png)

描画します。
```elixir
Ml.new(
  zoom: 5,
  style: :street,
  center: {-117.6981659, 35.873333, 9.22}
)
|> Ml.add_geo_source("data", geo_json)
|> Ml.add_layer(
  id: "stop",
  source: "data",
  type: :circle,
  paint: [circle_color: "#aa00ff", circle_radius: 5]
)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3657/35d8fc31-d4b7-21cd-919e-bccaaf0dc817.png)

# プロパティデータも一緒に描画する

さて、一体どうやるのでしょうか。
hexdocs見ても全くわかりません。

https://hexdocs.pm/maplibre/MapLibre.html

:symbolが「An icon or a text label」とあるのでこの線でググります。

https://dockyard.com/blog/2022/11/22/parsing-and-visualizing-sea-current-data-with-elixir-and-nx

いきなり高度すぎて咀嚼できない!

https://maplibre.org/maplibre-gl-js-docs/style-spec/layers/#paint-symbol-text-color

大元に行ってしまってElixirから遠い!

ググる力も最弱なのか、Elixir初心者に優しいものどころか、全く望むものにヒットしません。
仕方がないので色々とヒントにさせてもらいながらゴニョゴニョします。

その結果、プロパティの値を適当に引っ捕まえて表示できるようになりました。
```elixir
Ml.new(
  zoom: 4,
  style: :street,
  center: {141.154484, 39.702053}
)
|> Ml.add_geo_source("data", geo_json)
|> Ml.add_layer(
  id: "stop",
  source: "data",
  type: :circle,
  paint: [circle_color: "#aa00ff", circle_radius: 5]
)
|> Ml.add_layer_below_labels(
  id: "mag",
  type: :symbol,
  source: "data",
  layout: %{
    text_field: [:get, "mag"],
    text_offset: [0, 1.0],
    text_size: 12,
    text_font: ["Open Sans Bold"]
  },
  paint: [text_color: "#aa0055"]
)
|> Ml.add_layer_below_labels(
  id: "sig",
  type: :symbol,
  source: "data",
  layout: %{
    text_field: [:get, "sig"],
    text_offset: [0, -1.0],
    text_size: 12,
    text_font: ["Open Sans Bold"]
  },
  paint: [text_color: "#0033bf"]
)
|> Kino.MapLibre.new()
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3657/100bc663-84c7-75ca-6ffd-d64fa79ae91d.png)

これがしたかった!
と思ったけど、一つのレイアウトで複数のデータをフォーマットして描けないかな、と思いました。
どうやるのだろう。

# まとめ
Elixir Livebook でマップにプロパティの値も描画出来ました。
本当にこれでいいんだろうか?
外部のsshでGCPのVMインスタンスにアクセスできないときはメタデータを確認しよう！

GCPのインスタンスに外部のsshでアクセスしようとし、`Permission denied (publickey).`と出てしまう方は、本記事で解決するかもしれません！

## まとめ

OS Loginが有効になっている(`enable-oslogin`のメタデータが`TRUE`になっている)VMインスタンスに外部のsshでアクセスするためには、<a href="https://cloud.google.com/compute/docs/connect/add-ssh-keys?hl=ja#os-login">SSHの認証鍵をVMインスタンスに追加</a>する必要がある！

詳細はこちらです！→https://cloud.google.com/compute/docs/troubleshooting/troubleshooting-ssh?hl=ja#permission_denied_publickey
<br>
因みに私はこの問題を解決するために2時間かかりました()
`Permission denied (publickey).`だけじゃわからんて...
AWS認定クラウドプラクティショナー(CLF)を英語で受験してみた

## はじめに

![score_report.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2658776/f236bc7d-fb10-af96-50f5-db62d258ccdb.png)

2023年2月にAWSクラウドプラクティショナー(CLF)を英語で受験して合格することができたので、受験に至るまでの経緯と、どのように勉強をしたのかをまとめました。

## AWSクラウドプラクティショナー(CLF)を受験したモチベーション

(この記事を執筆した時点からみて)去年の10月に担当する案件が変わり、↓のような出来事がありました。

```txt
先輩: 「IAMのアカウント申請しといたからアカウントが払い出されたらコンソールにログインできるか確認して」
私: 「(アイアム....????この人はなんのことを言っているんだろうか...とりあえず返事をしておこう)はい!」

~~~~~ 数分後 ~~~~~

私: 「(さっき言ってたアイアムってなんことだったんだろう調べてみよ)」
私: 「...」
私: 「AWSのサービスのことだったのか!!」
私: 「(このままじゃまずい)」
```

この出来事を通して自分が直接AWSでのインフラ構築をする機会はなくとも、流石にAWSの主要なサービスくらいは知っておかないと"お話しにならない"ということを痛感したためAWSについて勉強することを決意しました。

私の職場ではAWS認定資格の取得を推奨していることもあり、どうせ勉強するなら客観的に結果が目にみえるAWS認定を受験しようと考えました。

社内ではAWSソリューションアーキテクトアソシエイト(SAA)の取得が主に推奨されていたため、初めはSAAについて調べていましたが、それよりも基礎的な内容が問われるAWSクラウドプラクティショナー(CLF)という試験があることを知り、まずはCLFから受験しようと決めました。

### 英語受験を選択したきっかけ

CLFの受験を決意してから数日後にQiitaで次の記事を読んだのがきっかけです。

https://qiita.com/tsuvic/items/c07e90bb0b300363c636#fn-3

それに加えてCLFは数あるAWS認定試験の中で一番難易度が易しいのでチャレンジするハードルが低かったのも一つの要因でした。

### 当時のスペック

参考までに当時の私のスペックを載せておきます。

- 実務経歴
  - アプリケーション開発経験が約2年
  - AWS関連の知識はなし
- 保有資格
  - FE/AP
  - DB
  - LPIC-001
  - 認定スクラムデベロッパー
- 英語力
  - 留学経験なし
  - 海外出張経験なし
  - TOEICは800点

## 勉強方法

試験勉強は主に[Udemy](https://www.udemy.com/)を中心に行いました。後で紹介する本やWebの問題集は補助的な役割として使っていました。
勉強した期間は大体2ヶ月くらいだったと思います(平日も休日も1時間程度)。

具体的にどのような教材を使ったのかを紹介します。

### Udemy

まずAWSの全体像を薄く理解したかったので、以下の講座を受講しました。
ハンズオン形式でAWSの主要なサービスの解説をしてくれるため、実際の使用方法をイメージしながら知識をインプットすることができます。

受験までに余裕がない場合や資格の取得に重きを置く場合はハンズオンは実施せずに2倍速で聞き流すだけでも良いかもsれません。

また、講座には日本語の模擬試験が2回分ついているので後で紹介する英語の模擬試験集に取り掛かる前の肩慣らしとして、そもそもどのような問題が問われるのかを確認することができます。

https://www.udemy.com/course/ok-aws-e/

日本語で全体像が理解できたらあとはひたすら英語の模擬試験をといていきます。
以下の講座は6回分の英語の模擬試験が収録されているので、これらのすべての試験で80%以上取れるようになるまでひたすらやりこみましょう。(大体3周くらい)

https://www.udemy.com/course/practice-exams-aws-certified-cloud-practitioner/

### 書籍

書籍は参考書として↓を購入しましたが、正直Udemyでの学習だけで事足りるので、動画講座より本が好きな人やUdemyだけだと不安な人のみ買ってみてください

https://www.amazon.co.jp/AWS%E8%AA%8D%E5%AE%9A%E8%B3%87%E6%A0%BC%E8%A9%A6%E9%A8%93%E3%83%86%E3%82%AD%E3%82%B9%E3%83%88-AWS%E8%AA%8D%E5%AE%9A-%E3%82%AF%E3%83%A9%E3%82%A6%E3%83%89%E3%83%97%E3%83%A9%E3%82%AF%E3%83%86%E3%82%A3%E3%82%B7%E3%83%A7%E3%83%8A%E3%83%BC-%E5%B1%B1%E4%B8%8B-%E5%85%89%E6%B4%8B/dp/4797397403

### Web問題集

先ほど紹介したUdemyの模擬試験はすべての問題を解き終わってからしか解答を確認できないので、ある程度まとまった時間を確保して取り組まないといけないので、隙間時間にやるのは難しいというデメリットがあります。

以下のサイトは1問ずつ解答を確認できるので通勤時などの微妙な時間に気軽にやることができますので、活用してみてください。(問題は日本語ですが)

https://aws-exam.net/clf/

## 受験してみて(感想)

実際に受験してみた感想としては「**英語受験でも案外いける**」です。

問題の難易度的には「Udemyの模擬試験>=本番>>web問題集」でした。
なので私が紹介した方法で学習を進めれば無理なく合格可能だと思います。

日本語受験よりは時間よりは勉強する時間が多くかかると思いますが、英語学習も一緒にできるので一石二鳥なので、是非チャレンジしてみてください。

また試験学習を通して、AWSの基本的なサービスについて知識をつけることができましたので、「AWSの勉強をしたいが何からすれば良いのかわからない」という方は日本語受験でも良いので是非CLFの受験を検討してみるのも良いアプローチかもしれません。
時計ICの時間合わせプログラム簡易型(DS1307)(Arduino UNO)


x 過去ログを見よ
x HHとMMを書き換えてタイミングよく実行


目的
なんとなく


https://qiita.com/caa45040/items/347a73b45f79bcc10fac

SSD1306_DS1307_TIME_SET_UNO_1

```c++



#include <Wire.h> //I2C library

#define ADDR    0x68  // 2進数 1101000

char    data_read[8]; //i2cバッファー

#define HH  12
#define MM  34

void setup()
{
  Wire.begin(); //uno

//i2c書き込み
  Wire.beginTransmission(ADDR);

  Wire.write((char) 0    ); //0 レジスターの位置は0
  Wire.write((char) 0    ); //1 秒
  Wire.write((char) ( MM /10)*16+( MM %10) ); //2 分
  Wire.write((char) ( HH /10)*16+( HH %10) ); //3 時

  Wire.write((char) 3    ); //4 曜日
  Wire.write((char) 1    ); //5 日
  Wire.write((char) 1    ); //6 月
  Wire.write((char) 0x20 ); //7 年

  Wire.endTransmission();

} //end setup

void loop()
{

} //loop



```
mysqlが一生文字化けしていたけど何とか解決した備忘録

# 経緯
WEBアプリが開発してみたい！そうだ、ToDoアプリを作ろう！！
そう思い立ちネットの海を徘徊し、Express+mysqlの環境を構築していてぽちぽちやってみていたのですが…
![キャプチャ1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2028933/b00a1430-db3d-b04e-b1ba-231f21b16fea.png)

なんか一生エラー吐くじゃんウケるぅ…。と半泣きになっていたのがやっと解決したのでメモ書き程度に置いておきます。

環境
・Windows
・mysql 5.7

スクショを取っていなかったので前半画像ないです。すみません。

# DBに登録をしようと日本語を入力しても反映されない。

色々試していたところ、半角英数字は問題なくDBに登録されていた様子。
エラーコードをぐぐってみたところ、やっぱりと言うか何と言うか、日本語の入力が一切受け付けられていなかったようです。

**原因：mysqlの文字コードが日本語非対応だったから。**

`C:\ProgramData\MySQL\MySQL Server 5.7`に格納されてる`my.ini`を編集。

```
[mysqldump]
default-character-set = utf8mb4

[mysqld]
character-set-server=utf8mb4
skip-character-set-client-handshake
default-storage-engine=INNODB
```

色々試したけれど、上記を追記してみたところ、エラーが消えました。

# 文字化け、襲来

日本語の入力をしてもエラーが出ない！やったー！と思ったのもつかの間…。
![キャプチャ2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2028933/7f8a09ea-5129-396f-2cb5-75fb16124120.png)


ばちくそに文字化けしとるやんけェ…。

何が起きているんだと調べたところ、DB側の文字コードとコマンドプロンプトの表示の文字コードが一致していない為に発生している模様。
なるほど確かに…そりゃ化けますね。

コマンドプロンプトの文字コードを確認します。
コマンド`chcp`を叩く。
![キャプチャ3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2028933/36840cfe-65cf-7c07-7441-7f865dfa490e.png)

932…って何？
![キャプチャ4.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2028933/e0e5564b-4ee7-fabf-d1ea-54046e665a49.png)

左上のウィンドウの枠のところで右クリック→プロパティの「現在のコードページ」で文字コードを確認出来ます。
![キャプチャ5.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2028933/3a5eec76-9ae8-1c97-9164-3bf635e28f9e.png)

現在のDB側の文字コードは「UTF-8」、対するコマンドプロンプト側は「Shift-JIS」
このずれが文字化けの原因なので、コマンドプロンプト側もUTF-8に揃えます。


コマンド`chcp 65001`を叩く。
![キャプチャ6.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2028933/e4b3b5b6-964e-7020-3001-51cf83faabbe.png)


文字コードがUTF-8になったことを確認。
![キャプチャ7.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2028933/7b369a8e-f43c-064e-5371-0e43bf1c74a9.png)



日本語がちゃんと日本語で表示されてるー！！！！
私の心の叫びが入力されていますね。

これにて一件落着。
私の備忘録代わりに置いておきます…。

参考URL：
https://dev83.com/mysql-insertinto-error/
https://motomotosukiyaki.com/cant-input-japanese-in-mysql

https://my-web-note.com/mysql-mariadb-japanese-garbled-text/
GrafanaでAzureAD認証を使用する


まだメモ書きです

1. Azure ADアプリケーションの作成
Azure PortalでAzure ADアプリケーションを作成します。作成時に、アプリケーションのタイプとして「Webアプリケーションとして登録する」を選択し、リダイレクトURIとしてGrafanaのログインページのURIを指定します。

1. Grafanaの設定ファイルを変更する
Grafanaの設定ファイル（grafana.ini）を編集し、以下のように設定を追加します。

```
[auth.azuread]
# name = Azure AD
enabled = true
# allow_sign_up = true
client_id = YOUR_CLIENT_ID
client_secret = YOUR_CLIENT_SECRET
scopes = openid email profile
auth_url = https://login.microsoftonline.com/YOUR_TENANT_ID/oauth2/authorize
token_url = https://login.microsoftonline.com/YOUR_TENANT_ID/oauth2/token
# api_url = https://graph.microsoft.com/v1.0
allowed_domains = yourdomain.com
```

client_idおよびclient_secretには、先ほど作成したAzure ADアプリケーションのクライアントIDとシークレットを指定します。auth_urlおよびtoken_urlには、Azure ADのOAuth2エンドポイントを指定します。allowed_domainsには、ログインを許可するドメインを指定します。

1. Grafanaを再起動する
設定ファイルを変更した後は、Grafanaを再起動します。

1. Azure ADでの認証を有効にする
最後に、GrafanaのWebインターフェースでAzure AD認証を有効にします。[サーバー]→[認証/承認]→[Azure AD]を選択し、Azure AD認証を有効にします。
巨大なベースイメージに差分があるときだけデプロイしたい、かも

ビジネスロジックを担うアプリより、ベースとなるDockerImageが巨大&ビルド時間が長い場合、[fetch & run構成](https://dev.classmethod.jp/articles/aws-eaws-ecs-fetch-run-shell/)をとることが結構ある。

これをデプロイCIに乗せる上で、Dockerfileなどの変更がないときはイメージのビルドは必要なし、という扱いにしたい。
Docker Imageのキャッシュも考えたが、キャッシュ保持期間や転送料金的な事情もあり今回は別のアプローチを思考実験するメモ。


- 1 . Dockerfile周辺の可視ファイルをzip化し、ハッシュ値をとる
- 2 . イメージのリポジトリ(今回はAWS ECR)にそのハッシュ値のタグがないか探す
- 3 . なければビルド&プッシュする

今回は変更頻度の高いアプリ本体は別でビルドするので、ハッシュ検出はあくまでベースイメージ周辺のファイル群だけでいいはず。無圧縮のzipを使う。



```Make

deploy-on-hash-notexist:
	@mkdir -p .build || true; \
	export TAG=$$(zip -rq -0 .build/data.zip ./ -x ".*" && shasum -a 256 .build/data.zip | cut -d ' ' -f 1) && \
	echo "$$TAG" && \
	if aws ecr describe-images --repository-name <リポジトリ名> --image-ids imageTag="$$TAG" > /dev/null 2>&1; then \
		echo "buildしない && deployしない"; \
	else \
		echo "build & deployする"; \
	fi


```

あくまでfetch & run構成だからできる差分検知ではある。

こういう差分で副作用起こしたいときのケース出しがめんどいから、みんな基本時間かかってもビルドキャッシュ愚直に使ったりbazelみたいなの使ったりするのかもしれない
WindowsTerminalにPowerShellを管理者実行で開くプロファイルを追加してみる（gsudo）

下記画像赤枠のように、Windows TerminalでPowerShellを管理者実行で起動するようなプロファイルの書き方について。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670622/f5f4e044-87f1-4ba0-143e-c9903793145f.png)

## 事前準備

本記事ではgsudoコマンドを利用するため、下記記事にあるように`gsudo`をインストールして下さい。

[gsudoコマンドをつかって、WindowsのPowerShell上でいい感じに管理者権限を利用する](https://qiita.com/SAITO_Keita/items/2974265ba03de7c3ca71)

## 設定

Windows Terminalの設定から新しいプロファイルのを追加しますを選択

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670622/d7b19a3b-e858-5ee7-85bd-97f7985bf79c.png)

今回は`PowerShell`を管理者実行で開くプロファイルを追加したいので、複製元に`PowerShell`を選択して複製を選択

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670622/b16a2d10-67f2-e0e0-5fe9-2fe183ae7289.png)

既存設定がコピーされました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670622/e5d0073c-fef7-6ff8-719d-ca63331c4018.png)

名前がコピーとなっているので、適当な名前をつけます。

コマンドラインは`"C:\Program Files\PowerShell\7\pwsh.exe"` となっていた部分を `gsudo "C:\Program Files\PowerShell\7\pwsh.exe"` とgsudo経由で起動するように変更。

名前とコマンドラインを変更したら、保存を選択

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670622/7aa47c8f-d5db-7285-7035-3a39a7fc8ceb.png)

設定を反映させるため、一度`windows Terminal`を終了します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670622/d3e9fcfe-1e5a-87f7-723d-33171c5533a0.png)

`Windows Terminal`を起動すると先程設定したプロファイルに従い、管理者実行の`PowreShell`起動が追加されています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670622/f5f4e044-87f1-4ba0-143e-c9903793145f.png)

このメニューから起動すると、`gsudo`経由でPowerShellが起動され管理者実行されたプロンプトが起動します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1670622/8fd40549-29b4-8f34-0812-83f7f532f635.png)

上記画像は、.NETの`WindowsPrincipal.IsInRole メソッド`で管理者実行されているのを確認した図。

## 総評

`gsudo`コマンドがあるので、既存のプロンプトを昇格することが多いかと思いますが。
管理者実行のPowerShellプロンプトをもう一枚開きたいといったケースの場合、便利かと思います。
zabbixでAzureAD認証を使うには

まだメモです

# 概要
ZabbixでAzure ADを使用してログイン認証を設定するには、以下の手順を実行する必要があります。

1. Azure ADにZabbixを追加する。
1. Zabbixサーバーで、OpenID Connect認証プロトコルを有効にする。
1. Zabbixの「authconfig.php」ファイルを編集して、Azure ADのテナントID、クライアントID、クライアントシークレット、およびテナントのドメイン名を追加します。
1. Zabbixの「nginx.conf」ファイルを編集して、Azure ADのOpenID Connectエンドポイントを追加します。
1. Zabbixを再起動して、Azure ADでログインできるようになります。

# OpenID有効にする
ZabbixサーバーでOpenID Connect認証プロトコルを有効にするには、以下の手順を実施する必要があります。

1. OpenID Connectプラグインをインストールするまず、ZabbixサーバーにOpenID Connectプラグインをインストールします。プラグインは、Zabbixの拡張機能として提供されています。
1. OpenID Connectプロバイダーの設定を行う
次に、OpenID Connectプロバイダーの設定を行います。Zabbixサーバーの設定ファイル（zabbix_server.conf）に、以下のように設定を追加します。
```
# OpenID Connect Provider URL
SSO_OIDC_URL=https://your-oidc-provider.com

# OpenID Connect client ID
SSO_OIDC_CLIENT_ID=your-client-id

# OpenID Connect client secret
SSO_OIDC_CLIENT_SECRET=your-client-secret
```

SSO_OIDC_URLには、OpenID ConnectプロバイダーのURLを指定します。SSO_OIDC_CLIENT_IDおよびSSO_OIDC_CLIENT_SECRETには、OpenID ConnectクライアントのIDおよびシークレットを指定します。

1. 認証プロトコルを有効にする
最後に、ZabbixのWebインターフェースでOpenID Connect認証プロトコルを有効にします。管理者ユーザーでログインし、[管理]→[認証]→[OpenID Connect]と進んで、OpenID Connect認証プロトコルを有効にします。
統計検定2級を振り返る

今後統計準1級に挑戦しようかなと考えた時に、
2級の内容がほぼ抜けてしまっていることに気づいたので、
2級を振り返るためにも、その時どのような学習をしていたかを記していく。

筆者の2級受験時の状況は、
・販売員（IT業界未経験）
・私立大学卒（食品系）
・ほぼ文系（数ⅠAと生物を受験に使った程度でⅡB、化学はわからない）
・統計は大学1年時に少しだけ授業取っていたが完全に内容忘れている
といった感じ。

受験に使っていないだけで高校の定期試験で微分・積分など必要だったので
雰囲気覚えている程度のなんちゃって理系、8割文系と捉えていただければと思う。

## なぜ受けようと思った？

当時販売員をしていた自分は、売り場のレイアウト担当をしていて、
どの売場でどの商品が売れているのか、という数字を見る機会が多かった。

そのときの気づきや仮説を試していく過程で、分析やマーケティングに興味を持った。

そんなときちょうどデータサイエンティスト、データアナリストという職があることを知り、
何か面白そうだし、未経験だけど挑戦してみようと決意。

その際に未経験でIT業界に挑戦するには何かしら実績や資格でアピールした方が
書類の通過率や面接でのウケも良さそうだし、最悪落ちても今の仕事の質を高められる
何かに挑戦してみよう！と考え、統計2級を受けることを決意。

## どのぐらいの期間勉強した？

詳しくは覚えていないが、統計の参考書を買ったのがamazonの履歴で8月下旬、
合格したのが11月上旬だったため、およそ2ヶ月半で合格した。

## 実際に取り組んだ学習内容

ここからは自分が実際に勉強した内容を振り返っていく。

・「よくわかる心理統計」を読む
統計学って結局どんなことやるんや？という感じだった（学生の時も授業あまり聞いていなかった）ので、概要をざっくりと掴むために読破。

・「ゼロから始める統計入門」、「マンガでわかる統計学　素朴な疑問からゆる〜く解説」を必要に応じて読む
本によって各用語の意味や、検定方法の説明に差があるので、うまく理解できない場合は
他の本を頼ってみる。全体感を掴むのは「よくわかる心理統計」だけで十分だが、
文字よりイラストの方がわかりやすかったり、同じ説明をされていても言い回しが違うだけで
理解度が変わってくるので、金銭的に余裕のある方はぜひ。

・統計WEBをひたすらやり込む
ここに一番時間をかけた。２級合格者のほとんどがこのサイトにお世話になっているはず。
微分・積分以外にも難しい計算が必要になるため、その都度調べて計算方法を確認していた。

統計WEBで問題を解く→よくわからなかったら各書籍を確認したりググる

をひたすら繰り返して内容を叩き込む。

・過去問を解く
ある程度統計WEBの内容を理解できたら、過去問を解いていく。
自分は一応4~5年分の過去問に取り組んだ。
多分応用力のある人は2年分でも合格できるかもだが、自分は自信がなかったので
とにかく量をこなした。

過去問を解いた後は、過去問の解説やネットの解説記事を読んで、どうしてその答えになるのか、
途中式がどうなっているか、自分は問題のグラフを見てこのように解釈したがこの見方は
合っているのか、などを確認した。

特に分散や期待値などの公式、変換などを理解しておくと試験の時に応用が効く。

これらを繰り返して過去問の内容を6~7割理解することを目指す。

・チートシートを確認
試験3日前ぐらいに確認した。
統計検定２級　チートシートなどで調べると結構出てくる。
ものによって自分の知らない公式が記載されているチートシートも出てくるが
あまり焦らず、こんなものもあるのか〜程度に見ておく。


以上が2級を受けるために自分が取り組んできた内容である。
これ以外にも書籍を購入したりしたが、あまり使わなかったので省く。
結論統計WEBと過去問さえやりこめば問題ないが、自分はほぼ文系かつ
自分に合った言葉で説明されないと理解できない人間だったので、
色々なサイトや書籍に手を出した。

## 試験当日

試験当日はとりあえず受けてみよう、過去問６割ぐらいしか理解できていないけど
なんとかなるやろ、という気持ちで挑んだ。

過去問はペーパー方式だったかもしれないが、
実際の試験はCBT方式だったため、かなり雰囲気が違い
そのおかげで合格できたところが大きい。

今までの過去問だと、
１問目の答えを２問目、３問目で活用することが多くその結果、
１問目がわからなければ総崩れ、ということがしばしばあり、
その結果自分も過去問で6~7割止まりとなっていた。

しかし、CBT方式では1つ1つ問題が独立していることが多く見られたため、
上記のようなやりづらさはあまり感じなかった。

また自分の計算結果が選択肢の中になかったとしても、
そこで慌てずに、もう一度計算をやり直してみる、
もしくは選択肢に自分の計算結果と近い値がないか確認する、
この2つを徹底した。

小数点をどこまで含んで計算するかで計算結果に多少の違いが出てくるので、
やり直しやそれに近いものを探すことは重要だと試験中に感じた。

あと自分はあまり人前で発言するのが得意ではないので、試験中に追加で計算用紙を
もらう行為が一番緊張したかもしれない。
大きな試験会場じゃなかったので本当によかった、他にたくさんの受験者がいたら
多分できなかった。

まとめると
・CBT方式は1問ずつ独立している傾向にある（前問の答えを次の問題で必要としない傾向）
・自分の計算と選択肢が合わなくても、それに近い値を選択する
・会場選びも割と重要
の3つが試験当日に感じたことである。



以上が自分の統計検定2級までの合格ロードマップである。
準1級に挑戦し受かったらまたそちらについても書きたい。
WASM基礎知識

## WASMとは何か

- Webブラウザで動作するプログラミング言語
    - HTML、CSS、JSに続く4つ目の言語
- 実行前にコンパイルが必要なバイナリフォーマット
    - さまざまな言語のソースコードを.wasmフォーマットにコンパイル可能
    - C、C++、Rust、PHP、Ruby、Pythonなど
    - これによりバックエンド言語のコードをブラウザで実行可能になる
- W3Cによって標準化された(2019)

## WASMバイナリ

- Ruby言語単体がコンパイルされたruby.wasmはCDNで提供されている

## WASMのメリット

- ネイティブ水準の高速でコードを実行できる
- 普通の機械語よりも安全
- 多くの言語を活用できる
- ブラウザで動作するため環境やOSを選ばず、ポータブル
- Openである
- OS上でも実行できる(WASI)
    - ホスト上で実行するWASMランタイム：Wasmtimeもリリースされている(2022)

## WASMのユースケース

- Google Meetのボカシ
- Figma
- ゲーム(Unity)
- Showcase
- Pydodide(PythonのREPL)
- Postgres WASM(PostgreSQLのREPL)
- Krustlet(KubernetesでWASMコンテナ)
- 既存アプリの移植
- Adobe Photoshop
- Google Earth
- AutoCAD

## WASMの問題点

- JSからWASMの呼び出しにかかるオーバーヘッド
- ファイルサイズの肥大化(ライブラリ・ランタイムが必要なため)

## WASM開発の背景

- AIやデータ分析などのトレンドによってブラウザ上でより高速な処理を必要とした
- asm.jsをさらに進化させた仕組みとしてWASMが出てきて、W3Cで標準化された
【JavaScript】配列の中の連想配列のデータを取得する。

## はじめに
今回は、配列内の連想配列のデータを取得する方法を書きます。
こちらのドキュメントを参考にしました。
https://developer.mozilla.org/ja/docs/Learn/JavaScript/Objects/JSON

## サンプルデータ
こちらが今回のサンプルデータになります。
GitHub APIから取得したJSONデータになります。
```
"files": [
    {
      "sha": "aa8066a1fe98eb3f9436a30b4ff9c7300af8c0df",
      "filename": "13.java/src/index.html",
      "status": "modified",
      "additions": 0,
      "deletions": 1,
      "changes": 1,
      "blob_url": "https://github.com/hukuryo/hukuryo/blob/b6d6f503de6f1eeb340ac17e48f627e460d839cf/13.java%2Fsrc%2Findex.html",
      "raw_url": "https://github.com/hukuryo/hukuryo/raw/b6d6f503de6f1eeb340ac17e48f627e460d839cf/13.java%2Fsrc%2Findex.html",
      "contents_url": "https://api.github.com/repos/hukuryo/hukuryo/contents/13.java%2Fsrc%2Findex.html?ref=b6d6f503de6f1eeb340ac17e48f627e460d839cf",
      "patch": "@@ -8,6 +8,5 @@\n </head>\r\n <body>\r\n     <p>レビュー</p>\r\n-    <p>newレビュー</p>\r\n </body>\r\n </html>\r"
    }
  ]
```
今回はこのデータの中の、"filename"というカラムのデータを取得してみましょう。
取得するためのJavaScriptのコードはこちらです。
```
// データが格納されているエンドポイントのURLをfetchで取得する
fetch("https://api.github.com/repos/hukuryo/hukuryo/commits/b6d6f503de6f1eeb340ac17e48f627e460d839cf")
    .then( response => response.json())
    // 受け取ったJSONデータをdataという変数に格納
    .then( data => {
        // 配列の中の連想配列からデータを取り出す
        console.log(data.files[0]['filename'])
    });
```
こちらが実行結果です。
![スクリーンショット 2023-02-28 20.41.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2613586/1c276bca-0a51-999a-e9f5-be54cf044aa5.png)
データが取得できました！
A0サイズ1ページのPDFをA4サイズ16ページのPDFに分割する

まず、PyPDF2モジュールの中にあるトリミングするための関数cropbox.lower_leftとcropbox.upper_rightは理解しにくいのですが、分かりやすく言うと、A0サイズ(縦1189mm 横841mm)を例にすると、

.cropbox.lower_left=(0で左切れない,1189で上切れない)
.cropbox.upper_right=(841で右切れない,0で下切れない)

というように書くことができます。


下が、A0サイズ1ページのPDFをA4サイズ16ページのPDFに分割するためのプログラムです。

```python:
import PyPDF2

# A0サイズPDFのファイルパス。予め縦にしておく。
pdf_path = '学会ポスター.pdf'

# PDFファイルを読み込む
pdf_file = open(pdf_path, 'rb')
pdf_reader = PyPDF2.PdfReader(pdf_file)

#ミリをポイントに変換するための定数。
#2.8ポイント≒1ミリメートル
pt_per_mm = 72 / 25.4 #≒2.8

# 各A4ページを作成
for a in range(4):
  for b in range(4):
        #aは列。bは行を指し、最初に縦を上から取り、その後に右へ移動します
        p1 = pdf_reader.pages[0]
        p1.cropbox.lower_left=((0+210*(a))*pt_per_mm,(1189-297*(b))*pt_per_mm)
        p1.cropbox.upper_right=((841-(3-a)*210)*pt_per_mm,(0+891-297*(b))*pt_per_mm)#y

        #A4ページをPDFファイルに保存します
        output_path = f"output/{a}列{b}行目.pdf"
        pdf_writer = PyPDF2.PdfWriter()
        pdf_writer.add_page(p1)
        with open(output_path, 'wb') as output_file:
            pdf_writer.write(output_file)
```

A0サイズのPDFは、ポスター用であればパワーポイントで用意するのが良いと思います。

参考
A4サイズのページサイズ
a4_width = 210
a4_height = 297

A0サイズのページサイズ
a0_width = 841
a0_height = 1189


参考文献：https://blog.shikoan.com/pdf-trimming-in-python/#CropBox%E3%81%A7%E3%83%88%E3%83%AA%E3%83%9F%E3%83%B3%E3%82%B0
Ruby 文字の順番を入れ替えて出力するプログラム

# 文字の順番を入れ替えて出力するプログラムを作成します

- 条件1:任意の文字列の最初の2文字を取得する
- 条件2:取得した2文字を最後尾に移動させた状態で、その文字列を出力する

```ruby
def left2(str)
  puts str[2..-1] + str[0..1]
end
# 呼び出し例
left2("Hello")
```

```
# ターミナル
lloHe
```

# 解説
指定の文字列が何文字であっても対応できるようにコーディングしていく必要があります。

- 最初の2文字はどのように取得するか
```ruby
str[0..1]
```
[0..1]
0番目から始まるため、0~1と指定しています。

- 最初の2文字を除いた残りの文字列はどのように取得するか?
問題を解いていて考えたことは、最後の文字が何番目かということ。
今回は「Hello」5文字ですが、何文字であってもプログラムとして成り立つように作らないといけません。
```ruby
str[2..-1]
```

最後の文字を指定するには、-1と書きます。
以上で完成です！