Oracle® Fusion Middleware Oracle Identity Governanceのためのアプリケーションの開発とカスタマイズ 12c (12.2.1.3.3) E91981-03 |
|
![]() 前 |
この付録では、ユーザー名の予約と共通名の生成について説明します。次の項目が含まれます。
ユーザー名の予約には、ユーザー名の予約の有効化と無効化、ユーザー名ポリシーの構成と記述、ユーザー名の解放、およびActive Directoryをサポートするためのユーザー名生成の構成が含まれます。
この項では、ユーザー名の予約に関連する概念および構成について説明します。次の項目が含まれます。
ユーザー作成リクエストが承認のために保留中になっている間、Oracle Identity ManagerとLDAPの両方でユーザー名を予約できます。
ユーザー作成に対するリクエストの送信時には、次のようなシナリオが考えられます。
リクエストが保留中の間に、同じユーザー名で別のユーザー作成リクエストが送信されました。2番目のリクエストが承認されてユーザーが作成されると、1番目のリクエストは、ユーザー名がすでにOracle Identity Managerに存在するため、承認時に失敗します。
リクエストが保留中の間に、同じユーザー名の別のユーザーがLDAPアイデンティティ・ストアに直接作成されました。ユーザー作成リクエストが承認され、ユーザー・エンティティをLDAPにプロビジョニングするときに、同じユーザー名のエントリがすでにLDAPに存在するため、リクエストは失敗します。
これらの問題を回避するには、ユーザー作成リクエストが承認のために保留中の間、Oracle Identity ManagerとLDAPの両方でユーザー名を予約できます。同じユーザー名のユーザーを作成するリクエストが作成されると、エラー・メッセージが表示され、そのユーザー作成リクエストは作成されません。
ユーザー名を予約するには、次のことが必要です。
「ユーザー属性予約有効」システム・プロパティを「True」に設定して、機能を有効化する必要があります。システム・プロパティの検索と変更の詳細は、Oracle Identity Governanceの管理のシステム・プロパティの作成と管理を参照してください。
LDAPで予約が行われるのは、予約機能が有効化され、LDAPがOracle Identity Managerデータベースと同期化している場合のみです。
注意:
LDAPプロバイダが構成されていない場合、予約はOracle Identity Managerでのみ行われます。
LDAPの同期化およびユーザー属性の予約機能が有効な場合は、ディレクトリ・サーバーでUID一意性を有効化することをお薦めします。そうしないと、ユーザーが予約コンテナに予約されているときに、同じユーザーIDのユーザーをユーザー・コンテナに作成できるため、ディレクトリ内でユーザーの予約が適切に機能しません。この結果、Oracle Identity Managerでユーザーを予約コンテナからユーザー・コンテナに移動するときに、ユーザー作成が失敗します。
ユーザー属性の予約が有効な場合、予約は2つのフェーズで行われます。
最初のフェーズでは、エントリがOracle Identity Managerデータベースに作成され、ユーザーが予約コンテナに作成されます。Oracle Identity Managerデータベース内のこのエントリは、ユーザーが正常に作成された後、承認者によって却下された後、またはリクエストが失敗した後に削除されます。
2番目のフェーズでは、LDAPでユーザーが正常に作成されると、ユーザーが予約コンテナに移動します。他の状況(承認者による却下、リクエストの失敗など)の場合、ユーザーは予約コンテナから削除されます。
ユーザー作成リクエストがリクエスト・レベルおよび操作レベルで承認された後は、LDAPのユーザー名コンテナにユーザー名は予約されません。ユーザー名は、既存のユーザーが格納されているコンテナに移動します。また、ユーザーはOracle Identity Managerでも作成されます。
ユーザー名の予約機能はデフォルトで有効になっています。これを行うには、「ユーザー属性予約有効」システム・プロパティの値を「True」に設定します。
このシステム・プロパティの値は、Oracle Identity Managerシステム管理コンソールの「システム構成」セクションで確認できます。
ユーザー名の予約を無効化する手順は、次のとおりです。
ユーザー名ポリシーは、ユーザー名の生成やユーザー名の検証などのユーザー名操作のプラグイン実装です。
次の各トピックでは、ユーザー名ポリシーの構成について説明します。
ユーザー名ポリシーは、ユーザー名の生成やユーザー名の検証などのユーザー名操作のプラグイン実装です。Oracle Identity System Administrationの「システム構成」セクションで、デフォルト・ポリシーを変更できます。
ユーザーの作成ユースケースについては、プラグインが起動するのは、ユーザー・ログインが入力されなかった場合のみです。この場合、起動されるプラグインは、「ユーザー名の生成に関するデフォルト・ポリシー」システム・プロパティから取得されます。カスタム・ユーザー名ポリシーは、次のすべてのユースケースにおいて適用されます。
管理ユーザーの作成
「ユーザーの作成」のリクエスト
リコンシリエーション
一括ロード
ポリシー実装によって、ユーザー名が生成され、その可用性がチェックされ、そのユーザー名が使用できない場合は表B-1で説明した順序でポリシーに基づいて別のユーザー名が生成され、この手順が繰り返されます。生成されるユーザー名に含まれるドル記号($)はランダムなアルファベットを示します。必要な情報が欠落している場合は、ポリシーでエラーが発生します。
ユーザー名生成形式のすべてのパラメータに対して値を入力する必要があります。入力されないパラメータがあると、Oracle Identity Managerでエラーが発生します。たとえば、firstname.lastnameポリシーが構成され、firstnameが入力されない場合は、次のエラーが表示されます: 「ユーザー名の生成中にエラーが発生しました。firstname.lastnameポリシーで必要なfirstnameを指定してください。」
表B-1に、Oracle Identity Managerで提供される事前定義済のユーザー名ポリシーを示します。この表で、生成されるユーザー名に含まれるドル記号($)はランダムなアルファベットを示します。
表B-1 事前定義済のユーザー名ポリシー
ポリシー名 | 必要な情報 | 生成されるユーザー名 |
---|---|---|
oracle.iam.identity.usermgmt.impl.plugins.EmailIdPolicy |
電子メール |
電子メールの値は、自動生成されたユーザー名として使用されます。 |
oracle.iam.identity.usermgmt.impl.plugins.LastNameFirstInitialLocalePolicy |
名、姓およびロケール |
last name + first initial_locale、last name + middle initial + first initial_locale、last name + $ + first initial_locale(すべてのアルファベットからランダムな1文字)、last name + $$ + first initial_locale |
oracle.iam.identity.usermgmt.impl.plugins.FirstInitialLastNameLocalePolicy |
名、姓、ロケール |
first initial + lastname_locale、first initial + middle initial + first name_locale、first initial + $ + lastname_locale、first initial + $$ + lastname_locale |
oracle.iam.identity.usermgmt.impl.plugins.LastNameFirstInitialPolicy |
名、姓 |
lastname+firstInitial、lastname+middleinitial+firstInitial、lastname+$+firstInitial(すべてのアルファベットからランダムな1文字)、lastname+$$+firstInitial |
oracle.iam.identity.usermgmt.impl.plugins.FirstInitialLastNamePolicy |
名、姓 |
firstInitial+lastname、firstInitial+middleInitial+firstname、firstInitial+$+lastname、firstInitial+$$+lastname |
oracle.iam.identity.usermgmt.impl.plugins.LastNameFirstNamePolicy |
名、姓 |
lastname.firstname、lastname.middleinitial.firstname、lastname.$.firstname(すべてのアルファベットからランダムな1文字)、lastname.$$.firstname |
oracle.iam.identity.usermgmt.impl.plugins.FirstNameLastNamePolicy |
名、姓 |
firstname.lastname、firstname.middleinitial.lastname、firstname.$.lastname(すべてのアルファベットからランダムな1文字)、firstname.$$.lastname |
oracle.iam.identity.usermgmt.impl.plugins.DefaultComboPolicy |
次のいずれか: - 電子メール - 名、姓 - 姓。 |
電子メールを入力すると、ユーザー名は電子メールに基づいて生成されます。電子メールを使用できない場合は、名と姓に基づき、ユーザー・ドメインを付加してユーザー名が生成されます。名を使用できない場合は、姓のみに基づき、ユーザー・ドメインを付加してユーザー名が生成されます。 ユーザー・ドメインは「デフォルト・ユーザー名ドメイン」システム・プロパティとして構成され、デフォルト値は「@oracle.com」です。 |
oracle.iam.identity.usermgmt.impl.plugins.LastNamePolicy, |
姓 |
lastname、middle initial + lastname、$ + lastname、$$ + lastname |
oracle.iam.identity.usermgmt.impl.plugins.LastNameLocalePolicy |
姓、ロケール |
lastname_locale、middle initial + lastname_locale、$ + lastname_locale、$$ + lastname_locale |
oracle.iam.identity.usermgmt.impl.plugins.FirstNameLastNamePolicyForAD |
名、姓 |
firstname+lastname、firstnameの部分文字列+lastname+$、firstnameの部分文字列+lastnameの部分文字列+$ |
oracle.iam.identity.usermgmt.impl.plugins.LastNameFirstNamePolicyForAD |
姓、名 |
lastname+firstname、lastname+firstnameの部分文字列+$、lastnameの部分文字列+firstnameの部分文字列+$ |
ユーザー・マネージャでは、ユーザー名生成がパブリックAPIとして公開されています。Oracle Identity Managerでは、ユーザー名の生成機能にアクセスするためのユーティリティ・クラスが用意されています。ユーティリティ・メソッドが含まれるクラスを次に示します。
oracle.iam.identity.usermgmt.api.UserManager
UserManagerクラスでは、ユーザー名の生成および検証用に次のパブリックAPIが公開されます。
//Method that will generate username based on default policy public String generateUserNameFromDefaultPolicy(Map<String, Object> attrMap) throws UserNameGenerationException, UserManagerException; //Method that will generate username based on policy public String generateUserNameFromPolicy(String policyId, Map<String, Object> attrMap) throws UserNameGenerationException, UserManagerException; //Method that will check whether username is valid against default policy public boolean isUserNameValidForDefaultPolicy(String userName, Map<String, Object> attrMap) throws UserManagerException; //Method that will check whether username is valid against given policy public boolean isUserNameValidForPolicy(String userName, String policyId, Map<String, Object> attrMap) throws UserManagerException; //Method to return all policies (including customer written) public List<Map<String, String>> getAllUserNamePolicies(Locale locale) //Method that will return policy description in given locale public String getPolicyDescription(String policyID, Locale locale)
表B-2に、デフォルト・ユーザー名ポリシーのポリシーIDを表すためにoracle.iam.identity.usermgmt.utils.UserNameGenerationUtilに定義されている定数を示します。
表B-2 ポリシーIDを表す定数
ポリシー名 | 定数 |
---|---|
EmailIDPolicy |
EMAIL_ID_POLICY |
LastNameFirstInitialLocalePolicy |
FIRSTNAME_LASTNAME_POLICY |
FirstInitialLastNameLocalePolicy |
LASTNAME_FIRSTNAME_POLICY |
LastNameFirstInitialPolicy |
FIRSTINITIAL_LASTNAME_POLICY |
FirstInitialLastNamePolicy |
LASTNAME_FIRSTINITIAL_POLICY |
LastNameFirstNamePolicy |
FIRSTINITIAL_LASTNAME_LOCALE_POLICY |
FirstNameLastNamePolicy |
LASTNAME_FIRSTINITIAL_LOCALE_POLICY |
DefaultComboPolicy |
DEFAULT_COMBO_POLICY |
LastNamePolicy |
LASTNAME_POLICY |
LastNameLocalePolicy |
LASTNAME_LOCALE_POLICY |
FirstNameLastNamePolicyForAD |
FIRSTNAME_LASTNAME_POLICY_FOR_AD |
LastNameFirstNamePolicyForAD |
LASTNAME_FIRSTNAME_POLICY_FOR_AD |
ポリシー・クラスでは、コールされてユーザー名を生成するときに、「oracle.iam.identity.utils class.Constants」で定義されたキー定数を使用して、マップに属性値が設定されている必要があります。これは、パラメータに対して定義された適切な定数(たとえば、「FirstName」パラメータに対して定義された定数)を使用して、正しいパラメータ値が渡されてメソッドがコールされる必要があることを意味します。
カスタム・ユーザー名ポリシーの記述には、プラグイン・インタフェースの実装とplugin.xmlファイルの作成および登録が含まれます。
この項では、カスタム・ユーザー名ポリシーを記述する方法について説明します。次の項目が含まれます。
独自のポリシーを記述するには、Oracle Identity System Administrationの「システム構成」セクションで、新規プラグインを追加してデフォルト・ポリシーを変更します。
関連項目:
プラグイン・フレームワークの詳細は、プラグインの開発を参照してください
UserManagerでは、ユーザー名操作用にAPIが公開されます。APIでは、ユーザー・データを入力として取得し、生成されたユーザー名を返します。APIでは、ユーザー名を返すプラグインをコールします。これによって、ユーザー名操作の実装で、デフォルト・ポリシーをカスタム・プラグインに置換できます。
注意:
UserManagerでは、ユーザー名の生成および検証用にパブリックAPIが公開されます。
ポリシーを作成するときは、ユーザー名の生成で使用する属性がリクエスト・データセットに定義されていることを確認してください。
次に示すように、プラグイン・インタフェースを実装して、独自のユーザー名ポリシーを記述できます。
package oracle.iam.identity.usermgmt.api; public interface UserNameGenerationPolicy extends oracle.iam.identity.usermgmt.api.UserNamePolicy { public String getUserName(Map<String, Object> reqData) throws UserNameGenerationException; public boolean isGivenUserNameValid(String userName, Map<String, Object> reqData); //methods inherited from old user name policy interface //oracle.iam.identity.usermgmt.api.UserNamePolicy public String getUserNameFromPolicy(HashMap<String, String> reqData) throws UserNameGenerationException; public boolean isUserNameValid(String userName, HashMap<String, String> reqData); public String getDescription(Locale locale); }
このプラグイン・ポイントは、リクエスト・データを入力として取得し、ユーザー名を返すカーネル・プラグインとして公開されます。各プラグインでは情報の入力が必要で、入力された情報に基づいてユーザー名が生成されます。
注意:
Oracle Identity Managerでは、oracle.iam.identity.usermgmt.api.AbstractUserNameGenerationPolicyクラス名としてoracle.iam.identity.usermgmt.api.UserNameGenerationPolicyインタフェースの抽象実装を提供します。したがって、次の2つのメソッドを実装する必要はありません。
public String getUserNameFromPolicy(HashMap<String, String> reqData) throws UserNameGenerationException; public boolean isUserNameValid(String userName, HashMap<String, String> reqData);
カスタム・ユーザー名ポリシーの記述についてのガイドラインを次に示します。
ポリシーには、新しいインタフェースoracle.iam.identity.usermgmt.api.UserNameGenerationPolicyを実装する必要があります。
カスタム・ユーザー名ポリシーを再度読み込む必要があります。つまり、承認者がユーザー・ログインの生成に影響を与えない属性を更新した場合は、ポリシー内のカスタム・コードは、同じユーザー・ログインを返す必要があります。
次に、プラグインのサンプル実装を示します。
package oracle.iam.identity.usermgmt.impl.plugins; import java.util.Locale; import java.util.Map; import oracle.iam.identity.exception.UserNameGenerationException; import oracle.iam.identity.usermgmt.api.AbstractUserNameGenerationPolicy; import oracle.iam.identity.usermgmt.api.UserManagerConstants; import oracle.iam.identity.usermgmt.api.UserNameGenerationPolicy; public class CustomDepartmentNumberEmployeeNumberPolicy extends AbstractUserNameGenerationPolicy implements UserNameGenerationPolicy { private String departmentNumberKey = UserManagerConstants.AttributeName.DEPARTMENT_NUMBER.getId(); private String employeeNumberKey = UserManagerConstants.AttributeName.EMPLOYEE_NUMBER.getId(); @Override public String getUserName(Map<String, Object> reqData) throws UserNameGenerationException { String departmentnumber = reqData.get(departmentNumberKey) == null ? null : reqData.get(departmentNumberKey).toString(); String employeeNumber = reqData.get(employeeNumberKey) == null ? null : reqData.get(employeeNumberKey).toString(); // Required in case of approver edit. If approver has not modified any attribute which contributes in user name generation , then return same old user login //Check if user data is not changed using checkForSameUserLogin method present in AbstractUserNameGenerationPolicy, then return same user login //OR use Map<String, Object> existingData = (Map<String, Object>) reqData.get(oracle.iam.identity.usermgmt.api.UserManagerConstants.EXISTING_DATA ) to implement your own comparison logic // If existingData is NULL, it means generate a new user login. If it is not NULL, then it means policy is invoked during approver edit. // If it is NOT NULL, Compare value of participating attributes from existingData and reqData. If same, return same user login as present in existingData ; otherwise generate a new user login. String oldUserLogin = checkForSameUserLogin(reqData , new String[]{departmentNumberKey , employeeNumberKey}); if(oldUserLogin!=null) return oldUserLogin; // TODO: DO basic validations. Also, Ensure newly generated user name is unique and not reserved. You may use utility methods in oracle.iam.identity.usermgmt.utils.UserNamePolicyUtil for preforming validations. return departmentnumber + "-" + employeeNumber; } @Override public boolean isGivenUserNameValid(String userName, Map<String, Object> reqData) { // TODO : custom implementation return true; } @Override public String getDescription(Locale locale) { return "User Name Generation Policy using department number and employee number"; } }
リクエストが承認または却下されるか、失敗した場合、ユーザー名は解放されます。
ユーザー名は、次のシナリオで解放されます。
リクエストが承認され、ユーザーがOracle Identity Managerで正常に作成されてLDAPにプロビジョニングされると、予約表からユーザー名が削除されます。予約されていたユーザー名は、承認後にユーザーが正常に作成されると削除されます。LDAPで予約されていたエントリは削除され、実際のユーザーが作成されます。
リクエストが却下されると、LDAPおよびOracle Identity Managerで予約されていたユーザー名のエントリは削除されます。
Oracle Identity ManagerまたはLDAPでユーザーを作成中または作成前にリクエストが失敗すると、予約されていたユーザー名は削除されます。
ADがデータ・ストアとして使用されている場合にユーザー名の自動生成を行うには、XL.DefaultUserNamePolicyImplシステム・プロパティの値を設定します。
LDAPとの同期が有効化されたOracle Identity Managerデプロイメントで、Microsoft Active Directory (AD)がデータ・ストアの場合、Oracle Identity Managerの「ユーザー・ログイン」属性はLDAPの「uid」属性にマップされ、さらに、その「uid」属性は「sAMAccountName」属性にマップされます。「sAMAccountName」属性は、ADベースのすべてのアプリケーションでログインとして使用されます。ADでは、「sAMAccountName」属性に格納される値に対してサポートされている最大長に制限があります。これは、20文字を超えることはできません。
Oracle Identity Managerでは、ユーザー作成時にユーザー名を入力として受け取り、ユーザー名が20文字を超えることも可能です。ADでは20文字を超えるユーザー名がサポートされていないため、Oracle Identity Managerでは、20文字以下のユーザー名が生成されるように構成できます。
ADがデータ・ストアとして使用されている場合は、「XL.DefaultUserNamePolicyImpl」システム・プロパティの値を次のいずれかに設定して、ユーザー名の自動生成を構成できます。
FirstNameLastNamePolicyForAD: 名の部分文字列を姓の部分文字列の接頭辞として付加することによって、ユーザー・ログインを生成します。
LastNameFirstNamePolicyForAD: 姓の部分文字列を名の部分文字列の接頭辞として付加することによって、ユーザー・ログインを生成します。
XL.DefaultUserNamePolicyImplシステム・プロパティおよびシステム・プロパティの値の設定の詳細は、Oracle Identity Governanceの管理のOracle Identity Managerの構成を参照してください。
注意:
ADがデータ・ストアの場合は、「FirstNameLastNamePolicyForAD」または「LastNameFirstNamePolicyForAD」のいずれかのポリシーを使用する必要があります。その他のユーザー名生成ポリシーを使用してユーザー名を生成しようとしても失敗します。
「共通名」ユーザー属性値の生成は、ユーザー作成およびユーザー変更操作について行うことができます。
この項では、Oracle Identity Managerでの「共通名」ユーザー属性値の生成について説明します。次の項目が含まれます。
共通名は、共通名生成ポリシーを使用して生成されます。
Oracle Identity ManagerのLDAP対応デプロイメントでは、Human Capability Management (HCM)などのFusionアプリケーションはSPMLリクエストを介して共通名を渡しません。LDAPで共通名が必須属性で、Oracle Identity Managerが共通名をRDNとして使用するように設定されている場合、Oracle Identity Managerでは一意の共通名を生成する必要があります。
共通名の説明に基づいて、名と姓で構成されるユーザーの表示名が共通名になります。この場合、Oracle Identity Managerでは、「firstname lastname」形式で共通名を指定する共通名生成ポリシーを使用して、共通名が生成されます。
「FirstNameLastNamePolicy」の詳細は次のとおりです。
必要な情報: 名、姓
生成される共通名: firstname.lastname、firstname.$.lastname(すべてのアルファベットからランダムな1文字)、firstname.$$.lastnameなど、共通名が一意になるように生成されます。
注意:
リクエストによってユーザーが作成されるまで共通名は予約されるため、同じ名と姓を使用した複数のリクエストが同時に生成された場合でも、同じ共通名は生成されません。
Oracle Identity Managerで共通名の生成を構成するには、「XL.DefaultCommonNamePolicyImpl」システム・プロパティの値をoracle.iam.identity.usermgmt.impl.plugins.FirstNameLastNamePolicyに設定します。
XL.DefaultCommonNamePolicyImplシステム・プロパティおよびシステム・プロパティの値の設定の詳細は、Oracle Identity Governanceの管理のOracle Identity Managerの構成を参照してください。
ユーザー変更操作については、ターゲットLDAPサーバーで参照整合性をオンにする必要があります。
ユーザー・プロファイルが変更されると、1つ以上の属性が変更される可能性があります。HCMでは、変更前のユーザー属性を保持しておらず、どの属性が変更されたかを判断できないため、変更されたデータのみをフィルタ処理してOracle Identity Managerに送信できません。このため、共通名(CN)を含むすべての属性がSPMLリクエストを介してOracle Identity Managerに渡されます。CNが変更されると、Oracle Identity Managerではディレクトリ内で変更操作(modrdn)が実行されるため、DNが変更される結果になります。この意図しないDN変更によって、グループ・メンバーシップのDNが失効し、ユーザーはそのグループのメンバーシップを失います。この結果、認可が失敗します。これは、LDAPサーバーで参照整合性がオフの場合に発生し、ユーザーのRDNが変更されたときに参照先グループが更新されません。したがって、ターゲットLDAPサーバーで参照整合性をオンにする必要があります。そうしないと、グループ・メンバーシップが失効します。参照整合性の問題はロールにも該当します。グループが他のグループのメンバーでもある場合、RDNの変更は同様に影響を与えます。
参照整合性をオンにするには、「XL.IsReferentialIntegrityEnabled」システム・プロパティの値を「TRUE」に設定します。このシステム・プロパティの詳細は、Oracle Identity Governanceの管理のOracle Identity Managerの構成を参照してください。
RDN変更のシナリオの詳細は、RDN変更のシナリオを参照してください。
変更操作の結果は、RDNが変更される場合に考えられるシナリオによって異なります。
表B-3は、RDNが変更される場合に考えられるシナリオのリストです。
表B-3 RDN変更のシナリオ
LDAPでの参照整合性 | XL.IsReferentialIntegrityEnabled | 変更操作(modrdn)の結果 |
---|---|---|
無効 |
FALSE |
Oracle Identity Managerでエラーが発生し、操作は失敗します。 |
無効 |
TRUE |
Oracle Identity Managerからの変更操作が正常に実行され、LDAPでRDNが変更されます。ただし、グループ参照は更新されずに失効します。この構成はお薦めしません。 |
有効 |
FALSE |
Oracle Identity Managerでエラーが発生し、変更操作は失敗します。LDAPで参照整合性が有効であるため、Oracle Identity Managerでこのプロパティを「TRUE」に設定する必要があります。 |
有効 |
TRUE |
変更操作が正常に実行され、RDNが更新されます。さらに、LDAPでDNの参照が更新されます。 |
各ディレクトリにロールおよびユーザーが格納された複数のディレクトリ。 ここでは参照整合性プロパティは関係ありません。 |
FALSE |
Oracle Identity Managerからの変更操作が失敗します。これはLDAPでサポートされていません。このため、Oracle Identity Managerでは、このプロパティの値を「FALSE」に設定することをお薦めします。 |
各ディレクトリにロールおよびユーザーが格納された複数のディレクトリ。 ここでは参照整合性プロパティは関係ありません。 |
TRUE |
変更操作が正常に実行され、RDNが変更されます。ただし、LDAPでは複数のディレクトリでの参照整合性をサポートしていないため、グループ参照は失効し、手動で更新する必要があります。 |