RTX Video Super Resolutionを使う

AIを活用したアップスケーリング機能が、Google ChromeおよびMicrosoft Edgeブラウザで使用できるようになったらしいので早速設定する。ビデオの解像度より大きな解像度のディスプレイで再生する場合、単純な拡大だとぼやけた感じになってしまうところを、AIによってシャープにすることが出来るらしい。

どのような機能なのか詳しい内容はこちらの記事(Pixel Perfect: RTX Video Super Resolution Now Available for GeForce RTX 40 and 30 Series GPUs)を参照。

1.スタートボタンからNVIDIA Control Panelを起動する。

NVIDIA Control Panelの「ビデオ イメージ設定の調整」にある、「RTXビデオ強調」をオンにする。

Eclipseのフォントを変更する

いつもEclipseでコーディングするときは、MS ゴシックを使用していた。しかし、最近になってもっと見やすいフォントに変更したいと思うようになった(歳のせいかもしれない)。その過程で、プログラミング向けフォントというものがあることを知った。

これらのプログラミング向けフォントは幾つかの種類が公開されているが、今回は日本語に対応している「UDEV Gothic」を試してみることにした。

フォントのインストール

ダウンロードしたファイルを解凍して、右クリックのメニューからインストールをクリックする。UDEV Gothic内にも色々なスタイルが存在しているが、標準で良ければ以下の選択で良い。

Eclipseのフォントの変更

Eclipseの設定から、一般>外観>色とフォントを選択し、「テキスト・エディター・ブロック選択フォント」と「テキスト・フォント」のフォントをUDEV Gothicに変更する。

適用して閉じると以下の通りエディターのフォントが変わる。
変更前(MSゴシック):

変更後(UDEV Gothic):

かなり見やすくなったと思う。

Ubuntu Proを使ってみる

少し前に個人利用であれば、Proバージョンを無償で使用できるようになった。そこで、このサイトとは別に個人で利用しているサーバーのUbuntuをProにアップグレードしてみる。

Ubuntu Oneアカウント作成

Proバージョンの利用を始めるには、Ubuntu Oneアカウント作成しTokenを発行する必要がある。まだ持っていない場合は、以下のURLにアクセスしてアカウントを作成する。
https://login.ubuntu.com/

ログイン後、トップ画面に戻り、右上メニューのUbuntu Pro dashboadをクリックする。

画面が切り替わり少し待つと以下のような画面が表示されFree Personal Tokenが発行される。

Ubuntu Proにアップグレードする

Ubuntu Proを利用したいサーバー上で以下のコマンドを入力する。

sudo apt update
sudo apt upgrade
# 必要ならここでサーバー再起動
sudo pro attach 先ほどのトークン
sudo apt install ubuntu-advantage-tools
sudo apt update
sudo apt upgrade

ChatGPTを使ってみる

ちょっと試してみたくなった。

ユーザー登録

ユーザー登録だけで、今は無料で使用できる。最初に以下のページにアクセスし、「TRY CHATGPT」をクリックしてユーザー登録を行う。
https://openai.com/blog/chatgpt/

使ってみる

試しに「ChatGPTを上手に使うには?」と質問してみた。

ChatGPT:ChatGPTを上手に使うには以下のようなポイントがあります。

  1. 明確な質問をすること: ChatGPTには具体的な質問をすることが重要です。
  2. 十分な情報を提供すること: 質問に対する回答を最適化するために、できるだけ多くの情報を提供することが大切です。
  3. 自然な言語を使うこと: ChatGPTは人工知能モデルですが、自然な言語を使うことで、より正確な回答を得ることができます。
  4. 信頼性の高い情報ソースからの情報を求めること: ChatGPTはトレーニングデータに基づいていますが、常に正確な情報を保証することはできません。正確な情報を求める場合は信頼性の高い情報ソースからの情報を求めることをお勧めします。

対話式に質問を続けられるはすなので、さらに意地悪に質問を掘り下げてみた。

「ChatGPTからの回答が間違えている可能性はどのくらいあるのか?」

ChatGPT:ChatGPTはOpenAIによってトレーニングされた大規模な言語モデルですが、常に正確な回答を保証することはできません。トレーニングデータに基づいて回答を生成しますが、トレーニングデータに誤りが含まれていたり、最新の情報が含まれていなかったりする場合があります。また、ChatGPTは意図や文脈を正確に理解することもできない場合があります。そのため、ChatGPTからの回答を単独で信頼することは避け、常に他の情報源と照らし合わせて判断することが重要です。

