• EnglishEspañol日本語한국어Português
  • ログイン今すぐ開始

この機械翻訳は、参考として提供されています。

英語版と翻訳版に矛盾がある場合は、英語版が優先されます。詳細については、このページを参照してください。

問題を作成する

テスト終了確認モーダルを表示する

ヒント

このレッスンは、New Relic アプリケーションをゼロから構築する方法を学習するコースの一部です。 まだご覧になっていない方は、概要をご覧ください。

コースの各レッスンは前回のレッスンに基づいて構築されるため、このレッスンを開始する前に、前回のレッスン「選択したバージョンを保持する」を完了していることを確認してください。

このチュートリアルでは、A/B テスト アプリケーションを構築します。 このアプリケーションは、Web サイトで進行中の A/B テストに関するデータを表示し、それを使用して、どのページ デザイン バージョンがユーザーを引き付けるのに最も効果的かを決定します。 その包括的な目標の一部として、実験の勝者を決定してテストを終了できるセクションを構築します。

残念ながら、このセクションのコードとデザインにはいくつか問題があります。 このコースの最後に、 End test [テストの終了]を押すと、ウェブサイトのバックエンド サーバーに、すべての顧客にここで選択したバージョンが表示されるように指示されます。 これは、Web サイトに不可逆な変更を加える破壊的な動作です。 End test [テスト終了]を押すことによる破壊性を考慮するには、アプリケーションのいくつかの機能を変更する必要があります。

  • 注目を集めるためにボタンを重要に見せましょう
  • テストを途中で終了しないように、終了する前に確認メッセージで自分自身に警告します。

確認モーダルを表示または非表示にする

コースワークリポジトリpresent-confirmation-modal/ab-testディレクトリに変更します:

bash
$
cd nru-programmability-course/present-confirmation-modal/ab-test

このディレクトリには、コースのこの時点でアプリケーションに必要なコードが含まれています。 各レッスンの開始時に正しいディレクトリに移動することで、カスタム コードが残され、間違ったコードがレッスン間で持ち越されることがなくなります。

nerdlets/ab-test-nerdlet/end-test.jsで、 DESTRUCTIVEスタイルを使用するようにButtonを更新します。

import React from 'react';
import {
Button,
Grid,
GridItem,
HeadingText,
Select,
SelectItem,
} from 'nr1';
class VersionSelector extends React.Component {
constructor(props) {
super(props);
}
render() {
return <Select onChange={this.props.selectVersion} value={this.props.selectedVersion}>
<SelectItem value={'A'}>Version A</SelectItem>
<SelectItem value={'B'}>Version B</SelectItem>
</Select>
}
}
class EndTestButton extends React.Component {
render() {
return <div>
<Button type={Button.TYPE.DESTRUCTIVE}>End test</Button>
</div>
}
}
export default class EndTestSection extends React.Component {
constructor() {
super(...arguments);
this.state = {
selectedVersion: 'A',
};
this.selectVersion = this.selectVersion.bind(this);
}
selectVersion(event, value) {
this.setState({ selectedVersion: value });
}
render() {
return <Grid className="endTestSection">
<GridItem columnSpan={12}>
<HeadingText className="endTestHeader">
Pick the winner of your A/B test:
</HeadingText>
</GridItem>
<GridItem columnStart={5} columnEnd={6} className="versionSelector">
<VersionSelector
selectedVersion={this.state.selectedVersion}
selectVersion={this.selectVersion}
/>
</GridItem>
<GridItem columnStart={7} columnEnd={8}>
<EndTestButton>End test</EndTestButton>
</GridItem>
</Grid>
}
}

nru-programmability-course/present-confirmation-modal/ab-testにある Nerdpack のルートに移動します。

Nerdpack の新しい UUID を生成します。

bash
$
nr1 nerdpack:uuid -gf

既存の Nerdpack を含むコースワーク リポジトリを複製したため、独自の一意の識別子を生成する必要があります。 この UUID は Nerdpack を New Relic アカウントにマッピングします。

アプリケーションをローカルで提供します。

bash
$
nr1 nerdpack:serve

https://one.newrelic.com?nerdpacks=localにアクセスし、 Apps [アプリ] > Your apps [あなたのアプリ]でアプリケーションを表示します。

