Webページの画像を全部俺の顔にするChrome拡張

はじめに

クソアプリ Advent Calendar 2018 の22日目です。 Webページの画像を全部俺の顔にするChrome拡張を作りました。

Webページの画像を全部俺の顔にするChrome拡張

f:id:inabajunmr:20181205021917g:plain

なぜこのようなことになってしまったのか

当初はWebページ2つを合体するツールで参加する予定でしたが、作成していくつかのページを合体してみたところ、なんだかよくわからなくなってしまいました。

GitHubTwitter

f:id:inabajunmr:20181205022204p:plain

WikipediaとCult of the Party Parrot

f:id:inabajunmr:20181205023736p:plain

Cult of the Party Parrotと合体するのが一番しっくり来た

ただしその中でもCult of the Party Parrotと合体すると、しっくりくる結果が出る可能性が高いことに気づきました。 ですが、これってもうWebページの画像を全部Party Parrotにするやつで良いのでは?となりました。

Webページの画像を全部Party Parrotにするやつを作った

f:id:inabajunmr:20181205022426g:plain

しかしすでにあった

作ってからすでに同じものが作られていることに気づきました。

chrome.google.com

なので俺の顔にした

仕方ないからParty Parrotじゃなくて俺の顔にしました。 そのような経緯で、このChrome拡張は作成されました。

URL

10月にやったこと

やったこと

IntelliJ IDEAハンズオン――基本操作からプロジェクト管理までマスター

読み終わった。身についているかどうかは別の話とする。

Docker/Kubernetes 実践コンテナ開発入門

150ページまで読んだ。そろそろkubernetesに入れる。コンテナの良さがちょっと理解できてきた気がする。

Java 8のHashMapのコード読んでた

ちょっと読み進めてたんだけどDocker本をとりあえず終わらせてしまいたいので一旦止めた。

GitHubのTrendingのビューアーを作った

inabajunmr.hatenablog.com

とりあえず雰囲気でGolangをかけるようになった感じがしている。

英語

ひたすらイングリッシュベル。DME Teensがレベル6に入った。単純計算でここまでで半分だが現時点で15万円ほど課金している。お金のことを考えて集中力を加速していく。 今月は50レッスン=21時間受講。あとTOEIC受けた。途中でトイレにいってしまったので多分ダメそう。

今月書いた記事

Hacktoberfestに参加してOSSにコントリビュートしてシャツをもらおう | DevelopersIO

シャツもらえる連絡きた。

【Spring Fest 2018 レポート】決済システムの内製化への旅 – SpringとPCFで作るクラウドネイティブなシステム開発 #jsug #sf_h1 | DevelopersIO

久しぶりにイベントに行った。CIの使い方がすげーいいなーって思いながら見てたやつの話。

これからやること

  • Docker/Kubernetes 実践コンテナ開発入門を読む
  • HashMap読む
  • Goならわかるシステムプログラミングを読む
  • ひたすら英語
  • Release It!読む

あとSICPを読まねばならない運びになってきた。とりあえず↑の本を読んでから考える。

今思ってること

コンテナの本をいい加減読まなければならない。

JavaのHashMapの実装を眺める会③

HashMap#resizeを読む

とりあえずputValを読んでるがしょっぱなテーブルが初期化される前に呼び出すとresizeが呼ばれる

* Initializes or doubles table size.  If null, allocates in
 * accord with initial capacity target held in field threshold.
 * Otherwise, because we are using power-of-two expansion, the
 * elements from each bin must either stay at same index, or move
 * with a power of two offset in the new table.

テーブルのサイズを初期化もしくは2倍にする。 もしnullの場合、フィールドの閾値に保持している初期キャパシティに合わせてアロケートする。

  • 🍙 フィールドの閾値に保持しているがよくわからん

さもなくば、2のべき乗の拡張を利用しているため、それぞれのbinの要素は同じインデックスに保たれなければならない、もしくは新しいテーブルの2のべき乗のオフセットに移動する。

  • 🍙 2のべき乗の拡張を利用、とかbinが何をさしてるのとかがわからん
  • 🍙 とりあえず初期化時は初期キャパシティでアロケートするし、そうでなければエレメントを同じインデックスか、2のべき乗のオフセットに移動する、という話?
  • 🍙 なんで2のべき乗なのかはわかんないけどとりあえずhashのロジックのあたりとまとめて理解しないとわからん気がする

コードを読む

MAXIMUM_CAPACITYってなんだろ

static final int MAXIMUM_CAPACITY = 1 << 30;

https://stackoverflow.com/questions/21638080/why-is-the-maximum-capacity-of-a-java-hashmap-130-and-not-131 1を左に30ビットシフト

2進数で1000000000000000000000000000000

なぜInteger.MAX_VALUEでないのかがよくわからん

ざっくりやってること

  • thresholdの計算
  • tableの初期化、もしくはリサイズ

