ChatGPT で調べる Singleton Pattern

試してみます。


👉 ChatGPT hatena-bookmark

日本語ではどうなのか。

👉 Singleton パターン - Wikipedia hatena-bookmark

 

■ "java singleton"

In Java, a singleton is a design pattern that ensures that a class has only one instance and provides a global point of access to it. This is useful when you need to have only one instance of a class for the entire application, such as for managing a shared resource.

To implement a singleton in Java, you would typically create a static member in the class that holds the sole instance of the class, and provide a static method that returns the instance. This method is typically called getInstance(). Here is an example:


public class Singleton { 
    private static Singleton instance; 

    private Singleton() { 
        // Private constructor to prevent instantiation 
    } 

    public static Singleton getInstance() { 
        if (instance == null) { 
            instance = new Singleton(); 
        } 
        return instance; 
    } 

}

To use the singleton, you would call the getInstance() method, like this:


Singleton instance = Singleton.getInstance();

It is important to note that a singleton in Java is not thread-safe by default. If multiple threads can access the getInstance() method simultaneously, it is possible for two or more instances of the class to be created. To make the singleton thread-safe, you can use synchronization in the getInstance() method, like this:


public static synchronized Singleton getInstance() { 
    if (instance == null) { 
        instance = new Singleton(); 
    } 
    return instance; 
}

This ensures that only one thread can execute the getInstance() method at a time, which prevents multiple instances of the class from being created.

 

■ "javaでシングルトン"

Javaでシングルトンとは、あるクラスが1つのインスタンスだけを持ち、そのインスタンスに対するグローバルなアクセスポイントを提供するデザインパターンです。これは、アプリ全体で1つのクラスのインスタンスだけが必要な場合に役立ちます。例えば、共有リソースの管理などです。

Javaでシングルトンを実装するには、通常はクラス内にクラスの唯一のインスタンスを保持するための静的メンバーを作成し、そのインスタンスを返す静的メソッドを提供します。このメソッドは通常、getInstance()と呼ばれます。以下に例を示します。


public class Singleton {
    private static Singleton instance;

    private Singleton() {
        // Private constructor to prevent instantiation
    }

    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

シングルトンを使用するには、getInstance()メソッドを呼び出します。以下はその例です。


Singleton instance = Singleton.getInstance();

Javaでのシングルトンはデフォルトでスレッドセーフではありません。複数のスレッドが同時にgetInstance()メソッドにアクセスできる場合、クラスの2つ以上のインスタンスが作成される可能性があります。シングルトンをスレッドセーフにするには、getInstance()メソッド内で同期を使用します。以下に例を示します。


public static synchronized Singleton getInstance() {
    if (instance == null) {
        instance = new Singleton();
    }
    return instance;
}

これにより、1つのスレッドだけがgetInstance()メソッドを実行できるようになり、クラスの複数のインスタンスが作成されることを防ぎます。

 

■ "java で singleton"

Javaでのシングルトンとは、あるクラスが1つのインスタンスだけを持ち、そのインスタンスに対するグローバルなアクセスポイントを提供するデザインパターンです。これは、アプリ全体で1つのクラスのインスタンスだけが必要な場合に役立ちます。例えば、共有リソースの管理などです。

Javaでシングルトンを実装するには、通常はクラス内にクラスの唯一のインスタンスを保持するための静的メンバーを作成し、そのインスタンスを返す静的メソッドを提供します。このメソッドは通常、getInstance()と呼ばれます。以下に例を示します。


public class Singleton {
    private static Singleton instance;

