<追記>
スーバーバッジの名称が「Lightning Component Framework Specialist」から「Aura Components Specialist」に変更になりました。
ですが、内容は前のLightning Component Framework Specialistと同じですので、そのまま読み替えていただいて構いません。
ここからは、仕様部分の本文の内容を記載しています。
こちらは一気に翻訳したいと思います。
本文の翻訳(仕様編)
使用事例
過去数年間、世界最大のRVレンタル会社HowWeRoll Rentalsが、レクリエーション・ビークル(RV)レンタル市場を支配するようになりました。彼らのタグラインは、 “私たちはどのようにロールしているのですか?”という素晴らしいサービスを提供しています。彼らのレンタル艦隊には、豪華な移動式住宅から古い学校のクロームエアストリームキャンプまで、あらゆる形式のキャンパー車両が含まれています。あなたがワンダーラストに悩まされているなら、彼らは治療法を持っています!
HowWeRollのSalesforce開発者の一員として、あなたは会社を大成功に導いてくれました。収入を増やすために、同社のリーダーシップは、RVの旅行者の大部分がボートの所有者であることが調査によって示されているため、RV市場のコアを超えて拡大し、レクリエーションボート業界に参入することに決定しました。 HowWeRollは、自分たちのボートを取得するために多額の投資をする代わりに、ボートシェアリングプログラムを開始し、ボートのリースエージェントとしての役割を果たします。 HowWeRollはこの新しいサービスをFriends with Boatsと呼んでいます。
営業担当者が顧客のボートに関する情報を入力できるようにするライトニングエクスペリエンス、Salesforce App、Lightningアプリケーションに登場したカスタムライトニングページを実装するために1週間与えられています。また、各ボートを検査する際にチームメンバーが自分の経験についてコメントや評価を投稿できるようにします。
開発したカスタム検索エンジンを使用すると、HowWeRollの営業担当者は、ボートタイプ(漁船、遊覧船、パーティボートなど)に基づいてボートのリストをフィルタリングして、ボート在庫と顧客の要求を一致させることができます。
標準オブジェクト
次の標準オブジェクトで作業します:
- Contact – 組織の連絡先とボートの所有者。
- User – ボートのレビューとコメントを投稿するユーザー。
カスタム
次の標準オブジェクトで作業します:
- Boat – あなたの連絡先が所有するボートに関する情報。 このオブジェクトにはジオロケーションフィールドが含まれているため、マップ上の典型的なドックの位置をプロットすることができます。 このオブジェクトは、連絡先標準オブジェクトとのマスター – 詳細関係と、BoatTypeとのルックアップ関係を持っています。
- BoatType – 漁船、パワーボート、ヨット、パーティーバージなど、さまざまなタイプのボートのリスト。
- BoatReview – ボートのコメントと評価。
エンティティダイアグラム
「Setup」の「クイック検索」ボックスに「Schema Builder」と入力し、「Schema Builder」を選択して、イメージの対話バージョンを表示します。 詳細は、「データモデリング」モジュールの「スキーマビルダーを使用した作業」を参照してください。
アプリケーション設計
HowWeRollの主要なステークホルダーとの会合に費やした時間は貴重な時間でした。 Lightningページの次の青写真を思いつきました。
先行する仕事の大きさを評価した後、コーヒーを飲み、大きな仕事を征服する最善の方法はそれをより小さなものに分割することだと決めます。 完了したら、完成した製品が完成する次の9つの段階を計画します。
検索フォームを作成する
百万海里の旅は、1行のコードから始まります。
プールをドロップダウンで表示して、各ボートの種類と、検索ボタンと新規ボタンを表示して、モーターを稼動させます。 フォームコンポーネントには、ドロップダウンとボタンが含まれています。
〜ここに画面イメージの図〜
図1.1:サンプルバイクエリーインターフェイスの構築
フォームを作成するには、以下のLightningコンポーネントを作成します。 各コンポーネントは、図1.1の対応する番号で強調表示されています。
- BoatSearchForm.cmp – 最初のデフォルト値として空の文字列、「すべてのタイプ」というラベルを使用して、ユーザーがドロップダウンメニューを使用してBoatTypeで結果をフィルタリングできるようにするフォーム。 <lightning:layout>コンポーネントとhorizontalAlign属性を使用して、ドロップダウンに中央揃えの検索ボタン(青いバリアント)と新規ボタン(白いバリアント)を含めます。ユーザーが新規をクリックすると、コントローラー機能が適切なイベントを起動して新しいBoatレコードを作成します。ボートタイプが選択されている場合、新しいボートレコードはデフォルトで選択されたボートタイプになります。フォームのコントローラーは、スタンドアロンアプリケーションでevent.force:createRecordイベントがサポートされているかどうかをチェックし、ベストプラクティスに従ってNewボタンを表示するか非表示にします。ユーザーが[検索]をクリックすると、フィルタ機能が実装されていないため、[検索フィルタの実装]フェーズが実行されます。
- BoatSearchResults.cmp – このコンポーネントは最終的には対応するレイアウトで一致するボートを表示しますが、現在は空のままです。
- BoatSearch.cmp – BoatSearchForm.cmpとBoatSearchResults.cmpの両方を呼び出し、LightningカードでそれぞれのタイトルをBoatとMatching Boatsでラップするコンテナコンポーネントです。 BoatSearchFormコンポーネントとBoatSearchResultsコンポーネントを視覚的に分離するために、Find a Boatカードに10pxの余白を追加します。
メイン列と右側のサイドバーレイアウトを使用するFriends with Boatsという名前のライトニングページを作成します。 BoatSearchコンポーネントをメイン列に配置します。 ライトニングエクスペリエンスとSalesforce Appの新しいタブとしてページをアクティブにします。 最後に、Lightningページに似たレイアウトで、URL経由で直接アクセスできるFriendswithBoats.appというLightningアプリケーションを作成します。 <lightning:layout>を使用してアプリケーションレイアウトを生成し、アプリ内のコンポーネントでLightning Design Systemスタイルを使用できることを確認します。
~ここに検索フォームの画像〜
図1.2:検索フォームの最初。
次に、応答のないレイアウトでフィルタリングされていない検索結果を表示し始めます。
検索結果を取り込む
ボートタイプのリストを見るのが楽しいので、美しいボートの写真を見せてください! この段階が終了すると、HowWeRollの在庫にあるすべてのボートのフィルタリングされていないリストがページに表示されます。
~ここに検索結果の画像〜
図2:BoatSearchResultsコンポーネント(1)は、Apexメソッドから返されたデータをループし、BoatTile(2)コンポーネントを生成します。
Lightningコンポーネント、BoatTile.cmpを作成します。このコンポーネントには、賃貸用ボートが表示され、Boat__c型の属性ボートがあります。 テーマのlightning:buttonとしてタイルを実装します。 稲lightning:buttonにタイルのクラスを割り当て、BoatTile.cmpの中にボートの画像を表示する方法の目安として、次のマークアップとCSSを使用します。
〜ここにソースコード〜
ApexクラスBoatSearchResultsを使用して検索結果を取得します。 このクラスは、String型のboatTypeIdを受け取り、そのIDでフィルタリングされたボートのリストを返すgetBoats()メソッドを使用します。 ユーザーが「すべての型」を選択すると、空の文字列がこの関数に渡され、すべてのボートが返されます。
BoatSearchResults.cmpは、コンポーネント結果ボートに検索結果を格納するonSearch()というヘルパーメソッドを使用して、BoatSearchResultsによって返されたデータを取得します。 次に、BoatSearchResults.cmpは結果をループし、図2に示すように複数の行を含むレスポンスグリッドに配置されたBoatTile.cmpとしてそれぞれを表示します。<lightning:layout>を使用して、 レイアウト。
Apexクラスが結果を返さない場合は、BoatSearchResults.cmpの絶対的な中央に “No boats found”というメッセージを表示します。
次のセクションでは、検索フィルタを機能させるようにします。
検索フィルタの実装
いくつかの人は航海したい人もいれば釣りたい人もいますし、他の人はただ楽しんだりしたい人もいます。 検索フォームを結果コンポーネントに接続することで、アソシエートが顧客が望むボートを簡単に見つけることができます。
〜ここにボートタイプ選択の画像〜
図3:検索フィルタの実装ボートタイプを選択して検索ボタンをクリックすると、結果がフィルタリングされます。
今度は、イベントを使用してboatTypeIdが次のパスをたどるように、3つのコンポーネントを変更します。
BoatSearchForm – > BoatSearch – > BoatSearchResults – > Apex
新しいイベントc:formSubmitという名前のformubmitをformDataというObject属性で使用して、選択したboatTypeIdをformDataのプロパティとしてBoatSearchFormからその親コンポーネントBoatSearchに渡します。これは、検索ボタンに添付されたonFormSubmit()というコントローラー関数を介して行います。
BoatSearchコンポーネントでは、onFormSubmitというコントローラアクションでFormSubmitを処理します。コントローラから、searchというBoatSearchResultsコンポーネントのパブリックメソッドにformData.boatTypeIdを渡します。
検索メソッドでコントローラの関数doSearchを呼び出すと、メソッドの引数からboatTypeIdパラメータが取得され、コンポーネントのboatTypeId属性の値が設定されます。次に、helper関数onSearch()を呼び出して、新しく更新されたboatTypeIdコンポーネント属性を取得し、それをサーバーに渡してボートのリストを要求します。ボートのリストを表示し、ボートカテゴリを選択してSearchをクリックすることで、ボートのリストをフィルタリングできるようになりました。
選択されたボートを強調表示する
ボート・リース契約を結ぶには、HowWeRollセールス・チームは単に美しい写真を表示するだけではありません。 彼らはこれらのボートのすべての詳細に素早くアクセスする必要がありますが、最初に彼らは彼らが見ているボートを知る必要があります。
シンプルなCSSルールを使用して選択されたボートが、コンポーネント間の通信によって切り替えられるコンポーネント属性と一緒にユーザーに明確になっていることを確認します。 これは、別のイベントを作成し、BoatTileおよびBoatSearchResultsコンポーネントを変更することで実現します。
〜ここにボート選択の画像〜
図4:ボートをクリックすると、ボートタイルの周りに青色の境界線(1)が表示されます。
まず、BoatTileコンポーネントを変更します。 selectedという名前のブール属性をデフォルト値falseで追加します。タイルの稲妻:ボタンで、三項演算子を使用して、v.selectedがtrueの場合はクラスを選択タイルに、v.selectedがfalseの場合はタイルにクラス属性を追加します。選択したクラスのborderプロパティに次の値を指定して、コンポーネントバンドルにCSSを追加します。3px solid rgb(0、112、210);
コントローラー機能onBoatClickを呼び出すBoatTileの稲妻:ボタンにクリックハンドラーを定義して続行します。 onBoatClick内で、BoatTelectに登録されたBoatSelectという新しいイベントを発生させ、イベントを使用してBoatSearchResultsコンポーネントにboatIdを送信します。
BoatSearchResultsは、onBoatSelectというコントローラ関数を呼び出すことによってBoatSelectイベントを処理する必要があります。この関数は、イベント経由で渡されたboatIdをselectedBoatIdというコンポーネント属性に格納します。 boatという名前の反復変数を使用し、BoatTileのBoatSearchResults呼び出しで、現在出力されているboat.IdがコンポーネントのselectedBoatId属性に格納されている値と等しいかどうかに基づいて、選択された属性にtrueまたはfalseの値を渡すために、 。
ボートの詳細を表示
あなたが見ているボートがはっきりしているので、選択したボートの詳細を表示します。 タブセットを持つ親コンポーネントBoatDetailsを作成します。 詳細タブの中に新しい子コンポーネントBoatDetailをインスタンス化します。 Lightning Data Serviceを使用して、情報が正しくロードされ、アプリケーションの残りの部分と同期した状態を維持するようにします。
〜ここにボート選択時の詳細画面の画像〜
図5.1:BoatTetailsコンポーネント(1)は、BoatDetailsコンポーネント(2)が処理するイベントを起動し、BoatDetailコンポーネント(3)の表示を更新します。
図5.1に示すように、BoatDetailsコンポーネントはLightningページの右上のサイドバーに配置されています。ボート(Boat__c型)とid(型Id)の2つのパブリック属性があります。このコンポーネントは、Details、Reviews、Add Reviewの3つのタブを出力しますが、コンポーネントのboat属性が未定義の場合はタブセットを非表示にします。
BoatTileコンポーネントのonBoatClickハンドラを更新して、BoatSelectedという新しいイベントを発生させ、選択したBoat__cのボートを渡します。
BoatDetailsコンポーネントは、BoatSelectedイベントがアプリケーション内の他の場所から起動されたときにonBoatSelectedというコントローラ関数を実行する必要があります。 onBoatSelectedは、BoatDetailsコンポーネントのid属性を、イベントと共に送信されたボートのIDに設定します。
BoatDetailsコンポーネントは、次のフィールドをBoat_Detailsコンポーネントのid属性に基づいてBoat__cオブジェクトからコンポーネントのボート属性にロードするaura:serviceのidを持つforce:recordDataのtargetFields構文を使用します。
- Id
- Name
- Description__c
- Price__c
- Length__c
- Contact__r.Name
- Contact__r.Email
- Contact__r.HomePhone
- BoatType__r.Name
- Picture__c
force:recordDataは、後のフェーズで使用されるonRecordUpdatedという空のコントローラ関数を呼び出します。 BoatDetails onBoatSelected関数は、Lightning Data Serviceに指定されたレコードを強制的に再ロードさせます。
BoatDetailコンポーネントは、BoatDetailsコンポーネントのDetailsタブ内で使用され、Boat__c型の属性ボートで呼び出されます。 これは、ユーティリティを備えた稲妻カードを使用します:アンカーアイコンと、<lightning:layout>を使用して構築された2列レイアウト。 左側の列にはボートに関するテキスト情報が表示され、右側の列にはボート画像が表示されます。 このコンポーネントは、以下のマークアップとCSSを使用してボート情報を表示します。価格は米国の通貨形式を使用し、説明に埋め込みHTMLを許可します。
Markup – Column 1
Markup – Column 2
カードのヘッダーは、 “ボート”と連結されたボート連絡先の名前です。カードのアクションセクションには、フルディテールというラベルのボタンが表示され、onFullDetailsというコントローラーメソッドが呼び出され、適切なイベントが発生し、ユーザーを ボートのデフォルトの詳細ページ。 ただし、[詳細]ボタンは、イベントが展開プラットフォームで利用可能な場合にのみ出力されます。
〜DETAILSタブの画像〜
図5.2:タブセットを作成し、ボートの詳細を表示するタブの1つを実装します。
この時点で、ボートをブラウズしてフィルタリングし、ボートの詳細を表示することができます。 次に、レビューを追加して表示し、安全なJavaScriptを作成し、地図上にボートをプロットします。
ボートレビューを追加
HowWeRollはこれらのボートのすべてを所有していないので、顧客にリースするときに肯定的および否定的な経験を追跡して、レモンを取り除くことが重要です。 各ボートのレビューを提出する機能を追加することで、この目標を達成してください。
[送信]をクリックすると、次の操作が実行されます。
- BoatReview__cに新しいレコードを作成します(Lightning Data Serviceを使用)
- 送信が成功したというトーストメッセージを表示します。
- [レビュー]タブを有効にします。まだ表示されません
〜ADD REVIEWタブの画像〜
図6:レビューの追加フォーム
フォームを作成する
BoatDetailsコンポーネントの[Add Review]タブは新しいコンポーネントAddBoatReviewをインスタンス化し、コンポーネントのBoat__c型のパブリック属性ボートを使用してボートデータを渡します。 コンポーネントは、SLDSを使用してフォームレイアウトを定義し、すべてのフォームフィールドが垂直に配置されるようにします。 titleフィールドとdescriptionフィールドは、適切なLightningコンポーネントを使用し、BoatReview__c型のコンポーネントのprivate属性のboatReviewのNameおよびComment__cプロパティにバインドされています。 フォント選択オプションは、説明フィールドのリッチテキストエディタから削除されます。 送信ボタンはユーティリティ:保存アイコンを使用し、コントローラメソッドonSaveを呼び出します。 評価フィールドは、サードパーティスクリプトの統合フェーズまで追加されません。
新しいBoatReviewレコードを作成する
このコンポーネントは、Lightning Data Serviceを利用してBoatReview__cレコードを作成します。 force:recordDataへの呼び出しは、targetFields構文を使用し、値が “service”のaura:idを持ち、boatReview属性を参照し、以下のフィールドをtargetとします:Id、Name、Comment__c、Boat__c。レコードが更新されると、この節で後述するように、onRecordUpdatedというコントローラ関数が呼び出され、recordErrorというプライベートコンポーネント属性があり、サービスエラーが書き込まれます。
コンポーネントの初期化時に、AddBoatReviewは、コントローラ関数doInit()を介してonInit()というヘルパー関数を呼び出し、コンポーネント、イベント、ヘルパーの各引数を渡します。 onInit()関数は、Lightning Data Serviceの適切なメソッドを呼び出して新しいBoatReview__cレコードを取得し、レコードのBoat__cプロパティをコンポーネントに渡されたボートのIDに設定し、その結果をBoatReviewコンポーネント属性に格納しますconsole.log()コマンドを使用して、ブラウザのJavaScriptコンソールにエラーデータを書き込みます。
onSave()コントローラ関数は、Lightning Data Serviceを使用してレコードを保存します。レコードが保存されると、force:showToastイベントがサポートされている場合、トーストメッセージが表示されます。 force:showToastがサポートされていない場合は、JavaScriptのalert()メソッドを使用してメッセージを表示します。最後に、helper.onInit()を呼び出してコンポーネントをリセットし、ユーザーが別のレビューを追加できるようにします。 onSave()コントローラ関数と同様に、onRecordUpdated()コントローラ関数は、トーストメッセージまたはJavaScriptアラートを使用して、レコードが更新されたことをユーザーに通知します。
タブのフォーカスをレビュータブに変更する
レビューが正常に保存されると、新しいイベントBoatReviewAddedがBoatDetailsの親コンポーネントに戻され、イベントをリスンし、onBoatReviewAddedというコントローラ関数を呼び出し、現在選択されているタブをIDを持つレビュータブに設定します ボートレビュータブの
ディスプレイボートレビュー
ユーザーにレビューを追加できるようにしたので、レビューを追加しましょう。
〜REVIEWSタブの画像〜
図7:ボートレビュー
コンポーネントの定義
BoatDetailsコンポーネントの[レビュー]タブでは、新しいコンポーネントBoatReviewsがインスタンス化され、選択されたボート情報がboat__cタイプのボートという名前のパブリック属性として渡されます。
選択したボートのレビューを読み込む
ApexクラスBoatReviewsは、type IdのboatIdという名前の引数を受け取り、BoatReviewカスタムオブジェクトから次のフィールドを含むBoat Reviewsのリストを返すgetAll()という関数を定義しています。
- Id
- Name
- Comment__c
- Rating__c
- LastModifiedDate
- CreatedDate
- CreatedBy.Name
- CreatedBy.SmallPhotoUrl
- CreatedBy.CompanyName
BoatReviews Lightningコンポーネントには、BoatReview__cの配列としてboatReviewsという名前のプライベートコンポーネント属性が含まれています。 コンポーネントのinitハンドラは、コントローラ関数doInit()を介してヘルパ関数onInit()を呼び出します。 onInit()関数はApexと通信し、結果をコンポーネントのboatReviews配列属性に配置し、Apexエラーを正常に処理します。
ボートレビューを出力する
ボートレビューの出力は、ライトニングデザインシステムのフィードコンポーネントに基づいています。 BoatReviewsコンポーネントは、Salesforceアプリケーションでのネイティブスクロールを可能にするLightningコンポーネントを使用して、最大高さ250pxの独立したスクロール領域を定義します。レビューが見つからない場合は、スクロール可能な領域内の中央に絶対的に配置されたテキスト「No reviews available」を出力します。ボートレビューが見つかった場合は、boatReviewという名前の反復変数を使用して、図7に示すようにBoatReview.getAll()関数で指定されたすべてのフィールドを使用して、Lightning Design Systemのフィードコンポーネントに記述されているようなマークアップを出力します 。
CreatedByの名前がハイパーリンクされているため、onUserInfoClick()というコントローラー関数を呼び出す場合があります。このリンクには、boatReview.CreatedBy.Idの値を保持するdata-userid属性が含まれています。 onUserInfoClick()関数は、ハイパーリンク上でエンコードされたdata-userid属性から値を取得し、ユーザーをレビューの作成者の詳細ページに移動させるイベントを発生させます。
プログラム的に出力を更新する
コンポーネントの出力は、ユーザーが別のボートを選択したり、新しいレビューを追加したりするたびに更新する必要があります。コンポーネントには、コンポーネントのボート属性の値が変更されるたびにApexからデータをリロードするイベントハンドラがあります。これは、コンポーネントのdoInit()コントローラメソッドを呼び出すpublicメソッドrefreshを定義します。 refresh()メソッドは、BoatDetails.onBoatReviewAdded()メソッドとBoatDetails.onRecordUpdated()メソッドから呼び出されます。
サードパーティのスクリプトを統合する
あなたは前方思想家です。 HowWeRollの在庫が何千ものボートになったら(あなたは悲観主義者であると非難したことはありません!)、一目であなたのベストボートのリストを見ることができる必要があります。あなたが知っている – 良いプログラマーは良いコードを書いていますが、偉大なプログラマーは良いプログラマーのコードを再利用するので、最初から始めるのではなく、関係者が開発したスクリプトから始めます。このスクリプトは、5つ星の評価尺度を実装しています。残念ながら、あなたのアソシエートはスクリプトをかなり完成させていないので、いくつかの詳細を記入する必要があります。
〜ADD REVIEWタブの評価画像〜
図8.1:AddBoatReviewコンポーネントの編集モードのFiveStarRatingコンポーネント
このフェーズでは、図8.1に示すように、ユーザーが金星をクリックしてレーティングを割り当てることを可能にするFiveStarRatingコンポーネントを作成します。
〜REVIEWSタブの評価画像〜
図8.2:BoatReviewコンポーネントの読み取り専用モードでのFiveStarRating。
このコンポーネントには、図8.2に示すように、評価を出力するがクリック可能ではない読み取り専用モードもあります。
コンポーネントの作成
最新のコンポーネントFiveStarRatingには、valueon属性(Integer default 0)とreadonly属性(boolean default false)があります。 rating.cssファイルとrating.jsファイルをfivestar静的リソースからロードします。 スクリプトがロードされた後、afterScriptsLoadedというコントローラー関数を呼び出します。
コンポーネントのvalue属性が変更されたときに発生するonValueChangeというコントローラ関数を呼び出す変更イベントリスナーを追加します。 aura:idがratingareaのコンポーネントに
-
- タグを追加し、3値演算子を使用して、readonly属性の値に応じてクラス属性をc-ratingまたはc-ratingに設定します。
コントローラロジックの基礎として、次のコードを使用します。 プレースホルダを適切なコードに置き換えます。
コンポーネントのデプロイ
AddBoatReviewコンポーネントとBoatReviewsコンポーネントでコンポーネントをインスタンス化します。 コンポーネントの値は、BoatReviewカスタムオブジェクトのRating__cフィールドにバインドされています。
マップ上にマーカーをプロットする
彼らがリース契約を締結すると、HowWeRollの顧客はリースしているボートをどこから拾うかを知る必要があります。 グランドフィナーレでは、ボートのドッキング場所を示すマッピングコンポーネントをデプロイし、アプリケーション内のどこからでもPlotMapMarkerイベントをリッスンするようにコンポーネントを更新します。
〜地図表示の画像〜
図9:BoatTileコンポーネント(1)をクリックすると、緯度と経度を渡してPlotMapMarkerイベントが発生します。 Mapコンポーネント(2)はPlotMapMarkerをリッスンし、指定された緯度と経度にマーカーを配置します。
Mapコンポーネントとそのコントローラは、このスーパーバージョのプレワークの一部としてインストールしたアンマネージドパッケージに含まれていたので、変更するだけで済みます。作業を開始する前に、コンポーネントに付属の各ファイルを確認して、動作の仕組みを理解してください。
ビジネスユーザーが地図コンポーネントの幅と高さを設定できるデザインリソースを作成します。次に、図9に示すように、右側のサイドバーのBoatDetailsコンポーネントの下にあるLightningページにMapコンポーネントを追加します。
をaura:idマップで括弧で囲んで更新します。 UIをページ上の他の要素と一貫性を保つために使用します。地図の1ピクセルの点線を削除します。次に、sObjectId、lat、long、およびlabelの4つの文字列属性を含む新しいPlotMapMarkerイベントを作成します。ユーザーがBoatTileコンポーネントからボートをクリックするとイベントが発生しますが、コンポーネントはアプリケーション内の他のコンポーネントからのイベントもリスンします。 PlotMapMarkerのイベントリスナーでは、イベントを通過した緯度と経度を使用してボートの場所を更新します。
翻訳はこれで終わり
いかがでしたでしょうか。
日本語でも読むのが大変なんですが、全部英語でさらに大変でした。
だいぶGoogle先生に任せっきりだったので、徐々に手直しはしていこうと思います。
上記翻訳内容を利用して、次からは問題に入っていきます。
コメント