<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array">
    <added>
      <filename>spec/fixtures/position_feed_for_9_GOOG.xml</filename>
    </added>
    <added>
      <filename>spec/fixtures/transaction_feed_for_GOOG_1.xml</filename>
    </added>
  </added>
  <modified type="array">
    <modified>
      <diff>@@ -9,5 +9,5 @@ class Fixnum
   
   def transaction_id
     self.to_s.transaction_id
-  end
+  end    
 end</diff>
      <filename>lib/extensions/fixnum.rb</filename>
    </modified>
    <modified>
      <diff>@@ -20,6 +20,16 @@ class String
     Float self rescue false
   end
   
+  def portfolio_feed_id
+    self[self.rindex('/')+1..-1]
+  end
+  
+  def position_feed_id
+   portfolio = self[self.rindex('portfolios/')+11..index('/positions')-1]
+   position = self[rindex('/')+1..-1]
+   &quot;#{portfolio}/#{position}&quot;
+  end  
+  
   def portfolio_id
     if self[@@transaction_re_in] || self[@@position_re_in] || self[@@portfolio_re_in]
       self[@@portfolio_re]
@@ -28,8 +38,10 @@ class String
     end
   end
   
-  def position_id      
-    if self[@@position_re_in] 
+  def position_id
+    if self[@@portfolio_re_in] 
+      &quot;&quot;
+    elsif self[@@position_re_in] 
       self[self.index('/')+1..-1]  
     elsif self[@@transaction_re_in]
       self[self.index('/')+1..self.rindex('/')-1] 
@@ -39,7 +51,9 @@ class String
   end
   
   def transaction_id
-    if self[@@transaction_re_in]
+    if self[@@position_re_in] 
+      &quot;&quot;
+    elsif self[@@transaction_re_in]
       self[self.rindex('/')+1..-1] 
     else
       raise TransactionParseError</diff>
      <filename>lib/extensions/string.rb</filename>
    </modified>
    <modified>
      <diff>@@ -2,18 +2,31 @@ module GMoney
   class Portfolio 
     class PortfolioRequestError &lt; StandardError;end
   
-    attr_accessor :title, :currency_code, :positions
+    attr_accessor :title, :currency_code
                   
     attr_reader :id, :feed_link, :updated, :gain_percentage, :return1w, :return4w, :return3m, 
                 :return_ytd, :return1y, :return3y, :return5y, :return_overall, 
                 :cost_basis, :days_gain, :gain, :market_value
+     
+    def self.all(options = {})
+      retreive_portfolios(:all, options)
+    end
     
-    def initialize()    
-      @positions = []
+    def self.find(id, options = {})
+      retreive_portfolios(id, options)
     end
     
-    def self.all(options = {})
-      url = &quot;#{GF_FEED_URL}/portfolios&quot;
+    def positions(options = {})
+      if options[:refresh]
+        @positions = Position.find(@id.portfolio_feed_id, options)
+      else
+        @positions ||= Position.find(@id.portfolio_feed_id, options)
+      end
+    end
+       
+    def self.retreive_portfolios(id, options = {})
+      url = GF_PORTFOLIO_FEED_URL
+      url += &quot;/#{id}&quot; if id != :all
       url += &quot;?returns=true&quot; if options[:with_returns]
       portfolios = []
       
@@ -22,13 +35,16 @@ module GMoney
       if response.status_code == HTTPOK
         portfolios = PortfolioFeedParser.parse_portfolio_feed(response.body)
       else
-        raise PortfolioRequestError
+        raise PortfolioRequestError, response.body
       end
 
-      portfolios.each do |portfolio|
-        portfolio.positions = Position.find_by_url(portfolio.feed_link, {:with_returns =&gt; options[:with_returns]})
-      end      
-      portfolios  
-    end
+      portfolios.each { |p| p.instance_variable_set(&quot;@positions&quot;, p.positions(options))} if options[:eager]
+      
+      return portfolios[0] if portfolios.size == 1
+      
+      portfolios        
+    end        
+    
+    private_class_method :retreive_portfolios         
   end
 end</diff>
      <filename>lib/gmoney/portfolio.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,15 +1,21 @@
 module GMoney
   class Position
     class PositionRequestError &lt; StandardError; end