    private Singleton() {
        // Private constructor to prevent instantiation
    }

    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

シングルトンを使用するには、getInstance()メソッドを呼び出します。以下はその例です。


Singleton instance = Singleton.getInstance();

Javaでのシングルトンはデフォルトでスレッドセーフではありません。複数のスレッドが同時にgetInstance()メソッドにアクセスできる場合、クラスの2つ以上のインスタンスが作成される可能性があります。シングルトンをスレッドセーフにするには、getInstance()メソッド内で同期を使用します。以下に例を示します。


public static synchronized Singleton getInstance() {
    if (instance == null) {
        instance = new Singleton();
    }
    return instance;
}

これにより、1つのスレッドだけがgetInstance()メソッド

 

■ "kotlin singleton"

In Kotlin, a singleton is a design pattern that ensures that a class has only one instance and provides a global point of access to it. This is useful when you need to have only one instance of a class for the entire application, such as for managing a shared resource.
To implement a singleton in Kotlin, you can use the object keyword. This keyword is used to create a single instance of a class. Here is an example:


object Singleton { 
    fun doSomething() {
        // Code to perform some operation 
    } 
}

To use the singleton, you can simply call its methods like any other object, without the need to call a getInstance() method:


Singleton.doSomething()

One advantage of using the object keyword to implement a singleton in Kotlin is that it is thread-safe. Because the object keyword creates a single instance of the class, and because this instance is created when the class is loaded, multiple threads cannot access the getInstance() method simultaneously, and so it is not possible for multiple instances of the class to be created. This means you do not need to use synchronization to make the singleton thread-safe.

 

■ kotlin で singleton

Kotlinでのシングルトンとは、あるクラスが1つのインスタンスだけを持ち、そのインスタンスに対するグローバルなアクセスポイントを提供するデザインパターンです。これは、アプリ全体で1つのクラスのインスタンスだけが必要な場合に役立ちます。例えば、共有リソースの管理などです。

Kotlinでシングルトンを実装するには、objectキーワードを使用します。このキーワードは、クラスの1つのインスタンスを作成するために使用されます。以下は例です。


object Singleton {
    fun doSomething() {
        // Code to perform some operation
    }
}

シングルトンを使用するには、getInstance()メソッドを呼ぶ必要がないので、他のオブジェクトのように単にそのメソッドを呼び出します。以下はその例です。


Singleton.doSomething()

Kotlinでシングルトンを実装する際に、objectキーワードを使用する利点の1つは、それがスレッド

 

■ "dagger singleton"

Dagger is a dependency injection framework for the Java and Android platform. It is not itself a singleton, but rather a framework for creating and managing objects that are singletons or have other specific scope.
To create a singleton with Dagger, you would first define a class that provides the singleton instance. This class is called a "module" in Dagger terminology. Here is an example of a singleton module in Dagger:


@Module 
public class SingletonModule { 
    private static Singleton instance; 

    @Provides 
    @Singleton 
    public Singleton provideSingleton() {
        if (instance == null) {
            instance = new Singleton(); 
        }
        return instance; 
    } 
}

Next, you would define a "component" that uses the module to provide the singleton instance to other classes. Here is an example of a component that uses the above module:


@Component(modules = {SingletonModule.class}) 
public interface SingletonComponent { 
    Singleton getSingleton(); 
}

To use the singleton in your code, you would create an instance of the component and use it to get the singleton instance. Here is an example:


SingletonComponent component = DaggerSingletonComponent.create(); 
Singleton singleton = component.getSingleton();

In this example, the DaggerSingletonComponent class is generated by Dagger at compile time, based on the SingletonComponent interface. The create() method is a static factory method that creates an instance of the component.
By using Dagger to manage the singleton, you can avoid the need to use synchronization to make the singleton thread-safe, as Dagger takes care of this for you. Additionally, Dagger allows you to easily replace the singleton instance with a mock or test double in unit tests, which can make your tests more robust and easier to write.

 

■ "dagger2 singleton"

Dagger 2 is a dependency injection framework for the Java and Android platform. It is not itself a singleton, but rather a framework for creating and managing objects that are singletons or have other specific scope.
To create a singleton with Dagger 2, you would first define a class that provides the singleton instance. This class is called a "module" in Dagger terminology. Here is an example of a singleton module in Dagger 2:


@Module 
public class SingletonModule { 
    private static Singleton instance; 