「そうではなくて、間違いが含まれている可能性の具体的な数値を知りたい。」

ChatGPT:具体的な数値は提供されていませんが、ChatGPTは高精度の言語モデルであり、多くの場合、正確な回答を生成します。ただし、トレーニングデータに基づいているため、トレーニングデータに含まれていない情報や最新の情報に対する回答など、間違いが含まれる可能性があります。また、文脈や意図の誤りなどもありますので、常に他の情報源と照らし合わせて判断することが重要です。

「最新の情報ほど間違いが含まれている可能性が高いということか?」

ChatGPT:はい、そのような傾向があります。トレーニングデータは一定期間前の情報であり、最新の情報は含まれていない可能性があります。また、最新の情報はまだ完全には明らかでない場合もありますので、正確性が低い可能性があります。そのため、最新の情報に関する質問に対しては特に他の情報源と照らし合わせて確認することが重要です。

まとめ

同じような回答になってしまっているところもあるが、自然に会話しているように文章が繋がっている。本当にすごいツールが出てきたと思う。

Java 8のOptionalクラスの考察

動機

Optionalについて、うまく使えていない気がするため、改めて整理してみる。

実装例

Nullチェック

nullの一番の問題点は、nullチェックを行わなくともコンパイルエラーにならないこと。そして実行時にNullPointerExceptionが発生する可能性があること。

例として、nullチェックを行う場合について考えてみる。

public String getFruit() {
    return 果物の名前または、nullを返却する処理とする;
}

public void fruitCheck() {
    var fruit = getFruit();

    if (fruit != null) {
        System.out.println(fruit + " are delicious.");            
    }
}

これを単純にOptionalに置き換えると下記のようになる。

public Optional<String> getFruit() {
    String name = 果物の名前または、nullを返却する処理とする;
    return Optional.ofNullable(name);
}

public void fruitCheck() {
    var fruit = getFruit();

    if (fruit.isPresent()) {
        System.out.println(fruit.get() + " are delicious.");
    }
}

これだと、nullチェックを行っているときと変わらない。この処理を典型的な関数型プログラミングのスタイルに書き換えてみる。

public void fruitCheck() {
    var fruit = getFruit();

    fruit.ifPresent(name -> System.out.println(name + " are delicious."));
}

elseの処理が必要な場合は、下記のように書ける。

fruit.ifPresentOrElse(name -> System.out.println(name + " are delicious."),
        () -> System.out.println("I'm hungry."));

Nullの場合にデフォルト値を設定する処理

getFruit()のメソッドでnullを返すのではなく、nullの場合デフォルトの値を返す場合を考えてみる。

public String getFruit() {
    String name = 果物の名前または、nullを返却する処理とする;

    if (name != null) {
        return name;
    } else {
        return "Apple";
    }
}

public void fruitCheck() {
    var fruit = getFruit();

    System.out.println(fruit + " are delicious.");            
}

Optionalに置き換えると下記のようになる。

public String getFruit() {
    String name = 果物の名前または、nullを返却する処理とする;

    return Optional.ofNullable(name).orElse("Apple");
}

関数型プログラミングのスタイルになって、Nullチェックのミスも減るだろうか。

Nullチェックするとともに値のチェックも行う場合

public void fruitCheck() {
    var fruit = getFruit();

    if (fruit != null && fruit.equals("Banana")) {
        System.out.println(fruit + " are very delicious.");            
    }
}
public void fruitCheck() {
    var fruit = getFruit();

    fruit.filter(name -> name.equals("Banana"))
            .ifPresent(name -> System.out.println(name + " are delicious."));
}

Nuxt 3が出たので使ってみる

動機

Vue 3に対応したNuxt 3がリリースされたので、早速使ってみる。

ゴール

以前作成した下記のアプリと同等の機能を実装する。すでに、Vue3対応は完了しているため、大きな変更は必要ないはず。
https://github.com/hide6644/crawler-client

今回はインストールまで行う。インストール途中に「

ExperimentalWarning: The Fetch API is an experimental feature. This feature could change at any time

」のワーニングが表示されるが、今は気にしても仕方がないので、無視する。

インストール

実行環境
Windows 11
node 18

npx nuxi init プロジェクト名
cd プロジェクト名
npm install

実行

