Category Archives: プログラミング

JavaScript プログラミング

<input type=”date”>を使いやすく

Published by:

普通に <input type="date" placeholder="日付を選択してください" value=""> と書くと、

日付の選択:



となって、placeholderも効かないし、「yyyy/mm/dd」なんて表示されてもどうなの?となりますよね?

そこで、<input type="text" onfocus="this.type='date'" onblur="this.type='text'" placeholder="日付を選択してください" value=""> としてフォーカスが付いたときだけ type=”text” を type=”date” に切り替えるというミニテクニック。

日付:




さらに、<input type="text" onfocus="this.type='date'" onblur="if(!this.value)this.type='text';" onchange="if(!this.value)this.type='text';" placeholder="日付を選択してください" value=""> のようにして、選択済みならtype属性を戻さないのもありかも。


ビットコイン ブロックチェーン プログラミング

Ledger Nanoの受取アドレスを生成するプログラムを作った

Published by:

朝からこんな怖い話がニュースになっていました・・・!

レッジャー社のハードウェアウォレットに脆弱性 「中間者攻撃」で資金流出リスク

 レッジャー社がツイッターで参照する匿名レポートによると、マルウェアに感染したパソコンを使ってレッジャー中にビットコイン受取アドレスを生成しようとする際、「中間者攻撃」とよばれるセキュリティ侵害が起こる可能性がある。マルウェアがアドレス生成のためのコードを改編し全ての入金がハッカーに送られてしまうという。

普通のディスプレイ付きLedger Nanoであればこのサイトで紹介されている方法でアドレスが正しいかどうかを判定できますが、私が持っている古いディスプレイなしのタイプでは確認できません。

というわけで確認用のツールを作ってみました。

Ledger wallet address checker
http://hello.lumiere-couleur.com/app/browser_ledger/

browser_ledger

サーバー生成ではありませんので、ネットワークを切断した状態でも使えます。
というか、そのように使った方がいいかと思います。

TypeScript+Browserify+jQueryで作りましたが、意外に簡単なんですね。
ちょっとしたツールだったら、これからこの方法で行こうかな。

Github リポジトリはこちら

ビットコイン ブロックチェーン プログラミング 発表、ニュース

ビットコインのウォレットと、支払い用のプログラムを作ろう

Published by:

ビットコインのウォレットは数多くありますが、ハードウェアウォレットは高いしなあ・・・という方は、とりあえずウォレットアプリを利用するのがおすすめです。
ウォレットアプリだと、スマホが壊れたときや新しいスマホに買い替えたときに大事なビットコインがなくなっちゃうんじゃない?なんて心配になりますが、大丈夫!
すべてのビットコインはブロックチェーン上に保管されていて、そのブロックチェーンは世界中に遍在しています。

ハードウェアウォレットだろうとペーパーウォレットだろうと、もちろんウォレットアプリも同じですが、すべてその中にビットコインはありません!
これらウォレットはブロックチェーンに保管されているビットコインへの鍵のようなもので、仮にウォレットがぶっ壊れてもビットコインが失われたわけではなく、合鍵を使ってアクセスすればいいのです。

合鍵となるのがリカバリーフレーズですが、最初にウォレットを作るときに必ずメモを残すようにしましょう。
また、このリカバリーフレーズさえあればだれでもそのウォレットへアクセスできますので、十分気をつけて保管して下さい。

私が使っているCopayというウォレットアプリでは、12の日本語の単語(ひらがな)でリカバリーフレーズが作れます。
仮に私がCopayでウォレットを1つ作り、そのリカバリーフレーズを人にあげれば、それはそのまま相手のウォレットにもなっちゃいます。
この仕組み、本当に面白いですよね・・・

最近個人的に作っているプログラムでビットコインの支払いを受け付ける必要があったのですが、HDウォレット形式に対応することで毎回支払いのビットコインアドレスを変えることが出来ます。
こうすることでちゃんと支払われたかどうかをプログラムでチェックできるのでおすすめです。
1つのアドレスに全部送ってもらうようにすると、どれが誰のものか分からなくなってしまうんですよね。

