iSCSI 上に仮想イメージを導入し、ついでに Live Migration してみる
# virt-manager &








openssh-askpass-gnome
openssh-askpass
zypper addrepo https://download.opensuse.org/repositories/openSUSE:Leap:15.2:Update/standard/openSUSE:Leap:15.2:Update.repozypper refreshzypper install openssh-askpass-gnome
zypper addrepo https://download.opensuse.org/repositories/openSUSE:Backports:SLE-15-SP3/standard/openSUSE:Backports:SLE-15-SP3.repozypper refreshzypper install openssh-askpass
opensuse152:~ # rpm -qa openssh*openssh-askpass-1.2.4.1-bp153.1.3.x86_64openssh-askpass-gnome-7.6p1-7.13.x86_64openssh-helpers-7.6p1-7.8.x86_64openssh-7.6p1-7.8.x86_64opensuse152:~ #

2020年 12月 09日
openSUSE15.2 x86-64 環境でARMのクロスコンパイル
cross-arm-linux-gnueabi-gcc


zypper addrepo https://download.opensuse.org/repositories/home:duwe:crosstools2/openSUSE_Leap_15.2/home:duwe:crosstools2.repozypper refresh
# zypper install cross-arm-linux-gnueabi-gcc
# yast2 & もしくは# yast

