やるしかなっちゃん

やるしかない!

jQueryでページ読み込みが終わった後の処理

これがいつもどっちがどっちかわからなくなるので

DOM構築後に実行

$(document).ready( function() {
  alert('hoge');
});
$(function() {
  alert('hoge');
});

書き方が2つあるので頭が混乱するのだけれども下の書き方だけを覚えて上の書き方は二度と書かないようにしたい

CSSファイルや画像を読み込み終わった後に実行

$(window).on("load",function() {
  alert('hoge');
});

感想

これで完全にマスターした

CSSで画像の縦横比を維持したまま縮小する方法

max-width/max-heigthで最大値を指定して、widthとheightプロパティをautoにすればタイトル通りのことを実現できた

  /* 横に合わせる場合 */
  max-width: 100%;
  height: auto;
  /* 縦に合わせる場合 */
  max-height: 100%;
  width: auto;

jsfiddle.net

参考サイト(というかこのサイトを見れば全てわかる) bashalog.c-brains.jp

Facebookのアクセストークンをlocalhostで取得する方法

開発者登録の時にアプリドメインを指定するとそのドメインが認証の対象になるので、そのドメインならアクセストークンの取得ができるみたい

でもこのアプリドメインにはlocalhostを指定できないのでこれは困ったと思ったら簡単に解決できた

開発者画面の設定 -> 詳細設定 -> クライアントOautn設定から有効なOauthリダイレクトURLにlocalhostのURLを指定すればよいだけだった

f:id:k213:20160426005426p:plain

↑ここの場所ね

ポートを調べるコマンド

ポート番号決め打ちでどのプロセスが使っているか調べるにはlsofコマンドの-iを使えばいいらしい

$ lsof -i :3000
COMMAND   PID USER   FD   TYPE             DEVICE SIZE/OFF NODE NAME
node    99380 user   23u  IPv6 0xbf5d0b7b0a938607      0t0  TCP *:hbci (LISTEN)

curlでGET/POST/PUT/DELETE

最近wgetからcurlに改宗した
取り敢えずGET/POST/PUT/DELETEのリクエストを投げられたら勝ちだと思う

GETはcurlコマンドの後にURLでOK

$ curl http://www.example.com/

他のメソッドは-Xオプションの後にメソッド名を書けばOK

$ curl -X POST http://www.example.com/
$ curl -X PUT http://www.example.com/
$ curl -X DELETE http://www.example.com/

POSTでデータを送信するには-dオプションの後に書けばOK
ファイルデータの場合にはファイル名の前に@を付けるだけ

$ curl -X POST -d "hoge=0&fuga=1" http://www.example.com/
$ curl -X POST -d @hoge.json http://www.example.com/

完全勝利してしまった

Javaでのビットの入出力(改善版)

前回(Javaでのビットの入出力 - やるしかなっちゃん)から改善しました。
I/OでひとまとめにしないでそれぞれをBitInputStreamとBitOutputStreamにするようにしました。
また、Input/OutputStreamを継承ではなくてコンポジションしてます。

public class BitInputStream {
    private InputStream input;
    private byte bitBuffer;
    private byte bufferPosition;
    private boolean isEOF;

    public BitInputStream(InputStream input) {
        if (input == null) {
            throw new NullPointerException("InputStream is null.");
        }
        this.input = input;
        this.bitBuffer = 0;
        this.bufferPosition = -1;
        this.isEOF = false;
    }

    private void bufferBits() throws IOException {
        if (bufferPosition == -1) {
            bufferPosition = 7;
            bitBuffer = (byte)input.read();
        }
        if (bitBuffer == -1) {
            isEOF = true;
        }
    }

    /**
     * Return 0 or 1 or -1(EOF).
     * @throws IOException
     */
    public int read() throws IOException {
        bufferBits();
        if (isEOF) {
            return -1;
        }
        int mask = 1;
        mask <<= bufferPosition--;
        if ((bitBuffer & mask) == 0) {
            return 0;
        } else {
            return 1;
        }
    }

