ガイド変更履歴HERE SDK API references
ガイド

エンジン

マップビューとの統合の有無、初期化オプション、マップキャッシュの効率的な管理など、HERE SDKエンジンの操作の基本コンセプトを確認します。

エンジンの操作方法

HERE SDK には、RoutingEngine を使用したルートの計算や SearchEngine 経由での検索結果のリクエストなど、特定のタスクを実行するいくつかのモジュール (HERE ではエンジンと呼ぶ) が含まれています。HERE SDK で使用できるエンジンは他にもたくさんあります。詳細については、以下の各章を参照してください。ただし、ほとんどのエンジンは共通の概念を共有しているため、簡単に使用できます。例:

  • すべてのエンジンは、タスクを非同期的に実行し、メイン スレッドで結果を受け取ります。
  • すべてのエンジンは、類似するインターフェース、コールバック、エラー処理を共有しています。
  • 1 つのエンジンの複数のインスタンスを並行して開始できます。
  • オンライン接続が必要です。

以下に、HERE SDK の最も一般的なエンジンの概要を示します。

  • SearchEngine:ジオコーディングやリバースジオコーディングなど、場所、候補、位置情報を検索するすべての機能が含まれています。
  • OfflineSearchEngine (Navigateでのみ使用可能):ダウンロード済みのマップデータを使用してローカルでリクエストを実行する、オフラインバージョンの検索です。
  • RoutingEngine/TransitRoutingEngine:さまざまなオプションや交通機関タイプを含むルートを計算できます。
  • OfflineRoutingEngine (Navigateでのみ使用可能):ダウンロード済みのマップデータを使用してルートを計算するオフラインバージョンです。
  • LocationEngine (Navigateでのみ使用可能):高度なHERE Positioningのソリューションです。
  • ConsentEngine (Navigateでのみ使用可能):LocationEngineなどを使用する前にユーザーの同意を集約するのに役立つサポートエンジンです。
  • Navigator / VisualNavigator (Navigateでのみ使用可能):名前に「エンジン」は含まれていませんが、これらのクラスはエンジンとして機能し、ターン・バイ・ターンナビに関連するすべての機能を制御します。
  • DynamicRoutingEngine (Navigateでのみ使用可能):現在の交通状況に基づいて、より短いルートやより速いルートを定期的に検索するエンジンです。これは、ドライバーに代替ルートを通知するガイダンス中に役立ちます。
  • TrafficEngine:交通事案を検索できるエンジンです。
  • MapDownloader / MapUpdater/ RoutePrefetcher (Navigateでのみ使用可能):これらのクラスは、マップデータのダウンロードまたは更新を実行し、オフラインモードをサポートするアプリケーションで重要な役割を果たします。
  • VenueEngine (Navigateでのみ使用可能):アプリへの非公開施設の統合をサポートする専用エンジンです。
  • SDKNativeEngine:資格情報をプログラムで設定するために必要です。その他のいくつかの詳細設定を行うことができます。
  • MapView:マップ データを視覚化するビューです。実際にはエンジンではありませんが、完全を期すためにこちらに掲載しています。

なお、SDKNativeEngine を除くすべての HERE SDK エンジン は互いに独立して動作でき、データをリクエストするには HERE Credentials が必要です。

HERE SDK は、インスタンス化時に資格情報を検証しません。これは、認証を必要とする機能が使用された場合にのみ実行されます。失敗した場合は、専用のエラー メッセージが表示されます。たとえば、SearchEngineSearchError.AUTHENTICATION_FAILED エラーを返します。他のエンジンでも同様のエラー コードが表示されます。

すべての資格情報がすべての機能で有効なわけではありません。資格情報が無効な場合、ログにはFailed to get the authentication token: Authentication failed, error code: 1に類似した[ERROR]メッセージが出力されます。これは、サービスを使用した際に資格情報が受け入れられなかったことを示しています。資格情報が正しく設定されていることを確認するには、専用エンジンの機能を使用して、エンジンがエラー値で応答するかどうかを確認します。

パラメーターレス コンストラクタを使用して、任意のエンジンを作成できます。例:

try {
    searchEngine = new SearchEngine();
} catch (InstantiationErrorException e) {
    throw new RuntimeException("Initialization of SearchEngine failed: " + e.error.name());
}