下はTypeScript版のコードですが、これで新しい受取用のアドレスを生成することが出来ます。
Wallet.tsの「const mnemonic = ‘リカバリーフレーズ’;」のところに、Copayで生成したウォレットのリカバリーフレーズを入れます。

import bitcoin = require('bitcoinjs-lib');
import bip39 = require('bip39');

const mnemonicToM = (mnemonic, password, network) => {
    const seed = bip39.mnemonicToSeed(mnemonic, password || "")
    const m = bitcoin.HDNode.fromSeedBuffer(seed, bitcoin.networks[network || "bitcoin"])
    return m
}
const mnemonic = 'リカバリーフレーズ';

/**
 *  ビットコインウォレット
 */
export class Wallet {
  /**
   *  支払い用アドレス生成
   */
  public static createPaymentAddress(tx_index: number) {
    const m = mnemonicToM(mnemonic, '', 'bitcoin');  // 秘密鍵
    // console.log(m.derivePath("m/44'/0'/0'").toBase58()); // xpriv...
    // console.log(m.derivePath("m/44'/0'/0'").neutered().toBase58());  // xpub...
    // console.log(m.derivePath("m/44'/0'/0'/0/0").getAddress()); // 1DQ...

    let paymentAddress = m.derivePath("m/44'/0'/0'/0/" + tx_index).getAddress();
    return paymentAddress;
  }
}

次に、受取チェックのプログラム。

import blockexplorer = require('blockchain.info/blockexplorer');
import rp = require('request-promise-native');

import { BitcoinAddress } from "./BitcoinAddress";
import { BitcoinTransaction } from "./BitcoinTransaction";

/**
 *  ビットコイントランザクション
 */
export class Transaction {
  /**
   *  最新のブロック総数を取得
   */
  public static getBlockCount(): Promise<number> {
    let url = 'https://blockchain.info/ja/q/getblockcount';
    return rp(url)
      .then((body: string) => {
        let count = parseInt(body.trim());
        if (isNaN(count)) {
          return -1;
        }
        return count;
      });
  }

  /**
   *  指定のアドレスの情報を取得
   */
  public static getAddress(address): Promise<BitcoinAddress> {
    // 最新のブロック総数を取得
    return Transaction.getBlockCount()
      .then((count: number) => {
        // アドレス情報を取得
        return blockexplorer.getAddress(address)
          .then((result) => {
            let bitcoinAddress = new BitcoinAddress();
            bitcoinAddress.address = address;
            bitcoinAddress.total_received = result.total_received / 100000000;
            bitcoinAddress.last_confirmation = 0;
            bitcoinAddress.txs = [];

            // トランザクションの承認数を確認
            if (result.txs && result.txs.length > 0) {
              for (let i = 0; i < result.txs.length; i++) {
                let tx = result.txs[i];
                let bitcoinTransaction = new BitcoinTransaction();
                bitcoinTransaction.block_height = tx.block_height ? tx.block_height : count;
                bitcoinTransaction.confirmation = Math.max(0, count - tx.block_height);
                bitcoinTransaction.confirmation = !isNaN(bitcoinTransaction.confirmation) ? bitcoinTransaction.confirmation : 0;
                if (bitcoinAddress.last_confirmation == 0) {
                  bitcoinAddress.last_confirmation = bitcoinTransaction.confirmation;
                } else {
                  bitcoinAddress.last_confirmation = Math.min(bitcoinAddress.last_confirmation, bitcoinTransaction.confirmation);
                }
                bitcoinTransaction.btc_amount = 0;
                for (let j = 0; j < tx.out.length; j++) {
                  let out = tx.out[j];
                  if (out.addr == address) {
                    bitcoinTransaction.btc_amount += out.value / 100000000;
                  }
                }
                bitcoinAddress.txs.push(bitcoinTransaction);
              }
            }

            return bitcoinAddress;
          });
      });
  }
}
import { BitcoinTransaction } from "./BitcoinTransaction";

/**
 *  ビットコインアドレス
 */
 export class BitcoinAddress {
   public address: string;
   public total_received: number;
   public last_confirmation: number;
   public txs: BitcoinTransaction[];
 }
