キバン

PPT2Flash / 文字化けの問題について

CATEGORIES 北海道ラボby.a.takeuchi1 Comments2011.01.27

PPT2Flash Professionalを用いた変換の際に、文字化けが発生する場合があります。

PPT2Flashでは下記に挙げるフォントに対応しています。

  • MS Pゴシック
  • MS P明朝
  • MS UI Gothic
  • MS ゴシック
  • MS 明朝

しかし、これらのフォントが混在しているPPT資料を変換すると文字化けが発生することがあります。
できる限りひとつのPPT資料内ではひとつのフォントに統一することをお勧めします。

ひとつのフォントに統一していたつもりでも、
『意図せずにフォントが切り替わってしまう』
という場面もあります。

その最も多い例としては、
『箇条書きの入力中に「Shiftキー + Enterキー」で改行を行なって、複数行入力した』
という、次ような場合が考えられます。

箇条書きの一項目に複数の行がある場合

始めの行は「MS Pゴシック」となっています。

最初の行は「MS Pゴシック」

そして、改行を行なって入力した行も同様であることが分かります。

改行して入力した行も「MS Pゴシック」となっている

しかし、行頭部分を選択すると、「MS ゴシック」に変わってしまっています。

行頭部分は「MS ゴシック」に変わっている

このような場合に、次の画像に示すような文字化けが発生することがあります。

箇条書きの3行目で文字化けが発生している

解決策としては、先ほども述べたとおり
『ひとつのフォントに統一する』
ということが一番効果的だと思われます。

今回のように、意図せずにフォントが変わってしまうこともありますので、
文字化け発生の際には入力ボックス内を全て選択してフォントの再指定を行なってみてください。

入力ボックス内をすべて選択し、フォントを「MS Pゴシック」に再指定します

すると、文字化けが解消されました。

3行目の文字化けが解消されました

第2回 SCORM技術者資格試験・講習会開催案内

第2回のSCORM技術者資格試験・講習会が開催されるそうです。申込締切は、2011年2月1日(火)となっていますが、先着20名までしか受講できないそうなので、興味のあるかたは早めに申し込みましょう。私は、講習日程周辺も函館で開発業務を行っている予定なので今回の参加は見送ることになりそうです。

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

CATEGORIES 北海道ラボby.a.takeuchi98 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月中の公開と予定しております。

2011年1月27日(木)、株式会社キバンインターナショナルでは、日興コーディアル証券株式会社(以下、日興コーディアル証券)の投資信託専門サイト、「投信スーパーセンター」(以下、投スパ)が行う、「投スパ新春座談会」をUstreamレンタルスタジオ、パンダスタジオからUstream生中継いたします。
今回の配信は、Ustreamの公式有料サービスWatershedを使い、広告がない配信を行います。参加申し込み不要、無料のオンラインセミナーで、自宅やオフィスなどからご覧いただけるようになっています。

【開催概要】
日  時: 2011年1月27日(木) 19時~20時半(予定)
タイトル: 『投スパ新春座談会 ~2011年どうする!?あなたの投資運用&マーケット展望』
トピックス: ○過去のマーケットを振り返って
○分配型投信の投資ポイント
○先進国・新興国動向
○2011年のマーケット展望
○2011年の投信運用
実施形式:座談会形式 Ustream+Twitterによるオンライン配信
参加方法:お申し込み等は不要です。下記サイトよりどなたでもご覧いただけます。
「投スパ新春座談会」:http://toshin-sc.tv
ハッシュタグ: #tscs
主  催:日興コーディアル証券 投信スーパーセンター
協  力:イボットソン・アソシエイツ・ジャパン
ゲ ス ト:川口一晃氏(金融ジャーナリスト)
島田知保氏(イボットソン・アソシエイツ・ジャパン)
竹川美奈子氏(ファイナンシャルジャーナリスト)
進  行:日興コーディアル証券アセットマネジメント・マーケティング部長 櫻井歩
事前質問&アンケート:座談会でゲストに聞きたい質問などをお送りください。事前のご質問をお送りいただいた方、座談会後のアンケートにご回答いただいた方の中から抽選で、座談会ゲストよりオリジナルプレゼントを進呈いたします。
事前質問受付フォーム
http://toshin-sc.tv

パンダスタジオ:Ustream配信、動画コンテンツ制作、eラーニング教材作成用レンタルスタジオ
http://pandastudio.tv

キバンインターナショナルについて
2009年7月に株式会社キバンから分離独立。
eラーニング専門企業。eラーニングシステム以外に、6種類の教材作成ソフトを発売。
2700社にeラーニング関係の製品を提供している。
また、国内初の企業向け課金可能、会員限定可能インターネット生中継「ナマチューケー」サービスを提供している。
2010年2月には、将来有望なベンチャー企業300選”VentureNow300″に選定された。