このデフォルトのコンストラクタを使用するには、HERE SDK がすでに初期化されており、SDKNativeEngine の共有インスタンスが SDKNativeEngine.setSharedInstance(sdkNativeEngine) を呼び出すことで直接的に設定されているか、SDKNativeEngine.makeSharedInstance(context, options) を呼び出すことで暗黙的に設定されている必要があります。

次のセクションに示すように、ごく一部のユースケースでは、個別に作成された SDKNativeEngine エンジンを受け取る、オーバーロードされたコンストラクタを使用できます。

ApplicationonCreate() ライフサイクル中にエンジンを初期化できます。それ以外の任意の時点でも問題はありません。たとえば、エンジンを初期化するのに適したもう1つの場所はActivityonCreate()メソッド内です。

RoutingEngineTransitRoutingEngineOfflineRoutingEngineなどの一部のエンジンでは、リソースをクリーンアップするために呼び出すことができるdispose()メソッドが提供されています。たとえば、インスタンスが使用されなくなった際に、保留中のリクエストをキャンセルします。

マップビューの有無にかかわらずエンジンを使用する

エンジンが動作するのにマップ ビューは必要ありません。そのため、アプリケーションにマップ ビューを追加しなくても、エンジンをそのまま実行できます。このようにすることで、特定のエンジンのみを中心にアプリを構築できます。マップ ビューの有無を問わず、新しいエンジンを作成する手順はまったく同じです。必ず事前に HERE SDK を初期化してください。

初期化オプション

HERE SDK は、さまざまなオプションを使用して初期化できます。これらのオプションは、SDKNativeEngine に直接設定するか、SDKOptions を使用してエンジンを初期化するときに設定できます。

「API リファレンス」に特に注記がない限り、どのオプションも保持されません。つまり、HERE SDK を再度初期化するたびに、以前のオプションを引き続き利用する場合は再設定する必要があります。

同じことは、さまざまな機能エンジンに設定するオプションやRouteを計算するRoutingEngineなどの機能を使用する場合のオプション (例:RoutingOptions) にも当てはまります。

HERE SDK自体は手動で初期化する必要があります。詳細については、「HERE SDKを統合する」を参照してください。

  • アプリを起動したらすぐにマップ ビューが表示されるようにするには、ほとんどのユースケースでは、「HERE SDK を統合する」のガイドに従うだけで十分です。例外:
  • アプリでマップ ビューを後の時点で表示する必要がある場合、または初期化を遅らせる場合は、後の時点で HERE SDK を初期化することも可能です。

HERE SDK を初期化する手順は次のとおりです。

  1. 廃止された InitProvider を無効化します (このステップは HERE SDK 4.15.0 で廃止されます)。
  2. SDKOptions を作成し、これを使用して新しい SDKNativeEngine を作成することで HERE SDK を初期化します。

SDKNativeEngine およびその他の SearchEngine などのエンジンは、ごく短時間で同期的に作成されます。

HERE SDK は、次の 2 つの方法で初期化できます。

  • SDKNativeEngine.makeSharedInstance(context, options) を使用して、SDKNativeEngine の共有インスタンスを作成します。
  • SDKNativeEngine​(context, options) を介して、SDKNativeEngine の個別のインスタンスを作成します。

SDKNativeEngine.makeSharedInstance(context, options) を呼び出すことで、HERE SDK で使用できる SDKNativeEngine の共有インスタンスが作成されます。このシングルトン アプローチでは、パラメーターを必要としないデフォルトのコンストラクタ (SearchEngine()) を使用できるため、SearchEngine などのエンジンを簡単に作成できます。内部的には、SearchEngine は初期化時に作成した SDKNativeEngine の共有インスタンスを使用します。そのため、HERE SDK を再度初期化する場合は、このパラメーターレス コンストラクタを使用して作成されたすべてのエンジンも再度作成する必要があります。

再初期化の場合は、MapView インスタンスもその onCreate(..) メソッドを呼び出して再度初期化する必要があります。SDKNativeEngine が破棄されると、MapView の状態は無効になります。mapView.isValid() を呼び出して、MapView が正しく初期化されたかを判断します。

または、ごく一部のユースケースでは、各機能エンジンのインスタンスに個別の SDKNativeEngine インスタンスを設定できます。

SearchEngine searchEngine = new SearchEngine(sdkNativeEngine);