/**
 *  ビットコイントランザクション
 */
 export class BitcoinTransaction {
   public block_height: number;
   public confirmation: number;
   public btc_amount: number;
 }

実行するとこんな感じです。

import { BitcoinAddress } from "bitcoin/BitcoinAddress";
import { Transaction } from "bitcoin/Transaction";
import { Wallet } from "bitcoin/Wallet";

// tx_indexは0スタートのインクリメント値
let paymentAddress = Wallet.createPaymentAddress(0);
console.log('paymentAddress', paymentAddress);

Transaction.getAddress(paymentAddress)
  .then((bitcoinAddress: BitcoinAddress) => {
    console.log('bitcoinAddress', bitcoinAddress);
  });

$ npm run wallet_test 

> myprogram@1.0.0 wallet_test /home/xxxxxxxxx/myprogram
> env NODE_PATH=./build node ./build/wallet_test.js

paymentAddress 1rUTG3jWJ3rkEiKFLyvXbMaQcLnqxr49c
bitcoinAddress BitcoinAddress {
  address: '1rUTG3jWJ3rkEiKFLyvXbMaQcLnqxr49c',
  total_received: 0.0104252,
  last_confirmation: 1508,
  txs: 
   [ BitcoinTransaction {
       block_height: 492652,
       confirmation: 1508,
       btc_amount: 0.0104252 } ] }

生成された支払い法のアドレス(上の実行例では1rUTG3jWJ3rkEiKFLyvXbMaQcLnqxr49c)が、Copayで表示される受取用アドレスと一致してればOK。
または、Copayの設定画面で確認できる、ウォレットの拡張公開鍵と、Wallet.tsでコメントアウトしている「// console.log(m.derivePath(“m/44’/0’/0′”).neutered().toBase58()); // xpub…」のコメントを外して実行してみて、その出力結果が一致しているかどうかも確認した方がいいでしょう。

ソースのダウンロードはこちら

WordPress プログラミング

WordPressテーマフレームワーク「Beans」の日本語翻訳ファイル作成方法

Published by:

WordPressテーマを作ろうと思ってテーマテンプレートを探していたら、「Beans」というテーマフレームワークのことを知りました。

beans-logo-contrast

さっそく試してみたらかなり良さげだったので、そのままページを作っていたところ、パンくずリスト(ページ階層を表示する部分)の先頭が「Home」になってる。
ここを日本語で「ホーム」にしたいなと設定してみました。

ビフォー

ビフォー

アフター

アフター

インストールするのは「Loco Translate」という翻訳サポートプラグインで、名前は知っていましたが使うのは今回初めてです。
使ってみて分かりましたがすごい便利です。potファイル(テンプレート)からpoファイル(言語別翻訳ファイル)、moファイル(言語別翻訳ファイルをコンパイルしたもの)を作ってくれるし、全部WordPressの管理画面の中で作業ができてしまいます。
やっぱりWordPressすごいなあ・・・

プラグインの新規追加で「Loco Translate」を検索&インストール&有効化して、管理メニューの「Loco Translate > Themes」を開きます。
Beansテーマフレームワークを使うときは子テーマを作って作業しますが、翻訳は親テーマの方を直接行いました。

loco1

Beansのpotファイルが通常の「<テーマディレクトリ>/languages/tm-beans.pot」ではなかったのでpotファイルが見つからないというエラーが出ています。
Advancedタブの「Template file」を「lib/languages/tm-beans.pot」と設定してあげたら読み込んでくれるようになりました。

loco4

Overviewタブで「(+) New language」をクリックして、「WordPress language」の方の「Japanese」を選択します。
location(保存先)は Otherの中の「languages/themes/tm-beans-.po」を選択しました。

loco2

そうするとpoファイル編集画面が表示されますので、Source Textから「Home」を選択してJapanese translationに「ホーム」と入力し、Saveボタンをクリックします。

loco3

