君は心理学者なのか?

大学時代に心理学を専攻しなぜかプログラマになった、サイコ(心理学)プログラマかろてんの雑記。

scpでリモートサーバからローカルにファイルを落とす&ローカルからリモートに転送する

f:id:karoten512:20180306214627g:plain

↑ test-serverにあるfilesディレクトリの中身を、localに落としてきているところ。

scpコマンドについて

ファイルを送信したり、受信したりすることができる。

ファイル送受信時に使用するプロトコルsshプロトコルなので安全。

また、使用帯域なども絞れるので、

他の通信を圧迫しないようにファイルの送受信をすることができる。

使用シーン

リモートホストの特定のディレクトリにある、大量のファイルを落としたい時。

ローカルで作ったシェルをリモートに置きたい時。

などなど。

使用法

リモートからローカルに落としてくる

scp [ユーザー名]@[ホスト名]:[リモートファイルパス] [ローカルファイルパス]

また、-r オプションを付けると、

ディレクトリの中のファイルを再帰的に取ってきてくれる。

ディレクトリ構造が保持されるので、便利。

scp -r [ユーザー名]@[ホスト名]:[リモートディレクトリパス] [ローカルディレクトリパス]

使用例

リモートホストにある、sshクライアントの設定ファイルを取ってくる時。

scp user@remote_host:~/.ssh/config ~/

ローカルからリモートに転送する

scp [ローカルファイルパス] [ユーザー名]@[ホスト名]:[リモートファイルパス]

ローカルファイルパスを複数指定すると、

複数個のファイルを取ってくることができるらしい。これも便利。

参考サイト

www.atmarkit.co.jp

余談

なお、scpと語感が似ているsftpというコマンドがあるが、

結構違う。

イメージとしては、ftpプロトコルsshになった感じ。安全。

リモートにログインして操作ができるので、

リモート上でファイル名を変えたり、移動させたりすることができる。

canvasで画像を表示する

いきさつ

canvasを使って画像のリサイズをしたり、

画像のくり抜きがしたかったので、まずはcanvasで画像を表示できるようにした。

手順

1. input type='file'で画像を登録できるようにする

<input type="file" id='file'>

2. fileを登録した時にイベントが発火するようにする

/** input要素の取得 */
const input = document.getElementById('file');

/** inputに画像を追加した時にイベントを受け取る */
input.addEventListener('change', function(e) {
  /** 処理 */
}

3. 処理を書く

/** inputに画像を追加した時にイベントを受け取る */
input.addEventListener('change', function(e) {

  /** File オブジェクトを読み込む */
  const file = e.currentTarget.files[0];
  const fr = new FileReader();

  fr.onload = function() {
    /** ファイルが読み込まれたあとの処理 */
    const image = new Image();
    
    /** 画像がimageタグに読み込まれた後の処理 */
    image.onload = function() {
      ctx.beginPath() ;
      ctx.drawImage(this, 50, 0, 400, 400, 0, 0, 200, 200);   
    }
    image.src = fr.result;
  }
  fr.readAsDataURL(file);
});

解説1

canvasで画像を描く際、drawImageというメソッドを用います。

drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh)

imageはHTMLImageElement, HTMLCanvasElement, HTMLVideoElement のいずれかを取ることができます。

ということは、まずはHTMLImageElemenetを生成する必要があります。

解説2

const image = new Image();

でHTMLImageElemenetが生成できます。が、

Imageのsrcを指定する必要があります。

    const image = new Image();
    
    /** 画像がimageタグに読み込まれた後の処理 */
    image.onload = function() {
      ctx.beginPath() ;
      ctx.drawImage(this, 50, 0, 400, 400, 0, 0, 200, 200);   
    }
    image.src = fr.result;

こんな感じで。

fr.resultはFileReaderがFileオブジェクトを読み込んだ際の結果です。

ソースコード

jsfiddle.net

macのlocal環境にtypescriptを導入

f:id:karoten512:20180303225527p:plain

職場が静的型付け言語使ってきた人が多いので、

その人達の学習コストの事だったり

コンパイル時にバグを発見できたりであったり

そんな事情でtypescriptを使っています。

導入の仕方の備忘録。

typescriptの導入

1. typescriptをglobal install

npm install -g typescript

2 . コードを書く

class Dog {
  private name: string;

  constructor(name: string) {
    this.name = name;
  }
}

const dog = new Dog('pochi');

3. typescriptからJavaScriptコンパイルする

tsc hello.ts

こんなjsファイルが生成されます。

var Dog = /** @class */ (function () {
    function Dog(name) {
        this.name = name;
    } 
    return Dog;
}());
var dog = new Dog('pochi');

webpackの導入

いちいちコンパイルするの面倒くさいよね。

