feedly ではてブ数を表示する userscript (1行表示時にも対応)

以前、下記の記事で紹介させていただいたはてぶ数表示の userscript ですが、
feedly ではてなブックマーク数の確認(とはてブページへ) - 弘法にも筆の誤り

一覧表示の時もはてぶ数を確認したくなったので、勉強も兼ねて元スクリプトを読んでみました。
プログラマー人生のほぼ全てを静的言語で歩んできたので、正直javascriptはほとんど読めません。
試行錯誤を繰り返して何とか形になりました。



で、完成系がこんな感じ。
f:id:hiwa4:20130702183302p:plain
chrome のバージョン 27.0.1453.116 m で動作確認しています。
表示場所がなかったので、更新時間の領域に上書きしています。
# マウスオーバーすると場所が変わったり、そのままではクリック出来ないなど問題も多々。。


userscript は以下に置いています。
Feedly にはてぶ数を表示するUserscript

もっと綺麗に書けるんだろうなー。
javascript、難しい。。でも面白い!

Chrome の userscript (とConsole)で jQuery を使う方法

Chrome の userscript は @require を使えないので自前で呼ばないとダメらしい。
知らなかったのでメモメモ。


From:How can I use jQuery in Greasemonkey scripts in Google Chrome? - Stack Overflow


で、上記サイトのコードだと関数がグローバルスコープなので即時関数で囲います。
即時関数については以下のサイトが分かりやすかったです。
知ってて当然?初級者のためのJavaScriptで使う即時関数(function(){...})()の全て - 三等兵
こんな感じ。


ちなみに Chrome の Console 内で jQuery 読み込むには上記のコードから jQuery 読み込みの部分だけ抜き出して Console で以下を実行します。


追記:Chrome のスニペットでもっと楽に!
Chrome スニペット機能を使う - 弘法にも筆の誤り


javascript、楽しくなってきた:-)

JavaEE7とGlassfish4.0でJAX-RSを試してみた

タイトルの通り。
tomcat + Jersey でやってたことと同じ事ができるのか試してみました。

f:id:hiwa4:20130618100841p:plain
新規プロジェクトで「Java Web」=>「Webアプリケーション」



f:id:hiwa4:20130618100855p:plain
次へ。



f:id:hiwa4:20130618100858p:plain
次へ。



f:id:hiwa4:20130618100859p:plain
プロジェクト右クリックから「新規」「パターンからのRESTful~」



f:id:hiwa4:20130618100902p:plain
次へ。



f:id:hiwa4:20130618100907p:plain
リソースパッケージetcを埋めて終了。



f:id:hiwa4:20130618100910p:plain
生成直後はこんな構成。



ShopResource.java を以下の内容に修正。

package example.resource;

import java.util.ArrayList;
import java.util.List;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.Path;
import javax.ws.rs.GET;
import javax.ws.rs.Produces;
import javax.enterprise.context.RequestScoped;
import javax.ws.rs.PathParam;
import javax.ws.rs.core.MediaType;

/**
 * REST Web Service
 *
 * @author Administrator
 */
@Path("Shop")
@RequestScoped
public class ShopResource {

    @Context
    private UriInfo context;

    public ShopResource() {
    }

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public List<Shop> getJson() {
        List<Shop> shopList = new ArrayList<>();
        for (int i = 0; i < 5; i++) {
            Shop shop = new Shop();
            shop.setShopId(String.valueOf(i));
            shop.setShopName("shopName" + i);
            shopList.add(shop);
        }
        return shopList;
    }

    @Path("{shopNo}")
    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Shop getJson2(@PathParam("shopNo") String shopNo) {
        Shop shop = new Shop();
        shop.setShopId(shopNo);
        shop.setShopName("URIから取得したshopです");

        return shop;
    }
}

箱となるクラスを新規作成。

package example.resource;

/**
 *
 * @author iwa4
 */
public class Shop {

    private String shopId;
    private String shopName;

    public String getShopId() {
        return shopId;
    }

    public void setShopId(String shopId) {
        this.shopId = shopId;
    }

    public String getShopName() {
        return shopName;
    }

    public void setShopName(String shopName) {
        this.shopName = shopName;
    }
}