    @Provides 
    @Singleton 
    public Singleton provideSingleton() { 
        if (instance == null) { 
            instance = new Singleton(); 
        }
        return instance; 
    } 
}

Next, you would define a "component" that uses the module to provide the singleton instance to other classes. Here is an example of a component that uses the above module:


@Component(modules = {SingletonModule.class}) 
public interface SingletonComponent { 
    Singleton getSingleton(); 
}

To use the singleton in your code, you would create an instance of the component and use it to get the singleton instance. Here is an example:


SingletonComponent component = DaggerSingletonComponent.builder().singletonModule(new SingletonModule()).build(); 
Singleton singleton = component.getSingleton();

In this example, the DaggerSingletonComponent class is generated by Dagger at compile time, based on the SingletonComponent interface. The builder() method is a static factory method that creates a builder for the component, which you can use to specify the module(s) to use.
By using Dagger 2 to manage the singleton, you can avoid the need to use synchronization to make the singleton thread-safe, as Dagger takes care of this for you. Additionally, Dagger 2 allows you to easily replace the singleton instance with a mock or test double in unit tests, which can make your tests more robust and easier to write.

 

■ "hilt singleton"

Hilt is a dependency injection framework for the Android platform, built on top of Dagger. It is not itself a singleton, but rather a framework for creating and managing objects that are singletons or have other specific scope.
To create a singleton with Hilt, you would first define a class that provides the singleton instance. This class is called a "module" in Hilt terminology. Here is an example of a singleton module in Hilt:


@Module 
@InstallIn(ApplicationComponent.class) 
public class SingletonModule { 
    private static Singleton instance; 

    @Provides 
    @Singleton 
    public Singleton provideSingleton() { 
        if (instance == null) { 
            instance = new Singleton(); 
        } 
        return instance; 
    } 
}

Next, you would annotate the class that wants to use the singleton with the @Inject annotation. Here is an example:


public class MyClass { 
  @Inject Singleton singleton; 
  // Code that uses the singleton goes here 
}

To use the singleton in your code, you would create an instance of the class and use the singleton. Hilt will automatically inject the singleton into the class when it is created. Here is an example:


MyClass myClass = new MyClass(); 
Singleton singleton = myClass.singleton;

By using Hilt to manage the singleton, you can avoid the need to use synchronization to make the singleton thread-safe, as Hilt takes care of this for you. Additionally, Hilt allows you to easily replace the singleton instance with a mock or test double in unit tests, which can make your tests more robust and easier to write.

 

■ "Flutter singleton"

In Flutter, a singleton is a design pattern that ensures that a class has only one instance and provides a global point of access to it. This is useful when you need to have only one instance of a class for the entire application, such as for managing a shared resource.
To implement a singleton in Flutter, you can use the Singleton class from the singleton_pattern package. Here is an example of how to use it:


import 'package:singleton_pattern/singleton_pattern.dart'; 
class MySingleton extends Singleton<MySingleton> { 
    // Code for your singleton goes here 
}

To use the singleton in your code, you would call the instance property of the class, like this:


MySingleton singleton = MySingleton.instance;

The Singleton class uses Dart's Isolates feature to ensure that the singleton is initialized only once and is thread-safe. This means you do not need to use synchronization to make the singleton thread-safe.

 

■ "Dart singleton"

In Dart, a singleton is a design pattern that ensures that a class has only one instance and provides a global point of access to it. This is useful when you need to have only one instance of a class for the entire application, such as for managing a shared resource.
To implement a singleton in Dart, you can use the Singleton class from the singleton_pattern package. Here is an example of how to use it:


import 'package:singleton_pattern/singleton_pattern.dart'; 
class MySingleton extends Singleton<MySingleton> { 
    // Code for your singleton goes here 
}

To use the singleton in your code, you would call the instance property of the class, like this:


MySingleton singleton = MySingleton.instance;

The Singleton class uses Dart's Isolates feature to ensure that the singleton is initialized only once and is thread-safe. This means you do not need to use synchronization to make the singleton thread-safe.
Alternatively, you can implement a singleton in Dart using a static property and a private constructor. Here is an example:


class MySingleton { 
    static final MySingleton instance = MySingleton._(); 
    MySingleton._(); // Private constructor 
    // Code for your singleton goes here 
}

To use the singleton, you would call the instance property, like this:


MySingleton singleton = MySingleton.instance;

This implementation is not thread-safe, so you would need to use synchronization if multiple threads can access the instance property simultaneously. For example:


class MySingleton { 
    static final MySingleton _instance = MySingleton._(); 
    static MySingleton get instance { 
        return _instance; 
    } 
    MySingleton._(); // Private constructor 
    // Code for your singleton goes here 
}

In this example, the instance property is a getter that uses synchronization to ensure that only one thread can access it at a time. This prevents multiple instances of the class from being created.

 

■ "swift singleton"

In Swift, a singleton is a design pattern that ensures that a class has only one instance and provides a global point of access to it. This is useful when you need to have only one instance of a class for the entire application, such as for managing a shared resource.

To implement a singleton in Swift, you would typically create a static constant property in the class that holds the sole instance of the class, and provide a static method that returns the instance. This method is typically called shared or sharedInstance. Here is an example:


class Singleton {
    static let shared = Singleton()

