protected Void doInBackground(List<LotLocation>... locations) {
      try {
        int count = locations[0].size();
        for (LotLocation placemark : locations[0]) {
          ReplaceableAttribute descriptionAttribute =
              new ReplaceableAttribute("description", placemark.getDescription(), Boolean.TRUE);
          ReplaceableAttribute latAttribute =
              new ReplaceableAttribute(
                  "lat", String.valueOf(placemark.getPoint().latitude), Boolean.TRUE);
          ReplaceableAttribute lngAttribute =
              new ReplaceableAttribute(
                  "lng", String.valueOf(placemark.getPoint().longitude), Boolean.TRUE);

          List attrs = new ArrayList(3);
          attrs.add(descriptionAttribute);
          attrs.add(latAttribute);
          attrs.add(lngAttribute);

          PutAttributesRequest par =
              new PutAttributesRequest(
                  "Locations", new Generator().getRandomID("LOT-ADMIN-"), attrs);
          SimpleDB.getInstance().putAttributes(par);

          publishProgress((int) ((count-- / (float) locations[0].size()) * 100));
        }
      } catch (Exception e) {
        Log.e("LoadLocationsTask", "Failure attempting to load locations in background task", e);
      }

      return null;
    }
    @Override
    protected void onPostExecute(TreeMap<Float, DropsiteLocation> result) {
      Log.d("GetDropsiteTask", result.size() + " total locations obtained");

      int count = RETURN_COUNT;
      List<DropsiteLocation> locations = new ArrayList<DropsiteLocation>();
      for (Map.Entry<Float, DropsiteLocation> l : result.entrySet()) {
        locations.add(l.getValue());

        // only return a subset of the overall count
        if (--count == 0) break;
      }

      Log.d(
          "GetDropsitesTask",
          "Passing "
              + mGetDropsiteLocationsCompleteListeners.size()
              + " listeners "
              + locations.size()
              + " locations");
      // notify all listeners that work is complete
      for (GetDropsiteLocationsCompleteListener listener : mGetDropsiteLocationsCompleteListeners) {
        listener.onDropsiteLocationFetchComplete(locations);
      }
    }
  public void loadLocationsAsync(String kml) {
    List<LotLocation> locations = new ArrayList<LotLocation>();

    try {
      XMLReader parser = XMLReaderFactory.createXMLReader("org.ccil.cowan.tagsoup.Parser");
      InputStream is = new ByteArrayInputStream(kml.getBytes());

      // build out an XML document using TagSoup
      Document doc = new Builder(parser).build(is);

      // set the ns of the document as the XPathContext or we will not find the elements when we
      // attempt to parse
      XPathContext context = new XPathContext("ns", "http://www.w3.org/1999/xhtml");

      // get the Placemark nodes within the data
      Nodes nodes = doc.query(".//ns:Placemark", context);

      for (int index = 0; index < nodes.size(); index++) {
        LotLocation placemark = new LotLocation();
        Node placemarkNode = nodes.get(index);

        Node nameNode = placemarkNode.query("ns:name", context).get(0);
        if (nameNode != null) placemark.setLocation(nameNode.getValue());

        Node descriptionNode = placemarkNode.query("ns:description", context).get(0);
        if (descriptionNode != null) placemark.setDescription(descriptionNode.getValue());

        Node lnglatNode = placemarkNode.query("ns:Point/ns:coordinates", context).get(0);
        if (lnglatNode != null) {
          // get longitude,latitude,altitude, per KML spec
          String[] points = lnglatNode.getValue().split(",");
          placemark.setPoint(
              new LatLng(
                  Double.parseDouble(points[1].trim()), Double.parseDouble(points[0].trim())));
        }

        locations.add(placemark);
      }

      // spin off a new thread and load locations
      new LoadLocationsTask().execute(locations);

    } catch (Exception e) {
      Log.e("LoadLocationsTask", "Failure attempting to load locations", e);
    }
  }