最後に画面。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>JAX-RS test</title>
  </head>
  <body>
    <h1>JAX-RS test</h1>
    <button id="button1">get json!</button>
    <button id="button2">get json2!</button>
    <div id="list"></div>
    <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.0.2/jquery.min.js"></script>
    <script>
      $("#button1").click(function() {
        $.getJSON("webresources/Shop", function(data) {
          for (var i in data) {
            $("#list").append("<li>" + data[i].shopName + "</li>");
          }
        });
      });

      $("#button2").click(function() {
        $.getJSON("webresources/Shop/999", function(data) {
          $("#list").append("<li>" + data.shopName + "</li>");
        });
      });
    </script>
  </body>
</html>

実行してみる。
f:id:hiwa4:20130618113802p:plain
「get json!」「get json2!」を押下すると、それぞれJSONを取得している。



f:id:hiwa4:20130618100919p:plain
動作確認するにはこのテスト・リソースURIが楽だなぁと思いました。



関係ないけど、Rictyフォントに変えてから少し幸せになりました。

テーブルをjQueryでインクリメンタルサーチ

これぐらいだったらライブラリなしで実装できますね。

コールバック関数とか使ったらもっと綺麗に書けるんだろうけど、JavaScriptの言語仕様とAPI理解が足りなひ。
show()とhide()にアニメーションつけるとチラつくし、作りが悪いんだろうなー。

feedly ではてなブックマーク数の確認(とはてブページへ)

20130702追記:feedly ではてブ数を表示する userscript (1行表示時にも対応) - 弘法にも筆の誤り



Google Reader 閉鎖まであと一ヶ月だ。。。

と同じ思いで、はてぶ数確認したいなーと思っていたら、ChromeのUserScriptを書いていらっしゃる方がいました。

Feedly 移行記念、Feedly をはてブ対応させるユーザースクリプト – OTCHY.NET

助かりました!
ちょっとだけ嵌ったんだけど、拡張機能タブ内にjsファイルをドロップしても、file:// で中身を開いてしまい、なんでインストール出来ないのかな、と思っていたら、UserScriptは

*.user.js

のファイル名じゃなきゃダメなんですね。
ダウンロードしたjsファイルの名前を変更してドロップすると、インストールダイアログ出てきました。
短いスクリプトなので、中身も理解しておこう。

Windows で Node.js を始める時のあれこれ

インストール

公式から。
これでNode.js と npm(node package manager) がインストールされる。

>node -v
v0.8.20

npm -v
1.2.11

npm

プロキシ設定

package.json があるディレクトリで npm install を実行すると、依存するパッケージを npm がインストールしてくれる。
ダウンロードされたパッケージは node_modules 以下に配置される。
プロキシ環境で実行する場合は、npmコマンドでプロキシを指定する必要がある。

>npm config set proxy http://PROXY-SERVER:PROXY-PORT
ローカルとグローバル

npm コマンドは -g フラグを付けるとグローバルディレクトリに対して処理が実行される。
グローバルディレクトリの場所は

>npm bin -g
C:\Users\iwa4\AppData\Roaming\npm
(not in PATH env variable)

not in PATH env variable と出てるのは、システム環境変数にパスが通っていないから。
NODE_PATH 環境変数にパスを通せばいい。
# インストール時にグローバルディレクトリにユーザー環境変数のパスが通っているので、
 気にしなくてもおk。

設定確認

上記の内容など、設定した内容は npm config list で見れる。

>npm config list
; cli configs
registry = "https://registry.npmjs.org/"

; userconfig C:\Users\iwa4\.npmrc
proxy = "http://PROXY-SERVER:PROXY-PORT/"

; builtin config undefined
prefix = "C:\\Users\\iwa4\\AppData\\Roaming\\npm"

; node bin location = C:\Program Files\nodejs\\node.exe
; cwd = C:\develop\nodejs-sample
; HOME = C:\Users\iwa4
; 'npm config ls -l' to show all defaults.

デバッグ

デバッグには node-inspector を使う。

>npm -g install node-inspector

最初、-g をつけずにインストールしたところ、

>npm WARN prefer global node-inspector@0.2.0beta4 should be installed with -g

という警告が出た。
この辺りがまだ理解出来ていないのだけど、ローカルにインストールした場合とグローバルにインストールした場合で、生成されるファイルが少し異なっている。
node-inspector.cmd ファイルが出来てなかったり、node-inspector ファイルの中身が異なっていたり。
直接コマンド叩いて起動するものはグローバルディレクトリにインストールした方が無難みたい。


で、デバッグしてみる。

デバッガ起動。

>node-inspector
   info  - socket.io started
visit http://0.0.0.0:8080/debug?port=5858 to start debugging

