それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

pkexec のインストール

pkexec がみつならないの。。

探したら、policykit-1 というパッケージに含まれてた。

http://manpages.ubuntu.com/manpages/xenial/man1/pkexec.1.html

pkexec の pk は policy kit の略なんですね

ubuntu の LTS Serverには含まれてなかったんですよね。。。便利だから使ってるけど余り一般的ではないコマンドなのなか。本来なら pkexec の代わりには何を使うべきなんだろう。

sudo だと環境変数の設定を sudoers に書く必要とかあるし、gksudo だと面倒だし一覧楽な do as だと思うんだけどな。

コマンドからunix ドメインソケットのパーミッションを実験する

unix:/var/.../unicorn.sock にアクセスできないの

nginx の プロキシの upstream を unix ドメインソケットに設定したのだけれど動かないのね。 だから、ソケットが正しく動いてるかテストしてみたかったの。

nc コマンドと組合せて使うことで、テストできる。

nc -U unix:/path/to/some.sock

コレを使えばコマンドからunixソケットにアクセスして、アクセス可能かテストできるし、パーミッションもここでテストできる。

echo ' GET / '  | nc  -U /path/to/unicorn.sock

これで応答するか調べられる。

パーミッションのテストをするときは pkexec を使えば楽

pkexec でnc 実行して別ユーザからの読込とアクセスを見てみたら確認できた

echo "GET /" | sudo  pkexec --user www-data nc -U   /var/opt/gitlab/gitlab-workhorse/socket
nc: unix connect failed: Permission denied

これで、 www-data ( nginx ) から gitlab のソケットにアクセスできてないことが分かる。

usermod でグループに追加

アクセス出来ないときはパーミッションをいじるよりもグループをいじったほうが確実だね。

usermod -aG gitlab-wwwdata www-data

これで試してみる

nc でアクセス出来るから試す例

echo "GET /" | sudo  pkexec --user www-data nc -U   /var/opt/gitlab/gitlab-workhorse/socket
HTTP/1.1 400 Bad Request
Content-Type: text/plain; charset=utf-8
Connection: close

400 Bad request が正しく返ってくるので通信できることがわかった。これでnginx の設定が間違ってないことが確認できて安心。

2018-02-03 追記

traditional な nc ( netcat ) は -U オプションが存在しないので、invalid オプションになる。

/bin/nc.openbsd

nc: invalid option -- 'U'
nc -h for help

BSDパッケージのnetcat をインストールする必要があった。

apt install netcat-openbsd

参考資料

https://unix.stackexchange.com/questions/26715/how-can-i-communicate-with-a-unix-domain-socket-via-the-shell-on-debian-squeeze

ファイルを指定バイトコピーする(テスト用に壊れたファイルを作る)

zip が正しく転送できてない実験をしてみたかった

zip ファイルをアップロードしたり、バックアップしたりしてて、「ファイルが壊れた」のを検出したりしたかった。状況を再現したいなと思ってもそう簡単に壊れたりはしないので、壊れたファイルを作る必要がああった。

壊れたファイルを作る → dd

壊れたファイルを作るには、ファイルに0バイトを書き込んで壊したり、半分にちぎったり、変なバイトを書き込む。

これをやるには cp などのコマンドでは出来ないので、 dd コマンド を使うことになる。Cやpythonruby でfopenして書いても良いんだけど、dd コマンドが一番楽だと思う。

dd でファイルをコピーする。

最初に dd でファイルをコピーして、使い方を確認しておく

takuya@Desktop$ dd if=test.zip of=test.safe.zip
0+1 records in
0+1 records out
438 bytes copied, 0.000324 s, 1.4 MB/s
takuya@Desktop$ md5sum  test*.zip
48949110457174e7f10541080235174b  test.safe.zip
48949110457174e7f10541080235174b  test.zip

