OmniAICreator/Qiita-1.07M huggingface dataset:
rubio-radio - Rubyで作るシンプルなGUIラジオアプリ

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144608/e166db65-1b1b-0f8b-1684-62b97a4d6bf3.png)


## はじめに

Rubyを使ってシンプルなGUIのラジオアプリを作った。
 
https://github.com/kojix2/rubio-radio

[Glimmer-DSL-LibUI](https://github.com/AndyObtiva/glimmer-dsl-libui) を利用した。

https://github.com/AndyObtiva/glimmer-dsl-libui

## 概要

* [RadioBrowser](https://www.radio-browser.info)のTopVote500がテーブルに表示される。
* インプットボックスに打ち込むと、ラジオ局をインクリメンタルサーチできる（Glimmer-DSL-LibUIの機能）
* 再生ボタンを押すとコマンド(デフォルトでは[VLC](https://github.com/videolan/vlc))が起動してラジオを再生する。

## ポイントと感想

* GUIのポイントは、テーブルのインクリメンタルサーチだが、これはGlimmer-dsl-libuiの標準機能を使った。
    * テーブルのColumnの幅の調節ってできるんだろうか？
    * Glimmer-DSL-LibUI 自動でテーブルの変更を検知して更新してくれるようだ。
* ラジオ局は https://www.radio-browser.info のAPIを叩いて取得している。
    * TopVoteから取得している。
        * 本当はもっと利用できるラジオ局を増やしたいが、あまり多くするとパフォーマンスが悪化。
* 再生自体はVLCに丸投げしている。
    * spawnを利用してコマンドを起動。PIDを記録。終了時はPIDをkill。
    * [この方法はコマンドに空白文字などが含まれるとうまくいかない。](https://qiita.com/kojix2/items/3408dccb082f8b11352e)
        * グループIDを指定すれば大丈夫かも。
    * 監視用のスレッドが作成される。[これをui_timerから監視。](https://github.com/kojix2/rubio-radio/blob/af6b7509219cceb68e492914140ce38da17122ab/lib/rubio/radio.rb#L17-L30)そうすることで、VLCが途中で終了したら気がつくようにしてある。
    * VLCは[インターフェイス](https://wiki.videolan.org/Interfaces/)を選べる。ここでは `dummy` を指定している。
* Glimmer-DSL-LibUIの作者の方からプルリクエストを頂いた。自分が気が付かなかったバグをいくつか修正してもらった。Mac対応やWindows対応が行われた。ありがたいし勉強になった。

この記事は以上です。
javascript で全角英数記号を半角にする

１２３４５６ -> 123456 みたいな変換をしたい場合のコード。
`style="ime-mode: off"` を書いてもchromeだとシカとされる。
そんな場合に `input type="tel"` を使おう、なんて言う記事も多いけど tel でもないのに tel を使うの気持ち悪いので focus out時とかにフィルター通して正規化しよう、って魂胆。

```javascript
var filters = filters || (function () {
    const FullWidthStart = 0xff00
    const FullWidthEnd  = 0xff7e;
    const HalfWidthStart = 0x20;
    // ascii 文字はそのまま通す
    const AsciiEnd = 0x7f;
 
    return {
        toNarrow: function(s){
            let  result = '';
            for(let i = 0; i < s.length; i++){
                let c = s.charCodeAt(i);
                // ascii 文字はそのまま通す
                if(c < AsciiEnd){
                  result += String.fromCharCode(c);
                  // ここで戻らないと！
                  continue;  
                }
                if(c < FullWidthStart || FullWidthEnd < c){
                    continue;
                }
                let code = c - FullWidthStart + HalfWidthStart;
                result += String.fromCharCode(code);
            }   
            return result;
        }
    }
})();

let halfStrings = filters.toNarrow('１２３４５６７８９０ａｂｃｄｅｆｇｈｉｊｚＡＢＣＤＥＺあいうえお憂鬱な空！”＃＄％＆’（）＝～');
console.log(halfStrings);
```
INSTALL_FAILED_INSUFFICIENT_STORAGE

容量がいっぱいとかそんな感じなので、エミュレーターのデータを削除すれば直ります。


![スクリーンショット 2022-06-22 4.20.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/494487/ad1734fc-f4b6-151e-5078-1f89eb8fd723.png)

![スクリーンショット 2022-06-22 4.22.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/494487/77fba7b0-c57e-0e98-dfe0-94219e36b34e.png)

![スクリーンショット 2022-06-22 4.24.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/494487/182d03f6-eba3-8262-1fe7-196592f645ab.png)

なんか謎にアプリ起動できないなーって思ってて調べたらすごく単純でした。
Flutter AlertDialog での画面遷移でエラーが出る場合

# 初めに
データの削除機能を、AlertDialogを使って実装した際に
「削除をしますか？」→「はい」or「いいえ」を選択後の画面遷移でエラーが出た為、解決方法の記述です。

# 解決方法
「はい」「いいえ」等の選択肢を記述している``TextButton``にカーソールを合わせて、
command と　.(ドット)　を押すと選択肢が出てきます。
その中の、``Wrap with builder``を選択して、``TextButton``を``Builder``でwrapをしてあげる事で、エラーは消えました!

## 元のエラーが出たコード

```
   return AlertDialog(
     title: Text("削除の確認"),
     content: Text("『${book.title}』を削除しますか？"),
     actions: [
       TextButton(
         child: Text("いいえ"),
         onPressed: () => Navigator.pop(context),
       ),
       TextButton(
         child: Text("はい"),
         onPressed: () async {
           await model.delete(book);
           Navigator.pop(context);
       );
```



## エラー解決後のコード
```
      return AlertDialog(
        title: Text("削除の確認"),
        content: Text("『${image.title}』を削除しますか?"),
        actions: [
          Builder(
            builder: (context) {
              return TextButton(
                child: Text("いいえ"),
                onPressed: () => Navigator.pop(context),
              );
            }
          ),
          Builder(
            builder: (context) {
              return TextButton(
                child: Text("はい"),
                onPressed: () async{
                  //modelで削除
                  await model.delete(image);
                  Navigator.pop(context);
              );
```

# 終わりに
今回下記の記事を参考にエラーを解決しております。
エラーの原因まで理解したい方は、ぜひ参考にしてください。
https://zenn.dev/ryouhei_furugen/articles/2fa82ba62c88da
[Unity]ランキング全体の中からn個ずつ表示

## 経緯
Unityでランキングを表示する機能を実装する際、今までランキングのリストの要素全てを一度に表示するようにしていました。ぶっちゃけそんなにユーザーもいないからそのままでも良かったのですが、すぐ実装できる気がしたのでやってみました。

## 実装した機能
ランキング全体の中から一部の範囲に絞って表示する。
1ページ目は1位〜30位まで表示して、次のページボタンを押すと31位〜60位まで表示される的な奴。

## 流れ
1. ランキングの元になるリストを取得(サーバーなどから)
2. 取得したリストを並べ替える(レートの高い順など)
3. 何番目から何番目まで表示するかのインデックスリストを作る(例:そのリストが[0,30,60]の場合、1ページ目で1位〜30位,2ページ目で31位〜60位までが表示される)
4. 3で作成したインデックスリストを利用してランキングを表示する

## コード
### SetRanking
引数`start`の数から`end`の数までリストを回す。
ここでランキング表示用のprefabを生成しています。`SetContent`メソッドでそのprefab内のテキストを変更していますが、今回はそこがメインではないので割愛します。
```:SetRanking
public void SetRanking(int start, int end, List<UserData> list)
{
    end = (end>list.Count)?list.Count:end;
    for(int i=start;i<end;i++){
        Transform prefab = Instantiate(original, content).transform;
        UserData data = all[i];
        SetContent(data,prefab);
    }
}
```

### SplitIndex
引数`splitCount`はランキングを何個ごとに分けるかを決めます。
引数`listCount`にはランキングの元となるリストの長さを与えます。
`splitCount:30, listCount:120` みたいな感じにすると
`[0,30,60,90,120]`というリストが得られます。
これを`indexList`という変数に保持しておきます。
```:SplitIndex
List<int> SplitIndex(int splitCount, int listCount)
{
    List<int> list = new List<int>();
    int num = 0;
    while(true){
        list.Add(num);
        num += splitCount;
        if(num>=listCount) {
            list.Add(listCount);
            break;
        }
    }
    return list;
}
```

### ChangeIndex
上二つを実装できればあとは単純です。
現在のページ番号を保持する `currentIndex` みたいな変数を用意します。そして`SetRanking(indexList[currentIndex],indexList[currentIndex+1],all);`
とすることで`[0,30,60,90,120]`というリストがあり、例えば1ページ目を表示したいときは`currentIndex = 0`とすることでリストの0番目から29番目を取得できます、

```:ChangeIndex
public void ChangeIndex(int n)
{
    currentIndex += n;
    if(currentIndex<0)currentIndex=0;
    else if(currentIndex>indexList.Count-2) currentIndex = indexList.Count-2;
    SetRanking(indexList[currentIndex],indexList[currentIndex+1],all);
}
```
S3の用語要点まとめ１（自分用メモ

Amazon S3（Simple Storage Service）

保存容量が無制限のオブジェクトストレージサービス（SaaSのサービス）
オブジェクトストレージとは、データを固有のIDを持つ「オブジェクト」として扱う、ディレクトリのような階層構造を持たないストレージのこと。
オブジェクトに割り当てられる固有のIDは「オブジェクトキー」と呼ばれ、各データはオブジェクトキーによって一意に特定できる。
オブジェクトが保存される領域を「バケット」と呼ぶ。一つのバケットにはオブジェクト数が無制限で保存でき、バケット名はグローバルで一意にする必要がある。
作成したバケットのバケット名は変更できないので注意。
一つのオブジェクトには一つのURLが付与され、URLにはリージョン、バケット名、オブジェクトのファイル名が付く。


・ストレージクラス
S3のストレージは、利用者が目的に合わせて選択できるよう複数の種類（ストレージクラス）がある。
ストレージクラスは、大きく分けて「可用性」と「遅延の度合い」によって分けられ、可用性が高く、データ取得時の遅延が低いストレージクラスほど利用料金が高く設定されている。
オブジェクトアップロード時のデフォルトのストレージクラスは「S3 Standard」。


・ライフサイクルポリシー
S3バケット内のデータに対して、ストレージクラスの変更やオブジェクトの削除を自動化する機能。指定した期間が経過したデータを自動的に、よりコストパフォーマンスの高いストレージへ移動したり、保管期限の過ぎたデータを削除することができる。アクセス頻度が予測できるデータや、保管期間が決められているデータのバケットに設定することで、コスト削減の効果が期待できる。


・バージョニング
オブジェクトの世代管理をしたい場合にバケット単位で有効にする。バージョニングを有効にすると、オブジェクトの更新時に更新前と更新後の両方のオブジェクトが保存され、各オブジェクトに固有のバージョンIDが割り当てられる。オブジェクトの削除時には、オブジェクトを完全に削除する代わりに削除フラグを意味する削除マーカーが付与され、それが最新のバージョンとなる。バージョニングを使うことで、ユーザーが誤ってデータの上書きや削除をしてしまっても元のデータを復元できます。


・MFA Delete
S3のバージョニング機能で世代管理されているオブジェクトを削除する際に、MFAデバイス認証が必要となる機能。
MFA（Multi-Factor Authentication：多要素認証）とはIDやパスワードと同時に、指紋などのバイオメトリクスやワンタイムパスワードを利用する認証方法。
MFA Deleteでは、ルートアカウント（AWSとの契約を行ったアカウント）と紐付いたMFAデバイスによる認証が求められます。MFA Deleteが有効になったバケットのオブジェクトを完全に削除する際は、ルートアカウントにてMFA認証した上で削除したいオブジェクトのバージョンIDを指定。
DTOとは

### DTO(Data Transfer Object)とは

* ユーザーの要請データをサーバに受け渡し、サーバの応答データをユーザーに渡すオブジェクト
* MVCでは、ControllerがModelとViewのデータを送受信するときにDTOを使用する
* User ⇄ View ←[DTO]→ Controller ←[DTO]→ Model

#### DTOを使用する利点
* Modelを**カプセル化**し、UI画面で使用するデータのみを選択的に送信することで情報漏洩を防止する
* 複数のデータをまとめて1つの要請に送ることができ、データの検証とロジック処理が1回で終わる
* 検証とロジック処理を何度もしないことで安定性が高くなり、処理時間が短縮される

　※**カプセル化**は、変数(データ）とメソッド（データの処理行為）を1つに結び、
　　外部には見せないようにすること。データ保護のために使用する
【yocto】レシピ内変数の早見表

# はじめに
- デフォルトでは、おそらく下記表のようになっている
- 環境によっては必ずしも下記表とは限らないため、注意すること
- (メンテ中)

# path系変数
|変数名|内容|備考|
|---|---|---|
|${base_bindir}|/bin|-|
|${base_libdir}|/lib|-|
|${base_prefix}||-|
|${base_sbindir}|/sbin|-|
|${bindir}|/usr/bin|-|
|${datadir}|/usr/share|-|
|${docdir}|/usr/share/doc|-|
|${exec_prefix}|/usr|-|
|${includedir}|/usr/include|-|
|${infodir}|/usr/share/info|-|
|${libdir}|/usr/lib|-|
|${libexecdir}|/usr/libexec|-|
|${localstatedir}|/var|-|
|${mandir}|/usr/share/man|-|
|${nonarch_base_libdir}|/lib|-|
|${nonarch_libdir}|/usr/lib|-|
|${oldincludedir}|/usr/include|-|
|${prefix}|/usr|-|
|${sbindir}|/usr/sbin|-|
|${servicedir}|/srv|-|
|${sharedstatedir}|/com|-|
|${sysconfdir}|/etc|-|
|${systemd_system_unitdir}|/lib/systemd/system|-|
|${systemd_unitdir}|/lib/systemd|-|
|${systemd_user_unitdir}|/usr/lib/systemd/user|-|

- 確認方法は2通り
~~~
$ cat poky/meta/conf/bitbake.conf
$ bitbake -e recipe-name | grep "export "
~~~

# その他
|変数名|内容|備考|
|---|---|---|
|${S}|ソースコードの展開先| |
|${BPN}|レシピ名|zlib-native-1.2.11-r0の場合、zlib|
|${PN}|(prefix、suffixが付いた)レシピ名|zlib-native-1.2.11-r0の場合、zlib-native。BBCLASSEXTENDでnative等を無指定の場合、\\${PN}=${BPN}。|
|${PV}|バージョン|zlib-native-1.2.11-r0の場合、1.2.11|
|${PR}|リビジョン|zlib-native-1.2.11-r0の場合、r0|
|${BP}|\\${BPN}-${PV}|zlib-native-1.2.11-r0の場合、zlib-1.2.11|
|${PF}|\\${PN}-\\${PV}-${PV}|zlib-native-1.2.11-r0の場合、zlib-native-1.2.11-r0|
|${TOPDIR}|buildディレクトリ|poky/build|
|${TMPDIR}|${TOPDIR}/tmp|poky/build/tmp|
|${WORKDIR}|\\${TMPDIR}/work/\\${MULTIMACH_TARGET_SYS}/<br>\\${PN}/\\${EXTENDPE}\\${PV}-\\${PR}|zlib-native-1.2.11-r0の場合、poky/build/tmp/work/x86_64-linux/zlib-native/1.2.11-r0|
|${D}|${WORKDIR}/image|zlib-native-1.2.11-r0の場合、poky/build/tmp/work/x86_64-linux/zlib-native/1.2.11-r0/image|
昨日までの投稿を削除するバッチ処理

## 記事の対象者
バッチ処理で投稿のデータを管理したい人

## 前提条件
Ruby 2.6.3
Rails 6.1.5

## 実装の流れ
**１、削除プログラムの作成
２、gem【whenever】の導入**

## 削除プログラムの作成
app/libの配下にbatchフォルダを作成します。
次に作成したbatchフォルダの中でdata_reset.rbファイルを作成して以下を記述して保存します。

```php:app/lib/batch/data_reset.rb
class Batch::DataReset
  def self.data_reset
    @activity_points = ActivityPoint.all.where("date <= ?", Date.yesterday)
    @activity_points.delete_all
    p "前日の活動拠点を全て削除しました"
  end
end
```
コードの解説をします。
私は活動日が昨日になっているものを削除するプログラムを作成しました。
ActivityPointモデル内にあるdateカラムから日付が昨日のものを抽出します。
※[データ抽出の参考記事](https://qiita.com/thk__u/items/741711bd743b80eda51a)

```php:app/lib/batch/data_reset.rb
    @activity_points = ActivityPoit.all.where("date <= ?", Date.yesterday)
```

## gem【whenever】の導入
wheneverはcrontab管理を行なってくれるgemです。
crontabとは、cronという定期的に指定のプログラムを実行するスケジューラーの設定を編集するための管理コマンドです。viエディタで操作するのでviの操作に慣れておかなくてはなりません。
**一方、wheneverはRailsでの記述をcrontabへ反映させてくれるので管理が便利になります。**
[wheneverの参考記事](https://easyramble.com/rails-cron-with-whenever.html)
```php:config/schedule.rb
# 1日１回前日までのデータを削除
require File.expand_path(File.dirname(__FILE__) + "/environment")
rails_env = Rails.env.to_sym
set :environment, rails_env
set :output, 'log/cron.log'
every 1.day, :at => '4:30 am' do
  begin
    runner "Batch::DataReset.data_reset"
  rescue => e
    Rails.logger.error("aborted rails runner")
    raise e
  end
end
```


## まとめ
昨日のデータを取り出して削除という簡単なプログラムですが、データの抽出方法に意外と時間を取ってしまいました。データ操作を考えるの楽しいです。もっと扱えるようになりたいです。

少しでも参考になれば幸いです。
最後まで読んでいただきありがとうございました。
emacsの電卓のいいとこ、ちょっとした表示の改善

## 環境
Windows GNU emacs 29あたりです。

## 「今更電卓って！」と思うなかれ
普段ソフトウェア開発をしている関係で、

2進数、10進数、16進数変換

をそこそこ良く行います。
そんなちょっとした計算をするために、Windowsの電卓を起動するのは面倒ですよね。
また、引き出しに眠っている電卓取り出すのはプライドが許さない、のです。


## emacsの電卓のいいとこ
普段の作業母艦であるemacsの電卓で良いものがないかなーと探してみたら、emacs標準のもの(calculator)が好みに合っていて気に入りました。

### 気に入ったこと
#### 1. ショートカットキーで進数切り替えが一瞬でできる
　　　16進数(Shift+H)
　　　10進数(Shift+D)
　　　2進数(Shift+B)   

    例) 16進数で、B7 入力。
        そこで Shift+Bキーで2進数 1011'0111 がすぐ表示される。
        それって、キーボードホームポジションから手を離すことなく計算できる
#### 2. 計算結果をソースコードに反映させるの簡単(emacsでソース書いてるから)
#### 3. 編集中の内容を邪魔しないようにemacs内に小さく表示される


## ちょっとした表示の改善
emacs電卓気に入ったものの、小さく表示されすぎてemacsのタブモードのタブ表示で数字や式の表示が見切れてしまうのが残念でした。
電卓起動したあと、手作業でウインドウサイズを調整してから計算って、面倒です。

init.elに以下のhook(*1)を追加するだけで電卓初期表示サイズが解決できたのであげておきます。

~~~ init.el
;; calculator をタブモードで開くのでウインドウサイズ垂直方向に2つ大きくする
(add-hook 'calculator-mode-hook
'(lambda ()
(enlarge-window 2)))
~~~


emacs標準電卓を小窓で表示して、16進数 F * 24 計算してるところ。
![emacs_calculator.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2712713/0d9acf3b-f2a7-cb53-8f5f-36de5d5d9bfb.png)


追記) MacOS GNU emacs 28,29ではこの設定なしに見切れず表示されました。環境依存ぽいです。


*1) emacs lisp hook については、 https://tomoya.hatenadiary.org/entry/20100112/1263298132 あたりの記事が詳しくお世話になっています。


本日はマニアックな話題にお付き合いありがとうございます。
2022年6月21日に発生したCloudflareの大規模障害の原因

# 概要

* 今回は、2022年6月21日に発生したCloudflareの大規模障害についての原因がまとめられた記事が公開されたため、その内容について翻訳およびサマライズしていきます。

https://blog.cloudflare.com/cloudflare-outage-on-june-21-2022/

# 何が起こったのか

* 2022年6月21日にCloudflareの19のデータセンターのトラフィックに影響を与える障害が発生したようです。
* また、この19のデータセンターはどうやら世界中のトラフィックのかなりの割合を扱う拠点だったようです。
* ではなぜ、大規模な障害が発生したのかというと、原因はどうやらこれらの重要な拠点の耐障害性を向上させるための変更(ネットワーク設定の変更)を行なったことが起因しているようです。
* **なので、今回の障害では悪意のある攻撃等ではなかったことになります。**

## 障害が発生した時刻と復旧した時刻

* 障害が発生した時刻は、2022年06月22日 15:58ごろに発生し、2022年06月22日 16:42ごろにはすべてのデータセンターが正常に動作するようになったようです。
* **わずか44分ほどでの復旧さすがです。。**

## ちなみにTwitterで確認できた影響を受けたサービス一覧

* Twitterで調べたところ、どうやら下記のサービスが影響を受けていたようですね。

  * discord
  * pixiv
  * 5ちゃん
  * VRC
  * DeepL
  * 原神
  * ブルーアーカイブ
  * 雀魂
  * VALORANT
  * BOOTH
  * ホロライブ公式ショップ
  * ToonBlast
  * アークナイツ
  * LOL
  * Uxアップローダー
  * フラッシュパーティ
  * Fortnite
  * Anker Japan

## 世界規模での影響度はどれくらい？

* 下記の図は、時間ごとにおけるグローバルにおいて処理し成功したHTTPリクエストを表しています。
* 影響を受けた時間帯で成功したリクエスト数がガクっと落ちていますが、これらの場所ではリクエスト全体の50％に影響を与えていたとブログでは記載されています。

![スクリーンショット 2022-06-22 0.58.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563635/485c65fb-6d55-1278-4ea6-2b7325cf6cab.png)

## 19のデータセンターの拠点はどこ？

* ブログによると下記の都市にあるようです。

  * アムステルダム
  * アトランタ
  * アッシュバーン
  * シカゴ
  * フランクフルト
  * ロンドン
  * ロサンゼルス
  * マドリード
  * マンチェスター
  * マイアミ
  * ミラノ
  * ムンバイ
  * ニューアーク
  * 大阪
  * サンパウロ
  * サンノゼ
  * シンガポール
  * シドニー
  * 東京

## Cloudflareにおけるネットワークアーキテクチャ

* Cloudflareでは[Closネットワーク](https://en.wikipedia.org/wiki/Clos_network)と呼ばれるメッシュ構造のアーキテクチャが採用されているようです。
* このメッシュ構造のアーキテクチャを利用すると、データセンターの内部ネットワークの一部を簡単に無効化および有効化して、メンテナンスや問題への対処を行うことができるようになるそうです。
* 実は今回はこのアーキテクチャにおいて欠点があり、クライアントのトラフィックを中断することなく、一部をメンテナンスしたりすることができるものの、この一部というのがかなりのトラフィックの流していた為、大きな影響を与えてしまったようです。

![スクリーンショット 2022-06-22 0.33.16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/563635/1ac086ca-f373-c5ac-153a-1d9ebd8f6c02.png)

### 根本の原因は何？

* もう少し深ぼっていくとCloudflareのネットワークではBGPなるプロトコルを使用しています。
* このBGPというプロトコルについては、深そうなので別記事にしたいと思います。
* 障害発生時、ルータの設定を変更するのですが、変更前に複数のエンジニアによるレビューも行われた状態だったようです。
* **変更内容としてはルーティングポリシーの更新だったようですが、「明示的な拒否」というルールが本来ルーティングされなければいけないルールより優先されるようになってしまったことが直接の原因のようです。**

## その後の対応

* 設定の誤りに気づいたため、問題のある変更を元に戻す作業を行い復旧となったようです。

# まとめ

* 詳細については、引用元のCloudflareの記事を読むことをお勧めしますが、この障害で様々なサービスの裏側ではCloudflareが使用されていることが分かりましたね。
* その影響のデカさからAWSの障害も疑われるくらいでしたw
* また、原因発覚から対応までの速さはめちゃめちゃ早かったと感じます。
* ただ、原因にも書きましたが複数のエンジニアによるレビューを通ったのに今回障害が発生してしまったとあるので、この障害を反面教師にGitのPRレビューはちゃんと隅々まで確認したいものです(汗)

# 引用

https://blog.cloudflare.com/cloudflare-outage-on-june-21-2022/
ガードチョイスの「ロケーションが見つかった場合」直後の「マウスを移動」でDeviceIssueやFinderIssueが発生する場合。


## 根拠まではわからないけど経験則的に行けそうな対応「備忘」
DAの Chromium において、デバッグ実行した際に `ロケーションが見つかった場合（Location Found）` の後続に続く `マウスを移動（Mouse Move）` でなぜかエラーが出てしまう場合、それは不完全な状態でコンポーネントを評価したまま次のステップに流れてしまっているからかもしれません。

Chromium 限定の属性値なのですが、そのような場合には指定コンポーネントの属性値として `[der_rendered="y"]` を追加してあげることでうまく同期をとって処理が動くようになったりします。
 ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1524794/aefb4594-cd89-a505-677a-9e47c345deea.png)
この属性は v11.2 以降は特に意識しなくても自動で付与されるようになっていますが、それ以前のバージョンについては意識して手動で追加してあげる必要があります。

かなり強力な設定値で、これを入れることで画面遷移の時などに時々設定していた「〇秒待って同期させる」[^1]必要が一切なくなり、断然Chromiumロボが安定して動作するようになりました。

[^1]:ガードチョイスで `秒が経過したとき（Seconds has passed）` を指定して固定秒数待たせる行為
初心者から始めるプログラミング　LeetCode:Valid Parentheses

## はじめに
 就活が始まり、コードテストなるものを受けるようになった。プログラミング自体は1~2年ほど前から学んでいたため、なんとかなるだろうとたかを括っていたら意外と難しい。しかも、今自分が使っている言語(TypeScript)はどうやらコードテストには向いていないらしい・・・
ちょうど、大学院の研究でPythonを使い始めたのでこれを機にPythonでアルゴリズムを学ぼうと決意。
その中で、自分が引っかかった点や学びになった点を備忘録を兼ねて記載していきます。

本日はLeetCodeからStackの理解におすすめと噂の20.Valid Parenthesesを解いていきます。

## 問題
{　,　}　,　[　,　]　,　(　,　)この6種類の文字が組み合わされて文字列sとして与えられます。
例えば、s='{]()'など
その時,Sが正しい括弧の並びになっているかを判定するというもの。
例えば、

`s='()'`はtrue
`s='{}()[]'` はtrue 
`s='{)[)'`はfalse

空文字列もtrueになるのには要注意です。

## 解法
まず考えたことはペアをどう教えるかということです。
今回は辞書のkeyとvalueとして `pair = {'(':')','{':'}','[':']'}`と管理することにしました。

次に、正誤判定の方法に関して。ここではスタックという考え方を活用しました。

![スタック.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2713472/8fa47d42-89d7-743c-f9ad-953b0f1c8080.png)

スタックのイメージはこんな感じ。ブロックが縦に積んであると一番最後に積んだものしかとれないですね。
スタックとはいくつかの要素の中で最後に追加したものを取り出すという考え方になります。

今回のケースで考えると、左側の括弧が出てきたときはそれに対応する右括弧をStackに保存します。
`stack.append(pair[char])`
右側の括弧が出てきた場合それが’最後に保存された’右括弧と一致するかを確認し、一致した場合Stackから除外します。仮に一致しなかった場合、その時点で括弧が成立していないことがわかります。
`Array.pop()`は配列から最後の要素を除外しながらその除外した要素を返してくれます。とても便利ですね。

上の操作を文字列の中の全ての文字に行いStackの長さが0(0でなかったら余っている左括弧があるので括弧として成立していません。)のときにTrueを返せば完了です！

これらを行ったのが以下のコード


```
class Solution:
    def isValid(self, s: str) -> bool:
        stack = []
        pair = {'(':')','{':'}','[':']'}
        
        for char in s:
            if char in pair.keys():
                stack.append(pair[char])
            else:
                if len(stack) == 0 or char != stack.pop():
                    return False
        
        if len(stack) == 0:
            return True
        return False
```

## 終わりに
今回学んだことは、
・Array.pop()はただ配列から要素を消すのではなく、消した要素も受け取れる。
・要素を1列に並べ、最後に加えられた要素から取り出していくデータ構造をスタックという。
でした！

また、コーディングの勉強をするたびに時間があれば書いていこうと思うので最後まで読んでくださった方がいれば改善点など教えていただけると幸いです。
最近SQLを書くのが楽しい

実務でOracleのSQL\*Plus使い始めて、そろそろ1ヶ月です。
振り返りがてら、どんな感じで成長したのか見ていこうと思います。

# SQLと出会った当初

### 知らない言葉が多すぎる
当時の脳内こんな感じでしたね。

* SELECT:わかる
* FROM:わかる
* WHERE:ホエア?
* HAVING:食事?
* オーダーバイク:かっこいい

単一行関数が出てきたあたりでオーバーフローしました。
SQLは「データ操作言語」で、私にとって多少蓄積のあった「プログラミング言語」ではないので、新しい単語と概念多すぎて全然頭に入ってきませんでした。

### 一文に要素が多すぎて読めない
C++がほんのすこし書けるんですが、せいぜい一行でセミコロンにたどり着きます。
SQL長過ぎませんか?
SELECTやWHEREで5個も出てきたらショートするし(しかもカラム名ってだいたい長い)、副問合せとかもうわからん。
上司や先人たちに蓄積されたスクリプト、1個の問い合わせに平気で20行くらいあります。
全然わからないのに、大量のアルファベットが直接脳内に来るので、毎日パンクしていたような。

### 思い通りの出力ができない
欲しいデータをどこに取りに行けばいいかわからない。
いい感じに出力したいだけなのに、上司のスクリプトをコピらないとできない。
Silver DBAを取るときに、そのくらい勉強したはずなのに…
「もうSQLとわかりあえる日は来ないんだ…」と思ってました。

# いま

### ユーザを消して作るSQLが書ける
```
DROP USER hogehoge CASCADE;
CREATE USER "hogehoge"
IDENTIFIED BY "egohegoh";
GRANT CREATE SESSION TO hogehoge;
GRANT RESOURCE TO hogehoge;
```
これですね。コード甘いかもしれないですが目を瞑って下さい。
実務で、検証時に無限回ユーザ(スキーマ)作って表作ってユーザごと消して…をやるおかげで、普通に書けるようになりました。
(SQLの勉強だけしてた頃は書けなかったです。なんでや)

### SQL*Plusのおまじないがわかり、定義情報を取れるようになった
set lin 1000
set pages 500
col owner for a10
col max_value for 999999999999999999999999999
こういうのですね。
最初はおまじないと言われて育てられたが、気にはなっていた。
この子たちがわかって、やっと出力時の整形ができるようになりました。

1ヶ月仕事した結果、こんなのを1から書けるように。
```sqlplus:hoge
spool C:\hogehoge\hogelog

conn hogehoge/egohegoh@oraora

set lin 1000
set pages 500
col owner for a10
col table_name for a50
col constraint_name for a50

select count(*)
from dba_indexes
where owner = 'hogehoge';

select owner,index_name
from dba_indexes
where owner = 'hogehoge'
order by index_name;

spool off
```
コード甘いかもしれないですが目を瞑って下さい(2回目)。
どこから取るのかすら不明だった定義情報も、a10をa20にして文字数オーバーの改行が起きないようにするなど、工夫しながら確認できるようになりました。
SQLとはわかりあえないと思ってたので、こういうのを仕事内容に合わせて柔軟に書けるようになったのは、感慨深いですね…

### 安全なDBの運用保守がちょっとわかる
依頼があってDBの運用保守する過程で、例えばカラム追加なら、
・カラム追加するテーブルは存在するか?
・既にテーブルに同名のカラムはないか?
など、安全に運用するための確認観点がわかるようになってきました。
止めてはいけない基幹システムですから、ミスしない仕組みは重要だなって常々思ってます。

## まだまだ知らないこといっぱい
新人が1ヶ月でできるようになることなんて、たかが知れてると思います。
でも、こう見返すと「ちょっとはできるようになったのかも~」って調子に乗りそうです。

ここまで成長できたのは、何万行あるスクリプトをボンと渡してくれた上司のおかげですね。
最初はヒーヒー言ってましたが、今はすごく楽しいです。
[RSpec] トップレベルに定義されたメソッドをモックする方法

## サンプルコード
トップレベルに定義した`hoge`メソッドをモックして、モックできたことの検証を行うテストです。
```ruby:hoge_spec.rb
require 'rspec/core'

def hoge
  '👍'
end

RSpec.describe 'トップレベルに定義されたメソッドをモックする' do
  it 'モック前に👍を返し、モック後に👎を返す' do
    expect(hoge).to eq '👍'

    allow_any_instance_of(Object).to receive(:hoge).and_return('👎')

    expect(hoge).to eq '👎'
  end
end
```

上記のテストをRSpecで指定して実行すると、成功します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/468458/fa32148e-399f-5a6d-ebe8-8fab79e9fbdc.png)

## なぜ成立するのか？
モックを行っている箇所は下記のコードです。
Objectクラスに定義されたインスタンスメソッド`#hoge`をモックしています。
```ruby
allow_any_instance_of(Object).to receive(:hoge).and_return('👎')
```

トップレベルで定義したメソッドは Objectクラスのprivateインスタンスメソッドとして定義されるため、上記のコードでモックが可能になるという原理です。

参考: [Ruby 3.1 リファレンスマニュアル object main](https://docs.ruby-lang.org/ja/latest/class/main.html)

https://docs.ruby-lang.org/ja/latest/class/main.html

## そもそもトップレベルに定義したメソッドをモックするような機会が在ってはいけない
トップレベルにメソッドを定義した場合、
呼び出し箇所が分かり辛かったり、意図せず上書きしてしまうといった問題があります。
利用できるスコープはできるだけ狭めたいものです。

下記の記事ではRubyのRefinements機能を使ってスコープを限定する方法を紹介してるので、
参考にしてください。

https://qiita.com/hanachin_/items/6cf63dd3987a60e3d264
MongoDBのデータダンプとリストア

## 概要

MongoDBのデータダンプとリストアの方法について記載します。

## ダンプ

```sh
mongodump -d {database} -c {collection} -o {OUTPUT_PATH} 
```

- コレクションの指定が必要なければ `-c`の指定は不要
    - `-c`の指定がなければデータベース内のすべてのコレクションを取得する

## リストア

```sh
mongorestore  -d {database} -c {collection} --dir {dir}
```


### ※注意
リストア時、`-d`オプション無しで、

```sh
mongorestore /tmp/mongotest/user.bson
```

のように実行することも可能であるが、その際、bsonファイルの親ディレクトリがデータベース名として認識されるので注意
(上記の例でいうとmongotestというデータベースが作成され、その中にuserコレクションがリストアされる)

また、`user.metadata.json`のようなjsonファイルがbsonと同ディレクトリ内に存在しない場合、Indexは登録されない
(jsonファイルにIndex情報を持っている)
VBA_13_Class_Get_Set_サンプル

Keyword
---
Class
private
Get
Set

Sample Source
---
```vb:Modules
Public Sub MySample20220620()
    Dim mySheet As Worksheet
    Dim myWktime2 As Class_WorkTime2
    Dim myWktime3 As New Class_WorkTime3
    Dim myData As Variant
    Dim i As Long, j As Long
    Dim myDataList As New Collection
    
    Debug.Print "追加前：" & myDataList.Count & "件"

    Set mySheet = ThisWorkbook.Sheets("20220620")

    myData = mySheet.UsedRange
   
    For i = LBound(myData, 1) + 1 To UBound(myData, 1)
        Set myWktime2 = New Class_WorkTime2
        
        myWktime2.BusinessDay = myData(i, 1)
        myWktime2.DayOfWeek = myData(i, 2)
        myWktime2.WorkTime = myData(i, 3)
        
        myDataList.Add myWktime2
    Next i
    Debug.Print "追加後：" & myDataList.Count & "件" 
End Sub
```

```vb:Class Modules 1
Private myBusinessDay As String
Private myDayOfWeek As String
Private myWorkTime As Long

Public Property Get BusinessDay() As String
    BusinessDay = myBusinessDay
End Property
Public Property Get DayOfWeek() As String
    DayOfWeek = myDayOfWeek
End Property
Public Property Get WorkTime() As Long
     WorkTime = myWorkTime
End Property
Public Property Let BusinessDay(ByVal pBusinessDay As String)
    myBusinessDay = pBusinessDay
End Property
Public Property Let DayOfWeek(ByVal pDayOfWeek As String)
    myDayOfWeek = pDayOfWeek
End Property
Public Property Let WorkTime(ByVal pWorkTime As Long)
    myWorkTime = pWorkTime
End Property
```
```vb:Class Module 2
Private mySheetInfo As Collection
Private myClassWorkTime2 As Class_WorkTime2

Public Property Get SheetInfo() As Collection
    Set SheetInfo = mySheetInfo
End Property
Public Property Get ClassWorkTime2() As Class_WorkTime2
    Set ClassWorkTime2 = myClassWorkTime2
End Property
Public Property Set SheetInfo(ByVal pSheetInfo As Collection)
    Set mySheetInfo = pSheetInfo
End Property
Public Property Set ClassWorkTime2(ByVal pClassWorkTime2 As Class_WorkTime2)
    Set ClassWorkTime2 = pClassWorkTime2
End Property
```
【SAPトライアル環境構築】トライアル環境のライセンス延長はできるか？

<!-- wp:paragraph -->SAP Cloud Platformは30日、SAP GUIは90日のライセンス期間が設定されていますが、有効期間後はライセンスの延長ができるのか試してみました。

## SAP Cloud Platformのライセンス延長

延長方法は不明です。厳密に言えば一度はライセンス延長ができたのですが、二度目の延長がうまくいきません。やり方が悪いのか・・・。一度目にうまくいった手順を載せておきます。

### トライアル環境にログイン

以前の投稿を参考にトライアル環境にログインします。

https://qiita.com/sapmemo/items/7f0e53da6d3260a5ff5e

### アカウント延長

アカウント延長を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2712997/4d2fe25b-aa6c-d88e-930c-6168b176b72d.png)

これで延長作業は完了です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2712997/2c47ee96-42ef-9169-2ce0-b09266fad37f.png)

アカウント延長後にEclipseでプロジェクトを開けばログインできるはずなのですが、二度目の延長処理後は下記画面の通り承認はされるのですが、承認画面がループして先に進みません。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2712997/fc2b673d-1145-2a42-3a11-250a06cad431.png)

## SAP GUIのライセンス延長

### 準備作業

以前の投稿を参考にして、SAPサーバを起動してください。

https://qiita.com/sapmemo/items/2cfd7c1e506301cef6c9

### SAP GUIへのログイン

上記の投稿ではユーザID：DEVELOPERでログインしていますが、有効期限が切れた後はそのユーザでは入れなくなるため、別ユーザでログインします。

| クライアント | 001 |
|--------------------|-----|
| ユーザ | SAP* |
| パスワード | Down1oad |

### 既存ライセンス削除

Tr-cd：SLICENSEを実行

明細行の一番右に「Expired」と表示されているので期限切れの状態になっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2712997/3fa879ed-49e2-2a7d-c279-e91e88ff8b6c.png)

行選択し、右クリック⇒Delete Licenseを実行します。

期限切れの行を全て削除してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2712997/15d3aa8e-afad-5419-8c9e-fc87b7c46a70.png)

### ライセンスファイル更新

こちらを参考にライセンスファイルの取得からSAPへのインストールまでを実行してください。

https://qiita.com/sapmemo/items/2cfd7c1e506301cef6c9#%E9%96%8B%E7%99%BA%E8%80%85%E3%83%A9%E3%82%A4%E3%82%BB%E3%83%B3%E3%82%B9%E5%8F%96%E5%BE%97 

これでライセンスの延長が完了です。

あとはCloud Platformの再延長をどうやるか、完全に期限が切れた後に試してみます。
【ABAP】メッセージタイプによる挙動の違い（サンプルあり）

<!-- wp:paragraph -->アドオン開発で意外と盲点になるのがメッセージ出力の部分です。

ABAPでの基本的な機能の一つなので何が盲点なのかと疑問に思う方もいるかと思いますが、エラーメッセージを出力するときの挙動が作る人によって違うことがよくあります。

設計者が「エラーメッセージを出力する」と設計書に書いて、開発者が字面通りに実装しても、設計者が思い描いている挙動と異なる場合があるのです。

それでは何故そんなことが起きるのか、メッセージについて詳しくみていきましょう。

## SAPで出力できるメッセージの種類
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2712997/25b2c1de-5d2b-db13-4bb8-4687794476ca.png)
ABAPヘルプに記載がありますが、まとめると以下の6種類あります。

