「String」を含む日記 RSS

はてなキーワード: Stringとは

2008-06-12

*[Java][Python]

javaからpythonスクリプトの構文チェックをするメソッドを作りたいんだけど、

スクリプトを実行しないで構文チェックだけする方法知ってる人いる?

イメージ

boolean isCollectGrammar( String strPythonScriptFilename ){
   ????
}

みたいな感じ。

jythoncあたりを利用してうまくいかないものかと試してるんだけどなかなかうまくいかず。。

org.jython.parserとかorg.jython.compilerあたりを使うとイケるのかなぁ。。

2008-05-13

GuiceSeasar2 を連携させてみたよ

[参考文献]

    S2 は、.dicon ファイルで定義をだいぶ簡略化できる。パフォーマンスはどうなんだろう。誰かテストしてくれいw

    app.dicon

    <?xml version="1.0" encoding="UTF-8" ?>

    <!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN" "http://www.seasar.org/dtd/components24.dtd">

    <components namespace="client">

    <include path="hello.dicon" />

    <component class="org.seasar.guice.Client" />

    </components>

    hello.dicon

    <?xml version="1.0" encoding="UTF-8" ?>

    <!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.4//EN"

    "http://www.seasar.org/dtd/components24.dtd">

    <components initializeOnCreate="false">

    <component class="org.seasar.guice.HelloServiceImpl" />

    </components>

    HelloService.java、HelloServiceImpl.java は、上記 ITPro と内容が同じなので省略。

    Module.java

    package org.seasar.guice;

    import org.seasar.framework.container.S2Container;

    import org.seasar.framework.container.SingletonS2Container;

    import org.seasar.framework.container.factory.S2ContainerFactory;

    import com.google.inject.AbstractModule;

    import com.google.inject.name.Names;

    public class Module extends AbstractModule {

    S2Container container = null;

    public Module(S2Container container){

    this.container = container;

    }

    @Override

    protected void configure() {

    bind(S2ContainerFactory.class).annotatedWith(Names.named(container.getPath()));

    bind(Client.class).toInstance(SingletonS2Container.getComponent(Client.class));

    }

    }

    Client.java

    package org.seasar.guice;

    public class Client {

    private HelloService helloService = null;

    public void setHelloService(HelloService helloService) {

    this.helloService = helloService;

    }

    public void execute() {

    helloService.sayHello();

    }

    }

    Main.java

    package org.seasar.guice;

    import org.seasar.framework.container.S2Container;

    import org.seasar.framework.container.factory.SingletonS2ContainerFactory;

    import com.google.inject.Guice;

    import com.google.inject.Injector;

    public class Main {

    private static final String PATH = ".\\app.dicon";

    public static void main(String[] args) {

    SingletonS2ContainerFactory.setConfigPath(PATH);

    SingletonS2ContainerFactory.init();

    S2Container container = SingletonS2ContainerFactory.getContainer();

    Module module = new Module(container);

    Injector injector = Guice.createInjector(module);

    Client client = injector.getInstance(Client.class);

    client.execute();

    }

    }

    実行結果

    java -cp ?? org.seasar.guice.Main

    2008/05/13 21:19:22 org.seasar.framework.log.Logger info

    情報: Running on [ENV]product, [DEPLOY MODE]Normal Mode

    Hello, world!

    実行環境JDK 7 (build 1.7.0-ea-b24)

    2008-03-14

    public class Main {
        public static void main( String[] args ) {
            // ( 5 - 3 ) + 1
            Exp exp = new Add(new Sub(new Num(5), new Num(3)), new Num(1));
            System.out.println(exp.eval());
        }
    }
    
    
    /**
     * 抽象クラス
     */
    abstract class Exp {
        public abstract int eval();
    }
    
    
    /**
     * 足し算
     */
    class Sub extends Exp {
    
        /** 左辺 */
        private Exp hidari;
        /** 右辺 */
        private Exp migi;
    
        /**
         * コンストラクタ
         */
        public Sub(Exp hidari, Exp migi){
            this.hidari = hidari;
            this.migi = migi;
        }
    
        /**
         * 評価
         */
        @Override
        public int eval() {
            return hidari.eval() - migi.eval();
        }
    
    }
    
    
    /**
     * 引き算
     */
    class Add extends Exp {
    
        /** 左辺 */
        private Exp hidari;
        /** 右辺 */
        private Exp migi;
    
        /**
         * コンストラクタ
         */
        public Add(Exp hidari, Exp migi){
            this.hidari = hidari;
            this.migi = migi;
        }
    
        /**
         * 評価
         */
        @Override
        public int eval() {
            return hidari.eval() + migi.eval();
        }
    }
    
    
    /**
     *
     */
    class Num extends Exp {
    
        /**
         *
         */
        private int self;
    
        /**
         * コンストラクタ
         */
        public Num(int self) {
            this.self = self;
        }
    
        /**
         * 評価
         */
        @Override
        public int eval() {
            return self;
        }
    
    }
    

    2008-03-08

    [][greasemonkey][seahorse]はてブのhotentryで、2chコピペブログや「ネタ」を削除す...勝手に改造

    firefoxでしか確認していないけれど、URL正規表現XPathで指定できる様にしてみたよ。

    // ==UserScript==
    // @name           filter for Hatena::Bookmark
    // @namespace      http://anond.hatelabo.jp/
    // @include        http://b.hatena.ne.jp/hotentry*
    // @include        http://b.hatena.ne.jp/entrylist*
    // origin http://anond.hatelabo.jp/20080302214727
    // ==/UserScript==
    (function(){
    	var itemxpath = "//div[@class='entry']";
    	function xpathgenURL(url) {return "//div[@class='entry' and descendant::a[starts-with(@href,'"+url+"')]]"}
    	var filters = [
    		// start with '//' then xpath
    		// moconico douga
    //		{"tag": "div", "name": "entry", "pattern": "nicovideo\.jp"},
    		"//div[@class='entry' and descendant::a[contains(@href,'nicovideo.jp')]]",
    /*
    		// tag of "2ch"
    		{"tag": "a", "name": "tag", "pattern": "2ch", "parentNum": HatebuTagParentNum},
    		{"tag": "a", "name": "tag", "pattern": "\\*2ch", "parentNum": HatebuTagParentNum},
    ***/
    		// start with 'http' then url
    		// 2ch blogs  
    		//  livedoor
    //		{"tag": "div", "name": "entry",
    //			"pattern": /http:\/\/blog\.livedoor\.jp\/(insidears|dqnplus)\//},
    		"http://blog.livedoor.jp/insidears/",
    		"http://blog.livedoor.jp/dqnplus/",
    //		{"tag": "div", "name": "entry",
    //			"pattern": /http:\/\/(guideline|alfalfa|news4vip)\.livedoor\.biz\//},
    		"http://guideline.livedoor.biz/",
    		"http://alfalfa.livedoor.biz/",
    		"http://news4vip.livedoor.biz/",
    		// typeof /regexp/ is function (@firefox) then regexp pattern
    		//  fc2
    //		{"tag": "div", "name": "entry",
    //			"pattern": /http:\/\/(urasoku|news23vip|waranote|vipvipblogblog|netanabe|res2ch|kanasoku|tenkomo)\.blog\d+\.fc2\.com\//},
    		/http:\/\/(urasoku|news23vip|waranote|vipvipblogblog|netanabe|res2ch|kanasoku|tenkomo)\.blog\d+\.fc2\.com\//,
    
    		// tag of "neta"
    //		{"tag": "a", "name": "tag", "pattern": "ネタ", "parentNum": HatebuTagParentNum},
    		"//div[@class='entry' and descendant::a[@class='tag' and string()='ネタ']]",
    //		{"tag": "a", "name": "tag", "pattern": "*ネタ", "parentNum": HatebuTagParentNum},
    		"//div[@class='entry' and descendant::a[@class='tag' and string()='*ネタ']]",
    
    		// hatena anonymouse diary
    //		{"tag": "div", "name": "entry", "pattern": /http:\/\/anond\.hatelabo\.jp\//}
    		"http://anond.hatelabo.jp/",
    	];
    
    	for (var i=0; i<filters.length; i++) {
    		var filter = filters[i];
    		var type = typeof filter;
    		var regexp;
    		var xpath;
    		if (type == "function") {
    			xpath = itemxpath;
    			regexp = filter;
    		} else if (type == "string") {
    			if (filter.match(/^http/)) {
    				xpath = xpathgenURL(filter);
    			} else if (filter.match(/^\/\//)) {
    				xpath = filter;
    			} else {
    				next;
    			}
    		}
    		var removeNodes = document.evaluate(xpath,document,null,XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,null);
    		for (var j=0; j<removeNodes.snapshotLength; j++) {
    			var node = removeNodes.snapshotItem(j);
    			if (!regexp || node.innerHTML.match(regexp)) {
    				node.parentNode.removeChild(node);
    			}
    		}
    	}
    })();
    

    ついでに増田版も作ってみたよ。

    // ==UserScript==
    // @name           filter for Hatelabo::AnonymousDiary
    // @namespace      http://anond.hatelabo.jp/
    // @include        http://anond.hatelabo.jp/
    // @include        http://anond.hatelabo.jp/*?page=*
    // @exclude        http://anond.hatelabo.jp/YourID/*
    // ==/UserScript==
    // origin http://anond.hatelabo.jp/20080302214727
    (function(){
    	var itemxpath = "//div[@class='section']";
    	function xpathgenURL(url) {return "//div[@class='section' and descendant::a[starts-with(@href,'"+url+"')]]"}
    	var filters = [
    		// start with '//' then xpath
    		"//div[@class='section' and child::h3[starts-with(string(),'■はてな嫌われ者!')]]",
    		// start with 'http' then url
    		"http://anond.hatelabo.jp/",
    		// typeof /regexp/ is function (@firefox) then regexp pattern
    		/釣り/,
    	];
    
    	for (var i=0; i<filters.length; i++) {
    		var filter = filters[i];
    		var type = typeof filter;
    		var regexp;
    		var xpath;
    		if (type == "function") {
    			xpath = itemxpath;
    			regexp = filter;
    		} else if (type == "string") {
    			if (filter.match(/^http/)) {
    				xpath = xpathgenURL(filter);
    			} else if (filter.match(/^\/\//)) {
    				xpath = filter;
    			} else {
    				next;
    			}
    		}
    		var removeNodes = document.evaluate(xpath,document,null,XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,null);
    		for (var j=0; j<removeNodes.snapshotLength; j++) {
    			var node = removeNodes.snapshotItem(j);
    			if (!regexp || node.innerHTML.match(regexp)) {
    				node.parentNode.removeChild(node);
    			}
    		}
    	}
    })();
    

    2008-03-03

    []内部的に数値か文字かを判別する

    どうーでもいいーですよー。

    どうでもいい話ー、聞いてください。

    Perlというやつは一応内部的には数値か文字列かをちゃんと分けて変数の管理をしているのです。

    でわ、現在ある変数が内部的に数値なのか?内部的に文字列なのか?判別しようと思ったらどうしますか?

    こうしてみます。

    
     my @data = (
         100,      # 100は内部的に数値
         '200'     # 200は内部的に文字
     );
     
     foreach my $d ( @data ) {
         if( ($d ^ $d) eq '0' ){
             print $d . " = It's numeric\n";
         }
         else {
             print $d . " = It's string\n";
         }
     }
    
    

    同じ変数同士を排他的論理和(^)すると、その変数が数値の場合は0になり、その変数が文字列の場合は空文字になるのです。

    なぜかって?そりゃ同じ値同士で排他的論理和したら必ず00000000になるでしょう?

    で00000000は、数値なら数字の0だし、文字列なら制御コードのNUL文字になるので上記のような処理が成り立つというわけです。

    あってますよね?

    ってか判別できたからなんだというんだと問われたらぐうの音すら出ません。まったくもってどうでもいい話でした。

    プログラ増田のあなぐら

    2008-02-21

    Java String#replace系の罠

    string.replace("target", "replace");
    

    ってやれば置換してくれるのかと思ってた。

    string = string.replace("target", "replace");
    

    こうしないと意味ないことに10分悩んで気づいた。

    2008-02-03

    Attacking cgi.rb

    cgi.rb がいかに駄目なライブラリか、という話。

    もちろん、反論もあるだろう。たとえば「Defending PHP」とか。

    でも、個人的にはやはり否定側の方が筋が通ってる印象かな。

    特に「ruby初心者に学びやすい(と言われていることが問題である)」という部分に共感する。 ruby初心者に簡単かもしれないが、初心者による手を抜いたWebアプリケーションrubyが作られた当初はともかく、現代では害悪ではないだろうか。

    Webアプリケーションをなめるな

    cgi.rbならではの理由がないわけではないことはわかる。標準添付されているとか、デプロイが簡単とか。

    でも、「標準添付」を一般公開されるWebアプリケーションを開発するためのライブラリとしての利点にするのはもうやめようよ。

    追記

    「どのライブラリで書いてもおかしなコードを書く奴は書く」という指摘もあった。それは言うまでもない事実ではある。そこには反論しない。

    が、本当に問題なのは、世の中には「おかしなコードを書くことを助長するライブラリ」もあるという点だ。で、そういうライブラリにはおおむね「標準添付」というラベルがついている。どういうわけだか。

    たぶん、「初心者がおかしなコードを書くのをじゃましない」とかあるいは「初心者っぽいコードを積極的に支援する」から、「標準添付」って呼ばれるんだろう。もしくは「設計者がまだ初心者」とか。

    そういうライブラリ存在しちゃいけないとは言わないけど(人に迷惑をかけない範囲で)、ここ半世紀のライブラリ進化をないがしろにするのはもったいないと思うな

    http://www.rubyist.net/~matz/20080126.html#p04

    2007-11-09

    Pythonではなぜ string.len() でなく len() なのか?

    http://anond.hatelabo.jp/20071021143442

    その理由は知らないが、なければ作ればいいじゃないか。

    class MyString(str):
        def length(self):
            return len(self)
    

    というクラスを作って

    string = MyString("Hello world")
    print string.count("o"), string.length()
    

    Rubyライクにやれば

    2 11

    とでるよ。え、リストもlist.length()が使いたいって?それも簡単。

    class MyList(list):
        def length(self):
            return len(self)
    
    l = MyList([1, 2, 3, 4, 5, 6])
    l.length()
    

    6

    きちんと他のメソッドも使えるよ。

    l[1:]
    

    [2, 3, 4, 5, 6]

    l.reverse()
    l
    

    [6, 5, 4, 3, 2, 1]

    ね。簡単でしょ。

    Pythonは仕組みが統一されているものが多いので、いじりやすいのですよ。上の例のやつは組み込みクラスオブジェクトユーザー定義のクラスオブジェクトがおおむね統一されているからこそ簡単にできる。他にも関数なんかもほかのオブジェクトと同じオブジェクトなので、高階関数なんてもの簡単に作ることができて関数プログラミングぽくできる。例えば今はなきapply関数なんかは

    def myApply(func, *args):
        return func.__call__(*args)
    

    と定義できる。実際に

    def sumUpThree(num1, num2, num3):
        return num1 + num2 + num3
    

    でためしてみる。

    myApply(sumUpThree, 1, 2, 3)
    

    結果はちゃんと

    6

    とでる。将来廃止されそうなmap関数も簡単に定義できる。他にも複数の引数をもつ関数の部分適用のようなことを行う関数も次のように簡単に定義できる。

    def partial(func, *oldArgs):
        def wrapper(*newArgs):
            return func.__call__(*(oldArgs + newArgs))
        return wrapper
    

    sumUpThree関数テストすると

    sum_1 = partial(sumUpThree, 1)
    sum_1(2, 3)
    

    6

    sum_1_5 = partial(sum_1, 5)
    sum_1_5(9)
    

    15

    sum_10_20 = partial(sumUpThree, 10, 20)
    sum_10_20(30)
    

    60

    こういう風に高階関数が簡単にできるのは関数オブジェクト関数の実行とはメソッドの呼び出しにすぎないからだ。以上のように組み込みオブジェクトユーザー定義オブジェクトの差があまりないことや関数オブジェクトであることに見られるようにPythonは仕組みが統一されていてシンプルだ。そのためひとつのことがわかれば他のこともわかることが多いし、簡単にいじることもできる。

    だからなければpythonをいじればいいと思うよ。

    最後にラムダ式信者のためにpartialをラムダ式を使って書いておく。

    def partial(func, *oldArgs):
        return lambda *newArgs:func.__call__(*(oldArgs + newArgs))
    

    Pythonラムダ式がだめだといわれているが、こんな風にかけたとして何がうれしいというのだ。

    2007-10-30

    []55行で作るC#テンプレートエンジン

    http://anond.hatelabo.jp/20071030034313二番煎じ

    あまりのアホさに、作ってて気が狂いかけた

    方針


    using System;
    using System.CodeDom.Compiler;
    using System.Collections.Generic;
    using System.IO;
    using System.Reflection;
    using Microsoft.CSharp;
    
    delegate void ConvertTemplateDelegate(TextWriter tw, Dictionary<object, object> args);
    static class TemplateGenerator {
        public static ConvertTemplateDelegate Generate(string code) {
            CompilerParameters param = new CompilerParameters();
            param.GenerateInMemory = true;
            param.ReferencedAssemblies.Add("System.Web.dll");
            CompilerResults rs = new CSharpCodeProvider().CompileAssemblyFromSource(param, ParseTemplate(code));
            if (0 < rs.Errors.Count) {
                StringWriter sw = new StringWriter();
                sw.WriteLine("Compile Error...");
                foreach (CompilerError err in rs.Errors)
                    sw.WriteLine(err.ToString());
                throw new Exception(sw.ToString());
            }
            return (ConvertTemplateDelegate) Delegate.CreateDelegate(typeof(ConvertTemplateDelegate), rs.CompiledAssembly.GetType("Template", true).GetMethod("Convert"));
        }
        private static string ParseTemplate(string code) {
            using (StringWriter sw = new StringWriter()) {
                sw.WriteLine("using System; using System.Collections.Generic; using System.IO; using System.Web;");
                sw.WriteLine("public static class Template {");
                sw.WriteLine("public static void Convert(TextWriter tw, Dictionary<object, object> args) {");
                int index = 0;
                while (0 <= index &amp;&amp; index < code.Length) {
                    int i = code.IndexOf("<%", index);
                    sw.WriteLine("tw.Write(\"{0}\");", EscapeString(i < 0 ? code.Substring(index) : code.Substring(index, i - index)));
                    if (0 <= i) {
                        i += 2;
                        int i2 = code.IndexOf("%>", i);
                        if (0 <= i2) {
                            string cc = code.Substring(i, i2 - i);
                            if (cc.StartsWith("="))
                                sw.WriteLine("tw.Write(HttpUtility.HtmlEncode(\"\"+({0})));", cc.Substring(1));
                            else
                                sw.WriteLine(cc);
                            i = i2 + 2;
                        }
                    }
                    index = i;
                }
                sw.WriteLine("}}");
                return sw.ToString();
            }
        }
        private static string EscapeString(string code) {
            return code.Replace("\\", "\\e").Replace("\"", "\\\"").Replace("\t", "\\t").Replace("\n", "\\n").Replace("\r", "\\r").Replace("\\e", "\\\\");
        }
    }
    

    サンプル C# コード。ためしにテンプレートから Xml 生成して、標準出力してみる。

    class Program {
        static void Main(string[] args) {
            ConvertTemplateDelegate func = TemplateGenerator.Generate(TemplateEngine.Resource1.template);
            using (StringWriter sw = new StringWriter()) {
                Dictionary<object, object> arg = new Dictionary<object, object>();
                arg["title"] = "template sample";
                arg["data"] = new string[] { "foo", "fooo", "<strong>foooooooooo!</strong>" };
                func(sw, arg);
                Console.WriteLine(sw);
            }
        }
    }
    

    サンプルテンプレート

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
              "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
      <head>
        <title><%= args["title"] %></title>
      </head>
      <body>
        <h1><%= args["title"] %></h1>
        <table>
    <% string[] data = (string[]) args["data"]; %>
    <% for(int i = 0; i < data.Length; i++) { %>
          <tr bgcolor="<%= i % 2 == 0 ? "#FFCCCC" : "#CCCCFF" %>">
            <td><%= i %></td>
            <td><%= data[i] %></td>
          </tr>
    <% } %>
        </table>
      </body>
    </html>
    

    出力例

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
              "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
      <head>
        <title>template sample</title>
      </head>
      <body>
        <h1>template sample</h1>
        <table>
    
    
          <tr bgcolor="#FFCCCC">
            <td>0</td>
            <td>foo</td>
          </tr>
    
          <tr bgcolor="#CCCCFF">
            <td>1</td>
            <td>fooo</td>
          </tr>
    
          <tr bgcolor="#FFCCCC">
            <td>2</td>
            <td>&lt;strong&gt;foooooooooo!&lt;/strong&gt;</td>
          </tr>
    
        </table>
      </body>
    </html>
    

    CodeDom 使って動的コンパイル……って、このコードのままだとセキュリティ的に大問題な気がするな。

    素直に ASP.NET 使ったほうが楽だと直感した。

    あと EscapeString すっごく自信ない。たぶん修正が必要だと思うw

    2007-10-21

    why not string.len()? Ruby vs. Python

    Ruby vs. Python

    Python:

    string = 'Hello world'

    print string.count('o'), len(string)    # prints 2, 11        why not string.len()?

    Ruby:

    string = 'Hello world'

    puts string.count('o'), string.length    # prints 2, 11


    Ruby Python の比較

    2007-09-10

    Gauche によるもう少し効率的なバージョン

    (define str "Hello world")
    
    (let ((a 0))
      (let1 b (with-input-from-string str
    	    (lambda ()
    	      (port-fold
    	       (lambda (c b)
    		 (if (eqv? #\o c) (inc! a))
    		 (+ 1 b))
    	       0
    	       read-char)))
        (print a " " b)))
    

    あるいはこう。

    (use srfi-1)
    
    (define (times* e n)
      (map (lambda _ (e)) (iota n)))
    
    (define-macro (with-gensyms var . body)
      `(let ,(map (cut list <> '(gensym)) var)
         ,@body))
    
    (define-macro (with-gensyms* var n . body)
      `(let ((,var (times* gensym ,n)))
         ,@body))
    
    (define-macro (port-vfold proc seed reader)
      (with-gensyms
       (loop %proc v)
       (with-gensyms*
        pr (length seed)
        (with-gensyms*
         npr (length seed)
         `(let ((,%proc ,proc))
    	(let ,loop ((,v (,reader)) ,@(map list pr seed))
    	     (if (eof-object? ,v)
    	       (values ,@pr)
    	       (receive ,npr (,%proc ,v ,@pr)
    		 (,loop (,reader) ,@npr)))))))))
    
    (receive (a b)
        (with-input-from-string "Hello world"
          (lambda ()		    
    	(port-vfold
    	 (lambda (c a b)
    	   (values
    	    (if (eqv? #\o c) (+ a 1) a)
    	    (+ 1 b)))
    	 (0 0)
    	 read-char)))
      (print a " " b))
    

    文字列操作関数って高価じゃね?

    Re: Ruby Python の比較

    悪魔perl:

    $,=", ";
    $\="\n";
    $_ = "Hello world";
    print scalar(@{[/o/g]}), length;
    

    printを知らないjavascript:

    string = 'Hello world';
    string.match(/o/g).length+', '+string.length+"\n";
    

    ちょっと趣旨は離れるけれど。他言語はどんな感じ?

    2007-09-09

    []Ruby Python の比較

    文字列 'Hello world' の o の合計数は2、全文字数は11

    Ruby vs. Python

    Python:

    string = 'Hello world'

    print string.count('o'), len(string)    # prints 2, 11        why not string.len()?

    Ruby:

    string = 'Hello world'

    puts string.count('o'), string.length    # prints 2, 11


    2007-09-19 - 偏った言語信者の垂れ流し

    2007-09-28 - プログラミング日記

    jijixi's diary - Ruby に比べて Python の面倒なところ

    激しく同意 - 日記を書く[・ _ゝ・]はやみずさん

    Django勉強会始まったよ|| Woops'dez | Bloggin'

    バベル案内

    Pythonはグローバルスコープローカル(関数)スコープ以外のスコープを何も持っていない。

    だからPythonには「本物の」OOシステムがあるのだとしても、クラスは自分のインスタンス変数にさえアクセスできない。

    あらゆるインスタンスメソッドに対し"self"パラメタを渡す必要があり、そうやってインスタンスデータにself経由でアクセスするのだ。

    だからPythonの中のものはすべて、self、selfself、selfselfself、selfSELFselfSELF__SELF__であり、

    たとえあなたがホワイトスペースの問題を気にかけないとしても、これはあなたの頭をおかしくするだろう。

    2007-09-07

    ようこそ、℃-uteLisp の世界へ

    発祥: http://ex23.2ch.net/test/read.cgi/morningcoffee/1188654905/

    はじめに

    Scheme という Lisp 語族言語を用いて ℃-ute相関関係プログラムし、様々な角度から関係性を分析する手法を紹介していきます(ソースコードは最後に張ります)。

    まずは、メンバー間の関係を「リスト」というデータ型で表現します。例えば「栞菜->愛理」という関係

    (kanna . airi)
    

    という形で表すことができます。これに、「大好き」という情報を付加し、ついでにその関係の性質を数値化したものを加えると

    ((kanna . airi) (desc "大好き") (score . 1))
    

    のようになり、関係図における一つの矢印の情報データ化できたことになります(暫定的に、好意は 1、良好・中立は 0、険悪は -1 の3段階で表すことにします)。

    メンバー間の全ての関係性をこのデータ単位で定義し、データベース化しておくことで、色んな条件に基づいた検索やスコア計算などが可能となります。

    例 1: リンク状況の調査

    ここで相関関係図における矢印を「リンク」と呼ぶことにして、あるメンバーから他のメンバーへどのようにリンクし、またリンクされているかを調べることができます。

    関係の中からリンクの起点を抽出してソートしてみると

    (sort-nodes (number-list (from-links)))
    

    結果:

    ((kanna . 6) (saki . 5) (maimi . 4) (erika . 3) (mai . 3) (chisato . 3) (airi . 2))
    

    栞菜ちゃんがメンバー全員にリンクを張っていることが分かり、℃-ute ラブっぷりが伺えます。なっきーにも同様の事が言えます。例の「女の子が好き」発言を数値的に裏付ける結果と言えるかもしれません。

    ただ、データ不足でリンク件数がまだ少ないのと、リンクの性質(好意/反感など)までは分からない点を考慮する必要があるでしょう。

    例 2: 被リンク状況の調査

    同様に、リンクの終点の件数を調べてみます。

    (sort-nodes (number-list (to-links)))
    
    ((chisato . 5) (erika . 5) (kanna . 4) (maimi . 4) (airi . 4) (mai . 3) (saki . 1))
    

    えりかちゃんと千聖ちゃんが高ポイントです。メンバーからの人気や注目度の高さを示すデータですが、千聖ちゃんの場合敵対的なリンクが2件含まれている点に注意してください。

    なっきーの被リンク数が極端に少ないですが、単純にデータ不足のためだと思われます。はぶら(ryとか言わないようにお願いします。

    例 3: 愛情度の評価

    リンクに付随するスコアを計算することで、愛情の度合いを測ることができるのではないか、という考えに基づく研究です。

    まず、全ての関係性を対象として、スコアマイナス関係を抽出してみます。

    (filter-nodes (lambda (n)
    		(< (score-relation n) 0)))
    

    結果:

    (((kanna . chisato) (desc "愛理に手出すんじゃねぇよ") (score . -1))
     ((saki . chisato) (desc "愛理に手出すんじゃねぇよ") (score . -1)))
    

    件数だけを得ると

    (length (filter-nodes (lambda (n)
    			(< (score-relation n) 0))))
    
    2
    

    僅か2件です。

    良好・中立的な関係

    (length (filter-nodes (lambda (n)
    			(= (score-relation n) 0))))
    
    8
    

    愛に満ちた関係

    (length (filter-nodes (lambda (n)
    			(> (score-relation n) 0))))
    
    16
    

    非常に多いです。舞美ちゃんの「℃-ute同士でラブラブなんですよ」発言(例のラジオ)を数値的に裏付ける結果と言えるんじゃないでしょうか。

    次に、メンバーごとのスコアを算出してみます。Lisp 的には以下のようにフィルタリングと畳み込み (fold) で計算することができます。例えば

    (foldr (lambda (n acc)
    	 (+ (get-score n) acc))
           0
           (filter-nodes (cut to? <> 'kanna)))
    

    栞菜ちゃんに対するリンクスコアが得られます。結果:

    3
    

    上式を一般化して一挙にメンバー全員に適用してみると

    (sort-nodes (map (lambda (x)
    		   (cons x (score-loved x)))
    		 (all-members)))
    

    結果:

    ((airi . 4) (kanna . 3) (mai . 2) (erika . 2) (maimi . 2) (saki . 1) (chisato . 0))
    

    愛理ちゃんが好意を寄せられやすい傾向が伺えます。

    今度は逆方向のスコアを計算してみると

    (sort-nodes (map (lambda (x)
    		   (cons x (score-loving x)))
    		 (all-members)))
    
    ((kanna . 3) (maimi . 3) (chisato . 2) (airi . 2) (saki . 2) (mai . 1) (erika . 1))
    

    まいまいえりかちゃんが特に堅い・一途だという傾向を読み取ることができます。

    例 4: 相性の調査

    今度は組み合わせ(カップリング)の評価です。

    2点間相互のリンクスコアを加算したものを「相性」と考えられるものとします。最大値 (互いに好意を寄せている場合の数値) は現在スコアリング方式では 2 です。例えば

    (score-between 'kanna 'airi)
    

    の値は

    2
    

    となります。1 であれば一方通行と考えます。

    関係性が未定義の場合もあるので 0 のものを除外して算出すると

    (sort-nodes (filter (lambda (n)
    		      (not (= (cdr n) 0)))
    		    (map (lambda (n)
    			   (cons n (apply score-between n)))
    			 (all-combinations))))
    
    (((chisato mai) . 2)
     ((chisato airi) . 2)
     ((airi kanna) . 2)
     ((saki kanna) . 2)
     ((kanna maimi) . 2)
     ((erika maimi) . 2)
     ((saki airi) . 1)
     ((saki erika) . 1)
     ((kanna mai) . 1)
     ((maimi airi) . 1)
     ((saki chisato) . -1)
     ((kanna chisato) . -1))
    

    となります。若干ピンとこない部分もあるかも知れませんが、計算上は矛盾無くデータの内容を表しています。

    参考までに、スコア 1 の相互関係の中身を見てみると

    (map (lambda (p)
           (find-relation (cons (caar p) (cadar p))
    		      identity))
         (filter (lambda (n)
    	       (= (cdr n) 1))
    	     (map (lambda (n)
    		    (cons n (apply score-between n)))
    		  (all-combinations))))
    
    (((kanna . mai) (desc "喰ってやるよ") (score . 1))
     ((saki . airi) (desc "好き") (score . 1))
     ((maimi . airi) (desc "良き妹") (score . 1))
     ((saki . erika) (desc "彼氏にしたい") (score . 1)))
    

    のようになります。

    まとめ

    以上の調査を経て気になった問題点を列挙してみます。

    特に最初の点に関して、「百合的」なるものの質的評価がなかなか難しいと感じました。例えば「大好き」も「良き妹」も同じ 1 と評価してしまっているのが妥当かどうか、といったことです。

    また、スレにて与えられた情報を評価・分析する方法としては有効だとしても、逆方向のフィードバックの手段がなかなか見つからないというのが三つ目の問題です(技術力不足とも言います)。(注:画像化の方法が分かりました。追記参照)

    最後に、プログラムソースを示します。実行には PLT Scheme が必要です。文字コードUTF-8 で保存した上で、(load "c-ute.ss") としてください。文字化けする場合はターミナルUTF-8 を表示できるよう設定する必要があります。がんばってください。

    プログラム

    c-ute.ss:

    (require (lib "etc.ss")
             (lib "list.ss")
             (lib "26.ss" "srfi")
             (lib "delete.ss" "srfi" "1"))
    
    ;;; Utilities
    
    (define true? (compose not not))
    
    (define (ignore _) #f)
    
    (define fif
      (case-lambda
        ((predicate consequent)
         (fif predicate consequent ignore))
        ((predicate consequent alternative)
         (lambda (x)
           (if (predicate x)
               (consequent x)
               (alternative x))))))
    
    (define (concat! xs) (apply append! xs))
    
    (define (mapconcat f lst sep)
      (let lp ((str (f (car lst)))
               (lst (cdr lst)))
        (if (null? lst)
            str
            (lp (string-append str sep (f (car lst)))
                (cdr lst)))))
    
    (define (slice-string str len)
      (let lp ((res '())
               (str str))
        (if (<= (string-length str) len)
            (reverse! (cons str res))
            (lp (cons (substring str 0 len) res)
                (substring str len)))))
    
    (define (break-string str len)
      (mapconcat identity (slice-string str len) "\\n"))
    
    ;; NOTE: input and output ports have to be either file-stream or #f
    ;; (i.e., cannot be a string port)
    (define (run exe opt in out)
      (let-values (((p p-i p-o p-e)
                    (subprocess out in #f exe opt)))
        (subprocess-wait p)
        (close-input-port p-e)))
    
    ;;; Database
    
    ;; http://ja.wikipedia.org/wiki/%E2%84%83-ute
    
    (define names
      '((erika . "えりか") (maimi . "舞美") (saki . "早貴") (airi . "愛理")
        (chisato . "千聖") (mai . "舞") (kanna . "栞菜")))
    
    (define (symbol->name sym)
      ((fif true?
            cdr)
       (assq sym names)))
    
    (define nodes '())
    (define edges '())
    
    (define (relate from to desc score)
      (let ((n (cons from to)))
        (or (find-relation n
                           (lambda (r)
                             (let ((d (assq 'desc r))
                                   (s (assq 'score r)))
                               (set-cdr! d (cons desc (cdr d)))
                               (set-cdr! s (+ score (cdr s))))))
            (begin
              (set! nodes (cons n nodes))
              (set! edges (cons (cons n `((desc ,desc)
                                          (score . ,score)))
                                edges))))))
    
    (define (find-relation n k)
      ((fif true? k)
       (assoc n edges)))
    
    (define (related? x y)
      (find-relation (cons x y) (lambda (_) #t)))
    
    (define (from? n x)
      (eq? (car n) x))
    
    (define (to? n x)
      (eq? (cdr n) x))
    
    (define flip-relation
      (case-lambda
        ((n)
         (and (related? (cdr n) (car n))
              (cons (cdr n) (car n))))
        ((n k)
         ((fif true? k)
          (flip-relation n)))))
    
    (define (get-score n)
      (cdr (assq 'score n)))
    
    (define (get-description n)
      (cdr (assq 'desc n)))
    
    (define (describe-relation n)
      (find-relation n get-description))
    
    (define (score-relation n)
      (or (find-relation n get-score) 0))
    
    (define (print-node . ns)
      (for-each (cute find-relation <>
                      (lambda (r)
                        (display
                         (format "| ~a => ~a  (~a)~%"
                                 (caar r) (cdar r)
                                 (mapconcat (lambda (s)
                                              (string-append "\"" s "\""))
                                            (cdr (assq 'desc r))
                                            ", ")))))
                ns))
    
    (define (iter-nodes k)
      (let lp ((nodes nodes))
        (unless (null? nodes)
          (k (car nodes))
          (lp (cdr nodes)))))
    
    (define (filter-nodes p)
      (let ((ns '()))
        (iter-nodes (fif p
                         (cut find-relation <> (lambda (n)
                                                 (set! ns (cons n ns))))))
        ns))
    
    (define (from-links)
      (map car nodes))
    
    (define (to-links)
      (map cdr nodes))
    
    (define (all-members)
      (delete-duplicates! (from-links)))
    
    (define (all-pairs) nodes)
    
    (define (ordered-pairs)
      (concat! (map (lambda (x)
                      (map car
                           (sort (filter-nodes (cute to? <> (car x)))
                                 (lambda (x y)
                                   (> (get-score x) (get-score y))))))
                    (sort-nodes (map (lambda (x)
                                       (cons x (score-loved x)))
                                     (all-members))))))
    
    (define (all-combinations)
      (let lp ((cs '()) (ns nodes))
        (if (null? ns)
            cs
            (let ((n (car ns)))
              (lp (if (member (list (cdr n) (car n))
                              cs)
                      cs
                      (cons (list (car n) (cdr n)) cs))
                  (cdr ns))))))
    
    ;; number-list :: [a] -> [(a . Int)]
    (define (number-list ls)
      (let lp ((ns '()) (ls ls))
        (if (null? ls)
            ns
            (let ((x (car ls)))
              (lp ((fif not
                        (lambda (_) (cons (cons x 1) ns))
                        (lambda (n)
                          (set-cdr! n (add1 (cdr n)))
                          ns))
                   (assq x ns))
                  (cdr ls))))))
    
    ;; sort-nodes :: [(a . Int)] -> [(a . Int)]
    (define (sort-nodes ns)
      (sort ns (lambda (x y)
                 (> (cdr x) (cdr y)))))
    
    (define (diff-nodes ms ns)
      (let lp ((ds '()) (ns ns))
        (if (null? ns)
            (sort-nodes ds)
            (lp (let* ((n (car ns))
                       (m (assq (car n) ms)))
                  (cons (cons (car n)
                              (- (cdr m) (cdr n)))
                        ds))
                (cdr ns)))))
    
    (define (get-total-score x p)
      (foldr (lambda (n acc)
               (+ (get-score n) acc))
             0
             (filter-nodes (cut p <> x))))
    
    (define (score-loved x)
      (get-total-score x to?))
    
    (define (score-loving x)
      (get-total-score x from?))
    
    (define (score-between x y)
      (+ (score-relation (cons x y))
         (score-relation (cons y x))))
    
    (define (-> x)
      (display (format "~%Links from [~a]~%" x))
      (iter-nodes (fif (cut from? <> x)
                       print-node)))
    
    (define (<- x)
      (display (format "~%Links towards [~a]~%" x))
      (iter-nodes (fif (cut to? <> x)
                       print-node)))
    
    (define (<-> x)
      (display (format "~%Reciprocal links for [~a]~%" x))
      (iter-nodes (fif (cut to? <> x)
                       (lambda (n)
                         (flip-relation n
                                        (lambda (m)
                                          (print-node m n)))))))
    
    (define (<=> x)
      (display (format "~%Reciprocal matches for [~a]~%" x))
      (iter-nodes
       (fif (cut to? <> x)
            (lambda (n)
              (flip-relation n
                             (lambda (m)
                               (if (ormap (lambda (x)
                                            (ormap (lambda (y)
                                                     (equal? x y))
                                                   (describe-relation m)))
                                          (describe-relation n))
                                   (print-node m n))))))))
    
    (define (<?> x)
      (let ((to (assq x (number-list (from-links))))
            (from (assq x (number-list (to-links)))))
        (display (string-append
                  (format "~%Link statistics for [~a]~%"
                          x)
                  (format "| ~a => ~a (love ~a)~%"
                          x
                          (cdr to)
                          (score-loving x))
                  (format "| ~a => ~a (love ~a)~%"
                          (cdr from)
                          x
                          (score-loved x))))))
    
    (define (info x)
      (for-each (cut <> x)
                (list <- <-> <=> -> <?>)))
    
    ;;; GraphViz (http://www.graphviz.org/) support
    
    (define graphviz "C:/Program Files/ATT/Graphviz/bin/dot.exe")
    
    (define (nodes->dot ns)
      (string-append "digraph cute {\n"
                     ;;"\tordering=out;\n"
                     ;;"\trankdir=LR;\n"
                     "\toverlap=true;\n"
                     "\tnode[fontname=\"msgothic.ttc\"];\n"
                     "\tedge[fontname=\"msgothic.ttc\",fontsize=9];\n"
                     (let lp ((str "") (ns ns))
                       (if (null? ns)
                           str
                           (let* ((n (car ns))
                                  (s (score-relation n)))
                             (lp (string-append
                                  str
                                  (format "\t\"~a\" -> \"~a\""
                                          (symbol->name (car n))
                                          (symbol->name (cdr n)))
                                  (format "[label=\"~a\",color=\"~a\","
                                          (break-string
                                           (car (describe-relation n))
                                           7)
                                          (cond ((> s 0) "red")
                                                ((= s 0) "green")
                                                (else "blue")))
                                  (format "style=\"bold~a\"];\n"
                                          (if (and (not (= s 0)) (< s 1) (> s -1))
                                              ",dashed"
                                              "")))
                                 (cdr ns)))))
                     "}"))
    
    (define (write-dotfile dot file)
      (and (file-exists? file) (delete-file file))
      (with-output-to-file file
        (lambda ()
          (display dot)))
      file)
    
    (define (dot->png dot png)
      (call-with-input-file (write-dotfile dot "c-ute.dot")
        (lambda (in)
          (and (file-exists? png) (delete-file png))
          (call-with-output-file png
            (lambda (out)
              (run graphviz "-Tpng" in out)))))
      'done)
    
    ;;; Setup database
    
    ;; Based on:
    ;; http://ex23.2ch.net/test/read.cgi/morningcoffee/1188654905/116-142
    (begin
      (relate 'maimi 'erika "大好き" 1)
      (relate 'maimi 'kanna "良き妹" 1)
      (relate 'maimi 'airi "良き妹" 1)
      (relate 'maimi 'mai "姉妹" 0)
      (relate 'erika 'maimi "一番可愛いよ" 1)
      (relate 'erika 'kanna "仲間" 0)
      (relate 'erika 'chisato "おソロパジャマ" 0)
      (relate 'kanna 'erika "仲間" 0)
      (relate 'kanna 'maimi "好き" 1)
      (relate 'kanna 'saki "喰ってやるよ" 1)
      (relate 'kanna 'mai "喰ってやるよ" 1)
      (relate 'kanna 'airi "大好き" 1)
      (relate 'kanna 'chisato "愛理に手出すんじゃねぇよ" -1)
      (relate 'saki 'maimi "荷物整理" 0)
      (relate 'saki 'erika "彼氏にしたい" 1)
      (relate 'saki 'kanna "興味がある" 0.5)
      (relate 'saki 'chisato "愛理に手出すんじゃねぇよ" -1)
      (relate 'saki 'airi "好き" 1)
      (relate 'airi 'kanna "受け入れる" 1)
      (relate 'airi 'chisato "最近親密" 1)
      (relate 'mai 'erika "保護者" 0)
      (relate 'mai 'maimi "姉妹" 0)
      (relate 'mai 'chisato "恋人" 1)
      (relate 'chisato 'erika "おソロパジャマ" 0)
      (relate 'chisato 'mai "恋人" 1)
      (relate 'chisato 'airi "最近親密" 1))
    
    ;; query relations / draw graphs
    
    (if (file-exists? graphviz)
        (dot->png (nodes->dot (ordered-pairs))
                  "c-ute.png")
        (for-each info (all-members)))
    

    追記(グラフ描画について)

    Graphviz というソフトによって関係図を可視化できる、ということを教えていただきました(既に上プログラムを実行すると自動的に関係画像を作成するようにしてあります)。ここでは技術的な観点から幾つか注意点を挙げておきます。

    まず、Scheme プログラムから Graphviz を動かす方法について。コマンドラインからの起動のように、プログラムへのオプション文字列で入出力ファイルを指定する方法ではどうも上手く行きませんでした。調査の結果、入出力ファイルポートScheme 側で用意しておく必要があるようです。処理系によって異なりますが、PLT Scheme の場合 subprocess という関数を次のように呼び出します。

    (subprocess output-port input-port #f "/path/to/dot.exe" "-Tpng")
    

    ここで output-port は png画像ファイルへの出力ポート。input-port は dot ファイルグラフの定義ファイル)の入力ポートです。エラーポートは必要無いでしょう (#f)。

    dot という名前の実行ファイルが、関係図のような有向グラフを描画するプログラムです。最後にオプション文字列として出力形式を指定します(png, jpeg, gif, etc.)。

    次に dot ファイルScheme で書く方法ですが、以下の基本的な有向グラフの書式

    digraph g {
      A -> B;
      B -> C;
      C -> A;
    }
    

    を理解すれば、後は実直に Schemeデータを当てはめて format 関数等で変換するだけです。

    (string-append
     "digraph g {"
     (format "~a -> ~a;" (car node) (cdr node))
     "}")
    

    問題は、ノードを配置する順番によって出来上がる画像が変わってくる、ということです。

    より見た目に分かりやすくするための工夫としては、相互にリンクするノード同士が dot ファイル上でも近接して出力されるようにすると良いでしょう。関連の強いものが画像の上でも近くに表示されるようになります。

    また上述(特に例3)のスコア概念を応用し、スコアの低いものが後に出力されるようにすることで、重力感覚に一致するような関係図を得ることができるでしょう。

    2007-08-25

    素人探訪今日の素敵 java1.0

    配列に格納したものと一致しないものだけをピックアップしたかったのだが、

    配列の中にその値があるかどうかの比較のしかたがわからずfor文でまわしました。

    なんとなく感覚でequals()と==をつかいわけているが、もしかしたら違うかもしれない。

    classインスタンスというかイニシャライズに相当する書き方がわからず、

    初期化が必要なクラスをつくることができず、ひとつのクラス内でダバダバ関数を書いている。

    } catch(ArithmeticException e) {

    System.err.println("エラー" + e.getMessage());

    関数ごとにこんな風にいちいち書いてみたが、もっといいやり方があるきがする。

    // デバック用出力関数

    private void fDebug(String msg) {

    if (!DEBUG_FLG){ return;}

    System.out.println(msg);

    }

    挙句、こんな関数を作った。俺はバカかとおもった。

    ログ出力用のヤツまでつくってしまった。いったいこれはどういうことだろう。

    昔し、配列のsortを教えてもらった記憶があるのだが実はいまだにできない。

    しかたが無いのでaddで任意の位置に足しているが、それをやるにもループ配列.size()で分岐しながらなのでカッコワルイ。

    勢いでつくった関数にオプショナルで引数を追加したくなったのだが、やりかたがわからなかったので諦めた。

    引数初期化ってどうやるんだろう。

    Eclipseで一気に複数行をコメントアウトするような方法がわからない。

    →わかった! ctrl+/だ! おー、便利。

    気持ち悪いループとbreak文だらけになってしまいわかり難いのでラベルをつけた。

    「label:」みたいにすればいいらしい。だが根本的に間違っている気がする。

    Integerとintみたいなものを区別せずに使っている。実際何が違うのかわからないけど動くからいいやとかおもってしまっている。

    @Overrideってなんだろう。

    参照が深くなりすぎてしまって、ループの中でわざわざ変数を宣言しなおしている。

    DDDDD masuda = AAAA.BBBB().CCCC(ohdeyansu);

    ookamiotokoto = masuda.funga() + masuda.hajimeruzamasu();

    どうなんだろうか。

    何か計算結果がおかしいなとおもったら int * (int/int) で、分母が計算途中で丸められてた。

    int * (float)(int/int) こんな回避の仕方をしてしまったのだがいいのだろうか。



    たいしたことをしていないのだがやたらとコードが長くなる。

    どうにかならんものか・・・。

    2007-07-19

    /* Ten */
    if (typeof(Ten) == 'undefined') {
        Ten = {};
    }
    Ten.NAME = 'Ten';
    Ten.VERSION = 0.06;
    
    /* Ten.Class */
    Ten.Class = function(klass, prototype) {
        if (klass && klass.initialize) {
    	var c = klass.initialize;
        } else if(klass && klass.base) {
            var c = function() { return klass.base[0].apply(this, arguments) };
        } else {
    	var c = function() {};
        }
        c.prototype = prototype || {};
        c.prototype.constructor = c;
        Ten.Class.inherit(c, klass);
        if (klass && klass.base) {
            for (var i = 0;  i < klass.base.length; i++) {
    	    var parent = klass.base[i];
                if (i == 0) {
                    c.SUPER = parent;
                    c.prototype.SUPER = parent.prototype;
                }
                Ten.Class.inherit(c, parent);
                Ten.Class.inherit(c.prototype, parent.prototype);
            }
        }
        return c;
    }
    Ten.Class.inherit = function(child,parent) {
        for (var prop in parent) {
            if (typeof(child[prop]) != 'undefined' || prop == 'initialize') continue;
            child[prop] = parent[prop];
        }
    }
    
    /*
    // Basic Ten Classes
    **/
    
    /* Ten.JSONP */
    Ten.JSONP = new Ten.Class({
        initialize: function(uri,obj,method) {
            if (Ten.JSONP.Callbacks.length) {
                setTimeout(function() {new Ten.JSONP(uri,obj,method)}, 500);
                return;
            }
            var del = uri.match(/\?/) ? '&' : '?';
            uri += del + 'callback=Ten.JSONP.callback';
            if (!uri.match(/timestamp=/)) {
                uri += '&' + encodeURI(new Date());
            }
            if (obj && method) Ten.JSONP.addCallback(obj,method);
            this.script = document.createElement('script');
            this.script.src = uri;
            this.script.type = 'text/javascript';
            document.getElementsByTagName('head')[0].appendChild(this.script);
        },
        addCallback: function(obj,method) {
            Ten.JSONP.Callbacks.push({object: obj, method: method});
        },
        callback: function(args) {
            // alert('callback called');
            var cbs = Ten.JSONP.Callbacks;
            for (var i = 0; i < cbs.length; i++) {
                var cb = cbs[i];
                cb.object[cb.method].call(cb.object, args);
            }
            Ten.JSONP.Callbacks = [];
        },
        MaxBytes: 8000,
        Callbacks: []
    });
    
    /* Ten.XHR */
    Ten.XHR = new Ten.Class({
        initialize: function(uri,opts,obj,method) {
            if (!uri) return;
            this.request = Ten.XHR.getXMLHttpRequest();
            this.callback = {object: obj, method: method};
            var xhr = this;
            var prc = this.processReqChange;
            this.request.onreadystatechange = function() {
                prc.apply(xhr, arguments);
            }
            var method = opts.method || 'GET';
            this.request.open(method, uri, true);
            if (method == 'POST') {
                this.request.setRequestHeader('Content-Type',
                                              'application/x-www-form-urlencoded');
            }
            var data = opts.data ? Ten.XHR.makePostData(opts.data) : null;
            this.request.send(data);
        },
        getXMLHttpRequest: function() {
            var xhr;
            var tryThese = [
                function () { return new XMLHttpRequest(); },
                function () { return new ActiveXObject('Msxml2.XMLHTTP'); },
                function () { return new ActiveXObject('Microsoft.XMLHTTP'); },
                function () { return new ActiveXObject('Msxml2.XMLHTTP.4.0'); },
            ];
            for (var i = 0; i < tryThese.length; i++) {
                var func = tryThese[i];
                try {
                    xhr = func;
                    return func();
                } catch (e) {
                    //alert(e);
                }
            }
            return xhr;
        },
        makePostData: function(data) {
            var pairs = [];
            var regexp = /%20/g;
            for (var k in data) {
                var v = data[k].toString();
                var pair = encodeURIComponent(k).replace(regexp,'+') + '=' +
                    encodeURIComponent(v).replace(regexp,'+');
                pairs.push(pair);
            }
            return pairs.join('&');
        }
    },{
        processReqChange: function() {
            var req = this.request;
            if (req.readyState == 4) {
                if (req.status == 200) {
                    var cb = this.callback;
                    cb.object[cb.method].call(cb.object, req);
                } else {
                    alert("There was a problem retrieving the XML data:\n" +
                          req.statusText);
                }
            }
        }
    });
    
    /* Ten.Observer */
    Ten.Observer = new Ten.Class({
        initialize: function(element,event,obj,method) {
            var func = obj;
            if (typeof(method) == 'string') {
                func = obj[method];
            }
            this.element = element;
            this.event = event;
            this.listener = function(event) {
                return func.call(obj, new Ten.Event(event || window.event));
            }
            if (this.element.addEventListener) {
                if (this.event.match(/^on(.+)$/)) {
                    this.event = RegExp.$1;
                }
                this.element.addEventListener(this.event, this.listener, false);
            } else if (this.element.attachEvent) {
                this.element.attachEvent(this.event, this.listener);
            }
        }
    },{
        stop: function() {
            if (this.element.removeEventListener) {
                this.element.removeEventListener(this.event,this.listener,false);
            } else if (this.element.detachEvent) {
                this.element.detachEvent(this.event,this.listener);
            }
        }
    });
    
    /* Ten.Event */
    Ten.Event = new Ten.Class({
        initialize: function(event) {
            this.event = event;
        },
        keyMap: {
            8:"backspace", 9:"tab", 13:"enter", 19:"pause", 27:"escape", 32:"space",
            33:"pageup", 34:"pagedown", 35:"end", 36:"home", 37:"left", 38:"up",
            39:"right", 40:"down", 44:"printscreen", 45:"insert", 46:"delete",
            112:"f1", 113:"f2", 114:"f3", 115:"f4", 116:"f5", 117:"f6", 118:"f7",
            119:"f8", 120:"f9", 121:"f10", 122:"f11", 123:"f12",
            144:"numlock", 145:"scrolllock"
        }
    },{
        mousePosition: function() {
            if (!this.event.clientX) return;
            return Ten.Geometry.getMousePosition(this.event);
        },
        isKey: function(name) {
            var ecode = this.event.keyCode;
            if (!ecode) return;
            var ename = Ten.Event.keyMap[ecode];
            if (!ename) return;
            return (ename == name);
        },
        targetIsFormElements: function() {
            var target = this.event.target;
            if (!target) return;
            var T = (target.tagName || '').toUpperCase();
            return (T == 'INPUT' || T == 'SELECT' || T == 'OPTION' ||
                    T == 'BUTTON' || T == 'TEXTAREA');
        },
        stop: function() {
            var e = this.event;
            if (e.stopPropagation) {
                e.stopPropagation();
                e.preventDefault();
            } else {
                e.cancelBubble = true;
                e.returnValue = false;
            }
        }
    });
    
    /* Ten.DOM */
    Ten.DOM = new Ten.Class({
        getElementsByTagAndClassName: function(tagName, className, parent) {
            if (typeof(parent) == 'undefined') {
                parent = document;
            }
            var children = parent.getElementsByTagName(tagName);
            if (className) { 
                var elements = [];
                for (var i = 0; i < children.length; i++) {
                    var child = children[i];
                    var cls = child.className;
                    if (!cls) {
                        continue;
                    }
                    var classNames = cls.split(' ');
                    for (var j = 0; j < classNames.length; j++) {
                        if (classNames[j] == className) {
                            elements.push(child);
                            break;
                        }
                    }
                }
                return elements;
            } else {
                return children;
            }
        },
        removeEmptyTextNodes: function(element) {
            var nodes = element.childNodes;
            for (var i = 0; i < nodes.length; i++) {
                var node = nodes[i];
                if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) {
                    node.parentNode.removeChild(node);
                }
            }
        },
        nextElement: function(elem) {
            do {
                elem = elem.nextSibling;
            } while (elem && elem.nodeType != 1);
            return elem;
        },
        prevElement: function(elem) {
            do {
                elem = elem.previousSibling;
            } while (elem && elem.nodeType != 1);
            return elem;
        },
        scrapeText: function(node) {
            var rval = [];
            (function (node) {
                var cn = node.childNodes;
                if (cn) {
                    for (var i = 0; i < cn.length; i++) {
                        arguments.callee.call(this, cn[i]);
                    }
                }
                var nodeValue = node.nodeValue;
                if (typeof(nodeValue) == 'string') {
                    rval.push(nodeValue);
                }
            })(node);
            return rval.join('');
        },
        onLoadFunctions: [],
        loaded: false,
        timer: null,
        addEventListener: function(event,func) {
            if (event != 'load') return;
            Ten.DOM.onLoadFunctions.push(func);
            Ten.DOM.checkLoaded();
        },
        checkLoaded: function() {
            var c = Ten.DOM;
            if (c.loaded) return true;
            if (document && document.getElementsByTagName &&
                document.getElementById && document.body) {
                if (c.timer) {
                    clearInterval(c.timer);
                    c.timer = null;
                }
                for (var i = 0; i < c.onLoadFunctions.length; i++) {
                        c.onLoadFunctions[i]();
                }
                c.onLoadFunctions = [];
                c.loaded = true;
            } else {
                c.timer = setInterval(c.checkLoaded, 13);
            }
        }
    });
    
    /* Ten.Style */
    Ten.Style = new Ten.Class({
        applyStyle: function(elem, style) {
            for (prop in style) {
                elem.style[prop] = style[prop];
            }
        }
    });
    
    /* Ten.Geometry */
    Ten.Geometry = new Ten.Class({
        initialize: function() {
            if (Ten.Geometry._initialized) return;
            var func = Ten.Geometry._functions;
            var de = document.documentElement;
            if (window.innerWidth) {
                func.getWindowWidth = function() { return window.innerWidth; }
                func.getWindowHeight = function() { return window.innerHeight; }
                func.getXScroll = function() { return window.pageXOffset; }
                func.getYScroll = function() { return window.pageYOffset; }
            } else if (de && de.clientWidth) {
                func.getWindowWidth = function() { return de.clientWidth; }
                func.getWindowHeight = function() { return de.clientHeight; }
                func.getXScroll = function() { return de.scrollLeft; }
                func.getYScroll = function() { return de.scrollTop; }
            } else if (document.body.clientWidth) {
                func.getWindowWidth = function() { return document.body.clientWidth; }
                func.getWindowHeight = function() { return document.body.clientHeight; }
                func.getXScroll = function() { return document.body.scrollLeft; }
                func.getYScroll = function() { return document.body.scrollTop; }
            }
            Ten.Geometry._initialized = true;
        },
        _initialized: false,
        _functions: {},
        getScroll: function() {
            if (!Ten.Geometry._initialized) new Ten.Geometry;
            return {
                x: Ten.Geometry._functions.getXScroll(),
                y: Ten.Geometry._functions.getYScroll()
            };
        },
        getMousePosition: function(pos) {
            // pos should have clientX, clientY same as mouse event
            if ((navigator.userAgent.indexOf('Safari') > -1) &&
                (navigator.userAgent.indexOf('Version/') < 0)) {
                return {
                    x: pos.clientX,
                    y: pos.clientY
                };
            } else {
                var scroll = Ten.Geometry.getScroll();
                return {
                    x: pos.clientX + scroll.x,
                    y: pos.clientY + scroll.y
                };
            }
        },
        getElementPosition: function(e) {
            return {
                x: e.offsetLeft,
                y: e.offsetTop
            };
        },
        getWindowSize: function() {
            if (!Ten.Geometry._initialized) new Ten.Geometry;
            return {
                w: Ten.Geometry._functions.getWindowWidth(),
                h: Ten.Geometry._functions.getWindowHeight()
            };
        }
    });
    
    /* Ten.Position */
    Ten.Position = new Ten.Class({
        initialize: function(x,y) {
            this.x = x;
            this.y = y;
        },
        subtract: function(a,b) {
            return new Ten.Position(a.x - b.x, a.y - b.y);
        }
    });
    
    /*
    // require Ten.js
    **/
    
    /* Ten.SubWindow */
    Ten.SubWindow = new Ten.Class({
        initialize: function() {
            var c = this.constructor;
            if (c.singleton && c._cache) {
                return c._cache;
            }
            var div = document.createElement('div');
            Ten.Style.applyStyle(div, Ten.SubWindow._baseStyle);
            Ten.Style.applyStyle(div, c.style);
            this.window = div;
            this.addContainerAndCloseButton();
            document.body.appendChild(div);
            if (c.draggable) {
                this._draggable = new Ten.Draggable(div, this.handle);
            }
            if (c.singleton) c._cache = this;
            return this;
        },
        _baseStyle: {
            color: '#000',
            position: 'absolute',
            display: 'none',
            zIndex: 2,
            left: 0,
            top: 0,
            backgroundColor: '#fff',
            border: '1px solid #bbb'
        },
        style: {
            padding: '2px',
            textAlign: 'center',
            borderRadius: '6px',
            MozBorderRadius: '6px',
            width: '100px',
            height: '100px'
        },
        handleStyle: {
            position: 'absolute',
            top: '0px',
            left: '0px',
            backgroundColor: '#f3f3f3',
            borderBottom: '1px solid #bbb',
            width: '100%',
            height: '30px'
        },
        containerStyle: {
            margin: '32px 0 0 0',
            padding: '0 10px'
        },
        // closeButton: 'close.gif',
        closeButton: 'http://s.hatena.com/images/close.gif',
        closeButtonStyle: {
            position: 'absolute',
            top: '8px',
            right: '10px',
            cursor: 'pointer'
        },
        _baseScreenStyle: {
            position: 'absolute',
            top: '0px',
            left: '0px',
            display: 'none',
            zIndex: 1,
            overflow: 'hidden',
            width: '100%',
            height: '100%'
        },
        screenStyle: {},
        showScreen: true,
        singleton: true,
        draggable: true,
        _cache: null
    },{
        screen: null,
        windowObserver: null,
        visible: false,
        addContainerAndCloseButton: function() {
            var win = this.window;
            var c = this.constructor;
            var div = document.createElement('div');
            win.appendChild(div);
            Ten.Style.applyStyle(div, c.containerStyle);
            this.container = div;
            if (c.handleStyle) {
                var handle = document.createElement('div');
                Ten.Style.applyStyle(handle, c.handleStyle);
                win.appendChild(handle);
                this.handle = handle;
            }
            if (c.closeButton) {
    	    var btn = document.createElement('img');
                btn.src = c.closeButton;
                btn.alt = 'close';
                Ten.Style.applyStyle(btn, c.closeButtonStyle);
                win.appendChild(btn);
                new Ten.Observer(btn, 'onclick', this, 'hide');
                this.closeButton = btn;
            }
            if (c.showScreen) {
                var screen = document.createElement('div');
                Ten.Style.applyStyle(screen, Ten.SubWindow._baseScreenStyle);
                Ten.Style.applyStyle(screen, c.screenStyle);
                document.body.appendChild(screen);
                this.screen = screen;
                new Ten.Observer(screen, 'onclick', this, 'hide');
            }
        },
        show: function(pos) {
            pos = (pos.x && pos.y) ? pos : {x:0, y:0};
            with (this.window.style) {
                display = 'block';
                left = pos.x + 'px';
                top = pos.y + 'px';
            }
            if (this.screen) {
                with (this.screen.style) {
                    display = 'block';
                    left = Ten.Geometry.getScroll().x + 'px';
                    top = Ten.Geometry.getScroll().y + 'px';
                }
            }
            this.windowObserver = new Ten.Observer(document.body, 'onkeypress', this, 'handleEscape');
            this.visible = true;
        },
        handleEscape: function(e) {
            if (!e.isKey('escape')) return;
            this.hide();
        },
        hide: function() {
            if (this._draggable) this._draggable.endDrag();
            this.window.style.display = 'none';
            if (this.screen) this.screen.style.display = 'none';
            if (this.windowObserver) this.windowObserver.stop();
            this.visible = false;
        }
    });
    
    /* Ten.Draggable */
    Ten.Draggable = new Ten.Class({
        initialize: function(element,handle) {
            this.element = element;
            this.handle = handle || element;
            this.startObserver = new Ten.Observer(this.handle, 'onmousedown', this, 'startDrag');
            this.handlers = [];
        }
    },{
        startDrag: function(e) {
            if (e.targetIsFormElements()) return;
            this.delta = Ten.Position.subtract(
                e.mousePosition(),
                Ten.Geometry.getElementPosition(this.element)
            );
            this.handlers = [
                new Ten.Observer(document, 'onmousemove', this, 'drag'),
                new Ten.Observer(document, 'onmouseup', this, 'endDrag'),
                new Ten.Observer(this.element, 'onlosecapture', this, 'endDrag')
            ];
            e.stop();
        },
        drag: function(e) {
            var pos = Ten.Position.subtract(e.mousePosition(), this.delta);
            Ten.Style.applyStyle(this.element, {
                left: pos.x + 'px',
                top: pos.y + 'px'
            });
            e.stop();
        },
        endDrag: function(e) {
            for (var i = 0; i < this.handlers.length; i++) {
                this.handlers[i].stop();
            }
            if(e) e.stop();
        }
    });
    
    /* Hatena */
    if (typeof(Hatena) == 'undefined') {
        Hatena = {};
    }
    
    /* Hatena.User */
    Hatena.User = new Ten.Class({
        initialize: function(name) {
            this.name = name;
        },
        getProfileIcon: function(name) {
            if (!name) name = 'user';
            var pre = name.match(/^[\w-]{2}/)[0];
            var img = document.createElement('img');
            img.src = 'http://www.hatena.ne.jp/users/' + pre + '/' + name + '/profile_s.gif';
            img.alt = name;
            img.setAttribute('class', 'profile-icon');
            img.setAttribute('width','16px');
            img.setAttribute('height','16px');
            with (img.style) {
                margin = '0 3px';
                border = 'none';
                verticalAlign = 'middle';
            }
            return img;
        }
    }, {
        profileIcon: function() {
            return Hatena.User.getProfileIcon(this.name);
        }
    });
    
    /* Hatena.Star */
    if (typeof(Hatena.Star) == 'undefined') {
        Hatena.Star = {};
    }
    
    /*
    // Hatena.Star.* classes //
    **/
    if (window.location && window.location.host.match(/hatena\.com/)) {
        Hatena.Star.BaseURL = 'http://s.hatena.com/';
    } else {
        Hatena.Star.BaseURL = 'http://s.hatena.ne.jp/';
    }
    Hatena.Star.Token = null;
    
    /* Hatena.Star.User */
    Hatena.Star.User = new Ten.Class({
        base: [Hatena.User],
        initialize: function(name) {
            if (Hatena.Star.User._cache[name]) {
                return Hatena.Star.User._cache[name];
            } else {
                this.name = name;
                Hatena.Star.User._cache[name] = this;
                return this;
            }
        },
        _cache: {}
    },{
        userPage: function() {
            return Hatena.Star.BaseURL + this.name + '/';
        }
    });
    
    /* Hatena.Star.Entry */
    Hatena.Star.Entry = new Ten.Class({
        initialize: function(e) {
            this.entry = e;
            this.uri = e.uri;
            this.title = e.title;
            this.star_container = e.star_container;
            this.comment_container = e.comment_container;
            this.stars = [];
            this.comments = [];
        },
        maxStarCount: 11
    },{
        flushStars: function() {
            this.stars = [];
            this.star_container.innerHTML = '';
        },
        bindStarEntry: function(se) {
            this.starEntry = se;
            for (var i = 0; i < se.stars.length; i++) {
                if (typeof(se.stars[i]) == 'number') {
                    this.stars.push(new Hatena.Star.InnerCount(se.stars[i],this));
                } else {
                    this.stars.push(new Hatena.Star.Star(se.stars[i]));
                }
            }
            if (se.comments && !this.comments.length) {
                for (var i = 0; i < se.comments.length; i++) {
                    this.comments.push(new Hatena.Star.Comment(se.comments[i]));
                }
            }
            this.can_comment = se.can_comment;
        },
        setCanComment: function(v) {
            this.can_comment = v;
        },
        showButtons: function() {
            this.addAddButton();
            this.addCommentButton();
        },
        addAddButton: function() {
            if (this.star_container) {
                this.addButton = new Hatena.Star.AddButton(this);
                this.star_container.appendChild(this.addButton);
            }
        },
        addCommentButton: function() {
            if (this.comment_container) {
                this.commentButton = new Hatena.Star.CommentButton(this);
                this.comment_container.appendChild(this.commentButton.img);
            }
        },
        showStars: function() {
            var klass = this.constructor;
            // if (this.stars.length > klass.maxStarCount) {
            //     var ic = new Hatena.Star.InnerCount(this.stars.slice(1,this.stars.length));
            //     this.star_container.appendChild(this.stars[0]);
            //     this.star_container.appendChild(ic);
            //     this.star_container.appendChild(this.stars[this.stars.length - 1]);
            // } else {
            for (var i = 0; i < this.stars.length; i++) {
                this.star_container.appendChild(this.stars[i]);
            }
        },
        showCommentButton: function() {
            if (this.can_comment) {
                this.commentButton.show();
                if (this.comments.length) this.commentButton.activate();
            } else {
                // this.commentButton.hide();
            }
        },
        addStar: function(star) {
            this.stars.push(star);
            this.star_container.appendChild(star);
        },
        addComment: function(com) {
            if (!this.comments) this.comments = [];
            if (this.comments.length == 0) {
                this.commentButton.activate();
            }
            this.comments.push(com);
        },
        showCommentCount: function() {
            this.comment_container.innerHTML += this.comments.length;
        }
    });
    
    /* Hatena.Star.Button */
    Hatena.Star.Button = new Ten.Class({
        createButton: function(args) {
            var img = document.createElement('img');
            img.src = args.src;
            img.alt = img.title = args.alt;
            with (img.style) {
    	    cursor = 'pointer';
    	    margin = '0 3px';
                padding = '0';
                border = 'none';
                verticalAlign = 'middle';
            }
            return img;
        }
    });
    
    /* Hatena.Star.AddButton */
    Hatena.Star.AddButton = new Ten.Class({
        base: ['Hatena.Star.Button'],
        initialize: function(entry) {
            this.entry = entry;
            this.lastPosition = null;
            var img = Hatena.Star.Button.createButton({
                src: Hatena.Star.AddButton.ImgSrc,
                alt: 'Add Star'
            });
            this.observer = new Ten.Observer(img,'onclick',this,'addStar');
            this.img = img;
            return img;
        },
        ImgSrc: Hatena.Star.BaseURL + 'images/add.gif'
    },{
        addStar: function(e) {
            this.lastPosition = e.mousePosition();
            var uri = Hatena.Star.BaseURL + 'star.add.json?uri=' + encodeURIComponent(this.entry.uri) +
                '&title=' + encodeURIComponent(this.entry.title);
            if (Hatena.Star.Token) {
                uri += '&token=' + Hatena.Star.Token;
            }
            new Ten.JSONP(uri, this, 'receiveResult');
        },
        receiveResult: function(args) {
            var name = args ? args.name : null;
            if (name) {
                this.entry.addStar(new Hatena.Star.Star({name: name}));
                //alert('Succeeded in Adding Star ' + args);
            } else if (args.errors) {
                var pos = this.lastPosition;
                pos.x -= 10;
                pos.y += 25;
                var scroll = Ten.Geometry.getScroll();
                var scr = new Hatena.Star.AlertScreen();
                var alert = args.errors[0];
                scr.showAlert(alert, pos);
            }
        }
    });
    
    /* Hatena.Star.CommentButton */
    Hatena.Star.CommentButton = new Ten.Class({
        base: ['Hatena.Star.Button'],
        initialize: function(entry) {
            this.entry = entry;
            this.lastPosition = null;
            var img = Hatena.Star.Button.createButton({
                src: Hatena.Star.CommentButton.ImgSrc,
                alt: 'Comments'
            });
            img.style.display = 'none';
            this.observer = new Ten.Observer(img,'onclick',this,'showComments');
            this.img = img;
        },
        ImgSrc: Hatena.Star.BaseURL + 'images/comment.gif',
        ImgSrcActive: Hatena.Star.BaseURL + 'images/comment_active.gif'
    },{
        showComments: function(e) {
            if (!this.screen) this.screen = new Hatena.Star.CommentScreen();
            this.screen.bindEntry(this.entry);
            var pos = e.mousePosition();
            pos.y += 25;
            this.screen.showComments(this.entry, pos);
        },
        hide: function() {
            this.img.style.display = 'none';
        },
        show: function() {
            this.img.style.display = 'inline';
        },
        activate: function() {
            this.show();
            this.img.src = Hatena.Star.CommentButton.ImgSrcActive;
        }
    });
    
    /* Hatena.Star.Star */
    Hatena.Star.Star = new Ten.Class({
        initialize: function(args) {
            if (args.img) {
                this.img = args.img;
                this.name = this.img.getAttribute('alt');
            } else {
                this.name = args.name;
                var img = document.createElement('img');
                img.src = Hatena.Star.Star.ImgSrc;
                img.alt = this.name;
                with (img.style) {
                    padding = '0';
                    border = 'none';
                }
                this.img = img;
            }
    	new Ten.Observer(this.img,'onmouseover',this,'showName');
    	new Ten.Observer(this.img,'onmouseout',this,'hideName');
    	if (this.name) {
                this.user = new Hatena.Star.User(this.name);
                this.img.style.cursor = 'pointer';
                new Ten.Observer(this.img,'onclick',this,'goToUserPage');
            }
            if (args.count && args.count > 1) {
                var c = document.createElement('span');
                c.setAttribute('class', 'hatena-star-inner-count');
                Ten.Style.applyStyle(c, Hatena.Star.InnerCount.style);
                c.innerHTML = args.count;
                var s = document.createElement('span');
                s.appendChild(img);
                s.appendChild(c);
                return s;
            } else {
                return this.img;
            }
        },
        ImgSrc: Hatena.Star.BaseURL + 'images/star.gif'
    },{
        showName: function(e) {
            if (!this.screen) this.screen = new Hatena.Star.NameScreen();
            var pos = e.mousePosition();
            pos.x += 10;
            pos.y += 25;
            this.screen.showName(this.name, pos);
        },
        hideName: function() {
            if (!this.screen) return;
            this.screen.hide();
        },
        goToUserPage: function() {
            window.location = this.user.userPage();
        }
    });
    
    /* Hatena.Star.InnerCount */
    Hatena.Star.InnerCount = new Ten.Class({
        initialize: function(count, e) {
            this.count = count;
            this.entry = e;
            var c = document.createElement('span');
            c.setAttribute('class', 'hatena-star-inner-count');
            Ten.Style.applyStyle(c, Hatena.Star.InnerCount.style);
            c.style.cursor = 'pointer';
            c.innerHTML = count;
            new Ten.Observer(c,'onclick',this,'showInnerStars');
            this.container = c;
            return c;
        },
        style: {
            color: '#f4b128',
            fontWeight: 'bold',
            fontSize: '80%',
            fontFamily: '"arial", sans-serif',
            margin: '0 2px'
        }
    },{
        showInnerStars: function() {
            var url = Hatena.Star.BaseURL + 'entry.json?uri=' +
            encodeURIComponent(this.entry.uri);
            new Ten.JSONP(url, this, 'receiveStarEntry');
        },
        receiveStarEntry: function(res) {
            var se = res.entries[0];
            var e = this.entry;
            if (encodeURIComponent(se.uri) != encodeURIComponent(e.uri)) return;
            e.flushStars();
            e.bindStarEntry(se);
            e.addAddButton();
            e.showStars();
        }
    });
    
    /* Hatena.Star.Comment */
    Hatena.Star.Comment = new Ten.Class({
        initialize: function(args) {
            this.name = args.name;
            this.body = args.body;
        }
    },{
        asElement: function() {
            var div = document.createElement('div');
            with (div.style) {
                margin = '0px 0';
                padding = '5px 0';
                borderBottom = '1px solid #ddd';
            }
            var ico = Hatena.User.getProfileIcon(this.name);
            div.appendChild(ico);
            var span = document.createElement('span');
            with(span.style) {
                fontSize = '90%';
            }
            span.innerHTML = this.body;
            div.appendChild(span);
            return div;
        }
    });
    
    /* Hatena.Star.NameScreen */
    Hatena.Star.NameScreen = new Ten.Class({
        base: [Ten.SubWindow],
        style: {
            padding: '2px',
            textAlign: 'center'
        },
        containerStyle: {
            margin: 0,
            padding: 0
        },
        handleStyle: null,
        showScreen: false,
        closeButton: null,
        draggable: false
    },{
        showName: function(name, pos) {
            this.container.innerHTML = '';
            this.container.appendChild(Hatena.User.getProfileIcon(name));
            this.container.appendChild(document.createTextNode(name));
            this.show(pos);
        }
    });
    
    /* Hatena.Star.AlertScreen */
    Hatena.Star.AlertScreen = new Ten.Class({
        base: [Ten.SubWindow],
        style: {
            padding: '2px',
            textAlign: 'center',
            borderRadius: '6px',
            MozBorderRadius: '6px',
            width: '240px',
            height: '120px'
        },
        handleStyle: {
            position: 'absolute',
            top: '0px',
            left: '0px',
            backgroundColor: '#f3f3f3',
            borderBottom: '1px solid #bbb',
            width: '100%',
            height: '30px',
            borderRadius: '6px 6px 0 0',
            MozBorderRadius: '6px 6px 0 0'
        }
    },{
        showAlert: function(msg, pos) {
            this.container.innerHTML = msg;
            var win = Ten.Geometry.getWindowSize();
            var scr = Ten.Geometry.getScroll();
            var w = parseInt(this.constructor.style.width) + 20;
            if (pos.x + w > scr.x + win.w) pos.x = win.w + scr.x - w;
            this.show(pos);
        }
    });
    
    /* Hatena.Star.CommentScreen */
    Hatena.Star.CommentScreen = new Ten.Class({
        base: [Ten.SubWindow],
        initialize: function() {
            var self = this.constructor.SUPER.call(this);
            if (!self.commentsContainer) self.addCommentsContainer();
            return self;
        },
        style: {
            width: '280px',
            height: '280px',
            overflowY: 'auto',
            padding: '2px',
            textAlign: 'center',
            borderRadius: '6px',
            MozBorderRadius: '6px'
        },
        handleStyle: {
            position: 'absolute',
            top: '0px',
            left: '0px',
            backgroundColor: '#f3f3f3',
            borderBottom: '1px solid #bbb',
            width: '100%',
            height: '30px',
            borderRadius: '6px 6px 0 0',
            MozBorderRadius: '6px 6px 0 0'
        },
        containerStyle: {
            margin: '32px 0 0 0',
            textAlign: 'left',
            padding: '0 10px'
        },
        getLoadImage: function() {
            var img = document.createElement('img');
            img.src = Hatena.Star.BaseURL + 'images/load.gif';
            img.setAttribute('alt', 'Loading');
            with (img.style) {
                verticalAlign = 'middle';
                margin = '0 2px';
            }
            return img;
        }
    },{
        addCommentsContainer: function() {
            var div = document.createElement('div');
            with (div.style) {
                marginTop = '-3px';
            }
            this.container.appendChild(div);
            this.commentsContainer = div;
        },
        showComments: function(e, pos) {
            var comments = e.comments;
            if (!comments) comments = [];
            this.commentsContainer.innerHTML = '';
            for (var i=0; i<comments.length; i++) {
                this.commentsContainer.appendChild(comments[i].asElement());
            }
            if (e.starEntry && !e.can_comment) {
                this.hideCommentForm();
            } else {
                this.addCommentForm();
            }
            var win = Ten.Geometry.getWindowSize();
            var scr = Ten.Geometry.getScroll();
            var w = parseInt(this.constructor.style.width) + 20;
            if (pos.x + w > scr.x + win.w) pos.x = win.w + scr.x - w;
            this.show(pos);
        },
        bindEntry: function(e) {
            this.entry = e;
        },
        sendComment: function(e) {
            if (!e.isKey('enter')) return;
            var body = this.commentInput.value;
            if (!body) return;
            this.commentInput.disabled = 'true';
            this.showLoadImage();
            var url = Hatena.Star.BaseURL + 'comment.add.json?body=' + encodeURIComponent(body) +
                '&uri=' + encodeURIComponent(this.entry.uri) +
                '&title=' + encodeURIComponent(this.entry.title);
            new Ten.JSONP(url, this, 'receiveResult');
        },
        receiveResult: function(args) {
            if (!args.name || !args.body) return;
            this.commentInput.value = ''; 
            this.commentInput.disabled = '';
            this.hideLoadImage();
            var com = new Hatena.Star.Comment(args);
            this.entry.addComment(com);
            this.commentsContainer.appendChild(com.asElement());
        },
        showLoadImage: function() {
            if (!this.loadImage) return; 
            this.loadImage.style.display = 'inline';
        },
        hideLoadImage: function() {
            if (!this.loadImage) return; 
            this.loadImage.style.display = 'none';
        },
        hideCommentForm: function() {
            if (!this.commentForm) return;
            this.commentForm.style.display = 'none';
        },
        addCommentForm: function() {
            if (this.commentForm) {
                this.commentForm.style.display = 'block';
                return;
            }
            var form = document.createElement('div');
            this.container.appendChild(form);
            this.commentForm = form;
            with (form.style) {
                margin = '0px 0';
                padding = '5px 0';
                // borderTop = '1px solid #ddd';
            }
            //if (Hatena.Visitor) {
            //    form.appendChild(Hatena.Visitor.profileIcon());
            //} else {
            //    form.appendChild(Hatena.User.getProfileIcon());
            //}
            var input = document.createElement('input');
            input.type = 'text';
            with (input.style) {
                width = '215px';
    	    border = '1px solid #bbb';
                padding = '3px';
            }
            form.appendChild(input);
            this.commentInput = input;
            var img = this.constructor.getLoadImage();
            this.loadImage = img;
            this.hideLoadImage();
            form.appendChild(img);
            new Ten.Observer(input,'onkeypress',this,'sendComment');
        }
    });
    
    /* Hatena.Star.EntryLoader */
    Hatena.Star.EntryLoader = new Ten.Class({
        initialize: function() {
            var entries = Hatena.Star.EntryLoader.loadEntries();
            this.entries = [];
            for (var i = 0; i < entries.length; i++) {
                var e = new Hatena.Star.Entry(entries[i]);
                e.showButtons();
                this.entries.push(e);
            }
            this.getStarEntries();
        },
        createStarContainer: function() {
            var sc = document.createElement('span');
            sc.setAttribute('class', 'hatena-star-star-container');
            sc.style.marginLeft = '1px';
            return sc;
        },
        createCommentContainer: function() {
            var cc = document.createElement('span');
            cc.setAttribute('class', 'hatena-star-comment-container');
            cc.style.marginLeft = '1px';
            return cc;
        },
        scrapeTitle: function(node) {
            var rval = [];
            (function (node) {
                if (node.tagName == 'SPAN' &&
                    (node.className == 'sanchor' ||
                     node.className == 'timestamp')) {
                         return;
                } else if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) {
                    return;
                }
                var cn = node.childNodes;
                if (cn) {
                    for (var i = 0; i < cn.length; i++) {
                        arguments.callee.call(this, cn[i]);
                    }
                }
                var nodeValue = node.nodeValue;
                if (typeof(nodeValue) == 'string') {
                    rval.push(nodeValue);
                }
            })(node);
            return rval.join('');
        },
        headerTagAndClassName: ['h3',null],
        getHeaders: function() {
            var t = Hatena.Star.EntryLoader.headerTagAndClassName;
            return Ten.DOM.getElementsByTagAndClassName(t[0],t[1],document);
        },
        loadEntries: function() {
            var entries = [];
            //var headers = document.getElementsByTagName('h3');
            var c = Hatena.Star.EntryLoader;
            var headers = c.getHeaders();
            for (var i = 0; i < headers.length; i++) {
                var header = headers[i];
                var a = header.getElementsByTagName('a')[0];
                if (!a) continue;
                var uri = a.href;
                var title = '';
                // Ten.DOM.removeEmptyTextNodes(header);
                var cns = header.childNodes;
                title = c.scrapeTitle(header);
                var cc = c.createCommentContainer();
                header.appendChild(cc);
                var sc = c.createStarContainer();
                header.appendChild(sc);
                entries.push({
                    uri: uri,
                    title: title,
                    star_container: sc,
                    comment_container: cc
                });
            }
            return entries;
        }
    },{
        getStarEntries: function() {
            var url = Hatena.Star.BaseURL + 'entries.json?';
            for (var i = 0; i < this.entries.length; i++) {
                if (url.length > Ten.JSONP.MaxBytes) {
                    new Ten.JSONP(url, this, 'receiveStarEntries');
                    url = Hatena.Star.BaseURL + 'entries.json?';
                }
                url += 'uri=' + encodeURIComponent(this.entries[i].uri) + '&';
            }
            new Ten.JSONP(url, this, 'receiveStarEntries');
        },
        receiveStarEntries: function(res) {
            var entries = res.entries;
            if (!entries) entries = [];
            for (var i = 0; i < this.entries.length; i++) {
                var e = this.entries[i];
                for (var j = 0; j < entries.length; j++) {
                    var se = entries[j];
                    if (!se.uri) continue;
                    if (encodeURIComponent(se.uri) == encodeURIComponent(e.uri)) {
                        e.bindStarEntry(se);
                        entries.splice(j,1);
                        break;
                    }
                }
                if (typeof(e.can_comment) == 'undefined') {
                    e.setCanComment(res.can_comment);
                }
                e.showStars();
                e.showCommentButton();
            }
        }
    });
    
    /* Hatena.Star.WindowObserver */
    Hatena.Star.WindowObserver = new Ten.Class({
        initialize: funct
    
    
      

    2007-06-22

    javascriptを理解するためのたった2つの大切なこと:改

    9割ぐらいはハッシュ

    何がハッシュなのか

    javascript存在するほとんどオブジェクトの実体はハッシュだよ。

    var arr = [0,1,2,3];
    

    とかをみると配列(人によってはリスト)に見えると思う。でも実際は違うんだ。

    これは

    var has = {0:0,1:1,2:2,3:3};
    

    と基本的には等価なんだ。ただちょっと束縛されているメソッド(インターフェイス)が違うだけ。

    ためしに

    arr[4] = 4;
    arr['x'] = 'string';
    arr[-1]  = -1;
    

    としてみよう。

    Firebugで確認してみると[0, 1, 2, undefined, 4]というような値がかえってくるよ。

    でもarr[-1]やarr['x']の値は保存されてないのかな?そんなことはないちゃんとアクセスできるんだ。

    それどころかarr.xで'string'がかえってくるんだ。

    別の例を見てみよう。

    var fx = function(){};
    fx[0] = 'somestring';
    

    こうするとfx[0]に'somestring'が束縛される。

    つまりfunctionも一つのハッシュだったんだ。

    これでほとんどのものがハッシュだということが解ってくれたかな?

    ハッシュじゃないのは文字列とか数字とかそいういシンプルなものだけなんだ。

    ハッシュへのアクセス

    ハッシュへはhash[name]でアクセスすることが出来る。

    それ以外にもname演算子や空白を含まなくて頭が数字でない場合はhash.nameでアクセスできるんだ。

    これでhash[name]が関数だったらhash.name(args)とできるよ。まるでメソッドみたいだね。

    関数のあれこれ

    無名関数

    関数には名前を付けなくても使用可能だよ。

    function(x){return x+x}(2); -> 4
    
    宣言文

    関数宣言の書き方って次見たいの覚えてる人が多いんじゃないかな?

    function funcname(args){ do something};
    

    でもこれはsystax sugerだってことを知ってほしい。

    上でも使ってるんだけど。

    var funcname = function(args){ do something};
    

    等価になる。もちろんどちらの書き方でもかまわないよ。

    ただ、(無名)関数を宣言してそれをfuncnameに束縛しているっていうことを理解しておくと便利だよ。

    スコープ closure

    javascriptレキシカルスコープを採用してるんだ。

    レキシカルスコープなんていうと難しく感じるかもしれないけど、結構単純なんだ。

    var x = 'global';
    var fx1 = function(){return x};
    var fx2 = function(){var x = 'local';return x}
    

    これの実行結果は以下になるよ。

    fx1() -> 'global'
    fx2() -> 'local'
    fx1() -> 'global'
    

    fx2の変数xはほかの場所に影響しないんだ。これは関数の中と外ではスコープが違うからなんだ。

    でも以下のような場合に注意してほしいな。

    var x = 'global';
    var fx1 = function(){return x};
    var fx2 = function(){x = 'local';return x}
    
    fx1() -> 'global'
    fx2() -> 'local'
    fx1() -> 'local'
    

    fx2は自分のスコープ変数xがないからその外側スコープに探しに出かけたんだ。

    つまり宣言文varはそのスコープに新しい名前を登場させる機能なんだよ。

    別の場合を見てみようね。

    var x = 'global';
    var fx1 = function(){
      var x = 'local';
      return function(){return x}
    };
    var fx2 = fx1();
    
    x -> 'global'
    fx2() -> 'local'
    

    この例だとfx2()の値がlocalになってるね。

    なぜなら外側スコープっていうのは関数を評価した場所じゃなくて、関数を定義した場所の外側なんだ。

    関数は返り値として関数ハッシュを指定できるよ。

    一つ上の例では実際に関数を返り値にしているね。

    戻り値関数を指定するとこんなことが出来るよ。

    var fx1 = function(){
      var x = 0;
      return function(){
        x = x+1;
        return x;
      }
    };
    var fx2 = fx1();
    var fx3 = fx1();
    
    fx2() -> 1
    fx2() -> 2
    fx2() -> 3
    fx3() -> 1
    fx3() -> 2
    

    fx2とfx3の値が違うのはそれぞれ別の関数が作られるからだよ。

    こんな風に関数が状態を持つことも出来るんだ。クロージャーとよんだりするよ。

    関数ハッシュを使って複数の関数を返すとこんなことも出来るよ。

    var fx = function(){
      var x = 0;
      return {
        'up':function(){
          x = x+1;
          return x;
        },
        'down':function(){
          x = x-1;
          return x;
        }
      }
    };
    var obj = fx();
    
    obj.up(); -> 1
    obj.up(); -> 2
    obj.down(); -> 1
    obj.down(); -> 0
    

    最後に一度ハッシュについてもうちょっとだけ。thisのはなし。

    thisという機能があるよう。ちょっとだけつかってみるね。

    var x = 0;
    var add = function(n){this.x = this.x + n; return this.x};
    var mul = function(n){this.x = this.x * n; return this.x};
    var obj = {'x':0,'do':add};
    
    add(1);   -> 1
    add(1);   -> 2
    mul(2);   -> 4
    obj.do(); -> 1
    obj.do(); -> 2
    obj.do = mul;
    obj.do(); -> 4
    

    thisは評価された場所によって値がかわるよ。

    objの中にいるときはobj.xを扱うし、グローバルにいるときはグローバルのxを扱うんだ。

    http://anond.hatelabo.jp/20070620200618を改訂してみたよ。

    このぶんしょうがjavascriptを覚える上の一助になるとうれしいんだ。

    あとここでつかってるハッシュ伝統的な意味連想配列のことね。

    突っ込みも大歓迎だよ。

    2007-06-20

    javascriptを理解するためのたった2つの大切なこと

    9割ぐらいはハッシュ

    何がハッシュなのか

    javascript存在するほとんどオブジェクトの実体はハッシュだよ。

    var arr = [0,1,2,3];
    

    とかをみると配列(人によってはリスト)に見えると思う。でも実際は違うんだ。

    これは

    var has = {0:0,1:1,2:2,3:3};
    

    と基本的には等価なんだ。ただちょっと束縛されているメソッド(インターフェイス)が違うだけ。

    ためしに

    arr[4] = 4;
    arr['x'] = 'string';
    arr[-1]  = -1;
    

    としてみよう。

    Firebugで確認してみると[0, 1, 2, undefined, 4]というような値がかえってくるよ。

    でもarr[-1]やarr['x']の値は保存されてないのかな?そんなことはないちゃんとアクセスできるんだ。

    それどころかarr.xで'string'がかえってくるんだ。

    別の例を見てみよう。

    var fx = function(){};
    fx[0] = 'somestring';
    

    こうするとfx[0]に'somestring'が束縛される。

    つまりfunctionも一つのハッシュだったんだ。

    これでほとんどのものがハッシュだということが解ってくれたかな?

    ハッシュじゃないのは文字列とか数字とかそいういシンプルなものだけなんだ。

    ハッシュへのアクセス

    ハッシュへはhash[name]でアクセスすることが出来る。

    それ以外にもname演算子や空白を含まなくて頭が数字でない場合はhash.nameでアクセスできるんだ。

    これでhash[name]が関数だったらhash.name(args)とできるよ。まるでメソッドみたいだね。

    関数のあれこれ

    スコープ

    javascriptレキシカルスコープを採用してるんだ。

    var x = 'global';
    var fx1 = function(){return x};
    var fx2 = function(){var x = 'local';return x}
    

    これの実行結果は以下になるよ。

    fx1() -> 'global'

    fx2() -> 'local'

    fx1() -> 'global'

    fx2の変数xはほかの場所に影響しないんだ。これは関数の中と外ではスコープが違うからなんだ。

    でも以下のような場合に注意してほしい。

    var x = 'global';
    var fx1 = function(){return x};
    var fx2 = function(){x = 'local';return x}
    

    fx1() -> 'global'

    fx2() -> 'local'

    fx1() -> 'local'

    fx2は自分のスコープ変数xがないからその外側スコープに探しに出かけたんだ。結果fx

    つまり宣言文varはそのスコープに新しい名前を登場させる機能なんだよ。

    宣言文

    関数宣言の書き方って次見たいの覚えてる人が多いんじゃないかな?

    function funcname(args){ do something};
    

    でもこれはsystax sugerだってことを知ってほしい。

    上でも使ってるんだけど。

    var funcname = function(args){ do something};
    

    等価になる。もちろんどちらの書き方でもかまわないよ。

    ハッシュを返す関数関数を返す関数。closureとthis

    関数は返り値として関数ハッシュを指定できるよ。次のハッシュを返す関数を見てみよう。

    var fx = function(){
      var x = 0;
      return {
        'x':x,
        'add1':function(y){this.x = this.x+y;return this.x},
        'add2':function(y){x = x+y;return x}
      }
    }
    var obj = fx();
    

    実行結果を見てみよう

    obj.x -> 0
    obj.add1(0) -> 0
    obj.add1(0) -> 0
    
    obj.x -> 0
    obj.add1(1) -> 1
    obj.add1(0) -> 0
    obj.x -> 1
    
    obj.x -> 1
    obj.add1(0) -> 1
    obj.add1(2) -> 2
    obj.x -> 1
    

    となる。

    add1はthis.xにたいして演算をしている。つまり返された値が変化しているんだ。

    add2は関数fxに閉じ込められた値に対して演算している。つまりこれらは別の値なんだ。

    とここまでかいたら疲れた。

    読んでくれた人ありがとう

    追記

    落書きのつもりでかいたんだけどブクマがついててびっくり。

    ちゃんとまとめてなかったし、自分のブログに描いても見てくれる人はいないから増田に書いてみたよ。

    ほかの言語技術についても同じような解説が欲しかったら何らかの方法で言及してくれるとうれしいな。

    さらに追記

    ここまではてブが300突破してるみたいだけどいま、自分のブログリンクを張ったら増田に書く意味がなくなるんじゃないかと思うんだ。

    やらないけど。

    こんなのもかいてみたよ、増田で。 http://anond.hatelabo.jp/20070621153600

    2007-05-11

    []http://anond.hatelabo.jp/20070509134106

    public class FizzBuzz {
    	public static class NumMessagePair {
    
    		private final int base;
    
    		private final String message;
    
    		public NumMessagePair(int base, String message) {
    			this.base = base;
    			this.message = message;
    		}
    
    		public boolean isAliquot(int num) {
    			return (num / base * base == num);
    		}
    
    		public String getMessage() {
    			return message;
    		}
    	}
    
    	private final int start;
    
    	private final int last;
    
    	private final NumMessagePair[] pairs;
    
    	private final StringBuilder result = new StringBuilder();
    
    	public FizzBuzz(int start, int last, NumMessagePair[] pairs) {
    		this.start = start;
    		this.last = last;
    		this.pairs = pairs;
    	}
    
    	public static void main(String[] args) {
    		System.out.print(new FizzBuzz(1, 100, new NumMessagePair[] {
    				new NumMessagePair(3, "Fizz"), new NumMessagePair(5, "Buzz") })
    				.execute());
    	}
    
    	public String execute() {
    		for (int i = 1; i <= last; i++) {
    			if (isAnyAliquot(i)) {
    				addMessages(i);
    			} else {
    				result.append(i);
    			}
    			result.append("\n");
    		}
    		return result.toString();
    	}
    
    	private void addMessages(int num) {
    		for (int i = 0; i < pairs.length; i++) {
    			if (pairs[i].isAliquot(num)) {
    				result.append(pairs[i].getMessage());
    			}
    		}
    	}
    
    	private boolean isAnyAliquot(int num) {
    		for (int i = 0; i < pairs.length; i++) {
    			if (pairs[i].isAliquot(num)) {
    				return true;
    			}
    		}
    		return false;
    	}
    }
    

    自称上級プログラマー仕様認識不足でバグったら教えてもらった後にゆっくり修正する。

    http://anond.hatelabo.jp/20070510174446

    public class FizzBuzz {
    	private final int start;
    	private final int last;
    	private final int fizz;
    	private final int buzz;
    
    	public FizzBuzz(int start, int last, int fizz, int buzz) {
    		this.start = start;
    		this.last = last;
    		this.fizz = fizz;
    		this.buzz = buzz;
    	}
    
    	public static void main(String[] args) {
    		new FizzBuzz(1, 100, 3, 5).execute();
    	}
    
    	private void execute() {
    		for (int i = start; i <= last; i++) {
    			if(isMultiple(i, fizz)){
    				System.out.println("Fizz");	
    			}
    			if(isMultiple(i, buzz)){
    				System.out.println("Buzz");			
    			}
    			if( !isMultiple(i, fizz) && !isMultiple(i, buzz)){
    				System.out.println(i);			
    			}
    		}
    	}
    
    	private boolean isMultiple(int i, int base) {
    		if(i/base * base == i){
    			return true;
    		}
    		return false;
    	}
    }
    

    勝手に修正してみた。

    Javaクラスってコンストラクタとデストラクタって必須じゃなかったっけ?

    あ、CならisMultipleは#defineするから一行で済むんだが…。

    2007-05-09

    []http://anond.hatelabo.jp/20070508170219

    ついでに作ってみた。Javaだお。

    public class FizzBuzz {
    	private final int start;
    
    	private final int last;
    
    	private final int fizz;
    
    	private final int buzz;
    
    	public FizzBuzz(int start, int last, int fizz, int buzz) {
    		this.start = start;
    		this.last = last;
    		this.fizz = fizz;
    		this.buzz = buzz;
    	}
    
    	public static void main(String[] args) {
    		new FizzBuzz(1, 100, 3, 5).execute();
    	}
    
    	private void execute() {
    		for (int i = 1; i <= last; i++) {
    			System.out.println((i) + (isMultiple(i, fizz) ? "Fizz" : "")
    					+ (isMultiple(i, buzz) ? "Buzz" : ""));
    		}
    	}
    
    	private boolean isMultiple(int i, int base) {
    		for (int j = base; j <= last; j += base) {
    			if (i == j) {
    				return true;
    			}
    		}
    		return false;
    	}
    }
    

    自称上級プログラマーならこれぐらい書けないといかん。てかテストコードも書け。

    2007-04-26

    re は response じゃない

    メールの件名の頭に付く「Re:」は Response の略じゃないよ!

    わかりやすい説明の例

    http://www.wdic.org/w/WDIC/re(re - 通信用語の基礎知識)

    ラテン語名詞res(レース)「こと・もの」の奪格re(レー)から英語の前置詞に転じた。なお、ラテン語では名詞の一変化であって前置詞ではない。

    例えば、メールの返答の件名(Re:〜)や、掲示板レスポンスタイトル等に使われる。しかしそもそも省略形ではないので、このRe:はreplyの略でもresponseの略でもない。

    re:がラテン語のres起源であることについては、メールについての標準であるRFC 2822にも触れられている。

    RFC ってのは、簡単に言うと「インターネットで使う技術の細かい作りについてちゃんと決めて、みんなでその決まりに従おうね!」というもの。じゃあ RFC 2822 について見てみよう。

    http://www.puni.net/~mimori/rfc/rfc2822.txtInternet Message Format)

    The "Subject:" field is the most common and contains a short string identifying the topic of the message. When used in a reply, the field body MAY start with the string "Re: " (from the Latin "res", in the matter of) followed by the contents of the "Subject:" field body of the original message.

    「Subject:」フィールドはもっとも一般的で、メッセージトピックを識別する短い文字列を持つ。返信で使われると、そのフィールドボディは「Re:」(ラテン語の「res」、「??について」から)で始まるかもしれない(MAY)。

    きちんとメールに関する標準規格文書に明記されているんだよ!

    これら二つの記事をまとめると、「Subject: フィールド(件名欄)にはラテン語の res (レース)が変化した re (レー)を使う場合もある」ってことになる。繰り返すけど replyresponse関係ないから注意してね!


    さて、それじゃあ次に他の辞書ではどうなってるか見てみようね!

    http://dictionary.goo.ne.jp/search.php?MT=re&kind=ej&mode=0&base=1&row=4(Re: - goo 辞書

    Re:

    コンピュータ】リプライreply) ((電子メールの返信)).

    \(^o^)/

    goo 辞書さんが出す情報(EXCEED 英和辞典の内容)まちがってるよ! これってどこにメール送ったらいいのかな。三省堂電話しなきゃだめ?

    訂正しないと RFC 2822 でちゃんと明記したひとがかわいそうだよ。だって「メールの頭についてる Re: はラテン語からきてるんだからね!」って言ってるのに「英語reply だよーんあばばばば」なんて言われたら、「最初にラテン語だっていったのに……」って悲しくなっちゃうよ。ひどいよ。

    辞書言葉に対する一般的な認識を列挙するものだってことはわかってるよ。言葉が変化するものだということもわかってる。俗説を書くなとも言わない。でもね、Re: の場合は最初にきちんとした定義があったんだよ。俗説は俗説なのであって、定義を超えることはできない。

    たとえば円周率は 3.14 って学校で習うけど、これは小学生に記号を使った計算は難しいので、円周率に関する計算では記号を使わずに 3.14 ということにするってだけの話で、別に円周率が 3.14 になったわけじゃない。円周率はπなんだよ。同じように、Re: が replyresponse の略称であるという誤った俗説がいくら広まったところで、Re: は ラテン語からきてて、その事実は全く変わらない!

    俗説を書くなとは言わない。だけど俗説は俗説だと明記しないとだめだよ。本来の意味とは全く無関係なんだから。この三省堂 EXCEED 英和辞典の内容は、俗説が本来の意味であるかのようにしか読めないよ。

    勘違いすることはわるいことだと思わない。科学技術者だって誤用ぐらい平気でやる。でも科学技術における、言葉に対する一般認識と正しい意味の差が理解できない人は、科学技術の用語について述べるべきではないよね! 少なくとも指摘を受けたら訂正するべきだよ。

    というわけなんだけど、三省堂 EXCEED 英和辞典の件はどこに連絡すればいいのかな。

    http://dictionary.sanseido-publ.co.jp/support/question.html(辞典に関するお問い合わせ - 三省堂書店

    ここでいいのかな。ちょっとメール送ってくるね!


    次はアルクだよ!

    http://www2.alc.co.jp/ejr/index.php?word_in=re&word_in2=%82%A0%82%A2%82%A4%82%A6%82%A8&word_in3=PVawEWi72JXCKoa0Je

    RE

    【前】 〈ラテン語〉??に関して、用件{ようけん}◆ビジネスレターや電子メールで使われる。

    正しかったので問題ないです! でも、〈ラテン語〉って書いてあるせいで、なんかラテン語の前置詞みたいに見えるね。最初の「re - 通信用語の基礎知識」にも書いてあったように、ラテン語の前置詞じゃなくて英語の前置詞だよ。まあこれはアルクの表記スタイルを把握できていない僕がわるいんだけどね!


    というわけで、みんな誤用しないようにね! ばいばい!

    ログイン ユーザー登録
    ようこそ ゲスト さん