Pivotal Labs

Main menu

Skip to primary content
Skip to secondary content
  • About
  • Case Studies
  • Team
    • Executives
    • Locations
      • San Francisco (HQ)
      • Boston
      • Boulder
      • Denver
      • London
      • Los Angeles
      • New York
  • Community
    • Blogs
    • Tech Talks
    • Events
  • Careers
    • Lifestyle
    • Principles & Practices
    • Benefits
    • FAQ
    • Apply
  • Tools
  • Contact
    • Press Room
    • Press Releases
    • In The News
    • Press Kit
  • All
  • Labs
  • Standup
  • Tracker

Monthly Archives: April 2009

Nate Clark

Standup 4/22/2009 Earth Day Edition: Rubymine 856, Object-Mother gotchas

Nate Clark
Wednesday, April 22, 2009

Interesting Things

  • Rubymine, just released a new beta revision 856. So far it “seems to work”.

  • When using Object-Mother patterns for creating objects in tests (i.e. Fixjour, FactoryGirl) one gotcha that caused one of our teams some pain was when inadvertently setting an object and object_id for the same association. For example, setting person = @nate and person_id = @david.id in the same object creation will cause really weird problems. Our team debugged and solved this by validating object creation … essentially writing tests for your test objects.

  • Try mapping SHIFT + Space to the underscore character, and save your underscore finger from unnecessary travel.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter

Managing Git Resources with Coral

Wednesday, April 22, 2009 | Run time: 50:26

Author Mislav Marohnic discusses Coral, a way to pull in and organize Git repositories that extends and partially replaces RubyGems. Although still in the early stages, Coral aims to brings sanity to maintaining your own third-party forks across projects.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Nate Clark

Standup 4/21/2009: Webrat save_and_open_page, CSS regression, Rubymine UTF8

Nate Clark
Tuesday, April 21, 2009

Interesting Things

  • Webrat, the acceptance testing framework that is all the rage right now, has a neat lesser-known save_and_open_page command that is helpful for debugging when your tests go wrong. Essentially, this command dumps the current HTML to the browser and lets you inspect the state of the page visually at any point within your test.

  • Rubymine, Pivotal’s favorite Ruby IDE, doesn’t really support UTF8. You can type UTF8 characters seemingly fine … but somewhere along the way it doesn’t save properly. Apparently this has been an issue with Rubymine for quite some time. Frustrating.

Ask for Help

  • Anyone know a reliable way of CSS regression testing? When we are refactoring CSS or markup, it would be great if there was an automated way to detect visual breakages. Some ideas floating around involve taking screenshots through Webkit’s API and comparing them pixel by pixel. This kind of thing has been attempted twice by Pivots without much success. Anybody have a good solution?
  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Nate Clark

Standup 4/20/2009: GoGaRuCo, Refactoring patches to Rails, Shared disk on EY

Nate Clark
Monday, April 20, 2009

Interesting Things

  • Many thanks to Pivot Josh Susser for his hard work co-coordinating this past weekend’s Golden Gate Ruby Conference. We also want to thank our Live Blogging team: Chad, Ryan, Zach, and David — who all did an excellent job of documenting the event. We also recorded videos of every talk, which will be posted to Talks within a week or so.

  • Something to be aware of if you are running your production app on EngineYard: Because of their shared disk setup, running disk intensive jobs on your staging environment may affect the performance of your production environment on the same slice. One of our teams ran into severe slowness on production due to tasks running on staging. This problem isn’t immediately apparent because of the way the EY storage system is well abstracted for each environment. Submit a ticket to EY support for more details if this is a problem for you.

Ask for Help

  • Adam Milligan submitted a patch to Rails a while ago that refactored the implementation of HasOneThroughAssociation. To his severe disappointment, the patch was rejected because the Rails core “doesn’t apply refactorings.” Adam is asking for help from Pivots and friends to add their comments and support to the patch so hopefully it will be applied to the upcoming Rails 3.0.
  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Chad Woolley

GoGaRuCo '09 – Relational Modeling Framework – Nathan Sobo

Chad Woolley
Sunday, April 19, 2009

Relational Modeling Framework – Nathan Sobo

Intro

GoGaRuCo '09 - Relational Modeling Framework - Nathan Sobo

