- 投稿日:2019-06-27T21:57:29+09:00
量子アルゴリズムの基本:算術演算の確認(加算)
$$
\def\bra#1{\mathinner{\left\langle{#1}\right|}}
\def\ket#1{\mathinner{\left|{#1}\right\rangle}}
\def\braket#1#2{\mathinner{\left\langle{#1}\middle|#2\right\rangle}}
$$はじめに
前々回の記事で「量子フーリエ変換」、前回の記事で「位相推定アルゴリズム」の確認ができたので、次は「Shorのアルゴリズム」と思っていたら、「べき剰余」も必要なのでした。で、べき剰余を実行するためには、いくつかの算術演算の基礎も必要ということなので、以後しばらくは、算術演算を順に確認していこうと思います。今回はもっとも簡単な「加算」です。アルゴリズムを説明した後、自作の量子計算シミュレータqlazyで、動作の確認をします。
参考にさせていただいた論文・記事は以下の通りです。
- V. Vedral,A. Barenco,A. Ekert; "Quantum Networks for Elementary Arithmetic Operations" (arXiv:quant-ph/9511018)
- 量子コンピュータ(シミュレータ)でモジュール化可能な加算器を作る
加算の実現方法
参考論文に全体の回路図が出ているので、まずそれを掲載します。
論文には、
\ket{a,b} \rightarrow \ket{a,a+b}を計算する回路と説明されています。ここで、$a_0,a_1,...$と$b_0,b_1,...$は、整数$a,b$を2進数で表したときの各桁の値{0,1}を下の桁から順に並べた数列です。$c_0,c_1,...$は、各桁を加算したときに発生する桁上げ情報を格納するための補助量子ビットです。また、CARRYとSUMと書いてあるボックスは各々以下のような量子回路で定義されます。
これで本当に加算が実現できるのでしょうか。まずは各部品(CARRYとSUM)の動作から地道に見ていくことにします。
CARRYの動作
CARRYの量子レジスタは4つあり、1つのCNOTゲートと2つのToffoliゲートから構成されています。入力状態を上から$\ket{x},\ket{y},\ket{z},\ket{w}$としたとき、最初のToffoliゲート、CNOTゲート、2番目のToffoliゲートを通っていくに従い、どのように状態が変化するかを以下の表に示してみます。
初期状態 Toffoli[1] CNOT Toffoli[2] $x$ $x$ $x$ $x$ $y$ $y$ $y$ $y$ $z$ $z$ $y \oplus z$ $y \oplus z$ $w$ $(yz) \oplus w$ $(yz) \oplus w$ $(xy \oplus yz \oplus zx) \oplus w$ 最終的に$x,y$のレジスタは変化せず、$z$のレジスタには$y,z$の加算(ただしmod 2)が入り、一番下のレジスタは、
\ket{w} \rightarrow \ket{(xy \oplus yz \oplus zx) \oplus w}となることがわかります。ここで、$(xy \oplus yz \oplus zx)$は、$x,y,z$のどれか2つ以上が1をとるときに1になり、そうでない場合0になります。ということは、$x,y,z$を全部足した結果、桁上げがある場合、$\ket{1 \oplus w}$、桁上げがない場合$\ket{0 \oplus w}$となりますので、一番下のレジスタは桁上げを表していると言えそうです。
改めて全体の回路図を見てみてください。CARRYの入力レジスタの状態は$c_{i},a_{i},b_{i},c_{i+1}$となっていますので、$a$と$b$の$i$番目の桁を足して、さらに$i-1$番目までの桁から来る桁上げの値(0または1)を足したものが、$c_{i+1}$のレジスタに入ります。どうでしょう。加算の桁上げの役割を果たしているような気がしてきますよね。
後の議論のため、上の表の記号を$x,y,z,w$ではなく、$c_{i},a_{i},b_{i},c_{i+1}$に変えて記載しておきます。
初期状態 Toffoli[1] CNOT Toffoli[2] $c_{i}$ $c_{i}$ $c_{i}$ $c_{i}$ $a_{i}$ $a_{i}$ $a_{i}$ $a_{i}$ $b_{i}$ $b_{i}$ $a_{i} \oplus b_{i}$ $a_{i} \oplus b_{i}$ $c_{i+1}$ $(a_{i}b_{i}) \oplus c_{i+1}$ $(a_{i}b_{i}) \oplus c_{i+1}$ $c_{i+1}^{\prime}$ ここで、
c_{i+1}^{\prime} = (c_{i}a_{i} \oplus a_{i}b_{i} \oplus b_{i}c_{i}) \oplus c_{i+1}とおきました。つまり、$c_{i}^{\prime}$は下の桁からやってくる桁上げの値を表しています。
ついでに、CARRYの逆演算(以下i-CARRYと呼ぶことにします)も見てみましょう。上の表を逆から読むだけです。
初期状態 Toffoli[2] CNOT Toffoli[1] $c_{i}$ $c_{i}$ $c_{i}$ $c_{i}$ $a_{i}$ $a_{i}$ $a_{i}$ $a_{i}$ $a_{i} \oplus b_{i}$ $a_{i} \oplus b_{i}$ $b_{i}$ $b_{i}$ $c_{i}^{\prime}$ $(a_{i}b_{i}) \oplus c_{i+1}$ $(a_{i}b_{i}) \oplus c_{i+1}$ $c_{i+1}$ となります。
SUMの動作
SUMは簡単です。3つの量子レジスタに対する入力を$c_{i},a_{i},b_{i}$とすると、量子状態は以下のように変化します。
初期状態 CNOT[1] CNOT[2] $c_{i}$ $c_{i}$ $c_{i}$ $a_{i}$ $a_{i}$ $a_{i}$ $b_{i}$ $a_{i} \oplus b_{i}$ $a_{i} \oplus b_{i} \oplus c_{i}$ ということで、$b_{i}$のレジスタに下の桁の桁上げも含めた加算(ただしmod 2)の結果が入ることがわかります。つまり、SUMは各桁の加算を表しています。
1量子ビットの加算
部品の動作が確認できたところで、これを組み合わせて本当に$a+b$が実行できるかを、具体的に確認してみます。まずは1量子ビットの場合です。全体の回路図を参照すると、$a,b$各々の入力が1量子ビットの場合は、以下のような回路になります。
c0=0 ---|C||------|S||--- c0=0 a0 ---|A||--*---|U||--- a0 b0 ---|R||--CX--|M||--- b0 c1=0 ---|R||------------- b1各部品の動作を表す上の表を参照しながら、この回路での状態変化を表にすると、
初期状態 CARRY CNOT SUM $c_{0}=0$ $c_{0}=0$ $c_{0}=0$ $c_{0}=0$ $a_{0}$ $a_{0}$ $a_{0}$ $a_{0}$ $b_{0}$ $a_{0} \oplus b_{0}$ $b_{0}$ $a_{0} \oplus b_{0}$ $c_{1}=0$ $c_{1}^{\prime}$ $c_{1}^{\prime}$ $c_{1}^{\prime} = b_{1}$ となります。この最終状態でレジスタ($b_{0},b_{1}$)を観測すると、ちょうど$a+b$を実行した結果に等しくなることがわかると思います(ここで$b_{0}$は下位、$b_{1}$は上位ビットを表します。この加算回路では補助量子ビット$c$の最上位を$b$の最上位ビットと同一視するようにしています)。
2量子ビットの加算
次に、2量子ビットです。回路図は、以下の通りです。
c0=0 --|C||------------------||C|--|S||-- c0=0 a0 --|A||------------------||A|--|U||-- a0 b0 --|R||------------------||R|--|M||-- b0 c1=0 --|R||--|C||------|S||--||R|-------- c1=0 a1 --------|A||--*---|U||-------------- a1 b1 --------|R||--CX--|M||-------------- b1 c2=0 --------|R||------------------------ b2先程と同様に、状態変化を表にしてみます。
初期状態 1番目のCARRY 2番目のCARRY CNOT 1番目のSUM i-CARRY 2番目のSUM $c_{0}=0$ $c_{0}$ $c_{0}$ $c_{0}$ $c_{0}$ $c_{0}$ $c_{0}=0$ $a_{0}$ $a_{0}$ $a_{0}$ $a_{0}$ $a_{0}$ $a_{0}$ $a_{0}$ $b_{0}$ $a_{0} \oplus b_{0}$ $a_{0} \oplus b_{0}$ $a_{0} \oplus b_{0}$ $a_{0} \oplus b_{0}$ $b_{0}$ $a_{0} \oplus b_{0}$ $c_{1}=0$ $c_{1}^{\prime}$ $c_{1}^{\prime}$ $c_{1}^{\prime}$ $c_{1}^{\prime}$ $c_{1}$ $c_{1}=0$ $a_{1}$ $a_{1}$ $a_{1}$ $a_{1}$ $a_{1}$ $a_{1}$ $a_{1}$ $b_{1}$ $b_{1}$ $a_{1} \oplus b_{1}$ $b_{1}$ $c_{1}^{\prime} \oplus a_{1} \oplus b_{1}$ $c_{1}^{\prime} \oplus a_{1} \oplus b_{1}$ $c_{1}^{\prime} \oplus a_{1} \oplus b_{1}$ $c_{2}=0$ $c_{2}$ $c_{2}^{\prime}$ $c_{2}^{\prime}$ $c_{2}^{\prime}$ $c_{2}^{\prime}$ $c_{2}^{\prime}=b_{2}$ となります。この最終状態でレジスタ($b_{0},b_{1},b_{2}$)を観測すると、ちょうど$a+b$を実行した結果に等しくなることがわかります。
N量子ビットの加算
3量子ビット以上の場合は、上の議論を延長してちょっと考えてみれば、確かに足し算を実行していることがわかります(2進数の足し算を筆算でやることを頭の中でイメージしていただければ、わかりやすいと思います)。
シミュレータで動作確認
重ね合わせ無し
さて、それではシミュレータで、この加算の動作を確認してみます。まず、重ね合わせがない一つの純粋状態を入力した場合です。全体のPythonコードは以下の通りです。
from qlazypy import QState def sum(self,q0,q1,q2): self.cx(q1,q2).cx(q0,q2) return self def carry(self,q0,q1,q2,q3): self.ccx(q1,q2,q3).cx(q1,q2).ccx(q0,q2,q3) return self def i_carry(self,q0,q1,q2,q3): self.ccx(q0,q2,q3).cx(q1,q2).ccx(q1,q2,q3) return self def plain_adder(self,id_a,id_b,id_c): depth = len(id_a) for i in range(depth): self.carry(id_c[i],id_a[i],id_b[i],id_c[i+1]) self.cx(id_a[depth-1],id_b[depth-1]) self.sum(id_c[depth-1],id_a[depth-1],id_b[depth-1]) for i in reversed(range(depth-1)): self.i_carry(id_c[i],id_a[i],id_b[i],id_c[i+1]) self.sum(id_c[i],id_a[i],id_b[i]) return self def encode(self,decimal,id): for i in range(len(id)): if (decimal>>i)%2 == 1: self.x(id[i]) return self def decode(self,id): iid = id[::-1] return self.m(id=iid,shots=1).lst def create_register(digits): num = 0 id_a = [i for i in range(digits)] num += len(id_a) id_b = [i+num for i in range(digits+1)] num += len(id_b) id_c = [i+num for i in range(digits+1)] id_c[digits] = id_b[digits] # share the qubit id's num += (len(id_c)-1) return (num,id_a,id_b,id_c) if __name__ == '__main__': # add metthods QState.encode = encode QState.decode = decode QState.sum = sum QState.carry = carry QState.i_carry = i_carry QState.plain_adder = plain_adder # create registers digits = 4 num,id_a,id_b,id_c = create_register(digits) # set input numbers a_list = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15] b = 12 for a in a_list: # initialize quantum state qs = QState(num) qs.encode(a,id_a) qs.encode(b,id_b) # execute plain adder qs.plain_adder(id_a,id_b,id_c) res = qs.decode(id_b) print("{0:}+{1:} -> {2:}".format(a,b,res)) qs.free()何をやっているか簡単に説明します。
def sum(self,q0,q1,q2): self.cx(q1,q2).cx(q0,q2) return self def carry(self,q0,q1,q2,q3): self.ccx(q1,q2,q3).cx(q1,q2).ccx(q0,q2,q3) return self def i_carry(self,q0,q1,q2,q3): self.ccx(q0,q2,q3).cx(q1,q2).ccx(q1,q2,q3) return selfで、上で説明したCARRY,i-CARRY,SUMの動作を関数として定義しています。QStateクラスのメソッドとして動的追加することを想定し、第1引数をselfにしています。
def plain_adder(self,id_a,id_b,id_c): depth = len(id_a) for i in range(depth): self.carry(id_c[i],id_a[i],id_b[i],id_c[i+1]) self.cx(id_a[depth-1],id_b[depth-1]) self.sum(id_c[depth-1],id_a[depth-1],id_b[depth-1]) for i in reversed(range(depth-1)): self.i_carry(id_c[i],id_a[i],id_b[i],id_c[i+1]) self.sum(id_c[i],id_a[i],id_b[i]) return selfで、それら部品関数を組み合わせた加算器をplain_adder関数として定義しています。これも、QStateクラスのメソッドとして動的追加するため、第1引数はselfです。第2引数以降のid_a,id_b,id_cはそれぞれa,b,cに対応した量子レジスタ番号のリストを表しています(量子レジスタの生成は別の関数create_registerで行います)。関数内部の処理は、上で説明した回路図そのものです。
def encode(self,decimal,id): for i in range(len(id)): if (decimal>>i)%2 == 1: self.x(id[i]) return selfは、入力量子ビットを設定する関数です。decimalという10進整数を、量子レジスタidに設定します(つまり、量子レジスタidを$\ket{desimal}$という状態にします)。関数内部では、decimalを2進数に直してビットが立っている桁に相当する量子レジスタのビットをXゲートで反転しています。
def decode(self,id): iid = id[::-1] return self.m(id=iid,shots=1).lstは、encodeと逆に最終状態の量子レジスタidを観測して得られた{0,1}系列から10進整数を構成してリターンします。idに相当する量子ビットだけを1回観測し、lstプロパティによってその結果(10進整数)を得ています。
def create_register(digits): num = 0 id_a = [i for i in range(digits)] num += len(id_a) id_b = [i+num for i in range(digits+1)] num += len(id_b) id_c = [i+num for i in range(digits+1)] id_c[digits] = id_b[digits] # share the qubit id's num += (len(id_c)-1) return (num,id_a,id_b,id_c)は、今回の量子レジスタの配置を決めてそのリストおよび全体で必要となる量子ビット数をリターンする関数です。digitsは入力として想定するビット数です。
一連の関数が定義できたところで、プログラムのmain部を見ていきます。まず、
QState.encode = encode QState.decode = decode QState.sum = sum QState.carry = carry QState.i_carry = i_carry QState.plain_adder = plain_adderで、上で定義した関数を、QStateクラスのメソッドとして追加しています。
digits = 4 num,id_a,id_b,id_c = create_register(digits)で、量子レジスタを決定して変数num,id_a,id_b,id_cに格納しています。量子計算(加算)の実体部分は以下です。
# set input numbers a_list = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15] b = 12 for a in a_list: # initialize quantum state qs = QState(num) qs.encode(a,id_a) qs.encode(b,id_b) # execute plain adder qs.plain_adder(id_a,id_b,id_c) res = qs.decode(id_b) print("{0:}+{1:} -> {2:}".format(a,b,res)) qs.free()量子ビット数はdigit=4と設定してあるので、4ビット同士の加算を実行します。ここでは、aの値を0から15まで変化させながら、固定値b=12との足し算結果を表示します。
実行結果を以下に示します。
0+12 -> 12 1+12 -> 13 2+12 -> 14 3+12 -> 15 4+12 -> 16 5+12 -> 17 6+12 -> 18 7+12 -> 19 8+12 -> 20 9+12 -> 21 10+12 -> 22 11+12 -> 23 12+12 -> 24 13+12 -> 25 14+12 -> 26 15+12 -> 27というわけで、正しく計算できることがわかりました。
重ね合わせ有り
さて、上に示したように逐次実行するのは、実は、あまり賢いやり方ではありません。量子計算では、入力値を量子重ね合わせとして用意しておけば、逐次的にぐるぐるforループを回さなくても、多数の入力値を一気に計算することができます。というわけで、やってみます。
まず、先程のencode関数の代わりに、
def superposition(self,id): for i in range(len(id)): self.h(id[i]) return selfという、入力状態を重ね合わせとして用意する関数superpositionを定義します。内部では引数として指定した量子レジスタのすべてに対してアダマールをかけています。入力が重ね合わせなので、出力も重ね合わせになります。そこから結果を引き出す関数も必要になるので、以下のように定義します。
def result(self,id_a,id_b): # measurement id_ab = id_a + id_b iid_ab = id_ab[::-1] freq = self.m(id=iid_ab).frq # set results a_list = [] r_list = [] for i in range(len(freq)): if freq[i] > 0: a_list.append(i%(2**len(id_a))) r_list.append(i>>len(id_a)) return (a_list,r_list)プログラムのmain部は以下のようになります。「重ね合わせなし」の場合との違いに注目してください。forループがないですよね。先程は15回、量子状態を初期化して量子計算をぐるぐると実行しましたが、今回は1回しか実行していません。
if __name__ == '__main__': # add methods QState.encode = encode QState.decode = decode QState.sum = sum QState.carry = carry QState.i_carry = i_carry QState.plain_adder = plain_adder # add methods (for superposition) QState.superposition = superposition QState.result = result # create registers digits = 4 num,id_a,id_b,id_c = create_register(digits) # set input numbers b = 12 # initialize quantum state qs = QState(num) qs.superposition(id_a) # set superposition of |0>,|1>,..,|15> for |a> qs.encode(b,id_b) # execute plain adder qs.plain_adder(id_a,id_b,id_c) a_list,r_list = qs.result(id_a,id_b) for i in range(len(a_list)): print("{0:}+{1:} -> {2:}".format(a_list[i],b,r_list[i])) qs.free()結果は以下の通りです。
0+12 -> 12 1+12 -> 13 2+12 -> 14 3+12 -> 15 4+12 -> 16 5+12 -> 17 6+12 -> 18 7+12 -> 19 8+12 -> 20 9+12 -> 21 10+12 -> 22 11+12 -> 23 12+12 -> 24 13+12 -> 25 14+12 -> 26 15+12 -> 27というわけで、4ビットのaの値すべてに対して一気に加算が実行できました。めでたしめでたし、と言いたいところですが、注意しておきたいことが一つあります。一気に結果が表示できるように見せかけていますが、これはシミュレータだからできることでありまして、実際の量子コンピュータでは、こんなことはできません。最終的な量子状態に対して測定をしたらば、基本一つの結果しか得られません。例えば"5+12->17"でした、という結果です。すべての加算結果を得るためには、やはり何度も何度も入力状態を用意して測定する必要があります。「なーんだ、量子コンピュータ、速くないじゃん」と思われるかもしれませんが、この例の場合は、確かにその通りかもしれません。
実際の量子計算では、求めたい結果に相当する状態の確率がなるべく高くなるように量子回路を構成し最後に測定することで、何度も計算実行しなくても、欲しい結果を効率よく得られるようにしています。量子アルゴリズムがこれまでにいろいろと提案されていますが、ざっくり言うと、要はそういうことをやっているわけです。
おわりに
今回、算術演算の中でもっとも簡単な「加算」の動作を確認しました。「Shorのアルゴリズム」で必要になる「べき剰余」に至るまで、あと何ステップかありますが、参考論文に従い、以後、順に確認していこうと思います。具体的には「剰余加算」→「制御剰余乗算」→「べき剰余」を予定しています。果たして最終ゴールまでたどり着けるかどうか...。ちょっとドキドキしてきましたが、何とか(できるところまでかもしれませんが)頑張ってみたいと思います。
以上
- 投稿日:2019-06-27T21:29:17+09:00
OCI Compute/DatabaseでVNCを構成する Part 2
前回の続き
前回から続いた内容なので、6から始まる連続した段落番号をつけている。
6. ポートフォワーディングを設定する
前回「OCI Compute/DatabaseでVNCを構成する Part 1」は、Linuxサーバ側の設定を行った。ここからはWindowsクライアント側の設定を行う。
以下の接続形態の中で、1と2ではポートフォワーディングが必要になる。また3のときでも、通信を暗号化したいときや、途中に踏み台があるときはポートフォワーディングが必要だ。
- インターネット経由(踏み台なし)
- インターネット経由(踏み台あり)
- 専用線/インターネットVPN
6-1. ポートフォワーディングとは
SSHポートフォワーディングは、SSHトンネリングとも呼ばれ、特定のポートに届いたパケットを別ホストの別ポートに転送する機能である。
たとえばHTTP(80)やSQL*Net(1521)は、それぞれ決められたポートを使用する。SSHポートフォワーディングを使用すると、通常使用するポートではなく、SSH(22)の経路を利用して疎通できる。
そのためSSHしか疎通できないネットワークでも、追加でポートを開けることなしに、さまざまなアプリケーションを利用できる。
おもなメリットは以下のとおり。
- 必要最低限のポートを開ければよい
- 暗号化通信に対応していないソフトウェアのパケットも、SSHの機能で暗号化できる
- パスワードログインを前提としているソフトウェアも、SSH公開鍵認証方式を利用できる
- SSHログインしているホストよりも、さらに先のホストにも転送できる。そのため踏み台サーバが前提の環境にも対応できる
6-2. ポートフォワーディングの仕組みを理解する
ポートフォワーディングには、さまざまな方式がある。今回はローカルポートフォワーディングについて、2つの例を説明する。
ポートフォワーディング例1(ログインホストと転送先ホストが同じ場合)
一番基本的なポートフォワーディングの利用例である。
リモートホスト上で稼働するWebサーバに接続するときは、上図のようにポートフォワーディングを設定する。ローカルホスト上のWebブラウザのURIに
http://localhost:80
と入力する。httpリクエストはsshの22番ポートを経由してリモートホストの80番ポートに転送され、Webページを表示できる。OpenSSHのシンタックスは以下のとおり。PuTTYやTera Termでは少し指定方法は違うが、このことを理解していることは重要なので理解しておくこと。
ssh -L [ローカルホストの待ち受けIP:]転送元ポート:転送先ホスト:転送先ポート ログインホスト
# 基本。ローカルホストの待ち受けIPは省略可能。 ssh -L 80:hostb:80 hostb # 「転送先ホスト」は、ログインホストからの相対的な位置になる。 # この例のようにlocalhostと書いても、hostbと同じ意味になる。 ssh -L 80:localhost:80 hostb # 転送先ポートは、転送先ホストで稼働するソフトウェアに一致させる # 必要がある。しかしローカルホストの転送元ポートは、利用していない # ポートならば何でもよい。 ssh -L 8080:hostb:80 hostbポートフォワーディング例2(ログインホストと転送先ホストが異なる場合)
応用編としては以下の構成も可能である。ログインホストと転送先ホストが異なる例だ。
この方式で直接ログインするのは、中間にあるログインホスト(Host B)なので、踏み台サーバのある環境に似ている。たとえば転送先ホスト(Host C)でOracle Databaseが稼働しているとする。このとき、ローカルホスト上で稼働するOracle SQL Developerから、ログインホスト(Host B)を経由して、Oracle Databaseに接続できる。
ssh -L 1521:hostc:1521 hostb
この接続形態で重要なことが2つある。
- 暗号化されるのは、ローカルホストとログインホストの間だけ
- ログインホストと転送先ホストの間は、転送先ポート(通常22番以外)で通信し、暗号化されない
このような特性があるため、転送先ホスト(Host C)では、22番だけでなく「転送先ポート」も開ける必要がある。暗号化されないことについては、クラウドの中でクローズドネットワークだから問題ないだろう。
どうしても暗号化するならば、多段SSHしたうえでポートフォワーディングとなるが、本題ではないので触れない。
ここまで理解できれば、あとは設定するだけだ。次に利用環境に応じたポートフォワーディングの設定方法を説明する。
6-3. ポートフォワーディングを設定する
ポートフォワーディングの設定は、PuTTYとTera Termのそれぞれについて説明する。ただし踏み台サーバまでSSH鍵認証で接続できていることを前提にする。
6-3-1. PuTTYでポートフォワーディングを設定する
左のツリーから[Connection]-[Data]を選択し、[When username is not specified]が[Prompt]になっていることを確認する。そして[Auto-login username]に前回設定したVNCのユーザーを設定する。
左のツリーから[SSH]-[Tunnels]を選択する。[Source port]と[Destination]に、次の書式で入力する。
Source port:「転送元ポート」
Destination:「転送先ホストのIPアドレス:転送先ポート」
入力が終わったら[Add]をクリックして、テキストボックスに
L転送元ポート 転送先ホストのIPアドレス:転送先ポート
が追加されていることを確認する。
ヒント:ログインホストと転送先ホストが同じときは、転送先ホストはIPアドレスでなく、localhostでもよい。また以下のように複数設定できる
左のツリーで[SSH]を選択する。この作業は必須ではないが [Don’t start a shell or command at all]にチェックを付ける。チェックすると、ログインしたセッションではコマンドが実行できなくなり、ポートフォワーディング用に実行していることを明確に区別できる。
接続に成功すると以下のように表示される。[Don’t start a shell or command at all]にチェックを付けているときは、プロンプトは表示されず、コマンドも実行できない。
ポートフォワーディングが動作していることは、Windowsの
netstat
コマンドで確認できる。コマンド・プロンプトから以下のように実行する。この例では、ローカルホストの5901ポートでTCP(IPv4とIPv6)を待ち受けしていることがわかる。C:\Users\foo> netstat -ant| findstr 5901 TCP 127.0.0.1:5901 0.0.0.0:0 LISTENING ホスト内 TCP [::1]:5901 [::]:0 LISTENING ホスト内注意:これでわかるのは転送元ポートがリスニングされていることだけだ。希望する先頭先ホストに転送されることまではわからない。またIPv4の同じポートをリスニングしているしている行が複数あるときは、誤動作の原因になるのでPuTTYを停止する。
9.次は「7. VNCサーバに接続する」に進む。ウィンドウをクローズすると、ポートフォワーディングも終了してしまう。このまま続けるときはクローズしないこと。
6-3-2. Tera Termでポートフォワーディングを設定する
[設定]メニューから[SSH転送]を選択する。
次の3箇所に入力して、[OK]をクリックする。
ローカルポート :「転送元ポート」
リモート側ホスト:「転送先ホストのIPアドレス」
ポート :「転送先ポート」
次回起動したときも登録した設定が使えるように、[設定]メニューから[設定の保存]を選択する。
ポートフォワーディングの設定が終わったので、[設定]メニューから[SSH認証]を選択する。必要な項目を設定してログインする。
ポートフォワーディングの確認方法はPuTTYを参考にすること。
7. VNCクライアントでVNCサーバに接続する
これでの設定がすべて終わった。VNCクライアントを起動して、VNCサーバに接続する。
7-1. VNCクライアントをダウンロードする
VNCクライアントが無いときは、先にダウンロードする。VNCクライアントにはインストーラーが必要なものもあるが、配置するだけで利用できるTigerVNCを使用する。
7-2.VNCクライアントで接続する
初期画面が表示されるので、接続方法に応じて以下のように入力する。たとえばポートフォワードでディスプレイ番号1に接続するときは
localhost:5901
と入力して、[Connect]をクリックする。
ポートフォワード使用:localhost:<ポートフォワードのポート番号>
直接接続:VNCサーバのIPアドレス:<VNCサーバのポート番号>
このあとのステップは6系と7系では異なるので、別々に説明する。
7-3. デスクトップ環境を設定する(7系Linux OS)
はじめてログインしたユーザーは初期設定が表示される。以下の手順に従って設定すること。1度設定すれば、2回目以降は表示されない。
オンラインアカウントとの連携が必要なときは設定する。サーバ利用では通常不要なので、そのまま右上の[次へ]をクリックする。
初期設定が終わったので[Oracle Linux Serverを使い始める]をクリックする。OSユーザーが同じであれば、次回以降は表示されない。
7-3-1. スクリーンロックを無効化する(7系Linux OS)
VNCサーバを起動したままにしておくとスクリーンロックがかかり、OSユーザーのパスワードが要求される。OSユーザーにはパスワード設定されていないので、この状況を回避するには以下の2つの対策がある。
- スクリーンロックを無効化する
- OSユーザーにパスワードを設定する
sshd_config
を確認すると、SSHのパスワード認証は無効化されている。そのためOSユーザーにパスワードを設定しても、外部からパスワード認証でSSH接続される危険性はない。grep ^PasswordAuthentication /etc/ssh/sshd_config ---以下画面出力--- PasswordAuthentication no
今回は「スクリーンロックを無効化する」方法を説明する。
もし設定に時間がかかり、スクリーンロックされたときはVNCサーバを再起動すること。
systemctl restart vncserver-opc@:<display-number>.service
7-4. デスクトップ環境を設定する(6系Linux OS)
6系Linux OSでは、7系のような初期設定画面はない。ただし、スクリーンロックの問題はあるので無効化する。またデスクトップ環境固有のパッケージアップデートチェックが有効になっているので無効化する。
7-4-1. スクリーンロックを無効化する(6系Linux OS)
以下の画面が表示されているときはスクリーンロックされている。そのときは
service vncserver restart
でVNCサーバを再起動する。
yum install gconf-editor -y
でGNOME設定エディタをインストールする。メニューバーから[Applications]-[System Tools]-[Configuration Editor]を選択する。
左のツリーから[apps]-[panel]-[global]を選択する。
disable_log_out
とdisable_lock_screen
の2つにチェックを入れる。
ヒント:設定ファイルでスクリーンロックを無効化する
GUIツールで設定する方法を紹介したが、設定ファイルを使用する方法もある。エディタで以下のファイルを開き、disable_log_out
とdisable_lock_screen
を探して以下のように変更する。変更が終わったらVNCサーバを再起動する。vi /etc/gconf/schemas/panel-global.schemas237行目付近をfalseからtrueに変更する<key>/schemas/apps/panel/global/disable_lock_screen</key> <applyto>/apps/panel/global/disable_lock_screen</applyto> <owner>panel</owner> <type>bool</type> <default>true</default>★この行250行目付近をfalseからtrueに変更する<key>/schemas/apps/panel/global/disable_log_out</key> <applyto>/apps/panel/global/disable_log_out</applyto> <owner>panel</owner> <type>bool</type> <default>true</default>★この行7-4-2. パッケージアップデートチェックを無効化する(6系Linux OS)
8. まとめ
- VNCを使うと、WindowsクライアントでLinuxのフルデスクトップ環境を利用できる
- VNCクライアント(TigerVNC)はファイルを配置するだけで使えるので、管理者権限を持っていないWindowsクライアントでも利用できる
- ポートフォワーディングを併用すると、VNCの通信を暗号化できるだけでなく、クラウドのようなネットワークにも対応できる
9. コピペ用コマンドまとめ(7系Linux OS)
7系Linux OSでのVNCサーバの設定をまとめる。
# デスクトップ環境をインストール yum groupinstall graphical-server-environment -y # VNCサーバをインストール yum install tigervnc-server mesa-libEGL -y # ユニットファイルをコピー。ファイル名やOSユーザー名は適宜変更すること cp /usr/lib/systemd/system/vncserver@.service /etc/systemd/system/vncserver-opc@.service # ユニットファイルを修正 sed -i -e '43,44 s/<USER>/opc/' /etc/systemd/system/vncserver-opc@.service su - opc vncpasswd ★ここまでが1回目のコピペ用★ # VNCサービス起動 systemctl start vncserver-opc@:1.service # 環境に応じてファイアウォール設定 # ログインホストと転送先ホストが異なるときや、直接接続のときはポートを開ける firewall-cmd --add-service=vnc-server --permanent --zone=public firewall-cmd --reload # ファイアウォールの設定確認 firewall-cmd --list-all
- 投稿日:2019-06-27T21:27:04+09:00
Linuxでテキストを編集するための最低限の知識
はじめに
この投稿ではLinuxでテキストを編集するための最低限の知識をお伝えします。
なぜこのような投稿をするかと言いますと、先日とあるハンズオンセミナーに参加しました。そのセミナーの前提知識としてLinuxでテキスト編集ができることと記載されており、windowsしか触ってこなかった私はとても焦りました。そこで実際にセミナーで必要となった内容を記載して備忘兼共有しておきたいと思います。
テキストファイルを作成したいディレクトリに移動する
最初にカレントディレクトリのファイルやフォルダを確認するために「ls」を入力してEnter押下します。
カレントディレクトリにあるフォルダやファイルが表示されます。cloudshell:~ (platinum)$ ls envs hello-world python-docs-samples README-cloudshell.txt今回は「hello-world」ディレクトリにテキストファイルを作成したいと思うので「cd hello-world」を入力して「hello-world」に移動します。コマンドプロンプトと同じ感覚です。
cloudshell:~ (platinum)$ cd hello-world cloudshell:~/hello-world (platinum)$テキストファイルを新規作成する
ファイル名が「test.txt」のテキストファイルを新規作成してみます。
「vi test.txt」を入力すると以下のようなテキストエディタが起動します。cloudshell:~/hello-world (platinum)$ vi test.txt~ ~ ~ ~ ~ "test.txt" [New File]そこで文字を入力する前に入力モードに切り替える必要があります。
エスケープ押下後に「i」を押下すると下部に「-- INSERT --」と表示され文字が入力できる状態になります。
その状態で「テストテキスト」と入力してみます。テストテキスト ~ ~ ~ ~ -- INSERT --テキストファイルを保存する
エスケープ押下→「:wq」の順で入力すると下の方に「:wq」が表示されます
その状態でEnter押下すると保存されてコマンド入力に戻ります。
エスケープを押すことでいろんなことができるようです。
保存後に再度「vi test.txt」を実行すると保存した内容を編集することができます。テストテキスト ~ ~ ~ ~ :wq保存内容を確認する
「cat test.txt」を入力してEnter押下します。
すると以下のようにテキストファイルの内容が表示されるので簡単に内容を確認できます。cloudshell:~/hello-world (platinum)$ cat test.txt テストテキスト cloudshell:~/hello-world (platinum)$その他の覚えておくと良いこと
- ファイル名やディレクトリ名を入力するタイミングでタブを押下すると以前に入力していた内容が補完されます。例えば「cat test」でタブを押下すると「cat test.txt」にしてくれます。
- コマンドプロンプトと同じですが、方向キーの上下で実行したコマンドの履歴を呼び出せます。
- rmコマンドでファイルを削除できます。今回のファイルを消す場合は「rm test.txt」
- コマンドプロンプトと同様に「cd ../」で一つ上の階層に移動できます。
最後に
上記のコマンドを覚えておくだけで設定ファイルを変更したり保存したりできるようになるので焦らずにハンズオンセミナーなどに参加できるようになります。
- 投稿日:2019-06-27T17:28:06+09:00
【開発環境構築】誰でもお手軽LAMP環境Scotch-box 3.5 使ってみる
「ローカルにLAMP環境を勉強用に用意したいけどまた1から作るのめんどくさいなー」
ポチポチ【ラクしてLAMPとかの環境を用意したい人のためのScotch Box】
https://qiita.com/naru0504/items/a14681b030816135b868?sb2【ラクして環境構築するためのScotch-Boxが2.0になってかなり進化してた。】
https://qiita.com/naru0504/items/560a150943d2251e1ae8「LAMP環境をラクに用意したいとか思っていたら、いいものを見つけました。」
わぁ!?なんと!
調べてみたところ現在はVersion3.5がリリースされているみたいです。
ということで実際に導入してみました。前提条件
- Vagrant導入済
https://www.vagrantup.com/downloads.html
- VirtualBox導入済
https://www.virtualbox.org/wiki/Downloads
私のPC環境
$ sw_vers ProductName: Mac OS X ProductVersion: 10.12.4 BuildVersion: 16E195
Scotch Boxに関して
公式サイト
https://box.scotch.io/
リポジトリ
https://github.com/scotch-io/scotch-box本文
インストール
公式サイト手順どおりやっていきましょう。
$ cd [インストールしたいディレクトリ] $ git clone https://github.com/scotch-io/scotch-box.git $ cd scotch-box $ vagrant up... default: Guest Additions Version: 5.1.21 default: VirtualBox Version: 5.2 ==> default: [vagrant-hostsupdater] Checking for host entries ==> default: [vagrant-hostsupdater] Writing the following entries to (/etc/hosts) ==> default: [vagrant-hostsupdater] 192.168.33.10 scotchbox # VAGRANT: c545e317eb29acab529f8d8c2d591bb2 (default) / 10c73402-26f2-42d6-98a2-a122365b9dd3 ==> default: [vagrant-hostsupdater] This operation requires administrative access. You may skip it by manually adding equivalent entries to the hosts file. # PCのパスワードを入力 Password:インストール終わったら
下記URLにアクセス
http://192.168.33.10/TOPページが表示されましたね。
SSHログインしてみよう
$ vagrant ssh ... MMMMMMMMMMMMMMMXl.:kXNWMMMMMMMMMMMMMMWWXOc.cXMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMMXx:;;:clooddddddddoolc:;;:dKWMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMMMWXOdl:;,,.........,;:cdkXWMMMMMMMMMMMMMMMMM ______ _ ______ ______ / _____) _ | | (____ \ (_____ \ ( (____ ____ ___ _| |_ ____| |__ ____) ) ___ _ _ _____) )___ ___ \____ \ / ___) _ (_ _) ___) _ \ | __ ( / _ ( \ / ) | ____/ ___) _ \ _____) | (__| |_| || |( (___| | | | | |__) ) |_| ) X ( | | | | | |_| | (______/ \____)___/ \__)____)_| |_| |______/ \___(_/ \_) |_| |_| \___/ For help, please visit box.scotch.io or scotch.io. Follow us on Twitter @scotch_io and @whatnicktweets. Last login: Wed May 31 01:25:33 2017 from 10.0.2.2 $sshでログインできました。
LAMP環境構成されているか確認してみよう。# OS $ cat /etc/issue Ubuntu 16.04.2 LTS \n \l # Apache $ apachectl -v Server version: Apache/2.4.18 (Ubuntu) Server built: 2017-05-05T16:32:00 # PHP $ php -v PHP 7.0.18-0ubuntu0.16.04.1 (cli) ( NTS ) Copyright (c) 1997-2017 The PHP Group Zend Engine v3.0.0, Copyright (c) 1998-2017 Zend Technologies with Zend OPcache v7.0.18-0ubuntu0.16.04.1, Copyright (c) 1999-2017, by Zend Technologies # MySQL $ mysql --version mysql Ver 14.14 Distrib 5.7.18, for Linux (x86_64) using EditLine wrapper全部入ってる!!!
ドキュメントルートを設定しよう
/etc/apache2/sites-available/000-default.conf
の設定を書き得えればいいみたい念の為デフォルト設定をコピー
$ cp 000-default.conf 000-default_origin.conf000-default.confを編集
$ sudo vim 000-default.conf<VirtualHost *80:> ServerAdmin webmaster@localhost DocumentRoot /var/www/public ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined <Directory "/var/www/public"> Options Indexes FollowSymLinks AllowOverride all Require all granted </Directory> </VirtualHost>↓↓↓
<VirtualHost *80:> ServerAdmin webmaster@localhost DocumentRoot /var/www/html ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined <Directory "/var/www/html"> Options Indexes FollowSymLinks AllowOverride all Require all granted </Directory> </VirtualHost>Apacheを再起動しましょう
# シンタックスチェック $ apachectl configtest Syntax OK # Apacheリスタート $ sudo service apache2 restart試しにHTMLを配置してあげましょう。
$ cd /var/www/ $ sudo mkdir html $ cd html # 最初からvimも入ってる! $ vim index.html Hello World ~ "index.html" 1L, 12C:wqで保存後
http://192.168.33.10/
にアクセスするとHello Worldが表示されると思います。初期画面はどこにいったの?
あくまで一例ですが僕は
# 名前を変更 $ mv /var/www/public/index.php /var/www/public/doc.php # ファイルを移動 $ mv /var/www/public/index.php /var/www/public/doc.php /var/www/html/http://192.168.33.10/doc.php
に移動させました。
他にもポート開けてあげるとかの方法はあると思います。synced_folderについて
公式のVagrantfileで既にsynced_folderが適応されているので
config.vm.synced_folder ".", "/var/www", :mount_options => ["dmode=777", "fmode=666"]ホスト側から編集してもリアルタイムで反映されてると思います。
最後に
WEB界隈は開発環境構築が簡単と聞きますが躓く人も多々いると思うのでお役に立てたら光栄です。
Scotch-boxBOXを使用しないVarant環境構築方法は別記事で書こうとは思ってます。
タイポや嘘が紛れてたら指摘頂けると幸いです。
お読み頂きありがとうございました。参考記事
【ラクしてLAMPとかの環境を用意したい人のためのScotch Box】
https://qiita.com/naru0504/items/a14681b030816135b868?sb2【ラクして環境構築するためのScotch-Boxが2.0になってかなり進化してた。】
https://qiita.com/naru0504/items/560a150943d2251e1ae8
- 投稿日:2019-06-27T13:49:02+09:00
何も知らないがActive Jobの基礎 from Rails Guide
Active Jobとは
ジョブを宣言し、それによってバックエンドでさまざまな方法によるキュー操作を実行するためのフレームワーク。
キューとは
first in, first outのデータ構造。スタックの逆。
ジョブとは
定期的なクリーンアップを始めとして、請求書発行やメール配信など、あらゆる処理がジョブになる。これらのジョブをより細かな作業単位に分割して並列実行することもできる。
ジョブとは、コマンドやプログラムがまとまった、ひとかたまりの処理のことだ。
Active Jobの目的
Railsアプリケーションにジョブ管理インフラを配置すること。
これにより、
- Delayed JobとResqueなどのように、さまざまなジョブ実行機能のAPIの違いを気にせずにジョブフレームワーク機能やその他のgemを搭載することができるようになる。
- バックエンドでのキューイング作業では、操作方法以外のことを気にせずに済む。
- ジョブ管理フレームワークを切り替える際にジョブを書き直さずに済む。
ジョブキュー処理のResqueとDelayed Jobの使い分けの方針などはありますか?
以下の3つはジョブキュー処理の主要gem。
Resque
良い点
- RMagickなどのメモリリークが存在するコードでも不安なくデプロイできる。
- エコシステムが出来上がってる。悪い点
- 毎回forkするので長時間ジョブ向き。
- キューのストレージとしてRedisが必要。
- メンテが追いついてない。Delayed Job
良い点
- 特になし。悪い点
- DMに専用テーブル作成が必要。
- メモリリークしてるコードがあれば定期的な再起動が必要。Sidekiq
良い点
- Resque互換API。
- 並列に動作するので、外部サイトへのAPI呼び出しなど、I/O待ちの比率が大きいような用途で使うのに便利。
- 1個のプロセスで動作させられるのでメモリ使用量が少なく経済的。悪い点
- プロセス肥大化には弱い。
- コネクションプールの扱い。
- 並列以外の扱い。ジョブの作成(飛ばす)
ジェネレータ使ったり。
ジョブの実行
production環境でのジョブのキュー登録と実行では、キューイングのバックエンドを用意しておく必要があります。=> Railsで使うべきサードパーティのキューイングライブラリ(Sidekiq, Resque, Delayed Jobなど)を決める必要があります。
Rails自身が提供するのは、ジョブをメモリに保持するインプロセスのキューイングシステムだけです。プロセスがクラッシュしたりコンピュータをリセットしたりすると、デフォルトの非同期バックエンドの振る舞いによって主要なジョブが失われてしまいます。
アプリケーションが小規模な場合やミッションクリティカルでないジョブであればこれでも構いませんが、多くのproductionでは永続的なバックエンドを選ぶ必要があります。バックエンド
キューイングバックエンドに接続できるアダプタ(キューイングライブラリ)がビルトインで用意されている。
ジョブはRailsアプリケーションに対して並列で実行されるので、多くのキューイングライブラリでは、ジョブを処理すためにライブラリ固有のキューイングサービスを(Railsアプリケーションの起動とは別に)起動しておくことが求められます。
キュー
多くのアダプタでは複数のキューを扱えます。Active Jobを使って、特定のキューに入っているジョブをスケジューリングできます。
その他
コールバック
Action Mailer
代表的なジョブ。Active JobはAction Mailerと統合されているので、非同期メール送信を簡単に行える。
国際化(i18n)
など
参考リンク
- 投稿日:2019-06-27T01:51:28+09:00
Windows WSL2でストレスフリーな開発環境
Windowsで手軽に開発したいんや!dirコマンドじゃなくてls使いたいんや!
Linuxを使うのもちょっと手間だし、使えたとして処理が早いかというと微妙だし、Webやアプリ開発の上でなにかと不遇なWindowsさん。
最近Microsoftの頑張りでVisualStudioCodeや本題のWSL2など開発環境の充実が目まぐるしいので、思わずQiitaのアカウント作って執筆に至ります。(はじめまして)前置きが長くなりましたが、2019年6月上旬に発表されたWSL2を用いてストレスフリーな開発環境を作成していきます。
最初に
2019年6月現在 Insider Previewを介さないとWSL2搭載のWindowsバージョン(Build 18917)にアップデートできないため、Insider Preview登録の上、Windows Updateをかけます。
WSL2の適用
WindowsのPowerShellを管理者として実行し、下記コマンドをうちこみます。
Enable-WindowsOptionalFeature -Online -FeatureName VirtualMachinePlatformRestartNeeded: Trueと言われたらまず再起動しましょう。
次に、私の場合はLinuxディストリビューションとしてUbuntuを利用したので、
MicroSoft StoreからUbuntuをダウンロードした後に下記コマンドを実行wsl --set-version Ubuntu 2※Ubuntuの部分をご利用のディストリビューション名に変更ください。
これによりUbuntuをWSL2で使用できるようになりました。
念の為ディストリビューションのバージョンを確認しておきましょう。
wsl -l -v NAME STATE VERSION * Ubuntu Stopped 2こうなっていたらWSL2の適用が成功しています。
ここまでがWSL2の適用となります。ストレスフリーな環境構築
さて、本題です。
私は主に下記を導入して、個人的に使いやすい環境を整えました。
- Windows Terminal
- Git(ssh key)
- fish
- fisher
- Powerline font
Windows Terminalの導入
こちらも最近リリースされたものでまだPreview版しかでていませんが、Microsoft製のSSHクライアント搭載のターミナルです。タブも使えるし、背景透過もできる。だいたいのニーズは満たしてくれる気がする。なによりMicrosoft製で固めたい欲が出てきたのでとりあえずこれを使います。
新規タブ追加横の▽からLinuxディストリビューションを選択することができます。
ターミナルのキーバインドや見た目の設定はsettingから json直書き です。Rockだセクション毎に設定が書かれているので、Ubuntuのセクションに
useAcrylic: true
とすると、ターミナルが半透明になります。ちなみに\$HOMEが分かりづらい場所にあるので、WindowsのDドライブ(/mnt/d)とかに変更したくなるのですが、後述のgit利用の際にssh keyのパーミッションがWindowsファイル領域だと変更できないといったトラブルに見舞われるため、$HOMEは/home/等にしておきます
git
/home/以下に.sshディレクトリを作成の上、SSH Keysを作成し
ssh-keygen -t rsa -b 4096 -C "your mail address"このままだとGit Cloneとかした際にPermissionがガバガバだって怒られるので
Permissionを変更しておきましょうsudo chmod 600 id_rsaここまででGitの疎通のためのSSH Keys設定は終了です。
Git config等設定の上、GitHubに公開鍵置いて疎通を確認しましょう。fishの導入
脳死でfish入れます。fish便利やでぇ
sudo apt-add-repository ppa:fish-shell/release-3 sudo apt-get update sudo apt-get install fishログインシェルをためらいなくfishに変更します
chsh -s /usr/bin/fishログインシェルを変更したら一度Terminalを再起動しましょう。
続いてfishのパッケージマネージャーのfisherを入れます
curl -Lo ~/.config/fish/functions/fisher.fish --create-dirs https://git.io/fisherfisherが動作するかバージョンを確認をします
fisher -v fisher version 3.2.9 ~/.config/fish/functions/fisher.fishこれで様々パッケージが手軽に入れられるようになりました。
ためしにテーマぐらい入れておきます。
fisher add oh-my-fish/theme-agnoster残念なことにPowerline対応フォントがないので文字化けします。
Powerline fontの導入
Powerline fontからPowerlineに対応したotfをDLしてきます。
Windowsの標準の手順に従ってインストールした後、Windows側のフォント一覧に反映されているか確認します。
fontのインストールが確認できたら、Windows Terminalの設定からfontを変更します。
前述のセクション毎に分かれているUbuntuのfontFaceを変更ください。"fontFace" : "Source Code Pro for Powerline"設定反映すると、文字化けせずにpowerlineフォントが表示されました!かっこいい!
Windowでここまでの開発環境を築けるとは。感動
おわりに
以上がWindowsでのストレスフリーな開発環境構築になります。
といってもまだまだtmuxを入れることやvimをカスタマイズすることもできるので、
以降はみなさんの好きなようにカスタマイズいただければと思います。
WSL2の旨味のDocker等にも触れていないので、それはまたの機会にしたいとおもいます。ありがとう Microsoft