はてなキーワード: MovableTypeとは
日本の幼稚園でよく使われる「チューリップの名札」の絵文字(📛)のこと。海外ではチューリップの名札にあまり馴染みがなく、また、それが「燃えている豆腐」に見えることから。
様々な呼び方があったようだが、「Tofu on fire」というワード自体は、2014年のTwitter投稿が初出のようだ。
※このTweetを引用した記事は、昔はてブで上がっていましたね。すっかり忘れていた。(https://twitter.com/cabel/status/513444503345037312
※絵文字自体の初出は、2002年のau携帯に実装された「Type C-2」(https://emojipedia.org/name-badge/
「Tofu」にまつわる名称として、Webサイトのテキスト表示に利用されることがあるGoogle製の「Noto Font」は、「No More Tofu」という意味から名付けられている。
由来は、デバイスがフォント表示に対応していない(フォントがインストールされていない)場合に、表示されるべきテキストが四角(□)に代替表示されるが、それが豆腐と呼ばれること。そして、それを「世界から無くす」ということから。
ちなみに、「tofubeats(音楽アーティストとして活動)」氏のご実家は、豆腐屋ではないとのこと。名前は大体雰囲気で決めたようだ。
また、Six Apart社が展開するCMS製品「MovableType」の公式キャラクター「トフくん」は、綴りが「Toph」であり、豆腐とは関係ないようだ。
まずは、大変遅ればせながらはてな上場おめでとうございます。2ヶ月遅れですが。
先にお断りしますと、この文章は長いです。12,000文字近くあります。そう言えば最近「長すぎて読めない」ってタグ見なくなりましたね。
元々は数日前に自分のブログに投稿したのですが、アイコンを見てもIDを見ても誰にも認識されていないであろう私がこんなことを書いているのも気持ち悪いような気がして、衝動的に消してしまいました。そんな文章ですが、せっかく書いたので思い返して増田に投下します。それでも交流のある僅かな方からは、「あ、あいつだ」とすぐバレると思いますが、全く構いません。
大げさな振りをしてしまいましたが、この、はてなの世界からゆるやかに距離を置こうと思いまして。
ハイコンテクストな話題で、関係者でも有名ユーザーでもない私が語るには随分と分不相応であろうことは承知しているのですが、私は人知れず長年このはてなという会社とそのサービスの利用者でした。たぶん、相当熱心なファンのほうだと思います。
しかしこのはてなという界隈、おそらく長年世間一般的には「俺ははてなが大好きなんだー!!」とはなかなか言い出しづらい雰囲気と言いますか、一部一種のギーク(ナードか?)臭さみたいなものから逃れられないセグメント感があったために、公の場であまりそれを声を大にして語る機会が無かったという状況があったような気はしています。
勝手な想像ですが、よく言われるとおり先日上場した株式会社はてなとしてはきっと、そういった閉鎖的なカルチャーからの脱却を図る必要があるのは事実なのであろうと考えています。
私は「はてな界隈」という自然発生的な、「インターネット好き」が作ったプラットフォームとコンシューマージェネレイテッドなコンテンツが組み合わさってできた若干マニアックな文化がとても好きで、かつてインターネットに期待していたワクワク感のようなものを自分の感性ともっとも近い形で目指している会社だなと思っていたので、はてなを好んで使っていた理由も、今これを書いている理由も、サービスが向かう方向性とのギャップが発生したということで仕方ないのかな、と考えてはいます。
回りくどい書き方ですが、つまり、ここ最近(数年)の急激な利用者層の変化、人気ブログやホッテントリに上がってくる記事とその使われ方の変化、新たな利用者層との精神的摩擦に疲れて消耗するのが嫌になった、ということです。
私は自分の楽しみのために自分が面白いこと書き、読むっていうスタンスで自分のスペースを使ってきたので特定のユーザー群を非難するのはその趣旨とズレるし、メタな「ブログ論」を書くつもりは無いんです。なのでわかりやすいバズワードは書きませんけど、要は、そういうことです。お察し。
ここまで書いておいてから自己ツッコミを入れますが、私がここでこんなことを書いていても、おそらくそれほどの価値は無いのでしょう。
私は長年使っているとは言いながらも、所謂「はてな村」と言われるような有名ユーザー層に所属するようなアカウントではないし、特別人に見られるコンテンツを上げていたわけでもコミュニケーションを取っていたわけでもないし、こんなことをグダグダ書いていても「知らない人。気持ち悪い。」で片付けられてしまうような気はします。
コンテンツもお金も落としてもいないアカウントですので、ある意味運営側の立場から見れば、「うるさいことだけごちゃごちゃ言って全くサービスに貢献しない面倒くさいアカウント」あるいは「フリーライダー」と言われても仕方がない気がします。
これは別に被害妄想を語っているわけではなくて、自分がサービスを利用して得たメリットと、お客さんとしての価値を第三者的に見た時、そういう風に判断されてしまっても仕方ないかな、と冷静に思っただけです。
最近、はてなブログやブクマを見ていて、「これは自分には合わないな」と思ってケチを付けたくなる機会が多くなってきたことと、でも、ケチを付ける発言力(あるいは権利)のバランスを天秤に掛けて、ああ、もう自分が楽しく見ていられる場所ではないのかな、と感じることが増えてきたことと、単なる1ユーザなのにそんなことを考えてしまうこと、考えさせられてしまうことが嫌になってきてしまったということがあって、こりゃ、私の居場所はもう無いのかもしれないな、と思いつつあるということです。
かつての掲示板サービス群から始まってブログランキングやら、SNSやら、インターネットのサービスではいろんなところでこのような文化の変遷みたいな場面は見てきたはずなのだけれども、思ったより自分の生活の大きな部分にはてブが入り込んで浸透していたことに自分でもかなり驚いていますね。
前提としてなぜ、こんなマイナーキャラの私がそこまで一、ネットサービスに入れ込んでいたのかについてちょっと語らせてください。長くてすみません。
私のはてな歴は12年くらいです。長かったらどうだというわけでは無いのですが、はてなを知ったのはまだ人力検索しか無かったころで、自分が実際にユーザーになったのは例の「日本人にはブログより日記」のちょっと後、「はてなダイアリーをはてなブログに名称変更」とかエイプリルフールネタでやっていたころです。最古参ではなくて、ブログブームの頃に「はてな界隈」を意識するようになったので第2世代くらい、ということになるのでしょうか。
その後アカウントが一回変わっていて今のIDは5、6年くらい前に取りなおしたものなので、おそらく古参ぽさは無いですね。
はてなには他社のサービスと比べてとりわけIT系ユーザーの比率が高いと思いますが、私もそうです。一貫してネット関連ですが完全な同業というわけではなく、何度か変遷を経て今は流通系事業会社のインターネット事業担当になったというキャリアです。
はてなのサービスを認識した時はちょうどMovableTypeの2.6あたりが日本でも流行りだした頃で、「Web日記がhtml無しでこんなに簡単にできるなんて!」「コメントとかトラバとかすげー!コミュニティ作れまくり!」とかっていう話題で日々興奮していたのを覚えています。90年代後半からネットは見ていたけれど、これからいよいよ「普通の人」にもオープンに普及していくんだなー、と夢描きながら仕事で、あるいはプライベートでどう活用しようか考えていたんですよ。「Web2.0」より2年前くらいのことですね。
その頃、ちょうどあるECサイトのコミュニティサービスの担当をしていたんですね。いろいろやりましたよ。掲示板サービスが炎上して閉鎖に追い込まれたり、画像著作権で揉めたり、ブログが使えるようになってからは、「ブログに商品の宣伝を書いてリンクを貼ってくれたら100ポイント!!」とかいう現代であればGoogle警察が1日でぶっ飛ばしにくるようなプロモキャンペーンもせっせこ考えては公開してました。更にその後はOpenPNEベースのmixiっぽいSNSをやったりとか。
今考えるとうわーっていう企画も多かったのですが、おおらかながら大真面目にやってたんですよ。まじめに、ライトユーザーに使ってもらうにはどうしたらいいかとか、コアユーザーがどう伝搬してくれるかとか考えてました。その頃は(ネット上のマーケティングにおいては)セグメントの乖離とかそういう問題も今ほどは研究されていなかったし、たぶん自分でもまだ十分理解できてなかったんですよね。私はそんな感じの人間です。
自分語り方面に脱線したので話を戻しますが、ブログブームちょい前の頃、世の中で出始めたブログのアカウントを片っ端から取っては試すということをやっていたんですよ。ココログ、はてダから始まって、livedoor、goo、Excite、Seesaa、Jugem、FC2、楽天、MSN、ドリコム、ウェブリブログ、ドブログ、Yahoo、ヤプログ、アメなんたら……
でですね、そのときにはてなの特異性に気付いたわけです。
なんだこりゃ、殺風景なサイトだなぁ、なんか研究室みたいだなぁ、システム屋くさいなぁ、ってのが当時の正直な印象です。まったく間違ってないと思いますが。
ダイアリー以外の他のブログサービスはだいたい大手キャリア系か、大手ポータル系か、大手ホスティング系のいずれかじゃないですか。実際仕事で関わることがあったのはそういった会社さん達だったわけだったんですけど、私個人的にはこのはてなダイアリーってやつにとても興味を持ったんですよね。
純粋にIT系オタク集団(失礼)がコミュニティで勝負するっていう構図のサービスがすごく面白いなって思いまして、当時から実際にIT系のギークな技術記事とか、濃厚なネットのいざこざとかそういうのがぐちゃぐちゃと集積されつつあって、うわぁ危険と思いながらもはてなだけは明確に識別して見に行く感じになってたんですよね。
人力検索もそうですが、アンテナとか、キーワードとか。私はネットコミュニティをやりたくてこの世界に入ってきた人間なので、人と人をつなげるサービス、というコンセプトに対して面白いことをやろうとしている人達がいるんだなーって思ってたんです。こんな殺風景な非コミュ論壇だらけのサイトなのに。なんだかそのギャップがまたすごく居心地が良くてね。よく閉鎖的って揶揄されるはてなですけど、私はそんな風に思ったことなかったな。
そう、私は村感というよりは、僻地の秘境だけどここは自由でオープンだ、っていうように感じていたんです。
今はなおさら顕著ですけど、その頃って既にインターネットサービスが外来の大手サービスに集約されつつあったじゃないですか。ブログにしたってMovableTypeもWordpressも外から来たものだし、MySpaceとか、Facebookもそうだし、その後の流れって周知のとおりって感じじゃないですか。強いて言えばmixi……はやっぱべつにいいや。
そんな中、日本のドメスティックな小さなネットベンチャーが純粋なコミュニケーションの仕組みだけで世界観を醸成して、しかも生き残るっていうことに夢を感じたんですよ。まあ、ドメスティックっていう部分について言えば、jkondoさんが渡米した時期とかあったなぁ、とかあるんですけども。
はっきり告白しますけど、私のような自分で新しいプラットフォームを開発するほどの実力が無い中途半端なネット屋にとって、超恥ずかしながら彼らはヒーローだったんですよ。jkondoさんやnaoyaさんは私とほぼ同い年ですけど、勝手に同世代のヒーローだと思ってたんですよ。
はてなブックマークでソーシャル・ブックマークという概念を身近に体験した時は「単なる『お気に入り』じゃなくて、興味を持ったものについて何時でも語り合える世界が作れるんだなあ」ってリアルに衝撃を受けたし、スターが登場した時は(FacebookやTwitterより前に)これ、シンプルだけどもしかして世界を幸せにする機能じゃね?って感動したりしましたよ。
だいたい、jkondoさんはすごいんですよ。私など勝てる要素が無いですよ。スプリントでもロングでもヒルクライムでも絶対勝てないですよ。山も強いし、みんな山手線一周1時間48分てできます??サラッと書かれてたけど、メチャクチャ速いよ!!俺も何度もやってるけど、大真面目にやっても3時間切るのだって大変だよ。明治通りや中央通りはともかく、田端駒込あたりの裏路地とかどうしてたんでしょうね。メッチャ危ないよ!!つか、あの頃の自転車クラスタみんなどこ行っちゃったんでしょうね……
何の話でしたっけ。そうそう、趣味が合いそうな人達が集ってるっていう話でしたね。
私の文章は、テキストサイトからアルファブロガーあたりまでの文章にめちゃくちゃ影響を受けていると思います。ちょっと極端なことを書いたら「フロムダ先生の真似か」とツッコまれてドキッとしたり、写真クラスタの真似をしてやたらでかい写真を並べてみたり。最近は年に一回お正月だけに現れるmk2さんの文章を見ると涙が出そうになります。長文には慣れています。必死に調べないとついていけないような技術論議や、内蔵をさらけ出して書いたような、編集が入った本では読めないようなブログを読みたいし、そういう記事でみんなが共感していく世界が見たかったんです。
はてなブログの目次記法は便利だと思うんですけど、他所のニュースサイトに貼られた記事を引っ張って目次を並べていかがでしたか?なんていう記事を、私は単純に面白く読めないんですよ。「参考になりました!」じゃねーよ!!ならねーよ!!残念すぎるだろ!!なんて思ってたんですよ。
ここまでで既に5,000文字を超えてしまいましたが、話が飛んでしまったので一旦元に戻します。
つまり、そういった「自分の好きなものを好きと言う」「好きなものを選んで、好きなものを見て共感する」という、人の本能的なコミュニケーションの楽しみの源泉のようなものを、私は求めていたんだと思います。自分の背中に正直な、泥だらけのスニーカーで追い越すような体験を期待していたんです。
もちろん、どんな時代にだって人と人のコミュニケーションにはいろいろあって、変わらないものがたくさんあるんだとは思いますよ。パソ通の時代だって、BBSの時代だって、初期のブログにだって、「読みました。記念カキコ☆」はあったし、コメント欄で交流が繋がって新たな友達ができるという興奮だってあったし。
最近のはてなだって、今、その興奮を新たに体験して純粋に喜びを感じている人達がいるはずだしそれはもちろん喜ばしいことなんですけど、さすがにこの情報過多なご時世なので、ツールと場所の管理と運営をしっかりやっていかないと、純粋な喜びを埋もれさせず、コンテンツの品質を保つのは相当に厳しいなという実感はありますね。
一般化、大衆化、というものはだいたいそうで、単純に「この村も昔は良かったのに」っておじいさんが言っているっていうような話ではないと思うんですよ。
こんなことを話している私自身が既にネット上では「古い側」の人間になっているのかもしれませんが、個人的には、「はてな村」とかって言われている界隈にそれほどイライラするような内輪感を感じたことは無いんですよね。実際にひどい攻撃的な言葉が飛んできて嫌な思いをしたことだってありますし、慣れ合いとかってのは昔も今もあるわけなんですけど、だいたいは好きなことを好きなように書いた、っていうモチベーションによって書かれた記事は、面白ければ当たるし、面白くなければ流行らないわけじゃないですか。読む側だって気に入ったら読めばいいし、気に入らなかったらスルーすればいい。だいたい、広い世界で見ればごく一部のできごとだっていう側面もあったわけじゃないですか。
だから、一定の、嘘を嘘と見抜ける程度のネットリテラシーさえあれば、海水浴場の中に浮かぶ邪魔な漂着物があっても、農耕地が石だらけで荒地になっていても、単に避ければいいだけだって思ってたんです。
むしろ、良い記事にフォローが集まったり、ひどい記事はひどい記事でそれに集まった批判が有益だったり、そうやってやり取りを応酬する中で集合知として収斂されていくという光景は、みんなで海を掃除したり、畑を耕していくような感覚を覚えていつもネットの醍醐味であり爽快ですらありました。
……でもね。最近の例の動向はちょっと様相が違っていて、私のようなユーザーにとってはもうちょっと見ているのが厳しいな、というのが本音です。商業的なまとめサイトが場を汚染している、というような話であればユーザー側コミュニティによるチェックと自浄作用が働きます。はてブはうまいことそういう機能を果たしてきたと思うんですよね。
でも、ユーザー側のほうで「良いと思ったから良いと言った」というお気に入りによるキュレーション機能が働かず、返報性の原理によるコミュニケーションが中心の場になってしまったら、今のままのはてブでは、(コメントツールとしてはともかく)少なくとも情報ツールとしての価値は大きく毀損されます。これは、ユーザーのモラルもありますが、サービスの構造上の問題として避けられなかったことだと思うんですよね。
海や畑が全部「あれ」になったら、もうどうしようもないでしょう。もう去るしかない。
この問題についてはさんっざんぱらたくさんの人に書き尽くされているのでここでは書くつもりないんですけど、小遣い目的で面白くない記事が量産される、共有のヘッドラインが専有されて他のユーザーに影響を及ぼす、内容に関係なく相互フォローする、これらは本人の意識あるなしに関わらず、関係ない人から見たら無益です。
これについてルール違反がないのならば、サービス品質を維持するための運営/システム側の構造課題を疑ったほうが良いし、ユーザー側についても、一部の炎上チャリーンで喜ぶようなやつは単なるスパムなのでこれは単純な絶対悪ですよ。
別に、ネットの世界で今始まったことじゃないんですよ。むしろはてブは牧歌的で今まで性善説でよくやってこれたなっていうレベルじゃないかと思います。Twitterでも「相互フォロー推進委員会」とかあったなあ。一方的に何百人単位でフォローしてきて、ふぁぼりまくって、こっちが反応しないと砂をかけて去っていくようなのが……
ただそういう人達がごにょごにょ楽しくやってるだけならどうだっていいんですけど、今はホッテントリが明らかに使いづらくなっていたり、更には他のSNS経由でこの界隈の記事が流れてきて反応したらおかしなことになったり、実際にそういうことが発生しだしているんですよね。これが結構精神的にくるものがあるんですよね。
というわけで、そういう一団がこのサービスのほんの数%、もしかしたら0.数%の人達であり、ほとんどの普通の人は何も気にせず普通に自分の日記を書いているんだ、てことはわかっていても、でももう気持ち的にこの界隈と一緒の世界でブログを書くのは無理かもしれない。既に古参と言われる人達がかなり去っていっているし、生き残っている人達も読者層が急激に変わっていたりとかして、なんていうか、見ててつらい。
※最近、ある有名人気ブロガーのブログを読んでいて、半年前にも同じテーマで書かれたことがある記事がホッテントリに入っていたのを見たんですけど、ふとブコメを見てみたら、半年前の記事と反応のコメントが全然違くてびっくりしたことがあったんですよ。よく見ると、並んでいるアイコンがガラリと変わっていることに気づきました。読者層が急激に入れ替わっているんですね。
この人はムラ社会に寄る人では(読者から見たイメージでは)無いし、長い人とも新しい人ともバランスのいい関係を築けていてすごいなあ、と思っていたのですが、図らずも急激に「有名人」として新規層の神輿に乗せられているように見える状態になってしまって、一方で彼自身は広告収入で儲けているようなブロガーではないし、内心複雑な気持ちなんじゃないかな、とか勝手な心配をしていたりします。そういう人、何人かいますよね。余計なお世話すぎるとは思うのですが。
------------------
そういう中で有名な人、について分析をしてみる
人気は勿論わかるんだけど、実績で見ていってみて、冷静に、どういう点で有名になって、今何が凄いのか?という点について考えてみる
### 伊藤直也氏
新卒でニフティ、はてなに転職して、ブログ時代に知名度をあげる
はてブを作って、はてブユーザにとっては神なのかもしれない。はてなCTO。
その後、グリーに転職し、スマホ事業部長。2015年の大赤字化したグリー。
経営の問題はあったのかもしれないが、明らかにスマホ事業の苦戦はスマホ事業の責任者であった、伊藤直也氏が作ったものだと言ってもおかしくはないと思う
http://www.itmedia.co.jp/news/articles/1009/07/news070_3.html
そして、今はフリー、とかいって優雅に寿司を食いながら技術系の人にインタビューしたり、技術顧問とかいって格好をつけているけど、新しい技術にちょこっと手を出し、マスターしたつもりになっているだけで、肝心のプロダクトを出して、それがヒットしたとか、そういうものが無いので、正直何が凄いのか分からない
知名度だけが先行して実力が伴わなかった最たる例であるように感じる
はてな自体のPVもキーワードリンクスパム、はてブのブックマークページのペナルティ扱い等、伊藤氏が作った仕組みによって、大きく下落していることも忘れてはいけない。
MovableType潰して、Plaggerも鳴かず飛ばず。
http://kessan-kanpo.blogspot.jp/2015/06/13.html
食えなくなったので、Cookpadに逃げ込んだ、というイメージ
この人も人気はあるにせよ、技術的観点以外での実績というものがない
### あまちゃん氏
技術系の人に人気があった、というだけで、具体的に何をどうしたとか、JavaScriptを作った人でもないのにそれっぽく扱われている事にかなりの違和感があった。
ヒットプロダクトがずーーーーーーっとない状態。お花のFacebookプレゼントサービスも鳴かず飛ばず
新しく作ったサービスも、200万PVを超えたとかいうことでニュースになっていたけど、200万PVでは到底食えないし、日本のトップサービスのPVからしてみれば誤差の範疇。
http://jp.techcrunch.com/2014/04/21/140421-kactel-pictory/
一向にiOS版が出てこないし、やはりプロダクトを作るのに向いてない人なんじゃないのって思ってしまう。
というか、センス無いよ、と思い続けて5年以上、やっぱりセンスなかったな、という印象。
----
まあ要するに私がいいたいことは、人気、知名度と実力は必ずしも一致せず、
本当にトップのサービスやヒットサービスをやっているような人ほど、いちいちブログなんか書かずにプロダクトに集中したり、コードを書いているよねっていう話です。
10年も前からはてな界隈では有名人だけど、今は没落している人が多いように感じるのは、実際の所、実力が無いのに過剰評価されていたことの証明だとは思う。IPO直後の株価のように、やはり実態は平均化される。
勿論、人気も実力のうち、であることは承知してはいるが、実力がないのに過大評価されている状態を見ると、なんとも残念な気持ちになってしまうのでした。
オシャレハットマン家入とホリエモンが「ロゴなんて5000円で十分でしょ」と言って批判されているらしいけど、それってもう英語圏では遠い昔に通り過ぎた話なんですよね。その辺のwebサービスとかのロゴなんて5000円が適正相場になってるのが英語圏の現実です。本当に日本人というのは頭が古いと言うか井の中の蛙というか、日本語という壁に守られて温々育っちゃって時代遅れの主張をよーいドンで一斉に始めちゃう恥ずかしい所がありますねえ。
そりゃ名だたる企業のロゴだったらそれなりの制作料になるわけですが、小さい企業とかローンチしたばかりのwebサービス、スマホアプリなどのロゴで10万以上かけて作る人はもう絶滅しました。いません。死にました。今のトレンドは「テンプレートから既成のロゴを選択して、+自分の企業名のフォントだけを手作業でデザイナーに入れてもらう」形式です。つまり同じロゴを使ってる企業やサービスが世界中にたくさんあるわけですよ。たくさんあるって言っても世界は広いからほとんどバッティングなんてしないわけですね。例えば最近見たパン屋さん向けのロゴで人気のものは15件も売れてるわけですが、世界中にいくつパン屋さんってあるんでしょうか。星の数ほどありますね。だから被ってたって問題にはならないわけです。それが2013年のロゴに対する世界の人々の普通の感覚です。
インターネットやスマホアプリの普及のお陰で、ロゴに対する需要は1990年に比べると15倍になったそうです。今や一般のブロガーですら自分のロゴを持つ時代ですからね、そのぐらい増えてても不思議ではありません。それに対して、ロゴを軽く作れちゃうぐらいのデザインスキルとソフトを持っている人は20年前から比べるとなんと50倍になったそうです。供給量は需要の伸びを大幅に超えてるんですね。これがロゴの価格低下の最もたる原因の一つです。あんな二次元の適当な仕事でクリエイティブなんてもう恥ずかしくて名乗れない時代なのです。(もちろんトップクラスの仕事は別ですよ、あくまで下の方ってこと)
こういった傾向は別にデザイン業界に限りません。例えばほんの8年前、2005年当時を振り返ってみましょう。
・MovableTypeでちょっとしたブログを書いているだけでネットメディアから取材が来ました。
・Ruby on Railsに詳しいというだけでRuby界で一目置かれました。
どれもこれも、今はその辺の20歳の大学生でもできるレベルですよね。それがたった8年前はもてはやされてたわけです。
ランサーズ(http://www.lancers.jp/)などの例を挙げるまでもなく、クラウドソーシングサービスによってますますクリエイティブの単価は下がっています。需給のミスマッチは価格を押し上げる方向に働きますが、ランサーズのようなサービスによってロゴ作れる人とロゴを欲している人がいとも簡単に繋がれるようになって、つまり需給ミスマッチが改善されている訳ですが、それによって何が起きるかと言うとますます価格が下がるんです。当たり前です。どんな世界もこういう風にできてます。この理屈がわからない人は学部一年生が読むような経済学の教科書でも読んでから出直してください。
僕みたいなデザイナーですらロゴ5000円は仕方ないかなと受け入れてます。だってブランドもCIも無いようなその辺の小さな事業主向けのロゴなんて、理屈も理念もへったくれも無いわけです。事業主の個人的な趣向に合わせてなんとなーーーく小綺麗なロゴを作るだけの仕事です。そんな仕事はもうまともなクリエイティブを持った人間はやってませんよ。そういう仕事で飯が食える時代はとっくの昔に過ぎたんですね。
なんだかこの手の話に毎回妙に怒る人いるじゃないですか。デザイナーでもないのに。なんなんでしょうねああいう人って。誰のために怒ってるの?デザイナーの権利のため?それとも社会のために正義を訴える自分に酔いたいから?こんなくだらないことに怒る暇があったら他に怒るネタはあるでしょう。怒るべきネタが。ほんと暇人ですよね皆さん。
僕らデザイナーは怒る暇があれば勉強します。僕は毎日2時間割いて、新しい技術・世界のデザイン趨勢・他文化の勉強・異業種との情報交換・ヘルニアにならないための運動などなど、生き残る為に必死で頑張ってます。怒ってる暇があれば勉強するのがどんな世界でも生き残るための唯一の策なんですよ。デザイン業界のグローバルな流れも知らないで、感情論で「5000円は安い!人権侵害だ!」って、そういう人はサヨク活動でもやってたらいいんじゃないですか。もうそういう時代じゃないんです。
PHPerの問題点は、視野が狭いこと。典型的には以下のような悪癖を持つ。
何も知らないからPHPを愛せるんだよ、PHPerは。だからまず、HTML、CSS、JavaScript、SQLを覚えろ。次に、Javaに移行しろ。そんなに難しくないよ、Java。特に大量にコードを書けるPHPerは、速度が出てライブラリ化が容易なJavaの方が向いている。今はVPSがあるので、小規模案件でも問題ない。
15年間ほどPHPはインターネットを支えてきたが、そろそろ設計の脆さが問題になっている。PHP 6の開発が振り出しに戻ったのは、不幸な事故ではない。ウェブで仕事をしていれば、PHPとJavaで共通する知識も多い。PHPerはJavaを覚えてPHPとさよならしろ。そして恥ずかしい悪癖を直すべきだ。
2010年の年末から年始にかけて10連休ほどあったので、新しいサイトを作ろうと思い立った。
月に1万円だと、毎日コーヒーを飲んでるだけでなくなってしまうので、コーヒー代くらい稼げたらうれしいなあ。じゃあどうする。何を作る?
ということで、まずTwitterを使ったものを作ることにした。
ひとつのジャンルにしぼってツイートをかき集めれば、面白い流れになるんじゃないか。人が来るんじゃないか。そう思った。togetterみたいな。で、ジャンルは、個人的に興味がある子育て。ていうか毎日帰宅してから朝まで子どもの寝かしつけや夜泣きの対応でサイトを更新する暇も、俺が寝る暇もあんまりない。ので、手がかからないことが大前提。なんだったら自動更新でもいい。
自動更新かー。と思って「ブログ 自動更新」でググったら、wordpressにRSSから更新するプラグインがあるらしいことを知った。はい決定。その瞬間、「TwitterのAPIからRSSを引っ張ってwordpressに投稿するサイト」に決まった。
さくらインターネットのスタンダードを申し込んだ。14日お試しがあるらしいけど、仮申し込みの時点で住所も入れてコンビニ請求にしたら、数日後に請求書が送られてきてビビった。(同時にドメインも申請しちゃった)
まあ、webで申し込んで、すぐにサーバコントロールパネルという画面に入れるようになった。「クイックインストール」というリンクがあったので見てみたらMovableTypeとWordPressを自動でインストールしてくれるらしかったので、ボタンを押した。インストールできましたというので発行されたURLをクリックしたけど404だった。1時間くらい404で、その日はもう寝た。
次の日の夜。これはもう、10連休を利用して毎晩1時間ずつ捻出するしかない、さくらのお試し14日あるから約14時間で作りきるしかねえ、と思った。
サイトにアクセスしたらwordpressが入ったページが出てきた。おお、サイトができてる!
まずTwitterを調べるか、と思って、「Twitter API」で検索したけどOauth?とかいう面倒なことをしないといけないらしかったのでやめた。じゃあ普通に検索は?と思って「Twitter 検索」で検索したら、search.twitter.comの結果はjsonかatomで取得できるし、APIコール制限もないらしいのでこれに決定。検索だけで1時間たった。
夜も更けて、続けて作業した。「wordpress xml 投稿」で検索していくつか探したらFeedWordpressというプラグインがあったので入れた。あ、事前知識としてMovableTypeでのブログはやったことがあったので、プラグインを入れるみたいな話はスムーズに進められた。
で、twitterの検索結果をatomで返した結果を入れてみた。ら、本当に投稿されてた。よっしゃできた、と思った。1ツイートが1エントリになってたし、投稿者もツイートした人になってた。よかった。でも、満足できなかった。
次の日。同じことを自力でやる方法を探した。「wordpress xml 投稿」で検索して、XMLをパースできるようになればいいんじゃないかと思い、simplepieというPHPライブラリにたどり着いた。が、PHPなんてまったく知らないし、憶える気もなかった。actionscriptで書かせてよ、とずっと思ってた。
次の日。「wordpress xml 投稿」でまた検索。どうやらwordpressの投稿って、xmlrpcというやり方を使ってるらしかった。ので、「wordpress xmlrpc 自動投稿」で検索したら、なんかサンプルコードが載ってたのでそのまんまコピペ(結局PHPだった)。したらちゃんと投稿されていた。ふむ。ここで何を思いついたのか、「wordpress xml パース」と昨日みたいなことを検索した。simpleXML?というライブラリがあるらしかったので、それを試してみることにした。(たぶんPHPが動いたので気をよくしてたんだと思う)
こういう流れでいけると思った。考え方はactionscriptをエディタに書いて、ノリであてにいった。変数に宣言するのはできた。$var1とかで宣言したことになるらしい。URLRequestに相当するコードを探したら「file_get_contents」らしいことが分かった。(「PHP 外部ファイル」で検索)
で、ゲットしたのはXMLなんだけど、上記検索したなかにたまたま書いてあった「simplexml_load_string」というのを使うとXMLをパースできそうな気がしたので、ノリで書いたactionscriptでは
var req:String = "http://search.twitter.com/?q.atom=mogemoge";
var r:URLRequest = new URLRequest(req);
var kekka:XML = r.send() as XML; ←いまここ
なので、XMLにキャストしたんだろうなみたいな感じだった。E4Xを使えればいいのにPHPって馬鹿ねと思いながら寝た。
年があけて、3が日が終わりそうだった。年末にやってたこと(上記までのこと)を思い出しながら、XMLの必要な部分だけ抜き出す方法を模索した。atomっていってもentryがたくさん入ってたから配列にするんだろうけど、ってんで「php foreach」を検索。なんとなくサンプルコードをまねしながら、記事タイトル、記事本文だけ取得した。あとはxmlrpcのサンプルにあわせて投稿するようにした。できた。寝た。
次の日の朝、ブログを見た。昨日更新したものしかあがってない。自動じゃねーじゃん。
で、「自動 投稿」で検索したら、クローン(cron)という仕組みを使わないといけないのだった。クローンはサーバの仕組みらしく、そういえば俺はPHPをはじめDB、サーバという単語を極力さけて仕事してきたので、もう気持ちが悪くなってきた。「さくらインターネット cron php」で検索して、なんとかやり方を見つけて、cronを登録した。(1時間に1回にした。設定は * * * 0)
仕事から帰ってきて、サイトを見ると、投稿が大量にたまっていた。やった!で、調子に乗ってツイッターアカウントを作った。なんだったらツイッターも自動化したかったので「twitter bot」で検索した。Easybotterというサンプルボットがあったので使わせてもらった。自動で一行ずつつぶやくようにした。
ツイートを集めることは成功したけど(毎時間100件のツイートを1エントリとして投稿してる)、それを眺めて面白いんだろうか? ボットを動かしてるけど人がくるんだろうか?
そんなとき「trivist」がはてブに載ってた。なんかにたものを感じた。やっぱツイートを引っ張ってきて投稿するサイトはアリなのか?アリなはずだ!
サイトの体裁を整えた
trivistをまねて、記事を評価(はてなスターとかいいねボタンとかに近いもの)する仕組みが欲しくなった。「wordpress 評価 プラグイン」で「wp-postratings」というプラグインを発見して、入れてみた。どうやら1エントリーに1評価しかできないらしい。俺のサイトは1エントリーに100ツイートあるから、どのツイートを評価するのかが分からない。
いったん、wordpressの全投稿を削除した。で、cron に登録されてるPHPを、1記事に1エントリーにした。
エントリーを投稿するついでに、Yahoo日本語解析APIをつかってツイートを分析して、名詞と動詞だけを取り出そうと思った。それをタグにすれば、タグクラウドが作れると思った。はてブはずっとずっと昔からやってるから、Yahoo日本語解析っていうのが2006年くらいに流行ったことをなぜか憶えてたので、やってみた。できた。
なんか俺、PHP書くのが早くなってね?
アクセス解析を入れてみた。サイトに来てる人は、俺だけだった。
どうにかして人を増やしたい。サイトの広告募集はする気がないし、ベタベタとバナーを貼りたくなかった。みんなが気軽に見に来て、軽い気持ちで評価してくれて、更新を楽しみにしてくれるサイトにしたかった。コミュニティサイトじゃないけど、やっぱりサイトはコミュニケーション設計をしないと意味がないんじゃないか、見てくれるユーザはどうやったら楽しいんだろう、ということを考え続けて10日ほど経った。Twitter経由で来てくれた人が3人ほどいるようだけど、何がダメなのか分からないので増田にお願い。
ここまで書いて教えてくんじゃねーか、と思われるかもしれないが、ググレカス的な検索は上記で書いたみたいにいろいろやってきた。でも、サイトを作ってみてはじめて、ユーザに向けたサイトってどう作ればいいのかが分からないということに気づいた。
小遣い稼ぎもしたいんだけど、面白いサイトを作るヒントがほしいと思った。
kanzen21やtrivistみたいに、俺も過程を全部さらしたから、辛辣な意見を求む。そしてはてブされるのを待ってます。
色々教えてください偉い人。
自分で考えろってのはご尤もですが、色々な方の意見が聞いてみたいのです。
・Struts(ver2じゃないほう)上でのJava(max2000行程度)
・perl(max7000行程度)
・c/c++(ちょっと)
・Haskell(ほんの少し)
・VisualBasic(.NETじゃないほう)(ほとんど忘れた)
・HTML/CSS(セマンティック厨)(HTML5は勉強中)(バイトでWEBデザイン経験有)
・javascript(簡単なものなら)
・MovableType(CMSとして利用。ちょっとした企業サイトレベルくらいのものの構築。簡単なプラグインの作成とかも)
・Apache(セットアップと最低限の設定くらい)
・Tomcat(同上)
・Linux(CentOSとUbuntu。セットアップとちょっとした設定程度)
・AdobeのDTP系製品(CS2)(雑誌編集経験有、ただし学生レベル)
・Oracle(10g)(Bronzeレベルの知識とちょっと触ったことがある程度の経験)
・postgreSQL(ちょっと触ったことがある程度)
・会計関連の知識(日商簿記2級)(大学で管理会計をかじった)
・数学系の知識(論理とか集合やらの基礎。大学で計算機科学をかじった)
・印刷物/WEBサイトのデザイン(独学だけどそれなりに。一般人よりはそれっぽいデザインが作れるかと)
http://anond.hatelabo.jp/20100424103036
Wordpressのサイトにリンクを貼ったのが、営業妨害と受け取られたということ?
デヴィ夫人が続報を書かれたようなので、MovableTypeとWordpressをやんわりとおすすめしてみた。
今のところコメント欄に反映されているみたいだけど、これも消されるのかな?
/* 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
何かのアカウントを作る必要がないのがいい
ってあるじゃん。
まさにそこ。
機能を得るための労力と、そのある意味わがまま(こだわり)と言える要望のどっちを取るかを取捨選択するのが分析作業だと思う。
たかだか内々での連絡に使用する用途が、携帯の固有番号とひもつけられる事によって本当に問題になりうるのかと言うのも判断すべき点かな。
と言うかむしろ「家族全員携帯持ってねぇよ」と言う問題の方がありそうで、mixiを捨てる致命的な理由になりそう。
後の候補は
通常の掲示板を、.htaccessが使えるサーバに設置してBASIC認証を掛けるとか、
MovableType使って非公開ページを運営するとか。
Movable Typeをローカルで動かしたいんだけど
そういうことって出来るの?CGIとデータベースの仕組みがイマイチわかってないのだけど、データベースを用意するだけでおk?それともそれだけじゃ駄目?
できます。と言うかできるか判らない時点で冒険しないほうがいいよ。(理由:答えを見つけるに足る知識がまず無いから)
複数ユーザで日記書きたいんだけど、Movable Typeなら出来るらしいから使ってみようかなーと思ったしだいなんだけど、はてなのユーザ切り替えよりは楽だよね?
ユーザの切り替えに限って聞いているんだろうけども、総合で言えば
1から環境構築しなきゃいけないサービス(自鯖&MovableType)が、既存の利用するだけでいいサービス(はてな)より簡単な理由は一つも無いぞ。
アドバイスください。
・自分ところで動かすために、自分の所でサーバを立てるか、レンタルサーバを借りる。
・MovableTypeをインストールする(簡単インストールサービスとかやってるとこもあるから探そう)
・日記を書く。
ブログは、我が国にとどまらず、世界のWebの流れのなかで“小さな巨人”としての地位を築いてきた。古今東西の名文を、無料で手に入れやすい形で提供できるからこそ、人はブログを自分の師として、また青春の想い出として、書きついできたのである。
その源を、文化的にはSixApartのMovableTypeに求めるにせよ、規模の上でGoogleのBloggerに求めるにせよ、いまブログはインターネット利用者層の多様化に従って、ますますその意義を大きくしていると言ってよい。
ブログの意味するものは、激動の現代のみならず将来にわたって、大きくなることはあっても、小さくなることはないだろう。
「はてな匿名ダイアリー」は、そのように多様化した対象に応え、ブックマークに耐えうるエントリを収録するのはもちろん、Web2.0を迎えるにあたって、既成の枠をこえる新鮮で強烈なアイ・オープナーたりたい。
その特異さ故に、この存在は、かつてブログがはじめてWebに登場したときと同じ戸惑いをブロガーに与えるかもしれない。
しかし、<Changing Time, Changing the Internet>時代は変わって、Webも変わる。時を重ねるなかで、精神の糧として、心の一隅を占めるものとして、次なるWebの担い手の若者たちに確かな評価を得られると信じて、ここに「はてな匿名ダイアリー」をリリースする。