npm run dev

実行後、http://localhost:3000/にアクセスすると、welcomeページが表示される。

開発環境

開発環境には、Visual Studio Codeを使用する。インストール済みであれば、先ほどのインストールフォルダで、「code ./」を実行すると即座に起動できる。
(プラグインVolar ExtensionTypeScript Vue Plugin (Volar)のインストール推奨)

Javaでファイル内容を比較し、結果を別ファイルに出力する

目的

キーが1対1の関係になっている2つのファイルを1行ずつ読みだし内容を比較する。その比較結果を別のファイルに出力するプログラムをJavaで作成する。

要件

〇入力ファイル
 ・在庫ファイル
   商品コード
   在庫数
 ・注文ファイル
   商品コード
   注文数
 ※それぞれ、商品コードで一意、昇順になっている。

〇出力ファイル
 ・新在庫ファイル
   商品コード
   在庫数
 ・エラーファイル
   商品コード
   注文数
 新在庫ファイル・・・入力ファイルの在庫と注文を突合して、在庫数から注文数を引いた数量を記録する
 エラーファイル・・・注文に対して、在庫がない、在庫が足りない場合はエラーとし、当ファイルに出力する

〇その他
 入力ファイルのサイズが大きいため、1行ずつ読み込んで処理していく必要がある。

実装例

public void matching() {
    try (var stockFile = Files.newBufferedReader(Paths.get("src/stock.txt"));
            var orderFile = Files.newBufferedReader(Paths.get("src/order.txt"));
            var newStockFile = Files.newBufferedWriter(Paths.get("src/newStock.txt"));
            var errorOrderFile = Files.newBufferedWriter(Paths.get("src/errorOrder.txt"));) {
        // 入力ファイルの1行目を読み込む
        // 文字列からオブジェクトに変換する
        Stock stock = Stock.createFromLine(stockFile.readLine());
        Order order = Order.createFromLine(orderFile.readLine());

        // どちらかのファイルの行があるうちは処理を続ける
        while (stock.getKey() < Integer.MAX_VALUE || order.getKey() < Integer.MAX_VALUE) {
            // 比較するコードを取得。(この例ではコードを数値としている)
            // コードで昇順になっているのでコードの大小を比較すれば、
            // 一方のファイルにしかない商品もわかる
            int stockKey = stock.getKey();
            int orderKey = order.getKey();

            if (stockKey - orderKey == 0) {
                // コードが一致
                int qty = stock.getQuantity() - order.getQuantity();

                if (qty < 0) {
                    // 在庫不足
                    // エラーファイル出力
                    errorOrderFile.write(order.toErrorOrder("01").toLine());
                    errorOrderFile.newLine();
                } else {
                    stock.setQuantity(qty);
                }

                // オブジェクトから1行分の文字列を生成し、書き出す
                newStockFile.write(stock.toNewStock().toLine());
                newStockFile.newLine();
                // 次の行を読み込む
                stock = Stock.createFromLine(stockFile.readLine());
                order = Order.createFromLine(orderFile.readLine());
            } else if (stockKey - orderKey > 0) {
                // 商品なし
                // エラーファイル出力
                errorOrderFile.write(order.toErrorOrder("02").toLine());
                errorOrderFile.newLine();
                // 次の行を読み込む
                order = Order.createFromLine(orderFile.readLine());
            } else {
                // 注文なし
                newStockFile.write(stock.toNewStock().toLine());
                newStockFile.newLine();
                // 次の行を読み込む
                stock = Stock.createFromLine(stockFile.readLine());
            }
        }
    } catch (IOException e) {
        e.printStackTrace();
    }
}

※他にも「var」宣言を使える箇所があるが、わかりやすくするため、あえて通常の宣言にしている。

@Builder
@Data
public class Order {

    private String category;
    private String code;
    private Integer quantity;

    public Integer getKey() {
        if (category == null && code == null) {
            return Integer.MAX_VALUE;
        } else {
            return Integer.valueOf(category + code);
        }
    }

    public ErrorOrder toErrorOrder(String errorCode) {
        return ErrorOrder.builder()
                .category(category)
                .code(code)
                .quantity(quantity)
                .errorCode(errorCode)
                .build();
    }