opensuse152:~/test # ls /opt/cross/arm-linux-gnueabi -altotal 0drwxr-xr-x 1 root root 64 Dec 8 13:26 .drwxr-xr-x 1 root root 136 Nov 6 03:45 ..drwxr-xr-x 1 root root 92 Dec 6 20:20 bindrwxr-xr-x 1 root root 6 Dec 6 20:20 includedrwxr-xr-x 1 root root 532 Dec 6 20:20 lib
opensuse152:~/test # cat test.c#include <stdio.h>int main(){printf("Hello World\n");return(0);}
opensuse152:~/test # /opt/cross/bin/arm-linux-gnueabi-gcc -o armhello test.ctest.c:1:10: fatal error: stdio.h: No such file or directory1 | #include <stdio.h>| ^~~~~~~~~compilation terminated.opensuse152:~/test #
/opt/cross/arm-linux-gnueabi/include/c++/9.3.0/tr1/*
を
/opt/cross/arm-linux-gnueabi/include/c++/9.3.0/
cross-arm-linux-gnueabi-glibc


opensuse152:~/test # find /opt/cross/ -name "crt1.o"/opt/cross/arm-linux-gnueabi/sys-root/lib/crt1.oopensuse152:~/test #
opensuse152:~/test # /opt/cross/bin/arm-linux-gnueabi-c++ test.c -o testtest.c: In function ‘int main()’:test.c:4:2: error: ‘printf’ was not declared in this scope4 | printf("Hello World\n");| ^~~~~~test.c:2:1: note: ‘printf’ is defined in header ‘<cstdio>’; did you forget to ‘#include <cstdio>’?1 | #include <stdio.h>+++ |+#include <cstdio>2 | int main()opensuse152:~/test # ls -al test-rwxr-xr-x 1 root root 7976 Dec 8 13:33 testopensuse152:~/test #
opensuse152:~/test # file testtest: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-, for GNU/Linux 3.2.0, not strippedopensuse152:~/test #

openSUSE:Leap:15.2:Update プロジェクト提供の qemu-arm

opensuse152:~/test # qemu-system-arm --versionQEMU emulator version 4.2.1 (openSUSE Leap 15.2)Copyright (c) 2003-2019 Fabrice Bellard and the QEMU Project developersopensuse152:~/test #opensuse152:~/test # qemu-system-arm -M ?Supported machines are:akita Sharp SL-C1000 (Akita) PDA (PXA270)ast2500-evb Aspeed AST2500 EVB (ARM1176)ast2600-evb Aspeed AST2600 EVB (Cortex A7)borzoi Sharp SL-C3100 (Borzoi) PDA (PXA270)canon-a1100 Canon PowerShot A1100 IS:: 以下略:opensuse152:~/test #
29.2 General qemu-system-ARCH Options
qemu-system-arm • helpQEMU emulator version 2https://helpmanual.io/help/qemu-system-arm/
2020年 11月 20日
ARMに失敗した Windows RT、 ARM ベースから無事ラウンチした Apple M1


ARM 版 Windows 10
ARMへの移行で変わるMacの「仮想化」
- はじめに -
Docker は「コンテナ型の仮想化」言われればそれまでなのですが、 SUSE ではドキュメントも少なく、いまいち手が出なかった。だけど不思議なもので、どこかできっかけを掴むと、やってしまえるものですね。XEN から始めて KVM そして Docker です。切り口が分かれば、意外と簡単に入り込むことができました。
という事で SUSE Linux Enterprise 15 sp2(SLES15 sp2) に Docker を組み込んで nginx HTTP サーバーを動かしいてみよう、にチャレンジします。
SLE15 Linux Enterprise sp2 (SLES15sp2) のインストールとファーストルックhttps://islandcnt.exblog.jp/240410042/
- 参考文書 -
まずは、次の文書を読んでおきます。
openSUSE and SUSE Linux Enterprise
http://docs.docker.jp/engine/installation/SUSE.html
Docker Open Source Engine Guide SUSE Linux Enterprise Server 15 SP1
https://documentation.suse.com/sles/15-SP1/pdf/book-sles-docker_color_en.pdf
- /var/lib/docker を BtrFS の別パーティションに -
1 Docker Open Source Engine Overview REPORT DOCUMENTATION BUG#
このドキュメントに
"Important: Mounting /var/lib/dockerIt is recommended to have /var/lib/docker mounted on a separate partition or volume to not affect the Docker Open Source Engine host operating system in case of a file system corruption.In case you choose the Btrfs file system for /var/lib/docker, it is strongly recommended to create a subvolume for it. This ensures that the directory is excluded from file system snapshots. If not excluding /var/lib/docker from snapshots, the file system will likely run out of disk space soon after you start deploying containers. What's more, a rollback to a previous snapshot will also reset the Docker Open Source Engine database and images. Refer to Creating and Mounting New Subvolumes in Section 7.1, “Default Setup” for details."
とあり、/va/lib/docker は別パーティションで BtrFS 強く推奨とあります。事前に Docker を導入する以前にパーティションを YaST > System > Partitioner で別パーティション、別ボリュームを準備しておきます。
インストールの際の注意事項です。

sles15doker:~ # snapper -c dockersnap(<--任意のファイル名) create-config /var/lib/dockersles15docker:~ # ls /etc/snapper/configs/dockersnap -l-rw-r----- 1 root root 1183 Jun 28 17:08 /etc/snapper/configs/dockersnapsles15docker:~ #sles15docker:~ # ls /var/lib/docker/ -ltotal 0drwxr-x--- 1 root root 0 Jun 28 17:08 .snapshotsdrwx------ 1 root root 20 Jun 28 11:49 btrfsdrwx------ 1 root root 20 Jun 28 11:47 builderdrwx--x--x 1 root root 92 Jun 28 11:47 buildkitdrwx------ 1 root root 12 Jun 28 11:47 containerddrwx------ 1 root root 256 Jun 28 13:53 containersdrwx------ 1 root root 10 Jun 28 11:47 imagedrwxr-x--- 1 root root 10 Jun 28 11:47 networkdrwx------ 1 root root 20 Jun 28 11:47 pluginsdrwx------ 1 root root 0 Jun 28 05:39 runtimesdrwx------ 1 root root 0 Jun 28 11:47 swarmdrwx------ 1 root root 0 Jun 28 14:39 tmpdrwx------ 1 root root 0 Jun 28 11:47 trustdrwx------ 1 root root 22 Jun 28 11:47 volumessles15docker:~ #
SLES12 の Snapper のチューニング
SLES12 ext3 から BTrFS への変換
- Forward を有効に -
Docker は Windows の Windows Subsystem for Linux に似ています。と言うか WSL 自体が Docker の Windows 版なんですね。たぶん。Dockerをインストールすると仮想ブリッジが作られ、コンテナのインターフェースが物理インターフェースと通信できるよう、フォワードを有効にしておく必要があります。一応 KVM と Docker を同居させている猛者はいるようですが、設定が複雑になるので止めとけ、という事です。
因みに、ここでは SUSE on SUSE の KVM 環境なので、仮想サーバー上で Docker を動かすことは問題ないようです。
Forward を有効にするには、 YaST > System > Network Settings の Routing のチェックを入れるだけです。
全体の流れを動画にしました。盛大に音出ます。
openSUSE Leap 15x と SLES15 SPx では若干インストール方法が違います。本当は openSUSE Leap を使いたかったのですが、機嫌が悪かったので、「あって良かった安心強護の SUSE Linux Enterprise」(SLES15 sp2) を使いました。
openSUSE Leap ではリポジトリの追加は不要です。SLE15 の場合、今回はトライアル版なので、ローカルディスクに ISO ファイルをコピーして、YaST > Software > Software repositories より ADD で、Local iso イメージを指定しました。
追加プロダクトとして Containers Module をチェックします。
後は、Software Management より "Docker" をサーチしてチェック、インストールします。
- ユーザを Docker グループに
YaST > Security and Users > User and Group Management より、Docker 使いたいヒトビトを Docker グループに追加します。
- 自動起動を Enable に
YaST > System > Service Manager より Docker を Enable, Active をセットして Docker を起動します。
- hellow-world を run -
sles15sp2:~ # docker run hello-worldUnable to find image 'hello-world:latest' locallylatest: Pulling from library/hello-world0e03bdcc26d7: Pull completeDigest: sha256:d58e752213a51785838f9eed2b7a498ffa1cb3aa7f946dda11af39286c3db9a9Status: Downloaded newer image for hello-world:latestHello from Docker!This message shows that your installation appears to be working correctly.To generate this message, Docker took the following steps:1. The Docker client contacted the Docker daemon.2. The Docker daemon pulled the "hello-world" image from the Docker Hub.(amd64)3. The Docker daemon created a new container from that image which runs theexecutable that produces the output you are currently reading.4. The Docker daemon streamed that output to the Docker client, which sent itto your terminal.To try something more ambitious, you can run an Ubuntu container with:$ docker run -it ubuntu bashShare images, automate workflows, and more with a free Docker ID:https://hub.docker.com/For more examples and ideas, visit:https://docs.docker.com/get-started/sles15sp2:~ #
- YaST2-Docker -
YaST2-Docker アプリケーションは、openSUSE では問題ない様ですが、SLE ではちょっと問題があり、インストールはひと工夫必要です。必ず必要なものではないので読み飛ばしてもらって結構です。
まず yast2-metapackage-handler の rom をダウンロードして
YaST2 - Easy Installation of Add-on RPMs using Metapackages
perl-XML-XPath を YaST か zypper でインストールします。# zypper install perl-XML-XPath*
yast2-metapackage-handler を rpm でインストールします。
# rpm -ivh yast2-metapackage-handler-4.1.0-lp151.1.1.noarch.rpm
これで、YaST2-Docker を 1 Click インストールできるので、software.opensuse.com から1クリックインストールしました。 この辺りはトラブルの元です。SLE15 BACKPORT リポジトリだけ有効にすると良い様です。
yast2-dockerYaST2 - GUI for docker management
- YaST2 docker -
YaST2-Docker はこんな感じです。コンテナの停止、削除には使えます。が、docker run は使い方がよく分かりません。マニュアルも見当たらなかった。
- nginx HTTP を動かす -
nginx のコンテナパッケージはこちらにあります。docker pull して run させるだけです。
Docker Official Images Official build of Nginx.
sles15sp2:~ # docker pull nginxUsing default tag: latestlatest: Pulling from library/nginx8559a31e96f4: Pull complete8d69e59170f7: Pull complete3f9f1ec1d262: Pull completed1f5ff4f210d: Pull complete1e22bfa8652e: Pull completeDigest: sha256:21f32f6c08406306d822a0e6e8b7dc81f53f336570e852e25fbe1e3e3d0d0133Status: Downloaded newer image for nginx:latestdocker.io/library/nginx:latestsles15sp2:~ #
Docker run リファレンスhttp://docs.docker.jp/engine/reference/run.html
- コンテナ起動
sles15docker:~ # docker run -d -p 80:80 nginx
nginx が動きました。
- 起動時にコンテナを自動起動させる -
これでは Docker の親が起動した時、コンテナが起動できないので、--restart=always スイッチを付けて、コンテナを起動させると、 Docker サービスが起動する際に、自動起動するようになりました。
sles15docker:~ # docker run --restart=always -d -p 80:80 nginxca5d8b4b8adc55dc352f6022ef70da93ab243449cfc35d2cd2bd0903e7bd4c42- 動作中のコンテナの確認sles15docker:~ # docker ps -aCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES3485ddc43916 nginx /docker-entrypoint.…" 3 minutes ago Exited (0) 2 minutes ago affectionate_clarkead88906a4cf0 hello-world /hello" 2 hours ago Exited (0) 2 hours ago agitated_perlman
<-- 只今停止中、停止しないと削除できない。
- 停止中のコンテナを削除
sles15docker:~ # docker rm 34853485sles15docker:~ # docker ps -aCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMESad88906a4cf0 hello-world /hello" 2 hours ago Exited (0) 2 hours ago agitated_perlman
<-- 消してみた
- 常時起動状態で起動
sles15docker:~ # docker run --restart=always -d -p 80:80 nginxcd43c374894d21a357a7835df7af11e1e59f51c11919c395d6a91cfe78da9d78
sles15docker:~ # docker ps -aCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMEScd43c374894d nginx "/docker-entrypoint.…" 8 seconds ago Up 5 seconds 0.0.0.0:80->80/tcp optimistic_chateletad88906a4cf0 hello-world "/hello" 2 hours ago Exited (0) 2 hours ago agitated_perlman
<-- --restart=always を付けて起動(Up)
- 稼働中のコンテナを停止
sles15docker:~ # docker stop cd43cd43sles15docker:~ # docker ps -aCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMEScd43c374894d nginx "/docker-entrypoint.…" 35 seconds ago Exited (0) 3 seconds ago optimistic_chateletad88906a4cf0 hello-world "/hello" 2 hours ago Exited (0) 2 hours ago agitated_perlmansles15docker:~ #
<--- コンテナを止めておく(Exited)
- docker deamon を再起動
sles15docker:~ # systemctl stop docker
sles15docker:~ # docker ps -aCannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?
sles15docker:~ # systemctl start docker- docker コンテナがデーモン起動で UP になった。
sles15docker:~ # docker ps -aCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMEScd43c374894d nginx /docker-entrypoint.…" About a minute ago Up 2 seconds 0.0.0.0:80->80/tcp optimistic_chateletad88906a4cf0 hello-world /hello" 2 hours ago Exited (0) 2 hours ago agitated_perlmansles15docker:~ #
<--- 止めたコンテナがサービス起動とともに開始した。
- その他 -
A Visual Way to Play with DockerHands on with Docker, openSUSE Leap 15
- まとめ -
Docker そのもののインストールや基本操作で理解できました。後は例えば nginx を使う場合の詳細な設定をどうするか、とか、自らコンテナを開発したりカスタマイズするにはどうするか、と言った問題があります。知るほどに置くが深そうですね。
食わず嫌いは良くない。
2019年 06月 19日
openSUSE Leap 15.1 で初めての KVM, 仮想化
いきなりですが、私は openSUSE Leapで「サーバールームのハイパーバイザーで本格運用」することはお勧めしません。 本格運用で使うなら、 SUSE Linux Enterprise(SLES) での運用を強くお勧めします。
SUSE Linux 15 (SLES15) でKVM/XEN仮想環境 https://islandcnt.exblog.jp/238685530/ KVM on SUSE(SLES12) で仮想インスタンスの作成 https://islandcnt.exblog.jp/238578664/ Windows 2019 Server を SUSE Linux 15 (SLES15)+KVM で仮想ドライバを使って最適な仮想化 https://islandcnt.exblog.jp/239122369/
しかし、今スグここで「KVMのテスト、開発環境が必要になった」のであれば、openSUSE Leap は Hyper-V と比較しても一つの良い選択です。軽いですし安定しています。何しろ無料でハイパーバイザーが手に入る気軽さ。LibreOffice も付いて GIMP も標準なので、そのまま仕事ができる。 いきなりステーキ!、じゃないな、いきなり SLES 15(SUSE Linux Enterprise Server) では、敷居も高いし、openSUSE と違いインストールが異なりちょっと面倒です。 何しろ SLE(SUSE Linux Enterprise) 譲りで SLES の鉄壁の信頼性を引き継ぐ openSUSE 上であり、openSUSE <---> SLES との相互運用性も高いので - テストと開発は : openSUSE で取り合えず開発し - 本番運用は : SUSE Linux Enterprise にマイグレーション という選択肢は十分に魅力的です。 ここでは無料で作れる openSUSE Leap 15.1 で KVM ハイパーバイザーの導入手順を説明します。 ここでは前提条件として
- openSUSE はインストール済とする。 - /var は仮想ディスクイメージを格納します。別パーティションとします。 - 固定IPでセットアップ済
とします。openSUSE Leap 15.1 のセットアップはこちらの記事を参考にしてください。
openSUSE Leap 15.1 インストール https://islandcnt.exblog.jp/239244204/
※ 画面のキャプチャは英語ですが、優先言語を日本語にすると root 以外のユーザは、全て日本語表記になります。
固定IPを設定するため、ネットワークの設定は openSUSE15.1 標準の Network-Manager ではなく Wicked にします。 YaST > Network Settings より、設定方法を "Wicked", 必要な固定IPを設定します。
仮想ディスクイメージは /var/lib/libvirt/images/ にデフォルトで作成されます。勿論、VM を create する時に、任意のディレクトリを指定できます。ここではデフォルトのルールに則って、 / パーティションは必要最低限、空きスペースの全てを /var を別パーティションに割り当てました。 ライブマイグレーションするなら iSCSI マウントできる NAS 上に作成するのも良いでしょう。 ※ ヒント 32Gb 程度の USB メモリに / パーティションをインストールしてライブUSB起動して、QNAP などの iSCSI NAS 上に仮想イメージを作るのも一案です。既存のPC環境を壊したくないのであれば、一つの手段ですね。 PR 楽天でQNAP の NAS を検索
openSUSE Leap 15.1 の Live USB で「どこでも Linux」の作り方
YaST > Software Management > View > Patterns より KVM Virtuialization Host and Tools をチェックします。 ここをチェックする事で、必要な殆どのパッケージがインストールされます。ここでは KVM をチェックしていますが、 XEN ハイパーバイザーもここで導入します。KVM と XEN はどちらか一択の排他関係です。一旦、システムを再起動すると KVM ハイパーバイザーが起動します。
KVMの必要なパッケージをインストールしたら、YaST > Virtualization > Install Hypervisor and Tools を開き、 Libvirt LXC containers をチェックします。
ネットワークブリッジを設定するかどうかは、 Yes YaST > System > Network Settings から、ブリッジインターフェースが設定されている事を確認します。 # virt-manager & を実行して、KVM仮想インスタンスが作成できる事を確認します。

ここまでの手順を動画でまとめました。(音出ます)
仮想VMインスタンスが立ち上がりました。

2019年 06月 05日
SUSE linux15 virt-manager が起動できない
いきなり結論です。virt-manager は二重起動できません。
xterm から virt-manager GUI が起動できない。実行すると[1]+ Done するが、GUI が上がってこない。
どこかのバカ(つまりオレ、もしくはワタクシ、たまにワシ)が、コンソールの Xターミナルから "# virt-manager &" して virt-manager を起動したまま、トイレに行ったついでに昼飯を食いに行って、お腹がが痛くなったのでそのまま帰ってこなかった。次の日の朝、頭をリセットした別な奴(ワタクシの別人2号)が、movaXterm の様な別なX端末から# virt-manager &したところ[1]+ Done virt-manager となるけれども、virt-manager GUI が起動出来なかった。あれれ?
どこかのバカ(くどいけどワタクシもしくは私)がそれに気が付いて、バカな自分ふるまいを思い出してリモート端末から virt-manager を終了させるか、ワタクシの別人二号が virt-manager のプロセスを kill すれば解決できる。# ps ax |grep virt-managerして”/usr/bin/python3 /usr/share/virt-manager/virt-manager” のプロセス番号を kill したら、問題なく動作した。sles15:~ # ps ax | grep virt-manager2275 ? Ssl 0:00 /usr/bin/python3 /usr/share/virt-manager/virt-manager <-- 残っている2295 pts/10 S+ 0:00 grep --color=auto virt-managersles15:~ #sles15:~ # kill 2275sles15:~ #sles15:~ # ps ax | grep virt-manager2325 pts/10 S+ 0:00 grep --color=auto virt-managersles15:~ #sles15:~ # virt-manager &[1] 2330sles15:~ #[1]+ Done virt-managersles15:~ # どうやら起動できた様だ。
GUIのソフトウェアを、同じユーザ名でログオンした状態で起動すると、拒否られる事があります。コンソールからroot で GUI ログオンしたまま。リモートX端末からアプリケーションをコマンドライン起動すると、ターミナル側で起動せずコンソールでGUI が起動してしまった。という笑い話もありました。gedit & って実行して、おっかしいなぁと思ったら、コンソールで起動していたとか......いや、笑い話ならまだしも、実際、movaXterm でリモートから# startx &なんてやってしまうと、実に面白い結果になります。コンソールでXが起動してしまう。閉じるには、実際コンソールに行かなければならない。つまり、root でのログインはどこか一つの端末で行って、いつでもどこでもログオンしまくるなよ、という事ですね。仕事が終わったら必ず logout する。初心者に限らずワタシの様なズボラな人間が陥りやすい罠です。ひどく当たり前な事でも、判っていなければやっぱりやっちゃう。ダメ人間別人1号です。水曜どうでしょう名セリフステッカー-ダメ人間
SUSE Linux Enterprise Virtual Machine Driver PackFAQに"有効なSUSE Linux Enterprise Serverサブスクリプションをお持ちのお客様には、これらの並行仮想化ドライバの保守およびサポートの使用権が自動的に付与されます。ドライバのサポート契約は、お客様が契約しているSUSE Linux Enterprise Serverサブスクリプションから継承されます。"
サブスクリプションの購入はこちら
SUSE Linux Enterprise Virtual Machine Driver Pack 2.5
SUSE Linux で XEN から KVM へ移行、VMDP はこんなに簡単
Windows Server 2019 on SUSE Linux 15 with VMDP + KVM install (仮想化インストール)





※ なお、ディレクトリはこのダイアログでは作成できないため、事前に# mkdir "仮想VM名"しておくと良いでしょう。




※ qcow2 形式は、指定したディスク容量より小さく、容量を節約できますが、一般に書き込み動作が低速で重い、と言われています。また、データの使い方によっては、それほど、効率が良くないようです。例えば一発デフラグすると、あっという間に容量を使い切ってしまうという事が起こりえます。システムドライブイメージでは初めから容量確保されて安定して高速な "raw" フォーマットの方が良いと思います。データドライブ、パーティションは qcow2 形式を選択する場合もありますが、データドライブは別メディア、例えば iSCSI SAN ストレージを使った方がベターです。







※VMDP はアンインストールしたり再インストールする場合があるので、C: ドライブの任意のフォルダにコピーしておくと良いでしょう。









2018年 06月 13日
KVM on SUSE(SLES12) で仮想インスタンスの作成
ここでは SUSE Linux Enterprise Server(SLES12) で仮想マシンを作成する手順を説明します。











マニュアルはこちらSUSE Linux Enterprise Server 12 SP3 Virtualization Guide
Windows 2019 Server を SUSE Linux 15 (SLES15)+KVM で仮想ドライバを使って最適な仮想化SUSE linux15 virt-manager が起動できないサブスクリプション購入はこちら
2017年 08月 08日
役割を終えた XEN , Citrix と XenServer が過去形となる日
2017年 07月 15日
Zabbix3.2 のソフトウェアアプライアンスUbuntu 版をSUSE 仮想環境で試してみた。
SUSE Studio から Zabbix 管理ツールの導入
How to setup zabbix4.2 on openSUSE Leap 15.1Zabbix4.2 snmp デバイスのグラフを表示させるまで
DownloadZabbix appliance Documets





######## ### ######## ######## #### ## #### ## ## ## ## ## ## ## ## #### ## ## ## ## ## ## ## ## #### ## ## ######## ######## ## ##### ######### ## ## ## ## ## ## #### ## ## ## ## ## ## ## ## ########## ## ## ######## ######## #### ## ##