な、なんと、これだけでpoファイルとmoファイルが同時に生成されて、画面上のパンくずリストにも表示されてしまいます!すごい!便利!
これまで Poedit 使って po 開いて mo 書き出して ftp でアップして・・・という面倒なことはいらないんですね。
ありがとう、Loco Translate!ありがとう、Beans!

ハードウェア ビットコイン プログラミング

ビットコインを普通のお財布に入れてみた

Published by:

ハードウェアウォレット Ledger Nano

ハードウェアウォレット Ledger Nano

ビットコインを買ってみたい、でも以前ハックされたMt.Gox(マウント・ゴックス)のことを思うとオンラインウォレットに購入したビットコインを置いておくのは怖い。

投資目的ではなく、単に買ってみたい、持ってみたい、使ってみたいというだけなので、Ledger Nanoというハードウェア・ウォレットを購入してみました。

2014年2月にMt.Goxがハック&破綻する数週間前にもビットコインを買ってみようと思い、まさにそのMt.Goxにアカウントを作ったところでしたが、結局買えずじまいで2年以上経ってしまいました。

そのころは1BTC=8万円くらいで2015年は2~3万円、2016年9月の今は5万円~6万円くらいと大きく変動するビットコインですが、今回はcoincheck(コインチェック)という日本の取引所でごく少額を購入してみました。

coincheckで、0.1ビットコインを購入するところ

coincheckで、0.1ビットコインを購入するところ

購入したビットコインをそのままcoincheck(コインチェック)のオンライン・ウォレットに保管しておいても問題ない(はず)ですが、手元のLedger Nanoに移しておくことでオンライン上でハックされる恐れがなくなります。

スマホアプリやPCアプリにもウォレットはありますし、そちらの方が使い勝手は良いと思いますが、仮想通貨がリアルに手に持てるというのはちょっと面白い感覚ですよね。

ハードウェア・ウォレットへのビットコインの出し入れは、PCのUSBポートにさして専用アプリを経由して行います。
その際は4桁のPINコードとセキュリティカードが必要です。
(ハードウェアを紛失したりコードがわからなくなった時や、新しいハードウェアへ移すときなどにもリカバリーできるそうです)

Ledger Wallet Nanoのセキュリティーカード。 裏に換字コードが書かれています。

Ledger Wallet Nanoのセキュリティーカード。
裏に換字コードが書かれています。

実際のビットコインのやり取りにかかる時間ですが、最初の一回だけ4~5分待った気がします。
その後は数十秒で終わりましたので、思っていたよりずっとスピーディに出し入れできるんですね。

これまでオンライン決済には、クレジットカードや銀行振込を使っていて、最近はそれほど手間に感じることなく買い物出来ていましたが、銀行やクレジットカード会社のサーバーを一切介さず、これだけスマートに直接お互いやり取りできるというのは、とてつもない進化です。

ほんのわずかのビットコインを買ってみただけですが、この技術の桁違いの新規性に冷や汗をかきました。
正直ブロックチェーン技術についてはまだまだプログラマーとして無知な状態ですが、今後理解を深めておかないとまずいよなあ。

coincheck(コインチェック)はこちら ↓。画面の作りが使いやすいです。

日本で一番簡単にビットコインが買える取引所 coincheck bitcoin

Java プログラミング

PDF内のすべての画像に、一気に透かし文字(ウォーターマーク)を入れる

Published by:

あまりなさそうな状況ではありますが、せっかくプログラムを作ったので公開しておきます。
実装言語はJavaです。

必要なライブラリ

※slf4jとlogbackはログ出力に使っているだけなので、なくても良い。

コード

package com.lumiere_couleur.java.pdfwatermark;
 
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.awt.image.Raster;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Iterator;
 
import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
 
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
 
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.pdf.PRStream;
import com.itextpdf.text.pdf.PdfDictionary;
import com.itextpdf.text.pdf.PdfName;
import com.itextpdf.text.pdf.PdfNumber;
import com.itextpdf.text.pdf.PdfObject;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfStamper;
import com.itextpdf.text.pdf.parser.PdfImageObject;
 
public class ReplaceImages {
 
    private static final Logger log = LoggerFactory
            .getLogger(ReplaceImages.class);
 
