OmniAICreator/Qiita-1.07M huggingface dataset:
相対パスで読み込まれたjsファイルの相対パスを修正する

# 何？？
例えば/docs/index.htmlから/img/atlas.pngを読み込みたいとき

絶対パスで書くと
```html:/docs/index.html
<img src="/img/atlas.png">
```

相対パスで書くと
```html:/docs/index.html
<img src="../img/atlas.png">
```

これを他の場所でも使いまわせるようにjsファイルに移すと
```html:/docs/index.html
...
<script src="../src/util.js"></script>
...
``` 
```js:/src/util.js
const src='../img/atlas.png';
addEventListener('DOMContentloaded',()=>document.body.append(Object.assign(new Image(),{src})));
```
→読めないじゃん
これは単に/src/util.jsからの相対パスにしているからだが
/docs/index.htmlからの相対パスに書き換えたところで他のファイルから/src/util.jsを読み込んだときに読まない

どうする？

# これ
`<script>`のsrcから/docs/index.html→/src/util.jsまでの相対パスを読んで
予め/src/util.jsにある/src/util.js→/img/atlas.pngの相対パスに付け足す
```js:/src/util.js
document.querySelector('script[src$="util.js"]').src
// → "https://example.com/src/util.js"
```
[x$=y]はyで終わる属性xに合致する属性セレクタ [MDN](https://developer.mozilla.org/ja/docs/Web/CSS/Attribute_selectors)

これでパスの部分が取れるねと思ったらなんと絶対パスが返ってきた
困ったので無理矢理outerHTMLと正規表現でぶんどる

```js:/src/util.js
document.querySelector('script[src$="util.js"]').outerHTML.match(/\"(.*)util.js\"/)[1]
// → "../src/"
```

あとで結合しやすいようにutil.jsの部分は除いて検索している
そして
```js:/src/util.js
const root=document.querySelector('script[src$="util.js"]').outerHTML.match(/\"(.*)util.js\"/)[1],
  src=root+'../img/atlas.png';
addEventListener('DOMContentloaded',()=>document.body.append(Object.assign(new Image(),{src})));
```
これでどこからでも/img/atlas.pngが読めますね
めでたしめでたし……

追記: 2023/08/13

- 空文字列になると不都合な場面があった
- グローバルなオブジェクトに入れた方が使い勝手が良い

```js
self.root=document.querySelector('script[src$="util.js"]').outerHTML.match(/\"(.*)util.js\"/)[1]||'./';
```
Jetpack composeでCoordinatorLayoutを実現する

NestedScrollConnectionを使ってスクロール可能な要素をスクロールした際のコールバックを受け取って、要素の高さを計算すればOK

``` kotlin
@Composable
fun Screen() {
    val density = LocalDensity.current
    val defaultToolBarHeight = 120.dp
    val minToolBarHeight = 48.dp
    var toolBarHeight by remember {
        mutableStateOf(defaultToolBarHeight)
    }

    val nestedScrollConnection = remember {
        object : NestedScrollConnection {
            override fun onPreScroll(available: Offset, source: NestedScrollSource): Offset {
                val delta = available.y
                // ここでスクロールに合わせて高さを計算する
                toolBarHeight = with(density) {
                    (toolBarHeight.toPx() + delta).coerceIn(minToolBarHeight.toPx(), defaultToolBarHeight.toPx()).toDp()
                }
    
                return Offset.Zero
            }
        }
    }
    
    Column(
        modifier = Modifier.nestedScroll(nestedScrollConnection),
    ) {
        TopAppBar(
            modifier = Modifier.height(toolBarHeight)
        ) {
            // 略
        }

        // この要素をスクロールするとTopAppBarの高さが変化する
        LazyVerticalGrid(
        ) {
            // 略
        }
    
    }
}
```

こんな感じの構造にするとsheetContentをスワイプして消そうとすると一緒にTopAppBarの高さも変わってしまうのでContent側で上記のようにコンテンツ部分でTopAppBarを管理する必要がある

``` kotlin
BottomSheetScaffold(
    modifier = Modifier.nestedScroll(nestedScrollConnection),
    topBar = {
        TopAppBar(
            modifier = Modifier.height(toolBarHeight)
        ) {
            // 略
        }
    },
    sheetContent = {
        Column {
            // 略
        }
    }
) {
    LazyVerticalGrid() {
        // 略
    }
}
```
ここが嫌だよPDFBox!!（複数行出力とか）

みなさん！無償で使えるPDF作成ライブラリとして有名なんですが　[PDFBox](https://pdfbox.apache.org/ "PDFBox")　ってご存知でしょうか？

ただいざ使ってみるともやっとするポイントがちらほら...
まぁニッチなニーズなので仕方ない側面もあるんですけどね...ッ！！

私がPDFBoxを使ってみて困った事や嫌だった事とかを以下にまとめたので参考にしてくださいな！

##### 複数行対応はしたが・・・・？

参考リンク：[PDFBox 2.0.21は複数行テキストフィールドの自動フォントサイズに対応](https://qiita.com/oohira/items/13de6968d5240ac16ae2 "参考記事")

上記の通りPDFBoxは複数行の出力にも自動フォントサイズにも対応をしています。

がしかし！！！

以下のコードの通り、**デフォルトフォントサイズ12ptという所を変更する事は出来ません。**
https://github.com/apache/pdfbox/blob/2.0.26/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/AppearanceGeneratorHelper.java#L817

ちなみに、**下寄せも出来ません。**実装例としては以下とかがありますね。
https://issues.apache.org/jira/browse/PDFBOX-3812


##### 日本語に対応したが・・・・？

参考リンク：https://qiita.com/ota-meshi/items/55a6c379544b33728b58

補足すると、TTFを見つける処理はFontFileFinderってものを使ったりするとインストール済みフォント見つけやすそうね。
参考リンク：https://github.com/apache/pdfbox/blob/2.0.26/fontbox/src/test/java/org/apache/fontbox/ttf/TTFSubsetterTest.java#L129

がしかし！！！

**"/Helv 0 Tf 0 g"** の説明とかなさすぎる。
Helvの部分はCOSNameについて調べるといい感じ、
```java
　　TrueTypeFont ttf = findTTF("ipag.ttf");
　　PDFont font = PDType0Font.load(new PDDocument(), ttf, true);
  String name = new PDResources().add(font).getName();
	String defaultAppearanceString = "/" + name + " 0 Tf  0 0 1 rg";
```
って感じです。

0 はfontSizeで12ptとか。0なら自動サイズです。
Tfは謎... 
0 g は文字色で黒らしいけど、どこまで調整可能かは調べてません。小数点とかいけるのかな？？例がない...


**日本語に対応した例がない！！**
これが結構きつい。例えば複数フォント対応をしたいと思ってサンプルを見つけたのが以下
https://svn.apache.org/viewvc/pdfbox/trunk/examples/src/main/java/org/apache/pdfbox/examples/pdmodel/EmbeddedMultipleFonts.java?revision=1892302&view=markup

でも実際蓋を開けてみると、サロゲートペアとかの考慮がかけてたり、そもそも
```java
if (isWinAnsiEncoding(s2.codePointAt(0)) && font != fonts.get(0))
```
の所なんかは ```&&``` じゃなくて　```||```　じゃないかとか...
codePointAtとかoffsetByCodePointsとかを意識的に使った実装修正が必要。

雑にURLまとめた記事になりましたが、皆さんの参考になればと思います！
Laravelアプリの画像がロリポップで表示されない問題

# はじめに
今回はロリポップにLaravelアプリを公開したものの、画像が表示されていなかったため、その対応を投稿。

# 原因
通常Laravelではstorage/app/publicに保存された画像を利用する場合は`php artisan storage:link`など使ってシンボリックリンクを作成して利用する。
しかしロリポップのハイスピードプランではシンボリックリンクが利用できないそう、、。

# 環境
PHP 8.1.4
Composer 2.3.4
Laravel 8.83.13
レンタルサーバーはロリポップ ハイスピードプラン


# シンボリックリンクなしで画像を表示する
### 1.シンボリックリンクを削除しておく（バックアップ推奨します！）
`$ unlink シンボリックリンクへのパス`


### 2.publc以下に任意の名前でフォルダを作成する。
今回はtestフォルダとします。
![スクリーンショット 2022-06-16 11.27.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1095135/a8bd5779-a70d-0766-de0c-95c6113abaf1.png)


### 3.storage/app/publicを先ほどのフォルダに移動する
※storage/app/publicのみを移動してその他のsotrage関連のファイルは変わらずstorage/app以下に置いておきます。
![スクリーンショット 2022-06-16 11.30.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1095135/c3b90543-ecd0-b7f3-75c8-8c244b906b49.png)



### 4.config/filesystems.phpを編集する
以下のように編集
```php
'public' => [
    'driver' => 'local',
    // 'root' => storage_path('app/public'),
    'root' => public_path('test/public'),
    'url' => env('APP_URL').'/storage',
    'visibility' => 'public',
],
```

### 画像表示部分のパス変更
```php
<img src="{{asset('test/public/〜〜/'. ~~~)}}"
```

### Storageファサード使うとき
```
Storage::disk('public')->〇〇
```

### 参考サイト
[https://shikakui.com/laravel_storage-public](https://shikakui.com/laravel_storage-public)
【備忘録】Go(fiber)× Dockerでの環境構築を実施する。(Hot Reload対応)

Go×Dockerで環境構築しました。備忘録も兼ねて記載しておきます。
下記構成で、HelloWorldまでは出力することができます！！

```shell:ディレクトリ構成          
~/develop/gotenroku/gotenroku-api$ tree
.
├── Dockerfile
├── README.md
├── docker-compose.yml
├── go.mod
├── go.sum
├── main.go
└── tmp
    └── main

1 directory, 7 files
```

```Dockerfile:Dockerfile
FROM golang:1.17-alpine

ENV TZ /usr/share/zoneinfo/Asia/Tokyo

ENV ROOT=/go/src/app
WORKDIR ${ROOT}

ENV GO111MODULE=on

COPY . .
EXPOSE 1323

RUN apk upgrade --update && \
    apk --no-cache add git

RUN go get -u github.com/cosmtrek/air && \
    go build -o /go/bin/air github.com/cosmtrek/air

CMD ["air", "-c", ".air.toml"]
```

```yml:docker-compose.yml
version: '3'
services:
  app:
    build: .
    volumes:
      - ./:/go/src/app
    ports:
      - "41323:1323"
```

```go:main.go
package main

import (
	"fmt"
	"log"

	"github.com/gofiber/fiber/v2"
)

func main() {
    app := fiber.New()
    app.Get("/", func(c *fiber.Ctx) error {
        fmt.Println("🥉 Last handler")
        return c.SendString("Hello, Docker 👋!")
    })
    
    log.Fatal(app.Listen(":1323"))
}
```

```toml:.air.toml
# Config file for [Air](https://github.com/cosmtrek/air) in TOML format

# Working directory
# . or absolute path, please note that the directories following must be under root.
root = "."
tmp_dir = "tmp"

[build]
# Just plain old shell command. You could use `make` as well.
cmd = "go build -o ./tmp/main ."
# Binary file yields from `cmd`.
bin = "tmp/main"
# Customize binary, can setup environment variables when run your app.
full_bin = "APP_ENV=dev APP_USER=air ./tmp/main"
# Watch these filename extensions.
include_ext = ["go", "tpl", "tmpl", "html"]
# Ignore these filename extensions or directories.
exclude_dir = ["assets", "tmp", "vendor", "frontend/node_modules"]
# Watch these directories if you specified.
include_dir = []
# Exclude files.
exclude_file = []
# Exclude specific regular expressions.
exclude_regex = ["_test\\.go"]
# Exclude unchanged files.
exclude_unchanged = true
# Follow symlink for directories
follow_symlink = true
# This log file places in your tmp_dir.
log = "air.log"
# It's not necessary to trigger build each time file changes if it's too frequent.
delay = 1000 # ms
# Stop running old binary when build errors occur.
stop_on_error = true
# Send Interrupt signal before killing process (windows does not support this feature)
send_interrupt = false
# Delay after sending Interrupt signal
kill_delay = 500 # ms
# Add additional arguments when running binary (bin/full_bin). Will run './tmp/main hello world'.
args_bin = ["hello", "world"]

[log]
# Show log time
time = false

[color]
# Customize each part's color. If no color found, use the raw app log.
main = "magenta"
watcher = "cyan"
build = "yellow"
runner = "green"

[misc]
# Delete tmp directory on exit
clean_on_exit = true
```
[redux] selector にて定数オブジェクトを返すときはglobalで定義しておく



## tl;dr

- selector 関数の返り値にて固定値のオブジェクトを返す場合は、globalにて事前に定義しておかないと再レンダリングの原因になる

## useSelector

- useSelector は`===` にて新古比較をする。
- `{}` / string などは別のオブジェクトだとfalseになる。

```ts
const str1 = "a"
const str2 = "b"
str1 === str2 // false

const obj1 = {};
const obj2 = {};
obj1 === obj2 // false
```

## selector

```ts
// NG
// dispatchを実行するたびに、useSelectorでこのselectorを
// 呼び出しているコンポーネントは再レンダリングが発生してしまう。
const selectOptions = state => state.user?.options ?? {};

// OK
const emptyObj = {};
const selectOptions = state => state.user?.options ?? emptyObj;
```

## shallowEqual

それか、useSelector側でshallowEqualを明示する

```ts
const selectOptions1 = state => state.user?.options ?? {};
const options = useSelector(selectOptions1, shallowEqual);
```
LaravelのResource ControllerによるCRUD操作

ドキュメント
公式：https://laravel.com/docs/9.x/controllers#main-content
Readouble：https://readouble.com/laravel/8.x/ja/controllers.html


```.bash
php artisan make:CreateController
php artisan make:DeleteController
```
などと記事の投稿・削除などのCRUD操作それぞれに対して自分で設定を行っていた。

が、これらを一括で作れるのがリソースコントローラー
```.bash
php artisan make:PostsController --resource
```
これにより以下のファイルが作成できる。
```PostsController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class PostsController extends Controller
{
    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        //
    }

    /**
     * Show the form for creating a new resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function create()
    {
        //
    }

    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        //
    }

    /**
     * Display the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function show($id)
    {
        //
    }

    /**
     * Show the form for editing the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function edit($id)
    {
        //
    }

    /**
     * Update the specified resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function update(Request $request, $id)
    {
        //
    }

    /**
     * Remove the specified resource from storage.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function destroy($id)
    {
        //
    }
}
```
それぞれのfunctionにコードを書いていけばいいだけだ。

Routingは以下のよう。
```.bash
php artisan route:list

  GET|HEAD        posts .......................................................... posts.index › PostsController@index
  POST            posts .......................................................... posts.store › PostsController@store
  GET|HEAD        posts/create ................................................. posts.create › PostsController@create
  GET|HEAD        posts/{post} ..................................................... posts.show › PostsController@show
  PUT|PATCH       posts/{post} ................................................. posts.update › PostsController@update
  DELETE          posts/{post} ............................................... posts.destroy › PostsController@destroy
  GET|HEAD        posts/{post}/edit ................................................ posts.edit › PostsController@edit
```
routesファイルには以下のように記述。
```web.php
Route::resource('posts', PostsController::class)->only(['index', 'show']);
```
only, exceptなどで使いたいメソッドだけを指定すれば出来上がり！
初めてみようAlpine.js(*^▽^*)

# |ω・｀)ﾉ ﾔｧ
jsのフレームワークを触った事のないそこの君！とっつきやすいAlpine.jsを触ってみない？ σ(・ω・,,｀)？

# 使う準備(*‘ω‘ *)

CDNで読み込むだけ！
```html
<script defer src="https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js"></script>
```
終了 (^_-)-☆


# 基本的な使い方( *´艸｀)

## サンプル1
テキストボックスに入力した文字をpタグに同期して表示してみよう！( ^^) _U~~
![Videotogif (1).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282328/3ec0f4db-92ee-5486-782a-7d7406f0f485.gif)

| ディレクティブ | 説明                                                    | 
| ---------- | ------------------------------------------------------- | 
| x-data     | 変数、メソッド、ゲッターなどを定義します                | 
| x-model    | inputタグなどに使用。指定した変数を同期して書き変えます | 
| x-text     | タグの直下に指定した変数の中身を同期して表示します      | 

### 1. x-dataで変数を宣言しよう! 宣言したタグの外からは使えないよ(^^♪

https://alpinejs.dev/directives/data

```html
<div x-data="{ name: '' }">
</div>
```
### 2. x-modelでテキストボックスに入力した内容と同期させよう(^_-)-☆

https://alpinejs.dev/directives/model

```html
<div x-data="{ name: '' }">
    <input type="text" x-model="name"/>
</div>
```

### 3. x-textで変数の中身を表示しよう(^^)/

https://alpinejs.dev/directives/text

```html
<div x-data="{ name: '' }">
    <input type="text" x-model="name"/>
    <p x-text="name"></p>
</div>
```

わぁ(n'∀')ηﾟ*｡:*!jsフレームワークデビュー、しちゃったね！

## サンプル2

特定のラジオボタンを選択した時にのみテキストボックスを表示しよう(*^^*)

| Directives | 説明                                                              | 
| ---------- | ----------------------------------------------------------------- | 
| x-on:click | クリックイベント、処理をそのまま記述も可能                        | 
| x-show     | 式の結果がfalseの時にdisplay:noneが付与され、trueの時に解除される | 

https://alpinejs.dev/directives/on

https://alpinejs.dev/directives/show

```html
<div x-data="{ isPet: false }">
    <p>ペットを飼っていますか？</p>
    <input type="radio" name="isPet" value="はい" x-on:click="isPet = true" id="yes"><label for="yes">はい</label>
    <input type="radio" name="isPet" value="いいえ" x-on:click="isPet = false" id="no"><label for="no">いいえ</label>
    <div x-show="isPet">
        <label>ペットの名前</label>
        <input type="text"/>
    </div>
</div>
```
![Videotogif (2).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282328/13f01b6b-4299-538e-964c-800a7e83c727.gif)


# おわりに (#^.^#)

軽い動的な機能ならjavascript書かずに作れちゃって快適ーなAlpine.js(*^。^*)。

興味を持ってくれたら嬉しいな( ｀ー´)ノ
RundeckのSSLを有効化したらCLIで諸々エラーが出た話

# 何をしたのか
rundeckは導入時は非SSLで動作していますが、そのためにChromeなどからアクセスすると警告表示がされます。プライベート空間で使っているのでそれで実用上問題ないと言えばないのですが、次第にうっとおしくなってきたのでSSLの設定を行いました。
プライベートCAに基づく証明書をcockpit用に作成しており、その証明書をkeytoolを使ってkeystoreやtruststoreに取り込むことでWebブラウザからのアクセスでは順当にSSLが有効になり、警告も表示されなくなりました。

https://docs.rundeck.com/docs/administration/security/ssl.html

SSLの有効化作業はうまくいったように見えました。
# 何がおきたのか
Rundeckの定義バックアップをCLI(rdコマンド)で行うようにスケジューリングしているのですが、こちらでエラーが出るようになりました。CLIはCLIでアクセスするURLを環境変数(RD_URL)で持たせているので、そちらの修正は当然なのですが、それとは別にCLI用のSSL設定が別途必要になります。

https://docs.rundeck.com/docs/rd-cli/ssl.html#_1-import-the-certificate

しかし、今度はJavaのSSLエラーが表示されるようになりました。
# もう少し詳しく
段どりとしてはRundeckのCLIでSSLの設定ガイドにある、キーストアを作成するImport the certificateと、そのキーストアを使ってCLIを使うためのConfigurateを実施した後に発生しています。エラーは２種類発生しました。
### エラー１
>__javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target__

このエラーは作成したキーストアにCLIがアクセスできないことが原因でパスの間違いやオーナー、パーミッションの設定で解消しました。
### エラー２
>__javax.net.ssl.SSLException: java.lang.RuntimeException:
Unexpected error: java.security.InvalidAlgorithmParameterException:
the trustAnchors parameter must be non-empty__

このエラーはjavax.net.ssl.trustAnchorsが設定されていないために発生しているような印象を受けるので、RD_OPTでjavax.net.ssl.trustAnchorsを追加設定してみたのですが、"must be non-empty"は解消しませんでした。
結論としては(Rundeckのガイドにある)javax.net.ssl.trustStoreで指定したキーストアにつけられたパスワードが実行時に与えられていないことが原因でした。
-Djavax.net.ssl.trustStorePassword　をRD_OPTに追加してパスワードを指定したところ解消しました。
# エラーは解消していますが
Rundeckから提供されているRundeck CLI - SSL Configurationガイドには必要な情報はほぼ含まれていて、記載されている手順通りに進めれば実装できます。ただ、キーストアのパスワードについての記載がありません。
ガイドにある1. Import the certificate の最後で storepassについて言及されているにも関わらず、2. Configuration ではパスワードが出てこないことに疑問が浮かばなかったわけではないのですが、エラーメッセージからは原因を読み取ることができなかったので少々手間取りました。検索するとJREのca-certを別途導入せよ、みたいなページが出て来るのですがrundeckの本体はHTTPSでアクセスできるようになっているのでそれほど根幹的な問題ではないはずだ、という見通しも持ってはいました。
今回は、作成したキーストアの内容を確認しようとしたときパスワードを要求されたことが、原因を掴む契機になりました。
AmazonのURLをひたすらDynamoDBに登録するだけのAPIをLambda Function URLsでつくった

# はじめに
この記事はLambda(Function URLs)とDynamoDBと連携させる内容となっています。
前回の記事の続きとなっているため同様の手順は省略しています。

https://qiita.com/tkhs1121/items/b1e332acdbc50fad8c45

# 環境
MacBook Air M1
開発言語 Go

# 追加で必要なパッケージのインストール
```
go get -u github.com/aws/aws-sdk-go
```

# ソースコード
```main.go
func HandleRequest(ctx context.Context, payload Payload) error {
	url, err := parseRequest(payload)
	if err != nil {
		return err
	}
	isAmazonURL, err := checkAmazonURL(url)
	if err != nil {
		return err
	}
	if !isAmazonURL {
		return fmt.Errorf("this is not amazon url: %v: %v", err, url)
	}

	db := new(DB)
	if err := db.newDynamoDB(); err != nil {
		return err
	}
	if err := db.putItem(url); err != nil {
		return err
	}

	return nil
}
```
### URLの取り出しとバリデーション
この部分は前回の記事のコードを再利用しています。
```commmon.go
func parseRequest(payload Payload) (string, error) {
	var req Request
	err := json.NewDecoder(strings.NewReader(payload.Body)).Decode(&req)
	if err != nil {
		return "", fmt.Errorf("cannot decode payload: %v: %v", err, payload.Body)
	}
	return req.URL, nil
}

func checkAmazonURL(url string) (bool, error) {
	return regexp.MatchString(`^http(s)?://(www.)?amazon.(co.)?jp[\w!\?/\+\-_~=;\.,\*&@#\$%\(\)'\[\]]*`, url)
}
```
### DynamoDBとの連携
``` infura.go
func (db *DB) newDynamoDB() error {
	sess, err := session.NewSession()
	if err != nil {
		return err
	}
	db.DDB = dynamodb.New(sess)
	return nil
}

func (db *DB) putItem(url string) error {
    rand.Seed(time.Now().UnixNano())
	randID := strconv.Itoa(rand.Intn(100))
	epoch := strconv.FormatInt(time.Now().Unix(), 10)
	input := &dynamodb.PutItemInput{
		TableName: aws.String("table"),
		Item: map[string]*dynamodb.AttributeValue{
			"id": {
				N: aws.String(randID),
			},
			"time": {
				N: aws.String(epoch),
			},
			"url": {
				S: aws.String(url),
			},
		},
	}
	if _, err := db.DDB.PutItem(input); err != nil {
		return err
	}
	return nil
}

```
https://github.com/tkhs1121/go-serverless-app-2

### ハマったところ
コンパイルする際にmain.goのみを指定するとgo undefinedエラーが出るので、
```
GOARCH=amd64 GOOS=linux go build -o main *.go
```
にする必要がある。
*https://yatta47.hateblo.jp/entry/2020/03/18/000000

# 動作確認
Lambdaのコンソール上でテストする場合はこうする。
```
{
  "body": "{\"url\": \"https://www.amazon.co.jp\"}"
}
```

# 最後に
所々粗があるので次回にリファクタリングする。
記事の更新を重ねて最終的にはちょっとしたSNSが出来上がる予定。
@nuxt/image【ipx is an optional dependency for local image optimization and is not properly installed. 】エラーの対応

[@nuxt/image](https://image.nuxtjs.org/)を導入後、Nuxtをビルドすると下記のエラーが出てビルドができなくなりました。その時に対処した方法になります。

```
ipx is an optional dependency for local image optimization and is not properly installed. 
```

## 発生したエラー
下記が発生したエラーの全文になります。
```
[error][@nuxt/image] ipx is an optional dependency for local image optimization and is not properly installed. 
Please try npm install or yarn install again.

[fatal] SyntaxError: Unexpected token '?'
```

## @nuxt/imageのバージョンを下げることで解決

@nuxt/imageのバージョンを`0.6.2`から`0.6.0`に下げることで無事にビルドが通る様になりました。

Githubのissuesでも同じ様なエラーが報告されているようです。

https://github.com/nuxt/image/issues/488
VSCode怖い。。。

VSCodeを触ってたら急に文字がめちゃくちゃ小さくなりました。。。

どうやら'Command' + '_'を押してしまっていたらしい。

いつか戻るかもと思って押し続けていたらどんどん小さくなって絶望。

調べると、'Command' + 'shift' + '+'で拡大できました！！！！！！！！！！！！

-fin-
案件準備

# 案件準備
## 0ベース
### 読書・今までの知識をまとめる。
◾️ 10年戦えるデータ分析
10年戦えるデータ分析入門　SQLを武器にデータ活用時代を生き抜く (Informatics ＆IDEA) by 青木 峰郎 
●進捗
一読しました。

https://www.amazon.co.jp/dp/B010CQD4Y0/ref=cm_sw_r_tw_dp_W0E0YB8NEVX3G16VHJ81 
### あるある
Oracleとpostgreの違いを軽くチェック
https://www.ashisuto.co.jp/tech-note/article/20141006_db.html

### 作戦
かなりたくさんの言葉を提示されたので作戦を考える。
Go   
↓
React
### Go編
#### チートシートを手に入れる
https://github.com/a8m/golang-cheat-sheet#basic-syntax
#### サクッとドットインストールを一周する。
はじめてのGo言語（完了)
https://dotinstall.com/lessons/basic_golang_v2

#### fizzbuzzやってみる。
```go
package main

import "fmt"

func main() {
	i := 1
	for i <= 100 {
		if i%3 == 0 && i%5 == 0 {
			fmt.Println("fizzbuzz")
		} else if i%3 == 0 {
			fmt.Println("fizz")
		} else if i%5 == 0 {
			fmt.Println("buzz")
		}
		i = i + 1
	}
}
```
#### Udemy学んでみる
https://www.udemy.com/course/go-fintech/
それが終わったらテキストを学びつつReactへ


◾️Take Away 
option + ¥ (\)(MAC)
Tab 
Shift + Tab
URLパラメータ（クエリ文字列）は文字列で取得されますよ。

先日会社でサービスの開発をしている時、URLパラメータを取得しているのに読み込まれていない事案が発生しました。
案外ミスしがちなポイントだったので記事に残します。（タイトルが結論ですが。）

# やりたかったこと
URLパラメータをインスタンス変数に入れてviewで表示内容を変えるというものです。

```controler.rb
@user_type = params[:id]     # URLパラメータの値を取得
```

```view.rb
<% if @user_type == "1" %>
  <%= link_to %>
<% end %>
```

# はまりポイント
はまりポイントというほどでもないですが、ちょいはまりくらいです。
URLパラメータは文字列型で取得されることです。
ですので「よし、id=1のパラメータを取得したぞぉ」といって```if @user_type == 1```と書いても認識されないわけです。

# まとめ
「URLパラメータは全て文字列で取得される。IntegerやArrayで使用したい場合は都度、変更する必要があ
る。」
URLパラメータ、別名クエリ文字列と言われるのでクエリ文字列で覚えてたらこんなミスはないと思いますが,,,
Cypressにlighthouseを導入する

# Cypress Lighthouse

## Table of Contents

```
0. 前提
1. lighthouseをProjectに入れる
2. Cypress Commandを追加する
```

## 0. 前提

```
lighthouse
  version "9.6.1"
cypress
  version "9.6.1"
typescript
  version "4.6.4"
```

## 1. lighthouseをProjectに入れる

```
$ yarn add lighthouse
```

## 2. lighthouseコマンドを追加する

`cypress/support/commands`以下に新しいコマンドを記載する。

```cypress/support/commands
/// <reference types="cypress" />
declare namespace Cypress {
  interface Chainable<Subject> {
    lighthouse(url: string): Promise<any>
  }
}
Cypress.Commands.add("lighthouse", (url: string) => {
  // https://github.com/GoogleChrome/lighthouse#using-the-node-cli
  cy.exec(`lighthouse ${url} --output json --chrome-flags="--headless"`).then(({ stdout }) => {
    const { categories, ...data } = JSON.parse(stdout)
    console.log(categories, data)
    return Object.keys(categories).reduce((curr, key) => {
      return {
        ...curr,
        [key]: categories[key].score
      }
    }, {});
  });
})
```


```cypress/integration/sample.spec.ts
describe("", () => {
    beforeEach(() => {
        cy.visit("/")
    })
    it("/", () => {
        cy.location().url().should("include", "/")
        cy.lighthouse("http://localhost:3000").then(res => {
            cy.wrap(res).its("accessibility").should("gt", 0.9)
            cy.wrap(res).its("best-practices").should("gt", 0.9)
            cy.wrap(res).its("performance").should("gt", 0.9)
            cy.wrap(res).its("pwa").should("gt", 0.9)
            cy.wrap(res).its("seo").should("gt",0.9)
        });
    })
})
```

上記のように対応するとScoreの計測が可能です。
ですが、めちゃめちゃ遅い。

Github ActionsでCloneを利用すれば、いくらか対応策はありそうです。。。

##### refs

- [Repo](https://github.com/Ntakuya/vite-react-recoil-cypress/tree/feature/cypress-typescript)
アプリケーション標準ナビゲーションの場合、新しいタブでレコード画面の表示

質問：コンソール版じゃないUIで、レコードをクリックしたら、新しいタブで開くように設定できますか？
画面遷移させないで、タブの横に新しいタブでレコード画面を開くようにしたいです。
回答：できます。
手順：
①アプリケーションの一番右に表示したいのレコードをクリックして実のレコードタブが表示されます。
②該当レコードのオブジェクト名のタブ一番下の方は「…を新しいタブで開く」ボタンがあります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/442974/d513521b-f481-1e5c-208c-c4ee627fcfc7.png)

③自動ではなくて手動設定したら、指定したレコードが取引先タブではなくて、新しいタブで表示されます。
でもユーザログアウトすれば、該当データが保持できない状態です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/442974/04cecec8-cdbb-9985-f1f7-9d54bd9ec2cb.png)
IE11 再インストール失敗（WSUSでWindows Updateが適用されない）


Internet Explorer 11 (IE11) は廃止され、2022 年 6 月 15 日にサポートが終了します。

社内で IE11 の使用禁止が通達されていたので、先月早々 IE11 をアンインストールしてしまいました。
ところが、月次の事務処理で社内イントラWebアプリを起動したが動かない・・・
イントラネットサイトを互換表示で表示するためには IE11 が必要だったのですね。

アンインストールした、IE11 の再インストール実行しました。

Windows10 オプション機能 機能の追加
インストールが失敗しました。


ログを確認します。
~~~text:C:\Windows\WindowsUpdate.log
--
Windows Update logs are now generated using ETW (Event Tracing for Windows).
Please run the Get-WindowsUpdateLog PowerShell command to convert ETW traces into a readable WindowsUpdate.log.


For more information, please visit https://go.microsoft.com/fwlink/?LinkId=518345
~~~
ログの指示通り PowerShell でコマンド入力して、ETWトレースを可読変換します。

~~~text:PS C:\Users\hoge> Get-WindowsUpdateLog

Converting C:\WINDOWS\logs\WindowsUpdate into C:\Users\hoge\Desktop\WindowsUpdate.log ...

入力
----------------
ファイル:
     C:\WINDOWS\logs\WindowsUpdate\WindowsUpdate.20220610.024902.808.1.etl
     C:\WINDOWS\logs\WindowsUpdate\WindowsUpdate.20220610.064623.636.1.etl
     C:\WINDOWS\logs\WindowsUpdate\WindowsUpdate.20220610.070530.362.1.etl
     C:\WINDOWS\logs\WindowsUpdate\WindowsUpdate.20220610.074728.627.1.etl

0.00%9.09%18.18%27.27%36.36%45.45%54.55%63.64%72.73%81.82%90.91%100.00%

出力
----------------
DumpFile:         C:\Users\hoge\AppData\Local\Temp\WindowsUpdateLog\wuetl.CSV.tmp

コマンドは、正しく完了しました。

WindowsUpdate.log written to C:\Users\hoge\Desktop\WindowsUpdate.log

~~~
生成されたログを参照します。
見ても *FAILED* があるので失敗しているんだな程度ですが、WSUS (Windows Server Update Services) は認識されていそうです。

WSUS が更新プログラムを受け取り、社内のPCに配布する。
社内ネットワークの負荷を分散させるために配信スケジュールを調整したり、不要な更新プログラムは配信しないよう設定したりすることができます。

たぶん WSUS が原因ということで、一時的に無効（0）にしてみたところ、IE11 の再インストールに成功しました。

~~~text:UseWUServer.reg
Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU]
"UseWUServer"=dword:00000000

~~~
Strictモードを使用しているとReactRouterのBrowserRouterがちゃんと動かない(究明中)

制作をしている中で気づいたのでメモがわりに残しておきます。
同じ事象になっている人がいたら参考になるかもしれません。

```React:test.jsx
<React.Strict>
  <BrowserRouter>
  </BrowserRouter>
</React.Strict>
```

上記のようにReact.StrictでBrowserRouterをラップするとURLは正常に変更されていても、画面遷移が行われない事象が起きました。公式ページを確認すると、Strictタグは使用しても、移動してもよいみたいなので、<React.Strict>タグを削除するかBrowserRouter内に移動するかで解消できました。

具体的な原因まではまだ不明ですが、本番環境ではStrcitモードは特に関わりないのでStrictモードを使用せずの開発を行うのがひとまずの対応。

Strictモードに関しては参考リンクは[こちら](https://qiita.com/Qiita/items/c686397e4a0f4f11683d)
間違ってルート(route)のみを消すつもりが、サービス(service)まで消してしまった時の対処法

ホスト名が間違ったり、デフォルトまま登録してしまい
一度、消してからやり直そうとした結果、ルートのみを消すつもりが、誤ってサービスまで消してしまった。
最初からDeploymentしかない場合の対処法です。

# 1. デプロイメント(Deployment)からサービス(Service)を作る
## OpenShiftの場合
```
oc expose deployment/my-deployment --name my-service --port 80 --target-port 8080
```
## Kubernetesの場合
```
kubectl expose deployment/my-deployment  --name my-service  --port 80 --target-port 8080
```

# 2. サービス(Service)からルート(Route)を作る
## OpenShiftの場合
```
oc expose service/my-service --hostname service.apps.ocp4.example.com
```
## Kubernetesの場合
```
kubectl expose service/my-service
```
対数を調べてみた。

**実数の対数 logb x** は、底 b が 1 でない正数であり (b ≠ 1, b > 0)、
真数 x が正数である場合 (x > 0)[注釈 1] について定義される。 ＜

https://ja.wikipedia.org/wiki/%E5%AF%BE%E6%95%B0

wolframalphaで、Log[b,z] b を底とする対数を返す．

https://reference.wolfram.com/language/ref/Log.html

sympy classで、sympy.functions.elementary.exponential.log(arg, base=None)

https://docs.sympy.org/latest/modules/functions/elementary.html#log

# wolframalphaで
4＾(log( a,3)/log( a,2)) 結果9 
4＾(log( 5,3)/log( 5,2))　"
4＾(log(-5,3)/log(-5,2))　"
4＾(log( 1,3)/log( 1,2)) 入力だけ。結果は出ませんでした。

https://www.wolframalpha.com/input?i=4%EF%BC%BE%28log%28+a%2C3%29%2Flog%28+a%2C2%29%29&lang=ja

https://www.wolframalpha.com/input?i=4%EF%BC%BE%28log%28+5%2C3%29%2Flog%28+5%2C2%29%29&lang=ja

https://www.wolframalpha.com/input?i=4%EF%BC%BE%28log%28-5%2C3%29%2Flog%28-5%2C2%29%29&lang=ja

https://www.wolframalpha.com/input?i=4%EF%BC%BE%28log%28+1%2C3%29%2Flog%28+1%2C2%29%29&lang=ja


# sympyで

```python
from sympy import *
var('a')
print("# a#",(4**(log(3, a)/log(2, a))).simplify())
print("# 5#",(4**(log(3, 5)/log(2, 5))).simplify())
print("#-5#",(4**(log(3,-5)/log(2,-5))).simplify())
print("# 1#",(4**(log(3, 1)/log(2, 1))).simplify())
# a# 9
# 5# 9
#-5# 9
# 1# nan
```

# オリジナル

https://kamelink.com/blog/2022/06/15/2-2-17-kounandai%e3%83%bbrikou%e3%83%bbtinou%e3%83%bbfuro-1/

解答pdf

https://kamelink.com/public/2017/2.2-17%E7%94%B2%E5%8D%97%E5%A4%A7%E3%83%BB%E7%90%86%E5%B7%A5%E3%83%BB%E7%9F%A5%E8%83%BD%E3%83%BB%E3%83%95%E3%83%AD1.pdf
Pythonのglobalキーワードを省略できるケース

# Pythonのglobal変数
短いスクリプトを書いたり、サンプルコードを少し実験してみるときには、私はしっかり作り込んだりせずglobal変数に頼ったりすることが多いです。そういったシーンでは、global変数を参照する際に毎回`global`キーワードを記述するのも面倒。省略できるなら省略したい。けどどんなときに省略できるのか詳しくわかっていませんでした。
いくつか実験をしてみましたのでみなさんの参考になればと思います。

### まずはわかった結論から
- globalキーワードを省略すると？
  - `def`の中など、あるローカル名前空間で`global`キーワードを省略した場合、**書き換えが行われる変数が**、グローバル変数と同じ名称だった場合、それはグローバル変数ではなく、新しいローカル変数であると判断されるようです。そして一旦ローカルであると判断されたあとはその名前空間では絶対に同一名称のグローバル変数へのアクセスができなくなるようです。
  - 一方で、書き換えを行わないのであれば`global`キーワードを省略してもグローバル変数として扱われるようです。ややこしい。誰だこんなヘンテコルール作ったやつ。
- 覚えておくこと
  - 開発の流れの中では、まずはグローバル変数を**参照する記述**をすることが多いのではないかと思います。そのときは`global`キーワードは必要ありません。
  - いざ、その変数を書き換えたくなった瞬間！`global`キーワードを書いてください。
    - 忘れた場合、グローバル変数を参照していたそれまでのコードが、**一転してローカル変数への参照となります**。
    - 1ヶ所書き換えただけなのに、その前から周辺が動かなくなるなんてことも十分あり得ます。
    - この法則は覚えておく必要があります。

```python
glb = 30
def func(arg):
	lcl = glb * glb # グローバル変数を参照する記述 ok!
	return lcl
```
　↓
```python
glb = 30
def func(arg):
	if arg == False:
		glb = 0 # 新規記述。グローバル変数を書き換えようとした。
	lcl = glb * glb # もうグローバル変数を参照していない。
	return lcl
```

### 実際のコードで確認
```python
#!python3
glb = 30
ret = None

def func0():
	return glb # これはglobalを参照している

def func1():
	glb = 5 # これはlocal変数
	return glb

def func2():
	global glb # これはglobalを参照している
	glb = 5
	return glb

def func3():
	lcl = glb # これはglobalを参照している
	return lcl

def func4():
	glb = glb # エラー。これはlocal変数。不定値参照。
	return glb

def func5():
	glb = 5 # これはlocal変数
	#global glb # エラー。local変数と同一名称のglobal変数
	glb = 5
	return glb

def reset():
	global glb
	global ret
	glb = 30
	ret = None


reset()
print(f"after reset :   ret:{ret}, glb:{glb}")

reset()
ret = func0()
print(f"after func0 :   ret:{ret}, glb:{glb}")

reset()
ret = func1()
print(f"after func1 :   ret:{ret}, glb:{glb}")

reset()
ret = func2()
print(f"after func2 :   ret:{ret}, glb:{glb}")

reset()
ret = func3()
print(f"after func3 :   ret:{ret}, glb:{glb}")

reset()
ret = func4()
print(f"after func4 :   ret:{ret}, glb:{glb}")

reset()
ret = func5()
print(f"after func5 :   ret:{ret}, glb:{glb}")

```


### 結果
```
after reset :   ret:None, glb:30
after func0 :   ret:30, glb:30
after func1 :   ret:5, glb:30
after func2 :   ret:5, glb:5
after func3 :   ret:30, glb:30
Traceback (most recent call last):
  File "/Users/shinya.ohtani/Documents/CodeRunner documents/Sample.py", line 52, in <module>
    ret = func4()
  File "/Users/shinya.ohtani/Documents/CodeRunner documents/Sample.py", line 29, in func4
    glb = glb # エラー。これはlocal変数。不定値参照。
UnboundLocalError: local variable 'glb' referenced before assignment
```

# 参考
- https://aiacademy.jp/media/?p=2527
プログラミング初心者のデザイナーがFlutterを勉強する日記 2,3日目

仕事にかまけてちゃんと書けていなかった...
2日目、3日目ではアプリを書くための環境が構築できたので、その記録

# Android Studioのインストール
基本的に教科書通りに進めればインストールはできたが、Android SDKライセンスの許諾の部分でつまづいた
```
% flutter doctor --android-licenses
```
これをコマンドラインに入力するだけなのだが、以下のようなエラーが出る
```
Android sdkmanager not found. Update to the latest Android SDK and ensure that
the cmdline-tools are installed to resolve this.
```
そこでQiitaを漁り、この記事を参照させていただいた
[fluter doctorに「Android sdkmanager not found.」と言われた時の対処](https://qiita.com/ShortArrow/items/46ca3717384039419605)
記事にある通り、Android StudioからAndroid SDK Command-line Tool(latest)を落としたらインストールできた！
集合知ってすごい。
ついでにVScodeも落としてみた（が、とりあえずはAndroid Studioをメインで使うことになりそうだ）

# Androidエミュレータを入れる
参考書によると、Tools->AVD Managerを選択して起動するとあるのだが、現行のAndroid Studioには該当するメニュー名がない。
項目を見て、どうやら今はDevice Managerから入れるようだと察した（このへんから参考書の記載結構古いのだなあと気づきはじめる）
DeviceはPixel 2、System ImageはPieで作ってみる。
Androidの画面がぽこっと出てきて感動（ただiPhoneユーザなので基本UIがわからずちょっとタジタジ）

# ホットリロードでHello Worldしてみる
まずは初期状態のmain.dartを無邪気にRunしてみて、エミュレータに反映されることを確認
そのうえでコードの一部を書き換えてCtrl+Sしてみたら、すぐに置き換わった...これがホットリロードの力。便利

# 自分で新しくプロジェクトを作ってみる
main.dartは本当に初めてのプロジェクトとしてとっておくとして、自分でも新しく作ってみる。
参考書通りにサンプルコードを打ってRunしてみるが、コンソールが真っ赤になりエラー...
どうやら参考書にあるコードの書き方が古いらしい。Android Studioが勝手に訂正してくれた、IDEのちからってすげー

Before
```
import 'package:flutter/material.dart';
void main(){
 runApp(MaterialApp(Text'Hello World')));
}
```
After
```
import 'package:flutter/material.dart';
void main() {
  runApp(MaterialApp(home: Text('Hello World')));
 }
```
home:の有無が違う。こんな細かいところで言語って変わるのか。はじめて知った

やっぱり参考書の書き方が古いっぽくて、会社の先輩に相談したところ、より新しめな参考書を教えてもらった
[Software Design 2022年4月号 はじめてのFlutter](https://gihyo.jp/magazine/SD/archive/2022/202204)
この記事に沿ってちょろっと書いたらめちゃくちゃちゃんと動いておおっとなった。けど、その続きは次の記事に書こうかな

あとはそもそもFlutter公式のGet Startedやるのが一番スムーズなのでは？という気もしてきた
[Flutter > Get Started > Write your first Flutter app](https://docs.flutter.dev/get-started/codelab)

プログラミングの概念（widget、クラス、関数とか）があんまり咀嚼しきれてない中で写経しても身につくかなあと思いつつだが、初歩的なところから少しずつやっていこう〜

# 今日のまとめ
* プログラミング言語は日進月歩で進歩している
* 前回に引き続きだが、すぐに結果が反映されなくても焦らない、あとエラーコードはちゃんと読む（エラー出てても単純に;が足りないだけとかある）
* デザインやってる人間がプログラミングやるとか効率悪いと思われるかと思ってたのだが、会社の先輩に「建築の構造や設計の仕方わからない人間が図面引くわけがない、それがなぜか許されてるのはソフトウェアだけ」という話をされたまさにだな、と思い勉強してることに意義はあるなと思った
入社１年目の終わりにLTでPythonを使ったモジュール開発について喋ってみた

# はじめに
こんにちは！
本日は、1年目の終わりにグループ会社横断で開催されたLTに登壇して、Pythonを使ったモジュール開発について喋ってきたので、その内容について発信していきたいと思います。

# 対象者

１：LTへの登壇を迷っている方
２：今回のLTでの発表内容について知りたい方
３：新入社員の方
４：LTを企画してる方

# 目次

１：結論
２：LTとは
３：登壇したLTの概要
４：なぜ登壇しようと思ったか
５：なにを喋ったか
６：まとめ

# 結論

まず、LTへの登壇はメリットしかありませんでした。大きく3つほどあったかと思います。

１：””繋がりの形成”” 
→　LTを通して、他の部署/他の会社の方々に私のことを知ってもらえました。

２：””知識の定着””　
→　発表はアウトプットに見えますが、相手に説明ができるということは自分がしっかりと理解している必要があります。そのため、発表までの準備を通して知識の定着につながります。

３：””モチベーション向上””　
→　他の人の発表から刺激をもらったり、自分の発表に対して良いFBをもらうことで、もっと頑張ろうとモチベーションの向上につながりました。

# LTとは

そもそもLTとはなんのことを表すのでしょうか。
LTとは、Lightning Talkの略で、これはカンファレンスなどのプレゼンテーションで、数分程度の短い時間で何かのテーマについて発表する手法のこと指します。文字通り、「雷や光のように素早く終わるプレゼン」という意味となります。

# 登壇したLTの概要
以下URLで、登壇したLTの情報を見ることができます。
https://techplay.jp/event/850180

# なぜ登壇しようと思ったか
&emsp;情報発信活動を通して、本記事冒頭の結論にも記載したようなメリットを享受し、自身を成長させたい/エンジニアとしての市場価値を上げていきたいと思い、登壇に至りました。ちなみに、LTへの登壇はこれが2回目になります。今回はグループ会社横断で開催されたもので、視聴者も20時前後にもかかわらず80名ほどいました。

# なにを喋ったか
* アブストラクト
&emsp;アサインされているシステム監視ソフトウェアの予測機能などを活用して将来のストレージ使用量を シミュレーションするスクリプトを開発を行う、自動化プロジェクトにおいて、ツール作成のためにPythonを用いたモジュール開発について、10分間で発表を行いました。

* ディティール
１：プロジェクトの環境
・メンバー：4人(PJリーダー、先輩エンジニア2名、自分)
・定例：週2回
・ 担当モジュール
&emsp;①データ削減容量補償サービス発動判定モジュールの開発
&emsp;②容量解放処理(unmap)が有効な筐体の選出モジュールの開発 ⇒ 今回はココ
・開発環境
&emsp;→検証環境で開発/テスト → 商用環境にリリース
&emsp;→言語：Python
&emsp;→エディタ：vi、VScode


&emsp;２：ストレージの空き容量を増やす手段 → Unmap
・Unmapは、データストアの不要領域を解放（マッピング解除）することです。
・ストレージを長期間利用すると、筐体使用量とユーザ実利用量と差分が発生するため、Unmapによりリソースを解放する必要があります。
![unmap.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/754596/3e28d649-95d4-fe6f-df5b-22ba592274ec.png)

・参考文献
https://docs.vmware.com/jp/VMware-vSphere/7.0/com.vmware.vsphere.storage.doc/GUID-BC1A172C-E649-4812-B8B2-A9E45AC97051.html

３：全体処理構成図
・容量解放処理(unmap)が有効な筐体の選出モジュールの開発（赤文字が担当箇所）
![スクリーンショット 2022-06-16 11.53.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/754596/67086e35-f8fe-ff9a-fbda-b90c9c146199.png)


４：担当箇所詳細（開発箇所）
・①〜④を担当
![スクリーンショット 2022-06-16 14.20.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/754596/9cca43cf-5a21-dd60-1c7e-9704eaa6fd62.png)

・スクリプトの一部をちょいみせ
→構成管理から取得したクラスタ名/Zone情報を基に、既に正規化されたリソース情報とパターンマッチングでZoneごとに上位X件ずつ辞書型でリスト化して返却する関数
![スクリーンショット 2022-06-15 21.20.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/754596/a4451c00-b4ed-c27d-f388-a67fb9c0cb9a.png)

５：苦労/工夫した点（抜粋）
○苦労
・ストレージAPIの仕様、リソース管理 サービスの詳細がわからなかった。
・社内システムの理解があいまい（新人なのでここがヘビーでした、、）。
○工夫
・社内外の関係者を巻き込むことと、とにかく上記2点の理解に時間を費やしました。
・あとは、気合いです（パワー！）



# まとめ
* 今回は、LTでの登壇とその内容について紹介しました。
* 今後も積極的にこういったイベントに参加して自分のしていることについて発信していきたいと思います。
* 発表したことについて、Qiitaでも発信することで振り返りにもなりますし、ここまでを1ショットにしてみてもいいかも知れません。

では、また！
【JavaScript 関数ドリル】中級編のdifferenceBy関数の実装アウトプット

## differenceBy関数の課題内容

\_.differenceBy関数を自分で実装する課題。
https://lodash.com/docs/4.17.15#differenceBy

「課題内容」/「解説動画」/「解答例」を確認したい場合は、以下リンク先のページを参照。
https://js-drills.com/blog/differenceBy/

## 課題に取り組む前の状態

- 解答を見なくてもできそうだと思った。

## 課題に取り組んだ後の状態

- 解答例とは異なるが、サンプル通りの実行結果が出るように実装できた。



## differenceBy関数の実装コード（答えを見る前）

```javascript

function differenceBy(array, values, iteratee) {
    const copiedArray = [...array];
    
    for (let i = 0; i < values.length; i++) {
        console.log(`values[i] : ${values[i]}`);
        for (let j = copiedArray.length - 1; j >= 0; j--) {
            if (iteratee(values[i]) === iteratee(copiedArray[j])) {
                copiedArray.splice(j, 1);
            }
        }

    }
    return copiedArray;
}

console.log(differenceBy([2.1, 1.2], [2.3, 3.4], Math.floor));
// => [1.2]
```

## differenceBy関数の実装コード（答えを見た後）

```javascript
// 同じ
```
100日後くらいに個人開発するぞ！day046

## 今日はメソッドを学んでみた！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2632394/cd7e40ec-c3b8-cb20-8128-0245c59fcab5.png)



## 今日の学び
### メソッドの作り方（定義の仕方）と呼び出し方
* メソッドとは複数の処理を1つにまとめたもの
* 「def メソッド名」と「end」の間にまとめたい処理を書くことでメソッドをつくることができる
    * `def メソッド名`
    * `処理1`
    * `処理1`
    * `end`
* 定義したメソッドを「メソッド名」で呼び出すことができる
    * `メソッド名`


### 引数
* 引数（ひきすう）とはメソッドに与える追加情報
    * メソッドを呼び出すときに一緒に引数を渡すことでメソッドの中でその値を利用することができる


### 引数を受け取るメソッドの定義
* 「def メソッド名(引数名)」とすることで引数を指定することができる
    * `def メソッド名(引数名)`
    * `処理1`
    * `処理2`
    * `end` 
* 引数を渡してメソッドを呼び出したい場合は`メソッド名(値)`と記述する
    * メソッドで指定した値はメソッドの引数に代入される
* 引数はメソッド内では変数のように使用することができる
    * 例
        * `def introduce(name)`
        * `puts "こんにちは"`
        * `puts "私の名前は#{name}です" `
        * `end` 
        * `introduce("山田太郎")`
6.4 (標準) 最尤推定2，推定量の評価1

## 方針

推定量の評価について．最尤法，モーメント法，ベイズ法，．．．などの異なる方法によって得られたパラメータの推定量のうち，どれが最も適切か，という評価基準が必要である．

![知ったこと-65.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1702786/b44daa21-a253-a0b9-2e9b-b38aa788912c.jpeg)

確率変数の台 (定義域) にパラメータが含まれている場合，尤度関数が微分できずイレギュラーなことになる．その例が一様分布．

## 答案

![6. 2周目-11.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1702786/dd58fcd6-fc97-8507-82de-2f40c9bc9d71.jpeg)
![6. 2周目-12.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1702786/7e953c6b-a2f2-ee47-4759-be3ae79f5bc9.jpeg)
![6. 2周目-13.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1702786/fe5ce274-8b27-d0d4-eb0a-35e9ee6cd318.jpeg)

## 参考文献

- 『[現代数理統計学の基礎](https://www.kyoritsu-pub.co.jp/bookdetail/9784320111660)』(久保川達也　著)
WSL2環境でUbuntu20.04を手動インストールしようと思ったら嵌まった件

# 困ったこと
WSL(Windows Subsystem for Linux)環境でUbuntu環境を構築したかったのですが、Microsoft Storeが上手く起動しないので（それは深く追求してないですが）、それなら手動インストールをしてみようと思ったら、がっつり嵌まった話です。
ちゃんとインストールできたように見えるのに、起動するとエラーが発生して、まったく起動しない状況で、何が悪いのかがエラーコードとかでも良く分からずに、とにかく嵌まってました。

# 公式ドキュメント
手動インストールの公式ドキュメントはこちらになります。
決して、この記事が悪い訳ではありません。でも、ちょっと。。。(2022/06/16現在)

https://docs.microsoft.com/ja-jp/windows/wsl/install-manual

# 嵌まったポイント
公式ドキュメントでは、ディストリビューションがいくつもあるのですが、この中で、[Ubuntu 20.04]をダウンロードします。すると、
"CanonicalGroupLimited.UbuntuonWindows_2004.2021.825.0.AppxBundle"
という拡張子のファイルがダウンロードされます。

「ん!?　公式ドキュメントの中には、xxxx.appxって書いてあるけど、なんか違うな。」
「なんかちょっと違うけど、まぁいいや。とりあえず、ダブルクリックして～」
「おぉ。なんかちゃんとインストールが始まったら、まぁ、これでいいんだろうなぁ～」

なのですが、
インストールがちゃんと完了した感じに見えるのですが、実際に、Ubuntuが起動するタイミングで、エラーになって止まりました。エラーメッセージやエラーコードを調べてみても良く分かりません。そして、試行錯誤しながら、トータル丸１日ぐらいモヤモヤと。

# 解決方法
こうすれば自分の環境では上手くいったという話なので、あくまで参考まで。

1. AppxBundle拡張子を、zip拡張子に変更して、解凍します
1. なんと！ 解凍後のフォルダにはappx拡張子のファイルがあります
1. 更に、appx拡張子をzip拡張子に変更して、更に解凍します
1. なんと！ 解凍フォルダには、ubuntu.exeがあります
1. これをダブルクリックするとインストールが始まりました

もしかしたら、appx拡張子のままでも大丈夫だったような気もしますが、環境を構築することが優先だったので、これ以上は深追いしません。

ということで、WSLの手動インストールで嵌まった人は試してみて下さい。
ちなみに、ディストリビューションによっては、appx拡張子でダウンロードされるものもあるので（どちらかというのそちらが多くて、[Ubuntu 20.04] で嵌まりました）、その場合は何も気にせずに上手くいくものだと思います。

まぁ、そもそも手動インストールする人もあまり多くないと思うので、そのせいか全然情報もなくて、途方に暮れてました。もしかしたら、次に嵌まりそうな誰かの為に記事にしておきます(笑)
webarenaでubuntu その59

# 概要
webarenaでubuntu18.04やってみた。
サーバーが重いので調査してみた。

# topコマンド

- 異常なし。

# dfコマンド

- /dev/sda1が１００％

# duコマンド

- du -h max-depth=1 /
- du -h max-depth=1 /var
- du -h max-depth=1 /var/mail
- /var/mail/userが１３G

# ここで、問題

- /var/mail/userは、chmod600で、パスワード不明（記録してるパスワードが通らない）

# （あわてず）passwdでパスワード変更

- sudo passwd user

# userになって、削除

- su user
- cat /dev/null > /var/mail/user


以上。
【Git】チーム開発における使用頻度の低い必須知識をまとめる

# はじめに
現在Git(GitHub)をガンガン触っていく案件にアサインされたのですが、その中でもたまにしか使わない必須知識がいくつかあったので紹介します。

主に自分の振り返り用に書いているので、色々端折ってますがご了承ください。

# git log
■使用タイミング
・ローカルリポジトリのコミット履歴を振り返りたいとき

自分自身git logコマンドの有能なオプションは把握しきれていないのですが、ローカルリポジトリのコミット履歴を追いたい場合は下記コマンドが有効です(他に有能なオプション発見次第追記します)。
```
$ git log --oneline --graph
```

# git reset
■使用タイミング
・リモートリポジトリに誤ってpushしたときに取り消す
・コミット履歴を残さず、前のコミットに戻りたいとき

■使用例
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2320311/de1497af-21ce-ca77-b1a6-3022203ec9ae.png)

上記のように、あなたは間違って重要なリモートブランチにpushしてしまったとします。
```
$ git reset --hard HEAD^
$ git push -f
```

しかし上記を行ってGitHubを見てみると最新のコミット履歴が無くなります。

# git revert
■使用タイミング
・誤ってリモートリポジトリのプルリクを打ち消したいとき
・コミット履歴を残したまま、前のコミットに戻りたいとき

■使用例
git revertではgit pushと違い、以前のコミット履歴を打ち消すコミットを作成してリモートリポジトリにpushすることでpush履歴を残したまま以前のコミットに戻ることができます。
```
$ git revert "直前コミット"
$ git push
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2320311/482649ad-977b-efce-ff3c-e43d758b8d7b.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2320311/ff5917a2-984f-d4e6-4941-3a6deadb8e01.png)

そして他にもマージの取り消しも行えます。
```
# ブランチを新規で作成する
$ git revert -m 1 "取り消したいマージコミット"
$ git push
# 上記ブランチをプルリク
# 元に戻る!!
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2320311/55ef389c-d6bf-712f-3d3b-8e99e276359e.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2320311/5cd72dc2-76ac-aaf1-9cda-21ff4bd8d4ec.png)

めちゃ簡単ですよね。

一応、「git reset --hard HEAD^」→「git push -f」のコンボでマージ前のコミットに戻ることは可能ですが、masterブランチにて作業する必要があるの(コミット履歴も残らない)と、別ブランチを切る場合はプルリク出せなくなるので実務ではgit revert一択だと思います。

# git mergeとgit rebaseについて
git mergeするとコミット履歴は以下となる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2320311/80a5e1eb-d5d9-8794-cfb7-dad4a7862c98.png)

しかし、git rebaseするとコミット履歴は以下となる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2320311/d64561cb-5f1a-a041-4574-a79dcc963a50.png)
扱いが難しくリモートにpush済みの場合は、使用に向いていないらしく中級者向けと言えます。

# git squash
下記のように微修正コミットが複数ある場合に、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2320311/20e1c1fb-f41b-c0b8-b0ae-9687dc5f2cc6.png)
```
$ git rebase -i "まとめたいコミットより1つ前のコミット"
# viにてコミットをまとめて、コメントを修正する
```
を行うと、下記のようにすっきりします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2320311/47ca2c17-ad22-f2a9-bcae-141903037641.png)

# まとめ
git難しいけど面白い！！
適宜ノウハウを更新します。
半日でホームページデザインを学ぶ

プログラミングを始める人はまずWeb系がおすすめです

HTML、CSSをを学んでそこからJavaScript やPHP、Rubyなどを習得スるればフリーとしても活動しやすいです

そこでちょっと学習サイトをご紹介

# ドットインストール
かなり有名ですね
月額制の会員登録をすればかなりのレッスンを受講できます
https://dotinstall.com/home

# Udemy
ドットインストール同様動画系の学習サイトです
いろんな講師の方が教材を売ってるって具合ですね
脱初心者には最適ですが教材の良し悪しは「講師による」
としか言えないのでレビューなどはしっかり見ましょう
https://www.udemy.com/

# HeiPro
昨日リリースしました
僕の作った学習サイトです
要点を絞り短期集中型で学びます
1日でRailsのメモアプリやHPデザインが学べます
すべて無料ですので覗いてみてください
https://heipro.site/
二重for文②　九九表

<!DOCTYPE html>
<html>
<head>
<title></title>
</head>

<body>
<h2>実行結果</h2>

![スクリーンショット 2022-06-16 5.43.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2133160/df839c2a-e9d0-56e0-fe91-d04e317e7404.png)

<h2>コード</h2>

```java
public class Main {
	public static void main(String[] args) {
		for(int i=1; i<=9; i++) {
			for(int j=1; j<=9; j++) {
                System.out.printf("%d*%d=%-4d",i,j,i*j);
                //Sysyem.out.printf(書式, 引数1, 引数2, ....)
            }
            System.out.println("");   
        }
    }
}
```
</body>
</html>
二重for文①　山型グラフ（累乗）

<!DOCTYPE html>
<html>
<head>
<title></title>
</head>

<body>
<h2>実行結果</h2>

![スクリーンショット 2022-06-15 21.19.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2133160/a1a45aa0-6b8e-b9fa-e1e0-8c6ea61abb42.png)

<h2>コード①：二重for文を2つ使う場合</h2>

```java
public class Main {
	public static void main(String[] args) {
		for(int i = 0;i < 10;i++) {
			System.out.print(i + ":");
			for(int j = 0;j < i*i;j++) {
				System.out.print("◯");
			}
			System .out .println("（" + i*i + "）");
		}
		for(int i = 8;i >= 0;i--) {
		    System.out.print(i + ":");
		    for(int j = 0;j < i * i;j++) {
		    	System.out.print("◯");
		    }
			System .out .println("(" + i * i + ")");
		}
	}
}
```
<h2>コード②：Math.abs()メソッドを使う場合</h2>
<p>※『Math.abs()』絶対値を取得するメソッド</p>

```java
public class Main { 
	public static void main(String[] args) {
		for(int i = -9;i <= 9;i++) {	
			int k =9-Math.abs(i);
			System.out.print(k + ":");
			for(int j = 0;j < k*k ;j++) {
				System.out.print("◯");
			}
			System .out .println("(" + k * k + ")");
		}
	}
}
```
</body>
</html>
レガシーな CI/CD をちょっとだけオシャレにする

# 背景
## レガシーなCI/CD例
コードを Github に push し、EC2 上でブランチを指定してデプロイする仕組み
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22939/35085e32-9df9-5ffc-ad81-0cf18e490bb9.png)

そもそもCIの概念があるのかは微妙ですが、EC2/踏み台EC2 に SSH してデプロイスクリプトを実行しているようなケースを未だに運用していたりしないでしょうか。（PHPだとDeployer使う等）


# 課題
一番の課題は EC2 に SSH するという部分です。
簡単に思い付くだけでも以下のデメリットがあります。

- 接続用のSSHアカウントを管理する必要がある
- 必要に応じて接続アカウントにキーペアを設定する必要がある
- SSH の接続に対してアクセス制限を設定する必要がある

実はこれだけでも運用コストからみればチリツモです。
 
# 解決
Github 使ってるなら CodeBuild 等で運用を重くするよりも開発チームだけで解決できるようにしましょう。
## ちょっとだけオシャレなCI/CD
コードを Github に push すれば自動でデプロイする仕組み
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/22939/6110ea2a-ef99-c0cb-1718-9e7891c2dc02.png)

## Github Actions 例
```.github/workflows/deploy.yml
name: AWS SSM Send-Command Example

on:
  push:
    branches: main

jobs:
  start:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v2

      - name: AWS SSM Send-Command
        uses: peterkimzz/aws-ssm-send-command@master
        id: ssm
        with:
          aws-region: ${{ secrets.AWS_REGION }}
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          instance-ids: ${{ secrets.INSTANCE_ID }}

          working-directory: /home/ubuntu
          command: deployer.sh
```

### IAMユーザーの必須ポリシー
```
{
   "Version":"2012-10-17",
   "Statement":[
      {
         "Effect":"Allow",
         "Action":[
            "ssm:SendCommand"
         ],
         "Resource":[
            "arn:aws:ec2:*:*:instance/*",
            "arn:aws:ssm:*:*:document/*"
         ]
      }
   ]
}
```


# 一言
少しでも運用コストを下げ、インフラ側の負担を減らしましょう。
SSHしたら負けですよ！