| メッセージタイプ | テキスト | 挙動 |
|--------------------------|--------------|--------|
| S | 正常メッセージ | 処理続行 |
| I | 情報メッセージ | 処理続行 |
| W | 警告メッセージ | 中断or続行を実行時に選択 |
| E | エラーメッセージ | 中断 |
| A | 強制終了メッセージ | プログラム終了 |
| X | 実行時エラー | ショートダンプ |

タイプAとX以外の4つはプロジェクトでよく使われますが、

レポートプログラムでメッセージを出力する場合、実装するイベントによって挙動が変わる場合があるので、設計者・開発者が共通の認識を持つことが重要です。

具体的な挙動は次で見ていきます。

## 警告メッセージ、エラーメッセージを出力する場合の注意点

警告メッセージ、エラーメッセージを出力したい場合、実装位置がイベント「AT SELECTION-SCREEN」であるか「START-OF-SELECTION」であるかで挙動が大きく変わるので注意が必要です。

### 警告メッセージ（タイプW）

AT SELECTION-SCREEN内（画面左側）で警告メッセージを出力する場合は、仕様通り警告メッセージとして選択画面上に表示されますが、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2712997/23e56e82-da39-27dc-048a-eb1534f48f24.png)
START-OF-SELECTION内（画面右側）で警告メッセージを出力すると、警告のメッセージタイプを指定してもエラーメッセージとして表示されます。しかも選択画面を抜けてしまっているので、メッセージが出た画面でENTERキーを押下すると、メニューの画面まで戻ってしまいます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2712997/bdd1370e-6eac-f6fd-f104-76e1071c20fb.png)

