|
|
Advanced サンプル・アプリケーションのビルド
ここでは、次の内容について説明します。
概要
Advanced サンプル・アプリケーションでは、ニュース・レポータが記事をポストし、ワイヤ・サービスがその記事をイベントとしてノーティフィケーション・サービスにポストし、ニュース・サブスクライバが記事を消費するニュース閲覧環境をシミュレートします。
Advanced サンプル・アプリケーションは、2 つのインプリメンテーションが用意されています。1 つは BEA シンプル・イベント・アプリケーション・プログラミング・インターフェイス (API) が使用される Java プログラミング言語のインプリメンテーション、もう 1 つは CosNotification サービス API が使用される C++ のインプリメンテーションです。
Advanced サンプル・アプリケーションは、BEA Tuxedo CORBA ノーティフィケーション・サービスを使用するレポータ・アプリケーション、サブスクライバ・アプリケーション、およびワイヤ・サービス・アプリケーションで構成されます。レポータ・アプリケーションは、クライアント・アプリケーションをインプリメントします。このアプリケーションは、ニュース記事の入力をユーザに促し、アプリケーション固有の IDL を使用して WireService サーバを呼び出します。WireService サーバは、イベントをポストします。サブスクライバは、共同クライアント/サーバ・アプリケーションをインプリメントします。このアプリケーションは、イベントをサブスクライブおよびアンサブスクライブするときにはクライアントとして機能し、イベントを受信するときにはサーバとして機能します。イベントを受信するために、サブスクライバはノーティフィケーション・サービスによってイベント配信が必要なときに呼び出されるコールバック・オブジェクトをインプリメントします。
注記 UNIX システムでは、ポートが再び利用可能になるまでに時間がかかるので (実際の時間はプラットフォームによって異なる)、サブスクライバを即座に再起動することはできません。あまりにも早く再起動すると、CORBA::OBJ_ADAPTER
例外が発生します。この例外が発生した場合は、少し待ってから再試行してください。Solaris システムでは、ポートが利用可能になるまで最高で 10 分かかります。ポートがまだ使用中かどうかを確認するには、”Restart -a | grep <
the port number
>”
というコマンドを使用します。
この Advanced サンプル・アプリケーションでは、BEA シンプル・イベント API、CosNotification サービス API、一時的および永続的なサブスクリプション、およびデータのフィルタ処理の使い方を例示します。
この Advanced サンプル・アプリケーションでは、次の 3 つの実行可能ファイルを使用します (図 6-1 を参照)。
図6-1 Advanced サンプル・アプリケーションの構成要素
イベント・ポスト元 (WireService アプリケーション) では、構造化イベントの domain_name
、type_name
、および filterable_data
フィールドを使用して 3 つのイベント (ニュース・イベント、サブスクライバ・シャットダウン・イベント、およびサブスクライバ取り消しイベント) を作成します。
このイベントでは、ドメイン名は文字列であり、アプリケーションによって事前に「News」として設定されます。型名は文字列であり、Reporter アプリケーションのユーザによって実行時に定義されます。型名は、ニュースのカテゴリ (「Sports」など) に設定されます。フィルタ処理可能データには、名前/値ペアが格納されます。その名前は「Story」で、値はポストされるニュース記事の本文である文字列です。
このイベントでは、ドメイン名は文字列であり、アプリケーションによって事前に「NewsAdmin」として設定されます。型名は文字列であり、アプリケーションによって事前に「Shutdown」として設定されます。フィルタ処理可能データは使用しません。
このイベントでは、ドメイン名は文字列であり、アプリケーションによって事前に「NewsAdmin」として設定されます。型名は文字列であり、アプリケーションによって事前に「Cancel」として設定されます。フィルタ処理可能データは使用しません。
Subscriber アプリケーションでは、構造化イベントの domain_name
、type_name
、および filterable_data
フィールドを使用して 2 つのサブスクリプションを作成します。1 つはニュース記事を処理するニュース・サブスクリプション、もう 1 つは Cancel イベントと Shutdown イベントを処理するシャットダウン・サブスクリプションです。実行時に、Subscriber アプリケーションではノーティフィケーション・サービスに対するそれら 2 つのサブスクリプションを確立します。
Subscriber アプリケーションでは、構造化イベントの domain_name
、type_name
、および filterable_data
フィールドを使用してノーティフィケーション・サービスのサブスクリプションを作成します。サブスクリプションでは、ドメイン名が「News」の内容の固定文字列として定義されます。実行時に、Subscriber アプリケーションではユーザに「ニュース・カテゴリ」と「キーワード」を問い合わせ、その入力を使用してサブスクリプションの type_name フィールドと data_filter フィールドを定義します。当然、両アプリケーション (リポーターとサブスクライバ) のユーザが協力し、サブスクリプションの「ニュース・カテゴリ」文字列と「キーワード」文字列がイベントと一致するようにしなければなりません。そうしないと、サブスクライバにニュース・イベントは配信されません。サブスクリプションでは、記事の本文が文字列であり、その記事が構造化イベントの filterable_data
フィールドの最初の名前/値ペアにあるものと想定され、filterable_data
フィールドのチェックが行われることはありません。
Subscriber アプリケーションでは、構造化イベントの domain_name フィールドと type_name フィールドを使用してノーティフィケーション・サービスのサブスクリプションを作成します。サブスクリプションでは domain_name が「NewsAdmin」の内容の固定文字列として定義され、type_name が「Shutdown」または「Cancel」のいずれかの文字列として定義されます。filterable_data フィールドは空の文字列です。
Reporter アプリケーションは、Shutdown イベントと Cancel イベントを生成するだけでなく、ニュースを報告するためのユーザ・インターフェイスをインプリメントします。ノーティフィケーション・サービスを直に使用してイベントをポストするのではなく、WireService サーバのメソッドを呼び出します。
WireService サーバでは、ノーティフィケーション・サービスを使用して次の 3 種類のイベントをポストします。
ノーティフィケーション・サービスでは、これらのイベントをサブスクライバに配信します。
サブスクライバでは、ノーティフィケーション・サービスを使用してニュース・イベントの永続的なサブスクリプションを作成します。サブスクライバは、ニュース・イベントを受信して処理するための永続的なコールバック・オブジェクトを (NewsConsumer_i
サーバント・クラスを通じて) インプリメントします。サブスクライバがサブスクライブするときには、このコールバック・オブジェクトのオブジェクト・リファレンスがノーティフィケーション・サービスに渡されます。一致するイベントが発生すると、ノーティフィケーション・サービスではこのコールバック・オブジェクトの push_structured_event
メソッドを呼び出してイベントをサブスクライバにプッシュします。このメソッドはイベントを出力します。
サブスクライバでは、ノーティフィケーション・サービスを使用して Shutdown イベントと Cancel イベントの一時的なサブスクリプションも作成します。サブスクライバは、それらのイベントを受信して処理するためのコールバック・オブジェクトも (ShutdownConsumer_i
サーバント・クラスを通じて) インプリメントします。
サブスクライバが実行されると、そのサブスクライバはユーザに名前の入力を要求します。このユーザが初めてサブスクライバ・プログラムを実行すると、サブスクライバでは News イベントの永続的なサブスクリプションが作成されます。そのために、サブスクライバはサブスクライブするニュース記事の種類とサブスクライバが動作するポート番号の入力をユーザに要求します。サブスクライバはこのポートで動作し、サブスクライブして、サブスクリプション ID、フィルタ ID (CosNotification API 使用の場合)、およびポート番号をファイルに書き込みます (ファイルの名前は <
user_name
>.pstore
)。サブスクライバは、次回の実行時には、ユーザに名前の入力を要求し、ファイル <
user_name
>.pstore
を開いて、このユーザのサブスクリプション ID、フィルタ ID (CosNotification API 使用の場合)、およびポート番号をファイルから読み取ります。これで、ニュース・コールバック・オブジェクトのオブジェクト・リファレンスが永続的であるため、実行のたびに同じポート番号を使用しなければならない、という要件が満たされます。
Subscriber では一時的なサブスクリプションを作成して Shutdown イベントと Cancel イベントを受信するので、一時的なサブスクリプションはサブスクライバが実行およびシャットダウンされるたびに作成および破棄されます。このサブスクリプション ID は、ファイル <
user_name
>.pstore
に書き出されません。
サブスクライバが Shutdown イベントを受信すると、シャットダウン/コールバック・サブスクリプションが破棄されますが、News サブスクリプションはそのまま維持されます。サブスクライバがシャットダウンされた後で、それが再起動される前に News イベントがポストされた場合、そのイベントはサブスクライバが再起動された時点で配信されるか、またはエラー・キューに入れられます。ntsadmin
ユーティリティを使用すると、エラー・キューからイベントを削除するか、配信を再試行できます。
イベントが再配信されるか、エラー・キューに入れられるかは、サブスクライバがすぐに再起動されるかどうかによって決まります。すぐに再起動されるかどうかは、キューの再試行パラメータによって決まります。キューの再試行パラメータの値については、advanced.inc
(ノーティフィケーション・サンプルの common ディレクトリ) を参照してください。
News イベントには、カテゴリ (見出しなど) と記事 (複数行のテキスト文字列) という 2 つのパートがあります。Subscriber アプリケーションは、ニュース・カテゴリの入力をユーザに求めます。サブスクライバでは、カテゴリがその文字列と一致するニュース・イベントをサブスクライブします。Reporter アプリケーションは、ニュース・カテゴリと記事の入力をユーザに要求します。レポータでは、ワイヤ・サービスのメソッドを呼び出して対応するニュース・イベントをポストします。イベントは、そのカテゴリのニュースをサブスクライブしたサブスクライバだけに配信されます。
注記 カテゴリは文字列です。Reporter のユーザと Subscriber のユーザは同じ文字列を使用しなければなりません。このサンプルには固定のカテゴリはありません。したがって、Reporter のユーザと Subscriber のユーザは両者とも、カテゴリが要求されたときに (大文字と小文字の区別およびスペースの有無を含めて) 同じ文字列を入力しなければなりません。
このサンプルではデータのフィルタ処理も利用します。ユーザが初めて Subscriber を実行すると、そのユーザは「キーワード」の入力を要求されます。カテゴリが一致し、記事にキーワードが含まれているイベントがサブスクライバに配信されます。たとえば、ユーザが「none」というキーワードを入力した場合、データのフィルタ処理は行われません。その場合、ユーザは選択したニュース・カテゴリのすべてのイベントを受信することになります。「smith」というキーワードを入力した場合、そのキーワードは "Story %% '.*smith.*'"
に変換されます。この場合、文字列の含まれる「Story」というフィールドが存在し、その文字列が任意数の文字で始まり、リテラル文字列「smith」が含まれ、任意数の文字で終わっているイベントのみがサブスクリプションで受け入れられます。
このサンプルを実行するには、Reporter と Subscriber を少なくとも 1 つずつ実行する必要があります (それぞれ複数を実行することも可能)。Reporter によってポストされたイベントは、(カテゴリに基づいて) 一致するすべてのサブスクライバに配信されます。
また、サブスクライバは必ずイベントをポストする前に起動してください。サブスクライバが起動する前にポストされたイベントは配信されません。
Advanced サンプル・アプリケーションのビルドと実行
Introductory サンプル・アプリケーションをビルドして実行するには、次の手順を行う必要があります。
"TUXDIR"
環境変数と "JAVA_HOME"
環境変数が適切なディレクトリ・パスに
設定されていることを確認します。
注記 "JAVA_HOME"
環境変数は、Java アプリケーションの場合のみ必要となります。
make
ファイルがパスに含まれているようにします。
Microsoft Windows の場合は、nmake
ファイルがパスに含まれているように
します。
これらの手順は、次の節でさらに詳しく説明されます。
環境変数の設定を確認する
Advanced サンプル・アプリケーションをビルドして実行する前に、システムで TUXDIR
環境変数が設定されていることを確認する必要があります。ほとんどの場合、この環境変数はインストールの過程で設定されます。しかし、正確な情報が反映されているかどうかを確認することが必要です。
表 6-1 は、Callback サンプル・アプリケーションを実行するために必要な環境変数のリストです。
インストール時に定義された環境変数の情報が正しいかどうかを確認するには、次の手順を行います。
Windows
コントロール・パネルが表示されます。
[システムのプロパティ] ウィンドウが表示されます。
[詳細] ページが表示されます。
TUXDIR and JAVA_HOME
の設定を確認します。
UNIX
ksh prompt>printenv TUXDIR
ksh prompt>printenv JAVA_HOME
設定を変更するには、次の手順を行います。
Windows
UNIX
ksh prompt>export TUXDIR=
directorypath
ksh prompt>export JAVA_HOME=
directorypath
Advanced サンプル・アプリケーションのファイルを作業ディレクトリにコピーする
Advanced サンプル・アプリケーションのファイルをローカル・マシンの作業ディレクトリにコピーする必要があります。
注記 アプリケーション・ディレクトリと common ディレクトリは同じ親ディレクトリにコピーしなければなりません。
Advanced サンプル・アプリケーションのファイルは、次のディレクトリに配置されています。
Windows
C++ の Advanced サンプルdrive:
\tuxdir
\samples
\corba
\notification
\advanced_cos_cxx
drive:
\tuxdir
\samples
\corba
\notification
\common
Java の Advanced サンプルdrive:
\tuxdir
\samples
\corba
\notification
\advanced_simple_java
drive:
\tuxdir
\samples
\corba
\notification
\common
UNIX
C++ の Advanced サンプル/usr/local/tuxdir
/samples/corba/notification/advanced_cos_cxx
/usr/local/tuxdir
/samples/corba/notification/common
Java の Advanced サンプル/usr/local/tuxdir
/samples/corba/notification/advanced_simple_java
/usr/local/tuxdir
/samples/corba/notification/common
表 6-2 と 表 6-4 のファイルは、BEA シンプル・イベント API を使用してインプリメントされる Java Advanced サンプル・アプリケーションをビルドして実行するために使用します。表 6-3 と 表 6-4 のファイルは、CosNotification API を使用してインプリメントされる C++ Advanced サンプル・アプリケーションをビルドして実行するために使用します。
表 6-3 と 表 6-4 のファイルは、Advanced サンプル・アプリケーションをビルドして実行するために使用します。
表 6-4 は、Advanced サンプル・アプリケーションで使用されるほかのファイルのリストです。IDL ファイル以外のファイルは、ノーティフィケーション common ディレクトリに配置されています。
Advanced サンプル・アプリケーションのファイルの保護属性を変更する
BEA Tuxedo ソフトウェアのインストール時に、Advanced サンプル・アプリケーションのファイルは読み取り専用に設定されます。Advanced サンプル・アプリケーションのファイルを編集またはビルドするには、作業ディレクトリにコピーしたファイルの保護属性を次のように変更する必要があります。
Windows
cd
)。
prompt>attrib -r
drive:
\workdirectory
\*.*
UNIX
cd
)。
prompt>/bin/ksh
ksh prompt>chmod u+w /
workdirectory
/*.*
UNIX オペレーティング・システム・プラットフォームでは、次のように setenv.ksh
のパーミッションを変更して実行可能にすることも必要です。
ksh prompt>chmod +x setenv.ksh
環境を設定する
環境を設定するには、次のコマンドを入力します。
Windows
prompt>.
\setenv.com
UNIX
prompt>. ./setenv.ksh
Advanced サンプル・アプリケーションをビルドする
makefile
を実行するには、make
コマンドを使用します。makefile は、Microsoft Windows および UNIX の両方でサンプル・アプリケーションをビルドするために使用します。Microsoft Windows では、nmake
を使用します。UNIX では、make
を使用します。
makefile の概要
makefile では、次の手順が自動的に行われます。
setenv.cmd
) が実行済みであることを確認します。環境
変数が設定されていない場合は、エラー・メッセージを画面に出力して終了
します。
common.nt
コマンド・ファイル (Microsoft Windows) または common.mk
コマ
ンド・ファイル (UNIX) をインクルードします。このファイルでは、サンプ
ルで使用される makefile シンボルが定義されます。それらのシンボルによ
り、UNIX および Microsoft Windows の makefile でビルド規則をプラット
フォームに依存しない makefile に委譲することができます。
makefile.inc
コマンド・ファイルをインクルードします。このファイルで
は、is_reporter
、is_subscriber
、および AS_WIRESERVICE
の実行可能
ファイルがビルドされ、不要なファイルとディレクトリがクリーン・アップ
されます。
advanced.inc
コマンド・ファイルをインクルードします。このファイルで
は、tmadmin
コマンドと qadmin
コマンドを実行してトランザクション・ロ
グおよび永続的なサブスクリプションで必要なキューが作成されます。さら
に、UBBCONFIG
ファイルが作成され、tmloadcf -y ubb
コマンドを実行し
て TUXCONFIG
ファイルが作成されます。
makefile を実行する
makefile
を実行する前に、次の確認作業を行う必要があります。
nmake
がマシンのパスに含まれていることを確認します。make
がマシンのパスに含まれていることを確認します。Advanced サンプル・アプリケーションをビルドするには、make
コマンドを次のように入力します。
Windows
nmake -f makefile.nt
UNIX
make -f makefile.mk
Advanced サンプル・アプリケーションを起動する
Advanced サンプル・アプリケーションを起動するには、次のコマンドを入力します。
prompt>tmboot -y
このコマンドでは、次のサーバ・プロセスが開始されます。
TMSUSREVT
ノーティフィケーション・サービスで使用される、BEA Tuxedo システムに付属の EventBroker サーバ
TMNTS
サブスクリプションおよびイベントのポストの要求を処理する BEA Tuxedo CORBA ノーティフィケーション・サービス・サーバ
TMNTSFWD_T
一時的なサブスクリプションのあるサブスクライバにイベントを転送する BEA Tuxedo CORBA ノーティフィケーション・サービス・サーバ。このサーバは、一時的なサブスクリプションで必須です。
TMNTSFWD_P
永続的なサブスクリプションのあるサブスクライバに永続的なイベントを転送する BEA Tuxedo CORBA ノーティフィケーション・サービス・サーバ。このサーバは、永続的なサブスクリプションで必須です。
TMQUEUE
メッセージ・キュー・マネージャは、tpenqueue
(3) および tpdequeue
(3) を呼び出してプログラムの代わりにキューのメッセージの登録と取り出しを行う BEA Tuxedo システム付属のサーバです。このサーバは、永続的なサブスクリプションで必須です。
TMQFORWARD
メッセージ転送サーバは、後で処理するように tpenqueue
(3c) を使用して格納されたメッセージを転送する BEA Tuxedo システム付属のサーバです。このサーバは、永続的なサブスクリプションで必須です。
WIRE_SERVICE_SERVER
Reporter アプリケーションからイベントを受信し、そのイベントをノーティフィケーション・サービスにポストする、Advanced サンプル・アプリケーション用に特別にビルドされたサーバ。News、Shutdown、および Cancel という 3 タイプのイベントが受信およびポストされます。
ISL
IIOP リスナ/ハンドラ・プロセス
C++ の場合: prompt>is_subscriber
Microsoft Windows 上の Java の場合: prompt>java %IC_SUBSCRIBER%
UNIX 上の Java の場合: prompt>java $IC_SUBSCRIBER
Subscriber をもう 1 つ起動するには、別のウィンドウを開き、ディレクトリを作業ディレクトリに変更して (cd
)、環境変数を設定し (setenv.cmd
または setenv.ksh
を実行)、プラットフォームに適した起動コマンドを入力します。
C++ の場合: prompt>is_reporter
Microsoft Windows 上の Java の場合: prompt>java %IC_REPORTER%
UNIX 上の Java の場合: prompt>java $IC_REPORTER
Reporter をもう 1 つ起動するには、別のウィンドウを開き、ディレクトリを作業ディレクトリに変更して (cd
)、環境変数を設定し (setenv.cmd
または setenv.ksh
を実行)、プラットフォームに適した起動コマンドを入力します。
Advanced サンプル・アプリケーションの使い方
Advanced サンプル・アプリケーションを使用するには、Subscriber アプリケーションを使用してイベントをサブスクライブし、Reporter アプリケーションを使用してイベントをポストする必要があります。サブスクライブは、各イベントをポストする前に行う必要があります。そうしないと、イベントは失われます。
Subscriber アプリケーションを使用したイベントのサブスクライブ
次の手順を行います。
prompt>is_subscriber
)、
次のプロンプトが表示されます。
Name?
(スペースなしで名前を入力する)
Port (e.g. 2463)
(このサブスクライバが動作するポートの番号を入力 する)
Category (or all)
(ニュース・カテゴリまたは「all」を入力する)
Keyword (or none)
(配信するすべての記事に含まれている必要のある キーワードを入力する)
注記 Subscriber アプリケーションが Reporter アプリケーションからの Shutdown イベントによってシャットダウンされた場合 (Shutdown イベントでは永続的なサブスクリプションは取り消されない)、Subscriber アプリケーションの以降の起動では、名前以外は入力を要求されません。Subscriber アプリケーションは、名前以外の情報を <user_name>.pstore
ファイルから取り出します。このようにすることで、同じポート番号が必ず使用されるようになります (永続的なサブスクリプションでは不可欠)。
Subscriber アプリケーションが Reporter アプリケーションからの Cancel イベントによってシャットダウンされた場合 (Cancel イベントでは永続的なサブスクリプションを含むすべてのサブスクリプションが取り消される)、Subscriber アプリケーションの以降の起動では、名前、ポート番号、カテゴリ、およびキーワードの入力が要求されます。
同様に、キーワードでも文字列を入力できます。キーワードも決まったリストは存在しません。したがって、レポータを実行して記事を入力するときには、その記事に同じ文字列が含まれているようにしてください。そうしないと、記事はサブスクリプションに配信されません。
ユーザ名、カテゴリ (または「all」)、およびキーワード (オプション) の入力に基づいて初めて Subscriber アプリケーションが実行されたときには、ニュースのサブスクリプションが作成されます。次以降の実行時には、サブスクライバではこのサブスクリプションが再利用されます。Subscriber アプリケーションは常に、イベントを受信する準備ができた時点で「Ready」を出力します。
Subscriber アプリケーションは、サブスクリプションを作成し、イベント受信の準備ができた時点で「Ready」を出力します。
注記 Reporter アプリケーションを使用してイベントをポストする前に、必ず Subscriber アプリケーションを使用してイベントをサブスクライブする必要があります。そうしないと、イベントは失われます。Subscriber アプリケーションで News イベントの永続的なサブスクリプションが作成される場合でも、そのサブスクリプションは Subscriber アプリケーションが起動するまで作成されません。
注記 別のウィンドウを開いてこの手順を繰り返せば、複数のサブスクライバを起動できます。
Reporter アプリケーションを使用したイベントのポスト
次の手順を行います。
prompt> is_reporter
)、次のプロ
ンプトが表示されます。
(r) Report news
(s) Shutdown subscribers
(c) Cancel Subscribers
(e) Exit
Option?
r
を入力します。次のプロンプトが表示されます。
Category?
ニュース・カテゴリを入力すると、次のプロンプトが表示されます。
Enter story (terminate with '.')
カテゴリとキーワード (指定された場合) がこの記事と一致するサブスクライバが記事を受信して出力します。
s
」オプションを選択すると、Shutdown イベントがポストされ、そのイベ
ントがすべてのサブスクライバによって受信されて、それらのサブスクライ
バがシャットダウンされます。サブスクライバがシャットダウンされていて
も、再び「r
」オプションを使用すれば別のニュース記事をポストできます。
ノーティフィケーション・サービスはそのニュース記事を保留キューに入れ
ますが、News イベントのサブスクリプションは永続的であるため、依然と
して有効です。サブスクライバを再起動すると、サブスクライバはこの 2 番
目のニュース記事を受信します (再起動の遅延によってイベントがエラー・
キューに移動された場合を除く)。なぜなら、ニュース記事の永続的なサブ
スクリプションがサブスクライバによって作成されているからです。
注記 ntsadmin
retryerrevents
コマンドを使用すると、エラー・キューのイベントを保留キューに移動することができます。
c
」オプションを選択すると、Cancel イベントがポストされ、そのイベント
がすべてのサブスクライバで受信されます。サブスクライバは、ニュースの
サブスクリプションを取り消し、シャットダウンされます。サブスクライバ
を再起動するときには、新しいサブスクリプションを作成することになるの
で、ポート、カテゴリ、およびキーワードを再び入力する必要があります。
(e)
オプションを選択します。
注記 別のウィンドウを開いてこの手順を繰り返せば、複数のレポータを起動できます。レポータによって報告されたニュース記事はすべて、一致するすべてのサブスクライバに配信されます。システムをシャットダウンするときには、その前に必ずすべてのレポータを終了してください。
システムのシャットダウンとディレクトリのクリーン・アップ
Reporter と Subscriber のプロセスが停止しているのを確認してから、次の手順を行ってください。
prompt>tmshutdown -y
Windows
prompt>nmake -f makefile.nt clean
UNIX
prompt>make -f makefile.mk clean
|
Copyright © 2001, BEA Systems, Inc. All rights reserved.
|