本プレスリリースについて本プレスリリース内容のコピー・転載は自由です。
転載されましたら、ご一報いただけると幸いです。

きばらじ 194回の内容をブログでも公開します。

2011年、盛んになるといわれるFacebookと、その中に埋め込めるライブ動画配信サービス「Livestream」と「Ustream」の違いを解説しています。きばらじを見逃した人向けです。

「UstreamとLivestreamの違い」

本日は、ある企業の採用説明会をパンダスタジオから配信しています。
Ustreamではなく特定の相手に限定することができる「ナマチューケー」サービスを使っての配信を行っています。

Ustreamの配信というと、無料で誰でもがみられるということもあり、企業の中で就職活動の説明会に利用する機会が増えてきました。
こうしたUstreamの生中継配信を、ワールドビジネスサテライトでは「ソー活(ソーシャル・双方向の就職活動)」として番組の中で紹介していました。

今回は、Ustream(ユーストリーム)ではなく、Watershed(ウォーターシェッド) を使い、会員限定の配信を行っています。

キバンインターナショナルの「ナマチューケー」は、 Ustreamの有料サービスを使い、特定の相手だけに配信ができるサービスです。
今後、特定のお客様にだけ配信する生中継も増えるのではないかと思います。

ログインしないと、生中継はみられません!

配信風景は、Ustreamの配信とまったく同じ。

パンダスタジオと、ナマチューケーを組み合わせることで、クオリティの高い映像を、会員だけに配信しています。

ナマチューケーのシステムに興味をお持ちの方は、一度お問い合わせください。
パンダスタジオを使ってみたい方は、一度下見にいらしてください。

SmartBrain/サムネイルアップロード

CATEGORIES SmartBrain, 北海道ラボby.a.takeuchi0 Comments2011.01.19

SmartBrainには、コースのサムネイルを自動生成する機能があるのですが、教材の種類によってはうまくサムネイルを生成できない場合がありました。そこで、SmartBrain1.14(2011年2月中旬リリース予定)で、サムネイル画像のアップロード機能が追加される予定です。以下の画像は、開発環境で撮影したスクリーンショットなので、サムネイルの自動生成がうまく動作していませんが、手動でアップロードしたキバンのロゴはちゃんと表示されています。

サムネイル

サムネイル