Video of interaction model that drove thinking

Grockit – it is all common – pushing events collaboratively. This is harder than asynchronous model.

Client needs to respond to to the server in an asynchrounous manner.

All rendering occurs in the browser modifying the DOM as needed.

How do you model this? With a relational model. They build a relational model in the browser.

It is good because you don’t need pointers, you just use foreign keys and scalar values. Really flat, really easy to serialize and move across the wire.

However, it is difficult to work with. Things are indexed by id, etc.

Demo

Lots of live coding. See the video (up soon) at GoGaRuCo.com

New project is “June” – based on Unison, but Unison is being deprecated.

The most primitive object in June is the set

System for working things in the browser.

It behaves as you would expect any relational model. Support add/remove etc.
Example has User, Pet, and Species. Updating Tuples. Testing with Screwunit

Can have events on sets (i.e. on_insert, on_remove, on_update )

GoGaRuCo '09 - Relational Modeling Framework - Nathan Sobo

Events have other stateful information passed through a hash in changed attributes for each event.

on_update(function(model, changed_attributes) {
  if (changed_attributes.name) {
    print(changed_attributes.name.old_value + " was renamed to " + changed_attibutes.name.new_vaue );
  }
});

Also has join model:

var stephs_species = stephs_pets.join(Species).on(Pet.species_id.eq(Species.id)).project(Species);

Also has has_many, and others will be implemented too.

Nathan can live code very well. He is writing a lot of really cool code and talking about it at the same time. Like this:

relates_to_many("pet_species", function() {
  return this.pets_relation
    .join(Species).on(Pet.species_id.eq(Species.id))
    .project(Species);
});

Can also remotely access the entire server-side database (don’t worry, there will be a security model):

var remote = June.remote("/domain");

However, you can’t pull the whole database down to the browser. So, you can get a subset of the data that the client requests.

Security: Only give the browser access to things the user is authorized to see. Every Tuple acts as it’s own database.

Objects that have specific permissions only receive tuples and events that pertain to them.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Chad Woolley

GoGaRuCo '09 – Arduino is Rails for hardware hacking – Greg Borenstein

Chad Woolley
Sunday, April 19, 2009

Arduino is Rails for hardware hacking – Greg Borenstein

Intro

Greg Borenstein

GoGaRuCo '09 - Arduino is Rails for hardware hacking - Greg Borenstein

Obligatory safety talk

Electrical engineering is for experts!

Physical computing is for everyone!

  • Artists!
  • Idealists – Fab labs in India
  • Hackers – Cockroach driven robot. Cockroach runs, spins ball, drives robot

Physical computing is programming for stuff
read inputs from your surroundings and modify them based on logic