一般的には、SDKNativeEngine を複数回初期化する必要はありません。同時に設定できる共有インスタンスは 1 つだけです。この設定は、SDKNativeEngine.makeSharedInstance(context, options) を呼び出したときに暗黙的に行われます。または、利用可能なコンストラクタを使用して、SDKNativeEngine のインスタンスを直接作成できます。複数のインスタンスを個別に作成する場合、共有インスタンスは設定されません。上に示したように、SDKNativeEngine のインスタンスをコンストラクタ パラメーターとして使用して、各機能エンジンを作成する必要があります。この方法により、SearchEngine または RoutingEngine のような機能エンジンを、異なる SDKOptions を持つさまざまな SDKNativeEngine のインスタンスと一緒に使用できます。

個々のインスタンスは、SDKNativeEngine.setSharedInstance(sdkNativeEngine) を呼び出すことで明示的に共有インスタンスとして設定できます。注意:この場合は SDKNativeEngine.getSharedInstance().dispose() を呼び出して、以前のインスタンスがあれば dispose() (破棄) するようにしてください。なお、SDKNativeEngine.makeSharedInstance(context, options) を呼び出してグローバル インスタンスを作成する場合には、この操作は不要です。便宜上、この呼び出しによって、以前に共有されたインスタンスは内部的に破棄されます。

ほとんどのユースケースでは、複数のインスタンスを作成することはお勧めしません。不明な点がある場合は、「HERE SDKを統合する」トピックに示されているように、SDKNativeEngine.makeSharedInstance(context, options)を介してのみHERE SDKを初期化することをお勧めします。この初期化メソッドは、HERE SDKが必要になるたびに使用した後で、各ActivityなどのSDKNativeEngineを破棄できます。ただし、ほとんどの場合、HERE SDK はアプリケーションのライフタイム中に 1 回のみ初期化される方が効率的です。

複数の SDKNativeEngine インスタンスが同じアクセス キー ID を持つことはできません。また、キャッシュ パスはアクセス キー ID ごとに一意であることが保証されます。すでに使用されているアクセス キー ID を使用して 2 つ目のインスタンスが作成された場合は、InstantiationException がスローされます。一般的に、複数のインスタンスが必要な場合は、それぞれに異なる資格情報のセットも必要です。

資格情報のアクセス キー ID 部分は、キャッシュ パスに関連付けられています。実行時に資格情報が変更されると、以前のキャッシュがなくなったように見えることがあります。しかし、キャッシュはまだ存在しており、SDKNativeEngine の破棄後や新しい資格情報の設定後、自動的には消去されません。新しい資格情報が設定されたため、キャッシュ パスが変更されただけのことです。たとえば、以前の資格情報が復元されると、以前のキャッシュを再度使用できるようになります。

キャッシュの詳細については、以下を参照してください。

初期化と Android の権限

通常、すべての権限が付与される前に HERE SDK を初期化することはお勧めしません。

HERE SDK では、マップ ビューを表示するだけの場合、アプリケーション側での権限の処理は必要ありません。以下の権限が自動的に AndroidManifest.xml にマージされます。

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

AndroidManifest.xml ファイルでは、必要な権限について上記の権限を明示的に付与するために、最上位の manifest 要素内に追加することもできます (省略可)。

これらの権限は秘密性が高くなく、システムによってインストール時にすぐに付与されます。HERE SDK にはインターネット接続が必要であるため、これらの権限は常に必要です。これらの権限を処理する必要はありません。また、権限の処理方法に関する HERE SDK 固有の要件もありません。

ただし、ユーザーはインストール後にデバイスのアプリ設定で権限を拒否することができます。そのため、アプリの起動時にユーザーに通知するために、アプリに権限処理を追加することをお勧めします。

付属のサンプルアプリでは、便利なクラスを使用することでボイラープレートコードを使用せずにこれを行う方法を示しています。詳細は、HERESKUnitsアプリによって生成されたAARとしてカプセル化されています。もちろん、独自のアプリケーションの権限は別の方法で処理できます。また、権限を削除することもできます。インターネット接続が利用できない場合、ほとんどのHERE SDKサービスがそのことを適切なエラーメッセージで表示します。

注 (HERE SDK for Android Navigateの場合)