こんにちは。株式会社キバンインターナショナルの蔡(チェ)です。
ミレニアムプロジェクトで予測した2030年の中、教育と関連がある部分の内容をご紹介します。
(元データは、韓国のeラーニング大学院カフェーより:http://cafe.daum.net/E-LEARNING/SB9V/62)

教育(EDUCATION)

1. 未来には、「授業時間」という概念が完全に消えるでしょう。
高度のネットワーク時代になれば、教授及び先生たちは自分の仕事と日常生活をモザイクのように編まれた形態で運営しなければならない。
学生の生活も類似の形態となり、未来には自ら勉強する訓練が一番重要な教育関連イシューに浮び上がるでしょう。

2. 文字メッセージ、マイクロブルロギング及び、その他オンライン媒体の過度な使用は学生たちの書き取りと学業能力に否定的な影響を及ぼすでしょう。
学生たちがキーボードで文を書くことに慣れると、速度が早くなる反面いざ重要な内容を見逃しやすくなる。子供たちがインターネット環境で育った結果、正しくない表現を大まかに書くことに慣れてしまう。
このために大学は、新入生に書き込みに対する部分を再整備するために多くの時間を割くようになるでしょう。また、職場ではもっと多くの書き込みコーチが必要となるでしょう。

3. 中国がインターネット教育分野を善導するようになるでしょう。
貧しい地方地域の労動人口を教育しなければならない状況で、中国は、インターネットで大部分の国民を教育させることに成功する一番目の国家となるでしょう。
中国は、2003~2007年まで、地方地域に住む人口を教育するためのシステムを取り入れるのに約 1兆ウォンを投入した。

4. ソーシャルネットワークメディアがもっと協力的な学びの体系を提供するでしょう。
「ネット世代(net generation: N世代)」と呼ばれる現在の青少年たちは、SNS メディアを遊びだけではなく、学問の道具としても使うでしょう。
したがって、彼らの学業は以前より、より少なめに競争的で、チーム単位で働く形態に変わるでしょう。
教師たちもこれ以上、詰めこみ主義の受動的な教育学モデルで学生たちを教育してはいけなきなるでしょう。

5. 未来教育では、対人関係の技術も教えるようになるでしょう。
今日、ソーシャルメディアの世代は、読み-書き取り-演算の基本教育以外に、自分の訓練と責任、メディアの理解など、社会的素養面で脆弱な部分を現わした。
グループ別の実習、クラス討論など、他の学生たちとの意思疎通ができる多様な活動を用意しなければならないでしょう。

6. 未来には博士の学位所持者がもっと有り勝ちになるでしょう。
アメリカの国立科学財団の調査によれば、アメリカの国内博士の学位取得者の数字は、2008年現在、4万 8,802人に達し、6年連続増加している傾向を見せたと発表した。
博士の学位所持者の中、3分の 1は、他の国家出身であることで明らかになった。過去、10年間で電算学及び工学博士は、20% 以上増加した一方、教育学を除いた人文学分野では減少する傾向となった。

7. 2020年、学校では、本とペン、紙などをアナログ媒体で、読み・書くことができる方法を模索するでしょう。
デジタルとアナログ的な道具が、適切に混合した時こそ、知識が一番效果的に体得されることができるという認識が広がり、教師と学生たちの間では、アナログ的な部分をカリキュラムの必須要素と見るようになるでしょう。

8. 未来の大学では、これ以上教室での授業が重要ではない。
次の世代には、学生本人が願う所に住みながら、かなり多い数の科目をオンラインで受講するようになるでしょう。
また、国際的に認証された機関を通じて学位を取得する事がもっと頻繁になるでしょう。しかし、高度に世界化された環境でも、学生たちは相変らず「キャンパス」という空間で、同じ年齢集団との交わりを続くでしょう。

【参照 : UN未来報告 3, 朴栄淑・ジェロームグレン・テドゴドン作,  Kyobo文庫,  2010】

皆さん、こんにちは。株式会社キバンインターナショナルの韓国チームで頑張っている蔡(チェ)でございます。今回、皆様にご紹介する内容は、最近映画館でもよく接する「ソーシャルランニング:Social-Learning」についてです。

先週、韓国のeラーニング大学院のセミナーに行ってきて、いろんな面でよい刺激を受けてきましたが、その中で一つのキーワードが「ソーシャルランニング:Social-Learning」でした。今回は、2つの特別講演がありましたが、2つの特別講演、「Smart-Learningの意味と展望について」演説者:郭・ドックフン (EBS 社長)」と「A New Way for eLearning : Going Social」演説者:林・ゴル (高麗大 教授)の中で、共通にご紹介されたキーワードである「ソーシャルランニング:Social-Learning」について皆さんにもご紹介させていただきます。

▼以下、PowerPoint資料は、郭・ドックフン (EBS 社長)よりいただきましたものを日本語訳しました。

▼また、林・ゴル (高麗大 教授)より、現在、アメリカで一番人気があるソーシャルランニング:Social-Learningのサイトをご紹介されましたので、そのDemoの動画をご紹介いたします。(http://www.socialtext.com/index.php)

弊社では、「何かと忙しいあなたにお昼のホッとひとときを提供」する【きばらじ】キバンインターナショナル・ラジオ(http://kiban.tv/)サービスや【ナマチューケー】「会員限定・課金機能付きネット生中継サービス」(http://ustreamer.jp/)サービスを皆様に提供することで、既にソーシャルランニング:Social-Learningを実現しています。

また、PCでも、SmartPhoneでも学習と管理ができる「eラーニング学習管理システム(LMS)」である【SmartBrain】(http://smartbrain.info/)を皆様に提供することでSmart-Learningを実現していると言っても過言ではないと思います。

  • 製品・サービス
    PC、iPhone対応のeラーニングシステム。20名まで無料でASPサービスを利用できます
    PC、iPhone対応のeラーニング学習管理システム(LMS)【SmartBrain】
    http://smartbrain.info/
    PC、iPhone対応のeラーニングシステム。ユーザ数無制限のASPコースをご用意。


    eラーニングポータルサイト【elearning.co.jp】
    http://elearning.co.jp/
    eラーニング専門企業(株)キバンインターナショナルの製品を紹介しています。


    コンテンツビジネス支援パック
    http://contentsbank.jp/

    Ustream配信、動画コンテンツ制作、セミナーにご利用いただけるレンタルスタジオ
    Ustreamレンタルスタジオ「パンダスタジオ」
    http://pandastudio.tv/

    eラーニング専門企業(株)キバンインターナショナルのスタッフが、eラーニングに関する情報・最新事情をBlogでご紹介。月50本程度の情報発信を行っています。
    ブログ「blog.eラーニング.co.jp」
    http://blog.elearning.co.jp/

  • アーカイブ
  • カテゴリー
  • Amazon
  • タグ