壊れたzip にする。( コピーを途中で中断した

先頭から400バイトを読み込んで、残りをコピーぜずに、中断された状況を作ってみる。

takuya@Desktop$ dd if=test.zip of=test.corrupted.zip bs=1 count=400
400+0 records in
400+0 records out
400 bytes copied, 0.00151 s, 265 kB/s

結果を確認

takuya@Desktop$ md5sum  test*.zip
7eeef77e910c3a770c557e3bb9d3d8a1  test.corrupted.zip
48949110457174e7f10541080235174b  test.zip

壊れたことを確認する。 unzip しようとしても、return code = 9 が帰ってきて、異常終了したことが分かる。

takuya@Desktop$ unzip -t test.corrupted.zip  ; echo $?
Archive:  test.corrupted.zip
  End-of-central-directory signature not found.  Either this file is not
  a zipfile, or it constitutes one disk of a multi-part archive.  In the
  latter case the central directory and zipfile comment will be found on
  the last disk(s) of this archive.
unzip:  cannot find zipfile directory in one of test.corrupted.zip or
        test.corrupted.zip.zip, and cannot find test.corrupted.zip.ZIP, period.
9

ただしこの状態でも zip のエントリ一覧は取れたりする・・・だから壊れたことを再現できるよね。

takuya@Desktop$ lsar test.corrupted.zip  ; echo $?
test.corrupted.zip: Zip
tet/
tet/a
tet/b
0

変なバイトを書いてしまった

最初に、変なバイトを書き込むファイルを用意する。

takuya@Desktop$ cp test.zip test.wrong-byte.zip

400 バイト目から、30バイトのZEROを書き込んで壊す。

takuya@Desktop$ dd if=/dev/zero of=test.wrong-byte.zip bs=1 skip=400 count=30
30+0 records in
30+0 records out
30 bytes copied, 0.000153 s, 196 kB/s

ファイルが壊れたことを確認してみる

takuya@Desktop$ unzip test.wrong-byte.zip -t
Archive:  test.wrong-byte.zip
  End-of-central-directory signature not found.  Either this file is not
  a zipfile, or it constitutes one disk of a multi-part archive.  In the
  latter case the central directory and zipfile comment will be found on
  the last disk(s) of this archive.
unzip:  cannot find zipfile directory in one of test.wrong-byte.zip or
        test.wrong-byte.zip.zip, and cannot find test.wrong-byte.zip.ZIP, period.

これで、ファイルが壊れたりHDDが壊れて、ファイルが正しく転送できなかったとかプログラマ(わたし)がアホで、ファイルの転送時のネットワーク・エラー処理が甘く変なファイルが作っちゃったとか事件を再現してソレに対応した回復プログラムを作れる実験出来ると思った。

関連資料

Keychainでパスワードを確認するのは右クリックで!

キーチェーンにパスワードを全部入れてる。

キーチェーンはパスワードの管理ツールとしてとても優秀で。

OSにバンドルされてる所が更に魅力的なんです。

パスワードを入手するには、ダブルクリックで開くしか無いと思ってたら。

右クリックで良かったんです。

f:id:takuya_1st:20170818222017p:plain

取得したいパスワードを「クリップボード」に入れるのであとは、ブラウザやアプリ側で貼り付けるだけ

キーチェーンで項目を右クリック

右クリックしたらmacOSのパスワードを聞かれるので、MacからKeychainsに許可を与えればクリップボードにパスワードが降ってくる。楽ちん。

キーチェーン非対応なアプリが困る。

チャットワークとかいうクソアプリが対応してないのでブラウザでログインしなくちゃいけないわけですが。Mac app Store のアプリはパスワードを使えたと思うんだけど・・・なんでログインだけ毎回入れなきゃならないんだろう。 oAuth でブラウザに転送してくれたら良いのに。アプリ内でログインなんて手間なだけだろ。。。

ファイルを更新したら同期したい。

ファイルを更新したら、転送したい。

php のプロジェクトってちまちま転送してると、面倒くさいんですよね。ファイル監視してrsync するのに、grunt とか持ち出すのも馬鹿馬鹿しい。

かといって、サーバーにログインしてvim で編集するとIDE使えないし、コーディング規約を守るに自動整形が使えない。かといって、SFTPアクセスでエディタで開いて編集するのもかったるい。

考えられる選択肢

他になんか有る?

選択肢 面倒なところ
unison バージョンを揃える }
lsyncd 設定ファイルとサーバ側への導入
sshfs 遅い, FUSE導入面倒くさい、オフラインで困る
NFS 認証と導入設定とメンテが面倒、ポートも面倒
dropbox アカウントと課金、同期遅い
git commit/push/push をfsevent でやると本末転倒

ファイル更新イベントでrsync起動