### エラーメッセージ（タイプE）

AT SELECTION-SCREEN内（画面左側）でエラーメッセージを出力する場合は、選択画面上にエラーメッセージが表示されますが、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2712997/8e178630-6ad1-178b-56b8-b700a8d359e2.png)

START-OF-SELECTION内（画面右側）でエラーメッセージを出力すると、警告メッセージの場合と同様に選択画面を抜けてエラーメッセージが出力されてしまいます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2712997/a419828c-f223-51c6-6ceb-a5ceeea8f4f7.png)

選択画面を抜けてエラーメッセージが出力されるケースを実際のプロジェクトで案外よく見かけますが、操作性が悪くなるので避けるべきです。

一般的に、AT SELECTION-SCREENは選択画面項目のチェック処理、START-OF-SELECTIONはデータ抽出以降の主処理を実装するイベントとして使用されますが、主処理以降でエラーメッセージを出力したい場合はどうすればいいのでしょうか。

実装方法を見ていきましょう。

## DISPLAY LIKEオプションを効果的に使う

メッセージを出力する命令文はそのままMESSAGEですが、そのオプションに「DISPLAY LIKE ～ 」というものがあります。

英語の直訳通りの意味ですが、「メッセージタイプを～のように見せる」というもので、STAR-OF-SELECTION内でエラーメッセージを出力する場合はこのやり方が一般的です。