    /**
     * Close this stream.
     * @throws IOException
     */
    public void close() throws IOException {
        input.close();
    }
}
public class BitOutputStream {
    private OutputStream output;
    private byte[] bitBufferArray;
    private int bufferIndex;

    public BitOutputStream(OutputStream output) {
        if (output == null) {
            throw new NullPointerException("OutputStream is null.");
        }
        this.output = output;
        this.bitBufferArray = new byte[8];
        bufferIndex = 0;
    }

    private byte bufferBits(byte bit, byte bitBuf, byte bufPos) {
        bit = (byte)(bit << bufPos);
        bitBuf = (byte)(bitBuf | bit);
        return bitBuf;
    }

    private void flushBits(byte bitBuf) throws IOException {
        output.write(bitBuf);
    }

    /**
     * Write 8bit to stream.
     * @param bits BitArray(Length must be 8 or less)
     * @throws IOException
     */
    private void write(byte[] bits) throws IOException {
        if (bits.length > 8)
            throw new IllegalArgumentException("Length of Byte[] must be 8 or less");
        byte bitBuf = 0, bufPos = 0;
        for (int i = bits.length - 1; i >= 0; i--) {
            if (!(bits[i] == 0 || bits[i] == 1))
                throw new IllegalArgumentException("Elements of Byte[] must be 0 or 1");
            bitBuf = bufferBits(bits[i], bitBuf, bufPos);
            bufPos++;
        }
        flushBits(bitBuf);
    }

    /**
     * Write 1bit to stream.
     * @param bit Bit
     * @throws IOException
     */
    public void write(int bit) throws IOException {
        if (!(bit == 0 || bit == 1)) {
            throw new IllegalArgumentException("Argument must be 0 or 1");
        }
        if (bufferIndex == 7) {
            bitBufferArray[bufferIndex] = (byte)bit;
            write(bitBufferArray);
            bufferIndex = 0;
        } else {
            bitBufferArray[bufferIndex++] = (byte)bit;
        }
    }

    /**
     * Close this stream.
     * @throws IOException
     */
    public void close() throws IOException {
        if (bufferIndex != 0) {
            for (int i = bufferIndex; i < bitBufferArray.length; i++) {
                bitBufferArray[i] = 0; // 足りない分は0で埋める
            }
            write(bitBufferArray);
        }
        output.close();
    }
}

read()はリストから配列への変換とか糞みたいなことをしていた部分をガッツリ削ることができました。
あと、配列単位で色々とやっていたのを基本int型で0と1をやりとりするようにしました。

Javaでのビットの入出力

Javaでビットの入出力を行うのは自分で実装するしかなさそうなので実装してみた(もしかしたらちゃんとしたやり方があるのかも知れない)。
当然の前提だけど、Javaにはbit型というものは存在しないから何かで代用しなくてはいけないので、今回はbyte型をbit型として代用した。
よって書き込みは8bitずつ行うものとする(byte型の大きさは8bit)。書き込みをする操作は以下の通り。

public class FileBitIO {
    private File file;
    private byte[] bitAry;

    public FileBitIO(String fileName) {
        this.file = new File(fileName);
    }

    private byte bufferBits(byte bit, byte bitBuf, byte bufPos) {
        bit = (byte)(bit << bufPos);
        bitBuf = (byte)(bitBuf | bit);
        return bitBuf;
    }

    private void flushBits(byte bitBuf) {
        try(FileWriter filewriter = new FileWriter(file, true)) {
            printBit(bitBuf);
            filewriter.write(bitBuf);
        } catch(IOException e) {
            e.printStackTrace();
        }
    }

