decoration_mail 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gem 'mail', '>=2.2.9'
4
+ gem 'hpricot', '>=0.8.3'
5
+
6
+ group :development, :test do
7
+ gem 'rspec', '>=2.0'
8
+ gem 'jeweler'
9
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,39 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ activesupport (3.0.3)
5
+ diff-lcs (1.1.2)
6
+ git (1.2.5)
7
+ hpricot (0.8.3)
8
+ i18n (0.5.0)
9
+ jeweler (1.5.2)
10
+ bundler (~> 1.0.0)
11
+ git (>= 1.2.5)
12
+ rake
13
+ mail (2.2.15)
14
+ activesupport (>= 2.3.6)
15
+ i18n (>= 0.4.0)
16
+ mime-types (~> 1.16)
17
+ treetop (~> 1.4.8)
18
+ mime-types (1.16)
19
+ polyglot (0.3.1)
20
+ rake (0.8.7)
21
+ rspec (2.5.0)
22
+ rspec-core (~> 2.5.0)
23
+ rspec-expectations (~> 2.5.0)
24
+ rspec-mocks (~> 2.5.0)
25
+ rspec-core (2.5.0)
26
+ rspec-expectations (2.5.0)
27
+ diff-lcs (~> 1.1.2)
28
+ rspec-mocks (2.5.0)
29
+ treetop (1.4.9)
30
+ polyglot (>= 0.3.1)
31
+
32
+ PLATFORMS
33
+ ruby
34
+
35
+ DEPENDENCIES
36
+ hpricot (>= 0.8.3)
37
+ jeweler
38
+ mail (>= 2.2.9)
39
+ rspec (>= 2.0)
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 [name of plugin creator]
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,44 @@
1
+ = DecorationMail
2
+
3
+ == DecorationMailとは
4
+ 携帯電話で作成されたデコレーションメール(デコメール)をRubyで扱いやすくするためのライブラリです。
5
+
6
+ 今のところ受信したメールをパースするのみでデコメールの新規作成は出来ません。そのうち実装するかもしれません。。。
7
+
8
+ == 使用例
9
+ Rails3でも採用されているMailライブラリのMail::Messageを拡張しています。
10
+
11
+ decorationメソッドで本ライブラリの機能を呼び出す事が出来ます。
12
+
13
+ === 基本的な使い方
14
+
15
+ require 'mail
16
+ require 'decoration_mail'
17
+
18
+ @mail = Mail.read('/path/to')
19
+ @deco = @mail.decoration
20
+
21
+ @html = @deco.save do |image|
22
+ File.open("/path/to/#{image.filename}", "wb") {|f| f.write(image.body)}
23
+ end
24
+
25
+ puts @html # => "<div ...."
26
+
27
+ === 画像のURLを指定する
28
+ image.pathにURIを代入することで、出力されるHTMLの<img src="">を書き換えます。
29
+
30
+ MogileFSなどのストレージを利用する場合に使用すると便利でしょう。
31
+
32
+ @html = @deco.save do |image|
33
+ File.open("/path/to/#{image.filename}", "wb") {|f| f.write(image.body)}
34
+ image.path = "http://xxxxxx/#{image.filename}"
35
+ end
36
+
37
+ === 本文(デコレーション)で使用されていない添付画像をHTMLに追加する
38
+
39
+ # 本文上部に追加
40
+ @html = @deco.save(:other_images => :top) do |image|
41
+ .....
42
+
43
+ # 本文下部に追加
44
+ @html = @deco.save(:other_images => :bottom) do |image|
data/Rakefile ADDED
@@ -0,0 +1,37 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+
5
+ desc 'Default: run unit tests.'
6
+ task :default => :test
7
+
8
+ desc 'Test the decoration_mail plugin.'
9
+ Rake::TestTask.new(:test) do |t|
10
+ t.libs << 'lib'
11
+ t.libs << 'test'
12
+ t.pattern = 'test/**/*_test.rb'
13
+ t.verbose = true
14
+ end
15
+
16
+ desc 'Generate documentation for the decoration_mail plugin.'
17
+ Rake::RDocTask.new(:rdoc) do |rdoc|
18
+ rdoc.rdoc_dir = 'rdoc'
19
+ rdoc.title = 'DecorationMail'
20
+ rdoc.options << '--line-numbers' << '--inline-source'
21
+ rdoc.rdoc_files.include('README')
22
+ rdoc.rdoc_files.include('lib/**/*.rb')
23
+ end
24
+
25
+ begin
26
+ require 'jeweler'
27
+ Jeweler::Tasks.new do |gemspec|
28
+ gemspec.name = "decoration_mail"
29
+ gemspec.summary = "Decoration Mail Parser"
30
+ gemspec.email = "d.akatsuka@gmail.com"
31
+ gemspec.homepage = "https://github.com/dakatsuka/decoration_mail"
32
+ gemspec.description = "Decoration Mail Parser"
33
+ gemspec.authors = ["Dai Akatsuka"]
34
+ end
35
+ rescue LoadError
36
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
37
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.0
@@ -0,0 +1,73 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{decoration_mail}
8
+ s.version = "0.1.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Dai Akatsuka"]
12
+ s.date = %q{2011-02-08}
13
+ s.description = %q{Decoration Mail Parser}
14
+ s.email = %q{d.akatsuka@gmail.com}
15
+ s.extra_rdoc_files = [
16
+ "README.rdoc"
17
+ ]
18
+ s.files = [
19
+ "Gemfile",
20
+ "Gemfile.lock",
21
+ "MIT-LICENSE",
22
+ "README.rdoc",
23
+ "Rakefile",
24
+ "VERSION",
25
+ "init.rb",
26
+ "lib/decoration_mail.rb",
27
+ "lib/decoration_mail/base.rb",
28
+ "lib/decoration_mail/converter.rb",
29
+ "lib/decoration_mail/image.rb",
30
+ "lib/decoration_mail/message.rb",
31
+ "spec/resources/au_decoration.eml",
32
+ "spec/resources/au_decoration_with_attachment.eml",
33
+ "spec/resources/docomo_decoration.eml",
34
+ "spec/resources/docomo_decoration_with_attachment.eml",
35
+ "spec/resources/softbank_decoration.eml",
36
+ "spec/resources/softbank_decoration_with_attachment.eml",
37
+ "spec/spec_helper.rb",
38
+ "spec/unit/base_spec.rb",
39
+ "spec/unit/converter_spec.rb"
40
+ ]
41
+ s.homepage = %q{https://github.com/dakatsuka/decoration_mail}
42
+ s.require_paths = ["lib"]
43
+ s.rubygems_version = %q{1.3.7}
44
+ s.summary = %q{Decoration Mail Parser}
45
+ s.test_files = [
46
+ "spec/spec_helper.rb",
47
+ "spec/unit/base_spec.rb",
48
+ "spec/unit/converter_spec.rb"
49
+ ]
50
+
51
+ if s.respond_to? :specification_version then
52
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
53
+ s.specification_version = 3
54
+
55
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
56
+ s.add_runtime_dependency(%q<mail>, [">= 2.2.15"])
57
+ s.add_runtime_dependency(%q<hpricot>, [">= 0.8.3"])
58
+ s.add_development_dependency(%q<rspec>, [">= 2.0"])
59
+ s.add_development_dependency(%q<jeweler>, [">= 0"])
60
+ else
61
+ s.add_dependency(%q<mail>, [">= 2.2.15"])
62
+ s.add_dependency(%q<hpricot>, [">= 0.8.3"])
63
+ s.add_dependency(%q<rspec>, [">= 2.0"])
64
+ s.add_dependency(%q<jeweler>, [">= 0"])
65
+ end
66
+ else
67
+ s.add_dependency(%q<mail>, [">= 2.2.15"])
68
+ s.add_dependency(%q<hpricot>, [">= 0.8.3"])
69
+ s.add_dependency(%q<rspec>, [">= 2.0"])
70
+ s.add_dependency(%q<jeweler>, [">= 0"])
71
+ end
72
+ end
73
+
data/init.rb ADDED
@@ -0,0 +1,3 @@
1
+ # coding: utf-8
2
+
3
+ require File.expand_path("../lib/decoration_mail", __FILE__)
@@ -0,0 +1,82 @@
1
+ # coding: utf-8
2
+
3
+ module DecorationMail
4
+ class Base
5
+ def initialize(mail)
6
+ @attachments = mail.attachments
7
+ @body_text = parse_text(mail.text_part)
8
+ @body_html = parse_html(mail.html_part)
9
+ end
10
+
11
+ def images
12
+ images = []
13
+
14
+ @attachments.each do |attachment|
15
+ content_type = attachment.header['content-type'].to_s
16
+ content_id = "cid:" + attachment.header['content-id'].to_s.sub(/^</, '').sub(/>$/, '')
17
+ file_name = attachment.filename
18
+
19
+ next unless check_content_type(content_type)
20
+ images << DecorationMail::Image.new(content_id, content_type, file_name, attachment)
21
+ end
22
+
23
+ images
24
+ end
25
+
26
+ def save(options = {}, &block)
27
+ images.each do |image|
28
+ image.instance_eval(&block)
29
+
30
+ if image.content_id
31
+ @body_html.search("img").each do |element|
32
+ if element[:src] == image.content_id
33
+ element[:src] = (image.path ? image.path : image.filename)
34
+ end
35
+ end
36
+ else
37
+ case options[:other_images]
38
+ when :top
39
+ @body_html = Hpricot("<div style='text-align:center;'><img src='#{image.path ? image.path : image.filename}' /></div><br />" + @body_html.to_html)
40
+ when :bottom
41
+ @body_html = Hpricot(@body_html.to_html + "<br /><div style='text-align:center;'><img src='#{image.path ? image.path : image.filename}' /></div>")
42
+ end
43
+ end
44
+ end
45
+
46
+ @body_html.to_html
47
+ end
48
+
49
+ private
50
+ def parse_text(text)
51
+ NKF.nkf("-w", text.to_s)
52
+ end
53
+
54
+ def parse_html(html)
55
+ html = NKF.nkf("-w", html.body.to_s)
56
+ html = Hpricot.parse(html)
57
+
58
+ if html.search("body").empty?
59
+ raise ArgumentError, 'invalid HTML'
60
+ else
61
+ html = DecorationMail::Converter.convert_to_xhtml(html).at('div')
62
+ end
63
+
64
+ html
65
+ end
66
+
67
+ def check_content_type(content_type)
68
+ case content_type
69
+ when /^image\/gif/
70
+ true
71
+ when /^image\/jpg/
72
+ true
73
+ when /^image\/jpeg/
74
+ true
75
+ when /^image\/png/
76
+ true
77
+ else
78
+ false
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,101 @@
1
+ # coding: utf-8
2
+
3
+ module DecorationMail
4
+ module Converter
5
+ def self.convert_to_xhtml(html)
6
+ html = convert_body_to_div(html)
7
+ html = convert_font_color_to_css(html)
8
+ html = convert_font_size_to_css(html)
9
+ html = convert_align_to_css(html)
10
+ html = convert_blink_to_css(html)
11
+ html = convert_marquee_to_css(html)
12
+ end
13
+
14
+ private
15
+ def self.convert_body_to_div(html)
16
+ html.search("body").each do |body|
17
+ if body[:bgcolor]
18
+ body.swap('<div style="background-color:' + body[:bgcolor] + ';">' + body.inner_html + '</div>')
19
+ else
20
+ body.swap("<div>#{body.inner_html}</div>")
21
+ end
22
+ end
23
+ html
24
+ end
25
+
26
+ def self.convert_font_color_to_css(html)
27
+ html.search("font").each do |element|
28
+ if element[:color]
29
+ str = "<span>#{element.inner_html}</span>"
30
+ tmp = Hpricot.parse(str).search("span")
31
+ tmp.first[:style] = "color:#{element[:color].downcase};"
32
+ element.swap(tmp.to_html)
33
+ end
34
+ end
35
+ html
36
+ end
37
+
38
+ def self.convert_font_size_to_css(html)
39
+ html.search("font").each do |element|
40
+ if element[:size]
41
+ str = "<span>#{element.inner_html}</span>"
42
+ tmp = Hpricot.parse(str).search("span")
43
+
44
+ case element[:size]
45
+ when "1"
46
+ tmp.first[:style] = "font-size:xx-small;"
47
+ when "2"
48
+ tmp.first[:style] = "font-size:x-small;"
49
+ when "3"
50
+ tmp.first[:style] = "font-size:small;"
51
+ when "4"
52
+ tmp.first[:style] = "font-size:medium;"
53
+ when "5"
54
+ tmp.first[:style] = "font-size:large;"
55
+ when "6"
56
+ tmp.first[:style] = "font-size:x-large;"
57
+ when "7"
58
+ tmp.first[:style] = "font-size:xx-large;"
59
+ else
60
+ tmp.first[:style] = "font-size:x-small;"
61
+ end
62
+ element.swap(tmp.to_html)
63
+ end
64
+ end
65
+ html
66
+ end
67
+
68
+ def self.convert_align_to_css(html)
69
+ html.search("div").each do |element|
70
+ if element[:align]
71
+ str = "<div>#{element.inner_html}</div>"
72
+ tmp = Hpricot.parse(str).search "div"
73
+
74
+ tmp.first[:style] = "text-align:#{element[:align]};"
75
+ element.swap(tmp.to_html)
76
+ end
77
+ end
78
+ html
79
+ end
80
+
81
+ def self.convert_blink_to_css(html)
82
+ html.search("blink").each do |element|
83
+ element.swap('<span style="text-decoration:blink;">' + element.inner_html + '</span>')
84
+ end
85
+ html
86
+ end
87
+
88
+ def self.convert_marquee_to_css(html)
89
+ html.search("marquee").each do |element|
90
+ if element[:behavior] == "scroll"
91
+ element.swap('<div style="display:-wap-marquee;-wap-marquee-loop:infinite;">' + element.inner_html + '</div>')
92
+ elsif element[:behavior] == "alternate"
93
+ element.swap('<div style="display:-wap-marquee;-wap-marquee-style:alternate;-wap-marquee-loop:infinite;">' + element.inner_html + '</div>')
94
+ else
95
+ element.swap('<div style="display:-wap-marquee;-wap-marquee-loop:infinite;">' + element.inner_html + '</div>')
96
+ end
97
+ end
98
+ html
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,34 @@
1
+ # coding: utf-8
2
+
3
+ module DecorationMail
4
+ class Image
5
+ attr_accessor :path
6
+ attr_reader :content_id, :filename
7
+
8
+ def initialize(content_id, content_type, filename, attachment)
9
+ @content_id = (content_id == "cid:" ? nil : content_id)
10
+ @content_type = content_type
11
+ @filename = filename
12
+ @attachment = attachment
13
+ end
14
+
15
+ def body
16
+ @attachment.read
17
+ end
18
+
19
+ def extension
20
+ case @content_type
21
+ when /^image\/gif/
22
+ "gif"
23
+ when /^image\/jpg/
24
+ "jpg"
25
+ when /^image\/jpeg/
26
+ "jpg"
27
+ when /^image\/png/
28
+ "png"
29
+ else
30
+ nil
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,13 @@
1
+ # coding: utf-8
2
+
3
+ module DecorationMail
4
+ module Message
5
+ def decoration
6
+ if html_part
7
+ DecorationMail::Base.new(self)
8
+ else
9
+ nil
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ # coding: utf-8
2
+ $:.unshift(File.dirname(__FILE__))
3
+
4
+ require 'mail'
5
+ require 'hpricot'
6
+ require 'nkf'
7
+
8
+ require 'decoration_mail/converter'
9
+ require 'decoration_mail/image'
10
+ require 'decoration_mail/base'
11
+ require 'decoration_mail/message'
12
+
13
+ Mail::Message.send :include, DecorationMail::Message
@@ -0,0 +1,192 @@
1
+ Return-Path: <example@ezweb.ne.jp>
2
+ X-Original-To: d.akatsuka@ist-corp.jp
3
+ Delivered-To: akatsuka@ist-corp.jp
4
+ Received: from ezweb.ne.jp (xxxxx.ezweb.ne.jp [255.255.255.225])
5
+ by ist-corp.jp (Postfix) with ESMTP id DAA9038289
6
+ for <d.akatsuka@ist-corp.jp>; Mon, 7 Feb 2011 18:07:30 +0900 (JST)
7
+ Received: from xxxxx (localhost [127.0.0.1])
8
+ by xxxxx.ezweb.ne.jp (EZweb Mail) with SMTP id C34971C2380BC
9
+ for <d.akatsuka@ist-corp.jp>; Mon, 7 Feb 2011 18:07:30 +0900 (JST)
10
+ From: example@ezweb.ne.jp
11
+ To: d.akatsuka@ist-corp.jp
12
+ Subject: =?iso-2022-jp?B?YXUbJEIlRiU5JUgbKEI=?=
13
+ Message-ID: <2011020718073078334700004bae@nxev03mp01.ezweb.ne.jp>
14
+ Date: Mon, 7 Feb 2011 18:07:30 +0900
15
+ Mime-Version: 1.0
16
+ Content-Type: multipart/mixed; boundary="-----=_NextPart_39580_29716_19852"
17
+
18
+
19
+ -------=_NextPart_39580_29716_19852
20
+ Content-Type: multipart/alternative; boundary="-----=_NextPart_41084_31220_21356"
21
+
22
+
23
+ -------=_NextPart_41084_31220_21356
24
+ Content-Type: text/plain; charset="iso-2022-jp"
25
+ Content-Transfer-Encoding: 7bit
26
+
27
+
28
+ $B"(%3%3$r>C$7$F(B
29
+ $BJ8>O$rF~$l$F$M(B
30
+
31
+
32
+ -------=_NextPart_41084_31220_21356
33
+ Content-Type: text/html; charset="iso-2022-jp"
34
+ Content-Transfer-Encoding: quoted-printable
35
+
36
+ <HTML><HEAD><META http-equiv=3D=22Content-Type=22 content=3D=22text/html;=
37
+ charset=3Diso-2022-jp=22></HEAD><BODY bgcolor=3D=22=23BBF06A=22><DIV align=
38
+ =3D=22center=22><IMG src=3D=22cid:01=40110207.180712=22></DIV><DIV align=3D=
39
+ =22center=22><FONT color=3D=22=23478D00=22><IMG src=3D=22cid:02=40110207.18=
40
+ 0722=22>=1B=24B=22(%3%3=24r>C=247=24F=1B(B</FONT></DIV><DIV align=3D=22cent=
41
+ er=22><FONT color=3D=22=23478D00=22>=1B=24BJ8>O=24rF=7E=24l=24F=24M=1B(B</F=
42
+ ONT></DIV><DIV align=3D=22center=22><IMG src=3D=22cid:03=40110207.180712=22=
43
+ ></DIV></BODY></HTML>
44
+ -------=_NextPart_41084_31220_21356--
45
+
46
+ -------=_NextPart_39580_29716_19852
47
+ Content-Type: image/gif; name="SHmura01_1.gif"
48
+ Content-Transfer-Encoding: base64
49
+ Content-Disposition: attachment; filename="SHmura01_1.gif"
50
+ Content-ID: <01@110207.180712>
51
+
52
+ R0lGODlh5wCCAPemAH/ARv///73vawAAAOX5xOT4wyAwEgsaHF+QNHe0Qr/goyhEJ9/v0QcJBAgM
53
+ BD9gI6/YjAQGA7/wcZ/QdPf782ecORgkDW+oPWKWO8fygpfMaU94LBAYCafUgLHhZIfEUr7vbDBI
54
+ Gs/nuUBAQEdsJ6PPXDhUH+fz3O/36EVtMdfrxY/IXSg8Fo61UVduMdHzm3aWQ8fjrni2Q9/3uFVs
55
+ MFeEMLbnZ39/f5+fn7zuar+/v7rrabfcl1OCNsnyhxAQEI+2URwjEN73t3WUQtHzmu/v7xovIURW
56
+ JluMOS88G8vyjRIkH8Lxd8LxeCE5JMTxfCAgIDJAHMzyjarYYMHwdGmhPr7vbpnDVx8nEs/Pz4Om
57
+ St/f39LznNn1rZ+dnT5jLszzjt/3t8C9va+vr3CrQdX0pEx3NI+Pjy9OKYSnS8bxgQwPB3BwcDdY
58
+ LGaCOtr1rjAwMEVYJxEKDWBgYMbxgNX0o8/ymarYYc/ymq+trWiEOxceDdL0nBEKDMryizArLTAr
59
+ Ls7zlIuVgs7zldL0m4B9flFKTcjyhztWJMrsk8vyjJKugVBQUNn1rJnCVh8oGENiKdr2rWyOWrC9
60
+ rFdsRh0fG8Twf9r2rsnskkA7PtDzml9vRQ8QDTY7Mc3yk8TwfnFqbyEaHeDi487yk4KaXCo1IP//
61
+ /wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
62
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
63
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
64
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
65
+ AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEA
66
+ AAAh+QQFMgCmACwAAAAA5wCCAAAI/wABCBxIsKDBgwgTKlzIsKHDhxAjSpxIsaLFixgzatzIsaPH
67
+ jyBDihxJsqTJkyhTqlzJsqXLlzBjypxJs6bNmzhz6tzJs6fPn0CDCh1KtKjRo0iTKl3KtKnTp1Cj
68
+ Sp1KtarVq1izat3KtavXr2DDih1LtuqGfxYSlF178cK/tyHYpkzwACqJt28vyD2J4F+Fpw/w/ou7
69
+ t2TftE5ZCP6nt/DIvmj/MjWw2ITjx/8CO5CslLJgB2ovg+wLoIIDC0ATUGbBmaBnwRtemjBAu7YB
70
+ y1RJA9DtMwReByQMvsZr4OVw4lV1uwXqYHGI0AKP53Up/V/x3P8EhmABdPFbxAJNeP//F7xl9etT
71
+ SVcA73M82tCBvXM3b8G2gfrJsyOA7rP5eMTxeUddfbbhJ9UFCNxFVHVvcQeZdwiYFyFBCKAHmGBE
72
+ iefeP/u5V4OEBVUYVQKCWQhUBRuiBUB1dbFkwIQDiQiVW3h9SJQFKVZwl3cmovRiiD0y9YABrBl1
73
+ 1oYmkDieShUa4ACMsxkoGnUbOgCAYhCilIB/HAoUYJBTooTihjU8KFh5Jo2pokBY/hNbmC4FKB8A
74
+ HHhH2EmzhdBYabS9CSeV7l1wpGAc/DnWlu7VVedi/BnqlZmfATBojY6KJSdsdFZWqVjVoTapdWxB
75
+ IAIKAZQawAkxaFBWAosu9ler/1j/SVYHpJpqa6kMTECWaXZK6lxtLDzwwH5afaDCrciaGgNZn+al
76
+ ZopomdCaVBpQkOy1p6oqloaEQjseBw/s2ZO4DXVgLbbXUqBtWAx6O56ePhmAJkMQoGuvumIlgKO7
77
+ /Pqpk5PkHvSBCPYWTIEIEKzbFY0p9uGFGHn8AW2hPFHGwbQFQXBuwRwHQIEKCui6Vbt4eWHqFt4G
78
+ bJMBdTpgY0ETMNDxzMiiCsEKVu0IrRi2egtjTgYMywFoBMVM89HXogDBVIh6a3KpKEP7M05BA7Bl
79
+ cCvwUCvSXCO7dFQ6Q9sHz1tILHXFLSJCybFdt53s10/ty+/cjd5kACQQqAAFDm73/+31UwzP7e6d
80
+ OH0AQSc3BHAGHH43bivcS4UtOLQqx6QBDzIHMELiIxTh+OcBQJ7UpZO7h9tMH3Qw6q2bg+566EKW
81
+ PnHdLE2gwAnIsgHFPz8k/jroPCxFuuyCtdiS7Zkni4NgfP8OOgUx4HyU5MQLVvlIyHM8Al4/bOH8
82
+ 7yeIHhSk1b91OkkrdBAD7jSP8dYPOnz/PfTSC8Vl+WuG9IHtKmzMdRFZkJ8AcdUBofgGf4OhHUYm
83
+ wAMRsG+AEPwcChTwgZ80jXgWeFlGNCCqB0bwg68TgcJyoq/yEY4iHIxB8kDIwu8xoIA6kRvxwKSQ
84
+ /SlABCtsoQ4FOMEK2mR4k6MhQf/SpwAG+G+HSPygCGlywepRzCBENGISp5jEF8qEesQbSBSPSMUu
85
+ 7lBpMJFh9UpRRC568YxJfEngyjcCNLrxjC85IALb+MY6prElzaoeHe3IRxbiEYGC2WMfBznAk0yA
86
+ gQpQgSAAKRjfEfKR3+uIBibQAQUkkgEeLNUZGNlISHrydxOZZCUvmUl0zYGTghnDJ1f5OYTsj5KW
87
+ xGEOkYaD3aESL/FjpS7dNkpZmtFvtbzlYjy3y2K+8Qa2FCb3jMlMLwZTmYsRZDOnCcIsbA+a3nEk
88
+ NbcpwCKwAZvuCSA3x+m8LMABnOP5ATnX6Toc/ACd45kDO+fptxvA0z25pKc+j2b/z3t6R5r7DCi6
89
+ 3OdP73hPoPMsgEIXytBG2EETRCACJjhR0MWQIqJEsANDEbrKDGTgCRIIqUitIICSmvSkJ4VBRQXT
90
+ ABugtKQgkAAVMuAJIiiUo3x8qU53WtIdNGCleHEBT3UqgSccgghCKABOvTjUppZUpUD9RwNK4FSe
91
+ goAJfkjqUpFYVZ76NKr/iEJXnWqFDNRBqVsF4Vh1CtWoUnWtTgVBBrqA1rQKEK4nzcFPwZoGvHZV
92
+ Aoqoq11/59eSXgGsb4lDYbsKgkMIYbCELWwUECvVHSx2rBl4LGQ/V1gg7BWxV7jsWjO72cZJlrJv
93
+ 0YNo4UoHwZYWaX61wWcR24Ac/6x2rSBQgmtf2zG/lgC1eHnrbccKAkLslrfo8isQgPsWGAwXrxJ4
94
+ wXGRiyy/poG5/8DCc/3KBLpSN7l4dQFQ17AG7zTAA9v1K2m/myy/irei533vYpybXr/qlr23WqsN
95
+ 7gCEyRZ0qgJYrnnRW1/oShe/pepqf2frTwALQLbjaQAWhFvgsXYXwVWFAYMbTGH/jkeoFcZra9lb
96
+ 1Q3DswEucOlJ72Dif4A4xHDN7XTtmuEWC1PCMCDwSzVsXiDAuLAy5m1Xr+CCIrsABp7l5B6Q7AHL
97
+ NtUDMIhDAyTsgtD+eLG51SxkF2sDF9hYcHuw7ZXHzNMnRGLGARWtDdLgAixM+aXNb56blclM55dK
98
+ QAlaximMc+ABD5QACFFu8YvrTOiTMiEQaF4noXegYQarttCQRumhb7rPSPf50h4Qc6Q3bVIq+OCs
99
+ 9OS0qEetUxB4GtTjJLWqV21SCWSAEFptJqtnzWorMMEHLwhDonNK616zOqYZwLWud91FXxvb1xJg
100
+ QgbAQIRhv/HY0IZ2TF297Bc0m6HYzra2t81tbUf72+AOt7jHTe7FBgQAIfkEBTIApgAsCQAWAN4A
101
+ agAACP8ATQkcSLCgwYMIEQJYCCChw4cQI0qcSLGixYsYM2pkuFCjx48gQ37sKLJkwgoOHFQQyJGk
102
+ yZcwY15kKBOmgX//HCQw1bJhzZ9Ag3IMGhInThM8exJdyhRky6YYERjFeaGnT6hYswqUgeSgUq0S
103
+ pU41YPUq2LNAMRyQYbAjTbRtOYqdWsHq2bJm4XpUuyAuy7x6W841GsIuWLx6Q6o94ITtQJIuz15A
104
+ 8JhjhalGq37NijjxR76MHSf9C5cETg41kg7F/M+EYc5lPX8+YKrHATSVVcN1MJVFgqemMDt4jbWz
105
+ 7IxqBZqhTTqy1sE4TSHgaEDgVFMbNgftkaK79xQ9tB//t5jclAzaQxNDj559YXXr0VkQ/7nggP37
106
+ B/rmHo+x/JcFwOl1AWv/COQaAA8QFJ1q6QVVH3726UcafxclR8YSZASoF2+YDUQCAKkNZJR04tX0
107
+ IIQSjkYhebT1UEWJZ7FA4EAI7KRggQ/AGNMCbXyXQhspOrfiQzJgYBtBDSa2wYwCcQAACzeaQpaG
108
+ 9DmxwJVXWvmXkEMi1MMS93UpUAIcdihQDSHCV+BvVMq0AAYtYdBXm2IWdN59TtRpygNMSgkAB1G2
109
+ l6SJcHIkJ4OA6TlQFfh1VWcCHPRZwQY3/lMYnTC9yeChgypa0BcHGOGonustWBigIv7jJKYvaUrQ
110
+ oZ7G/1qRCQQWaMoFlKb6j2adlkRGd0ZgMBB3QMpq7EQWMHmqrh+yCpIR9wlb230pHmvtQQkky5op
111
+ OuUK35S9KnbfEo6dmMK16CKE0ow5vhccTmy+tWN+VQyExBJLfJHuvgaVmlMCK6Vag7NiojEqv2gt
112
+ SWCOSMHn2mQPRBwxCQjwWucCRoiG8Fl8sqYTmSI6gCpCDrBAQl2JelZfYxvDFcLCAHhrq0QcPKAZ
113
+ fxiHWi9LLWf1snAJkJCQIXl4AYhDBqB83JtmLJHxhD0zlS1rIxtkSABYFyEH0vLqpSmjPWwZdVNT
114
+ m3lQIVhjncmCB92ssrRfnMvg2FJrOyJCoKRtSihsG/80MJdaubqAGVsCTjdMZc98kBxiYF3I3Qfl
115
+ aDhWmvbAMqIpH/7SZX0jBIgc1yEkeeaUC2vEzqN1rblMP0tktkHNkg6VphqT9AEEq/+UAOQgoSw7
116
+ UUhcuYS0SH4gENa516RwSeDChQR+xA+kQgCmIJ+8TDIq/tF0ky+FBn5kGIS89dfDFKn2GjUPVwr3
117
+ SXIQ+eXHxLtH3P++1CKTiFJQ2vDH/9L8GmHTkPjXP/+V5HwhuZT9wEJA6hnQJp3DiE66BxcCPjAm
118
+ HUNfRVRCQb0U8IIiGVAEK1I/EJpQSgCkSHZOeMJ1aZCFMJzIkmJIw4t4q4Y4hMifPmKBHPrvhj4M
119
+ okH/3KWRRwjxiEg0YIKSiMSAMVGIKHmiFD/ChikiDAdW9CEWX7LFLB5LByPwIg3BKMYYkrGMLDwj
120
+ Gk1YhDms8YQBOMMPmKKDN46nCGFkygvtCJYsYIURfPQMDuYIlTEEUi9dbAocDgmXOmbFkYx8CQEm
121
+ SclKdgEPL8hkIiqRlU1k8gV4qGQkl9KCrETAAw8ZxQsmOUqYBCErSbCID14wAwK00iNDyMoeJdIE
122
+ U9TylhaJQFaCkAORlMGWwISIFrRSype8AZnJPMgrs9JMmCgBmtEUSAnAcoSf+GAG2RRIN7UizKCA
123
+ M5klKKdWtkmUc7YylmdxA1PUgM1A7kCdWgmCAJoi/4V6vnEKcIkAQKHCB3+WsZpnyWVWuGDQLCIU
124
+ LPDMShOeuUYaYAV9EbABWtzpRYsyJQIl8GhBlomWflpRADYoQUSDEoFlPlQgQdAoXBjKxCkcIQL4
125
+ ZKlCPZBTgUSABqhEy0SRqIWeshSh0zyISNFCTyEa9Sf/SMJAB9KCpy4VLibN4RF2WZJ/ROAIJSim
126
+ QYbQ038oVDZZpWEOhpAEnP6UrCI5Ag2G0AIPiDUhIXVrBIIwhLseRwoc9eEU2gqSI+zzcJdoaAxL
127
+ 4IYg4LRPDwFp7gCbRBt44LKYRWULWqAFGjgWIfJMXhMGodgneoAGEdDeVXM3WlaK0QZT2OxmHbED
128
+ EzEeM5zXuy1uc8eHX+72cL3kgm9/qznhupa4UeulKWh5XOQejgvMraR0p0vd6lp3ugEBADs=
129
+
130
+ -------=_NextPart_39580_29716_19852
131
+ Content-Type: image/gif; name="0002.gif"
132
+ Content-Transfer-Encoding: base64
133
+ Content-Disposition: attachment; filename="0002.gif"
134
+ Content-ID: <02@110207.180722>
135
+
136
+ R0lGODlhFAAUAPIFAAAAAP8AAP9p//868f/5AAAAAAAAAAAAACH5BAkPAAUAIf8LTkVUU0NBUEUy
137
+ LjADAQAAACwAAAAAFAAUAAADRliwXP7wrQACBTEry6mOVed9UmgtJGSOCvZNV+m6aoO2Dq01oN6/
138
+ N0lK0fNljERSsAZE4moMZ9QGICxTC4L2qqxysd8hLQEAIfkECQ8ABQAsAAAAABQAFAAAAzRYuszw
139
+ r0kHwbxW5Uv15l4IRuAEaSWpjmSHfRQMS3KLmawj0t9Z2D/gL1YpGU3CFGGWSk4SACH5BAkPAAUA
140
+ LAAAAAAUABQAAANHWLrczgC8CeWKtMStcO7WZlGeNmaneX3Q2qSOeMEzzYHyJEZBH9Az3+6zExgl
141
+ QNPRKMg9AMxjhFB6QaUAgrZa4Uy5RDBrlAAAIfkEBQ8ABQAsAAAAABQAFAAAA0tYutzOALwJ5Yq0
142
+ xK1w7tZmUZ42Zqd5fdDapI54wTPNgfIkRkEf0DPf7rMTGGGyyNEoSAEGTwyAeXQOrlATs3TBZk23
143
+ 1xMKfORYhQQAOw==
144
+
145
+ -------=_NextPart_39580_29716_19852
146
+ Content-Type: image/gif; name="SHmura01_2.gif"
147
+ Content-Transfer-Encoding: base64
148
+ Content-Disposition: attachment; filename="SHmura01_2.gif"
149
+ Content-ID: <03@110207.180712>
150
+
151
+ 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
190
+
191
+ -------=_NextPart_39580_29716_19852--
192
+