こんな感じで使います。

```
  MESSAGE 'test message' TYPE 'S'DISPLAY LIKE'E'.
  LEAVE LIST-PROCESSING.
```

ポイントは2つ。

- TYPE指定するメッセージタイプはS（正常）でDISPLAY LIKEオプションで表示したいメッセージタイプを指定すること
- LEAVE LIST-PROCESSINGで処理を終了すること
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2712997/149d93ea-73d0-ae80-c422-2de99bffe34e.png)

## まとめ

- START-OF-SELECTION内での警告メッセージ、エラーメッセージ出力は避けるべき
- 代わりにDISPLAY LIKEオプションで警告やエラーのように見せること

メッセージ出力時の挙動については、あまり意識されない部分のため、作る人によって挙動が変わってしまうことがよくあります。

しかし、ユーザから見ると挙動に統一感がないのは好ましくありません。結合テストなどの後工程に入ってから挙動を統一するために修正をする可能性もあります。

設計時からメッセージ出力時の挙動を意識しておくことで、後ろの工程での手戻りをなくすことにも繋がりますので、設計者はもちろん開発者も意識するのが良いと思います。
【ABAP】ALV – 一覧へのステータスアイコン表示（サンプルあり）

<!-- wp:paragraph -->大量データの一括登録時などで、処理結果をALV一覧で出すときに信号アイコンで処理ステータスを表現することがあります。状態把握という点で言えば、色の違いで把握できるので使う側からすればわかりやすくなります。

