SQLの窓

2016年12月24日


いまさらですが、IE9 を含むそれ以前の URL の QueryString の解釈のバグ

なんと無くは知っていたのですが、そうそう遭遇するものでも無く、忘れていました。

まず、ソース上はこうなっています。間違い無く
<img src="img.php?bc=&gt=">
しかし、IE9 にエミュレーションして、開発者ツールで見るとこうなっています
<img src="img.php?bc=>=">
つまり、&gt= が > になってしまっています。本来、セミコロンがあればまだ可能性がありますが、それでも URL 上ではバグです。

結局、一つ前の bc の内容が本来空なのに、>= という値が入ってしまうという凄まじさです。

▼ IE11 でテスト(2016/12/24)




posted by lightbox at 2016-12-24 14:53 | IE | このブログの読者になる | 更新情報をチェックする

VBScript + WMI : ファイルの状態の監視

WMI の典型的なイベント監視のサンプルです。
( リンク先は、Microsoft の TechNet のスクリプト センターです )

ファイル作成の監視
1) C:\scripts フォルダを作成します。
2) 適当な場所にスクリプトを作成します(file_create.vbs)
3) そのフォルダをエクスプローラでSHIFTキーを押しながら右クリックしてコマンドブロンプトを開きます
4) cscript file_create.vbs と実行します
5) C:\scripts でファイルを作成します
strComputer = "."  
Set objWMIService = GetObject("winmgmts:" _  
    & "{impersonationLevel=impersonate}!\\" & _  
        strComputer & "\root\cimv2")  
Set colMonitoredEvents = objWMIService.ExecNotificationQuery _  
    ("SELECT * FROM __InstanceCreationEvent WITHIN 10 WHERE " _  
        & "Targetinstance ISA 'CIM_DirectoryContainsFile' and " _  
            & "TargetInstance.GroupComponent= " _  
                & "'Win32_Directory.Name=""c:\\\\scripts""'")  
Do  
    Set objLatestEvent = colMonitoredEvents.NextEvent  
    Wscript.Echo objLatestEvent.TargetInstance.PartComponent  
Loop  

ファイル変更の監視
strComputer = "."  
Set objWMIService = GetObject("winmgmts:" _  
    & "{impersonationLevel=impersonate}!\\" & _  
        strComputer & "\root\cimv2")  
Set colMonitoredEvents = objWMIService.ExecNotificationQuery _  
    ("SELECT * FROM __InstanceModificationEvent WITHIN 10 WHERE " _  
        & "TargetInstance ISA 'CIM_DataFile' and " _  
            & "TargetInstance.Name='c:\\scripts\\index.vbs'")  
Do  
    Set objLatestEvent = colMonitoredEvents.NextEvent  
    Wscript.Echo "File: " & objLatestEvent.TargetInstance.Name  
    Wscript.Echo "New size: " & objLatestEvent.TargetInstance.FileSize  
    Wscript.Echo "Old size: " & objLatestEvent.PreviousInstance.FileSize  
Loop  
ファイル削除の監視
strComputer = "."  
Set objWMIService = GetObject("winmgmts:" _  
    & "{impersonationLevel=impersonate}!\\" & _  
        strComputer & "\root\cimv2")  
Set colMonitoredEvents = objWMIService.ExecNotificationQuery _  
    ("SELECT * FROM __InstanceDeletionEvent WITHIN 10 WHERE " _  
        & "Targetinstance ISA 'CIM_DirectoryContainsFile' and " _  
            & "TargetInstance.GroupComponent= " _  
                & "'Win32_Directory.Name=""c:\\\\scripts""'")  
Do  
    Set objLatestEvent = colMonitoredEvents.NextEvent  
    Wscript.Echo objLatestEvent.TargetInstance.PartComponent  
