Hypothesisを最近使っている
2021/11/21 11:18
chrome拡張
webページを彷徨っていると、気になった部分をハイライトしたり、その時の考え等をメモして保存しておきたい時がある。 上記のことができるchrome拡張として有名どころは[diigo](https://www.diigo.com/)があったりするが、こいつは**Markdownでの記録ができない**という欠点がある。まあどうしてもMarkdownじゃないと駄目という程ではないが、やはりMarkdownで書けた方が精神衛生上いいことは間違いない。 そこで色々探していたところ、以下のようなchrome拡張を見つけた。 https://web.hypothes.is/education/ chrome拡張のサイトはこっち https://chrome.google.com/webstore/detail/hypothesis-web-pdf-annota/bjfhmglciegochdpefhhlphglcehbmek?hl=ja 拡張を有効にした状態でwebページのコンテンツ部分を適当にドラッグすると、「Highlight」と「Annotate」の二つの操作を選択できるポップアップメニューが表示される。Highlightはシンプルにマーカーを引くのみで、Annotateだとマーカーを引く+該当部分にコメントを残す、ということができる。 以下は、適当にドラッグした箇所についてAnnotateした状態の図である。 赤枠内に、選択した範囲とそれに対するコメントを入力できているのが分かると思う。 ![hypothesis.png](https://drive.google.com/uc?export=view&id=1g9oyJPnRmVfMaLW0pNDP6Me6mQU3qnik) 後はhepothesisの一覧画面上で今までのハイライト・コメントした記事を確認できる。 ![hypothesis_index.png](https://drive.google.com/uc?export=view&id=1edHoeVFKkMewLEW3Cj2F5yr-JQz2L48G) そして、このハイライト・コメント機能自体はPCだけでなく、モバイルからでも利用できる。 過去にハイライトした記事の一覧画面はスマホ等のモバイル端末からもアクセスが可能で、一覧画面からそれぞれの記事に飛ぶことでハイライト・コメント機能が有効になった状態で該当の記事に遷移できる。そのため、モバイル端末上でドラッグ→コメントを残す、といったことができる。そして編集等も可能。 私的には上記の機能がかなり便利に感じられた。ここまでモバイルのことも考えているchrome拡張も珍しいと思った次第である。 また、モバイル上で一覧画面のブックマークをアプリ化することで、ホーム画面から簡単にアクセスできるようすることも可能である。 <br> 今のところ目立ったデメリットはないが、強いて言うなら下記はこれからの機能追加等で対応されたら嬉しいなと思っている。 - 管理画面上でも記事の削除ができること - 保存している記事自体の分類ができること 現状だと、コメントとかを消したいとなった時にはその記事に遷移して個別にコメントとかを消さないといけないため、少々手間である。 あと、コメント・ハイライトした箇所の単位でタグを付けられるがwebページへのタグ付けはできないようなので、〇〇系の記事・××系の記事といった分類は難しい。 今後も機能追加はされると思うので、この辺の実装を待ちたい。 もしくは自分で作るか。。
grapeのoptionsについての備忘録
2021/09/26 22:41
プログラミング, 備忘録
railsのgemに [grape](https://github.com/ruby-grape/grape)と [grape-entity](https://github.com/ruby-grape/grape-entity#options-hash)というものがある。 これらを使えば、RESTfulなAPIをそれなりに手軽に返せる機構を作ることが出来る。 以下のようなgrapeのフォーマットに従ったAPIレスポンス用のクラス、及び Entity定義用のクラスがあったとする。 ``` ruby # UserAPIクラス class Api < Grape::API format :json content_type :json, 'application/json' resource :users do desc 'user list' get do # アクティブ状態のuserを一覧取得するイメージ users = User.active # UserEntity.represent(users) = UserEntity.new(users) UserEntity.represent(users, class: request.headers[:class]) end end end ``` ``` ruby # UserEntityクラス class UserEntity < Grape::Entity expose :id expose :email expose :status expose :class_name private def class # object: Userの1インスタンスが入る object.class_users.find { |class| class.id == @options[:class].id } end end ``` この時、 `UserEntity`にて @optionsというインスタンス変数が使われているが、この中には ``` ruby UserEntity.represent(users, class: request.headers[:class]) ``` で指定された `class: request.headers[:class]`部分がkey-value形式で格納されている。 参考: - https://www.rubydoc.info/github/intridea/grape-entity/Grape%2FEntity.represent - https://blog.kyanny.me/entry/2015/11/22/224607
クリーンアーキテクチャを読んだ
2021/08/19 02:19
読書
[クリーンアーキテクチャ](https://www.amazon.co.jp/Clean-Architecture-%E9%81%94%E4%BA%BA%E3%81%AB%E5%AD%A6%E3%81%B6%E3%82%BD%E3%83%95%E3%83%88%E3%82%A6%E3%82%A7%E3%82%A2%E3%81%AE%E6%A7%8B%E9%80%A0%E3%81%A8%E8%A8%AD%E8%A8%88-Robert-C-Martin/dp/4048930656)を読んだのでメモとして残す。 ただし、所々省略していたりそもそもメモってない箇所もあるので悪しからず。 ## 一部 **1章** - ソフトウェアアーキテクチャの目的は「求められるシステムを構築・保守するために必要な人材を最小限に抑えること」 - 結果的に、クリーンなコードを書いた場合の最遅よりも、クリーンでないコードを書いた時の最速の方が遅くなっていく **2章** 省略 --- ## 二部 **3章** 3つのパラダイムは、それぞれ「何をすべきか」よりも「何をすべきでないか」、という意図を伝えている これらのパラダイムは、アーキテクチャの「コンポーネントの分離」「データ管理」「機能」という関心事に対応している - 構造化プログラミング - オブジェクト指向プログラミング - 関数型プログラミング **4章(構造化プログラミング)** - 反証可能(テストすることが可能)なプログラミングの単位を作成する能力が重要 - テストはバグが存在しないことは証明できず、バグが存在してることを示すものである - **機能分割** - プログラムを再帰的に分割して、証明可能な小さな機能する必要がある - 証明可能な小さな機能が正しくないことを、テストを使って証明する **5章(オブジェクト指向(OO)プログラミング)** OOとは:ポリモーフィズムを使用することで、システムにある全てのコードの依存関係を絶対的に制御する能力 --- ## 三部 SOLID原則について 目的 - 以下のような性質を持つ中間レベルのソフトウェア構造を作ること - 変更に強いこと - 理解しやすいこと - コンポーネントの基盤として、多くのソフトウェアシステムで利用できること - 中間レベル:コードレベルよりも上に適用されるもので、モジュールやコンポーネントで使うソフトウェア構造の定義に役立つ - SOLID原則 - 単一責任の原則(SRP):クラスに任せる責任は一つのみにすること - オープン・クローズドの原則(OCP):ソフトウェアのエンティティ(クラス、モジュール、関数)は拡張に対して開き、修正に対して閉じていなければならない - リスコフの置換原則(LSP):スーパークラスは、そのサブクラスで代用可能でなければならない - 要はサブクラスの型を知る必要がないようにし、サブクラス側にoverride を強制するようにしろということ - インターフェース分離の原則(ISP):クライアントが利用しないメソッドへの依存を強制してはならない - 依存性逆転の原則(DIP) - 高水準モジュールは低水準モジュールに依存してはならない。両者は、抽象化に依存するべきである。 - 抽象化は、詳細に依存してはならない。詳細は、抽象化に依存するべきである。 **7章(**単一責任の原則**)** リファクタリングとかでいう「どのモジュールも一つのことのみ行うべき」という原則とは異なる(これはリファクタリングの方の原則) **8章**(オープンクローズドの原則) - 拡張に対して開いていて、修正に対して閉じていないといけない - ちょっとした修正のために大量の書き換えが発生しないようにするのが重要 - 上位コンポーネントは、下位コンポーネントの修正に対して無関心であるべき **9章**(LSP: リスコフの置換原則) - スーパークラスとサブクラスは置換可能でないといけない - サブクラスの入力のパターンは、基本クラスの入力のパターンよりも緩い - 厳しくなってしまうと、利用者側はサブクラスを使う際に厳密な入力(引数)が求められてしまうことになる - サブクラスの出力のパターンは、基本クラスの入力のパターンよりも厳しい - 緩くなってしまうと、利用者がサブクラスの挙動について詳細を知る必要が出てきてしまう 参考: [https://qiita.com/yuki153/items/142d0d7a556cab787fad](https://qiita.com/yuki153/items/142d0d7a556cab787fad) [https://qiita.com/yuu341/items/1a45048950f3b5b76bdc](https://qiita.com/yuu341/items/1a45048950f3b5b76bdc) **10章**(ISP:インターフェース分離の原則) - クライアントは使用しないインターフェースの実装を強制されるべきではない - インターフェース実装時は、それぞれのクラスに必要な箇所のみを抽出したインターフェースを作れ、ということ 参考: [https://zenn.dev/chida/articles/882aad07effa5c](https://zenn.dev/chida/articles/882aad07effa5c) **11章**(依存関係逆転の原則) ソフトウェアの変更時は、具象の変更で収まるようにし、抽象の変更は極力しないようにするのが原則 - 変化しやすい具象クラスを参照しない - 代わりに抽象インターフェースを参照するようにすること(変更が少ないため、何らかの変更に巻き込まれて自分も修正しないといけない、ということが減る) - 変化しやすい具象クラスを継承しない - 具象関数をオーバーライドしない - 変化しやすい具象を名指しで参照しない 参考: [https://techracho.bpsinc.jp/hachi8833/2019_05_09/62314](https://techracho.bpsinc.jp/hachi8833/2019_05_09/62314) rubyの例あり [https://madogiwa0124.hatenablog.com/entry/2019/11/08/211648](https://madogiwa0124.hatenablog.com/entry/2019/11/08/211648) **12章**(コンポーネント) コンポーネントとはデプロイの単位→rubyならgemファイル インタプリタ型言語ならソースファイル **13章**(コンポーネントの凝集性) コンポーネントの凝集性に関わる3つの原則。 アーキテクトに対して以下の3つの原則をバランスよく取り入れることが重要 - 再利用・リソース投下の原則(REP)→再利用性のためのグループ化 - コンポーネントを再利用するには、コンポーネントのリリース単位で行う - 再利用の単位とリリースの単位は同じになる - 閉鎖性共通の原則(CCP)→保守性のためのグループ化 - 同じ理由、同じタイミングで変更されるクラスをコンポーネントにまとめること。 - 単一責任の原則の言い換え→コンポーネントを変更する理由が複数あるべきではない - 全再利用の原則(CRP)→不要なリリース作業を減らすための分割 - 1つのクラスのみを再利用することはほぼなく、複数のクラスと組み合わせて使われることが大半のため、そういったクラス群は1つのコンポーネントにまとめる 参考: コンポーネントに関する6つの原則(13・14章合わせて) [https://qiita.com/NagaokaKenichi/items/65c149ba92580fce5be2#全再利用の原則crpthe-common-reuse-principle](https://qiita.com/NagaokaKenichi/items/65c149ba92580fce5be2#%E5%85%A8%E5%86%8D%E5%88%A9%E7%94%A8%E3%81%AE%E5%8E%9F%E5%89%87crpthe-common-reuse-principle) **14章**(コンポーネントの結合) - 非循環依存関係の原則(ADP) - コンポーネントの依存構造に循環依存があってはいけない - 依存関係のグラフが有向非循環グラフ(循環構造が存在しない有向グラフ)で表されているか - 安定依存の原則(SDP) - 安定度の高いコンポーネントに依存するという原則 - 多数のコンポーネントから依存されたコンポーネントは変更しづらい、そのためこういったコンポーネントは安定度が高いと考えらえれる - 基本的には抽象度の高いレイヤーに依存するべきなので、安定度の高い=抽象度の高いと言い換えられる - 安定度・抽象度評価の原則(SAP) - コンポーネントの抽象度は、その安定度と同程度でなければならない - 安定度の高いコンポーネントは抽象度も高くあるべきで、安定度の高さが拡張の妨げになってはいけない - 安定度が低いことによってその内部の具体的なコードが変更しやすくなるため、安定度の低いコンポーネントはより具体的であるべき --- ## 五部 **15章(アーキテクチャとは)** アーキテクチャの形状の目的は、「できる限り長い期間、できるだけ多くの選択肢を残せるようにすること」 - 残すべき選択肢とは、重要ではない詳細のこと - **アーキテクトは、方針・詳細を区別して、方針が詳細を把握・依存することないようにする必要がある** - 方針:重要なもの、優先度高 - 詳細:重要でないもの、優先度低 - 詳細は決定を延期・留保することができる その他 - 早い段階から**デプロイ周り**の戦略を考える必要がある - アーキテクチャが優れていれば、自ずと運用方法は明確になる --- **16章(独立性)** 省略 **17章(バウンダリー)** ソフトウェアアーキテクチャに境界線を引くために、まずシステムをコンポーネントに分割する。この中のいくつかのコンポーネントがコアのビジネスルールとなる。 個人的に、DBの構成等はビジネスルールに密接に結びつくと考えていたので、DBの決定は遅らせることができる、というのは目から鱗 **18章(境界の解剖学)〜21章まで省略** **22章(クリーンアーキテクチャ)** アーキテクチャの目的 = 関心事の分離 クリーンアーキテクチャが生み出すシステムについての特性 - フレームワーク非依存 - アーキテクチャはソフトウェアのライブラリに依存しない - そのため、フレームワークに依存せず、単なるツールとして利用できる - テスト可能 - ビジネスルールはUI、データベース、webサーバ、その他の外部要素がなくてもテスト可能 - UI非依存 - ビジネスルールを変更することなく、ウェブUIをコンソールUIに置き換えることができる - データベース非依存 - どのデータベースにも置き換えることが可能 - 外部エージェント非依存 - ビジネスルールは、外界のインターフェイスについて何も知らなくていい - 下図について 円の外側は仕組み、内側は方針 アーキテクチャを動作させる重要なルールは「依存性のルール」 - ソースコードの依存性は、内側(上位レベルの方針)だけに向かっていなければならない - つまり、円の内側は外側について何も知らなくていい - エンティティ - 企業全体の最重要ビジネスルールをカプセル化したもの - ページのナビゲーションやセキュリティに変更があったとしても、エンティティが影響を受けることはない - ユースケース - アプリケーション固有のビジネスルールが含まれている - ソフトウェアが何ができるのか、を示す - ドメイン駆動設計でいうところのアプリケーションサービス - インターフェースアダプター - 入力、永続化、表示を担当するオブジェクトが所属する - 永続化とはデータの保存、表示は結果の表示を表す - 一般的な MVC フレームワークや単体テストクラスなどはこのレイヤーに所属する - フレームワークとドライバ - データベース操作オブジェクトやウェブフレームワークなど - このレイヤーではあまりコードは書かない - 境界線を越えるには - 図の右下がそれを表している - 例:ユースケースから円の内側にあるインターフェースを呼び出すようにして円の外側にあるプレゼンターを呼び出すなどする ![CleanArcitecture.png](https://drive.google.com/uc?export=view&id=1LQkqHUhAgz7qAt4B9F-bPsYjKu_kgJci) - 参考: [https://gist.github.com/mpppk/609d592f25cab9312654b39f1b357c60](https://www.notion.so/609d592f25cab9312654b39f1b357c60) [https://qiita.com/nrslib/items/a5f902c4defc83bd46b8#enterprise-business-rules](https://qiita.com/nrslib/items/a5f902c4defc83bd46b8#enterprise-business-rules) [https://www.slideshare.net/AtsushiNakamura4/clean-architecture-release](https://www.slideshare.net/AtsushiNakamura4/clean-architecture-release)
ブログ作りました
2021/08/12 23:16
ブログを自作しました。 ブログ作ってみると、はてなブログがいかに完成されたサービスかよく分かります。 改善点はまだまだあるけど、ひとまずこちらを運用していこうと思っています。 それではよろしくお願いします m(_ _)m
近況について
2021/05/20 23:17
<p>こんにちは、fujjimaです。</p> <p>ブログの方は、管理画面側は終わったんで一般画面の方作ってます。 全部<a class="keyword" href="http://d.hatena.ne.jp/keyword/Rails">Rails</a>なので特殊なことは何もしてないです。月別<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%A2%A1%BC%A5%AB%A5%A4%A5%D6">アーカイブ</a>作ってみて思ったけど、あれって結構実装面倒なんだね。</p> <p>最近の近況だけ言うと、一応仕事はしています。 2ヶ月ぐらい前から仕事再開し出しました。まだ当分は今の現場で働きます。</p> 基本的に設計の議論とかをメンバー内で行うのが通例になっているので、疑問点とかをそこでシェアできるのが私的にはいいと思います。 今の現場にどれぐらいいるかは分かりませんが、在籍している間はチームの生産性に少しでも寄与できればと考えています。
近々ブログを移設します
2021/03/08 22:47
<p>そういやブログの自作をしていなかったと思い立ったので、近々自分のブログを作ってそっちに引っ越そうと思います。 今のところ全部<a class="keyword" href="http://d.hatena.ne.jp/keyword/Rails">Rails</a>で作る予定で、簡単に済ませたい。</p> <p>というか転職しないといけないんだよ、俺は。</p>
Material-UIのSelect内のテキスト部分のスタイルをいじる
2021/02/13 18:19
<h3>したいこと</h3> <p>Material-UIのSelect<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%B3%A5%F3%A5%DD%A1%BC%A5%CD%A5%F3%A5%C8">コンポーネント</a>内にあるテキスト部分のスタイルを変更したかった。 具体的には、下図のようにテキストエリアの範囲を縮小したかった。</p> <p><b>変更前</b></p> <p><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/f/fujjima/20210208/20210208121616.png" alt="f:id:fujjima:20210208121616p:plain" title="" class="hatena-fotolife" itemprop="image"></span></p> <p><b>変更後</b></p> <p><span itemscope itemtype="http://schema.org/Photograph"><img src="https://cdn-ak.f.st-hatena.com/images/fotolife/f/fujjima/20210208/20210208121722.png" alt="f:id:fujjima:20210208121722p:plain" title="" class="hatena-fotolife" itemprop="image"></span></p> <h3>タグ構造</h3> <p>Select周りの構造は下記の通りになっているとする。 今回「ここから〜ここまで」で囲まれている範囲のスタイルを変更することを目的とした。 該当部分のReact<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%B3%A5%F3%A5%DD%A1%BC%A5%CD%A5%F3%A5%C8">コンポーネント</a>も記載しているが、jsx用の<a class="keyword" href="http://d.hatena.ne.jp/keyword/%A5%B7%A5%F3%A5%BF%A5%C3%A5%AF%A5%B9">シンタックス</a>ハイライトを当てていないので、雰囲気でおなしゃす。</p> <pre class="code lang-html" data-lang="html" data-unlink> <span class="synIdentifier"><</span><span class="synStatement">div</span><span class="synIdentifier"> </span><span class="synType">class</span><span class="synIdentifier">=</span><span class="synConstant">"MuiInputBase-root MuiOutlinedInput-root makeStyles-statusMenu-16"</span><span class="synIdentifier">></span> <span class="synComment"><!-- ここから --></span> <span class="synIdentifier"><</span><span class="synStatement">div</span> <span class="synIdentifier"> </span><span class="synType">class</span><span class="synIdentifier">=</span><span class="synConstant">"MuiSelect-root MuiSelect-select MuiSelect-selectMenu MuiSelect-outlined MuiInputBase-input MuiOutlinedInput-input"</span> <span class="synIdentifier"> </span><span class="synType">tabindex</span><span class="synIdentifier">=</span><span class="synConstant">"0"</span> <span class="synIdentifier"> role=</span><span class="synConstant">"button"</span> <span class="synIdentifier"> aria-haspopup=</span><span class="synConstant">"listbox"</span> <span class="synIdentifier"> aria-labelledby=</span><span class="synConstant">"demo-simple-select-filled"</span> <span class="synIdentifier"> </span><span class="synType">id</span><span class="synIdentifier">=</span><span class="synConstant">"demo-simple-select-filled"</span> <span class="synIdentifier"> ></span> 未着手 <span class="synIdentifier"></</span><span class="synStatement">div</span><span class="synIdentifier">></span> <span class="synComment"><!-- ここまで --></span> <span class="synIdentifier"><</span><span class="synStatement">input</span> <span class="synIdentifier"> aria-</span><span class="synType">hidden</span><span class="synIdentifier">=</span><span class="synConstant">"true"</span> <span class="synIdentifier"> </span><span class="synType">tabindex</span><span class="synIdentifier">=</span><span class="synConstant">"-1"</span> <span class="synIdentifier"> </span><span class="synType">class</span><span class="synIdentifier">=</span><span class="synConstant">"MuiSelect-nativeInput"</span> <span class="synIdentifier"> </span><span class="synType">value</span><span class="synIdentifier">=</span><span class="synConstant">"waiting"</span> <span class="synIdentifier"> /><</span>svg <span class="synIdentifier"> </span><span class="synType">class</span><span class="synIdentifier">=</span><span class="synConstant">"MuiSvgIcon-root MuiSelect-icon MuiSelect-iconOutlined"</span> <span class="synIdentifier"> focusable=</span><span class="synConstant">"false"</span> <span class="synIdentifier"> viewBox=</span><span class="synConstant">"0 0 24 24"</span> <span class="synIdentifier"> aria-</span><span class="synType">hidden</span><span class="synIdentifier">=</span><span class="synConstant">"true"</span> <span class="synIdentifier"> ></span> <span class="synIdentifier"><</span>path<span class="synIdentifier"> d=</span><span class="synConstant">"M7 10l5 5 5-5z"</span><span class="synIdentifier">></</span>path<span class="synIdentifier">></span> <span class="synIdentifier"></</span>svg<span class="synIdentifier">></span> <span class="synIdentifier"><</span><span class="synStatement">fieldset</span> <span class="synIdentifier"> aria-</span><span class="synType">hidden</span><span class="synIdentifier">=</span><span class="synConstant">"true"</span> <span class="synIdentifier"> </span><span class="synType">class</span><span class="synIdentifier">=</span><span class="synConstant">"PrivateNotchedOutline-root-29 MuiOutlinedInput-notchedOutline"</span> <span class="synIdentifier"> </span><span class="synType">style</span><span class="synIdentifier">=</span><span class="synConstant">"padding-left: 8px"</span> <span class="synIdentifier"> ></span> <span class="synIdentifier"><</span><span class="synStatement">legend</span><span class="synIdentifier"> </span><span class="synType">class</span><span class="synIdentifier">=</span><span class="synConstant">"PrivateNotchedOutline-legend-30"</span><span class="synIdentifier"> </span><span class="synType">style</span><span class="synIdentifier">=</span><span class="synConstant">"width: 0.01px"</span><span class="synIdentifier">></span> <span class="synIdentifier"><</span><span class="synStatement">span</span><span class="synIdentifier">></span><200b><span class="synIdentifier"></</span><span class="synStatement">span</span><span class="synIdentifier">></span> <span class="synIdentifier"></</span><span class="synStatement">legend</span><span class="synIdentifier">></span> <span class="synIdentifier"></</span><span class="synStatement">fieldset</span><span class="synIdentifier">></span> <span class="synIdentifier"></</span><span class="synStatement">div</span><span class="synIdentifier">></span> </pre> <pre class="code lang-javascript" data-lang="javascript" data-unlink><Select id=<span class="synConstant">"demo-simple-select-filled"</span> value=<span class="synIdentifier">{</span>task.<span class="synStatement">status</span><span class="synIdentifier">}</span> variant=<span class="synConstant">"outlined"</span> className=<span class="synIdentifier">{</span>classes.statusMenu<span class="synIdentifier">}</span> > <MenuItem value=<span class="synConstant">"waiting"</span>>未着手</MenuItem> <MenuItem value=<span class="synConstant">"working"</span>>作業中</MenuItem> <MenuItem value=<span class="synConstant">"completed"</span>>完了</MenuItem> <MenuItem value=<span class="synConstant">"pending"</span>>保留</MenuItem> </Select> </pre> <h3>方法</h3> <p><code>MenuItem</code>のinput部分の<code>MuiOutlinedInput-input</code>に対してスタイルを設定する</p> <pre class="code lang-css" data-lang="css" data-unlink>statusMenu: <span class="synIdentifier">{</span> <span class="synConstant">'& .MuiOutlinedInput-input'</span>: { paddingBottom: <span class="synConstant">'7px'</span><span class="synSpecial">,</span> paddingTop: <span class="synConstant">'7px'</span><span class="synSpecial">,</span> <span class="synIdentifier">}</span><span class="synSpecial">,</span> <span class="synError">}</span><span class="synSpecial">,</span> </pre>