早速実装方法を見ていきましょう。

サンプルコードは下記投稿のものをベースに更新します。

[【ABAP】ALV – 一覧リフレッシュ機能の実装（サンプルあり）](https://qiita.com/sapmemo/items/524d906409550aa87d7a)

## 実装方法

### ALV表示用構造にステータス項目を追加

ステータス表示用の項目「STATUS」を追加しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2712997/6b400090-c2f2-6630-cbf3-eafa95025a23.png)
### プログラム実装

レイアウトパラメータにステータスアイコン用の設定をします。

```
  wa_layout-lights_fieldname  = 'STATUS'.

  loop at it_main assigning field-symbol(<fs_main>).
    <fs_main>-status = sy-tabix.
  endloop.

  DATA: it_extab TYPE slis_t_extab.
  APPEND '&GRAPH' TO it_extab.

  CALL FUNCTION 'REUSE_ALV_GRID_DISPLAY'
    EXPORTING
      it_fieldcat              = it_fcat
      is_layout                = wa_layout
      i_callback_program       = sy-repid
      i_callback_pf_status_set = 'SET_GUI_STATUS'
      i_callback_user_command  = 'USER_COMMAND'
      it_excluding             = it_extab
    TABLES
      t_outtab                 = it_main
    EXCEPTIONS
      program_error            = 1
      OTHERS                   = 2.
```

結果がこちらです。構造上は最終行にステータスを追加しましたが、ALV表示錠は先頭に表示されます。

ステータスの設定値は以下の通りです。

| 1 | 赤信号 |
|---|-----------|
| 2 | 黄信号 |
| 3 | 青信号 |

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2712997/c6146b20-0c9a-77dd-5ee6-e547288b7506.png)
一覧に信号アイコンが表示されましたが、一つ問題が。