ファイル保存時に自動でコンパイルしてくれたらうれしい

コンパイルが終わった後にいちいちブラウザリロードするの、
面倒くさいよね。

コンパイルが終わったら自動でブラウザをリロードしてくれるとうれしい

コード量が増えたらファイル分けたいよね。

外部ファイルが読み込めるようになったらうれしい

webpackを導入しましょう。

(次回の記事)

地下アイドル「私、ぜったい売れっ子アイドルになるんだから!」で学ぶデザインパターン(Observer)〜アイドルとオタクを疎結合にしてみた〜

f:id:karoten512:20180226001228p:plain

ある日の地下アイドル

地ア「は〜あ。今日もライブは3人しかこなかったなぁ」

地ア「きょう来てくれたのは、たっくんと、しのぶんと、ゆっきーか」

地ア「この3人、いつも来てくれるんだよねぇ。大事にしなくちゃ」

地ア「私、ぜったいに売れっ子アイドルになるんだから!」

地ア「…そろそろCD発売だから、告知しよっと」

アイドルクラス

/** アイドルクラス */
function ChikaIdle() {
}

ChikaIdle.prototype.noticeCdRelease = function() {

  /** わたし、みんなの名前も顔も覚えてるよ! */
  var takkun   = new Otaku('takkun');
  var shinobun  = new Otaku('shinobun');
  var yukki = new Otaku('yukki');
  
  /** CD買って(はあと) */
  console.log('みんなだいすき!CD買ってね!');
  takkun.getCd();
  shinobun.getCd();
  yukki.getCd();
}

アイドルによる告知

var chikaIdle = new ChikaIdle();
chikaIdle.noticeCdRelease();

オタククラス

/** オタククラス */
function Otaku(name) {
    this.name = name;
}
Otaku.prototype.getCd = function() {
    console.log(this.name + 'はCDをぜってーかうぜ!!');
}

告知結果

みんなだいすき!CD買ってね!
takkunはCDをぜってーかうぜ!!
shinobunはCDをぜってーかうぜ!!
yukkiはCDをぜってーかうぜ!!

だんだん売れてきた地下アイドル

地ア「今日は10人もライブに来てくれた!!」

地ア「きょう来てくれたのは、たっくんと、しのぶんと、ゆっきーと、ちーくんと、るなくんと、、、」

地ア「ほげくんとほげくんとほげくんかぁ」

地ア「そろそろCD発売だから、また告知しよっと」

アイドルクラス

/** アイドルクラス */
function ChikaIdle() {
}
ChikaIdle.prototype.noticeCdRelease = function() {

  /** わたし、みんなの名前も顔も覚えてるよ! */
  var takkun   = new Otaku('takkun');
  var shinobun  = new Otaku('shinobun');
  var yukki = new Otaku('yukki');
  var chi = new Otaku('chi');
  var luna = new Otaku('luna');
  var hoge1 = new Otaku('hoge1');
  var hoge2 = new Otaku('hoge2');
  var hoge3 = new Otaku('hoge3');
  var hoge4 = new Otaku('hoge4');
  var hoge5 = new Otaku('hoge5');

  console.log('みんなだいすき!CD買ってね!');
  /** CD買って(はあと) */
  takkun.getCd();
  shinobun.getCd();
  yukki.getCd();
  chi.getCd();
  luna.getCd();
  hoge1.getCd();
  hoge2.getCd();
  hoge3.getCd();
  hoge4.getCd();
  hoge5.getCd();
}

アイドルによる告知

var chikaIdle = new ChikaIdle();
chikaIdle.noticeCdRelease();

メッチャ売れてきたアイドル

地ア「すごい!今日ははじめて箱(ライブハウスのこと)がいっぱいになったよ!」

地ア「200人も来てくれた!」

地ア「今日来てくれたのはたっくんと、しのぶんと、ゆっきーと、ちーくんと、るなくんと、、、」

f:id:karoten512:20180226003450j:plain

地ア「アアアアアアアアアアアアアアアアアアアアアア!!!!!!!」

しのぶん「地下アイドルちゃん!僕の事今日から、しのぶーって読んでね!」

/** アイドルクラス */
function ChikaIdle() {
}
ChikaIdle.prototype.noticeCdRelease = function() {
  /** わたし、みんなの名前も顔も覚えてるよ! */
  // var shinobun  = new Otaku('shinobun');
  var shinobu  = new Otaku('shinobu');
  // shinobun.getCd();
  shinobu.getCd();
}

f:id:karoten512:20180226003618j:plain

地ア「ア゛ア゛ア゛ア゛ア゛ア゛ア゛ア゛ア゛ア゛ア゛ア゛ア゛!!!!!!!」

どうしてこうなったのか

