taskmapper-pivotal 0.8.0

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.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.8.7
4
+ - 1.9.2
data/Gemfile ADDED
@@ -0,0 +1,14 @@
1
+ source "http://rubygems.org"
2
+ # Add dependencies required to use your gem here.
3
+ # Example:
4
+ # gem "activesupport", ">= 2.3.5"
5
+
6
+ gem "taskmapper", "~> 0.8"
7
+ # Add dependencies to develop your gem here.
8
+ # Include everything needed to run rake, tests, features, etc.
9
+ group :development do
10
+ gem "rspec", "~> 2.8"
11
+ gem "jeweler", "~> 1.6"
12
+ gem "simplecov", "~> 0.5", :platforms => :ruby_19
13
+ gem "rcov", "~> 1.0", :platforms => :ruby_18
14
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,50 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ activemodel (3.2.3)
5
+ activesupport (= 3.2.3)
6
+ builder (~> 3.0.0)
7
+ activeresource (3.2.3)
8
+ activemodel (= 3.2.3)
9
+ activesupport (= 3.2.3)
10
+ activesupport (3.2.3)
11
+ i18n (~> 0.6)
12
+ multi_json (~> 1.0)
13
+ builder (3.0.0)
14
+ diff-lcs (1.1.3)
15
+ git (1.2.5)
16
+ hashie (1.2.0)
17
+ i18n (0.6.0)
18
+ jeweler (1.6.4)
19
+ bundler (~> 1.0)
20
+ git (>= 1.2.5)
21
+ rake
22
+ multi_json (1.0.4)
23
+ rake (0.9.2.2)
24
+ rcov (1.0.0)
25
+ rspec (2.8.0)
26
+ rspec-core (~> 2.8.0)
27
+ rspec-expectations (~> 2.8.0)
28
+ rspec-mocks (~> 2.8.0)
29
+ rspec-core (2.8.0)
30
+ rspec-expectations (2.8.0)
31
+ diff-lcs (~> 1.1.2)
32
+ rspec-mocks (2.8.0)
33
+ simplecov (0.5.4)
34
+ multi_json (~> 1.0.3)
35
+ simplecov-html (~> 0.5.3)
36
+ simplecov-html (0.5.3)
37
+ taskmapper (0.8.0)
38
+ activeresource (~> 3.0)
39
+ activesupport (~> 3.0)
40
+ hashie (~> 1.2)
41
+
42
+ PLATFORMS
43
+ ruby
44
+
45
+ DEPENDENCIES
46
+ jeweler (~> 1.6)
47
+ rcov (~> 1.0)
48
+ rspec (~> 2.8)
49
+ simplecov (~> 0.5)
50
+ taskmapper (~> 0.8)
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2009-2010 The Hybrid Group
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
+ NONE
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.markdown ADDED
@@ -0,0 +1,17 @@
1
+ # taskmapper-pivotal
2
+
3
+ Description goes here.
4
+
5
+ ## Note on Patches/Pull Requests
6
+
7
+ * Fork the project.
8
+ * Make your feature addition or bug fix.
9
+ * Add tests for it. This is important so I don't break it in a
10
+ future version unintentionally.
11
+ * Commit, do not mess with rakefile, version, or history.
12
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
13
+ * Send me a pull request. Bonus points for topic branches.
14
+
15
+ ## Copyright
16
+
17
+ Copyright (c) 2010 The Hybrid Group. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,41 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "taskmapper-pivotal"
8
+ gem.summary = %Q{This is a taskmapper provider for interacting with Pivotal Tracker}
9
+ gem.description = %Q{This is a taskmapper provider for interacting with Pivotal Tracker .}
10
+ gem.email = "hong.quach@abigfisch.com"
11
+ gem.homepage = "http://ticket.rb"
12
+ gem.authors = ["HybridGroup"]
13
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
14
+ end
15
+ Jeweler::GemcutterTasks.new
16
+ rescue LoadError
17
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
18
+ end
19
+
20
+ require 'rspec/core'
21
+ require 'rspec/core/rake_task'
22
+ RSpec::Core::RakeTask.new(:spec) do |spec|
23
+ spec.pattern = FileList['spec/**/*_spec.rb']
24
+ end
25
+
26
+ RSpec::Core::RakeTask.new(:rcov) do |spec|
27
+ spec.pattern = 'spec/**/*_spec.rb'
28
+ spec.rcov = true
29
+ end
30
+
31
+ task :default => :spec
32
+
33
+ require 'rake/rdoctask'
34
+ Rake::RDocTask.new do |rdoc|
35
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
36
+
37
+ rdoc.rdoc_dir = 'rdoc'
38
+ rdoc.title = "taskmapper-kanbanpad#{version}"
39
+ rdoc.rdoc_files.include('README*')
40
+ rdoc.rdoc_files.include('lib/**/*.rb')
41
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.8.0
@@ -0,0 +1,74 @@
1
+ require 'rubygems'
2
+ require 'active_support'
3
+ require 'active_resource'
4
+
5
+ module PivotalAPI
6
+ class Error < StandardError; end
7
+ class << self
8
+ # Sets up basic authentication credentials for all the resources.
9
+ def authenticate(user, password)
10
+ Token.user = user
11
+ Token.password = password
12
+ self.token = Token.get(:active)['guid']
13
+ Token.user = nil
14
+ Token.password = nil
15
+ end
16
+
17
+ # Sets the API token for all the resources.
18
+ def token=(value)
19
+ resources.each do |klass|
20
+ klass.headers['X-TrackerToken'] = value
21
+ end
22
+ @token = value
23
+ end
24
+
25
+ def resources
26
+ @resources ||= []
27
+ end
28
+ end
29
+
30
+ class Base < ActiveResource::Base
31
+ self.site = 'https://www.pivotaltracker.com/services/v3/'
32
+ self.format = ActiveResource::Formats::XmlFormat
33
+ def self.inherited(base)
34
+ PivotalAPI.resources << base
35
+ super
36
+ end
37
+ end
38
+
39
+ class Project < Base
40
+ def stories(options = {})
41
+ Story.find(:all, :params => options.merge!(:project_id => self.id))
42
+ end
43
+ end
44
+
45
+ class Token < Base
46
+ end
47
+
48
+ class Activity < Base
49
+ self.site += 'projects/:project_id/'
50
+ end
51
+
52
+ class Membership < Base
53
+ self.site += 'projects/:project_id/'
54
+ end
55
+
56
+ class Iteration < Base
57
+ self.site += 'projects/:project_id/'
58
+ end
59
+
60
+ class Story < Base
61
+ self.site += 'projects/:project_id/'
62
+ end
63
+
64
+ class Note < Base
65
+ self.site += 'projects/:project_id/stories/:story_id/'
66
+ end
67
+
68
+ class Task < Base
69
+ self.site += 'projects/:project_id/stories/:story_id/'
70
+ end
71
+
72
+ class AllActivity < Base
73
+ end
74
+ end
@@ -0,0 +1,70 @@
1
+ module TaskMapper::Provider
2
+ module Pivotal
3
+ # The comment class for taskmapper-pivotal
4
+ # * author
5
+ # * body => text
6
+ # * id => position in the versions array (set by the initializer)
7
+ # * created_at => noted_at
8
+ # * updated_at => noted_at
9
+ # * ticket_id (actually the story id)
10
+ # * project_id
11
+ class Comment < TaskMapper::Provider::Base::Comment
12
+ API = PivotalAPI::Note
13
+
14
+ # A custom find_by_id
15
+ # The "comment" id is it's index in the versions array. An id of 0 therefore exists and
16
+ # should be the first ticket (original)
17
+ def self.find_by_id(project_id, ticket_id, id)
18
+ self.new(project_id, ticket_id, PivotalAPI::Note.find(id, :params => {:project_id => project_id, :story_id => ticket_id}))
19
+ end
20
+
21
+ # A custom find_by_attributes
22
+ #
23
+ def self.find_by_attributes(project_id, ticket_id, attributes = {})
24
+ self.search(project_id, ticket_id, attributes).collect { |comment| self.new(project_id, ticket_id, comment) }
25
+ end
26
+
27
+ # A custom searcher
28
+ #
29
+ # It returns a custom result because we need the original story to make a comment.
30
+ def self.search(project_id, ticket_id, options = {}, limit = 1000)
31
+ comments = PivotalAPI::Note.find(:all, :params => {:project_id => project_id, :story_id => ticket_id})
32
+ search_by_attribute(comments, options, limit)
33
+ end
34
+
35
+ # A custom creator
36
+ # We didn't really need to do much other than change the :ticket_id attribute to :story_id
37
+ def self.create(project_id, ticket_id, *options)
38
+ first = options.first
39
+ first[:story_id] ||= ticket_id
40
+ first[:project_id] ||= project_id
41
+ first[:text] ||= first.delete(:body) || first.delete('body')
42
+ note = PivotalAPI::Note.new(first)
43
+ note.save
44
+ self.new(project_id, ticket_id, note)
45
+ end
46
+
47
+ def initialize(project_id, ticket_id, *object)
48
+ if object.first
49
+ object = object.first
50
+ unless object.is_a? Hash
51
+ hash = {:id => object.id,
52
+ :body => object.text,
53
+ :update_at => object.noted_at,
54
+ :created_at => object.noted_at,
55
+ :project_id => project_id,
56
+ :ticket_id => ticket_id
57
+ }
58
+ else
59
+ hash = object
60
+ end
61
+ super hash
62
+ end
63
+ end
64
+
65
+ def body=(bod)
66
+ self.text = bod
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,37 @@
1
+ module TaskMapper::Provider
2
+ # This is the Pivotal Tracker Provider for taskmapper
3
+ module Pivotal
4
+ include TaskMapper::Provider::Base
5
+ TICKET_API = PivotalAPI::Story
6
+ PROJECT_API = PivotalAPI::Project
7
+
8
+ # This is for cases when you want to instantiate using TaskMapper::Provider::Lighthouse.new(auth)
9
+ def self.new(auth = {})
10
+ TaskMapper.new(:pivotal, auth)
11
+ end
12
+
13
+ # The authorize and initializer for this provider
14
+ def authorize(auth = {})
15
+ @authentication ||= TaskMapper::Authenticator.new(auth)
16
+ auth = @authentication
17
+ if auth.token.empty?
18
+ raise "You should pass a token for authentication"
19
+ end
20
+ if auth.token
21
+ PivotalAPI.token = auth.token
22
+ elsif auth.username && auth.password
23
+ PivotalAPI.authenticate(auth.username, auth.password)
24
+ end
25
+ end
26
+
27
+ def valid?
28
+ begin
29
+ PROJECT_API.find(:first)
30
+ true
31
+ rescue
32
+ false
33
+ end
34
+ end
35
+
36
+ end
37
+ end
@@ -0,0 +1,55 @@
1
+ module TaskMapper::Provider
2
+ module Pivotal
3
+ # Project class for taskmapper-pivotal
4
+ #
5
+ #
6
+ class Project < TaskMapper::Provider::Base::Project
7
+ API = PivotalAPI::Project
8
+ # The finder method
9
+ #
10
+ # It accepts all the find functionalities defined by taskmapper
11
+ #
12
+ # + find() and find(:all) - Returns all projects on the account
13
+ # + find(<project_id>) - Returns the project based on the id
14
+ # + find(:first, :name => <project_name>) - Returns the first project based on the attribute
15
+ # + find(:name => <project name>) - Returns all projects based on the attribute
16
+ attr_accessor :prefix_options
17
+ alias_method :stories, :tickets
18
+ alias_method :story, :ticket
19
+
20
+ # Save this project
21
+ def save
22
+ warn 'Warning: Pivotal does not allow editing of project attributes. This method does nothing.'
23
+ true
24
+ end
25
+
26
+ def initialize(*options)
27
+ super(*options)
28
+ self.id = self.id.to_i
29
+ end
30
+
31
+ # Delete this project
32
+ def destroy
33
+ result = self.system_data[:client].destroy
34
+ result.is_a?(Net::HTTPOK)
35
+ end
36
+
37
+ def ticket!(*options)
38
+ options.first.merge!(:project_id => self.id)
39
+ Ticket.create(options.first)
40
+ end
41
+
42
+ # copy from
43
+ def copy(project)
44
+ project.tickets.each do |ticket|
45
+ copy_ticket = self.ticket!(:name => ticket.title, :description => ticket.description)
46
+ ticket.comments.each do |comment|
47
+ copy_ticket.comment!(:text => comment.body)
48
+ sleep 1
49
+ end
50
+ end
51
+ end
52
+
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,124 @@
1
+ module TaskMapper::Provider
2
+ module Pivotal
3
+ # Ticket class for taskmapper-pivotal
4
+ # * id
5
+ # * status
6
+ # * priority
7
+ # * title => name
8
+ # * resolution
9
+ # * created_at
10
+ # * updated_at
11
+ # * description => text
12
+ # * assignee
13
+ # * requestor
14
+ # * project_id (prefix_options[:project_id])
15
+ class Ticket < TaskMapper::Provider::Base::Ticket
16
+ @@allowed_states = ['new', 'open', 'resolved', 'hold', 'invalid']
17
+
18
+ attr_accessor :prefix_options
19
+ API = PivotalAPI::Story
20
+
21
+
22
+ # The saver
23
+ def save(*options)
24
+ pt_ticket = @system_data[:client]
25
+ self.keys.each do |key|
26
+ pt_ticket.send(key + '=', self.send(key)) if self.send(key) != pt_ticket.send(key)
27
+ end
28
+ pt_ticket.save
29
+ end
30
+
31
+ def destroy(*options)
32
+ @system_data[:client].destroy.is_a?(Net::HTTPOK)
33
+ end
34
+
35
+ def project_id
36
+ self.prefix_options[:project_id]
37
+ end
38
+
39
+ def requestor
40
+ self.requested_by
41
+ end
42
+
43
+ def title
44
+ self.name
45
+ end
46
+
47
+ def title=(title)
48
+ self.name=title
49
+ end
50
+
51
+ def status
52
+ self.current_state
53
+ end
54
+
55
+ def priority
56
+ self.estimate
57
+ end
58
+
59
+ def resolution
60
+ self.current_state
61
+ end
62
+
63
+ def assignee
64
+ self.owned_by
65
+ end
66
+
67
+ def comment!(*options)
68
+ Comment.create(self.project_id, self.id, options.first)
69
+ end
70
+ # The closer
71
+ def close(resolution = 'resolved')
72
+ resolution = 'resolved' unless @@allowed_states.include?(resolution)
73
+ ticket = PivotalAPI::Ticket.find(self.id, :params => {:project_id => self.prefix_options[:project_id]})
74
+ ticket.state = resolution
75
+ ticket.save
76
+ end
77
+
78
+ class << self
79
+
80
+ def find_by_attributes(project_id, attributes = {})
81
+ date_to_search = attributes[:updated_at] || attributes[:created_at]
82
+ tickets = []
83
+ unless date_to_search.nil?
84
+ tickets = search_by_datefields(project_id, date_to_search)
85
+ else
86
+ tickets += API.find(:all, :params => {:project_id => project_id, :filter => filter(attributes)}).map { |xticket| self.new xticket }
87
+ end
88
+ tickets.flatten
89
+ end
90
+
91
+ def filter(attributes = {})
92
+ filter = ""
93
+ attributes.each_pair do |key, value|
94
+ filter << "#{key}:#{value} "
95
+ end
96
+ filter.strip!
97
+ end
98
+
99
+ def create(options)
100
+ super translate options, {:title => :name,
101
+ :requestor => :requested_by,
102
+ :status => :current_state,
103
+ :estimate => :priority,
104
+ :assignee => :owned_by}
105
+ end
106
+
107
+ private
108
+ def search_by_datefields(project_id, date_to_search)
109
+ date_to_search = date_to_search.strftime("%Y/%m/%d")
110
+ tickets = []
111
+ PivotalAPI::Activity.find(:all, :params => {:project_id => project_id, :occurred_since_date => date_to_search}).each do |activity|
112
+ tickets = activity.stories.map { |xstory| self.new xstory }
113
+ end
114
+ tickets
115
+ end
116
+
117
+ def translate(hash, mapping)
118
+ Hash[hash.map { |k, v| [mapping[k] ||= k, v]}]
119
+ end
120
+ end
121
+ end
122
+
123
+ end
124
+ end
@@ -0,0 +1,6 @@
1
+ require File.dirname(__FILE__) + '/pivotal/pivotal-api'
2
+
3
+ %w{ pivotal ticket project comment }.each do |f|
4
+ require File.dirname(__FILE__) + '/provider/' + f + '.rb';
5
+ end
6
+
@@ -0,0 +1,67 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "TaskMapper::Provider::Pivotal::Comment" do
4
+ before(:all) do
5
+ headers = {'X-TrackerToken' => '000000'}
6
+ wheaders = headers.merge('Content-Type' => 'application/xml')
7
+ ActiveResource::HttpMock.respond_to do |mock|
8
+ mock.get '/services/v3/projects/93790.xml', headers, fixture_for('projects/93790'), 200
9
+ mock.get '/services/v3/projects/93790/stories.xml', headers, fixture_for('stories'), 200
10
+ mock.get '/services/v3/projects/93790/stories.xml?filter=', headers, fixture_for('stories'), 200
11
+ mock.get '/services/v3/projects/93790/stories/4056827.xml', headers, fixture_for('stories/4056827'), 200
12
+ mock.get '/services/v3/projects/93790/stories/4056827/notes.xml', headers, fixture_for('notes'), 200
13
+ mock.get '/services/v3/projects/93790/stories/4056827/notes/1946635.xml', headers, fixture_for('notes/1946635'), 200
14
+ mock.post '/services/v3/projects/93790/stories/4056827/notes.xml', wheaders, fixture_for('notes/1946635'), 200
15
+ mock.put '/services/v3/projects/93790/stories/4056827.xml', wheaders, '', 200
16
+ end
17
+ @project_id = 93790
18
+ @ticket_id = 4056827
19
+ @comment_id = 1946635
20
+ end
21
+
22
+ before(:each) do
23
+ @taskmapper = TaskMapper.new(:pivotal, :token => '000000')
24
+ @project = @taskmapper.project(@project_id)
25
+ @ticket = @project.ticket(4056827)
26
+ @klass = TaskMapper::Provider::Pivotal::Comment
27
+ end
28
+
29
+ it "should be able to load all comments" do
30
+ @comments = @ticket.comments
31
+ @comments.should be_an_instance_of(Array)
32
+ @comments.first.should be_an_instance_of(@klass)
33
+ end
34
+
35
+ it "should be able to load all comments based on 'id's" do
36
+ @comments = @ticket.comments([@comment_id])
37
+ @comments.should be_an_instance_of(Array)
38
+ @comments.first.should be_an_instance_of(@klass)
39
+ @comments.first.id.should == @comment_id
40
+ end
41
+
42
+ it "should be able to load all comments based on attributes" do
43
+ @comments = @ticket.comments(:id => @comment_id)
44
+ @comments.should be_an_instance_of(Array)
45
+ @comments.first.should be_an_instance_of(@klass)
46
+ end
47
+
48
+ it "should be able to load a comment based on id" do
49
+ @comment = @ticket.comment(@comment_id)
50
+ @comment.should be_an_instance_of(@klass)
51
+ @comment.id.should == @comment_id
52
+ end
53
+
54
+ it "should be able to load a comment based on attributes" do
55
+ @comment = @ticket.comment(:id => @comment_id)
56
+ @comment.should be_an_instance_of(@klass)
57
+ end
58
+
59
+ it "should return the class" do
60
+ @ticket.comment.should == @klass
61
+ end
62
+
63
+ it "should be able to create a comment" do # which as mentioned before is technically a ticket update
64
+ @comment = @ticket.comment!(:body => 'hello there boys and girls')
65
+ @comment.should be_an_instance_of(@klass)
66
+ end
67
+ end
@@ -0,0 +1,39 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <activities type="array">
3
+ <activity>
4
+ <id type="integer">86811411</id>
5
+ <version type="integer">3</version>
6
+ <event_type>story_create</event_type>
7
+ <occurred_at type="datetime">2011/06/09 23:29:12 UTC</occurred_at>
8
+ <author>Clutch Test</author>
9
+ <project_id type="integer">136096</project_id>
10
+ <description>Clutch Test added &quot;Let's see with another story&quot;</description>
11
+ <stories type="array">
12
+ <story>
13
+ <id type="integer">14398445</id>
14
+ <url>http://www.pivotaltracker.com/services/v3/projects/136096/stories/14398445</url>
15
+ <name>Let's see with another story</name>
16
+ <story_type>feature</story_type>
17
+ <current_state>unscheduled</current_state>
18
+ </story>
19
+ </stories>
20
+ </activity>
21
+ <activity>
22
+ <id type="integer">86747595</id>
23
+ <version type="integer">2</version>
24
+ <event_type>story_create</event_type>
25
+ <occurred_at type="datetime">2011/06/09 20:06:46 UTC</occurred_at>
26
+ <author>Clutch Test</author>
27
+ <project_id type="integer">136096</project_id>
28
+ <description>Clutch Test added &quot;Hello, This is clutch&quot;</description>
29
+ <stories type="array">
30
+ <story>
31
+ <id type="integer">14389955</id>
32
+ <url>http://www.pivotaltracker.com/services/v3/projects/136096/stories/14389955</url>
33
+ <name>Hello, This is clutch</name>
34
+ <story_type>feature</story_type>
35
+ <current_state>unscheduled</current_state>
36
+ </story>
37
+ </stories>
38
+ </activity>
39
+ </activities>
@@ -0,0 +1,7 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <note>
3
+ <id type="integer">1946635</id>
4
+ <text>note</text>
5
+ <author>Hong Quach</author>
6
+ <noted_at type="datetime">2010/07/03 08:09:38 UTC</noted_at>
7
+ </note>
@@ -0,0 +1,15 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <notes type="array">
3
+ <note>
4
+ <id type="integer">1946635</id>
5
+ <text>note</text>
6
+ <author>Hong Quach</author>
7
+ <noted_at type="datetime">2010/07/03 08:09:38 UTC</noted_at>
8
+ </note>
9
+ <note>
10
+ <id type="integer">1946719</id>
11
+ <text>etuhanoeth naou</text>
12
+ <author>Hong Quach</author>
13
+ <noted_at type="datetime">2010/07/03 09:57:03 UTC</noted_at>
14
+ </note>
15
+ </notes>