ステータスの項目が「Exception（例外）」となっているのです。ラベルが「Status（ステータス）」であるにも関わらず。

ステータスのラベルを直すために次の一文を追加します。

```
  wa_layout-lights_rollname   = 'STEP_COLOR'.</span>
```

レイアウトパラメータの「LIGHTS_ROLLNAME」にステータス項目のデータエレメントを指定します。そうすることで、データエレメントのラベルが表示されるようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2712997/43700924-ff60-0c05-7fe9-b5b3f1c8a95f.png)

## まとめ

- レイアウトパラメータにステータスアイコン表示用の項目あり
- 項目名とステータスの値を設定するだけで信号アイコンが表示される
- ラベルが「Exception（例外）」と表示される場合はデータエレメントのパラメータ設定漏れを疑うこと

これだけ覚えておけば簡単に実装できますので参考にしてください。
【SAPトライアル環境構築】- 雑記 - SAP GUIにリモート接続したくてやり方を考えてみた

<!-- wp:paragraph -->このブログを書いている環境 ＝ SAP GUIを入れている環境なんですが、Macbook Pro 13インチを使っていて、1.4kgくらいあるんですね。

外出先でGUIにアクセスしようとすると、モバイルWi-Fiが必要ですし、何より1.4kgは気軽に持ち運ぶには少し重いんですね。あと、Macbookのタッチバッドだと縦スクロールが個人的にしんどい。

そこでどうしようかといろいろ思いついたことをメモがてら書いてみます。

たぶんほとんどの人には刺さらない話だとは思いますが。

## レッツノートを探してみた

軽量PCといえばレッツノート。自宅でメインで使ってるのは、メモリ8GB、ストレージ残容量が100GB前後とVirtualBoxで仮想サーバを立てるには心もとない。唯一SIMフリー版であることだけ条件は満たしているのですが。

ということで、ヤフオクで次の条件で探してみました。

- LTE付き（できればSIMフリー版）
- RAM 16GB
- SSD 512GB

・・・数が少ない、そして予算オーバー・・・。

新品同様品が1世代前くらいで30万程度。

1週間くらい探したのですが、そんなにすぐには出てきませんね。

ちなみに、パナソニック公式サイトで最新作を見てみましたが、Core i7版でカスタマイズして希望スペックに合わせると40万近く・・・。

レッツノート購入の線はなくなりました。

## 手持ちのレッツノートに入れられないか

新しいPC購入の前に手持ちレッツノートに入れられないのか、念のため確認してみました。

[SAP公式サイト](https://www.sap.com/documents/2019/09/32638f18-687d-0010-87a3-c30de2ffd8ff.html)でシステム要件を見てみると

- RAMは4GB以上、おすすめは8GB以上
- ストレージ容量は110GBくらい必要

メモリ8GBは何とか満たしているが、ストレージは微妙なところ。大容量のものに交換したいけど、SSD換装のやり方を調べてみるち、ちょっと心配。

さらに別の方法を考えてみました。

## Thinkpad T480を使ってみよう

そういえば、あまり使ってないThinkpad T480があったのを思い出す。

システム構成を見てみると、

- RAM 32GB
- ストレージ残容量 100GB

ストレージ容量が心もとないのは同じだけど、RAM32あれば十分。

ThinkpadのSSD換装は経験あるので、作業面での心配も少ない。

これでいこうと決定。

## というわけで・・・

Thinkpad T480のストレージ容量をアップさせて、そこにVirtualBoxとSAP GUIを入れてリモートデスクトップでレッツノートから接続する方法を試してみることにしました。

うまくいくのだろうか。。。

結果は調達した商品たちが届いたら更新します。
【ABAP】ALV –リフレッシュ時に行列の位置を保持する方法（サンプルあり）

<!-- wp:paragraph -->リフレッシュしたときに、表示データが多い場合に表示位置が先頭に戻って困る、リフレッシュボタンを押したときの位置をキープしたい、という方に解決方法を紹介します。

以前のALV一覧画面でのリフレッシュ機能で作ったサンプルをベースに作っていきます。

[【ABAP】ALV – 一覧リフレッシュ機能の実装（サンプルあり）](https://qiita.com/sapmemo/items/524d906409550aa87d7a)

## 事象確認

まずは事象を見てみましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2712997/35816585-e664-d4cf-b40e-b4621eb10272.png)
表示行や項目数を増やすと、縦横にスクロールバーが表示されます。

縦横にスクロールした状態でリフレッシュしてみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2712997/cbe4f4f8-30f4-869d-56f1-250ad59249ac.png)
スクロールバーの位置が縦横ともに先頭に移動してしまいましたね。

この現象を回避する方法を紹介します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2712997/c04841a9-a97d-6b71-e7d0-4101beaec52e.png)

## 実装方法（サンプルプログラム）