    public static Order createFromLine(String line) {
        if (line == null) {
            return Order.builder().build();
        } else if (line.length() < 35) {
            throw new IllegalArgumentException();
        }

        return Order.builder()
                .category(line.substring(4, 5))
                .code(line.substring(6, 7))
                .quantity(Integer.valueOf(line.substring(8, 9)))
                .build();
    }
}

NextCloudをUbuntu 22.04で動かす

前提条件

下記が導入済みであること
Apache 2
PHP 8.1
MariaDB

NextCloudのインストール

NextCloudのダウンロード

NextCloudのページからzipファイルをダウンロードする。

cd /var/www/html
wget https://download.nextcloud.com/server/releases/nextcloud-25.0.1.zip

NextCloudの配置

unzip nextcloud-25.0.1.zip
chown -R www-data:www-data /var/www/html/nextcloud

Apacheの設定

vi /etc/apache2/sites-available/nextcloud.conf
<Directory /var/www/html/nextcloud/>
  Require all granted
  Options FollowSymlinks MultiViews
  AllowOverride All
  <IfModule mod_dav.c>
    Dav off
  </IfModule>
</Directory>
sudo a2ensite nextcloud.conf
sudo a2enmod rewrite
sudo systemctl restart apache2
メモリエラーの解消
/etc/php/8.1/apache2/php.ini
memory_limit = 512M

Spring Boot 3にアップグレードする

目的

Spring Boot 3がリリースされたので、以前作成したプロジェクトをアップグレードしてみることにした。

主な変更点

主な変更点は「Spring Framework 6にアップグレードする」に記載したことと同じ。

実際に変更した箇所

依存関係

ライブラリの変更、またはバージョンアップを行った。

  • Spring Boot 3
  • hibernate-search-mapper-orm => hibernate-search-mapper-orm-orm6 6.1

コードの変更点

javaxをjakartaに書き換えただけの部分は省略する。

Spring Securityの設定箇所で@Configurationの追記が必要になった。

@EnableWebFluxSecurity
@EnableReactiveMethodSecurity
public class WebSecurityConfig {
    ↓
@Configuration
@EnableWebFluxSecurity
@EnableReactiveMethodSecurity
public class WebSecurityConfig {

まとめ

gradleを使用していれば、ほとんどの依存関係の更新も自動で行われるので、かなり簡単にアップグレードできた。

Spring Framework 6にアップグレードする

目的

Spring Framework 6がリリースされ、その他のパッケージも合わせて変更できそうだったので、勉強のために以前作ったプロジェクトをSpring Framework 6にアップグレードしてみることにした。

主な変更点

Jakarta EE 9への対応

大まかに言うとjavaxからjakartaに変わる。

import javax.servlet.http.HttpServletRequest;
    ↓
import jakarta.servlet.http.HttpServletRequest;

さらに、Jakarta EEに対応しているTomcat 10などに、デプロイする必要がある。

実際に変更した箇所

依存関係

ライブラリの変更、またはバージョンアップを行った。

  • greenmail 2
  • hibernate… 6.1
  • hibernate-search-mapper-orm => hibernate-search-mapper-orm-orm6 6.1
  • hibernate-validator 7
  • javax.el => jakarta.el 4
  • javax.servlet => jakarta.servlet 6
  • jakarta.mail 2
  • jakarta.xml.bind-api 3
  • jaxb-runtime 3
  • spring-core… 6
  • spring-data-jpa 3
  • spring-security… 6
  • thymeleaf-spring5 => thymeleaf-spring6 3.1
  • thymeleaf-extras-springsecurity5 => thymeleaf-extras-springsecurity6 3.1

コードの変更点

javaxをjakartaに書き換えただけの部分は省略する。

Spring MVC設定の変更

下記のようThymeleafのspring5パッケージをspring6に変更する。Resolver以外も同様に変更する。

    <bean id="templateResolver" class="org.thymeleaf.spring6.templateresolver.SpringResourceTemplateResolver">

MultipartResolverはStandardServletMultipartResolverを使用する。
web.xmlの<servlet>タグに<multipart-config>の設定を追加すると有効になる。

<bean id="multipartResolver" class="org.springframework.web.multipart.support.StandardServletMultipartResolver" />

Thymeleaf Ver. 3.1にアップグレードも同時に行った場合は下記の変更も必要になる。
Thymeleaf 3.1にアップグレード

web.xmlの変更

下記の通り、変更する。

<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
  version="5.0">

まとめ

javaxからjakartaに変更する箇所は多いが、結構簡単にアップグレード出来た。