選択肢としてやっぱりこれしかないのかな。ファイル更新のイベント通知をOSから受け取って、更新されたファイルだけを転送したい。 すると、 ファイル更新イベント + rsync の組合せが楽チンで無難な選択肢になるわけです。

作った

python でファイル更新イベントを監視して、ファイル更新がきたら転送する

ruby で書いたけど、ruby ダメだ。python のwatchdog で書き直した。

IntelliJがファイル保存同時に .idea/ を更新するので IDEがファイル更新イベントを作りまくるのでイベント検出後数秒スリープしてその間のイベントを無視するようにした。これで ファイル更新されたあとの プリプロセッサでイベント拾いまくる事が簡単に防げると思う。

#!/usr/bin/env python3

import sys
from watchdog.observers import Observer
from watchdog.events import PatternMatchingEventHandler
from subprocess import Popen
import shlex
import time


class SyncUpload( PatternMatchingEventHandler ) :

    def __init__(self,*args, **kwargs):
        super(SyncUpload,self).__init__(*args,**kwargs)
        self.prcs = None

    def start(self, path ):
        self.watch_path  = path
        observer = Observer()
        observer.schedule( self, path, recursive=True )
        observer.start()

        try:
            observer.join()
        except KeyboardInterrupt:
            observer.stop()
        except:
            observer.stop()

    def on_any_event( self, evt ):
        if self.prcs and  self.prcs.poll() == None : # 実行中ならキャンセルする
            pass
        else:
            time.sleep(1)
            # cmd = "bash -c 'for  i in {1..3} ; do echo 1 ; sleep 1 ; done; ' "
            cmd = "rsync -avz  '%s'   server:path/to/dir/ " % self.watch_path
            self.prcs = Popen( shlex.split(cmd) )




if __name__ == '__main__':
    path = sys.argv[1] if len( sys.argv ) > 1 else './'

    obj = SyncUpload( ['*.php'] )
    obj.start( path )

過去に試した似たようなもの

.net + python

オレオレDropBoxをrsyncで作る。 - それマグで!

lsyncd

lsyncd を使ってWinSCP的なリアルタイム同期を実現する.使い方 - それマグで!

FUSE ssh

http://takuya-1st.hatenablog.jp/entry/20111118/1321594453

他にも unison があるけど、unison はバージョンを併せないと動作しないのでめっちゃ面倒くさい。

lsyncd は片方向で使うのには、面倒だと思う、特に設定ファイルとサーバー側導入が面倒くさい。

mac os が /tmp に wifi-**.log を大量に作る

/tmp のサイズがやけに大きい

しらべたら、 /tmp の中に wifi ログって言うファイルが300くらいあった。なんでや。。。

ログをやめさせる

sudo wdutil log -wifi

これでログを取らなくなるので、静になる。

参考資料

https://superuser.com/questions/1064351/when-tmp-wifi-log-will-show-up-and-how-can-i-stop-it

JSでモーダルダイアログなポップアップを出すやつ

モーダルウインドウ出すやつで良いのがない。

jQuery に依存してたり、細かなイベントが取れなかったり、設定が煩雑だったり、もっと簡単に出来るだろう。と思ってたけど

ネット探して片っ端から試したけど、これ。というのがない。

仕方ないので作った。画像を真ん中に寄せたり、要素を真ん中に寄せてポップアップするのにどれだけ苦労したら良いんだ。。。 そもそも画像のモーダルウインドウのポップアップってあんまり好きじゃないのですよね。

要は、画像をクリックして拡大したり、画面の orientation(向き)を変えても追従してくれたり、画面をリサイズしても追従してくれたり、ちゃんと真ん中でてくれて、jQueryを不要なやつで、DOM API のちょっと古いやつでも動くやつ*1がほしいわけです。

それも、画像じゃなくて指定したElementをポップアップさせたいわけですよ。

サンプル

↓画像をクリックして拡大

使い方

拡大したい要素に、data-modal-image 属性を追加する。

<div style='width:150px'>
<img src='path/to/image' data-modal-image >
</div>
<script>
document.addEventListener('DOMContentLoaded',function(){
       var md = new ModaLayer({});
       md.add_lisnters();
})
</script>

指定した要素をポップアップするので、Width指定すると意図しない動作になることが有るのでdivで囲っておくと良い。

