2012/05/09


しなちく 「お前それ、シナチクって言いたかっただけやろ」

...
...
...
...

「そうですが、何か」

mruby で mruby-httpmruby-uv を使い、sinatra ライクなのが動くまでに到った。
ショボいアプリケーションなら書ける様になったけど、mrubyはまだファイルIOが出来ないのでアプリと呼べる様な物が動くにはまだまだ先。
require 'HTTP'
require 'UV'

# {{{
module Sinatic
  @routes = { 'GET' => [], 'POST' => [] }
  def self.route(method, path, opts, &block)
    @routes[method] << [path, opts, block]
  end
  def self.do(r)
    @routes[r.method].each {|path|
      if path[0] == r.path
        param = {}
        r.body.split('&').each {|x|
          tokens = x.split('=')
          param[tokens[0]] = HTTP::URL::decode(tokens[1])
        }
        body = path[2].call(r, param)
        return [
          "HTTP/1.0 200 OK",
          "Content-Type: text/html; charset=utf-8",
          "Content-Length: #{body.size}",
          """"].join("\r\n") + body
      end
    }
    return "HTTP/1.0 404 Not Found\r\nContent-Length: 10\r\n\r\nNot Found\n"
  end
  def self.run()
    s = UV::TCP.new()
    s.bind(UV::ip4_addr('127.0.0.1'8888))
    s.data = []
    s.listen(50) {|x|
      return if x != 0
      c = s.accept()
      c.read_start {|b|
        h = HTTP::Parser.new()
        h.parse_request(b) {|r|
          i = b.index("\r\n\r\n") + 4
          r.body = b.slice(i, b.size - i)
          c.write(::Sinatic.do(r)) {|x| c.close }
        }
      }
      s.data << c
    }
    while 1 do
      NOTE: must be call run_once to run GC.
      UV::run_once()
    end
  end
end

module Kernel
  def get(path, opts={}, &block)
    ::Sinatic.route 'GET', path, opts, &block
  end
  def post(path, opts={}, &block)
    ::Sinatic.route 'POST', path, opts, &block
  end
end
# }}}

get "/foo.js" do
'$(function() {
  $("#foo").text("hello world");
})'
end

get "/" do
'
<script src="http://code.jquery.com/jquery-latest.js"></script>
<script src="/foo.js"></script>
<div id="foo"></div>
<form action="/add" method="post">
<label for="name"/>お名前</label>
<input type="text" id="name" name="name" value="">
<input type="submit">
</form>
'
end

post "/add" do |rparam|
"
<meta http-equiv=refresh content='2; URL=/'>
通報しますた「#{param['name']}
"
end


Sinatic.run

# vim: set fdm=marker:
Posted at by




WIWA BLOG

... これだけ。 たった数10分で立ち上げられるんです。そう、Pythonならね。

http://blog.wiwa.jp/entry/4fa9ffa7d6f9fd22a5000002
Twitterのパスワードが流出していないか確認:WIWA TWIPASS
http://twipass.wiwa.jp/
Twitterの大量流出したパスワードに自分のものが含まれているかどうか一発でわかる「WIWA TWIPASS」 - GIGAZINE

本日明らかになったTwitterのパスワード大量流出(延べ5万5000件、重複しているものを除いて約3万5000件)について、自分のTwitterアカウントのパスワードが漏れていないかどうかが分かるサイトが登場しています。

http://gigazine.net/news/20120509-twipass/
僕も5分でプラグイン書いた! functions:twipass(name)
  let res = webapi#http#post("http://twipass.wiwa.jp/ctrl/get/twipass"{"name"a:name})
  echo webapi#json#decode(res.content).text
endfunction
command-nargs=1 TwiPass call s:twipass(<q-args>)
mattn/twipass-vim - GitHub
https://github.com/mattn/twipass-vim
これだけ。 たった5分で作れちゃうんです。そう、Vimならね。
Posted at by



2012/05/07


2009/08/16 追記

furyu-teiさんの記事でXSLTの場合はendpointを変えないといけない事が分かったので修正。動くようになった。



2009/07/16 追記

AWS認証制限に対応しましたがXSLTの処理において正しく動きません。手元だとXSLT変換出来ていますがAmazonサーバを通すと空の処理結果が戻ってきてしまいます。とりあえずは正しく動くはずだろうコードで置いて置きますが、動作しない事をご了承下さい。

またXSLTも使わないバージョンもありますのでそちらもご覧下さい。



気付いたらAmazon Ecommerce Web Serviceのバージョン3.0が終わっていました
それにともないmalaさんの「Amazon最速検索β」も動かなくなってしまっていました。
残念だったので気分だけでも...と思い作ってみました。
今回のポイントとしてはJSONではなくJSONPであること。malaさんのバージョンでは"end"というマーカーを使い、かつcallbackは指定出来ませんでしたが、以下のサンプルではcallbackパラメータを受け取りJSONPします。
AWS4では、与えられたパラメータがItemSearchResponse/OperationRequest/Arguments/Argumentに格納されるので、この属性Nameが"callback"の物を関数名となる様にしてあります。
まずXSLT <?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:aws="http://webservices.amazon.com/AWSECommerceService/2005-10-05"
  exclude-result-prefixes="aws">

  <xsl:output method="text" media-type="text/javascript" encoding="UTF-8"/>
  <xsl:variable name="lcletters">abcdefghijklmnopqrstuvwxyz</xsl:variable>
  <xsl:variable name="ucletters">ABCDEFGHIJKLMNOPQRSTUVWXYZ</xsl:variable>

  <xsl:template match="/aws:ItemSearchResponse">
    <xsl:value-of select="aws:OperationRequest/aws:Arguments/aws:Argument[@Name='callback']/@Value"/>
    <xsl:text>({isvalid:</xsl:text>
    <xsl:value-of select="translate(aws:Items/aws:Request/aws:IsValid/text(),$ucletters,$lcletters)" />
    <xsl:text>,errors:[</xsl:text>
    <xsl:for-each select="aws:Items/aws:Request/aws:Errors/aws:Error">
      <xsl:text>{code:'</xsl:text>
      <xsl:value-of select="aws:Code" />
      <xsl:text>',message:'</xsl:text>
      <xsl:call-template name="sanitize-text">
        <xsl:with-param name="target" select="aws:Message"/>
      </xsl:call-template>
      <xsl:text>'}</xsl:text>
      <xsl:choose>
        <xsl:when test='position() &lt; last()'>
          <xsl:text>,</xsl:text>
        </xsl:when>
      </xsl:choose>
    </xsl:for-each>
    <xsl:text>],result:</xsl:text>
    <xsl:apply-templates select="aws:Items"/>
    <xsl:text>})</xsl:text>
  </xsl:template>

  <xsl:template match="aws:Items">
    <xsl:text>[</xsl:text>
    <xsl:for-each select="aws:Item">
      <xsl:apply-templates select="."/>
      <xsl:choose>
        <xsl:when test='position() &lt; last()'>
          <xsl:text>,</xsl:text>
        </xsl:when>
      </xsl:choose>
    </xsl:for-each>
    <xsl:text>]</xsl:text>
  </xsl:template>

  <xsl:template match="aws:Item">
    <xsl:text>{</xsl:text>

    <xsl:text>asin:'</xsl:text>
    <xsl:value-of select="aws:ASIN"/>
    <xsl:text>'</xsl:text>

    <xsl:text>,url:'</xsl:text>
    <xsl:value-of select="aws:DetailPageURL"/>
    <xsl:text>'</xsl:text>

    <xsl:text>,title:'</xsl:text>
    <xsl:call-template name="sanitize-text">
      <xsl:with-param name="target" select="normalize-space(aws:ItemAttributes/aws:Title)"/>
    </xsl:call-template>
    <xsl:text>'</xsl:text>

    <xsl:text>,publisher:'</xsl:text>
    <xsl:call-template name="sanitize-text">
      <xsl:with-param name="target" select="normalize-space(aws:ItemAttributes/aws:Publisher)"/>
    </xsl:call-template>
    <xsl:text>'</xsl:text>

    <xsl:text>,date:'</xsl:text>
    <xsl:call-template name="sanitize-text">
      <xsl:with-param name="target" select="aws:ItemAttributes/aws:PublicationDate"/>
    </xsl:call-template>
    <xsl:text>'</xsl:text>

    <xsl:text>,authors:[</xsl:text>
    <xsl:for-each select="aws:ItemAttributes/aws:Author">
      <xsl:text>'</xsl:text>
      <xsl:call-template name="sanitize-text">
        <xsl:with-param name="target" select="text()"/>
      </xsl:call-template>
      <xsl:text>'</xsl:text>
      <xsl:choose>
        <xsl:when test='position() &lt; last()'>
          <xsl:text>,</xsl:text>
        </xsl:when>
      </xsl:choose>
    </xsl:for-each>
    <xsl:text>]</xsl:text>

    <xsl:text>,label:'</xsl:text>
    <xsl:call-template name="sanitize-text">
      <xsl:with-param name="target" select="aws:ItemAttributes/aws:Label"/>
    </xsl:call-template>
    <xsl:text>'</xsl:text>

    <xsl:text>,price:'</xsl:text>
    <xsl:call-template name="sanitize-text">
      <xsl:with-param name="target" select="aws:ItemAttributes/aws:ListPrice/aws:FormattedPrice"/>
    </xsl:call-template>
    <xsl:text>'</xsl:text>

    <xsl:text>,availability:'</xsl:text>
    <xsl:call-template name="sanitize-text">
      <xsl:with-param name="target" select="aws:Offers//aws:Availability"/>
    </xsl:call-template>
    <xsl:text>'</xsl:text>

    <xsl:text>,image:{</xsl:text>
    <xsl:for-each select="aws:*[local-name()='SmallImage' or local-name()='MediumImage' or local-name()='LargeImage']">
      <xsl:call-template name="image">
        <xsl:with-param name="type" select="substring-before(local-name(), 'Image')"/>
      </xsl:call-template>
      <xsl:choose>
        <xsl:when test='position() &lt; last()'>
          <xsl:text>,</xsl:text>
        </xsl:when>
      </xsl:choose>
    </xsl:for-each>
    <xsl:text>}</xsl:text>

    <xsl:text>,reviews:[</xsl:text>
    <xsl:for-each select="aws:CustomerReviews/aws:Review">
      <xsl:text>{summary:'</xsl:text>
      <xsl:call-template name="sanitize-text">
        <xsl:with-param name="target" select="normalize-space(aws:Summary)"/>
      </xsl:call-template>
      <xsl:text>',content:'</xsl:text>
      <xsl:call-template name="sanitize-text">
        <xsl:with-param name="target" select="normalize-space(aws:Content)"/>
      </xsl:call-template>
      <xsl:text>'}</xsl:text>
      <xsl:choose>
        <xsl:when test='position() &lt; last()'>
          <xsl:text>,</xsl:text>
        </xsl:when>
      </xsl:choose>
    </xsl:for-each>
    <xsl:text>]</xsl:text>

    <xsl:text>}</xsl:text>
  </xsl:template>

  <xsl:template name="image">
    <xsl:param name="type"/>

    <xsl:value-of select="translate($type,$ucletters,$lcletters)"/>
    <xsl:text>:{</xsl:text>
    <xsl:text>src:'</xsl:text>
    <xsl:value-of select="aws:URL"/>
    <xsl:text>',</xsl:text>

    <xsl:text>width:</xsl:text>
    <xsl:value-of select="aws:Width"/>
    <xsl:text>,</xsl:text>

    <xsl:text>height:</xsl:text>
    <xsl:value-of select="aws:Height"/>
    <xsl:text>}</xsl:text>
  </xsl:template>

  <xsl:template name="sanitize-text">
    <xsl:param name="target"/>
    <xsl:choose>
      <xsl:when test="contains($target, '&quot;')">
        <xsl:value-of select="substring-before($target, '&quot;')"/>
        <xsl:call-template name="sanitize-text">
          <xsl:with-param name="target" select="substring-after($target, '&quot;')"/>
        </xsl:call-template>
      </xsl:when>
      <xsl:otherwise><xsl:value-of select="$target"/></xsl:otherwise>
    </xsl:choose>
  </xsl:template>
</xsl:stylesheet>
ソース:aws2json.xmsl
ポイントとしては"apply-template"のselectを使うのではなく"xsl:for-each"を使うことで"position()"および"last()"を使った最終要素時のカンマ制御を行っている所。FirefoxではokですがIEだとエラーになっちゃいますからね。
そしてjavascript部分 $(document).ready(function() {
  var unsanitize = function(text) {
    return (text||'').replace(/&amp;/g, '&').replace(/&gt;/g, '>').replace(/&lt;/g, '<');
  }
  $('#aws-word').keydown(function(e) { if (e.keyCode == 13) $('#aws-search').click() });
  $('#aws-search').click(function() {
    if (!$('#aws-word').val()) {
      $('#aws').html('');
      return;
    }
    $('#aws').html('<img src="http://mattn.kaoriya.net/images/ajax-loader.gif"/>');
    $.ajaxSettings.cache = true;
    $.getJSON('http://xml-jp.amznxslt.com/onca/xml?callback=?',
      {
        Service: 'AWSECommerceService',
        SubscriptionId: '1GXPBVS13GJVA58PKVG2',
        AssociateTag: 'bigsky-22',
        Operation: 'ItemSearch',
        SearchIndex: $('#aws-kind').val(),
        ResponseGroup: 'Medium,Offers,Reviews',
        Version: '2005-10-05',
        Keywords: $('#aws-word').val(),
        ContentType: 'text/plain',
        Style: 'http://mattn.kaoriya.net/misc/aws2json.xsl'
      }, function(data) {
        $('#aws').html('');
        $.each(data.result, function(index, item) {
          $('<div>')
            .css('border', '1px dotted black')
            .css('border', '1px dotted black')
            .css('background-color', '#eeeeee')
            .css('padding', '0.5em')
            .css('margin', '0.5em')
            .attr('id', 'aws' + index)
            .hide()
            .appendTo('#aws');
          var c = $('#aws' + index);
      $('<a/>')
        .appendTo(c)
        .attr('href', item.url)
            .text(unsanitize(item.title))
            .appendTo(c);
          var a = $('a', c);
          if (item.image.medium) {
            $('<img>')
              .css('vertical-align', 'top')
              .css('padding', '0.5em')
              .css('border', '0px')
              .css('float', 'left')
              .attr('title', item.title)
              .attr('src', item.image.medium.src)
              .prependTo(a);
          }
          a.after('<br />');

          $.each(item.authors, function(index, item) {
            $('<b>')
              .text(item)
              .appendTo(c)
              .after('<br />');
          });
          $('#aws' + index)
            .append('<span>ASIN: ' + item.asin + '</span>')
            .append('<br />')
            .append('<br />')
            .append(item.publisher + '/' + item.price + ' (' + item.date + ')')
            .append('<br />')
            .append(item.availability);
          $(c).append('<br clear="all" /><br />');
          if (item.reviews.length) {
            $('<a href="#">review comments</a>')
              .css('font-size', 'small')
              .css('color', 'blue')
              .appendTo(c)
              .click(function() { $('.reviews', c).toggle('slow'); return false; });
            $('<div>')
              .attr('class', 'reviews')
              .css('display', 'none')
              .css('font-size', 'small')
              .appendTo(c);
            $.each(item.reviews, function(index, item) {
              $('.reviews', c)
                .append('<span class="name"><strong>' + item.summary + '</strong></span><br />')
                .append('<div class="comment">' + unsanitize(item.content) + '</div>')
                .append('<br />');
              $('.comment', c)
                .css('border', '1px dotted gray')
                .css('background-color', 'white')
                .css('padding', '0.5em')
            });
          }
        });
        $('div', '#aws').fadeIn('slow', function() {
          $('.reviews').hide();
        });
      }
    );
  });
});
amazon web serviceのXSLTプロセッサにcallback付きのXSLを処理させる事でjQueryのcallbackを呼び出させています。
getJSONのデータ部を弄る事である程度動きが変えられるかと思います。ただしOperationのItemSearchを変えると動かなくなりますので要注意です。
今回のサンプルとしてはレビューコメントも表示されるようになっています。"review comments"をクリックすると展開されます。
jQueryとXSLだけで動くのでCGIの動かないサーバでもokです。
あくまでサンプルですが、どなたかの参考になれば...

以下実行例

続きを読む...

Posted at by