Node.js起動。

>node --debug example.js
debugger listening on port 5858
http://127.0.0.1:8192/


これで、http://127.0.0.1:8080/debug?port=5858Webkit系のブラウザでアクセスすると、デバッグ用画面が表示される。
あとは、Scripts から js ファイルを選択して、ブレイクポイントを使ってデバッグ

CSV ファイルを マルチテーブル・インサート を使ってインポートする

大量データをDBに取り込む時、Oracleではマルチテーブル・インサートという機能があります。
CSVファイルを1レコードずつ読み込んでDBにINSERT、とかよくありますよね。
現行システムがここで時間かかっていたので、対応したいと思います。

PL/SQL or SQL*Loader の方が早いけど、今回は可能な限り修正コストを抑えたいので、コード修正だけで対応できるこの方法で。

構文はこんな感じ。

insert all
into sample_table (id, name, value) values (1, 'TKISHIMO', 0)
into sample_table2 (id, name, value) values (2, 'MHAYASHI', 0)
select * from dual;

1つのSQL文で複数の表にINSERTする絶品テクニック(1/2) − @IT


では、何件ずつ突っ込めば一番早いんだ?検証してみる。

using Oracle.DataAccess.Client;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;

namespace MultiInsert
{
    class Program
    {
        static void Main(string[] args)
        {
            var connStr = new OracleConnectionStringBuilder();
            connStr.UserID = "UID";
            connStr.Password = "PWD";
            connStr.DataSource = "SID";

            using (var conn = new OracleConnection(connStr.ToString()))
            {
                try
                {
                    conn.Open();
                    //create
                    Execute(String.Format("create table Test({0})", GetNames(true)), conn);

                    var insert = string.Format("insert into Test({0}) values({1})", GetNames(false), GetValue());
                    var sqls = new List<string>();
                    for (int i = 0; i < 50000; i++)
                        sqls.Add(insert);

                    var sw = new Stopwatch();
                    sw.Start();
                    foreach (var sql in sqls)
                        Execute(sql, conn);
                    sw.Stop();
                    Console.WriteLine("   1件ずつinsert : {0}", sw.Elapsed);

                    sw.Reset();
                    sw.Start();
                    MultiExecute(sqls, conn, 10);
                    sw.Stop();
                    Console.WriteLine("  10件ずつinsert : {0}", sw.Elapsed);

                    sw.Reset();
                    sw.Start();
                    MultiExecute(sqls, conn, 100);
                    sw.Stop();
                    Console.WriteLine(" 100件ずつinsert : {0}", sw.Elapsed);

                    sw.Reset();
                    sw.Start();
                    MultiExecute(sqls, conn, 500);
                    sw.Stop();
                    Console.WriteLine(" 500件ずつinsert : {0}", sw.Elapsed);

                    //delete
                    Execute("drop table Test", conn);
                    Console.WriteLine("Press any key...");
                    Console.ReadLine();
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }
            }
        }

        private static void MultiExecute(List<string> sqls, OracleConnection conn, int p)
        {
            var sb = new StringBuilder();
            var array = new string[p];
            for (int i = 0; i < sqls.Count; i += p)
            {
                sqls.CopyTo(i, array, 0, p);
                sb.AppendLine("insert all");
                foreach (var item in array)
                    sb.AppendLine(item.Replace("insert ", ""));

                sb.AppendLine("select * from dual");
                Execute(sb.ToString(), conn);
                sb.Clear();
            }
        }

        static string GetNames(bool isCreate)
        {
            var list = new List<String>();
            var type = isCreate ? "VARCHAR2(50)" : "";
            for (int i = 0; i < 100; i++)
                list.Add(String.Format("V_{0:000} {1}", i, type));
            return String.Join(",", list);
        }

        static string GetValue()
        {
            var list = new List<String>();
            for (int i = 0; i < 100; i++)
                list.Add("'test string'");
            return String.Join(",", list);
        }

        static void Execute(string sql, OracleConnection conn)
        {
            using (var cmd = new OracleCommand(sql, conn))
            {
                cmd.ExecuteNonQuery();
            }
        }
    }
}

結果はこんな感じ。

   1件ずつinsert : 00:01:15.7948220
  10件ずつinsert : 00:00:13.7392012
 100件ずつinsert : 00:00:06.7394553
 500件ずつinsert : 00:01:04.8971647
Press any key...

多すぎても良くないみたい。
だが、1件ずつループでINSERTするよりも断然早い。