modal.js

gist.github.com

*1:などと言いつつflexbox使ってますが

要素のスタイルをそのまま取り出して、要素をコピーして保存する

要素のスタイルを見た目をそのまま保存したくないですか?

出来るんですよ。 computedStyle を使えば出来ます。

大昔は 紙Copiとかあったし、あの人はそのまま、カーリル作ったりGyazo買収して忙しそうですけど。ScrapBoxはちょっと依存強すぎてすきになれないので、自前で作るかと昔のソース引っ張り出してた。

要素の見た目保持したやつ、現代のDOM API だととても簡単にかける。

cloneNode に少し細工する

cloneNode だと要素は取れてもスタイルは取れないので、要素のスタイルを取ってきて、見た目をそのままに、完全にコピーするような感じで、取ってくる。

キャプチャ画像にはかなわないけど、ある程度までは近くなる。

スタイルをそのまま、要素を取り出す方法。

これだけです。

   var clone_node_recursively = function( src, deep, with_css ){
        var src = src
        var dst = src.cloneNode(deep);
        if (with_css){
            dst.style.cssText = document.defaultView.getComputedStyle(src, "").cssText;
            var a = src.querySelectorAll('*');
            var b = dst.querySelectorAll('*');
            var c = Array.from(a).map( function (e,idx) {
                return [a[idx], b[idx]]
            } )
            c.forEach(function (e,i) {
                e[1].style.cssText = document.defaultView.getComputedStyle(e[0], "").cssText;
            })
        }
        return dst
    }

ポイント

ここで、要素に当たってるCSSの情報をテキストファイル化してる。

 document.defaultView.getComputedStyle(src, "").cssText

あとは、子要素をたどるだけ。簡単。ただ、親要素の背景の上に乗ってたりするので、背景色は取ってこれないのが難点ですね。背景がなかったらかなり印象が違ってしまう。

動作例