Loop  
利用できるディスク領域の監視
Const LOCAL_HARD_DISK = 3  
strComputer = "."  
Set objWMIService = GetObject("winmgmts:" _  
    & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")  
Set colMonitoredDisks = objWMIService.ExecNotificationQuery _  
    ("Select * from __instancemodificationevent within 30 where " _  
        & "TargetInstance isa 'Win32_LogicalDisk'")  

Do 
    Set objDiskChange = colMonitoredDisks.NextEvent  
    If objDiskChange.TargetInstance.DriveType = LOCAL_HARD_DISK Then  
        If objDiskChange.TargetInstance.Size < 100000000 Then  
            Wscript.Echo "Hard disk space is below 100000000 bytes."  
        End If  
    End If  
Loop  



posted by lightbox at 2016-12-24 14:34 | VBS + WMI | このブログの読者になる | 更新情報をチェックする

2016年12月18日


シャットダウンダイアログを表示する / ログオフ・リブート・シャットダウン / VBScript

※ Windows10 でも動作確認しました



Set objShell = CreateObject("Shell.Application")
objShell.ShutdownWindows()


▼ 右クリックから保存して下さい。
ブラウザでダウンロード
※ クリックすると、新しいウインドウで『プレーンテキスト(text/plain)』として開きます
ログオフ
シャットダウン
リブート
パワーオフ(こちらの環境では未確認)

logoff.vbs
Set colOperatingSystems = _
GetObject("winmgmts:{(Shutdown)}").ExecQuery( _
"Select * from Win32_OperatingSystem") 
For Each objOperatingSystem in colOperatingSystems 
	ObjOperatingSystem.Win32Shutdown(0) 
Next


関連するスクリプト

ログオフ・リブート・シャットダウン



posted by lightbox at 2016-12-18 17:04 | VBS + Shell | このブログの読者になる | 更新情報をチェックする

2016年12月17日


Android Studio の追加日本語化用に、キャラクタセットに依存しないコード文字列を作成するツールを作成しました

PHP で作ると大げさなので、jQuery で作成しました。元に戻したい時はデベロッパーツールで console.log すればいいと思います。ソースコードは、記事の最後にあります。ここでは、サンプルとして表示する為に、テキストエリアのサイズを小さくしているので、実際に使う場合はこちらからどうぞ。

Android Studio の日本語化は、『ANDROID STUDIO 2.0 を日本語化してみた』 で入手できるもので十分ですが、自分用に表現方法を変えたい場合は、こういう文字列が必要になります。


▼ 結果の文字列( クリックすると選択します )


▼ テスト用文字列( クリックすると選択します / デベロッパーツールのコンソールで実行用 )




ソースコード
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script>
$(function(){

	var text;

	$("#convert").on( "click", function(){
		text = "";
		var base = $("#text").val();
		var charCode = 0;
		for( i=0; i < base.length; i++ ) {
			charCode = base.charCodeAt(i);
			if ( charCode < 0x7f ) {
				text += base.charAt(i);
			}
			else {
				text += "\\u" + ( '0000' + base.charCodeAt(i).toString(16) ).slice( -4 );
			}
		}
		$("#result").val( text );

		$("#test_string").val("console.log('" + text + "')");
	});

//	$("#check").on( "click", function(){
//		eval("var x = \"" + $("#result").val() +"\"");
//		alert( x );
//	});

});
</script>
<pre>
<input id="convert" type="button" value="日本語を文字列内用コードに変換">
<textarea id="text" style='width:90%;height:100px;margin-top:5px;font-size:16px;'>abc 日本語を文字列内用コードに変換 123</textarea>
▼ 結果の文字列( クリックすると選択します )
<textarea id="result" style='width:90%;height:200px;font-size:16px;' onclick='this.select()'></textarea>
<!--input id="check" type="button" value="alert で表示"-->
▼ テスト用文字列( クリックすると選択します / デベロッパーツールのコンソールで実行用 )
<textarea id="test_string" style='width:90%;height:200px;font-size:16px;' onclick='this.select()'></textarea>




</pre>
その場で結果を見るコードとして、コメント内で eval を使った部分があります。ですが、一般的にはデベロッパーツールで確認するのがいいでしょう。

\unnnn (nは数字) というフォーマットでないと文字列としてエラーになるので eval が必要でした。




posted by lightbox at 2016-12-17 16:24 | Comment(0) | jQuery | このブログの読者になる | 更新情報をチェックする

2016年12月16日


Amazon API の 503エラー の対処について

長く使ってなかった Amazon の 商品情報を取得するコードを実行していたら、商品単位で一回目のアクセスに、かなりの確率で 503 エラーで失敗するという現象に出くわしました。ページをリロードすると、たいていは表示されますが、リロードできない仕様のページもあるので調べてみると、『Amazonマーケットプレイス Web サービス (Amazon MWS) ドキュメント』にこんな事が書いてありました

500エラー、または503エラーを受信後、オペレーションの呼び出しをリトライする場合は、最初のエラーレスポンス直後にリトライすることができます。複数回リトライする場合、Amazonでは最大リトライ回数4回の「Exponential backoff」(指数関数的後退)によるアプロ―ディを推奨します。その後エラーを記録し、手動のフォローアップと調査を進めます。の例えば、リトライの時間を、1秒、4秒、10秒、30秒の間隔で計ることができます。実際の後退時間と制限は、あなたのビジネスプロセスによって異なります。
という事で、手動のリロードは1秒程度なので、1秒づつ待って4回リトライして正常動作を確認しました。
if ( !$dom->load($req2) ) {
	sleep(1);
	if ( !$dom->load($req2) ) {
		sleep(1);
		if ( !$dom->load($req2) ) {
			sleep(1);
			if ( !$dom->load($req2) ) {
				sleep(1);
				if ( !$dom->load($req2) ) {
					print "<b style='color:white;font-size:24px;'>リロードして下さい <input type='button' value='リロード' onclick='location.reload(true)'> </b>";
				}
			}
		}
	}

}




posted by lightbox at 2016-12-16 09:40 | Comment(0) | API | このブログの読者になる | 更新情報をチェックする

2016年12月13日


Seesaa ブログのカテゴリ管理画面で、ブラウザのコンソールを使って jQuery で順序をソートする

Seesaa ブログのカテゴリ管理画面で、ブラウザのコンソールを使って 10 番毎の数字にリセットする の続きですが、ソートするとなるといったん配列にデータをため込む必要があります。

ここでは、_sortdata と言う変数を使用していますが、なんでもかまいません。Seesaa のカテゴリ管理画面で F12 でデベロッパーツールを開き、_sortdata が存在しない事を確かめればいいです。

ソートするので、sort メソッドを使用しますが、ソート対象はオブジェクトになるので、比較関数を実装する事になります。

オブジェクトは、{ title: "文字列", sort: jQueryの番号フィールドのオブジェクト } と言う形式で作成しているので、以下のソースのように title だけ見てソートさせます。

そののち、jQuery の $.each と言う、配列の処理用のメソッドを使ってソートされた順に数値をセットしていくだけです。



$(this).parent().parent().find("input") は、$(this) が td の中の アンカーです。その親の親となるのは、テーブルの tr になるわけです。なので、その中から必要な 入力フィールドを find で取得しています。
var _sortdata = [];
$(".wordlimit").each(function(){
   _sortdata.push({ title: $(this).text(), sort: $(this).parent().parent().find("input") })
});
_sortdata.sort(function(a,b){
   if ( a.title < b.title ) {
      return -1;
   }
   else {
      return 1;
   }
});
$.each(_sortdata,function(idx,val){
   _sortdata[idx].sort.val( idx*10+100 );
})
※ Google Chrome で、コンソールでタイプして作成しました




Seesaa独自タグ簡易リファレンス

タグ:jquery Seesaa
posted by lightbox at 2016-12-13 19:18 | Comment(0) | Seesaa プログ管理支援 | このブログの読者になる | 更新情報をチェックする

Seesaa ブログのカテゴリ管理画面で、ブラウザのコンソールを使って 10 番毎の数字にリセットする

こえいう作業に、jQuery は最適で、いまどきはどこでも jQuery がページで使えることが多いです。Seesaa の管理画面でも使用可能なので、F12 でコンソールを開けて、まず入力フィールドのグループを取得します。

F12 で開いているデベロッパーツールのインスペクタで入力フィールドを調べれば、対象の入力フィールドは以下の記述で取得できる事が解ります。
$( "input[name*='sort_number']" )

これだけでは、目的は達成できないので、おのおののフィールド毎の処理にする為、.each でループ処理にします。
$( "input[name*='sort_number']" ).each(function(){
   console.log( $(this).val() );
})

これで目的はほぼ達成されたようなものですが、function(idx){} という連番が使えるので以下のようにすると完成です。
$( "input[name*='sort_number']" ).each(function(idx){
   $(this).val(idx*10+100);
})

ぜひ、Seesaa のカテゴリ管理画面で実行してみてください。

ちなみに、この方式で行くと『リンク』は以下のようになります
$( "input[name$='content_link__sort_number']" ).each(function(idx){
   $(this).val(idx*10+100);
})
※ エキスパートモードからでないと、失敗する可能性があります。



Seesaa独自タグ簡易リファレンス

posted by lightbox at 2016-12-13 12:54 | Comment(0) | Seesaa プログ管理支援 | このブログの読者になる | 更新情報をチェックする

2016年12月11日


jQuery で呼び出した PHP で twitteroauth を使用してツイート(画像も簡単)するサンプル

基本的にブラウザとサーバの直接的なやりとりでサーバに処理をさせるのは、アプリケーションとして必ず複雑になり、メンテナンスにも労力を費やす事となるので、jQuery が前提となる環境では、$.ajax を使用するのが何より簡単になります。

abraham/twitteroauth

twitteroauth を使えば、PHP 側では簡単にツイートが可能になり、画像のアップロードも $.ajax で行えばとてもシンプルに機能を果たす事ができます。

ここでは、全体を説明しませんが、Bootstrap を画面に使用し、スマホ対応が容易になっており、また、だからこそ $.ajax との親和性も高くなっています。

$.ajax 呼び出し部分
	// *************************************
	// 送信ボタン
	// *************************************
	$("#frm").submit( function(event){
		// 本来の送信処理はキャンセル
		event.preventDefault();

		$("#post_check").modal();

	} );


	// **************************************
	// Bootstrap OK ボタン
	// **************************************
	$("#data_post").on("click", function(){

		// エラーメッセージエリアをクリア
		$(".error").next().text( "" );

		// 結果の表示エリアを全てクリア
		$("#result").html( "" );

		// **************************************
		// サーバへ送信
		// **************************************

		// 新規送信用オブジェクト
		var formData = new FormData();

		// 送信フィールド作成
		formData.append("text", $("#row1_fld").val());

		// **************************************
		// サーバ呼び出し
		// **************************************
		$.ajax({
			url: "./post_action.php",
			type: "POST",
			data: formData,
			processData: false,
			contentType: false
		})
		.done(function( data, textStatus ){
			console.log( "status:" + textStatus );
			console.log( "data:" + JSON.stringify(data, null, "    ") );
			options.info("処理が完了しました");

		})
		.fail(function(jqXHR, textStatus, errorThrown ){
			console.log( "status:" + textStatus );
			console.log( "errorThrown:" + errorThrown );
			options.info("アップロードに失敗しました");
		})
		.always(function() {

		})
		;

	});
Bootstrap では、Form ありきで画面設計されているので、その機能を十分に使用できるように、submit イベントで event.preventDefault() を実行し、処理は Bootstrap(JS) のダイアログ側で呼び出しています。

PHP 側の処理は、ツイートするのみの post_action.php が行います。

post_action.php
<?php
// *************************************
// キャラクタセット
// *************************************
header( "Content-Type: application/json; charset=utf-8" );
// *************************************
// キャッシュ無効
// *************************************
session_cache_limiter('nocache');
session_start();


// *************************************
// ライブラリ 
// https://twitteroauth.com/
// *************************************
require "twitteroauth/autoload.php";
use Abraham\TwitterOAuth\TwitterOAuth;
 
// *************************************
// API 情報
// https://apps.twitter.com
// *************************************
$consumer_key			= "";
$consumer_secret		= "";
$access_token			= "";
$access_token_secret	= "";
 
// *************************************
// POST
// *************************************
$connection = new TwitterOAuth($consumer_key, $consumer_secret, $access_token, $access_token_secret);
$result = $connection->post("statuses/update", ["status" => $_POST['text'] ]);

// *************************************
// POST 画像
// *************************************
/*
$connection = new TwitterOAuth($consumer_key, $consumer_secret, $access_token, $access_token_secret);
$media1 = $connection->upload('media/upload', ['media' => 'images/image1.png']);
$media2 = $connection->upload('media/upload', ['media' => 'images/image2.png']);
$parameters = [
	'status' => '画像投稿です https://twitteroauth.com/ サンプルそのまま',
	'media_ids' => implode(',', [$media1->media_id_string, $media2->media_id_string])
];
$result = $connection->post('statuses/update', $parameters);
*/

$_POST['result'] = $result;
 

// *************************************
// PHP の結果を result キーで
// JSON としてブラウザに返す
// *************************************
print json_encode($_POST , JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT );


?>

ソースコードを解りやすくするために、コメント内で固定の画像を含めたツイートの処理があります。(実際は、画像データが jQuery の $.ajax で送られて来るようにします。)

API 情報は、Twitter のページの右下にあるリンクの『開発者』から移動し、My apps でアプリケーションを作成して Keys and Access Tokens のタブより取得するわけですが、昔は無かったモバイルの登録が必要になります。

モバイルの登録は、元の Twitter のページの『設定』にありますが、ソフトバンクのスマホから電話番号を登録する場合は注意が必要です。

デフォルトでは海外から通信を遮断している

My Softbank の設定で海外からの受信の拒否を解除する必要がありますが、やはり海外からは拒否したいのが普通ですから、登録後は元に戻しておいたほうがいいと思います。

迷惑メールフォルダ機能を使っている場合

登録されていないところからのメールは迷惑フォルダに入って気が付かない可能性もあるので注意です。



タグ:jquery twitter PHP
posted by lightbox at 2016-12-11 02:08 | Comment(0) | PHP + Twitter | このブログの読者になる | 更新情報をチェックする

2016年12月05日


Android Studio で Twitter4J で ListView に検索結果を表示する



Twitter4J

非同期処理は、常に TwitterListener を作成して、AsyncTwitter からの実行を リスナー側で受けるという形になります。( 今回の場合、searched(QueryResult queryResult) で受けて、search(Query query) で呼び出す )

関連する記事

Android Studio で Twitter4J で画像付きツイート

注意する事
1) トークンの保存場所が、app\src\main\resources の twitter4j.properties