    public static float FACTOR = 1.0f;
 
    public static void main(String[] args) {
        if (args.length &lt; 3) {
            System.err
                    .println("Usage: java ReplaceImages input_pdf output_pdf watermark");
            System.exit(1);
        }
        String input_pdf = args[0];
        String output_pdf = args[1];
        String watermark = args[2];
        if (input_pdf == null || input_pdf.length() == 0
                || !(new File(input_pdf).exists())) {
            System.err
                    .println("Usage: java ReplaceImages input_pdf output_pdf watermark");
            System.exit(1);
        }
 
        try {
            PdfReader reader = new PdfReader(new FileInputStream(input_pdf));
            int n = reader.getXrefSize();
            PdfObject object;
            PRStream stream;
            for (int i = 0; i &lt; n; i++) {
                object = reader.getPdfObject(i);
 
                if (object == null || !object.isStream()) {
                    continue;
                }
 
                PdfDictionary dic = (PdfDictionary) PdfReader
                        .getPdfObject(object);
                if (dic == null) {
                    continue;
                }
 
                PdfName type = (PdfName) PdfReader.getPdfObject(dic
                        .get(PdfName.SUBTYPE));
                if (!PdfName.IMAGE.equals(type)) {
                    continue;
                }
 
                stream = (PRStream) object;
 
                PdfImageObject image = new PdfImageObject(stream);
 
                BufferedImage bi = null;
                try {
                    bi = image.getBufferedImage();
                } catch (javax.imageio.IIOException e) {
                    // Unsupported Image Type
 
                    // CMYK → RGBに変換
                    // http://stackoverflow.com/questions/2408613/problem-reading-jpeg-image-using-imageio-readfile-file
                    byte[] imgbytes = image.getImageAsBytes();
                    if (imgbytes == null) {
                        continue;
                    }
 
                    // Find a suitable ImageReader
                    Iterator&lt;ImageReader&gt; readers = ImageIO
                            .getImageReadersByFormatName("JPEG");
                    ImageReader imageReader = null;
                    while (readers.hasNext()) {
                        imageReader = (ImageReader) readers.next();
                        if (imageReader.canReadRaster()) {
                            break;
                        }
                    }
 
                    // Stream the image file (the original CMYK image)
                    ImageInputStream input = ImageIO
                            .createImageInputStream(new ByteArrayInputStream(
                                    imgbytes));
                    imageReader.setInput(input);
 
                    // Read the image raster
                    Raster raster = imageReader.readRaster(0, null);
 
                    // Create a new RGB image
                    bi = new BufferedImage(raster.getWidth(),
                            raster.getHeight(), BufferedImage.TYPE_4BYTE_ABGR);
 
                    // Fill the new image with the old raster
                    bi.getRaster().setRect(raster);
                }
 
                if (bi == null) {
                    continue;
                }
                int width = (int) (bi.getWidth() * FACTOR);
                int height = (int) (bi.getHeight() * FACTOR);
                BufferedImage img = new BufferedImage(width, height,
                        BufferedImage.TYPE_INT_RGB);
                AffineTransform at = AffineTransform.getScaleInstance(FACTOR,
                        FACTOR);
                Graphics2D g = img.createGraphics();
                g.drawRenderedImage(bi, at);
 
                // 透かしを入れる
                g.setPaint(Color.WHITE);
                Font font = new Font("メイリオ", Font.PLAIN, 18);
                g.setFont(font);
                g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
                        RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
 
                String s = watermark;
                FontMetrics fm = g.getFontMetrics();
                int x = img.getWidth() - fm.stringWidth(s) - 10;
                int y = img.getHeight() - 10;
 
                // 文字背景
                g.setColor(new Color(1f, 1f, 1f, 0.5f));
                int bgx = x - 10;
                int bgy = y - 10 - font.getSize() / 2 - 5;
                g.fillRect(bgx, bgy, img.getWidth() - bgx, img.getHeight()
                        - bgy);
 
                // 文字
                g.setColor(Color.BLACK);
                g.drawString(s, x, y);
 
                ByteArrayOutputStream imgBytes = new ByteArrayOutputStream();
                ImageIO.write(img, "JPG", imgBytes);
                stream.clear();
                stream.setData(imgBytes.toByteArray(), false,
                        PRStream.NO_COMPRESSION);
                stream.put(PdfName.TYPE, PdfName.XOBJECT);
                stream.put(PdfName.SUBTYPE, PdfName.IMAGE);
                stream.put(PdfName.FILTER, PdfName.DCTDECODE);
                stream.put(PdfName.WIDTH, new PdfNumber(width));
                stream.put(PdfName.HEIGHT, new PdfNumber(height));
                stream.put(PdfName.BITSPERCOMPONENT, new PdfNumber(8));
                stream.put(PdfName.COLORSPACE, PdfName.DEVICERGB);
            }
            PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(
                    output_pdf));
            stamper.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (DocumentException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
 
        log.debug("done");
    }
}

あーつかれた。

プログラミング

Eclipseの検索結果(検索ビュー)を複数表示

Published by:

検索ビュー

ガーン・・・・こんなことが出来たなんて知らんかったよ。

検索ビュー

単に、検索ビューの右上に表示される「検索ビューをピン止め」をクリックしておくだけ。
知ってた?みんな知ってたの???(涙)

検索結果一こずつにつき、検索をかけたいとき(たとえばメソッドの参照元検索:Ctrl+G)なんかに便利ですよね。。。

10年前から知っておきたかったなあ、これは。

プログラミング

chromeTouchをGitHubに放流

Published by:

長年気にしながらも完全放置していたchromeTouchを、GitHubへアップしました。

chromeTouch @ GitHub
https://github.com/smilkobuta/chromeTouch

アップしたのは現在リリースされているVer2.9ではなく、スクロールの方式を見直したVer3.0です。
最新版を試したいという手間を惜しまない方は、↑から試してみてくださいませ。。

いつかはオープンソースにしようと、開発当初からコメントも英語でつけていたのですが、こんなにほったらかしになるとは・・・(汗)

フリーで公開していましたので、何十万件ダウンロードされても1円にもならず、ついつい更新も二の次三の次になりがちで、タブレットが一般的に使われるようになった今となっては、もはやナンセンスなソフトウェアになってしまったかもしれません。

でも、PCでGoogle Chromeを使うときはやっぱり便利なので、私自身は使い続けています。
今後どなたかがバージョンアップして下さったりフォークして下さったりしてくれちゃったりしたら、ぜひ使ってみたいです。

プログラミング 学習

JavaScript絵かき歌

Published by:

1.かっこが2つあったとさ~♪
()()

2.後ろにセミコロンもついてきて♪
()();

3.jQueryかな?
()(jQuery);

4.functionだよ♪
(function(){})(jQuery);

5.コインを入れたら♪
(function($){})(jQuery);

6.あっという間にかわいいお財布(容れモノ)のできあがり~♪
(function($){ 
    
})(jQuery);

JavaScriptでグローバル変数を使わない方法で紹介した、正しいJavaScriptコードの書き方を覚えるための絵かき歌(コードかき歌?)です。
こういう順番で書くことを覚えると、いちいちコピペしなくても済みますよ♪

プログラミング

JavaScriptでグローバル変数を使わない方法

Published by:

JavaScriptでグローバル変数を減らす方法という記事がTwitterでリツイートされてきたので、ツッコんでおきます。

↓正しくはこうです。

(function(){
    var x = 1;
    var y = "こぶたのラッパ";
    
    function my_func() {
        alert(y);
    }
    
    my_func();
})();

↓jQueryを使う場合は、こう。

(function($){
    var x = 1;
    var y = "こぶたのラッパ";
    
    $(function(){
        my_func();
    });
    
    function my_func() {
        alert(y);
    }
})(jQuery);

グローバル変数はJavaScript実行環境が提供してくれている window とかを参照するためのもので、自分で定義するものではありません。
JavaScriptコードはコピペしてなんぼのものが多いので、グローバル変数を使わずコピペされやすいコードを書きましょう!