)]}'
{
  "log": [
    {
      "commit": "7196a10b1f1f433829b9870810c99e84b59e5607",
      "tree": "f1e936e83ebd3c369d2d22c61a574d552a4034b3",
      "parents": [
        "704a750fa2d098d0537ced60a36a8cdc7e4612e2",
        "0a6e45abb78bc2fa05956d13f99608897230d364"
      ],
      "author": {
        "name": "Samuel A. Falvo II",
        "email": "kc5tja@arrl.net",
        "time": "Thu Jul 11 17:02:57 2013 -0700"
      },
      "committer": {
        "name": "Samuel A. Falvo II",
        "email": "kc5tja@arrl.net",
        "time": "Thu Jul 11 17:02:57 2013 -0700"
      },
      "message": "Merge pull request #39 from rackspace/list-images-4\n\nAdd ListImages() support and acceptance test."
    },
    {
      "commit": "0a6e45abb78bc2fa05956d13f99608897230d364",
      "tree": "f1e936e83ebd3c369d2d22c61a574d552a4034b3",
      "parents": [
        "704a750fa2d098d0537ced60a36a8cdc7e4612e2"
      ],
      "author": {
        "name": "Samuel A. Falvo II",
        "email": "sam.falvo@rackspace.com",
        "time": "Thu Jul 11 17:00:41 2013 -0700"
      },
      "committer": {
        "name": "Samuel A. Falvo II",
        "email": "sam.falvo@rackspace.com",
        "time": "Thu Jul 11 17:00:41 2013 -0700"
      },
      "message": "Add ListImages() support and acceptance test.\n\nThis is needed to support a (currently broken) acceptance test for\ncreating a cloud server.  Without the ability to auto-detect an image, a\nhuman operator is required to specify an image manually, which defeats\nthe value of an automated test.\n"
    },
    {
      "commit": "704a750fa2d098d0537ced60a36a8cdc7e4612e2",
      "tree": "d371823f13567774bfd4c5ecc5e59fbc48279fc3",
      "parents": [
        "02f5e83ac462bf3ae8d768db9b895e57de457167"
      ],
      "author": {
        "name": "Samuel A. Falvo II",
        "email": "sam.falvo@rackspace.com",
        "time": "Wed Jul 10 15:23:43 2013 -0700"
      },
      "committer": {
        "name": "Samuel A. Falvo II",
        "email": "sam.falvo@rackspace.com",
        "time": "Wed Jul 10 15:23:43 2013 -0700"
      },
      "message": "Remove duplicate code from acceptance tests.\n\nJust cleaning things up here.\n"
    },
    {
      "commit": "02f5e83ac462bf3ae8d768db9b895e57de457167",
      "tree": "0351d482e1c8dd1daee895868e7583696134733a",
      "parents": [
        "489484776a96585dfd7eebf186b975b15f2022ce"
      ],
      "author": {
        "name": "Samuel A. Falvo II",
        "email": "sam.falvo@rackspace.com",
        "time": "Wed Jul 10 13:52:27 2013 -0700"
      },
      "committer": {
        "name": "Samuel A. Falvo II",
        "email": "sam.falvo@rackspace.com",
        "time": "Wed Jul 10 13:52:27 2013 -0700"
      },
      "message": "Add ServerById() function and acceptance test.\n"
    },
    {
      "commit": "489484776a96585dfd7eebf186b975b15f2022ce",
      "tree": "b2e001d59e7960412dd1f5e35ff767fb7e807619",
      "parents": [
        "fce34bf772da11f1ae4a8c15d2bf05c8ac669c17",
        "1dd740af61898a80dd5e5acada4a558b86de0c76"
      ],
      "author": {
        "name": "Samuel A. Falvo II",
        "email": "kc5tja@arrl.net",
        "time": "Mon Jul 08 17:30:55 2013 -0700"
      },
      "committer": {
        "name": "Samuel A. Falvo II",
        "email": "kc5tja@arrl.net",
        "time": "Mon Jul 08 17:30:55 2013 -0700"
      },
      "message": "Merge pull request #37 from rackspace/list-servers--rename-compute-api\n\nRename ComputeApi to ServerApi"
    },
    {
      "commit": "fce34bf772da11f1ae4a8c15d2bf05c8ac669c17",
      "tree": "f7d23b9e10f586ff7c1eaefd14dfae253789dd38",
      "parents": [
        "743795c1d58bf699c66a760c9c6f881ced1a4e81",
        "bc0d54a28253182cde9f78be19e03ae91a8326be"
      ],
      "author": {
        "name": "Samuel A. Falvo II",
        "email": "kc5tja@arrl.net",
        "time": "Mon Jul 08 17:29:15 2013 -0700"
      },
      "committer": {
        "name": "Samuel A. Falvo II",
        "email": "kc5tja@arrl.net",
        "time": "Mon Jul 08 17:29:15 2013 -0700"
      },
      "message": "Merge pull request #35 from rackspace/list-servers\n\nAdd support for Listing Servers."
    },
    {
      "commit": "1dd740af61898a80dd5e5acada4a558b86de0c76",
      "tree": "b2e001d59e7960412dd1f5e35ff767fb7e807619",
      "parents": [
        "bc0d54a28253182cde9f78be19e03ae91a8326be"
      ],
      "author": {
        "name": "Samuel A. Falvo II",
        "email": "sam.falvo@rackspace.com",
        "time": "Mon Jul 08 15:48:40 2013 -0700"
      },
      "committer": {
        "name": "Samuel A. Falvo II",
        "email": "sam.falvo@rackspace.com",
        "time": "Mon Jul 08 15:48:40 2013 -0700"
      },
      "message": "Rename ComputeApi to ServerApi\n\nComputeApi never sat well with me.  OpenStack documents prefer to call\ntheir computing service \"Cloud Server\" API instead.  So, I renamed all\npublic-facing types and procedure names to reflect this usage.\n\nFixes #33\n"
    },
    {
      "commit": "bc0d54a28253182cde9f78be19e03ae91a8326be",
      "tree": "f7d23b9e10f586ff7c1eaefd14dfae253789dd38",
      "parents": [
        "743795c1d58bf699c66a760c9c6f881ced1a4e81"
      ],
      "author": {
        "name": "Samuel A. Falvo II",
        "email": "sam.falvo@rackspace.com",
        "time": "Mon Jul 08 14:45:21 2013 -0700"
      },
      "committer": {
        "name": "Samuel A. Falvo II",
        "email": "sam.falvo@rackspace.com",
        "time": "Mon Jul 08 14:45:21 2013 -0700"
      },
      "message": "Add support for Listing Servers.\n\nUp to now, all you could do is authenticate with Gophercloud.  Now, you\ncan list your servers too!\n\nThis is a pretty straight-ahead port of logic from Gorax to Gophercloud.\n\nAfter you gain access to the ComputeApi, you simply invoke\nListServers().  This returns a slice of Server structures, one each for\nthe servers your account has access to.  See the 02-list-servers.go\nacceptance test.\n\nNote that no unit-level tests exist for this functionality.  Writing a\nunit test for this code would only serve to test the compiler\u0027s ability\nto emit bug-free machine code.  (Observe ListServers() has no control\nflow points, and all its dependencies already have their own unit\ntests.)\n\nBeing that this is a straight-ahead port from Gorax, some things remain\nto be done:\n\n1) Provide an API for accessing Rackspace-specific fields. (#34)\n2) Assuming (1) is successful, remove Rack-specific fields from Server\n   and other structures of interest. (#34)\n3) Rename ComputeApi to something more descriptive -- like ServerApi().\n   (#33)\n4) Implement token re-authentication logic.  (#12)\n"
    },
    {
      "commit": "743795c1d58bf699c66a760c9c6f881ced1a4e81",
      "tree": "c570f59c7b3c1c7c4deff246addc850428e2bef6",
      "parents": [
        "e7418aa97f14b17e5730fba2d973155158fbf4ea",
        "2e2b8776e9bdfe8e1e4d12692e8ac7e254914f9b"
      ],
      "author": {
        "name": "Samuel A. Falvo II",
        "email": "kc5tja@arrl.net",
        "time": "Thu Jul 04 16:01:29 2013 -0700"
      },
      "committer": {
        "name": "Samuel A. Falvo II",
        "email": "kc5tja@arrl.net",
        "time": "Thu Jul 04 16:01:29 2013 -0700"
      },
      "message": "Merge pull request #32 from rackspace/cloud-servers-1\n\nEpic refactoring to improve testability."
    },
    {
      "commit": "2e2b8776e9bdfe8e1e4d12692e8ac7e254914f9b",
      "tree": "c570f59c7b3c1c7c4deff246addc850428e2bef6",
      "parents": [
        "e7418aa97f14b17e5730fba2d973155158fbf4ea"
      ],
      "author": {
        "name": "Samuel A. Falvo II",
        "email": "sam.falvo@rackspace.com",
        "time": "Thu Jul 04 15:40:15 2013 -0700"
      },
      "committer": {
        "name": "Samuel A. Falvo II",
        "email": "sam.falvo@rackspace.com",
        "time": "Thu Jul 04 15:40:15 2013 -0700"
      },
      "message": "Epic refactoring to improve testability.\n\nIt all started when I wanted to write ListServers(), but doing that\nmeant acquiring the test context, so that I could intercept server-side\ncommunications.  However, that couldn\u0027t be easily acquired with the old\nsoftware configuration.  In fact, it was patently impossible to do,\nwithout breaking a lot of encapsulation and conflating concerns.\n\nAdditionally, I knew I didn\u0027t want to make ComputeApi() a method of an\nAccessProvider interface; considering how similar the OpenStack APIs\nare, I was banking on that design decision causing a lot of duplicate\ncode, even if said code was simple.  Not only that, but it conflated\nconcerns; again, something I wanted to avoid.\n\nSo, I needed to do a couple of things.\n\n1) Realize that module-global functions are delegators to the global\ncontext.  My original implementation of ComputeApi() wasn\u0027t, which meant\nthat I had zero access to any contexts created in unit testing.\n\n2) Realize that the Context interface is the true Gophercloud global\nAPI.  This meant I had to make a ComputeApi() method on the Context\ninterface, and implement it.  This proved very convenient -- it granted\nme access automatically to all test contexts.\n\nAs a checklist bullet point, whenever adding a new global-level function\nto gophercloud, do it in at least these steps: a) add the function as a\nmethod on Context.  Seriously -- this is the only real way to make it\ntestable.  b) Add a very dumb delegator function in global_context.go\nwhich dispatches to its eponymously-named method on globalContext.\n\n3) Making this simple change was sufficient to start to test an\nimplementation of ListServers().  However, invoking \"c :\u003d TestContext();\nc.foo(); c.bar();\" was becoming repetitive and error-prone.  So, I\nrefactored that into a Java-style DSL.  These things aren\u0027t terribly Go\nidiomatic, but for my needs here, they work nicely.\n\n4) I refactored the two different implementations of custom transports\ninto a single \"transport-double\" type.  This type will supports both\ncanned responses and some basic request validation.  It\u0027s expandable by\nsimply adding more configuration fields and DSL methods of its own.\n\n5) api.go is no more -- it previously served two separate purposes, each\nof which has its own source file now.  interfaces.go holds the\ndefinition of all publicly visible APIs, while global_context.go\nprovides the default global Context, its initialization, and the\nmodule-global entry points that delegate to the global context.\n\nWith these changes having been made, *now* I\u0027m ready to actually start\ntesting ListServers() development!  It only took 24 hours and 4\nrefreshes of the feature branch just to get this far.  :-)\n\nThe nice thing is, though, that going forward, these changes should\ncontribute to making future endpoint binding implementations\nsignificantly easier than what I had to do before.\n"
    },
    {
      "commit": "e7418aa97f14b17e5730fba2d973155158fbf4ea",
      "tree": "4dbdc42443d445867c78a4e50728bdadcec09a25",
      "parents": [
        "daf65dccfea6f631599b59aafd8a1c5ac4b3e4d4",
        "fca35b7d2e4753c88f16e2ff88cddf29caf1f060"
      ],
      "author": {
        "name": "Samuel A. Falvo II",
        "email": "kc5tja@arrl.net",
        "time": "Wed Jul 03 13:21:29 2013 -0700"
      },
      "committer": {
        "name": "Samuel A. Falvo II",
        "email": "kc5tja@arrl.net",
        "time": "Wed Jul 03 13:21:29 2013 -0700"
      },
      "message": "Merge pull request #31 from rackspace/service-catalog-search\n\nImplement Access.FirstEndpointUrlByCriteria\r\n\r\nThe FirstEndpointUrlByCriteria method is a key enabler for writing API\r\nprovider interface constructors. A simple, albeit incomplete, use-case\r\nfor Cloud Servers API demonstrates how it\u0027s used internally.\r\n\r\nIn order to list servers, we need access to a cloud server API.  This is\r\nthe job of the ComputeApi() function.\r\n\r\nComputeApi(), in turn, tries hard not to contrain the user in choosing\r\nan endpoint, while still offering an interface optimized for the common\r\ncase of using an existing service provider\u0027s endpoints.  Otherwise, the\r\nuser will end up having to use nested functions and bizarre predicate\r\nsequences like this:\r\n\r\n  func(ce *CatalogEntry, ee *EntryEndpoint) bool {\r\n    if ce !\u003d nil {\r\n      return ce.Name \u003d\u003d \"cloudComputeOpenStack\"\r\n    }\r\n    if ee !\u003d nil {\r\n      return ee.Region \u003d\u003d \"DFW\" \u0026\u0026 ee.VersionId \u003d\u003d \"2\"\r\n    }\r\n    return false\r\n  }\r\n\r\nThe current interface just encapsulates this kind of logic into a simple\r\nstructure, taking 66% fewer lines, and zero chance for error:\r\n\r\n  ApiCriteria{\r\n    Name: \"cloudComputeOpenStack\",\r\n    Region: \"DFW\",\r\n    VersionId: \"2\",\r\n  }\r\n\r\nFindFirstEndpointByConstraint() is invoked (via\r\nAccessProvider.FirstEndpointUrlByConstraint()) to actually look for a\r\nmatching endpoint in the provider\u0027s service catalog.  This interprets\r\nthe ApiCriteria structure settings, except for UrlChoice.  If it finds a\r\ncandidate endpoint, the user may select public or private endpoints via\r\nthe ApiCriteria.UrlChoice setting (which the\r\nFirstEndpointUrlByCriteria() function interprets). If nothing is found,\r\nan ErrEndpoint error will be returned to the caller.  Of course, this\r\nbeing a brand new implementation, it just returns the default of\r\n\"nothing found\" for all queries anyway.\r\n\r\nIf not specified, a criteria\u0027s UrlChoice defaults to PublicURL."
    },
    {
      "commit": "fca35b7d2e4753c88f16e2ff88cddf29caf1f060",
      "tree": "4dbdc42443d445867c78a4e50728bdadcec09a25",
      "parents": [
        "daf65dccfea6f631599b59aafd8a1c5ac4b3e4d4"
      ],
      "author": {
        "name": "Samuel A. Falvo II",
        "email": "sam.falvo@rackspace.com",
        "time": "Tue Jul 02 18:30:28 2013 -0700"
      },
      "committer": {
        "name": "Samuel A. Falvo II",
        "email": "sam.falvo@rackspace.com",
        "time": "Tue Jul 02 18:30:28 2013 -0700"
      },
      "message": "Implement Access.FirstEndpointUrlByCriteria\n\nThe FirstEndpointUrlByCriteria method is a key enabler for writing API\nprovider interface constructors.  A simple, albeit incomplete, use-case\nfor Cloud Servers API demonstrates how it\u0027s used internally.\n\nSee squashed commit history below for more detailed rationale behind the\nAPI design.\n\nSquashed commit of the following:\n\ncommit 625c31f754dcdcd2d348cf4cf5499a03ba6b2de1\nAuthor: Samuel A. Falvo II \u003csam.falvo@rackspace.com\u003e\nDate:   Tue Jul 2 18:21:36 2013 -0700\n\n    Fix service name typo\n\ncommit c6abcbe20bfe31a8c9399e78c186dca64d050140\nAuthor: Samuel A. Falvo II \u003csam.falvo@rackspace.com\u003e\nDate:   Tue Jul 2 18:15:41 2013 -0700\n\n    Added decision logic to FFEBC function.\n\ncommit bccf7178464c5071a81d63ef16fd20d7a241146f\nAuthor: Samuel A. Falvo II \u003csam.falvo@rackspace.com\u003e\nDate:   Tue Jul 2 17:18:14 2013 -0700\n\n    Added ListServers and its dependencies.\n\n    In order to list servers, we need access to a cloud server API.  This is\n    the job of the ComputeApi() function.\n\n    ComputeApi(), in turn, tries hard not to contrain the user in choosing\n    an endpoint, while still offering an interface optimized for the common\n    case of using an existing service provider\u0027s endpoints.  Otherwise, the\n    user will end up having to use nested functions and bizarre predicate\n    sequences like this:\n\n      func(ce *CatalogEntry, ee *EntryEndpoint) bool {\n        if ce !\u003d nil {\n          return ce.Name \u003d\u003d \"cloudComputeOpenStack\"\n        }\n        if ee !\u003d nil {\n          return ee.Region \u003d\u003d \"DFW\" \u0026\u0026 ee.VersionId \u003d\u003d \"2\"\n        }\n        return false\n      }\n\n    The current interface just encapsulates this kind of logic into a simple\n    structure, taking 66% fewer lines, and zero chance for error:\n\n      ApiCriteria{\n        Name: \"cloudComputeOpenStack\",\n        Region: \"DFW\",\n        VersionId: \"2\",\n      }\n\n    FindFirstEndpointByConstraint() is invoked (via\n    AccessProvider.FirstEndpointUrlByConstraint()) to actually look for a\n    matching endpoint in the provider\u0027s service catalog.  This interprets\n    the ApiCriteria structure settings, except for UrlChoice.  If it finds a\n    candidate endpoint, the user may select public or private endpoints via\n    the ApiCriteria.UrlChoice setting (which the\n    FirstEndpointUrlByCriteria() function interprets). If nothing is found,\n    an ErrEndpoint error will be returned to the caller.  Of course, this\n    being a brand new implementation, it just returns the default of\n    \"nothing found\" for all queries anyway.\n\n    If not specified, a criteria\u0027s UrlChoice defaults to PublicURL.\n\ncommit 9549f0b30e0736962dad55f3f38f88124e076fb9\nAuthor: Samuel A. Falvo II \u003csam.falvo@rackspace.com\u003e\nDate:   Tue Jul 2 17:10:14 2013 -0700\n\n    Removed VIM temp swap file\n\ncommit 8e00ad5ac3466cbec3c539e8b21bea6d23ab37f7\nAuthor: Samuel A. Falvo II \u003csam.falvo@rackspace.com\u003e\nDate:   Tue Jul 2 16:20:22 2013 -0700\n\n    Add ApiCriteria to API\n\ncommit 6f3b41929a496c6a0734221bf12ef27035b71e39\nAuthor: Samuel A. Falvo II \u003csam.falvo@rackspace.com\u003e\nDate:   Tue Jul 2 16:18:49 2013 -0700\n\n    Add acceptance test for list servers\n"
    },
    {
      "commit": "daf65dccfea6f631599b59aafd8a1c5ac4b3e4d4",
      "tree": "599f4e91aca206d6da8fe568873aeaaa3dd7aff5",
      "parents": [
        "43fa244bacff5277b68739b3c50586110196532c",
        "73e3e874bec15a06a8a2b165ad602477ff7397fe"
      ],
      "author": {
        "name": "Samuel A. Falvo II",
        "email": "kc5tja@arrl.net",
        "time": "Fri Jun 28 11:43:26 2013 -0700"
      },
      "committer": {
        "name": "Samuel A. Falvo II",
        "email": "kc5tja@arrl.net",
        "time": "Fri Jun 28 11:43:26 2013 -0700"
      },
      "message": "Merge pull request #10 from rackspace/getting-started-docs\n\nUpdate README.md -\u003e README.asciidoc, with typo fixes and Getting Started"
    },
    {
      "commit": "73e3e874bec15a06a8a2b165ad602477ff7397fe",
      "tree": "599f4e91aca206d6da8fe568873aeaaa3dd7aff5",
      "parents": [
        "1a28751ec60e4019b5d1129fe8d6ce88c939c795"
      ],
      "author": {
        "name": "Samuel A. Falvo II",
        "email": "sam.falvo@rackspace.com",
        "time": "Fri Jun 28 11:40:02 2013 -0700"
      },
      "committer": {
        "name": "Samuel A. Falvo II",
        "email": "sam.falvo@rackspace.com",
        "time": "Fri Jun 28 11:40:07 2013 -0700"
      },
      "message": "Align call-outs\n"
    },
    {
      "commit": "1a28751ec60e4019b5d1129fe8d6ce88c939c795",
      "tree": "906979d566cdf56dc1a6d910b7e8cbdad1f4d9b6",
      "parents": [
        "fc2cdefed8f8dba336222c17f2ad651269176d92"
      ],
      "author": {
        "name": "Samuel A. Falvo II",
        "email": "sam.falvo@rackspace.com",
        "time": "Fri Jun 28 11:37:42 2013 -0700"
      },
      "committer": {
        "name": "Samuel A. Falvo II",
        "email": "sam.falvo@rackspace.com",
        "time": "Fri Jun 28 11:37:42 2013 -0700"
      },
      "message": "Remove typo\n"
    },
    {
      "commit": "fc2cdefed8f8dba336222c17f2ad651269176d92",
      "tree": "c3f487a0ea147797bf534b320d50c96f281e78db",
      "parents": [
        "56e961f1257c11057ebc6c507d89922efdc39924"
      ],
      "author": {
        "name": "Samuel A. Falvo II",
        "email": "sam.falvo@rackspace.com",
        "time": "Fri Jun 28 11:36:00 2013 -0700"
      },
      "committer": {
        "name": "Samuel A. Falvo II",
        "email": "sam.falvo@rackspace.com",
        "time": "Fri Jun 28 11:36:00 2013 -0700"
      },
      "message": "Fix admonition again\n"
    },
    {
      "commit": "56e961f1257c11057ebc6c507d89922efdc39924",
      "tree": "fde124308bc3f8eb3193023114f6b9078788a488",
      "parents": [
        "9566bf8689231b467af3652679ab52e38b28edc7"
      ],
      "author": {
        "name": "Samuel A. Falvo II",
        "email": "sam.falvo@rackspace.com",
        "time": "Fri Jun 28 11:35:00 2013 -0700"
      },
      "committer": {
        "name": "Samuel A. Falvo II",
        "email": "sam.falvo@rackspace.com",
        "time": "Fri Jun 28 11:35:00 2013 -0700"
      },
      "message": "Add link to gophercloud-dev, fix admonition\n"
    },
    {
      "commit": "9566bf8689231b467af3652679ab52e38b28edc7",
      "tree": "b27ed8dce366463d35431560b30f4fa78126cefe",
      "parents": [
        "b4abb058ae399858dce42154dac40edd45ef75ac"
      ],
      "author": {
        "name": "Samuel A. Falvo II",
        "email": "sam.falvo@rackspace.com",
        "time": "Fri Jun 28 11:28:23 2013 -0700"
      },
      "committer": {
        "name": "Samuel A. Falvo II",
        "email": "sam.falvo@rackspace.com",
        "time": "Fri Jun 28 11:28:23 2013 -0700"
      },
      "message": "Replace table with callouts\n"
    },
    {
      "commit": "b4abb058ae399858dce42154dac40edd45ef75ac",
      "tree": "c7f2e081ba56f28efeb5d6f564674284b53aff94",
      "parents": [
        "4c11721051d516cf999666f30bfc7837ce4990d4"
      ],
      "author": {
        "name": "Samuel A. Falvo II",
        "email": "sam.falvo@rackspace.com",
        "time": "Fri Jun 28 11:25:09 2013 -0700"
      },
      "committer": {
        "name": "Samuel A. Falvo II",
        "email": "sam.falvo@rackspace.com",
        "time": "Fri Jun 28 11:25:09 2013 -0700"
      },
      "message": "Compensate for lack of gh support for admonitions\n"
    },
    {
      "commit": "4c11721051d516cf999666f30bfc7837ce4990d4",
      "tree": "202bc82bf82ab077d058d93d26201ee81d28cdb0",
      "parents": [
        "841204d289c81f16426cc7ba4727d85924c5fe98"
      ],
      "author": {
        "name": "Samuel A. Falvo II",
        "email": "sam.falvo@rackspace.com",
        "time": "Fri Jun 28 11:23:42 2013 -0700"
      },
      "committer": {
        "name": "Samuel A. Falvo II",
        "email": "sam.falvo@rackspace.com",
        "time": "Fri Jun 28 11:23:42 2013 -0700"
      },
      "message": "Fix accidental code block syntax\n"
    },
    {
      "commit": "841204d289c81f16426cc7ba4727d85924c5fe98",
      "tree": "22e1ea3ba5b28338cc85209d570e37e5396aa4f2",
      "parents": [
        "7b830c970d2a1011093f95a0a1f6df39fa2b9cd0"
      ],
      "author": {
        "name": "Samuel A. Falvo II",
        "email": "sam.falvo@rackspace.com",
        "time": "Fri Jun 28 11:20:29 2013 -0700"
      },
      "committer": {
        "name": "Samuel A. Falvo II",
        "email": "sam.falvo@rackspace.com",
        "time": "Fri Jun 28 11:20:29 2013 -0700"
      },
      "message": "Change filename to match new format\n"
    },
    {
      "commit": "7b830c970d2a1011093f95a0a1f6df39fa2b9cd0",
      "tree": "80e2591679c0e129efa65d7ec7d272b2cb30f438",
      "parents": [
        "07552815c87658057cfee56cfae9e50a9cfee889"
      ],
      "author": {
        "name": "Samuel A. Falvo II",
        "email": "sam.falvo@rackspace.com",
        "time": "Fri Jun 28 11:20:14 2013 -0700"
      },
      "committer": {
        "name": "Samuel A. Falvo II",
        "email": "sam.falvo@rackspace.com",
        "time": "Fri Jun 28 11:20:14 2013 -0700"
      },
      "message": "Translate from markdown to asciidoc\n"
    },
    {
      "commit": "07552815c87658057cfee56cfae9e50a9cfee889",
      "tree": "4f2495bb9915030652a9cbd8b572ab44d5536926",
      "parents": [
        "43fa244bacff5277b68739b3c50586110196532c"
      ],
      "author": {
        "name": "Samuel A. Falvo II",
        "email": "sam.falvo@rackspace.com",
        "time": "Thu Jun 27 15:02:13 2013 -0700"
      },
      "committer": {
        "name": "Samuel A. Falvo II",
        "email": "sam.falvo@rackspace.com",
        "time": "Thu Jun 27 15:02:13 2013 -0700"
      },
      "message": "Update README.md with typo fixes and Getting Started\n"
    },
    {
      "commit": "43fa244bacff5277b68739b3c50586110196532c",
      "tree": "f416308c2716b9cd2839199a65b532f3a6b5c1ed",
      "parents": [
        "a9b147cbd6be27c58777dbd447022fb4a7578a67",
        "4e89518cd94761fba4f9449d02530d1317f53681"
      ],
      "author": {
        "name": "Samuel A. Falvo II",
        "email": "kc5tja@arrl.net",
        "time": "Thu Jun 27 11:08:16 2013 -0700"
      },
      "committer": {
        "name": "Samuel A. Falvo II",
        "email": "kc5tja@arrl.net",
        "time": "Thu Jun 27 11:08:16 2013 -0700"
      },
      "message": "Merge pull request #9 from rackspace/authentication\n\nAdd Authentication functionality.\r\n\r\nNow that I have the time to write this up, here\u0027s the description that should have gone into the git commit message.\r\n\r\ngophercloud needs to authenticate against a provider. However, gorax\u0027s API isn\u0027t ideal from a multi-provider perspective. Thus, instead of requiring the user to instantiate Identity objects, configuring them, and then authenticating in a 3-step process, I create a single public function, Authenticate(), which performs (essentially) these tasks.\r\n\r\nI cannot predict the future, and cannot guarantee Identity V3 compatibility in its current form. However, in an attempt to anticipate the future, the Authenticate function is designed to automatically guess which Identity API you intend on using based on which set of credentials you provide it. The underlying assumption is that a V3 token is compatible with a V2 token; once we have the token, it should be usable with other V2 and V3 APIs as appropriate.\r\n\r\nUnlike Ruby or Python, Go lacks support for keyword arguments. There are two ways to overcome this deficiency: (1) Make a function that accepts one or more interface{} types, and rely on type-checks to disambiguate meaning from supplied parameters; and, (2) use a structure and rely upon Go\u0027s automatic initialization of unspecified fields to well-known \"zero\" values. Here\u0027s a comparison of the two approaches from the point of view of the caller:\r\n\r\n// option 1 -- use list of interface{} types\r\nacc, err :\u003d gophercloud.Authenticate(\"rackspace-us\", gophercloud.Username(\"sfalvo\"), gophercloud.Password(\"my-pass-here\"), gophercloud.TenantId(\"blah\"))\r\n\r\n// option 2 -- use of a dedicated options structure\r\naccRackspace, err :\u003d gophercloud.Authenticate(\"rackspace-us\", gophercloud.AuthOptions{\r\n    Username: \"sfalvo\",\r\n    Password: \"my-pass-here\",\r\n    TenantId: \"blah\",\r\n})\r\nAs can be seen, the latter requires much less physical typing (assuming one doesn\u0027t rename the gophercloud package to just \u0027g\u0027 in the import statement), and thus less chance for error. That\u0027s why I decided to use an options structure instead. It also impacts the design of the callee as well; with option (1), I\u0027d have to manually loop through all the parameters, using a type-case statement to decode the supplied parameters and fill in variables as they\u0027re discovered, while in (2) I just inspect the options structure directly. Less code means fewer bugs.\r\n\r\nSince the method of authentication remains the same across all providers, assuming universal use of V2 APIs, I associate an AuthEndpoint field with each Provider instance. That\u0027s the only per-provider piece of information defined at the moment.\r\n\r\nMost other SDKs hard-wire their providers; however, this is grossly inconvenient for unit-testing purposes. Therefore, I wrap what would otherwise be global state into a Context structure. TestContext exists to create a blank context, which can be used by unit tests at will. You\u0027ll notice that the init() function (in the api.go file) uses it to create the one, true, global context, and pre-populates it with the otherwise statically defined list of providers. Through this mechanism, users of the library needn\u0027t concern themselves with contexts and their proper initialization. Instead, they can just use the package-global functions, and they should \"just work.\"\r\n\r\nNote that the result of Authenticate() is a structure instance, allowing the client access to the service catalog, tenant ID information, and user information. As we flesh out additional APIs for the Go SDK, we will add methods to this Access structure, allowing more convenient access to various APIs. For example, one hypothetical approach to working with Cloud Compute services would involve using Access as a factory:\r\n\r\ncompute, err :\u003d accRackspace.CloudComputeApi()\r\nThis conforms to the first two levels of the desired \u003corganization.service.entity.method\u003e SDK organization, and provides the appropriate propegation of state that allows for token re-auth in a fully transparent manner, if necessary."
    },
    {
      "commit": "4e89518cd94761fba4f9449d02530d1317f53681",
      "tree": "f416308c2716b9cd2839199a65b532f3a6b5c1ed",
      "parents": [
        "d1ee7987fd4c036272d39d80bc3b89b6d22a518c"
      ],
      "author": {
        "name": "Samuel A. Falvo II",
        "email": "sam.falvo@rackspace.com",
        "time": "Wed Jun 26 15:44:18 2013 -0700"
      },
      "committer": {
        "name": "Samuel A. Falvo II",
        "email": "sam.falvo@rackspace.com",
        "time": "Wed Jun 26 15:44:18 2013 -0700"
      },
      "message": "Add global Authenticate() function.\n\nAlso finishes work started in last commit.\n"
    },
    {
      "commit": "d1ee7987fd4c036272d39d80bc3b89b6d22a518c",
      "tree": "8d6fd2780e0b05e3000cceee0c5f80a92b8cbc52",
      "parents": [
        "839428e0c2bc7006b922bfec7f1fdb04c4c749e6"
      ],
      "author": {
        "name": "Samuel A. Falvo II",
        "email": "sam.falvo@rackspace.com",
        "time": "Wed Jun 26 14:32:45 2013 -0700"
      },
      "committer": {
        "name": "Samuel A. Falvo II",
        "email": "sam.falvo@rackspace.com",
        "time": "Wed Jun 26 14:32:45 2013 -0700"
      },
      "message": "Parse out auth response and fill in access object\n"
    },
    {
      "commit": "839428e0c2bc7006b922bfec7f1fdb04c4c749e6",
      "tree": "4cab775ad5a75c81c2f484ab0ef0816a66fb3176",
      "parents": [
        "00a233d1e1a75d630ee886000642f41de4c969e2"
      ],
      "author": {
        "name": "Samuel A. Falvo II",
        "email": "sam.falvo@rackspace.com",
        "time": "Tue Jun 25 18:02:24 2013 -0700"
      },
      "committer": {
        "name": "Samuel A. Falvo II",
        "email": "sam.falvo@rackspace.com",
        "time": "Tue Jun 25 18:02:24 2013 -0700"
      },
      "message": "go fmt\n"
    },
    {
      "commit": "00a233d1e1a75d630ee886000642f41de4c969e2",
      "tree": "94980c6a5e4b9e92972d58fa4db3429f3597b8b3",
      "parents": [
        "978fed843429bf8a6e3c20c0f28e5f58eb2cfc09"
      ],
      "author": {
        "name": "Samuel A. Falvo II",
        "email": "sam.falvo@rackspace.com",
        "time": "Tue Jun 25 18:00:53 2013 -0700"
      },
      "committer": {
        "name": "Samuel A. Falvo II",
        "email": "sam.falvo@rackspace.com",
        "time": "Tue Jun 25 18:00:53 2013 -0700"
      },
      "message": "code cleanup\n"
    },
    {
      "commit": "978fed843429bf8a6e3c20c0f28e5f58eb2cfc09",
      "tree": "010c2124a715ae2734dc02f42a455b96d5fb3e6a",
      "parents": [
        "5d0d74ce130097c44e1c6290a607c74ec58a59ee"
      ],
      "author": {
        "name": "Samuel A. Falvo II",
        "email": "sam.falvo@rackspace.com",
        "time": "Tue Jun 25 17:59:19 2013 -0700"
      },
      "committer": {
        "name": "Samuel A. Falvo II",
        "email": "sam.falvo@rackspace.com",
        "time": "Tue Jun 25 17:59:19 2013 -0700"
      },
      "message": "Verify proper Tenant ID encoding behavior\n"
    },
    {
      "commit": "5d0d74ce130097c44e1c6290a607c74ec58a59ee",
      "tree": "0bc7a6766c8a3cf2acb56d6cf7533816ce511902",
      "parents": [
        "fd78c30473c2f64b2c0ef3263b0f1e1f963c36a8"
      ],
      "author": {
        "name": "Samuel A. Falvo II",
        "email": "sam.falvo@rackspace.com",
        "time": "Tue Jun 25 17:23:18 2013 -0700"
      },
      "committer": {
        "name": "Samuel A. Falvo II",
        "email": "sam.falvo@rackspace.com",
        "time": "Tue Jun 25 17:23:18 2013 -0700"
      },
      "message": "Make Authenticate issue an HTTP request\n"
    },
    {
      "commit": "fd78c30473c2f64b2c0ef3263b0f1e1f963c36a8",
      "tree": "212a485ebff4a28e1c9e9e1f9a10b7a07088923c",
      "parents": [
        "1d3fa667c76ec6dabb67a0b13ce07c3022768f4c"
      ],
      "author": {
        "name": "Samuel A. Falvo II",
        "email": "sam.falvo@rackspace.com",
        "time": "Tue Jun 25 16:35:32 2013 -0700"
      },
      "committer": {
        "name": "Samuel A. Falvo II",
        "email": "sam.falvo@rackspace.com",
        "time": "Tue Jun 25 16:35:32 2013 -0700"
      },
      "message": "Add provider registry support.\n"
    },
    {
      "commit": "1d3fa667c76ec6dabb67a0b13ce07c3022768f4c",
      "tree": "ab8cc3e95e3080b9a8526668661d58eec190cc28",
      "parents": [
        "d6092adfb69759791c3f3fdd99e5642066e3e642"
      ],
      "author": {
        "name": "Samuel A. Falvo II",
        "email": "sam.falvo@rackspace.com",
        "time": "Tue Jun 25 15:29:32 2013 -0700"
      },
      "committer": {
        "name": "Samuel A. Falvo II",
        "email": "sam.falvo@rackspace.com",
        "time": "Tue Jun 25 15:29:32 2013 -0700"
      },
      "message": "Add authentication acceptance test.\n\nBefore coding on the Authentication functionality of gophercloud, we\nneeded the acceptance test to know when we were finished.\n\nSince the authentication test is written in Go, I had to adjust the\nscripts/test-all.sh file to invoke Go programs directly.\n"
    },
    {
      "commit": "d6092adfb69759791c3f3fdd99e5642066e3e642",
      "tree": "721a3677d2efe67040252c11c5fc0356307fafeb",
      "parents": [
        "a9b147cbd6be27c58777dbd447022fb4a7578a67"
      ],
      "author": {
        "name": "Samuel A. Falvo II",
        "email": "sam.falvo@rackspace.com",
        "time": "Tue Jun 25 14:07:25 2013 -0700"
      },
      "committer": {
        "name": "Samuel A. Falvo II",
        "email": "sam.falvo@rackspace.com",
        "time": "Tue Jun 25 14:07:25 2013 -0700"
      },
      "message": "Add script to launch acceptance tests\n"
    },
    {
      "commit": "a9b147cbd6be27c58777dbd447022fb4a7578a67",
      "tree": "f33df8f533b31fee167616d7e5558dd22aea83cd",
      "parents": [
        "a1f6f222ec7bc16423aa1c6ed74c36c5f191c9f2",
        "563bf05417e6d210a4b4a4b89674b05d4bac5675"
      ],
      "author": {
        "name": "Samuel A. Falvo II",
        "email": "kc5tja@arrl.net",
        "time": "Tue Jun 25 13:46:49 2013 -0700"
      },
      "committer": {
        "name": "Samuel A. Falvo II",
        "email": "kc5tja@arrl.net",
        "time": "Tue Jun 25 13:46:49 2013 -0700"
      },
      "message": "Merge pull request #3 from rackspace/script-environment-setup\n\nScript to automate environment creation"
    },
    {
      "commit": "563bf05417e6d210a4b4a4b89674b05d4bac5675",
      "tree": "f33df8f533b31fee167616d7e5558dd22aea83cd",
      "parents": [
        "ff3f09dc53e2911fe4dac14d3d22564c4d60f0f8"
      ],
      "author": {
        "name": "stackedsax",
        "email": "alex@alexscammon.com",
        "time": "Tue Jun 25 13:21:00 2013 -0700"
      },
      "committer": {
        "name": "stackedsax",
        "email": "alex@alexscammon.com",
        "time": "Tue Jun 25 13:21:00 2013 -0700"
      },
      "message": "Making some changes to make the temporary installation steps even more explicit\n"
    },
    {
      "commit": "ff3f09dc53e2911fe4dac14d3d22564c4d60f0f8",
      "tree": "096a969d725de50b180849ce1bb373f75c3a25e1",
      "parents": [
        "f614c937c01213cb695b89b6ecd02c581a8432b4"
      ],
      "author": {
        "name": "Samuel A. Falvo II",
        "email": "sam.falvo@rackspace.com",
        "time": "Thu Jun 20 17:54:26 2013 -0700"
      },
      "committer": {
        "name": "Samuel A. Falvo II",
        "email": "sam.falvo@rackspace.com",
        "time": "Thu Jun 20 17:54:26 2013 -0700"
      },
      "message": "README updated\n"
    },
    {
      "commit": "f614c937c01213cb695b89b6ecd02c581a8432b4",
      "tree": "1c43b828c8c8e15aac65a57628f3b25eb020ef9a",
      "parents": [
        "a1f6f222ec7bc16423aa1c6ed74c36c5f191c9f2"
      ],
      "author": {
        "name": "Samuel A. Falvo II",
        "email": "sam.falvo@rackspace.com",
        "time": "Thu Jun 20 15:18:43 2013 -0700"
      },
      "committer": {
        "name": "Samuel A. Falvo II",
        "email": "sam.falvo@rackspace.com",
        "time": "Thu Jun 20 15:18:43 2013 -0700"
      },
      "message": "Script to automate environment creation\n"
    },
    {
      "commit": "a1f6f222ec7bc16423aa1c6ed74c36c5f191c9f2",
      "tree": "e521c99b28b4f33b139808b939e2fd9f99007387",
      "parents": [],
      "author": {
        "name": "Glen Campbell",
        "email": "glen@broadpool.com",
        "time": "Thu Jun 20 11:10:46 2013 -0700"
      },
      "committer": {
        "name": "Glen Campbell",
        "email": "glen@broadpool.com",
        "time": "Thu Jun 20 11:10:46 2013 -0700"
      },
      "message": "Initial commit\n"
    }
  ]
}