2) TwitterListener で受けたところから画面にアクセスするには、UI スレッドに対する考慮が必要
   ( runOnUiThread メソッドが簡単 )

3) ライブラリは twitter4j-core-4.0.4.jar と twitter4j-async-4.0.4.jar をコピーして core のみ Gradle に登録
MainActivity
public class MainActivity extends AppCompatActivity {

    // リストビュー
    private MyArrayAdapter adapter;
    private ListView listview;

    // 日付データ用
    private Calendar cal;
    private SimpleDateFormat sf;

    // Twitter 用
    private TwitterListener listener;
    private AsyncTwitter asyncTwitter;
    private ArrayList<TwitterData> twitterData;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        // アダプタを作成
        adapter = new MyArrayAdapter(MainActivity.this,R.layout.list_item);

        // リストビューの取得
        listview = (ListView) MainActivity.this.findViewById(R.id.listView);
        // リストビューにデータを表示
        listview.setAdapter(adapter);

        Button buttonSearch = (Button) MainActivity.this.findViewById(R.id.buttonSearch);
        buttonSearch.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                adapter.clear();
                loadDataList();
            }
        });

        cal = Calendar.getInstance();
        sf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
        // リスナーを作成する
        listener = new TwitterAdapter() {
            @Override
            public void searched(QueryResult queryResult) {

                twitterData = new ArrayList<TwitterData>();
                List<Status> list = queryResult.getTweets();

                Iterator<Status> it = list.iterator();
                while( it.hasNext() ) {

                    Status statudData = it.next();

                    twitterData.add(new TwitterData(
                        // ScreenName と Name
                        String.format("%s : %s", statudData.getUser().getScreenName(), statudData.getUser().getName()),
                        sf.format(statudData.getCreatedAt()),
                        statudData.getText()));

                }

                // UI スレッドで アダプタにデータをセット
                MainActivity.this.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        adapter.addAll(twitterData);
                    }
                });


            }

            @Override
            public void onException(TwitterException te, TwitterMethod method) {

                Log.i("lightbox", "onException");
                te.printStackTrace();

            }

        };

        // リスナーを登録する
        AsyncTwitterFactory factory = new AsyncTwitterFactory();
        asyncTwitter = factory.getInstance();
        asyncTwitter.addListener(listener);

    }

    // *****************************************
    // Twitter から リストビューにデータを表示
    // *****************************************
    public void loadDataList() {

        EditText editSearch = (EditText) MainActivity.this.findViewById(R.id.editSearch);
        String searchString = editSearch.getText().toString();

        Query query = new Query(searchString);
        asyncTwitter.search(query);


    }
}