    private init() {
        // Private initializer to prevent instantiation
    }

    // Code for your singleton goes here
}

To use the singleton, you would call the shared property, like this:


let singleton = Singleton.shared

It is important to note that a singleton in Swift is not thread-safe by default. If multiple threads can access the shared property simultaneously, it is possible for two or more instances of the class to be created. To make the singleton thread-safe, you can use synchronization in the shared property, like this:


class Singleton {
    static let shared: Singleton = {
        let instance = Singleton()
        return instance
    }()

    private init() {
        // Private initializer to prevent instantiation
    }

    // Code for your singleton goes here
}

This ensures that only one thread can execute the shared property at a time, which prevents multiple instances of the class from being created.

 

■ まとめ

日本語で技術的なことを問う場合、英語、カタカナ、区切りなど複雑なので困ったりします。

コードについては、分かる人が見ればすぐに分かります。

どこかで見たような微妙なコードも含まれています。

「とりあえずそれっぽい」ので分からない人には分かりません。

逆に、Google検索と同じように使う側の技量が問われることになりそうです。

👉 Temporary policy: ChatGPT is banned - Meta Stack Overflow hatena-bookmark

👉 Kotlin で書きたい「正しいシングルトン(Singleton)」 hatena-bookmark

👉 チャットできるAI、ChatGPTが「そこまですごくない」理由。見えてしまった限界 | Business Insider Japan hatena-bookmark


Amazonの裏技「コマンド検索」を ブックマークレット化する

Amazon の検索やレビューもあやしくなってきてます。

こんな記事があります。

悪徳業者が幅を利かせるのが今のAmazon。「ベストセラー」を装ったり、最新製品を騙ったりとやりたい放題で、闇市化するAmazonでは安心して買い物できません。Amazon側がきちんと対策してくれればいいのですが、駆逐するのは無理な気も…。そこで、Amazonの裏コマンド検索を活用して、自分自身で悪質業者の商品を回避しましょう。Amazonの裏技「コマンド検索」で絞り込みするのが基本です。

👉 闇市化Amazonの裏技「コマンド検索」で絞り込み hatena-bookmark

早速、ブックマークレット化します。


javascript:(function () {

var url = location.href;
var win = window.open(null, null, "width=400,height=300");
win.document.write("<html><head><title>Amazon コマンド検索</title></head><body></body></html>");
win.document.body.innerHTML = `
<p><a target="_blank" href="${url}&emi=AN1VRQENFRJN5">→ マーケットプレイス出品を除外</a></p>
<p><a target="_blank" href="${url}&sort=popularity-rank">→ 人気順</a></p>
<p><a target="_blank" href="${url}&sort=salesrank">→ 売上順</a></p>
<p><a target="_blank" href="${url}&sort=review-rank">→ レビュー順</a></p>
<p><a target="_blank" href="${url}&sort=price">→ 安い順</a></p>
<p><a target="_blank" href="${url}&sort=releasedate">→ 発売日順</a></p>
<p><a target="_blank" href="https://radiolife.com/internet/amazon/45201/">→ 参考: ラジオライフ.com 記事</a></p>
`;

})();

改行やスペースありますが、そのままコピペで動きます。

ブックマークレットの登録方法は調べたら見つかります。

以下の記事がシンプルで分かりやすいと思いました。

👉 Chromeにブックマークレットを登録する | 寝坊した hatena-bookmark

ちなみに、Netflix ではこちら。

👉 Netflix 「裏コマンド」というよりか「ジャンルコード」 hatena-bookmark


KMM や マルチプラットフォーム を見据えて SQLDelight で Repository

👉 Getting Started - Multiplatform - SQLDelight hatena-bookmark
👉 SQLDelight 1.x Quick Start Guide for Android – Handstand Sam hatena-bookmark

マルチプラットフォームに対応していますが、

まずは、Android のみで使ってみると良いです。

👉 Getting Started - Android - SQLDelight hatena-bookmark

Todo アプリ向けの Repository を作ります。

Hilt と Flow を使っています。

 

■ インストール

Gradleまわりは書き方いろいろですけども適宜書き換えてください。


buildscript {
  repositories {
    google()
    mavenCentral()
  }
  dependencies {
    classpath 'com.squareup.sqldelight:gradle-plugin:1.5.3'
  }
}

apply plugin: 'com.squareup.sqldelight'

// android driver
implementation "com.squareup.sqldelight:android-driver:1.5.3"

// flow-coroutine extension 
implementation "com.squareup.sqldelight:coroutines-extensions:1.5.3"

 

■ スキーマ / クエリー

パッケージ名を、com.your.package としています。


-- app/src/main/sqldelight/com/your/package/data/Todo.sq

CREATE TABLE todo (
  id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
  text TEXT NOT NULL,
  updated INTEGER NOT NULL DEFAULT (strftime('%s', 'now'))
);

INSERT INTO todo(text) VALUES ('宿題をする');
INSERT INTO todo(text) VALUES ('マンガを読む');
INSERT INTO todo(text) VALUES ('プールに行く');

selectAll:
SELECT * FROM todo ORDER BY updated DESC;

deleteAll:
DELETE FROM todo;

insert:
INSERT INTO todo (text) VALUES (:text);

update:
UPDATE todo SET text = :text, updated = (strftime('%s', 'now')) WHERE id = :entryId;

delete:
DELETE FROM todo
WHERE id = :entryId;

count:
SELECT COUNT(id) FROM todo;

Todo.sq ファイルをテキストで作成して、テーブル定義、実行クエリーとメソッド名を箇条書きします。

配置位置は、上記コメントの位置が自然で分かりやすいと思います。

この場合、SQLDelight によって以下に実装に利用するクラス群が生成されます。


app/build/generated/sqldelight/code/Database/debug/com/your/package/

 

■ Database Module

SQLDelightによって生成された Database クラスを利用して書きます。

今回は Android向けなので、AndroidSqliteDriver を使っています。


@Module
@InstallIn(SingletonComponent::class)
object DatabaseModule {