[Arduino](http://www.arduino.cc/)

Open source hardware and software project that makes physical computing really easy

arduino

  • Program via USB
  • power via 9v
  • 14 digital i/o pins
  • AVR microcontroller
  • 6 analog i/o pins

Most of the API is for sensing and controlling the physical world.

HELLO WORLD – make an LED blink on and off

class HelloWorld < ArduinoSketch
  output_pin 13, :as => led

  def loop
    led.blink(500)
  end
end

GoGaRuCo '09 - Arduino is Rails for hardware hacking - Greg Borenstein

RAD is Ruby Arduino Development

In a hardware demo, everyone is required to go “Oooooooooooh” (even if it doesn’t work)

rad command generates a project directories

You can buy an Arduino board for ~$30 from Make
or a Dorkboard for ~$6

Bell rings as a post commit-hook for git

.git/hooks/post-commit
require ‘bell.rb’
Bell.ring
exit 0

Demo Reason + Archeopteryx playing a drum

GoGaRuCo '09 - Arduino is Rails for hardware hacking - Greg Borenstein

  • Play midi via Reason
  • Playing same midi through arduino, a motor, a drumstick and a snare drum

Archeopteryx: code describes patterns with channels, and randomness.

Reason sends midi to Tascam midi device, Tascam sends to Arduino, which turns solenoid attached to drumstick.

Physical computing is for everyone, if you’ve ever wanted to make your code interact with the world, now you can.

Q: Can you use this to play rockband?
A: Yes. You can use a photoresistor to detect notes coming across the line.

Q: Are there latency problems with midi playback?
A: The clockspeed of the arduino is fast enough to keep up with the playback.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Chad Woolley

GoGaRuCo '09 – Raffles!

Chad Woolley
Sunday, April 19, 2009

Lots of nice prizes. Some people weren’t there. They lost!

GoGaRuCo '09 - Raffles

Zach won an iPhone!

GoGaRuCo '09 - Raffles

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Pivotal Labs

GoGaRuCo '09 – Lightning Talks

Pivotal Labs
Sunday, April 19, 2009

Lightning Talks

Bosco is introducing the speakers. Come to the ruby meetup!

Jeff Smick – Blather

GoGaRuCo '09 - Lightning Talks - Jeff Smick - Blather

  • Simpler XMPP
  • Make XMPP4R easier
  • Requires libxml-ruby and EventMachine
  • simple DSL
    -Handlers for ready, error, message, presence, iq
  • Guards route stanzas
    • Guards can be symbols, hashes with string, hashes with regexs, lambdas or arrays
  • PubSub is in the works and coming next

Tim Connor – Rack Middleware build, init call cycle

GoGaRuCo '09 - Lightning Talks - Tim Connor - Rack Middleware build, init call cycle

  • based on the sinatra flash plugin
  • Wanted to remove sinatra from it
  • Found that every time you say “use” you are creating a lambda which will create an app reference
  • You can check out his Rack::Flash

Wolfram Arnold – What’s Cool about cache money?

GoGaRuCo '09 - Lightning Talks - Wolfram Arnold - What's Cool about cache money?

  • Nick Kallen wrote the original Cache Money
  • Backed by Memcached
  • Abstracts away the caching between the code and the database so you don’t have to worry about it.
  • Can just do User.find instead of User.get_cache
  • named scope, has_many, etc will all work transparently
  • Can almost use it as a drop in to add caching
  • Cache Money doesn’t support joins but check out acts_as_most_popular

Yehuda Katz – Moneta

GoGaRuCo '09 - Lightning Talks - Yehuda Katz - Moneta

  • Moneta is allows you to create objects that behave like hashes backed by any format you want
  • Behaves just like a ruby hash
  • Has adapters for BerkeleyDB, Datamapper, Memcached, S3, xattr, rufus and more
  • Easy to write new adapters

Andy Delcambre – Datamapper Adapters

GoGaRuCo '09 - Lightning Talks - Andy Delcambre - Datamapper Adapters

  • Making it easier to write datamapper adapters
  • Wrote an adapter for github repos today
  • Demonstrating pulling down Github repos and searching with datamapper syntax

Brief interlude trying to figure out why the projector was not working

GoGaRuCo '09 - Lightning Talks - four developers trying to debug a bad display adapter

Erik Michaels-Ober – Merb Admin App

GoGaRuCo '09 - Lightning Talks - Erik Michaels-Ober - Merb Admin App

  • like active scaffold for rails, this is for merb
  • modeled after Django site admin
    uses their css and js
    python manage.py runserver
  • introspects your model to display form elements intelligently
  • adds a generator for adding new admin
  • not up on github yet try sferik on twitter

Mislav Marohnić – RSPACTOR for continuous tests on OSX (& more!)

GoGaRuCo '09 - Mislav Marohnić - RSPACTOR for continuous tests on OSX (& more!)

  • “make it green then make it clean”
  • autotest
    • Problems
      • one big file
      • awkward growl integration
      • pitfalls when using rspec-rails plugin
      • polling – uses 25% of cpu when idling :(
  • Original RSpactor written by Andreas Wolff
    • OS X only because it uses filesystem events
    • made for Rspec + Growl integration
    • Console tool
    • but abandonded :(
  • Mislav-RSpactor
    • cleaner, more modular, default mappings for usual directory structure
    • better mappings if its a rails project
    • tested!
    • so modular you can reuse the Listener if you want to listen for mac file system events
    • uses a lot less CPU
      Possibilities

      • running related tests while you TDD
      • compile Haml/Sass for static sites
      • trigger javascript sprockets build
      • render RDoc output while you edit comments
    • it can be run for all projects in your filesyste, you just opt each project in

Bryan Helmkamp – Rack::Bug

GoGaRuCo '09 - Lightning Talks - Bryan Helmkamp - Rack::Bug

  • Rack middleware
  • inspired by Django debug toolbar
  • Modular, can be used for any rack app
  • Panels
    • rails env
    • rails response time (cpu time)
    • request vars (session cookies, rack env)
    • keeps track of SQL queries – shows backtrace on queries, explain for queries
    • count of ActiveRecord instantiations on the page using Oink
    • can look in Memcache cache
    • template traces (times for rendering)
    • aggregates all Rails log entries
    • KB delta for process size of Ruby during a single request
  • runs on production environments, password protected
  • instruments using alias_method_chain hacks
  • Working with Yehuda Katz on Orchestra to someday soon simplify it

Pat Nakajima – No more Keynote with Slidedown

GoGaRuCo '09 - Lightning Talks - Pat Nakajima - No more Keynote with Slidedown and Maker's Mark

  • Speaks at NYCrb meetup, and didn’t want to use Keynote
  • Wanted to use Markdown but also wanted syntax highlighting
  • Generates an HTML page that you can use to run your presentation
  • The Maker’s Mark library was extracted to do easy syntax highlighting in Markdown

Chris Lee – Floxee – OS Twitter Dir

GoGaRuCo '09 - Lightning Talks - Chris Lee - Floxee - OS Twitter Dir

  • open source twitter dirctory application
  • tweet congress
    • directory of tweets from members of congress
  • Floxee on Github

Max – PaMP: Privacy-aware Marketplace

GoGaRuCo '09 - Lightning Talks - Max - PaMP: Privacy-aware Marketplace

  • From IBM Almaden Research Labs
  • privacy-aware market place
  • Goals
    • to develop a platform that allows users to manage their privacy settings across social network
      -reducing the cognitive burden on a user; leveraging the wisdom of his crowd
    • Maps to opensocial, etc

Andrew Cantino – SelectorGadget

  • No time :(
  • “SelectorGadget is an open source bookmarklet that makes CSS selector generation and discovery on complicated sites a breeze.”

Kyle Maxwell – Parsley

  • No time :(
  • “Parsley is a simple to use and elegant language for creating HTML and XML parsers”
  • “Parsley can be used from Ruby, Python, C/C++, and the *nix command-line.”
  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Chad Woolley

GoGaRuCo '09 – Webrat: Rails Acceptance Testing Evolved – Bryan Helmkamp

Chad Woolley
Saturday, April 18, 2009

Webrat: Rails Acceptance Testing Evolved – Bryan Helmkamp

Intro

Bryan Helmkamp ( more about him ). He works at WePlay. He is the co-author of “The RSpec Book”

Links:

  • bit.ly/wbrt-ggrc
  • Twitter: @brynary #webrat
  • brynary.com

Audience Poll: How many people know and use webrat (50%+ using, 25% using)

Webrat is an awesome tool everyone should use, but it doesn’t run on the iPhone, not written in Scala, and there is no Pr0n.

GoGaRuCo '09 - Webrat: Rails Acceptance Testing Evolved - Bryan Helmkamp

Beer Disclaimer

If you have questions that aren’t answered, find him for a beer after the conference

API

Writing a rails integration test how we test websites, traditional methods are brittle and tedious.

Webrat code is more readable than traditionally written integration tests

It behaves like a browser:

  • “visit” method – the equivalent typing in a URL to the browser.
  • “click_link” – like clicking a link (duh)
  • “fill_in” – fills in a field
  • “assert_contain” – perform assertions

Uses nokogiri to parse the response HTML and run assertions on it.

How to use it?

#config/environment.rb
config.gem "webrat", :version => ">= 0.4.4"

#test/test_helper.rb
Webrat.configure do |config|
  config.mode = :rails
end

Webrat’s Core API

  • visit
  • click_link
  • fill_in
  • check and uncheck
  • choose
  • select
  • attach_file
  • click_button

Webrat works with RSpec, Shoulda and Cucumber
Webrat and cucumber do not have to be used together. You can use Webrat with whatever testing framework you want to use.
Webrat also works with Rails, Sinatra and Merb.

Webrat can do input matching to labels. Webrat encourages you to put good labels on your form fields.

GoGaRuCo '09 - Webrat: Rails Acceptance Testing Evolved - Bryan Helmkamp

Webrat verifies HTTP Status codes for you behind the scenes.

  • Automatically makes sure you don’t get 500 HTTP server errors.
  • Also ensures that fields exist

Verify HTML content

response.should contain("Hello, world!")
response.should have_selector("li", :class => "new", :count => 2)
response.should_not have_xpath(".//meta[@name='robots']")


response.should have_selector("#album li:nth-child(3)") do |li|
  li.should have_selector("img", :src => photo_path(@photo))
  li.should contain("Vacation Photo")
end

When things go wrong Webrat uses ”’save_and_open_page”’ and writes out the current response body and brings up the page.

Webrat Adapters

  • Rails
  • Merb
  • Sinatra
  • Selenium
  • Mechanize (can use to scrape other websites i.e. google)

Evil plot is to write adapters so he can test everything at once.

Selenium

Webrat started as an alternative to selenium, but it now includes a selenium adapter. Bryan suggests not using selenium whenever possible. You should start with the traditional webrat mode and not the selenium mode. Unfortunately, it’s the only way to test a real browser, such as javascript.

# selenium doesn't support transactional fixtures
class ActiveSupport::TestCase
  #...
  self.use_transactional_fixtures = false
  #...
end

setup do |session|
  session_host "localhost:3000"
end


Webrat.configure do |config|
  config.mode = :selenium
end

Webrat talks to the selenium client gem to talk to the Selenium RC server which then drives a browser (IE, safari, and/or firefox).

Sometimes you’ll need to an action differently when a browser is actually present. These commands let you write code for a specific context:
webrat.simulate – traditional webrat simulation mode
webrate.automate – drive a real browser

# is not run in normal webrat mode
  webrat.automate do
end

# is not run in selenium webrat mode
webrat.simulate do
  ...
end

The ‘selenium’ object is exposed from the selenium client gem. You can use it directly within your tests.

Automating a real web browser is SLOW

One more thing…

rack::test – gives you a quick way to generate requests to any rack enabled application
Makes it easy to test complicated routing of requests through rack apps. For example, a rails metal that routes to a sinatra app.

Rack::Test API

get
post, put, delete head
request
…

Questions

  • Q: How do you deal with links with the same names?
  • A: Webrat has a method called “within” which allows you to scope your selectors to be inside an HTML tag.

  • Q: Does it have support for checking HTML validity?

  • A: No, that is outside of the scope of core webrat. However, we have talked about the ability to capture

  • Q: Where does the output of save_and_open_page go?

  • A: Into Rails’ tmp directory

  • Q: Selenium client has some interesting screen grab is that being exposed?

  • A: Webrat has that in Selenium mode now.
  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Ryan Dy

GoGaRuCo '09 – CouchDB + Ruby: Perform Like a Pr0n Star – Matt Aimonetti

Ryan Dy
Saturday, April 18, 2009

CouchDB + Ruby: Perform Like a Pr0n Star – Matt Aimonetti

Intro

GoGaRuCo '09 - CouchDB + Ruby: Perform Like a Pr0n Star - Matt Aimonetti

Matt Aimonetti is part of the Merb team.

Size matters

  • memory usage
  • amount of servers
  • infrastructure

You need reliability

Fault tolerant

  • downtime

GoGaRuCo '09 - CouchDB + Ruby: Perform Like a Pr0n Star - Matt Aimonetti

Multiple Partners

  • Nice public interfaces
  • no discrimination

Scalability

  • reaction underload
  • handle concurrent connections
  • numbert of requests persecond
  • latency

Approaches

Every p0rn star needs a trick

Enter CouchDB

Why aren’t you a porn star now? Because of RDBMS

What does RDBMS have problems?

  • most/all fields become options, schema changes and it becomes hard to deal with
  • joins hurts performance (add indices/tables)
  • replication is difficult when using multiple masters
  • auto-incremental ids

What other kinds of approaches can we use?

Hypertable

Distributed Hash Table

  • fault tolerant
  • used by p2p and IM
  • memached is another example

Some other projects:
Project Voldemort, Tokyo Cabinet, Redis

What is CouchDB?

It is a project written in Erlang by Apache. It uses spider monkey.

Can be used as a key/value store.
Can also put data in a schema-less store, format your data as a JSON object and dump the whole thing into the db

CouchDB comes with a nice web interface called Futon that lets you inspect your database and its contents.

CouchDB is de-centralized.
You can do replication between multiple masters.

map/reduce is built in to compute data. Maps and reduces can be written in Javascript.

Optimized for the web, more reads than writes.

  • full Acid compliance
  • https rest interface
  • caching (couchdb uses etags) – this makes caching with existing HTTP caching technology (nginx+memcache, varnish, etc) really easy.
  • built-in conflict management using MVCC (multiversion concurrency control)
    • Every single record gets saved as a different revision
  • document attachments are attached as document stubs, that also get replicated to different nodes and don’t use a lot of memory

couchdb-lucene

How does this relate to Ruby?

Using CouchRest
Everything is a JSON object.

You can define properties so you get an attribute reader/writer, and do document.attr

There is no SQL in CouchDB, you do queries like Card.first, Card.all, Card.get(’matt_aiomonetti’)

The problem is trying to map documents into Object-Oriented languages, but it doesn’t always work. If you have dependent objects (such as Card and Address), then you tell CouchDB to cast it as something.

property :questions, :cast_as > ['Question']

Callbacks:

save_callback :before, :generate_slug_from_title

Relationships can be done, but you have to decide how to do it, and there are a lot of ways.

When to use couch?

  • When you need to scale you database and availibility is more important than consistency.
  • When your data is decentralized (you have more than one master
  • When you need to compute data

Use cases:

  • Analytics – combined with traditional rdbms system to get statistics using couchdb
  • Personal finance – Bank accounts in different countries – download all accounts, and can process in one place – attach PDF files, desktop app, etc.
  • Medical Record System – Many patients with visits, history, records, etc.
  • distributed e-commerce sites (1 main website working with multiple partners, the data can be replicated easily) In this case, CouchDB is much faster than RDBMS, because of drugs, compounds, and complex structures.

Questions

Q: Can you use couchdb with objects that have attributes that change often?
A: Yes you can use it.

Q: There are many ways to do relationships. Can you give an example?
A: Blog has an article with many comments. You can make one doc that is an article, and you can add comments. Problem is you need to send the whole document that increases risk of conflicts. So you create a new object that is the comment object that just refers to the article. Then, in the view you define the Article as aggregating all comments. Alternately, you can make a query to retrieve all comments for the article.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter

Topics

  • agile (783)
  • rails (117)
  • testing (90)
  • ruby (85)
  • ruby on rails (71)
  • jobs (62)
  • javascript (59)
  • techtalk (44)
  • ironblogger (42)
  • rspec (39)
  • bloggerdome (34)
  • productivity (34)
  • activerecord (30)
  • rubymine (30)
  • git (29)
  • gogaruco (29)
  • nyc (27)
  • design (24)
  • mobile (23)
  • pivotal tracker (22)
  • process (21)
  • cucumber (21)
  • jasmine (19)
  • ios (18)
  • tracker ecosystem (17)
  • webos (17)
  • objective-c (17)
  • fun (16)
  • android (16)
  • palm (16)
  • ci (16)
  • "soft" ware (16)
  • bdd (15)
  • tdd (15)
  • cedar (15)
  • rails3 (14)
  • performance (14)
  • css (14)
  • gem (13)
  • mouse-free development (12)
  • selenium (12)
  • goruco (12)
  • bundler (12)
  • api (12)
  • keyboard (11)
  • meetup (11)
  • railsconf (11)
  • nyc-standup (11)
  • capybara (10)
  • mac (10)
Subscribe to Community Feed
  1. ←
  2. 1
  3. 2
  4. 3
  5. 4
  6. 5
  7. 6
  8. →
  • About
  • Case Studies
  • Team
  • Community
  • Careers
  • Tools
  • Contact
  • Labs
  • Events

Contact Us

contact@pivotallabs.com
+1 415-77-PIVOT
TwitterLinkedInFacebook

Pivotal Tracker

Tracker is the award-winning agile project management tool that enables real-time collaboration around a shared, prioritized backlog.
Visit pivotaltracker.com >