これで、ボタンの破壊的な結果を伝えるようにボタンのスタイルを設定しましたが、誤ってクリックするのを防ぐには十分ではありません。 次に、Web サイトのバックエンド用のシールドを作成します。 この追加の保護層では、実際にテストを終了する前に、テストを終了する意図があることを確認する必要があります。

EndTestButtonModalを追加します:

import React from 'react';
import {
BlockText,
Button,
Grid,
GridItem,
HeadingText,
Modal,
Select,
SelectItem,
} from 'nr1';
class VersionSelector extends React.Component {
constructor(props) {
super(props);
}
render() {
return <Select onChange={this.props.selectVersion} value={this.props.selectedVersion}>
<SelectItem value={'A'}>Version A</SelectItem>
<SelectItem value={'B'}>Version B</SelectItem>
</Select>
}
}
class EndTestButton extends React.Component {
render() {
return <div>
<Button type={Button.TYPE.DESTRUCTIVE}>End test</Button>
<Modal>
<HeadingText>Are you sure?</HeadingText>
<BlockText>
If you end the test, all your users will receive the version you selected:
</BlockText>
<BlockText spacingType={[BlockText.SPACING_TYPE.LARGE]}>
<b>Version A</b>
</BlockText>
<Button>No, continue test</Button>
<Button type={Button.TYPE.DESTRUCTIVE}>Yes, end test</Button>
</Modal>
</div>
}
}
export default class EndTestSection extends React.Component {
constructor() {
super(...arguments);
this.state = {
selectedVersion: 'A',
};
this.selectVersion = this.selectVersion.bind(this);
}
selectVersion(event, value) {
this.setState({ selectedVersion: value });
}
render() {
return <Grid className="endTestSection">
<GridItem columnSpan={12}>
<HeadingText className="endTestHeader">
Pick the winner of your A/B test:
</HeadingText>
</GridItem>
<GridItem columnStart={5} columnEnd={6} className="versionSelector">
<VersionSelector
selectedVersion={this.state.selectedVersion}
selectVersion={this.selectVersion}
/>
</GridItem>
<GridItem columnStart={7} columnEnd={8}>
<EndTestButton>End test</EndTestButton>
</GridItem>
</Grid>
}
}

新しいモーダルには、見出し、確認メッセージ、優勝したデザインバージョン、および 2 つのボタンが含まれます。 これらのコンポーネントのいくつかについては、このコースの後半で詳しく説明します。

Nerdpack がローカルで提供されている状態で、アプリケーションを表示して新しいModalを確認します。

ヒント

サーバーの実行中は、コードを保存すると自動的に更新されることに注意してください。

モーダルは見た目は素晴らしいですが、3 つの問題があります。

  • End test [テスト終了を]クリックする前に存在していた
  • 無視することはできない
  • 実際には選択していないのに、常に「バージョンA」を選択したと表示されます。

次の手順では、これら 3 つの問題をすべて修正します。

EndTestButtonで、 statemodalHiddenの値で初期化します。

import React from 'react';
import {
BlockText,
Button,
Grid,
GridItem,
HeadingText,
Modal,
Select,
SelectItem,
} from 'nr1';
class VersionSelector extends React.Component {
constructor(props) {
super(props);
}
render() {
return <Select onChange={this.props.selectVersion} value={this.props.selectedVersion}>
<SelectItem value={'A'}>Version A</SelectItem>
<SelectItem value={'B'}>Version B</SelectItem>
</Select>
}
}
class EndTestButton extends React.Component {
constructor(props) {
super(props);
this.state = {
modalHidden: true,
}
}
render() {
return <div>
<Button type={Button.TYPE.DESTRUCTIVE}>End test</Button>
<Modal>
<HeadingText>Are you sure?</HeadingText>
<BlockText>
If you end the test, all your users will receive the version you selected:
</BlockText>
<BlockText spacingType={[BlockText.SPACING_TYPE.LARGE]}>
<b>Version A</b>
</BlockText>
<Button>No, continue test</Button>
<Button type={Button.TYPE.DESTRUCTIVE}>Yes, end test</Button>
</Modal>
</div>
}
}
export default class EndTestSection extends React.Component {
constructor() {
super(...arguments);
this.state = {
selectedVersion: 'A',
};
this.selectVersion = this.selectVersion.bind(this);
}
selectVersion(event, value) {
this.setState({ selectedVersion: value });
}
render() {
return <Grid className="endTestSection">
<GridItem columnSpan={12}>
<HeadingText className="endTestHeader">
Pick the winner of your A/B test:
</HeadingText>
</GridItem>
<GridItem columnStart={5} columnEnd={6} className="versionSelector">
<VersionSelector
selectedVersion={this.state.selectedVersion}
selectVersion={this.selectVersion}
/>
</GridItem>
<GridItem columnStart={7} columnEnd={8}>
<EndTestButton>End test</EndTestButton>
</GridItem>
</Grid>
}
}