HERE Positioningなどの一部のHERE SDK機能では追加の権限が必要です。これらの操作方法については、専用の「Positioning」セクションを参照してください。

マップ キャッシュを操作する

オンラインおよびオフラインのユースケースをより適切にサポートするために、HERE SDK はダウンロードされたベクター マップ データのキャッシュをサポートしています。これはバックグラウンドで実行されます。地図を操作し、マップビューの有無にかかわらずナビゲーションをプリフェッチまたは使用すると、データはデバイスにローカルに保存され、デバイスの接続が失われた場合や、オフラインモードで操作している場合でもアクセスできます。

HERE SDK は、マップ タイルの一部として任意のデータを格納します。そのため、マップ ビューを表示しなくても、マップ キャッシュが使用されます。たとえば、ナビゲーション中に、必要なすべてのデータがマップ タイル内のマップキャッシュに保存されます。ただし、すべてのライセンスがプリフェッチやナビゲーションなどの機能をサポートしているわけではありません。

統合されたマップキャッシュメカニズムは、標準のベクターベースのマップスキームをサポートしています。衛星画像やその他のラスタータイルもキャッシュに保存されますが、設定できない別のキャッシュに格納されます。

キャッシュに保存されるデータ量には限りがあり、マップの使用中は新しいマップ データに上書きされることに注意してください。ほとんどの場合、これはユーザーに起動時間が短縮されたという印象を与えるのに十分です。以前と同じ場所でアプリを再度起動するときに追加のデータをダウンロードする必要がないためです。

キャッシュがいっぱいになると、LRU (least recently used) 方式が適用されます。

パスとキャッシュ サイズを変更する

  • SDKOptions を使用して HERE SDK を手動で初期化する場合は、絶対キャッシュ パスと最大サイズを指定できます。詳細については、「エンジン」セクションを参照してください。
  • SDKOptions を使用して、希望する cacheSizeInBytes を指定し、キャッシュの上限をバイト単位で定義できます。利用可能なプラットフォーム API を使用して、デバイス上の使用可能なディスク容量を照会してください。

カスタム ラスター レイヤー には、個別のキャッシュを定義できます。

次の方法でマップ キャッシュを消去します。

SDKCache.fromEngine(SDKNativeEngine.getSharedInstance()).clearCache(error -> {
    if (error != null) {
        // ...
    }
});

SDKNativeEngineの共有インスタンスを廃棄しても、キャッシュは消去されません。

空の文字列をキャッシュパスとして設定することで、デフォルトのキャッシュパスを保持します。このパスは、context.getCacheDir().getPath()またはSDKNativeEngine.getSharedInstance().getOptions().cachePathを使用してアクセスできます。デフォルトでは、新しいSDKOptionsを作成する際、デフォルトのキャッシュパスが使用されます。

Navigateでマップキャッシュを操作する

ターン・バイ・ターンナビにはキャッシュが必要なため、SDKNativeEngine を作成するときは有効なキャッシュ パスが必須です。

オフライン マップとは別に、マップ キャッシュを新しいマップ バージョンに更新できます。mapUpdater.performMapUpdate() を呼び出すと、Region が一度もインストールされていなくても、マップ キャッシュが新しいバージョン (利用可能な場合) に更新されます。オフライン マップが使用可能な場合は、以前と同様に、マップ キャッシュとともに更新されます。キャッシュの更新後にオフライン マップをインストールした場合、同じマップ バージョンが使用されます。マップ キャッシュとオフライン マップで異なるバージョンを使用することはできません。

マップ ビューのパン中に最新のマップ データを取得するには、更新が利用可能かどうかを確認してからインストールすることができます。オフラインの Region マップがインストールされていなければ、これはわずか数秒しかかかりません。MapVersionHandle は現在使用されているマップ バージョンを示します。

アプリケーションを新規にインストールする場合、必ずしも最新のマップ バージョンが使用されるわけではありません。通常、各 HERE SDK リリースには特定のマップ バージョンが付属しています。ただし、(カスタム) CatalogConfiguration を使用している場合は、DesiredCatalog で最新のマップ バージョンを指定するなどして、アプリのインストール直後に使用するマップ バージョンを指定できます。

マップバージョン、キャッシュ、オフライン マップの詳細については、「オフライン マップ」セクションを参照してください。