    public void writeBits(byte[] bits) {
        if (bits.length > 8) {
            System.err.println("一度に書き込めるのは8bitまでだよ");
            return;
        }

        byte bitBuf = 0;
        byte bufPos = 0;
        for (int i = bits.length - 1; i >= 0; i--) {
            bitBuf = bufferBits(bits[i], bitBuf, bufPos);
            bufPos++;
        }
        flushBits(bitBuf);
    }
}

writeBitsに要素数8以下の0と1を要素に持つ配列を渡せば実際に出力できる。
例えば01000001を書き込みたい場合は次のようにすればよい。
01000001は10進数で65なので、実際に書き込んだファイルを開けば文字コードが65のAが書き込まれている。

byte[] bits = {0, 1, 0, 0, 0, 0, 0, 1};
FileBitIO fb = new FileBitIO("./hoge.txt");
fb.writeBits(bits);

書き込みを行っている処理は単純で、受け取った配列の各要素を適切なビット位置にするためにシフト演算を行い、バッファとORをとっているだけ。

書き込みは多分誰が作っても同じような感じになると思うのだけれど、読み込みが以外に悩んだ。
もう思いついたままに実装したので以下のようになった。

public class FileBitIO {
    // 省略

    private void createBytesList(List<Byte> byteList) {
        try(FileReader filereader = new FileReader(file)) {
            int b;
            while((b = filereader.read()) != -1){
                byteList.add((byte) b);
            }
        } catch(IOException e) {
            e.printStackTrace();
        }
    }

    private void convertBitListToArray(List<Byte> byteList, byte[] bitAry) {
        int size = byteList.size();
        for (int i = 0; i < size; i++) {
            int x = byteList.get(i), bit = 1, len = 8;
            for (int j = len - 1; j >= 0; j--) {
                if ((x & bit) == 0) {
                    bitAry[(i*8)+j] = 0;
                } else {
                    bitAry[(i*8)+j] = 1;
                }
                bit <<= 1;
            }
        }
    }

    private void createBitArray() {
        List<Byte> byteList = new ArrayList<>();
        createBytesList(byteList);
        bitAry = new byte[byteList.size() * 8];
        convertBitListToArray(byteList, bitAry);
    }

    public byte[] readBits(int begin, int end) {
        if (bitAry == null) {
            createBitArray();
        }
        if (begin < 0 || end > bitAry.length || begin > end) {
            System.err.println("ダメやねん");
        }
        byte[] bits = new byte[end - begin + 1];
        System.arraycopy(bitAry, begin, bits, 0, end + 1);
        return bits;
    }
}

ファイルから1文字分読み込んでそれをリストに格納する。そして格納したそれぞれの値をビットに変換したものを配列に保存している。
readBitsはこの全ビットを保持した配列から、指定した範囲分のビットだけをコピーして返す。
ループが何箇所にも存在して非効率だとは思うけど、とりあえず動くものを作りたかったのでこうするしかなかった。
先ほどのAを書き込んだファイルから読み込んでみると以下のようになる。

FileBitIO fb = new FileBitIO("./hoge.txt");
byte[] bits = fb.readBits(0, 7);
for (int i = 0; i < bits.length; i++) {
    System.out.print(bits[i]);
}

これを実行すれば期待通りの出力01000001が得られる。

また、デバッグ用と実際に使用する時の為に以下の2つのメソッドを用意しとくと便利。

public class FileBitIO {
    // 省略

    private void printBit(byte x) {
        int bit = 1, len = 8;
        byte[] b = new byte[len];

        for (int i = 0; i < len; i++) {
            if ((x & bit) == 0) {
                b[i] = 0;
            } else {
                b[i] = 1;
            }
            bit <<= 1;
        }

        for (int i = len - 1; i >= 0; i--) {
            System.out.print(b[i]);
        }
        System.out.print(' ');
    }

    public int getBitAryLength() {
        if (bitAry == null) {
            createBitArray();
        }
        return bitAry.length;
    }

取り敢えず動くものはできたけど、果てしなく自分の実装に自信がないのでもうちょっと調べていい方法がないか試したい。