modalHidden モーダルを非表示にするかどうかを決定します。 End test [テストの終了を]選択した場合にのみモーダルを表示するため、 modalHiddenのデフォルト値はtrueです。

ModalmodalHiddenを供給します:

import React from 'react';
import {
BlockText,
Button,
Grid,
GridItem,
HeadingText,
Modal,
Select,
SelectItem,
} from 'nr1';
class VersionSelector extends React.Component {
constructor(props) {
super(props);
}
render() {
return <Select onChange={this.props.selectVersion} value={this.props.selectedVersion}>
<SelectItem value={'A'}>Version A</SelectItem>
<SelectItem value={'B'}>Version B</SelectItem>
</Select>
}
}
class EndTestButton extends React.Component {
constructor() {
super(...arguments);
this.state = {
modalHidden: true,
}
}
render() {
return <div>
<Button type={Button.TYPE.DESTRUCTIVE}>End test</Button>
<Modal hidden={this.state.modalHidden}>
<HeadingText>Are you sure?</HeadingText>
<BlockText>
If you end the test, all your users will receive the version you selected:
</BlockText>
<BlockText spacingType={[BlockText.SPACING_TYPE.LARGE]}>
<b>Version A</b>
</BlockText>
<Button>No, continue test</Button>
<Button type={Button.TYPE.DESTRUCTIVE}>Yes, end test</Button>
</Modal>
</div>
}
}
export default class EndTestSection extends React.Component {
constructor() {
super(...arguments);
this.state = {
selectedVersion: 'A',
};
this.selectVersion = this.selectVersion.bind(this);
}
selectVersion(event, value) {
this.setState({ selectedVersion: value });
}
render() {
return <Grid className="endTestSection">
<GridItem columnSpan={12}>
<HeadingText className="endTestHeader">
Pick the winner of your A/B test:
</HeadingText>
</GridItem>
<GridItem columnStart={5} columnEnd={6} className="versionSelector">
<VersionSelector
selectedVersion={this.state.selectedVersion}
selectVersion={this.selectVersion}
/>
</GridItem>
<GridItem columnStart={7} columnEnd={8}>
<EndTestButton>End test</EndTestButton>
</GridItem>
</Grid>
}
}

まず、コンポーネントのプロパティを受け入れるコンストラクターを作成しました。 これにより、コンポーネントはEndTestSectionで渡したmodalHiddenプロパティにアクセスできるようになります。 次に、 ModalコンポーネントのhiddenプロパティにmodalHiddenの値を指定します。

2 つの新しいメソッドをEndTestSectionに追加してバインドします。

import React from 'react';
import {
BlockText,
Button,
Grid,
GridItem,
HeadingText,
Modal,
Select,
SelectItem,
} from 'nr1';
class VersionSelector extends React.Component {
constructor(props) {
super(props);
}
render() {
return <Select onChange={this.props.selectVersion} value={this.props.selectedVersion}>
<SelectItem value={'A'}>Version A</SelectItem>
<SelectItem value={'B'}>Version B</SelectItem>
</Select>
}
}
class EndTestButton extends React.Component {
constructor() {
super(...arguments);
this.state = {
modalHidden: true,
}
this.showModal = this.showModal.bind(this);
this.closeModal = this.closeModal.bind(this);
}
closeModal() {
this.setState({ modalHidden: true });
}
showModal() {
this.setState({ modalHidden: false });
}
render() {
return <div>
<Button type={Button.TYPE.DESTRUCTIVE}>End test</Button>
<Modal hidden={this.state.modalHidden}>
<HeadingText>Are you sure?</HeadingText>
<BlockText>
If you end the test, all your users will receive the version you selected:
</BlockText>
<BlockText spacingType={[BlockText.SPACING_TYPE.LARGE]}>
<b>Version A</b>
</BlockText>
<Button>No, continue test</Button>
<Button type={Button.TYPE.DESTRUCTIVE}>Yes, end test</Button>
</Modal>
</div>
}
}
export default class EndTestSection extends React.Component {
constructor() {
super(...arguments);
this.state = {
selectedVersion: 'A',
};
this.selectVersion = this.selectVersion.bind(this);
}
selectVersion(event, value) {
this.setState({ selectedVersion: value });
}
render() {
return <Grid className="endTestSection">
<GridItem columnSpan={12}>
<HeadingText className="endTestHeader">
Pick the winner of your A/B test:
</HeadingText>
</GridItem>
<GridItem columnStart={5} columnEnd={6} className="versionSelector">
<VersionSelector
selectedVersion={this.state.selectedVersion}
selectVersion={this.selectVersion}
/>
</GridItem>
<GridItem columnStart={7} columnEnd={8}>
<EndTestButton>End test</EndTestButton>
</GridItem>
</Grid>
}
}