地下アイドルがいろいろ知りすぎです。

f:id:karoten512:20180226004952p:plain

このままでは、

オタク達が増えるたびに地下アイドルクラスに変更が行われ、

オタク達のあだ名が変わるたびにまた、地下アイドルクラスに変更が行われます。

つまり、

地下アイドルクラスはめちゃくちゃ仕様変更に弱いクラスということになります。

その時、地下アイドルは気づいた

地ア「そうだ!」

地ア「私は別に、みんなの名前を覚えなくていいんだ!」

これがObserverパターンの始まりです(嘘)

Observerパターンで書き直す

アイドルクラス

/** アイドルクラス */
function ChikaIdle() {
    this.fans = [];
}

ChikaIdle.prototype.addFan = function(fan) {
    this.fans.push(fan);
}

ChikaIdle.prototype.noticeCdRelease = function() {
  console.log('みんなだいすき!CD買ってね!'); 
  /*
   * アイドルはファンの名前は誰も知らない。
   * 知っているのはCDを買ってくれるということだけ
   */
  this.fans.forEach(function(fan, index, fans) {
    fan.getCd();
  });
}

アイドルクラスから、

Otakuクラス、

Otakuの名前が全て消えました。

f:id:karoten512:20180226010800p:plain

アイドルが知っているのは、

fanが「getCd」というメソッドを持っていることだけです。

もう、アイドルはオタクの顔も名前も思い出せません。

知っているのは、「告知をしたら、CDを買ってくれる」というただ1つだけ。。。

アイドルとオタクが非常に疎結合な、良い設計になりました。

使い方

var chikaIdle = new ChikaIdle();

var takkun   = new Otaku('takkun');
var shinobun = new Otaku('shinobun');
var yukki    = new Otaku('yukki');
var chi      = new Otaku('chi');
var luna     = new Otaku('luna');
var hoge1    = new Otaku('hoge1');
var hoge2    = new Otaku('hoge2');
var hoge3    = new Otaku('hoge3');
var hoge4    = new Otaku('hoge4');
var hoge5    = new Otaku('hoge5');

chikaIdle.addFan(takkun);
chikaIdle.addFan(shinobun);
chikaIdle.addFan(yukki);
chikaIdle.addFan(chi);
chikaIdle.addFan(luna);
chikaIdle.addFan(hoge1);
chikaIdle.addFan(hoge2);
chikaIdle.addFan(hoge3);
chikaIdle.addFan(hoge4);
chikaIdle.addFan(hoge5);

chikaIdle.noticeCdRelease();

さらなるメリット

アイドルは、CDを買ってくれる人ならだれでも通知することが出来ます。

/** 一般ピーポークラス */
function IppanPeople(name) {
    this.name = name;
}
IppanPeople.prototype.getCd = function() {
    console.log(this.name + 'はちょっと興味があるからCDかうよ');
}

getCdメソッドを持つクラスをまとめて扱うことが出来ます。

疎結合にしたことにより、ポリモーフィズムも使えるようになりました。

まとめ1

Observerパターンは、通知する側とされる側を疎結合にする。

疎結合にした結果、ポリモーフィズムも使えるようになる。

まとめ2

アイドルとオタクを疎結合にすると、

アイドルはオタクの顔も名前も覚えなくなり、

知っているのは「告知をしたら、CDを買ってくれる」というただ1つだけという

夢も希望もなくなる感じになる。

【JavaScript】画像をdrag and dropしてサムネイルを表示する〜DragEvent, DataTransfer, File, FileReaderオブジェクトについて〜

こういうのがやりたかった

f:id:karoten512:20180223161259g:plain

手順

簡単に言うと、

  • DragEventからDataTransferを取得

  • DataTransferからFileを取得

  • FileをFileReaderで読み込み、サムネイルとして表示

という手順になります。

1. dropエリアの準備

1-1. まずはdropエリアを作成する

imgは後でサムネイルを表示する際に使います。

<div id='droparea'>
</div>
<img src='' id='thumb'>
#droparea {
  width: 200px;
  height: 100px;
  border: 3px dotted #ccc;
}

1-2. dropエリアにイベントリスナを登録

const droparea = document.getElementById('droparea');
droparea.addEventListener('drop', function(evt) {
  console.log('dropしたよ');
  /** 以下、drop後の処理 */
}, true);

この中にdrop後の処理を書き込んでいきます。

2. dragしたファイル(Fileオブジェクト)を受け取る

dropしたファイルを取得します。

まず、dropイベントの中身を見てみましょう。

console.log(evt);

f:id:karoten512:20180223153824p:plain

DragEventというオブジェクトのようです。

今回用があるのは、このオブジェクトが持つ

DataTransferというオブジェクトです。