SDKOptions を使用して、キャッシュの有効期限を指定することもできます。時間を「0」に設定すると、アプリでデータがキャッシュに保存されなくなります。この場合、オフライン地域がインストールされていなければ、デバイスの接続が失われたときは、デバイスが再びオンラインになるまで地図は表示されません。このため、常に最新で最良の地図データが表示されるわけではありません。この場合は、地図の更新が利用可能かどうかを確認する必要があります。

マップキャッシュに関する質問と回答

Navigate

  • **マップタイルとは何ですか?**マップタイルはマップキャッシュに格納されます。マップタイルには、検索とルート検索に関連するデータと、視覚的表現のベクターデータが含まれています。これは最適化されたクライアントマップ (OCM) 形式で保存されます。マップタイルは、さまざまなズームレベルで使用できます。マップタイルには、ズームレベルによって異なるデータが含まれている場合があります。

  • **マップタイルはどのくらいの期間キャッシュに保存されますか?**マップ タイルは、キャッシュがいっぱいになったときにのみ削除されます。古いタイルが失効したり、時間に基づいて古いタイルが自動的に削除されたりすることはありません。これは衛星画像には適用されないのでご注意ください (下記参照)。

  • **キャッシュの削除ポリシーについて教えてください。**HERE SDK は LRU (Least Recently Used) ロジックを使用して、マップ キャッシュがいっぱいになったときにタイルを削除します。たとえば、現在の場所から遠く離れたタイルを削除するなどの高度なロジックはありません。ユーザーが次に世界のどの領域を訪問する可能性があるかは予測できないためです。ただし、マップ キャッシュはセッション固有のものではありません。前回デバイスが使用されたとき (つまり前回の電源サイクル) のキャッシュ データは、次にアプリが使用されるときにまだ残っています。キャッシュはデバイスごとではなく、アプリごとに固有であることに注意してください。

  • **マップ キャッシュにデータがない場合、どのような影響がありますか?**通常、マップ キャッシュは完全であることは想定されず、周囲の領域では常にタイルが欠落している可能性があります。これは、マップ タイルがレンダリングされている間に、オンデマンドでのみ読み込まれるためです。マップ キャッシュに不足しているタイルがある場合、たとえば OfflineSearchEngine は不足しているタイルの一部である POI や道路名を検出できず、HERE Rendering Engine はそのようなデータをレンダリングできません。また、不足しているタイルの周りにルートが見つからなければ、OfflineRoutingEngineが失敗することがあります。

Explore

  • **マップタイルとは何ですか?**マップタイルはマップキャッシュに格納されます。マップタイルには、検索とルート検索に関連するデータと、視覚的表現のベクターデータが含まれています。マップタイルは、さまざまなズームレベルで使用できます。マップタイルには、ズームレベルによって異なるデータが含まれている場合があります。

  • **マップタイルはどのくらいの期間キャッシュに保存されますか?**マップ タイルは 1 日後には使用できなくなり、削除されます。新しいイメージは、LRU方式に基づいて、1日後すぐにダウンロードされます。

