月別アーカイブ: 2011年 1月

Eラーニングは通学コースを超えるコストパフォーマンスを出せる!

キバンインターナショナルは『最高の学びをすべてのひとに!』をミッションに掲げ、EラーニングシステムSmartBrainをプラットホームとし、教材作成支援ツールの開発、提供また新たな学びのメディアとしてUstreamによる課金配信サービスを行っております。

企業内教育を中心として導入されてきたEラーニングは、今後教育をビジネスとする団体にも本格的に採用されていくことが予測されます。

Eラーニングは通学コースを超えるコストパフォーマンスを出せるか?が今回のテーマです、手軽な受講料で、教室講義より高い学習生産性が出せるかということです。

資格を取得したいが、なかなかふみ出せない最大の要因は『受講料が高い』『忙しい、時間がない』『近くに通学できる学校がない』だそうです。

まず通学コースで学ぶ人が支出する費用についてですが、これは教育団体のコスト構造とイコールです、教材開発費、講師料、教室家賃、教室運営費、受講生募集費、教材印刷費、教材在庫コスト、教材在庫ロス(教材の改定時発生します)が主なコストです、これに利益を加えたものが受講料として受講生が支払うわけです、通学コースは高いですが、それなりのコストがどうしてもかかってしまうわけですよね。

それから馬鹿にならないのが交通費、私の知人は都内まで週末新幹線で通学し宿泊費を含め毎週5万円もかかったそうです、遠隔地に住まいのかたが、それなりの教育を受けるには負担が大きいですね。

コスト面で考えれば講師料、教室運営もいらない、印刷費、在庫コストのないE-ラーニングは受講料を大幅に低減できることは、当然かもしれません。

一方講義の内容やサービスの面ではどうでしようか?某所でのEラーニングについて受講されたアンケートによれば、メリットとして、A学習時間・場所が自由」であること。好きなときに、自分のペースで受講できる点です。B「繰り返し学習することができる」が挙げられています。
デメリットの上位は、C「受講継続のモチベーションの維持が困難」D「講師や他の受講生とのインタラクティブ性が少ないため、研修自体を淡白に感じる」、さらにE「集合研修に比べて、理解度が下がるのではないか」などです。1人でPCに向かうeラーニングでは、学習の継続は本人の強い意志が大切だ、と経験者は考えているようで、いかにしてモチベーションを保つかが大きな課題といえましょう。

Eについてですが、キバンインターナショナルが協働しているベリタスアカデミーの例をあげますと、板書する時間、講義以外の会話に要する時間などを排除することにより、最先端の電子黒板を使用したEラーニングの講義は3倍の学習生産性を生み出していることが実証されております。

またC,DについてもUstreamの生中継サービスを加えることにより、情報配信、コミュニケーションの補完ができるようになっております。勿論通学コースのように、Face To Faceで講師、受講仲間とやり取りができるわけではないのですが、MixiやFacebookなどのソーシャルネットワークサービスの利用、新しいコミュニケーションメディアのUstreamによるによるスクーリング、セミナー、イベント開催、必要に応じてはリアルなスクーリング、セミナー等ももミックスすることも良いかもしれません。

公務員試験、中小企業診断士などの難関資格も、通学コースに勝るEラーニングで充分挑戦できることになると思います。

キバンインターナショナルは資格取得など、優れたコンテンツをもつ団体、個人のへのEラーニング事業支援を行っております、教材は開発のホームグラウンド、

パンダスタジオに是非いらしてください。

写真はパンダスタジオ近くの古い建物!Once  Upon A Timeというお店なんとも癒される名前です

.faviconを設置しよう

CATEGORIES WordPressby.yasu.tanaka5 Comments2011.01.24

皆さん、faviconってご存知でしょうか?名前は聞いたことなくとも、見たことはあると思います。ブラウザのタブや、ブックマークに表示されるアイコンのことです。faviconが適用されていないと、白紙のドキュメントのようなアイコンが表示されてしまいます。些細な違いなのですが、さみしいですね。

favicon適用前

favicon適用前

faviconを適用すると、こんな感じになります。企業のロゴや製品ロゴなど、そのサイトのイメージに合うものがいいですね。

favicon適用後

favicon適用後

favicon作成に用いたサービス

画像編集ソフトを使ってfaviconを作成することもできますが、ウェブサービスで作る方が楽です。今回は以下のサービスを使ってみました。

画像ファイルをアップロードするだけで、faviconにぴったりの画像ファイルが作成できました。favicon.icoという名前のファイルがダウンロードされるので、ドメインのルートにあたるディレクトリにアップロードするだけでOKです。

※ドメインのルートディレクトリ以外にfavicon.icoを設置する場合は以下のサイトを参照ください。
サイトアイコン – favicon.icoの設置方法

先日関西出張だったので、ついでに関西(和歌山と大阪)の書店に立ち寄ってみました。まずは、JR和歌山駅のビル4Fにある、宮井平安堂さんをみてみましょう。
うろうろ・・・・うろろ・・うろ・・うろ。Ustream関連の書棚はありましたが、肝心の「Ustreamで会社をPRする本」は無いみたい。がーん。しかしながら、弊社田中のfacebook本は置いてありました。facebook強いですね。

JR和歌山駅のビル4Fの書店 田中さんのFaceBook本はありました。

 

しかしこれでめげていてはいけません。パソコン関連書籍なら多分ココ!ヨドバシ梅田に来てみました。さてどうでしょうか。

パソコン書籍なら多分ココ!ヨドバシ梅田

 

うろうろ・・・・うろろ・・うろ・・うろ。あれ、パソコン関連書籍のところに無いよ。
うろろ・・うろ・・うろ。
おおー、広告関係の書棚にありました。ビジネス書の棚で、孫社長の本の横に並べてありました。ソフトバンクさんはユーストリームにも出資してますが、だからってことはなく、たまたま隣に並んでるだけでしょうね。

 

ビジネス書のところにありました。

 

