OmniAICreator/Qiita-1.07M huggingface dataset:
「Crawling Chaos」 ksnctf Writeup

# 問題
画像のようなWebページが与えられます。
![スクリーンショット 2023-06-29 202209.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576161/1f56b1cf-c37b-de79-8013-5ba2f09095b1.png)

# 解法
ソースコードを確認してみると怪しいスクリプトがいました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576161/34e04c4c-fa51-532a-5ee3-62df5898ee46.png)


とりあえずスクリプトをコピーして[Paiza](https://paiza.io/ja)にブチ込んでみると、スクリプトをデコードした文字列が出てきました。
![スクリーンショット 2023-06-29 204054.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576161/b95030cc-f824-3761-ae1b-2c72e27bf171.png)

軽く整形します。
```Javascript
$(function(){
    $("form").submit(function(){
        var t=$('input[type="text"]').val();
        var p=Array(70,152,195,284,475,612,791,896,810,850,737,1332,1469,1120,1470,832,1785,2196,1520,1480,1449);
        var f=false;
        if(p.length==t.length){
            f=true;
            for(var i=0;i<p.length;i++)
                if(t.charCodeAt(i)*(i+1)!=p[i]) 
                    f=false;
                if(f)alert("(」・ω・)」うー!(/・ω・)/にゃー!");
        }
        if(!f)alert("No");
        return false;
    });
});
```
どうやら`var t=$('input[type="text"]').val();`でテキストボックスに入れた文字列を変数`t`に格納してから`if(t.charCodeAt(i)*(i+1)!=p[i])`のif文で変数`p`内Arrayの整数と比較しているようです。
比較した文字列が一致していると`alert("(」・ω・)」うー!(/・ω・)/にゃー!")`するみたいです。


charCodeAt()メソッドで数値に変換するときに、for文のインデックス`i`を乗じていることに注意して、Pythonで`Array`を文字列に変換するコードを書いてみると、次のようになります。

```python
Array = [70,152,195,284,475,612,791,896,810,850,737,1332,1469,1120,1470,832,1785,2196,1520,1480,1449]

for i in range(len(Array)):
    print(chr(int(Array[i] / (i+1))), end="")
```

無事にフラグが出ました。
![スクリーンショット 2023-06-29 212401.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576161/444e563c-b120-3698-bfb7-cdd8769d7f6c.png)


# 関連
https://kusano-k.hatenadiary.com/entry/20120421/1335006525

https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/String/charCodeAt

https://docs.python.org/ja/3/library/functions.html#chr
EC2 Instance Connect Endpoint経由でElastiCacheにも接続しちゃう話

# 背景

Twitter でプロフィール写真変えているのにここではそのままになっている [@\_\_\_nix___](https://twitter.com/___nix___) です。

さて、

[EC2 Instance Connect Endpoint経由でRDSに接続してみた](https://dev.classmethod.jp/articles/how-to-connect-rds-instance-via-eic-endpoint/) 

の記事から始まり、次のステップとして

[[祝!]EC2 Instance Connect Endpoint経由でRDS(3389)に接続できた話](https://zenn.dev/nix/articles/d40566d33a2791)

までできましたね。

更に先に進みましょう。

# 何するの？

前回は RDS に接続できたので、今回は ElastiCache に接続してみましょう。

# 構築手順

基本的な手順は同じですのでこちらも併せてご覧ください。
[[祝!]EC2 Instance Connect Endpoint経由でRDS(3389)に接続できた話](https://zenn.dev/nix/articles/d40566d33a2791)

## ElastiCache と VPCエンドポイント用に SecurityGroup を準備
ここでも省略しますが、クラメソさんの記事を参考にしてください。

## ElastiCache(Redis) を構築
もちろん 3389 ポートで。
![](https://storage.googleapis.com/zenn-user-upload/646046e18689-20230630.png)

## VPCエンドポイントも構築
こちらのスクショも使い回しです。
![](https://storage.googleapis.com/zenn-user-upload/ea966bec4c78-20230629.png)


## ElastiCache(Redis) のプライベートIPを調べる

```
host xxxxxxxx.xxxxxx.ng.0001.apne1.cache.amazonaws.com
172.31.62.7
```

## VPCエンドポイントのIDを調べる
これはAWSマネージドコンソールから取得してください。

## open-tunnel を実行
3389 を 13389 にポートフォアディングします。

```
/usr/local/bin/aws ec2-instance-connect open-tunnel --instance-connect-endpoint-id eice-0af4f69191c240d32 --private-ip-address 172.31.62.7 --local-port 13389 --remote-port 3389 &
```

以下のメッセージが出ればOKです。

```
Listening for connections on port 13389.
```

## redis-cli で接続してみる
もうここまで来るとドキドキはありません。

```
redis-cli -h 127.0.0.1 -p 13389
[1] Accepted new tcp connection, opening websocket tunnel.
127.0.0.1:13389> ping
PONG
127.0.0.1:13389> quit
[1] Closing tcp connection.
```

はい、接続できちゃいました。

# 編集後記

基本的にポートを変更できて 22 か 3389 に変更できるAWSリソースであれば接続できてしまうのではないかと思われます。

AWSリソースへのアクセスだけでなく、色々と想像が膨らむわけですが、これ以上の詮索はやめておきましょう。

:::note alert
悪い使い方はせずに正しく使おう！
:::
【SwiftUI】Viewを画像として保存する(iOS16)

# はじめに
Viewを画像として保存する時の方法を記事にします

# 前提
画像を保存するためにはユーザーからの許可が必要です。
リクエストを表示させるために、以下のキーをInfo.plistにセットします
```
Privacy - Photo Library Usage Description
```

![スクリーンショット 2023-06-30 20.44.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1745371/40db01c7-86ef-f713-af53-44a02ad8b0fd.png)

# 実装
```swift
import SwiftUI

struct ContentView: View {
    @Environment(\.displayScale) private var displayScale
    
    var body: some View {
        VStack(spacing: 50) {
            sampleView()
            
            Button {
                if let image = render() {
                    UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil)
                }
            } label: {
                Text("保存")
            }
        }
    }
    
    private func sampleView() -> some View {
        Text("テスト")
            .font(.largeTitle)
            .foregroundColor(.white)
            .frame(width: 400, height: 250)
            .background(Color.green, in: RoundedRectangle(cornerRadius: 10))
    }
    
    @MainActor
    func render() -> UIImage? {
        let renderer = ImageRenderer(content: sampleView())

        renderer.scale = displayScale

        return renderer.uiImage
    }
}
```

# 解説
ここが保存したいViewです。
メソッドとして定義しています。
```swift
private func sampleView() -> some View {
    Text("テスト")
        .font(.largeTitle)
        .foregroundColor(.white)
        .frame(width: 400, height: 250)
        .background(Color.green, in: RoundedRectangle(cornerRadius: 10))
}
```

ここで`sampleView()`をUIImageに変換しています。
```swift
@MainActor
func render() -> UIImage? {
    let renderer = ImageRenderer(content: sampleView())

    renderer.scale = displayScale

    return renderer.uiImage
}
```

ここでUIImageを端末に保存しています。
```swift
if let image = render() {
    UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil)
}
```

# ドキュメント
https://developer.apple.com/documentation/swiftui/imagerenderer

# おわり
iOS16から`ImageRenderer`が使用できるようになったので簡単にViewを保存することができるようになりました。

透過させた画像を保存したい場合は↓こちら！！

https://qiita.com/SNQ-2001/items/5db16728ac7c39072ba9
Sentry Session Replay を使ってみた

最近、Sentryのバージョンを上げたのですが、Session Replayが追加されていました。
調べてみると、ページでのアクションを動画のように再現し、エラー発生直前の状況を確認する機能とのことで、実際にローカル環境で動かして使ってみました。
[Session Replay document](https://docs.sentry.io/product/session-replay/?original_referrer=https://d-publishing.sentry.io/)

## 導入方法
以下のリンクにある”Set Up”の説明が非常にわかりやすく、簡単に導入できました。
すでにSentryを導入している場合は、約10分程度で動作確認まで出来るかと思います。
[Set Up](https://docs.sentry.io/product/session-replay/getting-started/?original_referrer=https://d-publishing.sentry.io/)

## 実際のキャプチャー
![qiita_sentry-replay.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2513666/afbbb3c6-8fde-de3e-6b5b-04e2ba5dbaca.gif)


## 料金
トランザクションやエラーと同様、従量課金です。以下リンクのReplays Pricingに料金が記載されています。
[Pricing & Billing](https://docs.sentry.io/product/accounts/pricing/)

## 感想

めちゃくちゃ見やすいです！エラーが発生した直前のフローが確認出来るため、エラーの再現がよりやりやすく、また、さまざまなログがより見やすくなっています。

別料金が発生するため、運用を考える必要があります。リプレイはエラーよりも料金あたりの数が少ないのでエラーと同じ数リプレイすると料金が跳ね上がります。低い倍率でキャプチャーするのもいいですが、これまで原因がわからなかったものなど特定のエラーに対してキャプチャーするのもいいなと思いました。
LVM 論理ボリューム

1.fdiskでパーティション/dev/sdb6, /dev/sdb7 をつくる
2.pvcreate /dev/sdb6 /dev/sdb7 物理ボリューム
3.vgcreate /dev/sdb6 /dev/sdb7 datagroup datagroupというボリュームグループ作成
4.lvcreate -n data1 -l 30%FREE datagroup  datagroupの30％をdata1に割り当て。
lvcreate -n data2 -l 30%FREE datagroup  datagroup
lvcreate -n data3 -l 40%FREE datagroup  datagroup
5.mkfs /dev/datagroup/data1    システムファイル作成
6.mount /data/datagroup/data1  /mnt/data1 マウント
```
[root@localhost datagroup]# pvs
  PV         VG        Fmt  Attr PSize    PFree  
  /dev/sda2  centos    lvm2 a--   <19.00g   4.00m
  /dev/sdb6  datagroup lvm2 a--  1020.00m   8.00m
  /dev/sdb7  datagroup lvm2 a--  1020.00m 592.00m
[root@localhost datagroup]# vgs
  VG        #PV #LV #SN Attr   VSize   VFree  
  centos      1   2   0 wz--n- <19.00g   4.00m
  datagroup   2   3   0 wz--n-   1.99g 600.00m
[root@localhost ~]# lvs
  LV    VG        Attr       LSize   Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert
  root  centos    -wi-ao----  17.49g                                                    
  swap  centos    -wi-ao----   1.50g                                                    
  data1 datagroup -wi-a----- 612.00m                                                    
  data2 datagroup -wi-a----- 428.00m                                                    
  data3 datagroup -wi-a----- 400.00m   
```
```
[root@localhost ~]# df 
Filesystem                  1K-blocks    Used Available Use% Mounted on
devtmpfs                      1430580       0   1430580   0% /dev
tmpfs                         1447504       0   1447504   0% /dev/shm
tmpfs                         1447504   10572   1436932   1% /run
tmpfs                         1447504       0   1447504   0% /sys/fs/cgroup
/dev/mapper/centos-root      18331648 5466620  12865028  30% /
/dev/sdb1                     1032088    1284    978376   1% /usbmemory2
/dev/sda1                     1038336  230796    807540  23% /boot
tmpfs                          289504      24    289480   1% /run/user/1000
/dev/sr0                      9961428 9961428         0 100% /run/media/linuxstudy/CentOS 7 x86_64
/dev/mapper/datagroup-data1    616824     480    585012   1% /mnt/data1
```
echo の出力先は標準出力ではないという話

## echo は標準出力に書き込むという錯覚
PHP のサーバーサイドプログラミングをしているときに次のようなコードを書くと、出力がレスポンスボディに書き込まれて本来の内容と混ざってしまいます。

```php
echo "hoge"; // レスポンスボディに "hoge" と書き込まれてしまう
```

この挙動をみて、Apache や PHP-FPM はスクリプトの標準出力の内容からレスポンスボディを生成しているんだと私は勝手に納得していたのですが、これは間違いだったという話です。

## echo の出力先は出力バッファ
`echo` は標準出力とは別の出力バッファ (`php://output`)
 と呼ばれるバッファに書き込みます。この出力バッファの内容がレスポンスボディになるということみたいです。

そのため `echo` を使うとレスポンスボディと混ざる一方で `php://stdout` や `php://stderr` への出力は混ざらないということでした。

```php
echo "hoge"; // 混ざる

// Laravel
Log::info("fuga"); // 混ざらない

$stdout = fopen('php://stdout', 'a');
fwrite($stdout, "piyo"); // 混ざらない
fclose($stdout);

$output = fopen('php://output', 'a');
fwrite($output, "saga"); // 混ざる
fclose($output);
```
素人でも思う，原理原則

> 新たな誤交付は福岡県宗像市の庁舎内に設置した端末で28日に発生。住民票の写しを申請した利用者に、直前に発行した別人の住民票が交付された

新たな処理を始める前に，必要な初期化をするというのは当たり前の手順じゃないのかなあ？と素人は思いますが。
(リンクだけです)「Mathematicaの楽典(がくてん、英: musical grammar)」を調べてみたい。

# Mathematicaで 

https://search.wolfram.com/?q=music+&skip=

https://www.wolframalpha.com/input?i=music&lang=ja

# wikipediaで 
楽典（がくてん、英: musical grammar）

https://ja.wikipedia.org/wiki/%E6%A5%BD%E5%85%B8

??? wikipediaの英語版がありませんでした。???

# google 検索で

https://www.google.com/search?q=%E6%A5%BD%E5%85%B8&rlz=1C1GCEB_enJP1054JP1054&oq=%E6%A5%BD%E5%85%B8&aqs=chrome..69i57j35i39i650l2j0i512l7.4873j0j7&sourceid=chrome&ie=UTF-8

https://www.google.com/search?q=musical+grammar&rlz=1C1GCEB_enJP1054JP1054&oq=musical+grammar&aqs=chrome..69i57j0i15i19i30l2j0i5i15i19i30j0i5i19i30l2j0i8i19i30l4.767j0j7&sourceid=chrome&ie=UTF-8


# 勉強中

https://jp.yamaha.com/services/music_pal/study/chord/name/index.html

"三和音"は、wolframalphaにありませんでした。
以下、正しいのか間違っているのか？アドバイスいただくと幸いです。

・ハ長調（C Major / シーメジャー）

https://search.wolfram.com/?query=%E3%83%8F%E9%95%B7%E8%AA%BF&source=GUIHeader
https://search.wolfram.com/?q=C+Major&skip=

https://www.wolframalpha.com/input?i=%E3%83%8F%E9%95%B7%E8%AA%BF&lang=ja
https://www.wolframalpha.com/input?i=C+Major&lang=ja


続く...

# 参考
＞ページは、楽典を学習する人のためのページです。

https://xn--i6q789c.com/


# 2の12乗根(英:Twelfth root of two)

楽典の本で、通称 黄色い本(p16?)、白い本と言うそうです。

https://ja.wikipedia.org/wiki/2%E3%81%AE12%E4%B9%97%E6%A0%B9

https://en.wikipedia.org/wiki/Twelfth_root_of_two

＞２つ上のウィキペディアで、既に計算されていました。

https://www.wolframalpha.com/input?i=Twelfth+root+of+two&lang=ja

#### 数Ⅱの教科書より

＞教科書701 音と正弦曲線　P156

＞教科書705　音の高さと楽器の形　r^12=2すなわち rの値は、1.06

# 参考文献
＞1965年に出版され、いまだに人気のテキストです。「黄色い本」と呼ばれています。

https://classical-music.fun/6-recommended-books-for-learning-musical-grammar-beginner-intermediate-advanced/

＞2020年度 入試問題付 音大・音高受験生のための楽典 THEORY&LESSON 単行本 – 2020/12/17


www.amazon.co.jp/dp/4938986728
[Tip] ガードチョイスで "値が空のセル" を特定するファインダー設定の方法。

## 課題

- CSSセレクターを使ったコンポーネント指定ではタグに囲まれたテキスト コンテンツの内容までは判断できません。
- テキスト コンテンツに1文字以上の文字列が含まれていれば `テキスト一致（Regex）` による条件設定がテキストで可能です。
- 「空の値」を判断するために `テキスト一致（Regex）` で条件を設定する際、マッチングモードを `子孫のないテキスト` / `子孫のあるテキスト`[^1] にして Regex に `^$` （空文字）を指定しても、式（`=""`）を指定してもロケーションが特定できません。

[^1]: `子孫のないテキスト` 選択したコンポーネントの直下のテキストコンテンツ（ノード要素内）でテキストを検索します。配下の要素は無視されます。
`子孫のあるテキスト` 選択したコンポーネント配下のすべての子孫となる子要素を含めたテキストコンテンツ内でテキストを検索します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3090491/c7dea42c-0a05-f3b7-3050-3364b552a445.png)


:::note
本記事は、BizRobo! v11.3.0.2 の利用を前提に解説します。
:::

## 対応方法

- マッチングモードを `ツリー` に変更して、ツリーの要素ごと `<.*?></Cell>` と設定することで認識します。
- `<Cell.*?></Cell>` でも `^<Cell.*?></Cell>$` でも構いません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3090491/f18c8004-77b9-7aa5-ec24-e142160b1cd4.png)

### 参考情報

マニュアルから `テキスト一致（Regex）`を利用する際の `マッチングモード` の説明を引用します。

> すべてのタイプのコンポーネント ファインダーに、オプションの [テキスト一致 (Regex)] セレクターがあります。前述のセレクターを使用して、見つかったコンポーネントの中で一致するテキスト コンテンツを検索します。含まれるコンテンツのみで変化するエレメントを識別するには、[テキスト一致 (Regex)] が便利です。
たとえば、コンポーネント セレクターで `OK ボタン` と`キャンセル ボタン` が検出された場合、テキスト セレクターは「キャンセル」というテキストを識別して、的確にキャンセル ボタンを見つけ出します。テキスト セレクターは、正規表現の構文を使って記述されます。テキスト セレクターには、次の検索モードがあります。
> 
> `子孫のないテキスト`：選択した 1 つのノード要素内でテキストを検索します。ネストされた要素または子要素は無視されます。
> 
> `子孫のあるテキスト`： 選択したノードとそのすべての子孫となる子要素内でテキストを検索します。
> 
> `ツリー`： アプリケーション ツリーを XML に変換し、選択したノード内でタグと属性を含めて全文検索を実行します。

## まとめ

仕様か不具合かわかりませんが、備忘として。
ABC307 - A - Weekly Records

# 問題
https://atcoder.jp/contests/abc307/tasks/abc307_a

# 考察
1週間ごとの歩いた歩数を集計してくださいという問題です。`for`文を使って7日ごとに集計を行っていくのがいいと思います。$i$週目の$j$日目という2つの変数を2重ループで回すと集計しやすいです。配列$A$には、$A_{i×7+j}$で任意の日にちにアクセスできます。

※問題では1-indexedで表記していますが、C++の都合上、0-indexedで考察を書いてます。

# 提出コード(コンテスト後)

https://atcoder.jp/contests/abc307/submissions/43065414

ご不明点などがあれば教えていただけると幸いです。
アレクサでPCを起動する Wake-on-LANの設定方法

# はじめに

　いつのまにかアレクサスキルにWake on lan(以下,WoL)が追加されていました。
この機能はネットワークを通じてPCを起動可能にするものです。作者の方に感謝です。
実際に設定して試してみたので、備忘録を記しておきます。

# 参考
以下のページに従って設定しました。

[github: somq14/alexa-wake-on-lan](https://github.com/somq14/alexa-wake-on-lan/blob/master/README.md)

[eizone.info: Windows10/ Windows11 の Wake On Lan （WOL）設定](https://eizone.info/window-wake-on-lan/)

[n-Archives.net: 起動される側のPCのWOL設定(2/3)：Windows ネットワークアダプタの設定](https://n-archives.net/software/nwol/wol-pc-setting/windows-setting.html)

[デジカン: ASRockのマザーボードでWOLできない人はここをチェック](https://mimimopu.com/asrock-mb-wol/#:~:text=%E5%BF%85%E8%A6%81%E3%81%AA%E8%A8%AD%E5%AE%9A%E3%81%AF%5B%E3%82%A2%E3%83%89%E3%83%90%E3%83%B3%E3%82%B9%E3%83%89,%E3%81%AB%E3%81%99%E3%82%8B%E3%81%A0%E3%81%91%E3%81%A7OK%E3%80%82&text=%E3%81%93%E3%82%8C%E3%81%A7WOL%E3%81%A7%E8%B5%B7%E5%8B%95%E3%81%A7%E3%81%8D%E3%82%8B%E3%82%88%E3%81%86%E3%81%AB%E3%81%AA%E3%82%8A%E3%81%BE%E3%81%97%E3%81%9F%E3%80%82)

# 環境
M/B：AsRock B450 Steel Legend
OS：Windows 11 Pro 22H2
Alexa：Echo Dot第2世代

# 設定方法

1. BIOS/UEFIでWoLを有効化
1. ネットワークアダプタでWoLを有効化
1. アレクサスキルの設定

## 1. BIOS/UEFIの設定
　BIOS/UEFIを起動して、WoLを有効にします。メーカーごとに設定が異なります。
AsRockのM/Bを使っている人は次の設定に気をつけてください。私は引っかかりました。

誤った設定：UEFIの「起動」タブ->「オンボードLANからブート」->有効
正しい設定：「アドバンスド」タブ->「PCIEデバイス電源オン」->有効

誤った設定はWoLと関係のないPXEブートの有効化でした。

## 2. ネットワークアダプタの設定

「デバイスマネージャ」から「ネットワークアダプター」を開き、使用しているものをダブルクリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/455608/4dac3b75-d583-ead9-298f-f71f36a45471.png)

ネットワークアダプタの「詳細設定」タブを開き、Wake on Lan関連の設定を有効化します。
　　「Wake on magic packet when system」->有効
　　「WOLとシャットダウンリンク速度」->10 Mbps優先
　　「ウェイク・オン・パターン・マッチ」->有効
　　「ウェイク・オン・マジック・パケット」->有効


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/455608/1c225ae6-58c0-c112-901e-c4a3e4ea4798.png)

「電源の管理」タブの「Magic packetでのみ、コンピューターのスタンバイ状態を解除できるようにする」にチェック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/455608/e78d2fc3-df5e-1d4a-0c7f-cddbcf7ad423.png)

## 3. アレクサスキルの設定
始めに「https://wol.somq14.net/ 」にAmazonアカウントでログインします。
「+新しいパソコンを登録する」をタップし、先程のネットワークアダプタのMACアドレスを入力します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/455608/782eb614-936d-e0a3-1552-f3da2f5883e5.png)


次にアレクサアプリを起動し、下部の「その他」->「スキル・ゲーム」をタップします。
「Alexaスキルを検索」から「Wake-on-LAN」を探します。
「有効にして使用する」をタップしてしばらくすると完了です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/455608/abbfca2a-fcdf-16bf-a7b9-ca3dc609bee5.png)


# まとめ
アレクサスキル「Wake-on-LAN」の設定の仕方を記しました。
誰かの役に立てば幸いです。
python maya delete keys

```python
import maya.cmds as cmds

def GetAllByType(selType="joint"):
    all_curves = cmds.ls(type=selType, ni=True, o=True, r=True, l = True)
    curves_transforms = cmds.listRelatives(all_curves, p=True, type = "transform")
    return curves_transforms


joints = GetAllByType("joint")
cmds.select(joints)
    
mySel = cmds.ls(sl=1)

test = []
try:
	test += cmds.listConnections(mySel,s=True, type="animCurveTU")
except:
	pass
try:
	test += cmds.listConnections(mySel,s=True, type="animCurveTL")
except:
	pass
try:
	test += cmds.listConnections(mySel,s=True, type="animCurveTA")
except:
	pass

cmds.delete(test)
```
はじめましてのデザインスプリント

最近案件でデザインスプリントを取り入れようという話になりました。ただいま絶賛お勉強中です。今回は、簡単にその概要をまとめます。

※以下、机上の知識ベースでまとめてます。実践していく過程で理解が深まったら加筆修正するかもです。

## 前提：デザインスプリントとは？

### デザインスプリント

#### 概要: 
- [デザイン思考](#デザイン思考とは)を業務に組み込むために行われる、5つのプロセスからなる仕組み
#### 特徴:
- ユーザー中心主義(User-centred)
    - 全ての過程において、ユーザー視点で物事を考えていく。
- 役割の垣根を超えた共働(Interdisciplicnary)
    - 関係者全員を一か所に集めて行うのが理想。また参加者間に上下関係などない状態が理想
- 時間の制約がある(Time-constrained)
    - 正当なやり方だと、学校の時間割のように、時間ごとにやるべきタスクが区切られている。（必ずしもそれに従わなければいけない訳ではないようだけども…というのは後述。）
- 反復的なプロセス(Iterative)
    - 実現可能性に関わらず、限られた期間内で、問題解決のための創造的な方法を模索、開発、反復していく
- コラボレーション(Collaborative)
    - チームメンバーの貢献を引き出すことを重要視
   
### デザインスプリントの5ステップ

|日にち|フェーズ|概要|関連ツールなど|
|--|--|--|--|
|1|理解|ユーザーが解決したい課題を定義・分析|ユーザーインタビュー、データ分析、競合調査、課題定義、専門家|
|2|発散|課題解決のためのアイデアを出しまくる|アイデア出し（[クレイジー8](https://goodpatch.com/blog/crazys8)など）、ストーリーボード(アイデア可視化のため)|
|3|決定|アイデアを絞る|取捨選択、ワイヤーフレーム（webシステムなどの場合）|
|4|試作|アイデアを形にする|UIデザイン、プロトタイプ制作|
|5|検証|アイデアが正しく形にできるか（定義した課題解決できているか）テストする|ユーザビリティーテスト、テスト結果分析、仮説検証|

### 実践する上での注意点

グッドパッチのブログによると…

1. ログの記録・確認をしながら進める
    - デザインスプリントは、半永久的に継続するプロセスなため。記録を残さないと、忘れてしまう
        - 特に、クライアントや、新しい人がいる時は要注意 
2. 適切な仮説を選定
    - プロトタイプを使った仮説検証が最後のプロセスにあることを意識し、その実行ができるスコープ内での仮説にする
        - 自問すべき質問
            - 検証できる仮説か？
            - プロトタイプにおとしこめるだけのボリュームになっているか？
            - 十分具体的か？（ユーザーの行動レベルまで落としこめているか？） 
3. プロトタイプの精度とスピード感を意識
    - 精度に関しては、なるべくリアルなプロトタイプを目指す
        - システムであれば、紙でできた紙芝居よりは、専用ツールでデザインされたもの　等々
            - テストで用いられることが多い思考発話法（プロトタイプテスト中、ユーザーの考えや感じたことを話しながら行う）は、リアリティがないと、精度が低くなってしまう
    - かなりのスピード感が求められるので、覚悟！
4. ビジュアルは改めて検討する
    - 必要に応じて、改めて時間を確保して改善する方がよい

※このあたり、自分のチームでデザインスプリントを回していくことで、違った気づきや学びを加筆修正していきたいと思っています！

https://goodpatch.com/blog/designsprint-tips

#### デザイン思考とは？

> 「デザイン思考」とは、デザイナーやクリエイターが業務で使う思考プロセスを活用し、前例のない課題や未知の問題に対して最適な解決を図るための思考法

https://www.hrpro.co.jp/series_detail.php?t_no=2472

- デザインスプリントは、この思考法を実現する方法論の一つ
    - ちなみに、デザイン思考も、共感-定義-概念化-試作-テスト　という5段階のプロセスからなる
    - 背景にあるのは、今の市場の変化の激しさ。このような環境下では、従来のような仮説検証型（リサーチ->仮説->実践・実証）のアプローチではうまくいかないことも
        - 理由は、実践・実証の段階に行く前に、前提や環境が変化してしまうこともあるため。最初に解決すべきと思っていた課題自体が変化してしまうので、その解決策も通用しなくなってしまう。
    - そのような環境下でも、より価値のある解決策を作り続ける、それがデザイン思考！
        - そんなデザイン思考を効率的に実行する為の方法論、それがデザインスプリント！


##  おまけ

### 便利そうなツールなどへのリンク

英語だと、便利そうなツールが出てくるので、ついでに置いておきます。

- [The Design Sprint by SPRINT](https://www.thesprintbook.com/the-design-sprint)
    - [SPRINT 最速仕事術――あらゆる仕事がうまくいく最も合理的な方法](https://www.amazon.co.jp/-/en/%E3%82%B8%E3%82%A7%E3%82%A4%E3%82%AF%E3%83%BB%E3%83%8A%E3%83%83%E3%83%97/dp/447806699X/ref=pd_bxgy_sccl_1/357-1875358-4910528?pd_rd_w=s2NPI&content-id=amzn1.sym.bc57a5ab-9f02-4944-8c5c-9e1696e0d32c&pf_rd_p=bc57a5ab-9f02-4944-8c5c-9e1696e0d32c&pf_rd_r=BM2X54AZ12QRXFRKQD22&pd_rd_wg=l2fDx&pd_rd_r=b880abf7-78cc-4a73-938b-c6e9734f49f2&pd_rd_i=447806699X&psc=1)の著者によるツールや、デザインスプリントの概要まとめ
- [Design Sprint Kit by Google](https://designsprintkit.withgoogle.com/)
Go vs Java: メモリ管理とランタイムの違い



## はじめに
プログラムを書く言語はたくさんあり、それぞれの言語はメモリ管理に独自のアプローチを取ります。この記事では、GoとJavaのメモリ管理とそれぞれのランタイム環境について詳しく解説します。

## メモリの基本
プログラムを実行すると、新しい変数を作るたびにメモリが割り当てられます。このメモリ空間には、変数のデータが保存されます。RustやCなどの言語では、メモリ管理はほぼ手動です。これらの言語では、プログラムが直接メモリを割り当て、後でそのメモリを解放します。

## Javaとメモリ管理
Javaはガベージコレクションを行う言語で、メモリ管理は自動化されています。Java Virtual Machine（JVM）がメモリの割り当てと解放を行います。Javaプログラムを実行すると、JavaバイトコードがJVM内で動作する小さな仮想マシンが作成されます。これは、Javaプログラムが複数のプラットフォームで実行可能にする一方で、実行時のオーバーヘッドを生み出します。

## Goとメモリ管理
GoはJavaと同様にガベージコレクションを行う言語ですが、Javaとは違い、JVMは存在しません。代わりにGoのコンパイラは、ソースコードを直接ネイティブコード（マシン語）にコンパイルします。このネイティブコードは特定のハードウェアとオペレーティングシステムで直接実行可能な形式です。

Goでは、Javaのようにソースコードを最初にバイトコードにコンパイルするステップはありません。そのため、Goの実行時のオーバーヘッドはJavaよりも少ないです。しかし、このアプローチによりGoのプログラムはコンパイルしたプラットフォーム専用になります（つまり、Linux用にコンパイルしたGoのプログラムはWindowsでは直接実行できません）。これが、JavaとGoのメモリ管理と実行時の違いです。

## まとめ
プログラミング言語はそれぞれ異なるメモリ管理のアプローチを持っています。JavaとGoはどちらもガベージコレク

ションを行う言語ですが、その実行方法とオーバーヘッドは異なります。JavaはJVMを通じてメモリ管理を行い、Goは直接ネイティブコードへのコンパイルという方法を採用しています。
【AWS認定試験】DVA-C02を取得しました



---
# はじめに
先日、AWS Certified Developer – Associate(AWS-DVA)に受験しました。

受験したテストは、DVA-C02です。
(2023年 2月 28日から C01 → C02 にテストが変更になっています。)

合格までに実践した取り組みと受験した感想を紹介します。

# 試験対策前の状態
- エンジニア歴1年未満
- AWSの実務経験 8ヵ月
- 取得済みの資格：SAA


# 試験対策
### テキスト

以下の問題集を主軸としてやりました。

[徹底攻略AWS認定デベロッパー - アソシエイト教科書 徹底攻略シリーズ](https://www.amazon.co.jp/%E5%BE%B9%E5%BA%95%E6%94%BB%E7%95%A5AWS%E8%AA%8D%E5%AE%9A%E3%83%87%E3%83%99%E3%83%AD%E3%83%83%E3%83%91%E3%83%BC-%E3%82%A2%E3%82%BD%E3%82%B7%E3%82%A8%E3%82%A4%E3%83%88%E6%95%99%E7%A7%91%E6%9B%B8-%E5%BE%B9%E5%BA%95%E6%94%BB%E7%95%A5%E3%82%B7%E3%83%AA%E3%83%BC%E3%82%BA-%E6%A0%AA%E5%BC%8F%E4%BC%9A%E7%A4%BENTT%E3%83%87%E3%83%BC%E3%82%BF%E5%B7%9D%E7%95%91%E5%85%89%E5%B9%B3-ebook/dp/B09SKV1Q7C)

こちらで紹介されているサービスとその詳細について網羅できれば、試験は余裕で突破できると思います。
ですが、網羅性がある反面、下記口が読んでいて面白いものではないため結構つらいです。
それにめっちゃ分厚いので、1日30ページずつ進めるようにして何とか読みました。

読むだけで身につくというよりは、章末の問題を解くのと解説を読んで定着する感じの使い方です。

### 問題集

オンラインの問題集を利用しました。
こちらの方はおすすめです！


[Tech Stock](https://techstock.jp/)

AWSの資格のパッケージがあるため、そちらを購入しました。
問題の質は、当日の試験とほとんど変わらないと思います。

1セクション7問区切りになっているため、隙間時間に少しづつ進めることができました。
解説では、選択肢のサービスについての説明が乗っているため、簡易的に新しいサービスを知ることもできます。


### その他
- BalckBeltは読みませんでした。
- Udemyの講座も少し見ましたが、最終的には上記のテキストと問題集で対応しました。

### 試験でよく見たサービス
- Amazon APIGateway
- Codeシリーズ
- AWS x-ray
- AWS Lambda
- AWS Elastic Beanstalk
- AWS IAM
- Amazon Cognito
- AWS CloudFormation
- Amazon DynamoDB
- Amazon CloudWatch


# 受験してみての感想
SAAに比べると簡単だった印象です。サービスの範囲が狭いため、練習問題を事前に多く解くことでパターンになれることができると思います。試験時間もゆとりがありました。

01のテキストで勉強していましたが、問題に感じる部分はありませんでした。

ただSAAよりも細かい設定を聞かれることがほとんどなので、ユースケースとセットで覚えていくことが必要かなと思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3493360/1c9fd94d-f1ac-d071-7228-c560646e2389.png)
---
【Python】リストの要素数を取得して処理するとき、長い方の要素数に合わせて処理する方法

# 概要
- リストの要素数を取得して処理を行う場合に、`zip`関数だと短い方の要素数に合わせてペアが作成されてしまい、ちょっと詰まったフェーズがあったので備忘録として残します。

### 短い方の要素数に合わせて処理する場合

```py
abc_company_codes = ["a", "b", "c"]
xyz_company_codes = ["x"]
for abc_code, xyz_code in zip(abc_company_codes, xyz_company_codes):
    print("abc_code:", abc_code)
    print("xyz_code:", xyz_code)

# 出力結果
# abc_code: a
# xyz_code: x
```

- `zip`関数は、複数のイテラブル（リストやタプルなど）をまとめて処理するための関数。
- 大事なポイントは、要素数が異なるリストであっても、短い方の要素数に合わせてペアが作成される、と言うこと。「短い方」と言うことを知らないと詰まってしまう。
- 出力結果を見てわかるように、短い方の`xyz_company_codes`に合わせて作成されるので、`abc_company_codes`の`b`と`c`は出力されません。`abc_code`と`xyz_code`は1つずつのペアで取得されるからです。
- 要素ごとに対応関係がある場合には便利です。


### 長い方の要素数に合わせて処理する場合

```py
abc_company_codes = ["a", "b", "c"]
xyz_company_codes = ["x"]
max_len = max(len(abc_company_codes), len(xyz_company_codes))
for i in range(max_len):
    abc_code = abc_company_codes[i] if i < len(abc_company_codes) else None
    xyz_code = xyz_company_codes[i] if i < len(xyz_company_codes) else None
    print("abc_code:", abc_code)
    print("xyz_code:", xyz_code)

# 出力結果
# abc_code: a
# xyz_code: x
# abc_code: b
# xyz_code: None
# abc_code: c
# xyz_code: None
```

- 上記の場合、長い方の要素数を`max_len`として設定します。
- 要素数が異なるリストでも、要素のペアを作成せずに、それぞれのリストの要素を個別に処理します。ただし、要素数が足りない場合は上記の出力結果のように`None`となります。ここは、`else None`のところで調整できます。
- 対応関係がない場合に便利ですね。
- ただ、、、もっと楽な記載方法ないのか？と思ったら、ちゃんとあった。以下のように簡潔に記載できます。

```py
import itertools

abc_company_codes = ["a", "b", "c"]
xyz_company_codes = ["x"]
for abc_code, xyz_code in itertools.zip_longest(abc_company_codes, xyz_company_codes):
    print("abc_code:", abc_code)
    print("xyz_code:", xyz_code)

# 出力結果
# abc_code: a
# xyz_code: x
# abc_code: b
# xyz_code: None
# abc_code: c
# xyz_code: None
```

- `itertools.zip_longest`関数を使用すると、要素数の異なる複数のイテラブルをまとめて処理することができます。
- 異なる要素数の場合、欠損した部分は`None`で埋められますが、`fillvalue`引数を使用して欠損部分の値をカスタマイズすることもできるんですね。

```py
import itertools

abc_company_codes = ["a", "b", "c"]
xyz_company_codes = ["x"]
for abc_code, xyz_code in itertools.zip_longest(abc_company_codes, xyz_company_codes, fillvalue="N/A"):
    print(abc_code)
    print(xyz_code)

# 出力結果
# a
# x
# b
# N/A
# c
# N/A
```

## 参考記事：
- [Python公式ドキュメント](https://docs.python.org/3/library/itertools.html#itertools.zip_longest)
- [Python, zip関数の使い方: 複数のリストの要素をまとめて取得](https://note.nkmk.me/python-zip-usage-for/)
[iOS]バックグラウンドで継続して処理を実行できない

たまにXcodeをさわらなければいけない機会があるのだが、本腰入れて開発するわけではないため、知識がまったく身につかない。毎回Google先生のお世話になる。最近はChatGPT先生にもお世話になっている。

ただ、それらで調べた結果がすべて正しいとも限らない。古い情報だったりもする。公式のリファレンスを当たるのが一番なのだろうけれど、ド素人には手っ取り早いサンプルコードが欲しいものである。

今回、ロック中でもタイマーを動かしたい要件があったためネットでいろいろ調べていたのだが、振り回されてしまってちょっと苦労したため、備忘録としてここにメモしておく。

### 無操作タイムアウト処理がちゃんと動かない

規定時間アプリが無操作だった場合にアプリの初期画面に戻すという処理があり、実機デバッグ時はちゃんと動いていたのだが、通常実行時に画面ロックがかかると、時間を過ぎてロック解除しても初期画面に戻っていないという現象があった。

ホームボタンを押して、アプリをバックグラウンドにしていた場合も同様。

### ロック中にタイマーは動き続けるのか？

単純にscheduledTimerWithTimeIntervalで規定時間を指定し、selectorには初期画面に戻す処理を書いていたのだが、このタイマーがロック中に止まってしまっているらしい。

ロック中NSTimerはどうなるのかを調査。アプリがバックグラウンドになったとき、NSTimerは動いているのか？止まっているのか？動いているとの記事も見かけたが、結論としては「デバッグ実行時のみ動いている」ようだ。実機をMacから切り離し、アプリを実行した場合はロック中タイマーが動いていなかった。


### UIBackgroundTaskIdentifier

ちょっと調べたら、UIBackgroundTaskIdentifierを使うとバックグラウンドでも処理を継続できるということがわかった。

[[Objective-C] バックグラウンドで継続して処理を実行する](https://qiita.com/edo_m18/items/52fb7190d4285aabc1c9)

すごくわかりやすいサンプルコード。ド素人の私でもすぐに開発中のアプリに組み込むことができた。サンプルではNSLogしているところを、1秒ごとにカウンター用変数をカウントアップしていく処理に変えただけ。

しかし、永遠に動いてくれているわけではないようだ。

これはちょっと延命するだけのようで、バックグラウンドに入ってから30秒でタイマーが止まってしまった。今回の場合は30秒だったけれど、特に決まっているわけではないらしい。

>iOSではアプリがバックグラウンドに移行したらプロセスがすべて一時停止するのでタイマーも止まってしまいます。基本的に後ろで長時間動き続けるという動作はできません。こちらを参照してください。
beginBackgroundTaskWithNameで一時停止するまでの時間を延長することはできますが、どれくらいiOSが待ってくれるか明確な時間は決まっていません。
引用元：https://teratail.com/questions/123950#reply-188862


### Background Modes

CapabilityにBackground Modesというのもあるけれど、これは今回無関係のよう。

よくわからず全部チェック入れてやっていたが、それでも上記のように30秒でタイマーが止まっていた。

これはオーディオ再生や位置情報アプリなど限られた用途にしか対応しておらず、NSTimerで汎用的にバックグラウンド処理ができるようになるものではないらしい。

### 結局どうしたか

バックグラウンドで経過時間をカウントし続けるのは無理なので、バックグラウンドに入った時刻を記憶し、復帰したときに経過時間を算出、それをカウンター変数に加算することで、経過時間をカウントし続けたように見せることができた。

（バックグラウンドに入るイベントはUIApplicationWillResignActiveNotification、復帰イベントはUIApplicationDidBecomeActiveNotificationで作成）

（手っ取り早いサンプルコードが欲しい、と言いつつ、ここにサンプルコードを提示できないのは、単純化したサンプルコードを作るスキルすらないため…ごめんなさい）
イミュータブルを用いて保守のしやすいコードを書く

# はじめに
「良いコード/悪いコードで学ぶ設計入門」を読んでいたのですがその中で、変数をイミュータブルにすることの有用性について説かれていたのでそれをまとめてみました。

https://amzn.asia/d/a0vvJW2

# 使用箇所
本では変数を宣言する際は基本的にfinalを使ってイミュータブルな変数にすべきだと書かれていました。
理由としては以下の二点が述べられていました。

- 変数が本来の意味から逸脱することがなくなるため
変数は値が変わらないことが多いです。
また、変数の値を変えようとするときは別変数に置き換えたほうがいい場合も多いです。
- 影響範囲が限定されるので保守しやすいため

イミュータブルな変数のみでコードを書き、加算などを行う場合は新たなインスタンスを生成してそこに代入するという形を取ることで堅牢なコードが実現できます。
ただし、例外的にミュータブルな変数が認められる場合もあります。

# ミュータブルな変数を用いる場合
変数をミュータブルにするときは以下のような場合です。
- 値の変更が膨大になることが予想されるとき
  例) ゲームのHPなど
- パフォーマンスが求められる場合
  例) 計算ごとにインスタンスを生成する時間を削減したい場合など
- スコープが局所的な場合
  例) ループカウンタなど

また、ミュータブルな変数を用いるときはその変数が不正な状態にならないような設計をすることが求められます。

# Pythonでfinalを使う
書籍中ではJavaのfinalを使って説明されていましたが、
Pythonの場合だとPython3.8以降であれば次のようなコードで実装できます。

```python:python
from typing import Final

hoge: Final[int] = 100
```

このように記述すると、この後にhogeに対して別の値を代入などをした場合にエディタ上でエラー表示をしてくれます。
ただし、実行時にエラーを出すわけではなくあくまでPythonのFinalは型チェックとしての役割しかないため強制力がないことに注意が必要です。


# 感想
コードの堅牢さのために変数をイミュータブルにするという考え自体は持っていましたが、
イミュータブルが基本でミュータブルが例外という発想は目から鱗でした。
一方で、Pythonのイミュータブルには強制力がないため今回の考えがマッチするのかと考えると微妙なところです。


# 参考
https://docs.python.org/ja/3/library/typing.html
Snowflakeの自動テーブル更新とTableauダッシュボード【Snow Task・Snow pipe】

# 1.6月〜実装内容

今回は分析基盤構築・ダッシュボード作成・MLパイプライン構築
3つの開発を同時におこなっていきたいと思っております。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2526914/ebb2034b-6ee6-aa8b-d410-7ea575923af3.png)

# 2.6月開発内容
こちらが詳細のアーキテクチャ図になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2526914/85de006a-55cf-6c2d-0e0d-b6272b9bb7c1.png)

## 2.1 テーブル更新のアーキテクチャ図
GCPのPub/Subというメッセージングサービスを使って、テーブルをCloud Storgeにあるデータを紐づけることが可能になっています。
また、snowpipeとPub/subを用いることで、CloudstorageにJSONファイルが入ったことをトリガーとして、テーブルが自動的に更新されるようになっています。
ここで一点問題点が発生してしまい、URSERT INTOなどの複雑なSQLはSnowpipeではできず、設計の変更点としてCOPYINTOでまずはその日のTempテーブルを作成し、
その後に元のテーブルにMERGE INTOをすれば良いのではと思い、実装。
結果、うまくいくことができた。これらを管理するために、Snow TaskでそれぞれのSQLの実行をスケジューリングすることにした。

以上の処理から、Tableau上のダッシュボードが常に最新のものとなった。

最近流行りのSnowflakeになります

## 2.2 ダッシュボード構築
こちらはダッシュボード構築になります。
CloudStorageに画像データを保存させ、Snowflakeとリンクすることで、Tableau上で画像の表示を行いました。結果、どの月にどの商品が売れたかが画像を通して見ることができます。

また、レコメンドエンジンで知られるリフト値というものを算出し、アイテム間の関係性を見ることも行いました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2526914/c13b3e94-a851-25da-4c0c-322bde1c1135.png)
はじめてのデータ更新クエリ

# 背景
最近、データ更新クエリを書く機会があり、MySQLならではことなどを学びました。かれこれ6年ほどSQLを書いて居ますが、これからはじめて更新クエリを書く人たちに一読してもらいたい内容をまとめてみました。

# 環境
MySQL 5.7

デモデータとして次のようなテーブルを想定しています。

```sql
Classテーブル
id, name
1, A
2, B

Studentテーブル
id, name, pointa_a, point_b 
1, Ken, 10, 15
2, Ryu, 20, 25
3, Darusimu, 30, 35

PowerUpテーブル
id, up_point,
1, 100
2, 200
3, 300
```

# 更新クエリの書き方

## 1. 定数または同じテーブルの列の値を更新する

一番シンプルな形です。

```sql
UPDATE [テーブル名] 
SET [列名] = [更新したい値] 

UPDATE Student 
SET point_a = 40 
-- -> 全行40ポイントに更新されます

-- 一度に複数の列を更新することもできます
UPDATE Student 
SET point_a = 40, point_b = 90

-- 特定の行に対して更新したい場合はWHERE句を使います
UPDATE Student 
SET point_a = 99
WHERE id = 1
-- -> id = 1のみ99ポイントに更新されます
```

同じテーブルの列を指定することもできます。

※ 更新元、更新先の列の型には注意が必要です

```sql
UPDATE Student 
SET point_a = ponint_b 

-- -> 
Studentテーブル
id, name, pointa_a, point_b 
1, Ken, 15, 15
2, Ryu, 25, 25
3, Darusimu, 35, 35
```

## 2.  違うテーブルの値を更新する（JOIN）

他のテーブルの値を使って更新したい際はJOINを使います。

「,」はMySQLでは「INNER JOIN」と同じになります。ただしON句を指定してないので全行同士がJOINした状態になります。

```sql
-- WHERE句でidが同じものを指定して更新します
UPDATE Student, PowerUp
SET point_a = up_point
WHERE Student.id = PowerUp.id 

-- 同じ結果になります
UPDATE Student INNER JOIN PowerUp ON Student.id = PowerUp.id
SET point_a = up_point
```

## 3.  集計結果などを更新する（サブクエリ）

テーブルの値を集計結果した結果などを更新したい場合はサブクエリが使えます。サブクエリにはエイリアス（AS）を付ける必要があります。

```sql
-- point_aの平均値を全行更新する
UPDATE Student, (SELECT AVG(point_a) avg_point FROM Student) AS SubTable 
SET point_a = avg_point
-- -> 全行平均値の25に更新されます
```

これらを組み合わせることで、だいたいのデータ更新は行えると思います。注意する点としては、JOINを使用して複数のテーブルを扱う際にはON句またはWHERE句で更新の対象、条件を満たしている行をちゃんと絞り込むことです。絞り込みが足りなければ、意図しない値での更新、対象外の行への更新が行われる可能性があるので気をつけます。

# 組織で開発する際に気をつけていること

組織で開発している際に、お作法的な手順を踏むことで事故を防いだり、他の人からも利用しやすくしておくために気をつけていることです。

### 1. begin~rollbackで挟む

データ更新のクエリはまっさらの状態から、まず「begin;」と「rollback;」を書くようにしています。更新クエリを書いている途中で誤って実行しても大丈夫ですし、最終確認が終わってから「rollback」を「commit」に書き換えること手順を踏むことで、更新結果の確認漏れなどが無いようにする目的です。

```sql
begin;

-- 更新するクエリを書くところ

rollback;
```

### 2. 結果確認クエリをBeforeAfterで挟んで書く

begin~rollbackの中に更新前後の確認をするクエリを書いておき、更新が正確に行われたか確認します。同じ確認クエリにしておくことで、データ更新がの影響だけでデータが変更されたのか確認しやすくなります。

```sql
begin; 

-- 更新前の値を確認する
select * from piyo where id IN (...);

-- 更新するクエリを書くところ

-- 更新後の値を確認する
select * from piyo where id IN (...);

rollback;
```

### 3. 対象行数を把握する

更新の対象となる行を把握しましょう。IDで指定できればIDで指定するのが良いですし、時間経過やINSERTなどによって更新の対象行数が増減するような条件にしておくのは、正確に更新が行われたのかわからないのであまり良くないです。たとえ1行でも想定していた行数と違う場合は考慮漏れなどがあるはずです、何が原因か突き止めましょう。

### 4. ステートメントごとにコメントで何をしているのかわかりやすく書く

実行したクエリを今後残すものであれば、今後クエリを見る人がわかりやすいようにコメントを書いておきます。

ヘッダ部には簡単なタイトル、なんの開発の際に発生したものなのか（作成者や作成日時をいれておくと問い合わせなどするときに便利です）

各ステートメントにはその簡単な目的と結果セットで確認すべき点などを書いておきます。

```sql
-- piyoテーブルidが100より小さいレコードのsizeを一律「L」に更新するQuery
-- 〜〜〜の仕様変更、piyoたちが小さくなってきたので、これまでのpiyoたちをすべてLとして扱う

begin; 

-- 更新前のsizeを確認する（バラバラな状態）
-- 対象は90行（9行は欠番）
select size from piyo where id < 100;

-- id が100より小さいレコードを’L’で更新する
-- 対象は90行（9行は欠番）
UPDATE piyo SET size = 'L' where id < 100;

-- 更新前のsizeを確認する（すべてLになっている）
-- 対象は90行（9行は欠番）
select * from piyo where id < 100;

-- 確認できたらcommitにする
rollback;
-- commit;
```

# ひとこと

組織で開発していくときには、これら当たり前のことがなされていると事故を防げたり、連携がスムーズに行くかと思います。なにか発見があれば幸いです。
現場猫イラストのコードを解析してみた

# 初めに
![Dkt3fnqUcAAVaUN.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/500157/0e9bc35a-a49f-3b29-9f5d-d468b1456f82.jpeg)

コードを書いた現場猫イラストがあります。

今回はその書いたコードを解析して問題点を考えてみました。

# 書かれたコード

```jsx

var accounts = apiService.sql({"SELECT * FROM users"});

for(var i = 0; i < accounts.length; i++){
	var account = accounts[i]
	if(account.username === username && account.passwprd === password){
		return true;
	}
	if("true" === "true"){
		return true;
	}
}

$('#login').click(function(){// 内容不明})
```

このようなコードが書かれていました。

SQLとjQureyが同時に書かれているのでフロントとバックエンド両方書かれているのでしょうか…..?

# このコードの問題点

## 1.SQLインジェクション

フロントに直接SQLを書いているため、外部からSQLを流し込まれるリスクがあります。

## 2.変数宣言に`var`を使っている

varは可読性低下やバグを生み出す原因になります。

## 3.意味のないif文がある

以下コードは必ずTrueになり比較内容も意味がないです。
```jsx
	if("true" === "true"){
		return true;
	}
```
# 最後に
![main-qimg-19d23acaab9836f624443d851939fac2-lq.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/500157/784ca420-ce5f-f83a-376b-d29b20aca43c.jpeg)
【SamuraiStats】3. 自動でスクレイピングする

前回記事

https://qiita.com/kohki_takatama/items/2df783bff08b48f00cba

今回は**Google Apps Script**を使って、「定期的にサーバーを起こし、スクレイピングしてデータベースをアップデートする」というコードを書きました。


## コード
```js
function accessUrl() {
  var url = 'https://ssserver.glitch.me/update';
  var response = UrlFetchApp.fetch(url);
  Logger.log(response.getContentText());
}
```
どうしようかな～とぼんやり考えていたんですが、簡単でしたね。

SamuraiStatsの今後についてですが、今回、定期アップデートが可能になり、他のユーザーからも使える形になったなと思います。ので、もう少しちょこちょこした修正して、友達とかに使ってもらおうと思います。

それから、コード置いておきます
https://github.com/Kohki-Takatama/samuraiStatsServer

ほな、また。

記録：初挑戦：サーバーの定期アクセス
【Terraform x Snowflake】Terraformで外部テーブルのnotification_channelを取得する


# 結論

Terraformプロバイダ:[snowsql](https://registry.terraform.io/providers/aidanmelen/snowsql/latest)を使う (〜2023/6時点)

``` hcl
resource "snowflake_external_table" "external_table" {
  # ... 中略 ...
}

data "snowsql_query" "notification_channel" {
  statements = <<-EOT
    SHOW EXTERNAL TABLES;
    SELECT "notification_channel" FROM TABLE(RESULT_SCAN(LAST_QUERY_ID())) LIMIT 1;
  EOT

  depends_on = [
    snowflake_external_table.external_table
  ]
}

output "snowflake_notification_channel" {
  value = jsondecode(data.snowsql_query.notification_channel.results)[1]["notification_channel"]
}
```

これで、outputとして以下のような値が取得できる。

```text
arn:aws:sqs:ap-northeast-1:000000000000:sf-snowpipe-XXXXXXXXXXXXXXXXXXXXXXXXXXXXX
```

moduleのアウトプットにすれば、この値を後続処理に引き渡すことができる。

# 経緯

Snowflake (on AWS) のリソースとして外部テーブル(S3)を作成したかった。

Snowflakeのワークシートで外部テーブルを作成すると、その後にSnowflake側で自動で作成してくれるnotification_channel(中身はAWS SQSのarn)が取得できる。

![snow_notification.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3475867/2d302a54-d92f-bf13-d951-819986803e0b.png)

このarnを取得し、この後自前のAWSアカウントに入ってS3のイベント通知に設定することで、外部テーブルの自動更新ができるようになるというカラクリ。

(詳細は[Snowflake公式の情報](https://docs.snowflake.com/ja/user-guide/tables-external-s3)を参照)

これをTerrafromで定義すれば、GUI操作でSnowflakeとAWSを行き来することなく一通で設定できる...と思っていた。

そんな時に本件に引っかかってしまった。

Snowflake公式から提供されているTerraformプロバイダ:[snowflake](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/latest)があり、これを用いることでSnowflakeのリソース作成をIaC化できる。

しかしながら、この本家Terraformプロバイダでできることはまだまだ限られている模様。

シェル([SnowCLI](https://docs.snowflake.com/ja/user-guide/snowsql))や[Python](https://docs.snowflake.com/ja/developer-guide/python-connector/python-connector)等を使って、一部分だけを外部処理にするのも面倒だ...。
Terrafromでなんとかしたい...。

そう思っていた時、任意のSQLが実行できる非公式プロバイダ:[snowsql](https://registry.terraform.io/providers/aidanmelen/snowsql/latest)があって助かった。

# ぼやき

そもそもSnowflakeプロバイダ経由では、AWSのリソース情報が取れないのかなと思ったけどそうではなさそう。

似たようなシチュエーションとして、ストレージ統合 ([こちら](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/latest/docs/resources/storage_integration)) ではAWSのリソースとしてIAMユーザーのarnを持っている。
こちらに関しては、公式プロバイダーを用いることで「storage_aws_iam_user_arn」が取得できる。

``` hcl
# OK
snowflake_storage_integration.integration.storage_aws_iam_user_arn
```

一方、外部テーブル ([こちら](https://registry.terraform.io/providers/Snowflake-Labs/snowflake/latest/docs/resources/external_table)) 生成後に発行されるはずの「notification_channel」も同じノリで取得できてもいいんじゃなかろうかと思った次第。


``` hcl
# NG (こうやって値を取りたかった...)
snowflake_external_table.external_table.notification_channel
```
【Redis】RailsでRedisを使った排他制御を行いたい

## 背景
　ユーザーのログイン時に大量データを更新する処理が実装されていた。この更新処理は数時間に1回程度実行されれば最新が保たれるものだが、ログイン時以外にも同時に複数箇所から更新処理へアクセスすることがあり、その場合に、同時並列実行を防ぐために排他制御が実装されていた。しかし、その更新処理のエラーログなどから排他制御がうまく機能してないのでは？という疑惑がうまれ調査改善することとなった。
## 環境

- Ruby 3.1
- Rails 7.0.2

## 従来の排他制御

これまではRails.cacheを使って排他制御を行っていた。Rails.cacheにはRedisを使用するように設定されている。

```ruby
# 更新処理処理クラス

# 更新処理を実行する際に排他制御する
# valueの値がtrueならロック中、falseなら解除中とする
# ロックする
key = 'locking_id:1'
Rails.cache.write(key, true)

# 〜〜更新処理〜〜

# ロックを解除する
Rails.cache.write(key, false)
```

```ruby
# 更新処理を呼び出す前にロックが掛かってないか確認する
# ロックがかかっていればtrue, 解除中ならfalse, 取得できないときはnilなのでfalseを返すようにする
key = 'locking_id:1'
is_lock = Rails.cache.read(key) || false 

unless is_lock

	# 〜〜更新処理クラスを呼び出す〜〜

end
```

一見、問題なさそうに見えるが、排他状態を確認してからロックするまでにコード上、数十行だが間があり、ほぼ同時に実行される2つのアクセスなどから、実際にこの間を通り抜けて2重以上に更新処理が実行されているのが現状だった。

## 改善した排他制御

確認と排他状態の更新の両方を同時に行うために、RedisのSETNXメソッドを使うことにした。
### SETNXメソッド
- Set not exists の略で、keyが存在してなければその値をセットするメソッド。
- セットすることができたら1、セットできなかったら0を返してくれる
- 現在はSetメソッドにあるnxオプションを使っても同じことができる
- 参考：https://redis.io/commands/setnx/

### 実装した結果

```ruby
# 更新処理を実行する際に排他制御する

# Redisと接続する
redis = Redis.new(...)

# ロックする
key = 'locking_id:1'
is_set = redis.set(key, true, nx:true)

# セットできなかったらロックがかかっているので更新処理せずに処理を抜ける
return unless is_set

# 〜〜更新処理〜〜

# ロックを解除する
# 解除する際はデータを削除しておく
redis.del(key)
```

このように実装することで、確認とロックすることが同時に行われるようになったので、ほぼ同時にアクセスされた際にも排他制御が機能するようになった。

### Rails.cacheでは使えない？
最初に従来と同じようにRails.cacheのメソッドで実現できないか考えて、Rails.cache.writeにoptionを渡すことが可能のようだったので、下記のように書いてnxオプションが機能するか試してみたが、機能しなかった。

```ruby
# 常にセットされておりnxオプションが機能してない
is_lock = Rails.cache.write(key, value, nx: true)
```

## おわり
排他制御をRedisで行う際にはnxオプションを使おう!
どハマりしたAndroid App Bundle (AAB) + Firebase Google Auth の本番環境構築

## 概要

- Kotlin

を用いた環境において、

- Firebase Google Auth

を実装しており、それを内部テストするときの

- Android App Bundle (AAB)

としてビルドして公開した時に

- ログインが動作しない問題について

ハマったので２度とハマらないように供養したいと思います。


## Android アプリリリース時の署名について説明
dev 環境では、デバッグ用のSHA１をFirebaseマネジメントコンソールにて
Androidアプリの設定に登録
その後Google-services.jsonをダウンロード
アプリへとOAuthのclient_idなどを反映

の流れでできていましたが、
本番環境ではデバッグ用の署名は使わず、そのアプリ固有のものを使います。


この時、
Android App Bundle (AAB)
を使うと何がいいかというと、この署名用の鍵をGoogle側で管理してくれます。
これはもちろん自分で管理することは可能なのですが、
仮に管理を適当にしていて無くしてしまったとすると、
それ以降アプリのアップデートが不可能になります。
（もしかすると回避策はあるかもしれませんが、私はそこまで調べていないです。）

これはアプリの管理者というか、変更者の身元をきちんと証明するために署名があるので、
どこかの誰かが悪意を持ってアプデをかましてくるみたいなことを予防するためです。
ただ、いつでもそうであるように、セキュリティと利便性はトレードオフの関係にあり、
このセキュリティを担保するためには鍵を責任を持って自分で管理するというめんどくささと怖さがありました。

私はセキュリティ関連の企業に在籍しているので少しこのトレードオフについて語ってしまいましたが、話を元に戻すと、

Android App Bundle (AAB)
を使うことで、Googleがこのアプリの署名鍵を一元管理してくれるので、楽だということです。
また、先ほどの身元証明のためには、別の鍵（アップロード鍵）を自分で管理し、
アップロード時にこれで署名します。
そうすると、Google は管理している署名用の鍵で署名してくれ、それがリリースされるというわけです。
このアップロード鍵は自分で管理するのであれば何が今までと違うのか、と思われるかもしれませんが、
この鍵は無くしても大丈夫です。
無くしたとすると、Google Play Console からアップロード鍵を更新する、として設定し直せば大丈夫だからです。


## 今回のハマりポイント
さて、背景としては
Android App Bundle (AAB)
を使うと、Googleがディベロッパーの代わりに管理してくれる
署名鍵を使ってリリース用のAPKに署名してくれるということでした。

ここで、Google Play Console にて、
設定 --> アプリの安全性 --> アプリの署名
に進むと、

**アプリ署名鍵の証明書**

**アップロード鍵の証明書**

と二つセクションがあることがわかります。
これは先ほどの説明を読めばなるほど、たしかにね！
と思います。

ここで、一つ疑問がでます。

**では、Firebase Authで登録していたSHA1はどちらのものを登録すればいいのか？**

ここがハマりポイントであり、結局中身をよく理解したというよりは、どちらも試してどちらもなぜか動かんなとかなった挙句、
いや署名鍵登録すれば大丈夫やろ
と思いFirebase側に登録しました。

しかし、内部テストに登録してPlay store からインストールしたアプリからログインしようとすると、
ログインが遷移せず、途中で止まってしまう形になり、
Firebase側に間違いなく署名鍵のSHA1が登録されているにもかかわらずうまくいかず、ハマりました。


## 解決策

結論を言うと

**署名鍵の証明書**
に紐ついたSHA１をFirebase Console にて登録、
--> Google-services.json をダウンロード
--> アプリに反映
--> AAB　のビルド
--> AAB のアップロード
を行っていることは間違っていませんでした。
なぜこれでログインアクションで落ちていたのかわかりませんでしたが、

最終的に
**署名鍵**を作り直す（更新する）ようにGoogle Developer Console
で設定し、鍵を作り直した（リフレッシュ）した後に登録し直すことで解決しました。




## まとめ

同じような問題に時間を使ってしまった人が他にいるかわかりませんが、
もし自分のような人がいるのであれば、どこかの誰かの助けになれたら嬉しいです。


今回はこの辺で。


@kenmaro
Laravelでジョブのタイムアウト時間を変更・検証する

# ジョブのタイムアウト時間を引き上げる

- Laravelジョブのデフォルトのタイムアウト60秒だと、
workerが大量の処理時に途中でタイムアウトしてしまうことがある（ex. PUSH通知の一斉送信）

## タイムアウト時間の引き上げは、一行で完結

```HogeJob.php
public $timeout = 900; // =タイムアウトまで5分
```
https://laravel.com/docs/9.x/queues#timeout

# 検証方法は？

- 大量のI/O処理を行うのが簡単

```php
$storage = Storage::disk('s3');
for ($i = 1; $i <= 100000; $i++) {
    $storage->put('sample.txt', 'hoge');
    $storage->delete('sample.txt');
}
```
DatabricksでEnglish API for Sparkを試してみる

初めこれを読んだ時には「エイプリルフール？」と思いました。

https://qiita.com/taka_yayoi/items/e5f58ac7f80064627a30

こちらで公開されています。

https://github.com/databrickslabs/pyspark-ai/

# 事前準備

Databricksで動かす際にはいくつかの設定が必要です。最初の2つはデータ取得の際にweb検索するために必要です。

- Google Cloud PlatformでAPIキーを取得
- Google Cloud PlatformでGoogle Custom Search APIを有効化してCSE IDを取得
- OpenAI APIキーの取得
- GPT-4 API Waitlistへの登録(まだ通ってません)

# ライブラリのインストールと設定

```
%pip install pyspark-ai
```
```py
dbutils.library.restartPython()
```

以下のように環境変数にAPIキーを設定します。

```py
import os

os.environ["OPENAI_API_KEY"] = dbutils.secrets.get("demo-token-takaaki.yayoi", "openai_api_key")
os.environ["GOOGLE_API_KEY"] = "<Google Cloud PlatformのAPIキー>"
os.environ["GOOGLE_CSE_ID"] = "<CSE ID>"
```

私はGPT-4が使えないので、GPT-3.5に切り替えます。

```py
from langchain.chat_models import ChatOpenAI
from pyspark_ai import SparkAI

llm = ChatOpenAI(model_name='gpt-3.5-turbo-16k', temperature=0)

spark_ai = SparkAI(llm=llm)
spark_ai.activate()  # active partial functions for Spark DataFrame
```

# データの取り込み

```py
auto_df = spark_ai.create_df("2022 USA national auto sales by brand")
```
```py
auto_df.show(n=5)
```
```
+----------+----------+-------------+
|brand_name|sales_2022|sales_vs_2021|
+----------+----------+-------------+
|    Toyota|   1849751|           -9|
|      Ford|   1767439|           -2|
| Chevrolet|   1502389|            6|
|     Honda|    881201|          -33|
|   Hyundai|    724265|           -2|
+----------+----------+-------------+
only showing top 5 rows
```

ここまで英語の手順でEnglish APIを呼び出しただけ。なんだこれはー。

# プロット

これは単にプロットメソッドを呼び出してます。

```py
auto_df.ai.plot()
```
![Screenshot 2023-06-30 at 17.39.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/0d5c333e-fe68-3d76-3603-f312c07aff93.png)

`plot()`に自然言語も指定できるのですが、GPT-3.5のせいかエラーになってしまいます。

# データフレームに対する操作

最も成長しているブランド。

```py
auto_top_growth_df=auto_df.ai.transform("brand with the highest growth")
auto_top_growth_df.show()
```

返ってきてる…。

```
+----------+
|brand_name|
+----------+
|  Cadillac|
+----------+
```

# データフレームの説明

普通、`explain()`というと実行計画返ってきそうですが、本当に説明を求めているわけですね。

```py
auto_top_growth_df.ai.explain()
```
```
Out[15]: 'In summary, this dataframe is retrieving the brand name with the highest sales increase compared to 2021. It presents the result sorted by the sales increase in descending order and returns only the top 1 brand.'
```

うむー、確かに可能性を感じる。自然言語でコーディングするなんて、自分の年代では[ぴゅう太](https://ja.wikipedia.org/wiki/%E3%81%B4%E3%82%85%E3%81%86%E5%A4%AA)を思い出してしまいました。

### Databricksクイックスタートガイド

[Databricksクイックスタートガイド](https://www.amazon.co.jp/dp/B09V1YXFVQ/)


### Databricks無料トライアル

[Databricks無料トライアル](https://databricks.com/jp/try-databricks)
export

シェル変数を設定する
val変数に値を設定
```sample.sh
[linuxstudy@localhost ~]$ export val=valll
[linuxstudy@localhost ~]$ echo $val
valll
```
function内でvalを参照
```
[linuxstudy@localhost ~]$ ./sample.sh 
#!/bin/sh -v
function func1() {
  echo "${val}aaa"
}
func1
valllaaa
```
変数の格納

```sample.sh
#!/bin/sh -v
    var=$(ls)
    echo $var 
    var=`ls`
    echo $var 
    echo $((1+2))
```
```
[linuxstudy@localhost ~]$ ./sample.sh 
#!/bin/sh -v
    var=$(ls)
    echo $var 
Desktop Documents Downloads Music Pictures Public Templates Videos \aaa file.txt lo1 log1 log?1 logS1 logg1 logS0 logS1 logS2 logg1 loggg1 ret.txt sample.sh sleep.sh zsh-5.0.2-34.el7_8.2.x86_64.rpm
    var=`ls`
ls
    echo $var 
Desktop Documents Downloads Music Pictures Public Templates Videos \aaa file.txt lo1 log1 log?1 logS1 logg1 logS0 logS1 logS2 logg1 loggg1 ret.txt sample.sh sleep.sh zsh-5.0.2-34.el7_8.2.x86_64.rpm
    echo $((1+2))
3
```
python maya get min max key frame

```python
def GetAllByType(selType="joint"):
    all_curves = cmds.ls(type=selType, ni=True, o=True, r=True, l = True)
    curves_transforms = cmds.listRelatives(all_curves, p=True, type = "transform")
    return curves_transforms


def GetMinMaxFrame(selType="joint"):
    import math
    joints = GetAllByType(selType)
    minKey = 10000
    maxKey = 0
    for joint in joints:
        all_keys = sorted(cmds.keyframe(joint, q=True) or [])  # Get all the keys and sort them by order. We use `or []` in-case it has no keys, which will use an empty list instead so it doesn't crash `sort`.
        if all_keys:  # Check to see if it at least has one key.
            if all_keys[0] < minKey: minKey = all_keys[0]
            if all_keys[-1] > maxKey: maxKey = all_keys[-1]
    return math.floor(minKey), math.ceil(maxKey)
min, max = GetMinMaxFrame()
print(min, max)
```
RubyでAtCoder ABC237(A, B, C, D)を解いてみた

# はじめに
Webエンジニアを目指して、RubyやRailsをいじってます。
今回は、RubyでAtCoder ABC237のA, B, C, Dを解きました。備忘録として解き方をまとめていきたいと思います。

# A - Not Overflow
https://atcoder.jp/contests/abc237/tasks/abc237_a
```ruby:a-237.rb
n = gets.to_i
puts (-2) ** 31 <= n && n < 2 ** 31 ? "Yes" : "No"
```

# B - Matrix Transposition
https://atcoder.jp/contests/abc237/tasks/abc237_b
```ruby:b-237.rb
h, _ = gets.split.map(&:to_i)
array = Array.new(h){ gets.split.map(&:to_i) }.transpose

array.each do
  puts _1.join(" ")
end
```

# C - kasaka
https://atcoder.jp/contests/abc237/tasks/abc237_c
```ruby:c-237.rb
def counter_of_a(s, count = 0)
  while s[count] == "a"
    count += 1
  end
  return count
end

s = gets.chomp

left = counter_of_a(s)
right = counter_of_a(s.reverse)
s = "a" * [right - left, 0].max + s
puts s == s.reverse ? "Yes" : "No"
```
## 解説
最初に、左側から何個aが連続してあるか、右側から何個aが連続してあるかを求めておきます。そして、先頭にaをその差分の個数だけ加えた後のsが回文となっているかどうかを判定することで解くことができます。

# D - LR insertion
https://atcoder.jp/contests/abc237/tasks/abc237_d
```ruby:d-237.rb
n = gets.to_i
s = gets.chomp.chars

ans = [n]
(n - 1).downto(0) do
  if s[_1] == "L"
    ans.push(_1)
  else
    ans.unshift(_1)
  end
end
puts ans
```
## 解説
末尾から考えることで答えが求まります。

具体的には、入力例１の場合、`[5](R)->[4,5](L)->[4,5,3](R)->[2,4,5,3](R)->[1,2,4,5,3](L)->[1,2,4,5,3,0]`のように対応する値をRのときは先頭に追加し、Lのときは末尾に追加すれば良いことがわかります。

https://qiita.com/shoya15/items/50fd17e37d7c64f2b166
seleniumでTypeErrorが出たっていうメモ書き

## 前提
元々seleniumで書いていた、指定サイトにログインしてスクレイピングを行うプログラムが、TypeErrorを吐くようになってしまった！
実行環境ややりたいことの違いはありますが、基本的には以下サイトと同じ理由でエラーを吐いてしまったみたいでした。

https://teratail.com/questions/8tny5h52358nz4

## 原因
参考サイト

https://stackoverflow.com/questions/76428561/typeerror-webdriver-init-got-multiple-values-for-argument-options

seleniumのアップデートによるものみたいでした。

https://github.com/SeleniumHQ/selenium/commit/9f5801c82fb3be3d5850707c46c3f8176e3ccd8e

## 変更点
### ライブラリのインポート
変更前
~~~python3
from selenium import webdriver
from selenium.webdriver.common.by import By
import time
~~~

変更後
~~~python3
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
import time
~~~

### インスタンス化
変更前
~~~python3
#インスタンス化
driver = webdriver.Chrome('chromedriver',options=options)

#指定したドライバーが見つかるまで待機
driver.implicitly_wait(10)

#urlの指定
url="https://hogehoge"

driver.get(url)
time.sleep(5)

print("サイトのタイトル：", driver.title)
~~~
変更後
~~~python3
#インスタンス化
#version更新によってインスタンス化の記述変更
service = Service(executable_path=r'/usr/bin/chromedriver')
driver = webdriver.Chrome(service=service, options=options)

#指定したドライバーが見つかるまで待機
driver.implicitly_wait(10)

#urlの指定
url="https://hogehoge"

driver.get(url)
time.sleep(5)

print("サイトのタイトル：", driver.title)
~~~