MyArrayAdapter
public class MyArrayAdapter extends ArrayAdapter<TwitterData> {

	// コンストラクタで渡された画面の保存
	private int mResource;
	// 画面作成用
	LayoutInflater mInflater;

	public MyArrayAdapter(Context context, int resource) {
		super(context, resource);
		// ArrayAdapter でも、このようにして保存して利用してます
		mResource = resource;
		mInflater = LayoutInflater.from(context);
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {

		if (convertView == null) {
			convertView = mInflater.inflate(mResource, parent, false);
		}

		// アダプターより行データを取得
		TwitterData twitterData = MyArrayAdapter.this.getItem(position);

		// 画面にデータをセット
		TextView tv;

		// キー
		tv = (TextView) convertView.findViewById(R.id.textKey);
		tv.setText(twitterData.getScreenName());

		tv	= (TextView) convertView.findViewById(R.id.textItem1);
		tv.setText(twitterData.getStringDate());

		tv = (TextView) convertView.findViewById(R.id.textItem2);
		tv.setText(twitterData.getText());

		// 行の画面をシステムに返す
		return convertView;
	}

}


TwitterData
public class TwitterData {

	private String stringDate;
	private String screenName;
	private String text;

	public TwitterData(String screenName, String stringDate, String text) {
		this.screenName = screenName;
		this.stringDate = stringDate;
		this.text = text;
	}