では一般書店だとどんな塩梅でしょうか。今度は紀伊國屋書店さんに移動してみましょう。

紀伊國屋書店入り口。いっぱい人が居ます。


うろろ・・おっ検索端末じゃん!あったあった、広告PRの棚にあるようです。ちょっと奥まったところに鎮座しておりますが黄色い表紙は目立ちますね。

 

黄色い表紙の本が並んでいます。

 

引き続き新大阪のブックストア談さんにお邪魔してみます。ベストセラーから専門書まで新大阪で新幹線を利用するビジネスマンに人気(多分)の書店ではどうでしょうか。

新大阪のブックストア談さんにお邪魔


こちらも検索端末でパパっと検索しました。どうも、営業・販促の棚のようですね。

 

縦にならんでおります。


こちらでは、平積みでなく本棚ですが、ありました。

という訳で、「Ustreamで会社をPRする本」は都心の大型書店では、広告とかPRとかそういった関連の棚に並んでいそうです。書店で購入される方はそういったコーナーを観てみてください。(検索端末のあるお店なら検索がオススメですが)


また新たなパンダが、パンダスタジオ(http://pandastudio.tv/)の仲間に加わりましたので紹介します。長谷川さんが。

王です。株式会社キバンインターナショナルのパンダスタジオはオープニング以来、様々な改善が行っています。

社長から、パンダスタジオのCMを作ってみろと言われ、2日間かけて、やっとパンダスタジオのCMを作りました。

動画編集に対して、私がまだ初心者ですので、結構いろいろ分からないところがあります。このパンダスタジオのCMを作っている間に、分からないところに対して、一つずつ解決しながら、自分もすごく勉強になりました。

また、改良をする予定ですが、いったんこれまでできたCMを公開します。

Pythonを使う理由と作った物(ソース付)

CATEGORIES 北海道ラボby.yasu.tanaka98 Comments2011.01.21

みなさん、Pythonってご存知でしょうか?
ニシキヘビ。。ではないです。
プログラミング言語のPythonです。

↓Pythonのロゴ。蛇が2匹です。

このPython。日本国内では、それほど知名度は高くないのですが、2010年で最も成長したプログラミング言語にも選ばれるなど、急速に人気の高まりつつある言語です。2011年にはPHPとC++を抜かして3位になれそうな勢いです!では、このPython、どうして急に人気がでてきたのでしょうか?理由は大きくわけて3つあると思います。

Pythonが急に普及し始めた理由

  1. GAEで動作する

    これが最大の理由だと思います。Googleのサーバを使って簡単にサービスを提供できます。1日あたり1GBまでの転送なら、料金は一切かかりません ※1。無料利用分を超えて使った場合も、課金設定(1日当たりの支払い額の上限)を設定するだけで、簡単にサーバを増強できます。ロードバランス、データベースのレプリケーション、そんなことは一切考える必要がありません。全部自動でやってくれます。固定費が不要なので、AmazonEC2なんかより、よっぽど敷居は低いです。

  2. 理解しやすさ

    これには異論が多いと思います。C、Java、PHPなどとは似ても似つかないソースコード。でも、Python、慣れてしまえば読みやすいですよ。Pythonはインデントに縛られた言語です。プログラムの構造と見た目(インデント)が必ず一致しているので、誰が書いても似たようなソースコードになります。慣れないうちは思うように書き進められないかもしれませんが、しばらく使い込めば「読みやすいコード」が自然にかけるようになっているはずです。

  3. 遅さは問題ではなくなった

    Pythonはスクリプト言語です。コンパイル言語と比べると桁違いに遅いです。でも、Webアプリケーションのボトルネックって、言語ではないですよね?多くの場合、データベースアクセスや、ネットワーク通信、マルチメディアファイルのダウンロードがボトルネックです。スクリプト言語の遅さが問題になっていたのは10年前の話です。今は、PHPだって、RoRだって、Pythonだって実用上問題ない速度で動作します。1番にもつながりますが、言語の速度ではなく、スケールアウトするかどうか、つまり、サーバの台数に応じてきちんと性能が伸びるかが問題なのです。

※1 CPUの使用時間(無料分: 6.5時間/日)なども課金対象ですが、通信量制限(無料分: 1GB/日)が最も課金対象になりやすいです。

で、使ってみた。

Pythonを使う○○個の理由とか並べてても、実際に使ってみないと説得力がないので、実際につかってみた。ソースコードも全文貼り付けていますが、初心者が書いたコードなのであまり信用しないで頂けると幸いです。

1. サーバ監視

サーバ監視

サーバ監視

GAEからサーバの監視をしてみた。HTTPリクエストの応答時間を計るだけのシンプルなサービスだが、安定して稼動している。社内のサーバは、Zabbixなどを活用してデータセンタ内からきっちり監視しているが、データセンタと外部との回線の障害などに関しては、外部からの監視が有用だ。(スクリーンショットに掲載したデータは私が個人的に借りているサーバものです)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
#!/usr/bin/env python

import cgi
import datetime
import wsgiref.handlers
import urllib
import appengine_utilities.sessions
import os

from datetime import datetime
from datetime import timedelta
from google.appengine.api.urlfetch import fetch
from google.appengine.ext import db
from google.appengine.api import users
from google.appengine.ext import webapp
from google.appengine.api import images
from google.appengine.api.labs import taskqueue

class Site(db.Model):
  date = db.DateTimeProperty(auto_now_add=True)
  name = db.StringProperty()
  url  = db.URLProperty()

class Log(db.Model):
  date = db.DateTimeProperty(auto_now_add=True)
  response = db.FloatProperty()
  url = db.URLProperty()

class MainPage(webapp.RequestHandler):
  def get(self):
    session = appengine_utilities.sessions.Session()
    if "admin" in session:
      self.response.out.write('<html><head><title>Response Monitor!!</title></head><body>')
      self.response.out.write('<form method="post" action="/"><input type="submit" value="logout"/></form>')
      self.response.out.write('[ <a href="http://blog.elearning.co.jp?s=add&amp;search_404=1">+</a> ]<br />')
      sites = db.GqlQuery("SELECT * FROM Site ORDER BY date DESC LIMIT 10")
      for site in sites:
        self.response.out.write('[ <a href="#" onclick="if(confirm(\'Are you sure to delete it?\'))location.href=\'/delete?id=%s\'">delete</a> ] ' % (site.key()))
        self.response.out.write('<a href="/detail/%s">%s</a> [ %s ]<br />' % (site.url, site.name, site.url))
      self.response.out.write("</body></html>")
    else:
      self.response.out.write('<html><head><title>Response Monitor!!</title></head><body>')
      self.response.out.write('<form method="post" action="/"><input type="password" name="password"/><input type="submit" value="login"/></form>')
      sites = db.GqlQuery("SELECT * FROM Site ORDER BY date DESC LIMIT 10")
      for site in sites:
        self.response.out.write('<a href="/detail/%s">%s</a> [ %s ]<br />' % (site.url, site.name, site.url))
      self.response.out.write("</body></html>")
     
  def post(self):
    session = appengine_utilities.sessions.Session()
    if self.request.get("password") == "hakodate2010":
      session["admin"] = 1
    else:
      if "admin" in session:
        del session["admin"]
    self.redirect('/')

class Detail(webapp.RequestHandler):
  def get(self, key):
    self.response.out.write('<html><head><title>Log for %s</title></head><body>' % urllib.unquote(key))
    self.response.out.write("Log for '%s'" % urllib.unquote(key))
    self.response.out.write("<br />")
    responseMap = {};
    for i in range(0,4):
      query = db.GqlQuery("SELECT * FROM Log WHERE url = :1 ORDER BY date DESC LIMIT %s, 1000" % (1000 * i) , urllib.unquote(key) );
      for log in query:
        log.date+=timedelta(hours=9)
        day = str(log.date)[0:10]
        hour = str(log.date)[11:13]
        if day not in responseMap:
          responseMap[day] = {}
        if hour not in responseMap[day]:
          responseMap[day][hour] = {}
        responseMap[day][hour][log.date] = log.response

    self.response.out.write('<table border=1 style="border-style:solid ">')
    self.response.out.write("<tr><td></td>")
    for day in sorted(list(responseMap)):
      self.response.out.write("<td>")
      self.response.out.write(day)
    self.response.out.write("</td></tr>")

    for hour in range(0,24):
      hour = "%02d" % hour
      self.response.out.write("<tr>")
      self.response.out.write("<td>%s</td>" % hour)
      for day in sorted(list(responseMap)):
        self.response.out.write('<td valign="top">')
        if hour in responseMap[day]:
          limitter = 12
          for log in sorted(list(responseMap[day][hour])):
            limitter = limitter - 1
            if limitter < 0: break
            if responseMap[day][hour][log] == 0:
              self.response.out.write("<font color=red>")
              self.response.out.write(str(log)[14:19] + " ERR ")
            elif responseMap[day][hour][log] < 1.5 and responseMap[day][hour][log] != 0:
              self.response.out.write("<font>")
              self.response.out.write(str(log)[14:19] + " %.3f" % responseMap[day][hour][log])
            elif responseMap[day][hour][log] < 3:
              self.response.out.write('<font color="#FF8135">')
              self.response.out.write(str(log)[14:19] + " %.3f" % responseMap[day][hour][log])
            else:
              self.response.out.write('<font color="#FFBF00">')
              self.response.out.write(str(log)[14:19] + " %.3f" % responseMap[day][hour][log])
            self.response.out.write("</font><br />")
        self.response.out.write("</td>")
      self.response.out.write("</tr>")
    self.response.out.write("</table>")
    self.response.out.write('<div><a href="/">back</a></div>')
    self.response.out.write('</body></html>')

class Cron(webapp.RequestHandler):
  def get(self):
    size = 5
    sites = db.GqlQuery("SELECT * FROM Site ORDER BY date DESC")
    for i in range(0, sites.count(), size):
      params = {}
      for j in range(0, size):
        if i + j >= sites.count():
          break
        params["url"+str(j)] = sites[i+j].url
      taskqueue.add(url='/worker', params = params)

class Worker(webapp.RequestHandler):
  def post(self):
    if(int(self.request.headers.environ['HTTP_X_APPENGINE_TASKRETRYCOUNT']) > 0):
      return
    for key in self.request.arguments():
      try:
        url = self.request.get(key)
        fetchAndLog(url)
      except:
        pass
 
class Add(webapp.RequestHandler):
  def get(self):
    self.response.out.write("""
      <form action="/add" method="post" enctype='multipart/form-data'>
        <div>Name: <input type="text" name="name" /></div>
        <div>URL: <input type="text" name="url" /></div>
        <div><input type="submit" value="submit"/></div>
      </form>"""
)
  def post(self):
    if self.request.get('name') != '' or self.request.get('url') != '':
      site = Site()
      site.url = self.request.get('url')
      site.name = self.request.get('name')
      site.put();
    self.redirect('/')

class Delete(webapp.RequestHandler):
  def get(self):
    Site.get(self.request.get('id')).delete()
    self.redirect('/')

def fetchAndLog(url):
  log = Log()
  log.url = url
  log.response = 0.0
  log.put()
  start = datetime.now()
  ret = fetch(url = url, deadline = 30)
  end = datetime.now()
  diff = end - start
  log.response = diff.seconds + diff.microseconds / 1000000.0
  log.put()

application = webapp.WSGIApplication([
  ('/', MainPage),
  ('/add', Add),
  ('/delete', Delete),
  ('/cron', Cron),
  ('/worker', Worker),
  ('/detail/(.*)', Detail),
], debug=True)

def main():
  wsgiref.handlers.CGIHandler().run(application)

if __name__ == '__main__':
  main()

2. ZIPのアップローダー

GAEって静的ファイルおけないんでしょ?ってよく言われるので、アップロードしたZIPファイルを展開して公開するサービスを作ってみた。ファイルはデータストアに保存しているので厳密な意味では静的ファイルではない。(静的ファイルをデプロイすることもできますが、その場合、GAEの管理ツールを使わないとファイルを更新できません。)

zipアップローダー

zipアップローダー

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#!/usr/bin/env python

import cgi
import datetime
import wsgiref.handlers

from google.appengine.ext import db
from google.appengine.api import users
from google.appengine.ext import webapp
from google.appengine.api import images

class Entry(db.Model):
    content = db.StringProperty(multiline=True)
    date = db.DateTimeProperty(auto_now_add=True)
    data = db.BlobProperty()
    contentType = db.StringProperty()

class MainPage(webapp.RequestHandler):
    def get(self):
        self.response.out.write('<html><body>[ <a href="http://blog.elearning.co.jp?s=add&amp;search_404=1">+</a> ]<br />')
        entries = db.GqlQuery("SELECT * FROM Entry ORDER BY date DESC LIMIT 10")
        for entry in entries:
            self.response.out.write('[<a href="#" onclick="if(confirm(\'Are you sure to delete it?\'))location.href=\'/delete?id=%s\'">d</a>][<a href="http://blog.elearning.co.jp?s=edit?id=%s&amp;search_404=1">e</a>] %s<br />' % (entry.key(), entry.key(), cgi.escape(entry.content)))
            if entry.data:
                self.response.out.write('<a href="/image/%s/data"><img src="/image/%s/thumnail"/></a><br />' % (entry.key(),entry.key()))
        self.response.out.write("</body></html>")

class Get(webapp.RequestHandler):
    def get(self, key):
        image = db.get(key)
        if type == 'thumnail':
            self.response.headers['Content-Type'] = 'image/jpeg'
            self.response.out.write(image.thumnail)
        else:
            if image.contentType:
                self.response.headers['Content-Type'] = image.contentType.encode('utf-8')
            else:
                self.response.headers['Content-Type'] = 'image/jpeg'
            self.response.out.write(image.data)

class Add(webapp.RequestHandler):
    def get(self):
        self.response.out.write("""
            <form action="/add" method="post" enctype='multipart/form-data'>
                <div><textarea name="content" rows="3" cols="60"></textarea></div>
                <div><input type="file" name="file"/></div>
                <div><input type="submit" value="submit"/></div>
            </form>"""
)
    def post(self):
        if self.request.get('content') != '' or self.request.get('file') != '':
            entry = Entry()
            entry.content = self.request.get('content')
            if self.request.get('file'):
                entry.data = self.request.POST.get('file').file.read()
                img = images.Image(entry.data)
                img.resize(60, 100)
                entry.contentType = self.request.body_file.vars['file'].headers['content-type']
            entry.put();
        self.redirect('/')

class Edit(webapp.RequestHandler):
    def get(self):
        post = Entry.get(self.request.get('id'))
        self.response.out.write("""
            <form action="/edit?id=%s" method="post">
                <div><textarea name="content" rows="3" cols="60">%s</textarea></div>
                <div><input type="submit" value="submit"/></div>
            </form>"""
% (self.request.get('id'), post.content))
    def post(self):
        entry = Entry.get(self.request.get('id'))
        entry.content = self.request.get('content')
        entry.put()
        self.redirect('/')

class Delete(webapp.RequestHandler):
    def get(self):
        Entry.get(self.request.get('id')).delete()
        self.redirect('/')

application = webapp.WSGIApplication([
    ('/', MainPage),
    ('/add', Add),
    ('/get/([-\w]+)', Get),
], debug=True)

def main():
    wsgiref.handlers.CGIHandler().run(application)

if __name__ == '__main__':
    main()

3. ブログシステム

ブログシステムを作ってみた。一覧表示ページ、個別記事ページ、タグページぐらいしかないが、一般的な用途ならこれぐらいでいい気がする。RSSを配信しているので、FeedTweetなどを使ってTwttterに更新履歴を流したりもできる。Wordpressとなどと比べると機能も少ないし、デザインもテンプレート化できていないが、レスポンスはよいし、満足して使っている。

python-blog

python-blog

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from google.appengine.ext import webapp
from google.appengine.ext.webapp import util
from google.appengine.ext import db
from google.appengine.api import users
import urllib, datetime, re
step = 10
title = "Python blog system"

class AuthHandler(webapp.RequestHandler):
  def get(self, key = ""):
    if users.get_current_user() == None:
      self.write("<a href="%s">Sign in or register</a>." % users.create_login_url("/admin"))
    elif users.is_current_user_admin() != True:
      self.write('Your account %s is not admin. <a href="%s">Log out</a> and log in with an admin account.' % (users.get_current_user(), users.create_logout_url("/admin")))
    else:
      if key:
        self.get2(key)
      else:
        self.get2()
  def post(self, key = ""):
    if users.is_current_user_admin():
      if key:
        self.post2(key)
      else:
        self.post2()
  def write(self, str):
    self.response.out.write(str)

class MainHandler(AuthHandler):
  def get(self, pageStr):
    try:
      page = int(pageStr)
    except ValueError:
      page = 0
    printHeader(self, title)
    self.write('<h1><a href="/">%s</a></h1>' % title)
    if users.is_current_user_admin():
      self.write('<h2>[<a href="http://blog.elearning.co.jp?s=&amp;search_404=1">New</a>] [<a href="%s">Log out</a>]</h2>'  % users.create_logout_url("/"))
    entries = Entry.all().order("-datetime").fetch(step + 1, page * step)
    for entry in entries[:step]:
      printEntry(self, entry)
    if len(entries) > step:
      self.write('[ <a href="/%d"> Next %d</a> ]' % (page + 1, step))
    if page > 0:
      self.write('[ <a href="/%d"> Prev %d</a> ]' % (page - 1, step))
    printFooter(self)

class RSSHandler(AuthHandler):
  def get(self, pageStr):
    self.write(
u"""< ?xml version="1.0" encoding="utf-8"?>
<rdf:rdf xmlns:dc="http://purl.org/dc/elements/1.1/"
  xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
  xmlns="http://purl.org/rss/1.0/">
  <channel rdf:about="http://python-blog-system.appspot.com/">
    <title>%(title)s</title>
    <link>http://python-blog-system.appspot.com</link>
    <description>%(title)s</description>
    <dc:language>ja</dc:language>
    <dc:creator>N/A</dc:creator>
    <dc:date>%(now)s</dc:date>
  </channel>"""
% {'now' : '2010-12-31T16:57:12+09:00', 'title' : title})
    for entry in Entry.all().order("-datetime").fetch(30):
      self.write("""  <item rdf:about="http://python-blog-system.appspot.com/entry/%(key)s">
    <title>%(title)s</title>
    <link>http://python-blog-system.appspot.com/entry/%(key)s</link>
    <description>%(body)s</description>
    <dc:date>%(datetime)s</dc:date>
  </item>
"""
% {"key" : entry.key(), "title" : h(entry.title), "body" : h(entry.body), "datetime" : entry.formattedDatetimeInJST})
    self.write("</rdf:rdf>")

class AdminHandler(AuthHandler):
  def get2(self, key):
    self.redirect("/")

class PostHandler(AuthHandler):
  def get2(self,key = ""):
    entry = Entry.get(key) if key != '' else Entry()
    title = "Edit Entry" if key!= '' else "New Entry"
    deleteButton = """<input type="button" value="delete" onclick="if(confirm('Are you sure to delete it?'))location.href='/delete/%s'"/>""" % key if key!= '' else ''
    printHeader(self, title)
    self.write("<h1>%s</h1>" % title)
    self.write(u"""<form method="post" action="/post/%(key)s">
<h2>タイトル</h2><input type="text" name="title" value="%(title)s" style="width:400px"/>
<h2>本文</h2><textarea name="body" style="width:400px;height:300px;">%(body)s</textarea>
<h2>タグ</h2><input type="text" name="tags" value="%(tags)s" style="width:400px"/>
<h2>画像 [<a href="http://blog.elearning.co.jp?s=uploader&amp;search_404=1" target="_blank">uploader</a>]</h2>
<div>%(deleteButton)s<input type="submit" value="submit"/></div></form>"""
% {"key" : key, "title" : entry.title, "body" : entry.body, "tags" : entry.tagStr(), "deleteButton":deleteButton})
    printFooter(self)
  def post2(self, key = ""):
    if self.request.get("title") != '' and self.request.get("body") != '':
      entry = Entry.get(key) if key != '' else Entry()
      entry.title = self.request.get("title")
      entry.body = self.request.get("body")
      entry.tags = []
      for tagStr in self.request.get('tags').replace(u' ',' ').replace('  ',' ').replace(',',' ').split(' '):
        tag = Tag.all().filter("tag =", tagStr).get()
        if tag == None:
          tag = Tag(tag = tagStr)
          tag.put()
        entry.tags.append(tag.key())
      entry.put()
    self.redirect('/')

class PostCommentHandler(AuthHandler):
  def post(self, key):
    if self.request.get("comment") != '':
      Comment(
        entry = Entry.get(key),
        comment = self.request.get("comment"),
        delpass = self.request.get("delpass"),
        nickname = self.request.get("nickname")
      ).put()
    self.redirect("/entry/%s" % key)

class DeleteHandler(AuthHandler):
  def get2(self, key):
    db.delete(Entry.get(key))
    self.redirect('/')

class DeleteCommentHandler(AuthHandler):
  def post(self, key):
    comment = Comment.get(key)
    entry_key = comment.entry.key()
    self.write(self.request.get("delpass"))
    self.write(comment.delpass)
    if self.request.get("delpass") == comment.delpass:
      db.delete(comment)
    self.redirect('/entry/%s' % entry_key)

class TagHandler(AuthHandler):
  def get(self, key):
    tagStr = urllib.unquote(key).decode('utf-8')
    title = "Python blog system / %s" % tagStr
    printHeader(self, title);
    tag = Tag.all().filter("tag =", tagStr).get()
    self.write('<h1><a href="/">Python blog system</a> / %s</h1>' % h(tagStr))
    if tag:
      for entry in tag.entries:
        printEntry(self, entry)
    else:
      self.write("<h2>Tag %s does not exist</h2>" % h(tagStr))
    printFooter(self)

class EntryHandler(AuthHandler):
  def get(self, key):
    entry = Entry.get(key)
    printHeader(self, "%s / %s" % (title, entry.title));
    self.write('<h1><a href="/">%s</a></h1>' % title)
    printEntry(self, entry, commentDetail = True)
    printFooter(self)

class UploaderHandler(AuthHandler):
  def get2(self, key):
    printHeader(self, "Uploader")
    self.write("<h1>Uploader</h1>")
    for image in Image.all():
      self.write('<h2><img src="/image/%(key)s"/><br /><input type="text" value="[img:%(key)s]" style="width:300px;font-size:x-small"/><input type="button" value="delete" onclick="location.href=\'/deleteImage/%(key)s\'"/></h2>' % {"key":image.key()})
    self.write(u'<h2><form action="/uploader" enctype="multipart/form-data" method="post"><input type="file" name="file"/><input type="submit" value="Upload"/></form></h2>')
    printFooter(self)
  def post2(self, key):
    if self.request.get('file'):
      self.write("hoge")
      image = Image()
      image.image = self.request.POST.get('file').file.read()
      image.contentType = self.request.body_file.vars['file'].headers['content-type']
      image.put()
    self.redirect('/uploader')

class DeleteImageHandler(AuthHandler):
  def get2(self, key):
    Image.get(key).delete()
    self.redirect('/uploader')

class ImageHandler(AuthHandler):
  def get(self, key):
    image = Image.get(key)
    self.response.headers['Content-Type'] = image.contentType.encode('utf-8')
    self.response.out.write(image.image)

def printEntry(self, entry, commentDetail = False):
  user = users.get_current_user()
  if user:
    editLink = '[<a href="/post/%s">edit</a>]' % entry.key()
  else:
    editLink = ''
  self.write('<div class="entry">\n<div class="entryHeader">\n')
  self.write('<h2 class="title"><a href="/entry/%(key)s">%(title)s</a> %(editLink)s</h2> <div class="entryDate">%(datetime)s</div>'
    % {"key" : entry.key(), "title" : h(entry.title), "editLink" : editLink, "datetime" : entry.formattedDatetimeInJST})
  self.write('</div>\n')#header
  self.write(replaceImages(linkURLs(nl2br(h(entry.body)))));
  self.write('\n<div class="entryFooter">tag:\n')
  for tag in entry.tags:
    tagObj = Tag.get(tag)
    self.write('<a href="/tag/%s"><span class="tag">%s</span></a>\n' % (urllib.quote_plus(tagObj.tag.encode('utf-8')) ,h(tagObj.tag)))
  if commentDetail:
    self.write(u'<h2>コメント</h2><div class="comments"><a name="comments">\n')
    for comment in entry.comments.order('datetime'):
      if comment.nickname == None or comment.nickname == "":
        comment.nickname = "Anonymous"
      delbutton = u"""
        <div style="float:right">
          <form method="post" name="form" action="/deleteComment/%(key)s">
          <input type="text" name="delpass" class="delcommentpassword"/>
          <input type="button" onclick="if(confirm('本当に削除しますか?'))form.submit()" value="削除" class="delcommentbutton"/>
          </form>
        </div><br clear="all"/>"""
% {"key":comment.key()}
      self.write('<h3 class="comment">%s: %s %s</h3>' % (comment.nickname, comment.comment, delbutton))
    self.write(u'<div style="width:84px;float:left;font-size:xx-small;position:relative;top:6px;">名前</div>')
    self.write(u'<div style="width:184px;float:left;font-size:xx-small;position:relative;top:6px;">コメント</div>')
    self.write(u'<div style="width:100px;float:left;font-size:xx-small;position:relative;top:6px;">削除パス</div>')
    self.write(u'<br clear="all"/>')
    self.write(u'<form action="/postComment/%s" method="post" style="padding:0">' % entry.key())
    self.write(u'<input type="text" name="nickname" style="width:80px;"/>')
    self.write(u'<input type="text" name="comment" style="width:180px;"/>')
    self.write(u'<input type="text" name="delpass" style="width:50px;"/>')
    self.write(u'<input type="submit" value="投稿" style="width:50px"/>')
    self.write("</form></a></div>\n")
  else:
    self.write(u'<a href="/entry/%s#comments">コメント(%s)</a>\n' % (entry.key(), entry.comments.count()))
  self.write("</div>\n")#footer
  self.write("</div>\n")#entry

def urlReplacer(match, limit = 45):
  return '<a href="%s" target="_blank">%s</a>' % (match.group(), match.group()[:limit] + ('...' if len(match.group()) > limit else ''))

def linkURLs(str):
  return re.sub(r'([^"]|^)(https?|ftp)(://[\w:;/.?%#&=+-]+)', urlReplacer, str)

def replaceImages(str):
  return re.sub(r'\[img:(.*)\]', r'<img src="http://blog.elearning.co.jp?s=\1&amp;search_404=1" style="max-width:400px"/>', str)

def printHeader(self, title):
  self.write("""< ?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="ja" lang="ja">
<head>
  <link rel="alternate" type="application/rss+xml" title="RSS" href="rss"/>
  <meta http-equiv="content-script-type" content="text/javascript"/>
  <meta http-equiv="content-type" content="text/html; charset=utf-8"/>
  <title>%s</title>
  <link rel="stylesheet" type="text/css" href="/css/style.css"/>
  <meta name = "viewport" content = "width=420"/>
  <script type="text/javascript">
  var _gaq = _gaq || [];
  _gaq.push(['_setAccount', 'UA-20245912-2']);
  _gaq.push(['_trackPageview']);
  (function() {
    var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
    ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
    var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
  })();
  </script>"""
% (h(title)))
  self.write("</head>\n<body>\n");

def printFooter(self):
  self.write(u'<div>developed by <a href="http://php6.jp/python/">python練習帳</a></div>\n</body>\n</html>')

def nl2br(str):
  return str.replace('\r\n','\n').replace('\n','<br />\n')

class Entry(db.Model):
  title = db.StringProperty(default = "")
  body = db.TextProperty(default = "")
  tags = db.ListProperty(db.Key)
  datetime = db.DateTimeProperty(auto_now_add = True)
  @property
  def formattedDatetimeInJST(self):
    return (self.datetime + datetime.timedelta(hours=9)).strftime("%Y-%m-%d %H:%M:%S")
  def tagStr(self):
    return " ".join([Tag.get(x).tag for x in self.tags])

class Tag(db.Model):
  tag = db.StringProperty()
  @property
  def entries(self):
    return Entry.all().filter('tags', self.key()).order('-datetime')

class Comment(db.Model):
  comment = db.TextProperty(default = "")
  entry = db.ReferenceProperty(Entry, collection_name = 'comments')
  user = db.UserProperty()
  datetime = db.DateTimeProperty(auto_now_add = True)
  delpass = db.TextProperty()
  nickname = db.TextProperty()

class Image(db.Model):
  image = db.BlobProperty()
  contentType = db.StringProperty()

def main():
  application = webapp.WSGIApplication([
    ('/tag/(.*)', TagHandler),
    ('/entry/(.*)', EntryHandler),
    ('/admin/?(.*)', AdminHandler),
    ('/postComment/?(.*)', PostCommentHandler),
    ('/post/?(.*)', PostHandler),
    ('/rss/?(.*)', RSSHandler),
    ('/deleteComment/?(.*)', DeleteCommentHandler),
    ('/deleteImage/(.*)', DeleteImageHandler),
    ('/delete/?(.*)', DeleteHandler),
    ('/uploader/?(.*)', UploaderHandler),
    ('/image/(.*)', ImageHandler),
    ('/(.*)', MainHandler)
  ], debug=True)
  util.run_wsgi_app(application)

def h(html):
  return html.replace('&','&amp;').replace('< ','&lt;').replace('>','&gt;').replace('"','&quot;')

if __name__ == '__main__':
  main()

おわりに

Pythonの良さをざっと紹介しましたが、どのように感じられましたでしょうか?C、Java、PHPなどに慣れた人にとっては異質なソースコードだと思います。でも、一度慣れてしまうと、すごく合理的で分かりやすい言語だと思います。このブログにPython関連の記事を書き続けるのは気が引けますので、興味を持たれた方はPython練習帳をご覧いただければと思います。

皆さん、こんにちは。今回は、LectureMAKERの機能や使い方が一目でわかる「LectureMAKERを学ぶ講座」のWebページ(http://lecturemaker.jp/?page_id=3449)を公開しましたので、ご紹介いたします。

1.「製品概要」をクリックします。

2.LectureMAKERを学ぶ講座をクリックします。

3.公開されたPart1の画像をクリックし、InternetExplorer上で再生します。


本教材は、LectureMAKERのビューア形式で保存されています。Part1 のコンテンツ内容は以下となります。(LectureMAKERのビューアは、ActiveXを使うため、InternetExplorer のみ再生可能です)

Part 1. LectureMAKER はじめる

1. LectureMAKERとは?
2.活用分野
3.実務上の活用例
4.LectureMAKERの機能

Part 1. LectureMAKER はじめる

Part 1. LectureMAKER はじめる(クリックで再生)

また、Prat2~3までは、2月中の公開、Part4 ~5までは、3月中の公開と予定しております。

電車を長い時間乗っていると急に時間が勿体ないと思い、何か本が読みたいと思ったことありませんか。
私は、最近個人的に本にはまっていますが、小説や専門書籍も読んだりします。
そのようなことで、弊社の同じ韓国スタッフが買って来た本を簡単にご紹介したいと思います。

「知識デザインの実務」という本です。本の内容は、簡単(一部)に以下の通りです。
 情報通信技術及びネットの発達で知識の時代に入り、今は、知識は水のように必要な場所だと
どこでも接することが出来ています。しかしながら、知識が溢れる時代ですが、自分に合う正しい知識を探すのは、決して簡単ではないです。
自分に合う知識を正しく提供された時こそ、その価値を認められます。
知識を利用するには、正しく使えるように再加工する過程をファッションのようにデザインするとどうなるんだろう。
1.知識もファッションのように、デザインする時代、2.右脳と左脳の活動の融合、3.実用主義の志向
【知識サービスの発展戦略】
1.感性的な知識サービスの行動化で国家の競争力を強化する2.知識サービスの発展展望_知識サービスの意味や知識サービスの基盤のeラーニングの活性化戦略など

読んでいくうちに、本の内容をしっかり理解できそうな感じがしました。
何より、正しい情報を受け入れ、有効的に活用することが大事ですね。

▼知識デザインの実務の本

キーワードは「コスト削減」と「教育効果」2011年1月14日発行
■□■━━━━━━━━━━━━━━━━━━━━━━━━■□■

eラーニング導入こぼれ話 Vol.0021

■□■━━━━━━━━━━━━━━━━━━━━━━━━■□■

「最高の学びをすべての人に!」

こんにちは!いつも大変お世話になっております、株式会社キバンインターナショナルの田中です。

▲便利な画像管理ソフトPicasa

▲便利な画像管理ソフトPicasa

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
●今回のポイント
1. eラーニングと画像管理
2. 画像を使用する便利オーサリングツール一覧
3. Picasaはこんなに便利!
4. 「顔認識」など充実機能を一挙12個ご紹介。
5. 実際に使ってみよう。
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

●今回のお話はWEB動画でもご覧頂けます。

の「ユーザー登録」から登録後、ログインが必要です。

ログイン後、
「【毎週更新】eラーニング導入こぼれ話」→「Picasa便利機能ピックアップ」をクリックでご覧頂けます。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

【main contents】画像管理ソフトPicasa便利機能ピックアップ

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

●eラーニングと画像管理

デジカメで撮った画像をたくさん撮影してPCに保存しておくと、探すのが大変だったり、容量を食ったりするという問題が起こりがち。

今回は、そんなときに便利な画像管理・編集の無料ソフト『Picasa』をご紹介します。

私たちキバンインターナショナルでは、PowerPointからeラーニング教材を簡単に自製できるオーサリングツールを提供しています。

弊社のオーサリングツールをお使い頂いている方は、教材作成の際に画像を使用するケースもたくさんあると思います。

Picasaには「顔認識機能」など、とても無料とは思えない機能が満載。使い始めたら手放せなくなるはずです。ぜひお試し下さい。

※参考:eラーニング教材を自製できる便利なオーサリングツール一覧

・eラーニング先進国、韓国オンライン大学で採用の高機能教材作成
『Lecture MAKER』・・・99,750円(税込)
http://lecturemaker.jp/?arigatou20110114

・PowerPointから、自然な合成音声ナレーション付資料を作成
『PPT2Voice Neo』・・・189,000円(税込)
http://ppt2voice.jp/?arigatou20110114

▲eラーニング教材を自製する際には画像をよく使います。画面はPPT2VoiceNeo。

▲eラーニング教材を自製する際には画像をよく使います。画面はPPT2VoiceNeo。

・PowerPoint資料をFlashのラーニング教材に簡単変換
『PPT2Flash』・・・29,400円(税込)
http://ppt2flash.jp/?arigatou20110114

・PowerPointを携帯電話、スマートフォン用の動画に簡単変換
『PPT2 Mobile』・・・16,800円(税込)
http://ppt2mobile.jp/?arigatou20110114

●Picasaはこんなに便利!

Picasa と Picasa ウェブ アルバムを使用すると、簡単にデジタル写真を管理、編集し、オンライン アルバムを作成して友だちや家族、社内はもちろん、世界中のユーザーと共有することもできます。

Picasa は無料でダウンロードでき、Picasa ウェブ アルバムでは、最大 1 GB まで無料で保存できます。これは、標準解像度の写真 4,000 枚分です。

Picasaを使いこなすことで、時間の節約ひいてはコストの節約にもなります。これは使わない手はありません。

●Picasaの機能と特徴

・パソコンにある画像を一覧で見ることができる
フォルダをいちいち切り替えながら画像を探すのはかなり時間がかかって大変ですよね。Picasaではパソコン内の複数のフォルダにある全ての画像を、同時に見ることができますので、画像ファイルの確認が簡単です。

・簡単に検索
Picasa では、パソコン内のすべての写真を自動的に検索して簡単に見つけることができます。ファイル名だけでなく、フォルダ名や写真の説明コメントでも検索できるので便利です。「あの画像を入れたフォルダ、どこだっけなぁ~」とは、よくある話ですが、Picasaを使えば簡単に解決。検索スピードも速いです。

・画像のファイル名やコメントを簡単に変更・追加
デジカメに機械的つけられた画像のファイル名を簡単に変更することはもちろん、画像へのコメントの追加も簡単にできます。

・アルバム機能で、複数の画像を、グループ化することができる
パソコン内で、すべてのファイルはフォルダで管理されています。
Picasaでは、フォルダでの管理と同時に、アルバムでの管理でグループ化ができます。「フォルダ」は写真をフォルダに分けて分類、アルバムは写真にラベルを貼って分類するイメージです。

・顔認識機能を使って、人物写真の整理が簡単にできる
写真の人物を認識し、同一人物と判断された写真をグループにして管理することができます。

・画像を編集することができる
Picasa では、赤目処理、色や明るさ調整などの基本的な編集をワンクリックで処理できます。また、切り抜き・文字入れ・トリミングや明るさ・色調の修正など調整機能や効果機能を上手に使用すると、写真の修正も思うがまま。なお、編集した画像は、上書き保存されませんので、何度でも、元の画像の編集を行うことができます。

・WEBでアルバムを管理することができる
アルバムをWEBにアップして、家族や友人と画像を共有することができます。

・コラージュの作成
複数の画像(写真)を組み合わせたコラージュが簡単に作成できます。

・スライドショーの作成
写真を組み合わせた動画を作ることができます。音楽を付けることも簡単です。

・Google マップとの連携
どこで撮影した写真かすぐわかるように、Google マップを使用して簡単に写真にジオタグを付けることができます。

・ギフトCDの作成
たくさんの写真を高解像度のまま渡したい。インターネットを利用しない人に写真を見せたい。そんな場合におススメなのが「ギフトCD」機能です。

・画像サイズの変更
まとめて、画像サイズを変更することができます。サイズ変更はウェブへのアップロード時、エクスポート時、メール送信時などに行えます。変更後の画像は別フォルダに作成されますので、元の画像はそのまま残ります。例えば、画像を受け取る側が「大きいファイルサイズはイヤだな」という場合もあるでしょうから、サイズ変更は親切でもあります。

・画像のメール送信
画像をメールで送信できます。画像サイズは、指定されたサイズに変更されます。

▲切抜きや色の調整、スライドショーの作成など様々なことができます。

▲切抜きや色の調整、スライドショーの作成など様々なことができます。

●実際に使ってみよう!

今回ご紹介しましたPicasa、本当に便利ですのでぜひお使いになってみてください。今回はeラーニング動画で特におススメの機能についてご説明致します。ぜひご覧ください。

の「ユーザー登録」から登録後、ログインが必要です。

ログイン後、
「【毎週更新】eラーニング導入こぼれ話」→「Picasa便利機能ピックアップ」をクリックでご覧頂けます。

━━(編集後記)━━━━━━━━━━━━━━━━━━━━━━

このメールマガジンではいろいろな便利ツールをご紹介しています。

紹介しているのは主にキバンインターナショナル社内で使っているものですが、細かいところは知らないこともあるので調べながら書いていたりします。

調べるうちに「あ、こんな便利な機能があったのか!」と発見があります。すると「これはぜひ、みなさんにお伝えしなければ!」と思うのが毎週楽しみでなりません。と同時に喜んで頂けているか心配でもあります・・・。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

今後も役立つコンテンツを公開して参りますので、よろしくお願い申し上げます。

2011年1月20日のパンダスタジオから配信しているお昼の気が抜けるらじお、きばらじで放送した、Ustreamで投げ銭するシステム「リンクトシアター」のインタビューの部分の動画を公開します。

株式会社リンクトによる「リンクトシアター」は、UstreamとTwitcastingに対応した、参加者がオンライン上の劇場に集まってつぶやきあい、投げ銭をする仕組み。
参加すると、自分のTwitterのアイコンが、オンライン上の劇場に登場する。あらかじめPayPalに支払っておいた金額を、有料の場合最低500円から投げ銭することができる。
つぶやきは全て、ハッシュタグを認識して劇場や舞台などに反映され、擬似的なソーシャルビューイングになっていて、それぞれのツイッターアイコンからつぶやきが表示される。
主催者側の登録は無料で、受け取った投げ銭はPayPalで処理され、手数料を引いた額をリンクトと50%ずつ分け合い、Ustream側にはリンクトから支払いが行われることになる。Ustream公認で利益を受け取ることができる。

UstreamのPayperviewとは違ったやり方で、こうした投げ銭の仕組みあることで、応援したい個人やグループを盛り上げることができるでしょう。
リンクトシアターの登録はこちらから
また、Ustreamなどで配信を行う場合のスタジオは、Ustream対応スタジオ「パンダスタジオ」 でどうぞ。下見を受け付けています。