[【ABAP】ALV – 一覧リフレッシュ機能の実装（サンプルあり）](https://qiita.com/sapmemo/items/524d906409550aa87d7a)

こちらのサンプルをベースに、データ取得元をBUT000からSBOOKに変更したプログラムを作ってみました。

```
REPORT ytest0011.

TYPES:
  BEGIN OF t_main.
    INCLUDE TYPE sbook.
  TYPES:
    box TYPE checkbox,
  END   OF t_main.

DATA: it_main TYPE TABLE OF t_main.
DATA: it_fcat TYPE slis_t_fieldcat_alv.
DATA: wa_layout TYPE slis_layout_alv.

START-OF-SELECTION.
  PERFORM get_data.
  PERFORM display_alv.

FORM get_data.

  SELECT * FROM sbook INTO CORRESPONDING FIELDS OF TABLE it_main UP TO 500 ROWS.

ENDFORM.
FORM display_alv.

  CALL FUNCTION 'REUSE_ALV_FIELDCATALOG_MERGE'
    EXPORTING
      i_program_name         = sy-repid
      i_structure_name       = 'SBOOK'
      i_bypassing_buffer     = abap_on
    CHANGING
      ct_fieldcat            = it_fcat
    EXCEPTIONS
      inconsistent_interface = 1
      program_error          = 2
      OTHERS                 = 3.

  wa_layout-box_fieldname     = 'BOX'.
  wa_layout-colwidth_optimize = abap_on.
  wa_layout-zebra             = abap_on.

  DATA: it_extab TYPE slis_t_extab.
  APPEND '&GRAPH' TO it_extab.

  CALL FUNCTION 'REUSE_ALV_GRID_DISPLAY'
    EXPORTING
      it_fieldcat              = it_fcat
      is_layout                = wa_layout
      i_callback_program       = sy-repid
      i_callback_pf_status_set = 'SET_GUI_STATUS'
      i_callback_user_command  = 'USER_COMMAND'
      it_excluding             = it_extab
    TABLES
      t_outtab                 = it_main
    EXCEPTIONS
      program_error            = 1
      OTHERS                   = 2.

ENDFORM.
FORM set_gui_status USING it_extab TYPE kkblo_t_extab.

  SET PF-STATUS 'S001'.

ENDFORM.

FORM user_command USING i_ucomm    TYPE sy-ucomm
                        i_selfield TYPE slis_selfield.
  CASE i_ucomm.
    WHEN '&NTE'.  リフレッシュ
      PERFORM get_data.
      i_selfield-refresh     = abap_on.
     <span class="bold-blue"> i_selfield-col_stable  = abap_on.
      i_selfield-row_stable  = abap_on.</span>

      CALL FUNCTION 'REUSE_ALV_GRID_LAYOUT_INFO_SET'
        EXPORTING
          is_layout = wa_layout.

  ENDCASE.

ENDFORM.
```

ユーザコマンド処理の「I_SELFIELD」パラメータの2つの項目にフラグを立てるだけで実現できます。

- COL_STABLE
- ROW_STABLE

## まとめ

パラメータ2つを設定するだけと非常に簡単に実装できるので、困っている方は参考にしてください。
【ABAP】雑記 – ABAPで作られたゲーム

<!-- wp:paragraph -->トライアル環境でデモプログラムを探しているといくつかゲームを見つけましたので紹介してみます。いずれもSE38から実行できます。

## マインスイーパ

Windowsのプリインストールゲームとしても定番のマインスイーパがSAP環境にも用意されてました。

プログラム末尾の数字はABAPのリリース番号でしょうか。正確なところはわかりません。

DEMO_MINESWEEPER_740

DEMO_MINESWEEPER_700

![](https://sapmemo.com/wp-content/uploads/2020/08/image-81.png)![](https://sapmemo.com/wp-content/uploads/2020/08/image-82.png)![](https://sapmemo.com/wp-content/uploads/2020/08/image-92.png)
## Jawbreaker

同じ色のブロック同士をつなげて、少ないクリック数で全消しするゲームです。

マスは2×2が最小、15×15が最大でした。

DEMO_JAWBREAKER_HTML_740

DEMO_JAWBREAKER_HTML_700

![](https://sapmemo.com/wp-content/uploads/2020/08/image-84.png)![](https://sapmemo.com/wp-content/uploads/2020/08/image-85.png)同じ色のブロックがつながっていると1クリックでまとめて消せるようです。

![](https://sapmemo.com/wp-content/uploads/2020/08/image-86.png)私のベスト記録はこちら。上の続きで8クリックで全消しできました。

![](https://sapmemo.com/wp-content/uploads/2020/08/image-87.png)
## Game 2048

ゲームのルールは[Wikipedia](https://ja.wikipedia.org/wiki/2048_(%E3%82%B2%E3%83%BC%E3%83%A0))を参照してください。

ABAP7.40以降限定のようです。

矢印キーで操作します。

![](https://sapmemo.com/wp-content/uploads/2020/08/image-88.png)![](https://sapmemo.com/wp-content/uploads/2020/08/image-89.png)![](https://sapmemo.com/wp-content/uploads/2020/08/image-90.png)ここで右にスライドすると・・・

![](https://sapmemo.com/wp-content/uploads/2020/08/image-91.png)4と4がぶつかって8になり、スコアに8点加算されましたね。こうやって2048になるか、タイルの置き場所がなくなるまで続きます。結構時間がかかるので程々に。

## 最後に

ABAPで作られたゲーム3つを紹介しました。10年くらい前にいたプロジェクトでABAPでオセロを作った人がいたのを思い出しました。

ゲームだと挙動をイメージしやすいので、ABAPプログラミングの勉強に役立つのではないでしょうか。今回の3つはクラスの考え方を身に着けるのに良いと思いますよ。
【ABAP】ALV – ヘッダ情報出力（サンプルあり）

<!-- wp:paragraph -->ALV画面にヘッダを出力する方法を説明します。ツールバーのボタンやユーザコマンドに比べると使用頻度は少ないですが、初見でいきなりやってくれと言われても難しいのでここで紹介します。

ソースコードは下記投稿の続きです。

[【ABAP】ALV – ツールバーのボタン変更（REUSE_ALV_GRID_DISPLAY編）](https://sapmemo.com/alvbutton/)

## 実装方法（サンプルコード）

追加箇所を青字、さらに肝になる箇所を赤字で記載しました。

```
  CALL FUNCTION 'REUSE_ALV_GRID_DISPLAY'
    EXPORTING
      it_fieldcat              = it_fcat
      is_layout                = wa_layout
      i_callback_program       = sy-repid
      i_callback_pf_status_set = 'SET_GUI_STATUS'
      i_callback_user_command  = 'USER_COMMAND'
      i_callback_top_of_page   = 'TOP_OF_PAGE'
      it_excluding             = it_extab
    TABLES
      t_outtab                 = it_main
    EXCEPTIONS
      program_error            = 1
      OTHERS                   = 2.

FORM top_of_page.
  DATA: lt_head TYPE slis_t_listheader,
        lw_head TYPE slis_listheader.

* タイプH
  CLEAR: lw_head.
  lw_head-typ   = 'H'.
  lw_head-key   = 'TYPE:H'.
  lw_head-info  = 'タイプHのテスト'.
  APPEND lw_head TO lt_head.

* タイプS
  CLEAR: lw_head.
  lw_head-typ   = 'S'.
  lw_head-key   = 'TYPE:S'.
  lw_head-info  = 'タイプSのテスト'.
  APPEND lw_head TO lt_head.

* タイプA
  CLEAR: lw_head.
  lw_head-typ   = 'A'.
  lw_head-key   = 'TYPE:A'.
  lw_head-info  = 'タイプAのテスト'.
  APPEND lw_head TO lt_head.

  CALL FUNCTION 'REUSE_ALV_COMMENTARY_WRITE'
    EXPORTING
      it_list_commentary = lt_head.

ENDFORM.
```

### ①汎用モジュールのパラメータ追加

「I_CALLBACK_PROGRAM」に呼出元のプログラムID、

「I_CALLBACK_TOP_OF_PAGE」にヘッダ出力処理を実装するサブルーチン名を指定します。

### ②ヘッダ出力処理用のサブルーチン追加

「I_CALLBACK」で始まるパラメータに共通する考え方ですが、パラメータに指定した名前でサブルーチンを定義します。

### ③ヘッダ出力用汎用モジュール呼出

標準で用意されている汎用モジュール「REUSE_ALV_COMMENTARY_WRITE」を使います。

ヘッダに出力できる書式は決まっていて3種類の中から用途に応じて選んでください。

項目「typ」で制御します。

![](https://sapmemo.com/wp-content/uploads/2020/08/image-77.png)サンプルプログラムでは、「typ」、「key」、「info」の3項目全てにセットしていますが、実行結果ではタイプH、Aの「key」が出てませんね。

こういう仕様であることを知った上で使ってください。

表示順は内部テーブルの順番に関係なく、タイプH、S、Aの順に表示されます。また、同一タイプで複数レコードを表示することもできます。

![](https://sapmemo.com/wp-content/uploads/2020/08/image-80.png)
## まとめ

開発をやっててもALVヘッダを出力する機会は少ないかもしれませんが、標準機能で用意されている仕組みを使えば簡単に実装できますので参考にしてください。
Windowsで無線Profileを一括エクスポート、インポートするbat

以前に投稿した以下の記事で
端末移行などの際に登録しているprofileが多く
コマンド作るのが面倒だったのでbatをつくりました。
USB等で実行することで無線プロファイル移行が楽にできます。
　※今回はエクスポート用とインポート用で2つあります。

https://qiita.com/moomim/items/7f8bad3aea6658ba9ff0

# zipファイル
<p><a href="https://github.com/yyoshizu/SSID_Export-Inport.zip/releases/download/zip/SSID_Export-Inport.zip"download="https://github.com/yyoshizu/SSID_Export-Inport.zip/releases/download/zip/SSID_Export-Inport.zip">zipファイルをダウンロード</a></p>


# 移行できる無線Peofileについて
xmlとしてエクスポートできる箇所は赤枠の箇所のみ
ADからグループポリシーで配布しているものはできません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/475419/74d74438-fd01-fc3f-d5f0-166a75f7bd66.png)

# エクスポート手順
①　[SSID_Profile_Export.bat]を実行する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/475419/6ae99678-9f7a-9b29-8e91-4cdfb71a2b9b.png)

②以下のような画面が表示される
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/475419/60ec8a12-e27f-7612-2815-4be5c1064d67.png)

③ outputフォルダが作成され、中に生成した.xmlが格納される
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/475419/5c2a3fe1-d2f4-dbd0-af43-65314b813b4d.png)

# インポート手順

① bat格納フォルダ\output配下にインポートする.xmlを格納する
　　※SSID_Profile_Export.batの③と同じフォルダです。

②[SSID_Profile_Inport.bat]を実行する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/475419/cc12343d-7ab3-8612-d3b8-9d008ed0d7bf.png)

③以下のような画面が表示されて完了です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/475419/bbf75b74-557a-d706-4134-97f65f0076b5.png)

以上
【ABAP】ALV – ツールバーのボタン変更（REUSE_ALV_GRID_DISPLAY編）

<!-- wp:paragraph -->ALVツールバーに独自ボタンを追加したい、もしくは、標準の余計なボタンを消したイ場合にやることを説明します。

タイトルを「REUSE_ALV_GRID_DISPLAY編」としたのは、他のALV出力する汎用モジュールやクラスでは別のやり方になるからです。別の部品でのやり方についてもいずれ紹介したいと思っています。

ソースコードは下記投稿の続きです。

[【ABAP】ALV – ユーザコマンドの実装（サンプルあり）](https://sapmemo.com/alvusercommand/)

## 標準ボタンの削除

汎用モジュールへのパラメータ受け渡しだけで対応できます。

```
  DATA: it_extab TYPE slis_t_extab.
  APPEND '&GRAPH' TO it_extab</span>.

  CALL FUNCTION 'REUSE_ALV_GRID_DISPLAY'
    EXPORTING
      it_fieldcat             = it_fcat
      is_layout               = wa_layout
      i_callback_program      = sy-repid
      i_callback_user_command = 'USER_COMMAND'
      it_excluding            = it_extab
    TABLES
      t_outtab                = it_main
    EXCEPTIONS
      program_error           = 1
      OTHERS                  = 2.
```

元の画面からグラフボタンを削除してみました。

EXPORTINGパラメータの「IT_EXCLUDING」に削除したいボタンの機能コードを渡すだけです。

機能コードの確認は、メニュー⇒システム⇒ステータスからGUI STATUSを見てください。

![](https://sapmemo.com/wp-content/uploads/2020/08/image-70.png)修正前後の画面がこちらです。

左側の画面で赤く囲ったボタンが右側の画面にはありません。

- ![](https://sapmemo.com/wp-content/uploads/2020/08/image-71-wpp1598279126188.png)
- ![](https://sapmemo.com/wp-content/uploads/2020/08/image-72.png)

## 独自ボタンの追加

削除とは異なり、ボタンの追加は少し面倒ですが見ていきましょう。

### 独自のGUIステータスを作成

まずは、プログラム内にGUI STATUSを作成します。

このとき作成するGUIステータスの機能コードは、標準で用意されているテンプレートを使用してください。

メニュー⇒補足⇒テンプレート調整を選択

![](https://sapmemo.com/wp-content/uploads/2020/08/image-73-1024x684.jpg?v=1598279860)「List viewer」を選択して続行ボタン押下

![](https://sapmemo.com/wp-content/uploads/2020/08/image-73.png)アプリケーションツールバーにテンプレートで用意された機能コードや区切り線が表示されるす。不要なボタンや区切り線を削除したり独自ボタンを追加することができます。

ボタンと区切り線を合わせて35個まで定義できます。

左から3つ目に登録ボタンを追加してみました。

![](https://sapmemo.com/wp-content/uploads/2020/08/image-75-1024x439.png?v=1598280424)
### 汎用モジュールパラメータにGUIステータスを渡す

GUIステータスの表示なので、SET PF-STATUSを使いたくなるところですが、それだけでは認識されません。

サンプルコードの青字が追加部分、赤字は既存コードで今回の肝になる部分です。

```
  CALL FUNCTION 'REUSE_ALV_GRID_DISPLAY'
    EXPORTING
      it_fieldcat              = it_fcat
      is_layout                = wa_layout
      i_callback_program       = sy-repid
      i_callback_pf_status_set = 'SET_GUI_STATUS'
      i_callback_user_command  = 'USER_COMMAND'
      it_excluding             = it_extab
    TABLES
      t_outtab                 = it_main
    EXCEPTIONS
      program_error            = 1
      OTHERS                   = 2.

FORM set_gui_status USING it_extab TYPE kkblo_t_extab.

  SET PF-STATUS 'S001'.

ENDFORM.
```

「I_CALLBACK_PF_STATUS_SET」パラメータに、GUIステータス表示用のサブルーチン名を渡し、そのサブルーチン内でSET PF-STATUSを実行します。

実行すると追加ボタンが表示されたことが確認できます。

![](https://sapmemo.com/wp-content/uploads/2020/08/image-76.png)
## まとめ

ALVツールバーへのボタン追加は開発現場でよく出てきます。

独自ボタン押下時の処理は下記を参照してください。

[【ABAP】ALV – ユーザコマンドの実装（サンプルあり）](https://sapmemo.com/alvusercommand/)
【ABAP】ALV – ユーザコマンドの実装（サンプルあり）

<!-- wp:paragraph -->ALVレポートの開発でよく使うのがユーザコマンドの実装です。

セルをダブルクリックした場合の処理やボタン押下時の処理などがあります。

今回はセルのダブルクリックを例に説明します。

## 実装方法（サンプルコード）

追加箇所を青字、さらに肝になる箇所を赤字で記載しました。

```
REPORT ytest0008.

TYPES:
  BEGIN OF t_main.
    INCLUDE TYPE ytest0008.
  TYPES:
    box TYPE checkbox,
  END   OF t_main.

DATA: it_main TYPE TABLE OF t_main.
DATA: it_fcat TYPE slis_t_fieldcat_alv.
DATA: wa_layout TYPE slis_layout_alv.

START-OF-SELECTION.

  SELECT * FROM but000 INTO CORRESPONDING FIELDS OF TABLE it_main.

  CALL FUNCTION 'REUSE_ALV_FIELDCATALOG_MERGE'
    EXPORTING
      i_program_name         = sy-repid
      i_structure_name       = 'YTEST0008'
      i_bypassing_buffer     = abap_on
    CHANGING
      ct_fieldcat            = it_fcat
    EXCEPTIONS
      inconsistent_interface = 1
      program_error          = 2
      OTHERS                 = 3.

  wa_layout-box_fieldname     = 'BOX'.
  wa_layout-colwidth_optimize = abap_on.
  wa_layout-zebra             = abap_on.

  CALL FUNCTION 'REUSE_ALV_GRID_DISPLAY'
    EXPORTING
      it_fieldcat             = it_fcat
      is_layout               = wa_layout
      i_callback_program      = sy-repid
      i_callback_user_command = 'USER_COMMAND'
    TABLES
      t_outtab                = it_main
    EXCEPTIONS
      program_error           = 1
      OTHERS                  = 2.

FORM user_command USING i_ucomm    TYPE sy-ucomm
                        i_selfield TYPE slis_selfield.
  CASE i_ucomm.
    WHEN '&IC1'.  ダブルクリック
      READ TABLE it_main INTO DATA(lw_main) INDEX i_selfield-tabindex.
      <span class="bold-blue">IF sy-subrc <> 0.
        MESSAGE 'データ行を選択してください' TYPE 'S'.
        RETURN.
      ENDIF.
      ASSIGN COMPONENT i_selfield-fieldname OF STRUCTURE lw_main
                                            TO FIELD-SYMBOL(<fs_fnam>).
      CASE i_selfield-fieldname.
        WHEN 'PARTNER'.
          SET PARAMETER ID 'BPA' FIELD <fs_fnam>.
          CALL TRANSACTION 'BP'.
        WHEN 'CRUSR'.
          SET PARAMETER ID 'XUS' FIELD <fs_fnam>.
          CALL TRANSACTION 'SU01'.
        WHEN OTHERS.
          MESSAGE '画面遷移できません' TYPE 'S'.
          RETURN.
      ENDCASE.
  ENDCASE.

ENDFORM.
```

### ①汎用モジュールのパラメータ追加

「I_CALLBACK_PROGRAM」には呼出元のプログラムIDが必要なため、システム変数で自分自身のプログラムIDを指定しています。

「I_CALLBACK_USER_COMMAND」にはユーザコマンドを実装するサブルーチン名を指定します。

### ②ユーザコマンド実装用のサブルーチン追加

USINGパラメータは2つ決まったものがあります。1つ目は機能コード、2つ目は選択行や選択項目IDなどの情報を取得できます。

今回のサンプルコードでは、パートナを選択したらBPマスタへ、登録者を選択したらユーザマスタへ遷移する仕組みにしてみました。

3行目のパートナをダブルクリックすると、そのBPマスタの画面が表示されます。

- ![](https://sapmemo.com/wp-content/uploads/2020/08/image-66-wpp1598194487433.png)
- ![](https://sapmemo.com/wp-content/uploads/2020/08/image-67-1024x443.png)

1行目の登録者をダブルクリックすると、そのユーザマスタの画面が表示されます。

- ![](https://sapmemo.com/wp-content/uploads/2020/08/image-68-wpp1598194662607.png)
- ![](https://sapmemo.com/wp-content/uploads/2020/08/image-69.png)

## まとめ

今回のポイントは、「I_CALLBACK_USER_COMMAND」パラメータにサブルーチン名を指定する点です。こういうのは独学で辿り着くには時間がかかるので是非参考にしてもらって実装時間の短縮につながると幸いです。
【ABAP】ALV – 列幅の自動調整と行の縞模様表示（サンプルあり）

<!-- wp:paragraph -->今回はALV一覧の見栄えを上げるテクニックを紹介します。

列幅を表示データの桁数に合わせて自動で調整する機能と、奇数行と偶数行でセルの背景色を変えてくれる機能です。

## 列幅の自動調整

### 事象の確認

まずはこちらの一覧を見てください。

![](https://sapmemo.com/wp-content/uploads/2020/08/image-62-1024x196.png)名称（Name1）の列幅が表示データに対して必要以上に長く感じないでしょうか。パソコン画面の横幅には限界があるので、無駄に幅を取ってしまうと同じ項目数を表示するにも横スクロールが必要になり、操作性が悪くなります。

こんな時に役に立つのが幅の自動調整です。

### 対策方法

レイアウトパラメータの「COLWIDTH_OPTIMIZE」に\'X\'をセットするだけです。

```
  wa_layout-colwidth_optimize = abap_on.

  CALL FUNCTION 'REUSE_ALV_GRID_DISPLAY'
    EXPORTING
      it_fieldcat   = it_fcat
      is_layout     = wa_layout
    TABLES
      t_outtab      = it_main
    EXCEPTIONS
      program_error = 1
      OTHERS        = 2.
```

修正後の実行結果がこちらです。名称（Name1）の表示幅が小さくなりました。

![](https://sapmemo.com/wp-content/uploads/2020/08/image-63.png)
## 行の縞模様表示

### 事象の確認

上にも載せたように、データ行は単色で表示されます。

![](https://sapmemo.com/wp-content/uploads/2020/08/image-64.png)
### 対策方法

レイアウトパラメータの「ZEBRA」に\'X\'をセットするだけです。

```
  wa_layout-zebra             = abap_on.

  CALL FUNCTION 'REUSE_ALV_GRID_DISPLAY'
    EXPORTING
      it_fieldcat   = it_fcat
      is_layout     = wa_layout
    TABLES
      t_outtab      = it_main
    EXCEPTIONS
      program_error = 1
      OTHERS        = 2.
```

修正後の実行結果がこちらです。2行目の色が変わりました。奇数行と偶数行で色の濃淡がついて表示されます。

![](https://sapmemo.com/wp-content/uploads/2020/08/image-65.png)
## サンプルコード

レイアウトパラメータ2つを追加で設定しただけです。

```
REPORT ytest0008.

TYPES:
  BEGIN OF t_main.
    INCLUDE TYPE ytest0008.
  TYPES:
    box TYPE checkbox,
  END   OF t_main.

DATA: it_main TYPE TABLE OF t_main.
DATA: it_fcat TYPE slis_t_fieldcat_alv.
DATA: wa_layout TYPE slis_layout_alv.

START-OF-SELECTION.

  SELECT * FROM but000 INTO CORRESPONDING FIELDS OF TABLE it_main.

  CALL FUNCTION 'REUSE_ALV_FIELDCATALOG_MERGE'
    EXPORTING
      i_program_name         = sy-repid
      i_structure_name       = 'YTEST0008'
      i_bypassing_buffer     = abap_on
    CHANGING
      ct_fieldcat            = it_fcat
    EXCEPTIONS
      inconsistent_interface = 1
      program_error          = 2
      OTHERS                 = 3.

  wa_layout-box_fieldname     = 'BOX'.
  wa_layout-colwidth_optimize = abap_on.
  wa_layout-zebra             = abap_on.

  CALL FUNCTION 'REUSE_ALV_GRID_DISPLAY'
    EXPORTING
      it_fieldcat   = it_fcat
      is_layout     = wa_layout
    TABLES
      t_outtab      = it_main
    EXCEPTIONS
      program_error = 1
      OTHERS        = 2.
```

## まとめ

今回はALVの見栄えを上げるテクニック2つを紹介しました。どちらもよく使われる手法です。パラメータ1つ設定するだけで実現できるので知っておくと便利です。