ExploreとNavigate

  • **キャッシュの削除ポリシーについて教えてください。**HERE SDK は、LRU (Least Recently Used Tile) ロジックを使用して、1 日後にタイルを削除します。マップ キャッシュはセッション固有のものではありません。前回デバイスが使用されたとき (つまり前回の電源サイクル) のキャッシュ データは、次にアプリが使用されるときにまだ残っています。キャッシュはデバイスごとではなく、アプリごとに固有であることに注意してください。

  • **マップキャッシュのサイズはどれくらいですか?**マップ キャッシュのサイズは、アプリケーションによって変更できます。256 MB 以上を使用してください (デフォルト)。512 MB 以上または 1 GB を推奨します。 ターン・バイ・ターンナビ (Navigateなどで利用可能) には、ズームレベル14のマップタイルが必要です。これは、約2kmの円に相当します。ただし、これは場所によって多少異なる場合があります。

  • **以前にキャッシュに保存されたマップ タイルはオフラインで検索できますか?**はい。OfflineSearchEngine を使用していつでも検索できます。ただし、すべてのマップタイルにすべてのズームレベルで同じ検索結果が含まれているとは限りません。OfflineSearchEngineはすべてのライセンスで使用できるわけではありません。

  • **一度にキャッシュに保存されるマップタイルは1つだけですか?**はい。その場所が 2 つのタイルの端に位置しない限り、一度に 1 つのタイルのみが追加されます。ズーム レベルによっては、マップ ビューのレンダリングに複数のタイルが必要になります。これは自動的には行われず、ズーム レベルが変更された場合にのみ行われます。

  • **衛星画像はキャッシュに保存されますか?**はい。衛星写真のマップ スキームが設定されている場合は対応する画像もキャッシュに保存されますが、衛星画像は (契約上の理由により) 1 日過ぎると使用できず、削除されます。新しいイメージは、LRU方式に基づいて、1日後すぐにダウンロードされます。

  • **地球儀ビューなどの「ベース マップ」は常に利用できますか?**HERE SDK は、世界のタイル、つまり地球の最大ズーム レベルのタイルを自動的にダウンロードします。これは、レンダリング上の理由で情報量が非常に限定的な地球の地図を、常に利用できることを意味します。国や大陸の形状を確認でき、首都がテキスト ラベルで表示されます。

  • **キャッシュは自動的に消去されますか?**いいえ。フル キャッシュは LRU 方式に基づいてのみ消去されます (上記を参照)。接続の中断によりタイルが完全にダウンロードされなかった場合、これらのタイルは保持され、接続が再開されるとダウンロードが続行されます。

  • **接続性が確保されている場合は、ルート全体が事前にキャッシュに保存されますか?**いいえ。これは自動的には行われません。ただし、RoutePrefetcher を使用して、小道ルート沿いのマップ データをキャッシュにダウンロードできます。詳細については、「ターン・バイ・ターンナビ」セクションを参照してください。RoutePrefetcherはすべてのライセンスで使用できるわけではありません。


EN 日本語

HERE documentation

Find answers to your product and technical questions

Documentation

What's new

Videos

EN 日本語

HERE ドキュメント

製品や技術に関する質問の答えを見つけましょう。より多くの内容と最新の情報については、英語版をご覧ください。

ドキュメント

ダイナミックマップ

動的コンテンツ関連のAPIをアプリやサービスに活用して、ドライバーが安全・快適かつ予定どおりに目的地へ到着できるよう支援します。

地図とデータ

世界中を走行する多数のマッピング車両から得られる最新の位置情報データを活用し、精度の高い地図やカスタムレイヤーを構築できます。

最新情報

動画

(function () { const input = document.querySelector('input[data-typeahead]'); if (!input) return; // Prevent the form from submitting/navigating input.closest('form')?.addEventListener('submit', e => e.preventDefault()); input.addEventListener('input', function () { const q = this.value.trim().toLowerCase(); document.querySelectorAll('.nav-group-name').forEach(group => { let anyVisible = false; group.querySelectorAll('.nav-group-task').forEach(task => { const text = task.textContent.trim().toLowerCase(); const show = !q || text.includes(q); task.style.display = show ? '' : 'none'; if (show) anyVisible = true; }); // Hide the whole group header if nothing matches group.style.display = anyVisible || !q ? '' : 'none'; }); }); })(); (function () { function onTokenClick(event) { var link = event.target.closest('.sdk-for-ios .item .token'); if (!link) return; event.preventDefault(); console.log('token clicked', link.textContent.trim()); var item = link.closest('.item'); if (!item) return; var content = item.querySelector('.height-container'); if (!content) { console.log('no .height-container found for item', item); return; } var isHidden = window.getComputedStyle(content).display === 'none'; content.style.display = isHidden ? 'block' : 'none'; link.classList.toggle('token-open', isHidden); var href = link.getAttribute('href'); if (href) { if (history.pushState) history.pushState({}, '', href); else location.hash = href; } } function openHashTarget() { var hash = window.location.hash.slice(1); if (!hash) return; var anchor = document.querySelector('.sdk-for-ios a[name="' + hash + '"]'); if (!anchor) return; var item = anchor.closest('.item'); if (!item) return; var link = item.querySelector('.token'); var content = item.querySelector('.height-container'); if (!link || !content) return; content.style.display = 'block'; link.classList.add('token-open'); } function init() { console.log('HERE SDK accordion init'); openHashTarget(); } document.removeEventListener('click', onTokenClick); document.addEventListener('click', onTokenClick); if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', init); } else { init(); } window.addEventListener('hashchange', openHashTarget); window.addEventListener('pageLoad', init); })();