	public String getScreenName() {
		return screenName;
	}

	public void setScreenName(String screenName) {
		this.screenName = screenName;
	}

	public String getStringDate() {
		return stringDate;
	}

	public void setStringDate(String stringDate) {
		this.stringDate = stringDate;
	}

	public String getText() {
		return text;
	}

	public void setText(String text) {
		this.text = text;
	}
}




posted by lightbox at 2016-12-05 19:16 | Comment(0) | Android Studio 2016 | このブログの読者になる | 更新情報をチェックする
Seesaa の各ページの表示について
Seesaa の 記事がたまに全く表示されない場合があります。その場合は、設定> 詳細設定> ブログ設定 で 最新の情報に更新の『実行ボタン』で記事やアーカイブが最新にビルドされます。

Seesaa のページで、アーカイブとタグページは要注意です。タグページはコンテンツが全く無い状態になりますし、アーカイブページも歯抜けページはコンテンツが存在しないのにページが表示されてしまいます。

また、カテゴリページもそういう意味では完全ではありません。『カテゴリID-番号』というフォーマットで表示されるページですが、実際存在するより大きな番号でも表示されてしまいます。

※ インデックスページのみ、実際の記事数を超えたページを指定しても最後のページが表示されるようです

対処としては、このようなヘルプ的な情報を固定でページの最後に表示するようにするといいでしょう。具体的には、メインの記事コンテンツの下に『自由形式』を追加し、アーカイブとカテゴリページでのみ表示するように設定し、コンテンツを用意するといいと思います。


※ エキスパートモードで表示しています

アーカイブとカテゴリページはこのように簡単に設定できますが、タグページは HTML 設定を直接変更して、以下の『タグページでのみ表示される内容』の記述方法で設定する必要があります

<% if:page_name eq 'archive' -%>
アーカイブページでのみ表示される内容
<% /if %>

<% if:page_name eq 'category' -%>
カテゴリページでのみ表示される内容
<% /if %>

<% if:page_name eq 'tag' -%>
タグページでのみ表示される内容
<% /if %>
この記述は、以下の場所で使用します


Windows
container 終わり

フリーフォントで簡単ロゴ作成
フリーフォントでボタン素材作成
フリーフォントで吹き出し画像作成
フリーフォントではんこ画像作成
ほぼ自由に利用できるフリーフォント
フリーフォントの書体見本とサンプル
画像を大きく見る為のウインドウを開くボタンの作成

Android SDK ポケットリファレンス
改訂版 Webデザイナーのための jQuery入門
今すぐ使えるかんたん ホームページ HTML&CSS入門
CSS ドロップシャドウの参考デモ
Google Hosted Libraries
cdnjs
BUTTONS (CSS でボタン)
イラストAC
ぱくたそ
写真素材 足成
フリーフォント一覧
utf8 文字ツール
右サイド 終わり
base 終わり