console.log(evt.dataTransfer);

f:id:karoten512:20180223154003p:plain

DataTransferオブジェクトがもつfilesというプロパティから、

ドラッグされたFileオブジェクトにアクセスすることが出来ます。

/** 全件取得 */
console.log(evt.dataTransfer.files);
/** 1件取得 */
console.log(evt.dataTransfer.files[0]);

f:id:karoten512:20180223153619p:plain

複数件まとめて扱うこともできそうですね。

3. 取得したFileオブジェクトを、FileReaderで読み込む

ソースコード

droparea.addEventListener('drop', function(evt) {
  // ファイルオブジェクトの取得
  const file = evt.dataTransfer.files[0];
  
  // FileReaderの生成
  const reader = new FileReader();
  
  reader.onload = function() {
    // ファイルを読み込んだ後の処理
    console.log(reader.result);

    // サムネイルとして表示
    const thumb = document.getElementById('thumb');
    thumb.src = reader.result;
  };

  // ファイルの読み込み
  reader.readAsDataURL(file);
 
  // ブラウザのデフォルト挙動を抑制
  evt.preventDefault();

}, true);

FileReaderの解説

html5から、

FileReaderというローカルファイルを読み込めるAPIが使えるようになりました。

FileReaderが扱えるのはFileオブジェクト(またはBlobオブジェクト)です。

reader.onload = function() {
  // ファイルを読み込んだ後の処理
  // reader.resultでファイル内容にアクセスできる
};

としてファイルを読み込んだ後の処理を記載します。

読み込んだ結果は、

reader.resultでアクセスできます。

reader.readAsDataURL(file);

としてファイルオブジェクトを読み込みます。

完成したソースコード

const droparea = document.getElementById('droparea');

// dropイベントのリスナーを設定
droparea.addEventListener('drop', function(evt) {

  // Fileオブジェクトの取得
  const file = evt.dataTransfer.files[0];
  
  // FileReader生成
  const reader = new FileReader();
  
  // ファイルを読み込んだ後の処理
  reader.onload = function() {
      // サムネイルとして表示
      const thumb = document.getElementById('thumb');
      thumb.src = reader.result;
  };

  // ファイルの読み込み
  reader.readAsDataURL(file);

  evt.preventDefault();

}, true);

bashで特定の文字列を含むファイルの名前を、一括置換する

f:id:karoten512:20180220003702j:plain

bashである文字列を含むファイルについて、一括置換したかった

カレントディレクトリにあるファイルのうち、

無題を含むものをmudaiに変える、みたいなことがしたかった。

結論

解説

まず、以下のようにファイルを準備します。

$ touch hogeA hogeB fugaC

これらのファイルのうち、以下の2つのファイル名を

hogeA -> ho:)geA
hogeB -> ho:)geB

と変更することにします。

for文

こう書けば、カレントディレクトリのファイルについて

ループ処理をすることが出来ます。

# run.sh
for file in *
do
  echo ${file}
done
$ sh run.sh
fugaC
hogeA
hogeB

sed

新しいファイル名を生成する際、正規表現を使うことがあります。

そのときはこのsedを使いましょう。

以下のように使うことが出来ます。

$ echo hogeA | sed -E 's/(ho)(ge)/\1:)\2/g'
ho:)geA

-E オプション

正規表現が使えます。

's/(ho)(ge)/\1:)\2/g' について

ho, geという文字をかっこでくくることにより、キャプチャを撮っています。

そして、\1, \2で再度アクセスしてます。

\1, \2の間にhappy simbolをいれてます。

mv

forとsedを組み合わせて、

sedで新しいファイル名を生成しつつ、

mvでその新しいファイル名に変更していきます。

for file in *
do
    after_file=`echo ${file} | sed -E 's/(ho)(ge)/\1:)\2/g'`
    mv -i "${file}" "${after_file}"
done

まとめ

sedコマンド、とても便利。

とくにキャプチャを取り始めるとその便利さに驚く。

今回、xargsなどを用いるともっと簡単にかけるかもしれないが、

可読性のためにココらへんでとどめておくことにした。

またチャレンジしたい。

bashは最強のポータビリティ言語。

MySQLにて、特定のカラムに日本語が含まれているかどうかを抽出

あるカラムに日本語が含まれていることを検出したい

結論

あるカラムに対して、

LENGTH

CHARACTER_LENGTH

の値が異なることを利用する。

SQLの例

SELECT
  *
FROM
  table_name
WHERE
  LENGTH(column_name) != CHARACTER_LENGTH(column_name);

解説

LENGTHは「バイト」数

LENGTH:文字列のバイト数を調べる

CHAR_LENGTHは「文字」数

なるほどねぇ。

oshiete.goo.ne.jp