thresholdの計算

  • 既存のcapacity > MAXIMUM_CAPACITYなら、Integer.MAX_VALUE
    • ここよくわからん❓
  • 既存のcapacityが0より大きく
    • かつ既存のcapacityの2倍がMAXIMUM_CAPACITYより小さく、DEFAULT_INITIAL_CAPACITY以上なら、既存のthresholdの2倍
      • 要するに限界を超えないなら2倍
      • 拡張するパターン
      • ⭐️基本的にここと初期化以外はオーバーフローしないようにInteger.MAX_VALUEで切ってるだけだと思う⭐️
  • 既存のcapacityが0以下(要するに0?)でかつthresholdが0以下(要するに0?)ならthresholdはDEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY
    • デフォルトコンストラクタもしくはcapacityが0で初期化された後のtable初期化⭐️
  • 既存のcapacityが0以下かつthresholdが0より大きくてかつ、
    • 既存のthresholdがMAXIMUM_CAPACITYより小さくかつ既存のthreshold * loadFactorがMAXIMUM_CAPACITYより小さければ、既存のthreshold * loadFactor
    • 既存のthresholdもしくは既存のthreshold * loadFactorがMAXIMUM_CAPACITYを超えていれば、Integer.MAX_VALUE
      • capacity指定するコンストラクタから呼ばれるケース ⭐️

tableの初期化、もしくはリサイズ

新しいcapacityの計算
  • 既存のcapacityが0以下でかつthresholdが0より大きいなら、capacity=既存のthreshold
  • 既存のcapacityが0以下(要するに0?)でかつthresholdが0以下(要するに0?)ならcapacityはDEFAULT_INITIAL_CAPACITY
tableの初期化

上記capacityの数のNodeの配列を初期化し、tableに代入 // TODO 多分既存の値を入れ直す的なアレだと思う

JavaのHashMapの実装を眺める会②

そもそもクラスのJavaDocを読むべき

  • Hash table based implementation of the Map interface. This
  • implementation provides all of the optional map operations, and permits
  • null values and the null key. (The HashMap
  • class is roughly equivalent to Hashtable, except that it is
  • unsynchronized and permits nulls.) This class makes no guarantees as to
  • the order of the map; in particular, it does not guarantee that the order
  • will remain constant over time.

ハッシュテーブルをベースにしたMapインターフェースの実装です。 この実装はオプショナルを含めたMapのオペレーションを全て提供します。

  • 🍙 putってOptionalなんだな

null値とnullのキーを許容します。 HashMapは雑に言えば、同期的でないこと、nullを許容することをのぞいてHashtableと等価です。 このクラスはMapの順序を保証しません。時間が経っても順序が一定に保たれることを保証していません。

  • 🍙 in particularがよくわからん
  • This implementation provides constant-time performance for the basic

  • operations (get and put), assuming the hash function
  • disperses the elements properly among the buckets. Iteration over
  • collection views requires time proportional to the "capacity" of the
  • HashMap instance (the number of buckets) plus its size (the number
  • of key-value mappings). Thus, it's very important not to set the initial
  • capacity too high (or the load factor too low) if iteration performance is
  • important.

この実装はハッシュ関数バケット間に要素が適切に散らばることを仮定し、一般的な操作(get, put)をO(1)のパフォーマンスで提供します。 コレクションビューを超えたイテレーションは、Hashmapインスタンスのキャパシティ+そのサイズ(key-value mappingsの数)に比例する必要があります。 そのため、もしイテレーションのパフォーマンスが重要なのであれば、初期キャパシティを高くしすぎない、(もしくはload factorを低くしすぎない)ことがとても重要です。

  • An instance of HashMap has two parameters that affect its

  • performance: initial capacity and load factor. The
  • capacity is the number of buckets in the hash table, and the initial
  • capacity is simply the capacity at the time the hash table is created. The
  • load factor is a measure of how full the hash table is allowed to
  • get before its capacity is automatically increased. When the number of
  • entries in the hash table exceeds the product of the load factor and the
  • current capacity, the hash table is rehashed (that is, internal data
  • structures are rebuilt) so that the hash table has approximately twice the
  • number of buckets.

HashMapのインスタンスはパフォーマンスに影響する2つのパラメーターを持っています。 初期キャパシティとload factorを低くしすぎない)ことがとても重要です。 キャパシティは、ハッシュテーブルのバケットの数で、初期キャパシティはハッシュテーブルが作られたタイミングのキャパシティのことです。 load factorはキャパシティが自動的に増加するまでにハッシュテーブルがどれくらいまで埋まるかを許容する閾値です。 ハッシュテーブル内のエントリーの数がload factorと現在のキャパシティを超えた時、ハッシュテーブルはリハッシュします。 リハッシュとは、内部のデータ構造の再構築のことです。 ハッシュテーブルはおよそバケットの数の2倍となります。

  • As a general rule, the default load factor (.75) offers a good

  • tradeoff between time and space costs. Higher values decrease the
  • space overhead but increase the lookup cost (reflected in most of
  • the operations of the HashMap class, including
  • get and put). The expected number of entries in
  • the map and its load factor should be taken into account when
  • setting its initial capacity, so as to minimize the number of
  • rehash operations. If the initial capacity is greater than the
  • maximum number of entries divided by the load factor, no rehash
  • operations will ever occur.