  @Provides
  @Singleton
  fun provideDatabase(@ApplicationContext context: Context): Database {
    val driver = AndroidSqliteDriver(Database.Schema, context, DB_NAME)
    return Database(driver)
  }

  private const val DB_NAME = "database.db"
}

JetpackCompose の UI である Screen-level の Composable はマルチに稼働しているので、 @Singleton としておくことを忘れてはなりません。

 

■ Repository

時間のかかる処理は Flow を使っておきます。


class TodoRepository @Inject constructor(
  private val database: Database
) {

  fun load(): Flow<List<Todo>> {
    return database.todoQueries.selectAll().asFlow().mapToList(Dispatchers.IO)
  }

  fun count(): Flow<Long> {
    return database.todoQueries.count().asFlow().mapToOne(Dispatchers.IO)
  }

  fun insert(text: String) {
    database.todoQueries.insert(text)
  }

  fun update(id: Long, text: String) {
    database.todoQueries.update(text, id)
  }

  fun delete(id: Long) {
    database.todoQueries.delete(id)
  }

}

Flow - Couroutine Extension は非常に便利です。


fun load(): Flow<List<Todo>> {
  return database.todoQueries.selectAll().asFlow().mapToList(Dispatchers.IO)
}

Cold な Flow で単発の List<Todo> の emit ではなく、データベースが変更されるたびに、新しい List<Todo> を emit してくれます。


@JvmName("toFlow")
fun <T : Any> Query<T>.asFlow(): Flow<Query<T>> = flow {
  val channel = Channel<Unit>(CONFLATED)
  channel.trySend(Unit)

  val listener = object : Query.Listener {
    override fun queryResultsChanged() {
      channel.trySend(Unit)
    }
  }

  addListener(listener)
  try {
    for (item in channel) {
      emit(this@asFlow)
    }
  } finally {
    removeListener(listener)
  }
}

👉 sqldelight/FlowExtensions.kt at master · cashapp/sqldelight hatena-bookmark

(更新中...)

👉 Jetpack Compose で Todo アプリを作ってみた - Qiita hatena-bookmark


GitHub Code Search (Preview) の カスタムスコープ は強力 - cs.github.com

どこが新しくなったのか謎でしたが。

👉 GitHub Code Search (Preview) hatena-bookmark

「カスタムスコープ」機能が強力です。

分かりづらいとこにあるので見逃していました。

https://cs.github.com/

記述例に従って作成した自分のお気に入りスコープを複数保存することができます。

GitHub Code Search - cs.github.com

デフォルトに指定しておけばページを開いたときはそれが既に指定されています、

GitHub Code Search - cs.github.com

ちなみに、以前は検索できなかった記号も検索できるようになってます!
GitHub Code Search - cs.github.com

GitHub Code Search は、検索結果の並び替えをつけないことなど、こだわりのポリシーが感じられます。

期待できます。


GitHub Gist のコードをスクリプトから更新する方法

ブラウザ上で長文テキストを編集すること、

キモいですよね、クソです!

github gist edit browser

GitHub 公式のコマンドラインツールは便利です。
👉 cli/cli: GitHub’s official command line tool hatena-bookmark


$ gh gist -h
Work with GitHub gists.

USAGE
  gh gist <command> [flags]

CORE COMMANDS
  clone:       Clone a gist locally
  create:      Create a new gist
  delete:      Delete a gist
  edit:        Edit one of your gists
  list:        List your gists
  view:        View a gist

INHERITED FLAGS
  --help   Show help for command

ARGUMENTS
  A gist can be supplied as argument in either of the following formats:
  - by ID, e.g. 5b0e0062eb8e9654adad7bb1d81cc75f
  - by URL, e.g. "https://gist.github.com/OWNER/5b0e0062eb8e9654adad7bb1d81cc75f"

LEARN MORE
  Use 'gh <command> <subcommand> --help' for more information about a command.
  Read the manual at https://cli.github.com/manual

 

エディタを変える

このデフォルトのエディタ nano って誰が推してるんすかね。


$ gh gist edit f49d4d7a9963b77d00c89d1a3dbb6976

github gh gist edit nano

変えます、emacs に。


$ EDITOR=emacs gh gist edit f49d4d7a9963b77d00c89d1a3dbb6976

いいですね。

EDITOR=emacs gh gist edit

ということは、

「gh gist edit」 は、

シェル変数 EDITOR に反応するアプリケーションですね !

 

ファイルを上書き更新する

とはいえ、

いまどきはもろGUIなIDEで豊富な機能を使ってコードは書いていきます。

なので、

パソコン上のIDEで書いたコードを Gist に更新していきたいですよね !

「更新」とは同じIDの Gist の上書きのことを言っています。


$ EDITOR="cp ~/ide/path/to/script/new.js" \
 gh gist edit f49d4d7a9963b77d00c89d1a3dbb6976

想像できてましたか?

GitHub 公式アプリ内のシェル変数 EDITOR の処理を。


[ -z "$EDITOR" ] && EDITOR=nano
$EDITOR TEMP_FILE

通常、エディタの起動コマンドを入力する文字列に


cp src-file

をセットすることで


vi tmp-file


cp src-file tmp-file

となり実行されます。

👉 linux - How do I edit /etc/sudoers from a script? - Stack Overflow hatena-bookmark

実際、言語は Go で書かれていますが、処理の内容はそういうことです。

 

標準入力から更新する

こんなの公開されてる方がいます。


$ echo "edit a gist from output piped from another command" | \
 EDITOR="cp "<(cat -) gh gist edit {<gist ID> | <gist URL>} [flags]

👉 GitHub CLI の gist edit へパイプを接続し、gist を編集する hatena-bookmark

「プロセス置換 (Process Substitution)」を使って処理しています。

「コマンド出力をファイル化して、そのパスを返す。」という使えるやつ。


$ cat <(date)
Thu Jul 21 12:40:53 EEST 2011

$ echo <(date)
/proc/self/fd/11

👉 プロセス置換 (Process Substitution)について - 一から勉強させてください hatena-bookmark
👉 shell - Process substitution and pipe - Unix & Linux Stack Exchange hatena-bookmark

 

まとめ

この先人たちの作ったコマンドラインツールの素晴らしさよ。

「ノーコード」とか言うてるやつな。

👉 GitHub Gist に置いた Javascript をブックマークレットとして実行する hatena-bookmark