ユーザーがモーダルとどのように対話するかに応じて、それぞれcloseModalshowModalを使用してモーダルを閉じたり表示したりします。

End test [テスト終了を]クリックしたときにモーダルを表示します:

import React from 'react';
import {
BlockText,
Button,
Grid,
GridItem,
HeadingText,
Modal,
Select,
SelectItem,
} from 'nr1';
class VersionSelector extends React.Component {
constructor(props) {
super(props);
}
render() {
return <Select onChange={this.props.selectVersion} value={this.props.selectedVersion}>
<SelectItem value={'A'}>Version A</SelectItem>
<SelectItem value={'B'}>Version B</SelectItem>
</Select>
}
}
class EndTestButton extends React.Component {
constructor() {
super(...arguments);
this.state = {
modalHidden: true,
}
this.showModal = this.showModal.bind(this);
this.closeModal = this.closeModal.bind(this);
}
closeModal() {
this.setState({ modalHidden: true });
}
showModal() {
this.setState({ modalHidden: false });
}
render() {
return <div>
<Button type={Button.TYPE.DESTRUCTIVE} onClick={this.showModal}>End test</Button>
<Modal hidden={this.state.modalHidden}>
<HeadingText>Are you sure?</HeadingText>
<BlockText>
If you end the test, all your users will receive the version you selected:
</BlockText>
<BlockText spacingType={[BlockText.SPACING_TYPE.LARGE]}>
<b>Version A</b>
</BlockText>
<Button>No, continue test</Button>
<Button type={Button.TYPE.DESTRUCTIVE}>Yes, end test</Button>
</Modal>
</div>
}
}
export default class EndTestSection extends React.Component {
constructor() {
super(...arguments);
this.state = {
selectedVersion: 'A',
};
this.selectVersion = this.selectVersion.bind(this);
}
selectVersion(event, value) {
this.setState({ selectedVersion: value });
}
render() {
return <Grid className="endTestSection">
<GridItem columnSpan={12}>
<HeadingText className="endTestHeader">
Pick the winner of your A/B test:
</HeadingText>
</GridItem>
<GridItem columnStart={5} columnEnd={6} className="versionSelector">
<VersionSelector
selectedVersion={this.state.selectedVersion}
selectVersion={this.selectVersion}
/>
</GridItem>
<GridItem columnStart={7} columnEnd={8}>
<EndTestButton>End test</EndTestButton>
</GridItem>
</Grid>
}
}

ここでは、 ButtonコンポーネントのonClickイベントのコールバックとしてshowModal()を指定しました。

https://one.newrelic.com?nerdpacks=localに戻り、変更内容を確認します。

モーダルはデフォルトで非表示になっています。 モーダルを表示するには、 End test [テスト終了を]をクリックします。

ModalコンポーネントのonCloseコールバックと、 Yes, end test [はい、テストを終了]ボタンおよびNo, continue test [いいえ、テストを続行]ボタンからモーダルを閉じます。