-    attr_accessor :transactions
-
     attr_reader :id, :updated, :title, :feed_link, :exchange, :symbol, :shares, 
                 :full_name, :gain_percentage, :return1w, :return4w, :return3m, 
                 :return_ytd, :return1y, :return3y, :return5y, :return_overall, 
                 :cost_basis, :days_gain, :gain, :market_value
     
-    def initialize
-      @transactions = []
+    def self.find(id, options={})   
+      find_by_url(&quot;#{GF_PORTFOLIO_FEED_URL}/#{id.portfolio_id}/positions/#{id.position_id}&quot;, options)    
+    end
+    
+    def transactions(options={})
+      if options[:refresh]
+        @transactions = Transaction.find(@id.position_feed_id, options)
+      else
+        @transactions ||= Transaction.find(@id.position_feed_id, options)
+      end            
     end
     
     def self.find_by_url(url, options = {})
@@ -24,10 +30,13 @@ module GMoney
         raise PositionRequestError, response.body
       end
 
-      positions.each do |position|
-        position.transactions = Transaction.find_by_url(position.feed_link)
-      end      
-      positions
+      positions.each { |p| p.instance_variable_set(&quot;@transactions&quot;, p.transactions(options))} if options[:eager]
+      
+      return positions[0] if positions.size == 1
+      
+      positions              
     end 
+    
+    private_class_method :find_by_url
   end
 end</diff>
      <filename>lib/gmoney/position.rb</filename>
    </modified>
    <modified>
      <diff>@@ -6,16 +6,26 @@ module GMoney
 
     attr_accessor :type, :date, :shares, :notes, :commission, :price
     
-    def self.find_by_url(url)
+    def self.find(id, options={})   
+      find_by_url(&quot;#{GF_PORTFOLIO_FEED_URL}/#{id.portfolio_id}/positions/#{id.position_id}/transactions/#{id.transaction_id}&quot;, options)    
+    end    
+    
+    def self.find_by_url(url, options={})
       transactions = []
       
       response = GFService.send_request(GFRequest.new(url, :headers =&gt; {&quot;Authorization&quot; =&gt; &quot;GoogleLogin auth=#{GFSession.auth_token}&quot;}))
       
       if response.status_code == HTTPOK
-        TransactionFeedParser.parse_transaction_feed(response.body)
+        transactions = TransactionFeedParser.parse_transaction_feed(response.body)
       else
         raise TransactionRequestError, response.body
       end
-    end     
+      
+      return transactions[0] if transactions.size == 1
+      
+      transactions
+    end
+    
+    private_class_method :find_by_url
   end
 end</diff>
      <filename>lib/gmoney/transaction.rb</filename>
    </modified>
    <modified>
      <diff>@@ -17,7 +17,7 @@ describe GMoney::Portfolio do
     @gf_response = GMoney::GFResponse.new
     @gf_response.status_code = 200
     @gf_response.body = @default_feed
-    @positions = []
+    @positions = nil
   end 
 
   it &quot;should return all Portfolios when status_code is 200&quot; do   
@@ -31,66 +31,83 @@ describe GMoney::Portfolio do
     @url = 'https://finance.google.com/finance/feeds/default/portfolios?returns=true'
     @gf_response.body = @feed_with_returns
 
-    portfolios = portfolio_helper(@url, {:with_returns =&gt; true})
+    portfolios = portfolio_helper(@url, :all, {:with_returns =&gt; true})
     
     portfolios.size.should be_eql(3)
     portfolios[0].cost_basis.should be_eql(2500.00)
     portfolios[0].gain_percentage.should be_eql(28.3636)
     portfolios[0].return4w.should be_eql(-0.1670616114)
-
     portfolios[2].cost_basis.should be_nil
   end
   
   it &quot;should raise an error if the portfolio request does not return an OK status code&quot; do
-    @gf_response.status_code = 404
-  
+    @gf_response.status_code = 401  
     lambda { portfolio_helper(@url) }.should raise_error(GMoney::Portfolio::PortfolioRequestError)
   end
   
-  it &quot;should return an Array with only the default 'My Portfolio' portfolio when a user does not define his own portfolios&quot; do
+  it &quot;should raise an error with an error message when the user requests an invalid portfolio&quot; do
+    @url += '/235234'
+    @gf_response.status_code = 404
+    @gf_response.body = &quot;No portfolio exists with pid 235234&quot;
+
+    lambda { portfolio_helper(@url, 235234) }.should raise_error(GMoney::Portfolio::PortfolioRequestError, @gf_response.body)
+  end  
+  
+  it &quot;should return the default 'My Portfolio' portfolio when a user has not defined his own portfolios&quot; do
     @gf_response.body = @empty_feed
-    portfolios = portfolio_helper(@url)
-    
-    portfolios.size.should be_eql(1)  
-    portfolios[0].title.should be_eql('My Portfolio')
+    portfolio = portfolio_helper(@url)    
+    portfolio.title.should be_eql('My Portfolio')
   end
 
-=begin TODO - create a method that retreives individual portfolios
-  it &quot;should return a specific portfolio is the request a specific portfolio&quot; do
+  it &quot;should return a specific portfolio if the user requests a specific portfolio&quot; do
     @url += '/9'
     @gf_request.url = @url
     
     @gf_response.body = @portfolio_9_feed
-    portfolios = portfolio_helper(@url)
+    portfolio = portfolio_helper(@url, 9)    
+    portfolio.title.should be_eql('GMoney Test')  
+  end
+  
+  it &quot;should grab the latest positions when :refresh is used.&quot; do
+    @url += '/9'
+    @gf_request.url = @url
+    @positions = [GMoney::Position.new, GMoney::Position.new]
+    
+    @gf_response.body = @portfolio_9_feed
+    portfolio = portfolio_helper(@url, 9)
+
+    GMoney::Position.should_receive(:find).with(&quot;9&quot;, {:refresh =&gt; true}).and_return(@positions)
     
-    portfolios.size.should be_eql(1)  
-    portfolios[0].title.should be_eql('GMoney Test')  
+    portfolio.positions(:refresh =&gt; true).size.should be_eql(2)
   end
-=end
+  
+  it &quot;should use the cached portfolios when :refresh is not used (and the portfolios have already been set)&quot; do
+    @url += '/9'
+    @gf_request.url = @url
+    @positions = [GMoney::Position.new, GMoney::Position.new]
+    
+    @gf_response.body = @portfolio_9_feed
+    portfolio = portfolio_helper(@url, 9, :eager =&gt; true)
+    
+    GMoney::Position.should_not_receive(:find).with(9, :eager =&gt; true)
+    portfolio.positions.size.should be_eql(2)
+  end  
+  
 
-  def portfolio_helper(url, options = {})
+  def portfolio_helper(url, id = nil, options = {})
     GMoney::GFSession.should_receive(:auth_token).and_return('toke')
 
     GMoney::GFRequest.should_receive(:new).with(url, :headers =&gt; {&quot;Authorization&quot; =&gt; &quot;GoogleLogin auth=toke&quot;}).and_return(@gf_request)
 
     GMoney::GFService.should_receive(:send_request).with(@gf_request).and_return(@gf_response)
     
-    position_urls = get_position_urls(@gf_response.body)
-    
-    position_urls.each do |position_url|
-      GMoney::Position.should_receive(:find_by_url).with(position_url, {:with_returns =&gt; options[:with_returns]}).any_number_of_times.and_return(@positions)        
+    if options[:eager]
+      feed_ids = get_feed_ids(@gf_response.body)   
+      feed_ids.each do |feed_id|
+        GMoney::Position.should_receive(:find).with(feed_id.portfolio_feed_id, options).any_number_of_times.and_return(@positions)        
+      end
     end
       
-    GMoney::Portfolio.all(options)
-  end
-  
-  def get_position_urls(feed)
-    doc = REXML::Document.new(feed)
-    feed_links = []     
-
-    doc.elements.each('feed/entry') do |parsed_entry|
-      feed_links &lt;&lt; parsed_entry.elements['gd:feedLink'].attributes['href']
-    end
-    feed_links
+    portfolios = id ? GMoney::Portfolio.find(id, options) : GMoney::Portfolio.all(options)
   end
 end</diff>
      <filename>spec/portfolio_spec.rb</filename>
    </modified>
    <modified>
      <diff>@@ -5,12 +5,13 @@ describe GMoney::Position do
     @default_feed = File.read('spec/fixtures/positions_feed_for_portfolio_9.xml')
     @feed_with_returns = File.read('spec/fixtures/positions_feed_for_portfolio_9r.xml')
     @empty_feed = File.read('spec/fixtures/positions_feed_for_portfolio_14.xml')
+    @feed_for_port9_goog = File.read('spec/fixtures/position_feed_for_9_GOOG.xml')
   end
   
   before(:each) do
-    @url = 'https://finance.google.com/finance/feeds/default/portfolios/9/positions'
+    @portfolio_id = '9'
   
-    @gf_request = GMoney::GFRequest.new(@url)
+    @gf_request = GMoney::GFRequest.new(@portfolio_id)
     @gf_request.method = :get   
     
     @gf_response = GMoney::GFResponse.new
@@ -21,7 +22,7 @@ describe GMoney::Position do
 
   it &quot;should return all Positions when status_code is 200&quot; do   
     @gf_response.body = @default_feed
-    positions = position_helper(@url)
+    positions = position_helper(@portfolio_id)
     
     positions.size.should be_eql(5)
   end
@@ -29,7 +30,7 @@ describe GMoney::Position do
   it &quot;should return a position with returns data is :with_returns == true&quot; do
     @gf_response.body = @feed_with_returns
 
-    positions = position_helper(@url, {:with_returns =&gt; true})
+    positions = position_helper(@portfolio_id, {:with_returns =&gt; true})
     
     positions.size.should be_eql(5)
     positions[0].cost_basis.should be_eql(615.00)
@@ -40,41 +41,69 @@ describe GMoney::Position do
   end
   
   it &quot;should raise an error if the position request does not return an OK status code&quot; do
-    @gf_response.status_code = 404
-  
-    lambda { position_helper(@url) }.should raise_error(GMoney::Position::PositionRequestError)
+    @gf_response.status_code = 404  
+    lambda { position_helper(@portfolio_id) }.should raise_error(GMoney::Position::PositionRequestError)
   end
 
-=begin TODO - create a method that retreives individual positions
-  it &quot;should return a specific position is the request a specific position&quot; do
+  it &quot;should return a specific position if the user requests a specific position&quot; do
+    @portfolio_id = '9/NASDAG:GOOG'
+    @gf_response.body = @feed_for_port9_goog
+    
+    position = position_helper(@portfolio_id)
+
+    position.cost_basis.should be_eql(136300.25)
+    position.return1w.should be_eql(0.002075448663)
   end
-=end
+  
+  
+  it &quot;should raise an error message when a user request an invalid Position&quot; do
+    @portfolio_id = '9/NASDAG:ASDF'
+    @gf_response.status_code = 404
+    @gf_response.body = &quot;No position exists with ticker NASDAQ:ASDF&quot;
 
-  def position_helper(url, options = {})
+    lambda { position_helper(@portfolio_id)}.should raise_error(GMoney::Position::PositionRequestError, @gf_response.body)
+  end
+  
+  it &quot;should grab the latest transactions when :refresh is used&quot; do 
+    @position_id = '9/NASDAG:GOOG'
+    @transactions = [GMoney::Transaction.new, GMoney::Transaction.new, GMoney::Transaction.new]
+    
+    @gf_response.body = @feed_for_port9_goog
+    position = position_helper(@position_id, :refresh =&gt; true)
+          
+    GMoney::Transaction.should_receive(:find).with(position.id.position_feed_id, {:refresh =&gt; true}).and_return(@transactions)
+    
+    position.transactions(:refresh =&gt; true).size.should be_eql(3)
+  end
+  
+  it &quot;should grab cached transactions when :refresh is not used&quot; do 
+    @position_id = '9/NASDAG:GOOG'
+    @transactions = [GMoney::Transaction.new, GMoney::Transaction.new, GMoney::Transaction.new]
+    
+    @gf_response.body = @feed_for_port9_goog
+    position = position_helper(@position_id, :eager =&gt; true)
+          
+    GMoney::Transaction.should_not_receive(:find).with(position.id.position_feed_id, {:eager =&gt; true})
+    position.transactions(:eager =&gt; true).size.should be_eql(3)
+  end
+  
+  def position_helper(id, options = {})
     GMoney::GFSession.should_receive(:auth_token).and_return('toke')
 
+    url = &quot;#{GMoney::GF_PORTFOLIO_FEED_URL}/#{id.portfolio_id}/positions/#{id.position_id}&quot;
     send_url = options[:with_returns] ? (url + '?returns=true') : url
 
     GMoney::GFRequest.should_receive(:new).with(send_url, :headers =&gt; {&quot;Authorization&quot; =&gt; &quot;GoogleLogin auth=toke&quot;}).and_return(@gf_request)
 
     GMoney::GFService.should_receive(:send_request).with(@gf_request).and_return(@gf_response)
     
-    transaction_urls = get_transaction_urls(@gf_response.body)
-    
-    transaction_urls.each do |transaction_url|
-      GMoney::Transaction.should_receive(:find_by_url).with(transaction_url).any_number_of_times.and_return(@transactions)
-    end
+    if options[:eager]
+      feed_ids = get_feed_ids(@gf_response.body)   
+      feed_ids.each do |feed_id|
+        GMoney::Transaction.should_receive(:find).with(feed_id.position_feed_id, options).any_number_of_times.and_return(@transactions)        
+      end
+    end    
       
-    GMoney::Position.find_by_url(url, options)
-  end
-  
-  def get_transaction_urls(feed)
-    doc = REXML::Document.new(feed)
-    feed_links = []     
-
-    doc.elements.each('feed/entry') do |parsed_entry|
-      feed_links &lt;&lt; parsed_entry.elements['gd:feedLink'].attributes['href']
-    end
-    feed_links
+    GMoney::Position.find(id, options)
   end
 end</diff>
      <filename>spec/position_spec.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1 +1,11 @@
 require File.dirname(__FILE__) + '/../lib/gmoney'
+
+def get_feed_ids(feed)
+  doc = REXML::Document.new(feed)
+  feed_ids = []     
+
+  doc.elements.each('//entry') do |parsed_entry|
+    feed_ids &lt;&lt; parsed_entry.elements['id'].text
+  end
+  feed_ids
+end</diff>
      <filename>spec/spec_helper.rb</filename>
    </modified>
    <modified>
      <diff>@@ -38,6 +38,14 @@ describe String do
     '.'.is_numeric?.should be_false               
   end
   
+  it &quot;should be able to parse a portfolio id from an portfolio feed url&quot; do
+    &quot;http://finance.google.com/finance/feeds/user@example.com/portfolios/9&quot;.portfolio_feed_id.should be_eql(&quot;9&quot;)
+  end
+  
+  it &quot;should be able to parse a position id from an position feed feed url&quot; do
+    &quot;http://finance.google.com/finance/feeds/user@example.com/portfolios/9/positions/NASDAG:GOOG&quot;.position_feed_id.should be_eql(&quot;9/NASDAG:GOOG&quot;)
+  end  
+  
   it &quot;should be able to parse a portfolio id out of a string&quot; do
     1.portfolio_id.should be_eql(&quot;1&quot;)
     &quot;1&quot;.portfolio_id.should be_eql(&quot;1&quot;)
@@ -50,8 +58,8 @@ describe String do
   end
   
   it &quot;should be able to parse a position id out of a string&quot; do
-    lambda { 1.position_id }.should raise_error(String::PositionParseError)
-    lambda { &quot;1&quot;.position_id }.should raise_error(String::PositionParseError)
+    1.position_id.should be_eql(&quot;&quot;)
+    &quot;1&quot;.position_id.should be_eql(&quot;&quot;)
     lambda { &quot;asdf&quot;.position_id }.should raise_error(String::PositionParseError)
     lambda {&quot;123/NASDAQ:GOOG/2134/23&quot;.position_id}.should raise_error(String::PositionParseError)
     &quot;1/NASDAQ:GOOG&quot;.position_id.should be_eql(&quot;NASDAQ:GOOG&quot;)
@@ -63,7 +71,7 @@ describe String do
     lambda { 1.transaction_id }.should raise_error(String::TransactionParseError)
     lambda { &quot;1&quot;.transaction_id }.should raise_error(String::TransactionParseError)
     lambda { &quot;asdf&quot;.transaction_id }.should raise_error(String::TransactionParseError)
-    lambda {&quot;1/NASDAQ:GOOG&quot;.transaction_id}.should raise_error(String::TransactionParseError)
+    &quot;1/NASDAQ:GOOG&quot;.transaction_id.should be_eql(&quot;&quot;)
     lambda {&quot;123/NASDAQ:GOOG/asdf&quot;.transaction_id}.should raise_error(String::TransactionParseError)
     lambda {&quot;123/NASDAQ:GOOG/2134/23&quot;.transaction_id}.should raise_error(String::TransactionParseError)
     &quot;123/NASDAQ:GOOG/23&quot;.transaction_id.should be_eql(&quot;23&quot;)</diff>
      <filename>spec/string_spec.rb</filename>
    </modified>
    <modified>
      <diff>@@ -3,10 +3,12 @@ require File.join(File.dirname(__FILE__), '/spec_helper')
 describe GMoney::Transaction do
   before(:all) do
     @goog_feed = File.read('spec/fixtures/transactions_feed_for_GOOG.xml')
+    @goog_feed_1 = File.read('spec/fixtures/transaction_feed_for_GOOG_1.xml')
   end
   
   before(:each) do
     @url = 'https://finance.google.com/finance/feeds/default/portfolios/9/positions/NASDAQ:GOOG/transactions' 
+    @transaction_id = '9/NASDAQ:GOOG'
     
     @gf_request = GMoney::GFRequest.new(@url)
     @gf_request.method = :get   
@@ -17,7 +19,7 @@ describe GMoney::Transaction do
   end
   
   it &quot;should return all Tranasactions when the status code is 200&quot; do
-    transactions = transaction_helper(@url)
+    transactions = transaction_helper(@transaction_id)
   
     transactions.size.should be_eql(4)
     transactions[1].commission.should be_eql(12.75)
@@ -25,22 +27,31 @@ describe GMoney::Transaction do
   end
   
   it &quot;should raise an error when the status code is not 200&quot; do
+    @transaction_id += '/1'
     @gf_response.status_code = 404
+    @gf_response.body = &quot;No transaction exists with tid 1&quot;
   
-    lambda { transaction_helper(@url) }.should raise_error(GMoney::Transaction::TransactionRequestError)  
+    lambda { transaction_helper(@transaction_id) }.should raise_error(GMoney::Transaction::TransactionRequestError, @gf_response.body)  
   end
 
-=begin TODO - create a method that retreives individual transactions
-  it &quot;should return a specific transactions is the request a specific transactions&quot; do
-=end    
+  it &quot;should return a specific transactions if the user request a specific transaction&quot; do
+    @transaction_id += '/2'
+    @gf_response.body = @goog_feed_1
+    transaction = transaction_helper(@transaction_id)
   
-  def transaction_helper(url)
+    transaction.commission.should be_eql(50.0)
+    transaction.price.should be_eql(400.0)
+  end    
+  
+  def transaction_helper(id, options={})
     GMoney::GFSession.should_receive(:auth_token).and_return('toke')
 
+    url = &quot;#{GMoney::GF_PORTFOLIO_FEED_URL}/#{id.portfolio_id}/positions/#{id.position_id}/transactions/#{id.transaction_id}&quot;
+
     GMoney::GFRequest.should_receive(:new).with(url, :headers =&gt; {&quot;Authorization&quot; =&gt; &quot;GoogleLogin auth=toke&quot;}).and_return(@gf_request)
 
     GMoney::GFService.should_receive(:send_request).with(@gf_request).and_return(@gf_response)
     
-    GMoney::Transaction.find_by_url(url)
+    GMoney::Transaction.find(id, options)
   end
 end</diff>
      <filename>spec/transaction_spec.rb</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>63a6f1b1c83c30ac13d83ccab6a9ef31a9cec171</id>
    </parent>
  </parents>
  <author>
    <name>jspradlin</name>
    <email>jspradlin@gmail.com</email>
  </author>
  <url>http://github.com/jspradlin/gmoney/commit/9fd290ddda8e5046ea1613c6c2366c483d432ed6</url>
  <id>9fd290ddda8e5046ea1613c6c2366c483d432ed6</id>
  <committed-date>2009-09-30T20:28:28-07:00</committed-date>
  <authored-date>2009-09-30T20:28:28-07:00</authored-date>
  <message>Update the interface for accessing portfolios, positions, and transactions for consistency.</message>
  <tree>dc2051a3355ba49a724093147ab23380fac99156</tree>
  <committer>
    <name>jspradlin</name>
    <email>jspradlin@gmail.com</email>
  </committer>
</commit>