←右のサイドバーからデータ取ってくる(PCのみ

出力例

出力されたHTML

なつかしい

昔は、これでサービス作って一儲けだみたいな某K氏と夢を語ってたけど、あれからもう10年かー早いな。

当時のブラウザだと、body を見た目のままソノママ取り出そうとすると、計算量と出力HTMLが膨大になって使い物にならなったけど、現代のブラウザとCPUだと軽々動くんですよねー、生まれる時代を間違えたんじゃないか。

JSON をシリアライズ・デシリアライズ で関数を含めてObjectをコピーする

以前、JSONのstringify の 第二引数の話を書いた。

takuya-1st.hatenablog.jp

そういえば、完成形を書いてない。

JSONで関数も含めてシリアライズする例はこれ。

関数も含めてシリアライズしてコピーする。

var a = {
  name: "takuya",
  say: function() { console.log( this.name ) },
  tel : { name:'iphone', display: function(){ console.log(this.name) } }
}
var str = JSON.serialize(a)
var b = JSON.deserialize(str)
b.say() // => takuya

serialize/ deserialize はこれ。

//serialize/deserialize ツール
JSON.serialize = function(obj){
  try{
    var str =  JSON.stringify(obj, function replacer (k,v){
        if(typeof v === "function"){ return v.toString() };
        return v ;
      })
    return str

  }catch(e){
    return "";
  }
}
JSON.deserialize=function(str){
  try{
    var obj = JSON.parse( str ,function reciever (k,v ) {

    if ( typeof v === "string" && v.match(/^function/) ){
        return Function.call(this, "return "+ v  )();
      }
      return v
    })

    return obj;


  }catch(e){
    return null
  }
}

こういうの、公式にアレば良いんだけどなかったんだっけ?

grepコマンドでファイル名だけを取り出す。

grep してマッチした行ではなく、ファイル名が欲しい

検索したキーワードを含むファイル名を取り出して、それを全部開いて処理したいときに

grep -l 

-l をつけるとファイル名だけを取り出すことが出来る。

覚え方

l なので line ですね

関連資料:その他のgrep コマンドの活用方法など

grep で特定のディレクトリを外す - それマグで!

特定の拡張子(*.php)のファイルだけをGrepして検索したい。 - それマグで!

grepで逆検索 (マッチするモノを除外)でマッチしないものを探す - それマグで!

unar/lsar コマンドで指定したファイルを取り出す。ほとんどのアーカイブファイルを扱える。

unar / lsar コマンドが便利

unar コマンドで展開すると文字化けがあまり発生しない。

unar とペアになってる lsar コマンドも文字化けを余り起こさずにファイルを取り出せる。

また展開できる

指定したファイルだけを取り出すには

lsar で一覧したファイルの中から、指定したファイルを取り出すには次の方法で出来る。

unar sample.zip 'img001.jpg' 

指定したファイルを標準出力に取り出すには

いちいちディレクトリを作られるのが面倒なので、指定したファイルだけをぱぱっと取り出して標準出力に取り出してしまうと便利だった。

unar sample.zip 'img001.jpg' -r -o - > out.jpg

ただし日本語は通らなかった。

これは動かなかった。( mac 版での確認 )

unar sample.zip 'サンプル/img001.jpg' -r -o - > out.jpg

かわりにワイルドカードが使える。

日本語が入ってた場合はもう絶望的ですが、ワイルドカードを使うことである程度は回避することが出来る。

unar sample.zip '*/img001.jpg' -r -o - > out.jpg

ちょっとしたトリックですが、アーカイブディレクトリ内部にファイルがかぶってなければだいたいうまくいく。

日本語がマッチしないのは文字コードの問題かも

日本語がマッチしないのは、ZIP内部のファイル名がCP932 でLinux文字コードUTF-8 のためかもしれない。 windows め・・・

関連資料

http://takuya-1st.hatenablog.jp/entry/2016/08/03/145534

mac wifi を再起動するコマンド( 切断、起動、指定したSSIDに接続など無線LANコマンドのマトメ

macWifi をコマンドから操作できると楽だよね

切断して、オフして再起動して、接続する。

sudo airport -z
sudo networksetup -setairportpower en0 off
sudo networksetup -setairportpower en0 on
networksetup -setairportnetwork en0 0001docomo

これをスクリプトにしておけば、びっくりしなくて済む。macOS XWifiは優先度を高く設定してても、電波が強い方を優先するので、意図しないSSIDに繋いだりするので、注意が必要ですね。

切断

iOS 11 のコントロール・センターのWifiボタン相当

sudo airport -z

ネットワークオフ

ifdown コマンド相当

sudo networksetup -setairportpower en0 off

ネットワークオン

ifup コマンド相当

sudo networksetup -setairportpower en0 on

指定したSSIDにつなぐ

networksetup -setairportnetwork en0 0001docomo

WiFi DHCPを再取得

sudo /usr/sbin/networksetup -setdhcp Wi-Fi

これをまとめて使うって公衆無線LANと戦う

公衆無線LAN飛んでるととんでもないところにつなぐので、これで確実に接続を試行できる。

なぜか、再起動を挟まないとMacWifiDHCPや802.1認証でタイム・アウトしちゃうとその後の接続が全ておかしくなるんだよね。。。。

公衆無線LANが飛んでると便利な半面で、適当な業者は本当に迷惑だわ。

php のエルビス演算子を初期化以外の用途で使ったら・・・

エルビス演算子が便利だけど。

三項演算子の省略形 elbis operator が便利だけど

<?php
$a[0] = $a[0] ?: 10 ;
var_dump($a);

// array(1) {
//  [0]=> int(10)
//}

変数初期化チェックがシンプルになって嬉しいよね。empty 相当だよねーってウキウキして empty の代わりの使ってみたり。

三項演算子を省略する使うとちょっとね。

<?php
$a[0] = empty($a['a']) ?: 10 ;
var_dump($a);
// array(1) {
//  [0]=> true
//}

そうか、true になるのか。三項演算子の省略形としては「初期化」以外で使うと絶対ダメですね。。。

一時的にaliasをオフ無効にする バックスラッシュ

一時的にalias をオフにしたいとき

grep や ls などを使っていて、一時的にalias をオフにしたいことないですか?

私は結構たくさんあります。 grep や ls にいっぱいオプションを付けていて普段はそれを使っているのですが、素のgrep がほしいときはある。

そんなときは back slash を入れます。

\grep . -R 

このような、エイリアスがあったとしても、素のgrep が動いてくれます。

takuya@:www-data$ alias grep
alias grep='grep -i -E -a --color=auto -n '

これを知って、安心して rm や ls までどんどん alias にしていくことが出来ました。

不必要に エイリアスが呼び出されてしまわないように バックスラッシュをつけるのが良いです。

ただし、同名の関数が定義されているときは関数が優先されます。

シェルから一時的に使うと便利。

バックスラッッシュは、エイリアスがあるために意図した動作にならないときに、対話的prompt で使うと便利です。本当に便利です。

互換性を維持する目的であれば フルパス

alias しまくってると不意に動作することがあるので、シェルスクリプトにバックスラッシュを書きたくなると思います。別環境に持っていくときに alias が発動しないようにバックスラッシュを付与したスクリプトファイルにしても構わないのですが。。。。

互換性を目的にするのであれば、バックスラッシュよりもフルパスが好ましいと思います。

## これはalias発動するのでポータビリティに向いてない。
ls *.jpg | grep aaa| xargs identify

## これだと、alias なしで実行される。が、function grep {   ... } があればそちらが使われてしまう。
## またPATH優先順位にも左右されてしまう。
ls *.jpg | \grep aaa| xargs identify

##  フルパスで指定が無難
ls *.jpg | /bin/grep aaa| xargs identify

このように、シェルのコマンドの優先度を考えたら、ポータビリティを維持する目的でではバックスラッシュは向いていません。

2019-08-23

互換性についての記述を追加。

MySQLの基本的コマンド(ユーザ・DB・権限・パスワード)の設定削除作成の早見表 -- sql 版

MySQLをぱぱっと管理したときに困らないように

データベース作成したり削除したりで困らないように、チートシート的にコピペで使えるようなものを用意しておきます。

ユーザーの新規作成・削除・パスワードを変更などはよく使うのでどこかにメモっておくといい感じ。

ユーザーの確認

ユーザーの一覧を見ます。

select User,Host, Password from mysql.user;

データベース一覧

データベース表示するには、専用コマンド show databaseを使います。

show databases ;

テーブル一覧

テーブル一覧は、専用コマンド show tabales が便利です。

use my_db;
show tables ;

ユーザー作成

ユーザー作成は create user をつ使います。

create user 'your name' identified by 'your pass'

権限の追加

grant all on my_db.* to your_name@'%'

権限の確認

権限を委譲(grant) したら専用コマンドで権限の割当を確認します。

show grants for your_name;

権限の反映

データベースを作成したりユーザーを割り当てたあとは、権限(Privileges)を更新します。

FLUSH PRIVILEGES 

ペアで覚える

作成と削除はペアで使うことが多いのでまとめて掲載しておきます。

データベースの作成・削除・確認

create database YOUR_DB_NAME;
show databases;
drop database YOUR_DB_NAME;

作成・削除と確認はペアで覚えておかないと複数個作ったり消したりしてるとパニックになるので最初に覚えること

ユーザ作成・削除

作成削除はまとめて覚えておくといいので create user と drop user はペアで掲載しておきます。

create user 'your name' identified by 'your pass'

select User,Host, Password from mysql.user;

select User,Host, Password from mysql.user where User like  '%yourname%'

drop user 'your name' 
drop user takuya@'hostoname'

パスワードの変更

ALTER USER 'user'@'hostname' IDENTIFIED BY 'this_is_my_new_password';

設定したパスワードを忘れた場合は、パスワードを再設定するときや紛失・盗難でパスワードを変更する必要があるとき。といっても大抵の場合では、初期設定の時点でメモを忘れてパスワードを紛失するんだけど。

権限の追加削除と確認

grant all on my_db.* to your_name@'%'
revoke all on my_db.* from your_name@'%'

権限削除って余り使わないかも。Allつけておいて不要な権限だけ削除する感じ? それだったら必要な権限だけつけたら良いわけで。

root 権限をもつユーザーの作成

 grant all on *.* to 'takuya'@'%'  WITH GRANT OPTION;

GRANTをGRANTする。権限のGRANTを許可できるroot と同じ管理者権限を付与するには、with grant option をつける

2020-08-04

mysql のパスワード忘れの場合の、パスワードの初期化・変更を追記。

2021-03-30

revoke に記述ミスがあったので修正。

2021-05-28

検索エンジンにこのエントリが無視されるので、微妙にキーワードを追加する。