import React from 'react';
import {
BlockText,
Button,
Grid,
GridItem,
HeadingText,
Modal,
Select,
SelectItem,
} from 'nr1';
class VersionSelector extends React.Component {
constructor(props) {
super(props);
}
render() {
return <Select onChange={this.props.selectVersion} value={this.props.selectedVersion}>
<SelectItem value={'A'}>Version A</SelectItem>
<SelectItem value={'B'}>Version B</SelectItem>
</Select>
}
}
class EndTestButton extends React.Component {
constructor() {
super(...arguments);
this.state = {
modalHidden: true,
}
this.showModal = this.showModal.bind(this);
this.closeModal = this.closeModal.bind(this);
}
closeModal() {
this.setState({ modalHidden: true });
}
showModal() {
this.setState({ modalHidden: false });
}
render() {
return <div>
<Button type={Button.TYPE.DESTRUCTIVE} onClick={this.showModal}>End test</Button>
<Modal hidden={this.state.modalHidden} onClose={this.closeModal}>
<HeadingText>Are you sure?</HeadingText>
<BlockText>
If you end the test, all your users will receive the version you selected:
</BlockText>
<BlockText spacingType={[BlockText.SPACING_TYPE.LARGE]}>
<b>Version A</b>
</BlockText>
<Button onClick={this.closeModal}>No, continue test</Button>
<Button type={Button.TYPE.DESTRUCTIVE} onClick={this.closeModal}>Yes, end test</Button>
</Modal>
</div>
}
}
export default class EndTestSection extends React.Component {
constructor() {
super(...arguments);
this.state = {
selectedVersion: 'A',
};
this.selectVersion = this.selectVersion.bind(this);
}
selectVersion(event, value) {
this.setState({ selectedVersion: value });
}
render() {
return <Grid className="endTestSection">
<GridItem columnSpan={12}>
<HeadingText className="endTestHeader">
Pick the winner of your A/B test:
</HeadingText>
</GridItem>
<GridItem columnStart={5} columnEnd={6} className="versionSelector">
<VersionSelector
selectedVersion={this.state.selectedVersion}
selectVersion={this.selectVersion}
/>
</GridItem>
<GridItem columnStart={7} columnEnd={8}>
<EndTestButton>End test</EndTestButton>
</GridItem>
</Grid>
}
}

https://one.newrelic.com?nerdpacks=localに戻り、変更内容を確認します。

End test [テスト終了]をクリックします。 モーダルが開き、確認メッセージが表示されます。 モーダルを閉じるには、右上のX 、いずれかのボタン、または左側の暗いスペースをクリックします。

「バージョン B」を選択した場合でも、モーダルには「バージョン A」を選択したと表示されることに注意してください。 これは、「バージョン A」がModalテキストにハードコードされているためです。 次に、それを動的にします。

モーダルで選択したバージョンを使用する

EndTestSectionで、 selectedVersionEndTestButtonに渡します。

import React from 'react';
import {
BlockText,
Button,
Grid,
GridItem,
HeadingText,
Modal,
Select,
SelectItem,
} from 'nr1';
class VersionSelector extends React.Component {
constructor(props) {
super(props);
}
render() {
return <Select onChange={this.props.selectVersion} value={this.props.selectedVersion}>
<SelectItem value={'A'}>Version A</SelectItem>
<SelectItem value={'B'}>Version B</SelectItem>
</Select>
}
}
class EndTestButton extends React.Component {
constructor() {
super(...arguments);
this.state = {
modalHidden: true,
}
this.showModal = this.showModal.bind(this);
this.closeModal = this.closeModal.bind(this);
}
closeModal() {
this.setState({ modalHidden: true });
}
showModal() {
this.setState({ modalHidden: false });
}
render() {
return <div>
<Button type={Button.TYPE.DESTRUCTIVE} onClick={this.showModal}>End test</Button>
<Modal hidden={this.state.modalHidden} onClose={this.closeModal}>
<HeadingText>Are you sure?</HeadingText>
<BlockText>
If you end the test, all your users will receive the version you selected:
</BlockText>
<BlockText spacingType={[BlockText.SPACING_TYPE.LARGE]}>
<b>Version A</b>
</BlockText>
<Button onClick={this.closeModal}>No, continue test</Button>
<Button type={Button.TYPE.DESTRUCTIVE} onClick={this.closeModal}>Yes, end test</Button>
</Modal>
</div>
}
}
export default class EndTestSection extends React.Component {
constructor() {
super(...arguments);
this.state = {
selectedVersion: 'A',
};
this.selectVersion = this.selectVersion.bind(this);
}
selectVersion(event, value) {
this.setState({ selectedVersion: value });
}
render() {
return <Grid className="endTestSection">
<GridItem columnSpan={12}>
<HeadingText className="endTestHeader">
Pick the winner of your A/B test:
</HeadingText>
</GridItem>
<GridItem columnStart={5} columnEnd={6} className="versionSelector">
<VersionSelector
selectedVersion={this.state.selectedVersion}
selectVersion={this.selectVersion}
/>
</GridItem>
<GridItem columnStart={7} columnEnd={8}>
<EndTestButton selectedVersion={this.state.selectedVersion}>End test</EndTestButton>
</GridItem>
</Grid>
}
}

