pastehub 0.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,70 @@
1
+ #
2
+ # crypt.rb - PasteHub's encrypt/decrypt library
3
+ #
4
+ # Copyright (c) 2009-2011 Kiyoka Nishiyama <kiyoka@sumibi.org>
5
+ #
6
+ # Redistribution and use in source and binary forms, with or without
7
+ # modification, are permitted provided that the following conditions
8
+ # are met:
9
+ #
10
+ # 1. Redistributions of source code must retain the above copyright
11
+ # notice, this list of conditions and the following disclaimer.
12
+ #
13
+ # 2. Redistributions in binary form must reproduce the above copyright
14
+ # notice, this list of conditions and the following disclaimer in the
15
+ # documentation and/or other materials provided with the distribution.
16
+ #
17
+ # 3. Neither the name of the authors nor the names of its contributors
18
+ # may be used to endorse or promote products derived from this
19
+ # software without specific prior written permission.
20
+ #
21
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22
+ # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23
+ # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24
+ # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25
+ # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26
+ # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
27
+ # TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28
+ # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29
+ # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30
+ # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31
+ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32
+ #
33
+ #
34
+ require 'openssl'
35
+ require 'base64'
36
+
37
+ module PasteHub
38
+ class Crypt
39
+ def initialize( password )
40
+ @password = password
41
+ @des3 = OpenSSL::Cipher.new('des3')
42
+ end
43
+
44
+ def en( str )
45
+ if 0 == str.size
46
+ ""
47
+ else
48
+ @des3.encrypt
49
+ @des3.pkcs5_keyivgen( @password )
50
+ Base64.encode64( @des3.update( str ) + @des3.final )
51
+ end
52
+ end
53
+
54
+ def de( str )
55
+ if 0 == str.size
56
+ ""
57
+ else
58
+ begin
59
+ @des3.decrypt
60
+ @des3.pkcs5_keyivgen( @password )
61
+ ret = @des3.update( Base64.decode64( str ))
62
+ ret += @des3.final
63
+ rescue OpenSSL::Cipher::CipherError => e
64
+ ret = nil
65
+ end
66
+ ret
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,187 @@
1
+ #
2
+ # localdb.rb - PasteHub's localdb manager
3
+ #
4
+ # Copyright (c) 2009-2011 Kiyoka Nishiyama <kiyoka@sumibi.org>
5
+ #
6
+ # Redistribution and use in source and binary forms, with or without
7
+ # modification, are permitted provided that the following conditions
8
+ # are met:
9
+ #
10
+ # 1. Redistributions of source code must retain the above copyright
11
+ # notice, this list of conditions and the following disclaimer.
12
+ #
13
+ # 2. Redistributions in binary form must reproduce the above copyright
14
+ # notice, this list of conditions and the following disclaimer in the
15
+ # documentation and/or other materials provided with the distribution.
16
+ #
17
+ # 3. Neither the name of the authors nor the names of its contributors
18
+ # may be used to endorse or promote products derived from this
19
+ # software without specific prior written permission.
20
+ #
21
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22
+ # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23
+ # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24
+ # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25
+ # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26
+ # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
27
+ # TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28
+ # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29
+ # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30
+ # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31
+ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32
+ #
33
+ #
34
+ require 'gdbm'
35
+
36
+ module PasteHub
37
+ class MutexSingleton
38
+ include Singleton
39
+
40
+ attr_reader :mutex
41
+
42
+ def self.instance
43
+ @@instance ||= new
44
+ end
45
+
46
+ def initialize( )
47
+ @mutex = Mutex.new
48
+ end
49
+ end
50
+
51
+ ONLINE_STATE_KEY='__ONLINE_STATE'
52
+ LOCAL_DATE_KEY ='__LOCAL_DATE'
53
+ SERVER_DATE_KEY ='__SERVER_DATE'
54
+
55
+ LOCAL_PREFIX = "local::"
56
+ SERVER_PREFIX = "server::"
57
+
58
+ class LocalDB
59
+ def initialize( basepath = "/tmp/")
60
+ @mutex = MutexSingleton.instance.mutex
61
+ @basepath = basepath
62
+ end
63
+
64
+ def open( username, reader = false )
65
+ closed = false
66
+ (60*2).times { |n|
67
+ @mutex.synchronize {
68
+ if reader
69
+ @db = GDBM.new( @basepath + username + ".db", nil, GDBM::READER | GDBM::NOLOCK )
70
+ else
71
+ @db = GDBM.new( @basepath + username + ".db", nil, GDBM::WRCREAT )
72
+ end
73
+ closed = @db.closed?
74
+ }
75
+ break unless closed
76
+ #STDERR.puts "#Warning: DB open fail(locked) retry..."
77
+ sleep 0.5
78
+ }
79
+ @mutex.synchronize {
80
+ closed = @db.closed?
81
+ }
82
+ if closed
83
+ raise RuntimeError, sprintf( "DBM.new open error: file=%s", username + ".db" )
84
+ end
85
+ @username = username
86
+ end
87
+
88
+ def getList( limit = nil )
89
+ arr = self._getList().reject{|x| x.match( /^_/ )}
90
+ if limit
91
+ arr.take( limit )
92
+ else
93
+ arr
94
+ end
95
+ end
96
+
97
+ def _getList( )
98
+ forward_match_keys( LOCAL_PREFIX ).sort {|a,b| -(a <=> b) }.map {|x|
99
+ x[(LOCAL_PREFIX.size)...(x.size)]
100
+ }
101
+ end
102
+
103
+ def getServerList( )
104
+ self._getServerList().reject{|x| x.match( /^_/ )}
105
+ end
106
+
107
+ def _getServerList( )
108
+ forward_match_keys( SERVER_PREFIX ).sort {|a,b| -(a <=> b) }.map {|x|
109
+ x[(SERVER_PREFIX.size)...(x.size)]
110
+ }
111
+ end
112
+
113
+ def getValue( key, fallback = false )
114
+ val = nil
115
+ @mutex.synchronize {
116
+ val = @db[ LOCAL_PREFIX + key ]
117
+ }
118
+ if val
119
+ val.force_encoding("UTF-8")
120
+ else
121
+ fallback
122
+ end
123
+ end
124
+
125
+ def insertValue( key, value )
126
+ @mutex.synchronize {
127
+ @db[ LOCAL_PREFIX + key.force_encoding("ASCII-8BIT") ] = value.force_encoding("ASCII-8BIT")
128
+ }
129
+ end
130
+
131
+ def deleteValue( key )
132
+ ret = false
133
+ @mutex.synchronize {
134
+ val = @db[ LOCAL_PREFIX + key ]
135
+ if val
136
+ @db.delete( LOCAL_PREFIX + key )
137
+ ret = true
138
+ else
139
+ ret = false
140
+ end
141
+ }
142
+ ret
143
+ end
144
+
145
+ def setServerFlag( key )
146
+ @mutex.synchronize {
147
+ @db[ SERVER_PREFIX + key ] = '1'
148
+ }
149
+ end
150
+
151
+ def onServer?( key )
152
+ ret = false
153
+ @mutex.synchronize {
154
+ if @db[ SERVER_PREFIX + key ]
155
+ ret = true
156
+ else
157
+ ret = false
158
+ end
159
+ }
160
+ ret
161
+ end
162
+
163
+ def forward_match_keys( prefix )
164
+ keys = []
165
+ @mutex.synchronize {
166
+ keys = @db.keys( ).select {|key|
167
+ key.match( "^" + prefix )
168
+ }
169
+ }
170
+ keys
171
+ end
172
+
173
+ def clear
174
+ @mutex.synchronize {
175
+ @db.clear
176
+ }
177
+ end
178
+
179
+ def close
180
+ ret = nil
181
+ @mutex.synchronize {
182
+ ret = @db.close
183
+ }
184
+ ret
185
+ end
186
+ end
187
+ end
@@ -0,0 +1,95 @@
1
+ #
2
+ # log.rb - PasteHub's log manager
3
+ #
4
+ # Copyright (c) 2009-2011 Kiyoka Nishiyama <kiyoka@sumibi.org>
5
+ #
6
+ # Redistribution and use in source and binary forms, with or without
7
+ # modification, are permitted provided that the following conditions
8
+ # are met:
9
+ #
10
+ # 1. Redistributions of source code must retain the above copyright
11
+ # notice, this list of conditions and the following disclaimer.
12
+ #
13
+ # 2. Redistributions in binary form must reproduce the above copyright
14
+ # notice, this list of conditions and the following disclaimer in the
15
+ # documentation and/or other materials provided with the distribution.
16
+ #
17
+ # 3. Neither the name of the authors nor the names of its contributors
18
+ # may be used to endorse or promote products derived from this
19
+ # software without specific prior written permission.
20
+ #
21
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22
+ # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23
+ # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24
+ # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25
+ # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26
+ # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
27
+ # TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28
+ # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29
+ # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30
+ # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31
+ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32
+ #
33
+ #
34
+
35
+ module PasteHub
36
+ class LogBase
37
+ def initialize( hash )
38
+ @user = nil
39
+ if hash.is_a? Hash
40
+ if hash.has_key?( :user )
41
+ @user = hash[ :user ]
42
+ else
43
+ @user = 'UNSPECIFIED'
44
+ end
45
+ if hash.has_key?( :api )
46
+ @api = hash[ :api ]
47
+ else
48
+ raise ArgumentError if not @api
49
+ end
50
+ else
51
+ raise ArgumentError
52
+ end
53
+
54
+ @uri = URI.parse( "http://localhost:9880/pastehub.webapi" )
55
+ @http = Net::HTTP.new(@uri.host, @uri.port)
56
+ #Fluent::Logger::FluentLogger.open(nil, :host=>'localhost', :port=>24224)
57
+ end
58
+
59
+ def write( hashData )
60
+ begin
61
+ jsonStr = hashData.to_json
62
+ resp = @http.post( @uri.request_uri, "json=" + jsonStr )
63
+ if "200" != resp.code
64
+ STDERR.print "Error: can't post to fluentd(http)[1].\n"
65
+ end
66
+ rescue
67
+ STDERR.print "Error: can't post to fluentd(http)[2].\n"
68
+ end
69
+ #Fluent::Logger.post("pastehub.webapi", hashData)
70
+ true
71
+ end
72
+ end
73
+
74
+ class Log < LogBase
75
+ # info without error
76
+ def info( message, moreHash = {} )
77
+ hashData = {
78
+ "user"=>"#{@user}",
79
+ "api"=>"#{@api}",
80
+ "message"=>"#{message}",
81
+ "error" => false}
82
+ write( hashData.merge( moreHash ) )
83
+ end
84
+
85
+ # errors
86
+ def error( message, moreHash = {} )
87
+ hashData = {
88
+ "user"=>"#{@user}",
89
+ "api"=>"#{@api}",
90
+ "message"=>"#{message}",
91
+ "error" => true}
92
+ write( hashData.merge( moreHash ) )
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,66 @@
1
+ #
2
+ # macosx.rb - PasteHub's clipboard sync thread for MacOS X
3
+ #
4
+ # Copyright (c) 2009-2011 Kiyoka Nishiyama <kiyoka@sumibi.org>
5
+ #
6
+ # Redistribution and use in source and binary forms, with or without
7
+ # modification, are permitted provided that the following conditions
8
+ # are met:
9
+ #
10
+ # 1. Redistributions of source code must retain the above copyright
11
+ # notice, this list of conditions and the following disclaimer.
12
+ #
13
+ # 2. Redistributions in binary form must reproduce the above copyright
14
+ # notice, this list of conditions and the following disclaimer in the
15
+ # documentation and/or other materials provided with the distribution.
16
+ #
17
+ # 3. Neither the name of the authors nor the names of its contributors
18
+ # may be used to endorse or promote products derived from this
19
+ # software without specific prior written permission.
20
+ #
21
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22
+ # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23
+ # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24
+ # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25
+ # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26
+ # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
27
+ # TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28
+ # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29
+ # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30
+ # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31
+ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32
+ #
33
+ #
34
+
35
+ module PasteHub
36
+
37
+ class MacOSX
38
+
39
+ def self.push( data )
40
+ pbcopy = "/usr/bin/pbcopy"
41
+ if File.exist?( pbcopy )
42
+ begin
43
+ IO.popen(pbcopy, "r+") {|io|
44
+ io.write data
45
+ io.close
46
+ }
47
+ STDERR.puts "Info: push to MacOS X clipboard."
48
+ rescue IOError => e
49
+ STDERR.puts( "Error: program #{pbcopy} not found." )
50
+ return false
51
+ end
52
+ end
53
+ end
54
+
55
+ def self.hasNew?( username )
56
+ osxPaste = open( "|/usr/bin/pbpaste" ) { |f|
57
+ f.read
58
+ }
59
+ if 0 < osxPaste.size
60
+ osxPaste
61
+ else
62
+ nil
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,213 @@
1
+ #
2
+ # masterdb.rb - PasteHub's master database manager
3
+ #
4
+ # Copyright (c) 2009-2011 Kiyoka Nishiyama <kiyoka@sumibi.org>
5
+ #
6
+ # Redistribution and use in source and binary forms, with or without
7
+ # modification, are permitted provided that the following conditions
8
+ # are met:
9
+ #
10
+ # 1. Redistributions of source code must retain the above copyright
11
+ # notice, this list of conditions and the following disclaimer.
12
+ #
13
+ # 2. Redistributions in binary form must reproduce the above copyright
14
+ # notice, this list of conditions and the following disclaimer in the
15
+ # documentation and/or other materials provided with the distribution.
16
+ #
17
+ # 3. Neither the name of the authors nor the names of its contributors
18
+ # may be used to endorse or promote products derived from this
19
+ # software without specific prior written permission.
20
+ #
21
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22
+ # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23
+ # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24
+ # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25
+ # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26
+ # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
27
+ # TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28
+ # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29
+ # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30
+ # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31
+ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32
+ #
33
+ #
34
+ require 'dynamoid'
35
+ require 'date'
36
+
37
+ module PasteHub
38
+
39
+ # fake DynamoDB on localhost
40
+ Dynamoid.configure do |conf|
41
+ config = PasteHub::Config.instance
42
+ conf.adapter = 'aws_sdk'
43
+ conf.namespace = config.domain # To namespace tables created by Dynamoid from other tables you might have.
44
+ conf.warn_on_scan = config.awsWarn # Output a warning to the logger when you perform a scan rather than a query on a table.
45
+ conf.partitioning = false # Spread writes randomly across the database. See "partitioning" below for more.
46
+ conf.partition_size = 1 # Determine the key space size that writes are randomly spread across.
47
+ conf.read_capacity = 1 # Read capacity for your tables
48
+ conf.write_capacity = 1 # Write capacity for your tables
49
+ conf.access_key = config.dynamoAccessKey # If connecting to DynamoDB, your access key is required.
50
+ conf.secret_key = config.dynamoSecretKey # So is your secret key.
51
+ conf.endpoint = config.dynamoEp # Set the regional endpoint
52
+ conf.port = '443' # Use real dynamo
53
+ if not config.aws
54
+ conf.endpoint = 'localhost' # Set the regional endpoint
55
+ conf.use_ssl = false # Don't use SSL
56
+ conf.port = '4567' # Use fake_dynamo
57
+ end
58
+ end
59
+
60
+ class User
61
+ include Dynamoid::Document
62
+
63
+ table :name => :users, :key => :username
64
+
65
+ field :username
66
+ field :secretKey
67
+ field :created_datetime, :datetime
68
+ field :touched_datetime, :datetime
69
+ #field :friends, :set
70
+
71
+ # index :username
72
+
73
+ validates_presence_of :username
74
+ validates_presence_of :secretKey
75
+ end
76
+
77
+ class Entry
78
+ include Dynamoid::Document
79
+
80
+ table :name => :entries, :key => :userkey
81
+
82
+ field :userkey
83
+ field :username
84
+ # field :comment
85
+ # field :from
86
+ # field :to
87
+ # field :cc
88
+ # field :type
89
+ field :data
90
+
91
+ index [:username]
92
+
93
+ validates_presence_of :userkey
94
+ # validates_presence_of :data
95
+
96
+ def id
97
+ userkey
98
+ end
99
+ end
100
+
101
+
102
+ class Users
103
+ def addUser( username, secretKey )
104
+ user = User.new( :username => username, :secretKey => secretKey, :created_datetime => DateTime.new())
105
+ user.save
106
+ end
107
+
108
+ def updateSecretKey( username, secretKey )
109
+ arr = User.where( :username => username ).all
110
+ if 0 < arr.size
111
+ arr.first.secretKey = secretKey
112
+ arr.first.save
113
+ true
114
+ else
115
+ false
116
+ end
117
+ end
118
+
119
+ def getSecretKey( username )
120
+ arr = User.where( :username => username ).all
121
+ if 0 < arr.size
122
+ arr.first.secretKey
123
+ else
124
+ nil
125
+ end
126
+ end
127
+
128
+ def touch( username )
129
+ arr = User.where( :username => username ).all
130
+ if 0 < arr.size
131
+ arr.first.touched_datetime = DateTime.new()
132
+ arr.first.save
133
+ true
134
+ else
135
+ nil
136
+ end
137
+ end
138
+
139
+ def getList()
140
+ arr = User.all
141
+ arr.map { |x| x.username }.sort
142
+ end
143
+
144
+ def __deleteUser( username )
145
+ user = User.find( username )
146
+ if user
147
+ user.delete
148
+ true
149
+ else
150
+ false
151
+ end
152
+ end
153
+
154
+ end
155
+
156
+
157
+ class Entries
158
+ def initialize( username )
159
+ @holdUsername = username
160
+ end
161
+
162
+ def getList( limit = nil )
163
+ arr = Entry.where( :username => @holdUsername ).map {|x|
164
+ # remove username from `userkey'
165
+ field = x.userkey.split( /::/ )
166
+ field[1]
167
+ }.sort {|a,b| -(a <=> b) }
168
+ if limit
169
+ arr.take( limit )
170
+ else
171
+ arr
172
+ end
173
+ end
174
+
175
+ def getValue( key, fallback = false )
176
+ p "username=#{@holdUsername}"
177
+ p "key=#{key}"
178
+ entry = Entry.find( @holdUsername + "::" + key, :consistent_read => true )
179
+ if entry
180
+ if entry.data
181
+ entry.data.force_encoding("UTF-8")
182
+ end
183
+ else
184
+ fallback
185
+ end
186
+ end
187
+
188
+ def insertValue( key, value )
189
+ entry = Entry.new( :username => @holdUsername,
190
+ :userkey => @holdUsername + "::" + key,
191
+ :data => value.force_encoding("UTF-8") )
192
+ entry.save
193
+ end
194
+
195
+ def deleteLast( )
196
+ arr = getList( )
197
+ if 0 < arr.size
198
+ deleteValue( arr[arr.size-1] )
199
+ end
200
+ end
201
+
202
+ def deleteValue( key )
203
+ # caution: This method is non consistent read.
204
+ entry = Entry.find( @holdUsername + "::" + key )
205
+ if entry
206
+ entry.delete
207
+ true
208
+ else
209
+ false
210
+ end
211
+ end
212
+ end
213
+ end