一般的なルールとして、デフォルトのload factorは時間と容量のコストの間で良いトレードオフを提供します。 高い値はスペースのオーバーヘッドを減らしますが、参照時のコストは増加します。(参照時のコストはget,putを含むHashMapのほとんどの操作に影響します)

  • 🍙 高すぎるとギチギチまで詰める感じになる?
  • 🍙 参照時のコストが上がる理由がよくわからない
    • 🍙 衝突が増えるのかな?

予期されるマップにおけるエントリの数とそのload factorは、リハッシュの操作回数を最小化するように初期キャパシティがセットされる時に考慮されるべきです。 もし初期キャパシティがload factorで割ったエントリの最大数よりも大きい場合、リハッシュ操作は起こりません。

  • 🍙 キャパシティ10でload factorが0.5の場合、要素数が5まではリハッシュされない
  • If many mappings are to be stored in a HashMap

  • instance, creating it with a sufficiently large capacity will allow
  • the mappings to be stored more efficiently than letting it perform
  • automatic rehashing as needed to grow the table. Note that using
  • many keys with the same {@code hashCode()} is a sure way to slow
  • down performance of any hash table. To ameliorate impact, when keys
  • are {@link Comparable}, this class may use comparison order among
  • keys to help break ties.

もしたくさんのマッピングがHashMapのインスタンスに保存されるなら、十分に大きなキャパシティを与えたインスタンスを作成することは、必要に応じて自動的なリハッシュによるテーブルの拡張操作をさせるよりも効率的にマッピングを保存させることができます。

多くのキーが同じキー(hashCode()の結果)を用いる場合、ハッシュテーブルのパフォーマンスは落ちます。 この影響を改善するため、キーがComparableな時はこのクラスは、同じキーに対する値の決定のため比較を利用します。

  • 🍙 比較の下りがかなり適当くさい
    • 🍙 衝突した時の検索にComparableを使うという話だろうなとは思う
  • Note that this implementation is not synchronized.

  • If multiple threads access a hash map concurrently, and at least one of
  • the threads modifies the map structurally, it must be
  • synchronized externally. (A structural modification is any operation
  • that adds or deletes one or more mappings; merely changing the value
  • associated with a key that an instance already contains is not a
  • structural modification.) This is typically accomplished by
  • synchronizing on some object that naturally encapsulates the map.

この実装は同期的ではありません。もし複数スレッドがハッシュマップに同時にアクセスすると、 少なくとも一つのスレッドがマップを構造的に更新する場合、外部から同期される必要があります。 (構造的な変更とは、マッピングの追加や削除のことであり、すでにマップに含まれるキーに紐づいたインスタンスの変更は構造的な変更ではありません。)

これは一般的に、自然にマップをカプセル化するオブジェクトの同期によって達成されます。

  • 🍙 同期するためのオブジェクトでラップして同期はそいつに任せるべき的な話?
  • If no such object exists, the map should be "wrapped" using the
  • {@link Collections#synchronizedMap Collections.synchronizedMap}
  • method. This is best done at creation time, to prevent accidental
  • unsynchronized access to the map:
  • Map m = Collections.synchronizedMap(new HashMap(...));

そのようなオブジェクトが存在しない場合、マップはCollections#synchronizedMapによってラップされるべきです。これは同期的でないマップへの、意図しないアクセスを防ぐために、作成時に行うのがベストです。

  • The iterators returned by all of this class's "collection view methods"

  • are fail-fast: if the map is structurally modified at any time after
  • the iterator is created, in any way except through the iterator's own
  • remove method, the iterator will throw a
  • {@link ConcurrentModificationException}. Thus, in the face of concurrent
  • modification, the iterator fails quickly and cleanly, rather than risking
  • arbitrary, non-deterministic behavior at an undetermined time in the
  • future.

このクラスの全てのコレクションビューメソッドによって返るイテレーターは、フェイルファストです。 もしイテレーターが作成された後でイテレーター自身以外によるremoveメソッド以外による構造的な変更があると、イテレーターはConcurrentModificationExceptionをスローします。

このように同時に更新があった場合に、イテレーターは任意のタイミングで決定的でない振る舞いが、未来における確定していないタイミングで起こるリスクを取らずに、素早く明確に失敗します。

  • Note that the fail-fast behavior of an iterator cannot be guaranteed

  • as it is, generally speaking, impossible to make any hard guarantees in the
  • presence of unsynchronized concurrent modification. Fail-fast iterators
  • throw ConcurrentModificationException on a best-effort basis.
  • Therefore, it would be wrong to write a program that depended on this
  • exception for its correctness: the fail-fast behavior of iterators
  • should be used only to detect bugs.

このイテレーターにおけるフェイルファストな振る舞いは、一般的に非同期に並行に行われる変更においては明確に保障することは不可能なため、保証されません。 フェイルファストなイテレーターのスローするConcurrentModificationExceptionはベストエフォートです。 なので、この例外に依存するプログラムを書くのはよくないです。 イテレーターのフェイルファストな振る舞いは、バグの検知にのみ利用すべきです。