これで、 EndTestButtonコンポーネントのプロパティから選択したバージョンにアクセスできるようになりました。

確認メッセージにselectedVersion使用します:

import React from 'react';
import {
BlockText,
Button,
Grid,
GridItem,
HeadingText,
Modal,
Select,
SelectItem,
} from 'nr1';
class VersionSelector extends React.Component {
constructor(props) {
super(props);
}
render() {
return <Select onChange={this.props.selectVersion} value={this.props.selectedVersion}>
<SelectItem value={'A'}>Version A</SelectItem>
<SelectItem value={'B'}>Version B</SelectItem>
</Select>
}
}
class EndTestButton extends React.Component {
constructor() {
super(...arguments);
this.state = {
modalHidden: true,
}
this.showModal = this.showModal.bind(this);
this.closeModal = this.closeModal.bind(this);
}
closeModal() {
this.setState({ modalHidden: true });
}
showModal() {
this.setState({ modalHidden: false });
}
render() {
return <div>
<Button type={Button.TYPE.DESTRUCTIVE} onClick={this.showModal}>End test</Button>
<Modal hidden={this.state.modalHidden} onClose={this.closeModal}>
<HeadingText>Are you sure?</HeadingText>
<BlockText>
If you end the test, all your users will receive the version you selected:
</BlockText>
<BlockText spacingType={[BlockText.SPACING_TYPE.LARGE]}>
<b>Version {this.props.selectedVersion}</b>
</BlockText>
<Button onClick={this.closeModal}>No, continue test</Button>
<Button type={Button.TYPE.DESTRUCTIVE} onClick={this.closeModal}>Yes, end test</Button>
</Modal>
</div>
}
}
export default class EndTestSection extends React.Component {
constructor() {
super(...arguments);
this.state = {
selectedVersion: 'A',
};
this.selectVersion = this.selectVersion.bind(this);
}
selectVersion(event, value) {
this.setState({ selectedVersion: value });
}
render() {
return <Grid className="endTestSection">
<GridItem columnSpan={12}>
<HeadingText className="endTestHeader">
Pick the winner of your A/B test:
</HeadingText>
</GridItem>
<GridItem columnStart={5} columnEnd={6} className="versionSelector">
<VersionSelector
selectedVersion={this.state.selectedVersion}
selectVersion={this.selectVersion}
/>
</GridItem>
<GridItem columnStart={7} columnEnd={8}>
<EndTestButton selectedVersion={this.state.selectedVersion}>End test</EndTestButton>
</GridItem>
</Grid>
}
}

https://one.newrelic.com?nerdpacks=localに戻り、変更内容を確認します。

メニューから「バージョン B」を選択します。 End test[テスト終了]をクリックすると、確認モーダルに「バージョン B」が表示されます。

完了したら、ローカル サーバーのターミナル ウィンドウでCTRL+Cを押して、New Relic アプリケーションの提供を停止します。

おめでとうございます。多くの作業が行われました。その成果はアプリケーションの有用性に表れています。 モックデータを表示するグラフを作成しました。 チャートを読みやすい構造に整理しました。 ユーザーがテストと対話するためのインターフェースを追加しました。 ここで、実際のデータが必要になります。 次のレッスンでは、グラフ内の模擬データをバックエンド サービスの実際のデータに置き換えます。

ヒント

このレッスンは、New Relic アプリケーションをゼロから構築する方法を学習するコースの一部です。 次のレッスンに進みましょう: NrqlQuery コンポーネントをナードレットに追加します。

Copyright © 2024 New Relic株式会社。

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.