text:
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

this.EXPORTED_SYMBOLS = ['BookmarksEngine', "PlacesItem", "Bookmark",
                         "BookmarkFolder", "BookmarkQuery",
                         "Livemark", "BookmarkSeparator"];

const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;

Cu.import("resource://gre/modules/PlacesUtils.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://services-common/async.js");
Cu.import("resource://services-sync/constants.js");
Cu.import("resource://services-sync/engines.js");
Cu.import("resource://services-sync/record.js");
Cu.import("resource://services-sync/util.js");
Cu.import("resource://gre/modules/Task.jsm");
Cu.import("resource://gre/modules/PlacesBackups.jsm");

const ALLBOOKMARKS_ANNO    = "AllBookmarks";
const DESCRIPTION_ANNO     = "bookmarkProperties/description";
const SIDEBAR_ANNO         = "bookmarkProperties/loadInSidebar";
const MOBILEROOT_ANNO      = "mobile/bookmarksRoot";
const MOBILE_ANNO          = "MobileBookmarks";
const EXCLUDEBACKUP_ANNO   = "places/excludeFromBackup";
const SMART_BOOKMARKS_ANNO = "Places/SmartBookmark";
const PARENT_ANNO          = "sync/parent";
const ORGANIZERQUERY_ANNO  = "PlacesOrganizer/OrganizerQuery";
const ANNOS_TO_TRACK = [DESCRIPTION_ANNO, SIDEBAR_ANNO,
                        PlacesUtils.LMANNO_FEEDURI, PlacesUtils.LMANNO_SITEURI];

const SERVICE_NOT_SUPPORTED = "Service not supported on this platform";
const FOLDER_SORTINDEX = 1000000;

this.PlacesItem = function PlacesItem(collection, id, type) {
  CryptoWrapper.call(this, collection, id);
  this.type = type || "item";
}
PlacesItem.prototype = {
  decrypt: function PlacesItem_decrypt(keyBundle) {
    // Do the normal CryptoWrapper decrypt, but change types before returning
    let clear = CryptoWrapper.prototype.decrypt.call(this, keyBundle);

    // Convert the abstract places item to the actual object type
    if (!this.deleted)
      this.__proto__ = this.getTypeObject(this.type).prototype;

    return clear;
  },

  getTypeObject: function PlacesItem_getTypeObject(type) {
    switch (type) {
      case "bookmark":
      case "microsummary":
        return Bookmark;
      case "query":
        return BookmarkQuery;
      case "folder":
        return BookmarkFolder;
      case "livemark":
        return Livemark;
      case "separator":
        return BookmarkSeparator;
      case "item":
        return PlacesItem;
    }
    throw "Unknown places item object type: " + type;
  },

  __proto__: CryptoWrapper.prototype,
  _logName: "Sync.Record.PlacesItem",
};

Utils.deferGetSet(PlacesItem,
                  "cleartext",
                  ["hasDupe", "parentid", "parentName", "type"]);

this.Bookmark = function Bookmark(collection, id, type) {
  PlacesItem.call(this, collection, id, type || "bookmark");
}
Bookmark.prototype = {
  __proto__: PlacesItem.prototype,
  _logName: "Sync.Record.Bookmark",
};

Utils.deferGetSet(Bookmark,
                  "cleartext",
                  ["title", "bmkUri", "description",
                   "loadInSidebar", "tags", "keyword"]);

this.BookmarkQuery = function BookmarkQuery(collection, id) {
  Bookmark.call(this, collection, id, "query");
}
BookmarkQuery.prototype = {
  __proto__: Bookmark.prototype,
  _logName: "Sync.Record.BookmarkQuery",
};

Utils.deferGetSet(BookmarkQuery,
                  "cleartext",
                  ["folderName", "queryId"]);

this.BookmarkFolder = function BookmarkFolder(collection, id, type) {
  PlacesItem.call(this, collection, id, type || "folder");
}
BookmarkFolder.prototype = {
  __proto__: PlacesItem.prototype,
  _logName: "Sync.Record.Folder",
};

Utils.deferGetSet(BookmarkFolder, "cleartext", ["description", "title",
                                                "children"]);

this.Livemark = function Livemark(collection, id) {
  BookmarkFolder.call(this, collection, id, "livemark");
}
Livemark.prototype = {
  __proto__: BookmarkFolder.prototype,
  _logName: "Sync.Record.Livemark",
};

Utils.deferGetSet(Livemark, "cleartext", ["siteUri", "feedUri"]);

this.BookmarkSeparator = function BookmarkSeparator(collection, id) {
  PlacesItem.call(this, collection, id, "separator");
}
BookmarkSeparator.prototype = {
  __proto__: PlacesItem.prototype,
  _logName: "Sync.Record.Separator",
};

Utils.deferGetSet(BookmarkSeparator, "cleartext", "pos");

let kSpecialIds = {

  // Special IDs. Note that mobile can attempt to create a record on
  // dereference; special accessors are provided to prevent recursion within
  // observers.
  guids: ["menu", "places", "tags", "toolbar", "unfiled", "mobile"],

  // Create the special mobile folder to store mobile bookmarks.
  createMobileRoot: function createMobileRoot() {
    let root = PlacesUtils.placesRootId;
    let mRoot = PlacesUtils.bookmarks.createFolder(root, "mobile", -1);
    PlacesUtils.annotations.setItemAnnotation(
      mRoot, MOBILEROOT_ANNO, 1, 0, PlacesUtils.annotations.EXPIRE_NEVER);
    PlacesUtils.annotations.setItemAnnotation(
      mRoot, EXCLUDEBACKUP_ANNO, 1, 0, PlacesUtils.annotations.EXPIRE_NEVER);
    return mRoot;
  },

  findMobileRoot: function findMobileRoot(create) {
    // Use the (one) mobile root if it already exists.
    let root = PlacesUtils.annotations.getItemsWithAnnotation(MOBILEROOT_ANNO, {});
    if (root.length != 0)
      return root[0];

    if (create)
      return this.createMobileRoot();

    return null;
  },

  // Accessors for IDs.
  isSpecialGUID: function isSpecialGUID(g) {
    return this.guids.indexOf(g) != -1;
  },

  specialIdForGUID: function specialIdForGUID(guid, create) {
    if (guid == "mobile") {
      return this.findMobileRoot(create);
    }
    return this[guid];
  },

  // Don't bother creating mobile: if it doesn't exist, this ID can't be it!
  specialGUIDForId: function specialGUIDForId(id) {
    for each (let guid in this.guids)
      if (this.specialIdForGUID(guid, false) == id)
        return guid;
    return null;
  },

  get menu()    PlacesUtils.bookmarksMenuFolderId,
  get places()  PlacesUtils.placesRootId,
  get tags()    PlacesUtils.tagsFolderId,
  get toolbar() PlacesUtils.toolbarFolderId,
  get unfiled() PlacesUtils.unfiledBookmarksFolderId,
  get mobile()  this.findMobileRoot(true),
};

this.BookmarksEngine = function BookmarksEngine(service) {
  SyncEngine.call(this, "Bookmarks", service);
}
BookmarksEngine.prototype = {
  __proto__: SyncEngine.prototype,
  _recordObj: PlacesItem,
  _storeObj: BookmarksStore,
  _trackerObj: BookmarksTracker,
  version: 2,

  _sync: function _sync() {
    let engine = this;
    let batchEx = null;

    // Try running sync in batch mode
    PlacesUtils.bookmarks.runInBatchMode({
      runBatched: function wrappedSync() {
        try {
          SyncEngine.prototype._sync.call(engine);
        }
        catch(ex) {
          batchEx = ex;
        }
      }
    }, null);

    // Expose the exception if something inside the batch failed
    if (batchEx != null) {
      throw batchEx;
    }
  },

  _guidMapFailed: false,
  _buildGUIDMap: function _buildGUIDMap() {
    let guidMap = {};
    for (let guid in this._store.getAllIDs()) {
      // Figure out with which key to store the mapping.
      let key;
      let id = this._store.idForGUID(guid);
      switch (PlacesUtils.bookmarks.getItemType(id)) {
        case PlacesUtils.bookmarks.TYPE_BOOKMARK:

          // Smart bookmarks map to their annotation value.
          let queryId;
          try {
            queryId = PlacesUtils.annotations.getItemAnnotation(
              id, SMART_BOOKMARKS_ANNO);
          } catch(ex) {}

          if (queryId)
            key = "q" + queryId;
          else
            key = "b" + PlacesUtils.bookmarks.getBookmarkURI(id).spec + ":" +
                  PlacesUtils.bookmarks.getItemTitle(id);
          break;
        case PlacesUtils.bookmarks.TYPE_FOLDER:
          key = "f" + PlacesUtils.bookmarks.getItemTitle(id);
          break;
        case PlacesUtils.bookmarks.TYPE_SEPARATOR:
          key = "s" + PlacesUtils.bookmarks.getItemIndex(id);
          break;
        default:
          continue;
      }

      // The mapping is on a per parent-folder-name basis.
      let parent = PlacesUtils.bookmarks.getFolderIdForItem(id);
      if (parent <= 0)
        continue;

      let parentName = PlacesUtils.bookmarks.getItemTitle(parent);
      if (guidMap[parentName] == null)
        guidMap[parentName] = {};

      // If the entry already exists, remember that there are explicit dupes.
      let entry = new String(guid);
      entry.hasDupe = guidMap[parentName][key] != null;

      // Remember this item's GUID for its parent-name/key pair.
      guidMap[parentName][key] = entry;
      this._log.trace("Mapped: " + [parentName, key, entry, entry.hasDupe]);
    }

    return guidMap;
  },

  // Helper function to get a dupe GUID for an item.
  _mapDupe: function _mapDupe(item) {
    // Figure out if we have something to key with.
    let key;
    let altKey;
    switch (item.type) {
      case "query":
        // Prior to Bug 610501, records didn't carry their Smart Bookmark
        // anno, so we won't be able to dupe them correctly. This altKey
        // hack should get them to dupe correctly.
        if (item.queryId) {
          key = "q" + item.queryId;
          altKey = "b" + item.bmkUri + ":" + item.title;
          break;
        }
        // No queryID? Fall through to the regular bookmark case.
      case "bookmark":
      case "microsummary":
        key = "b" + item.bmkUri + ":" + item.title;
        break;
      case "folder":
      case "livemark":
        key = "f" + item.title;
        break;
      case "separator":
        key = "s" + item.pos;
        break;
      default:
        return;
    }

    // Figure out if we have a map to use!
    // This will throw in some circumstances. That's fine.
    let guidMap = this._guidMap;

    // Give the GUID if we have the matching pair.
    this._log.trace("Finding mapping: " + item.parentName + ", " + key);
    let parent = guidMap[item.parentName];

    if (!parent) {
      this._log.trace("No parent => no dupe.");
      return undefined;
    }

    let dupe = parent[key];

    if (dupe) {
      this._log.trace("Mapped dupe: " + dupe);
      return dupe;
    }

    if (altKey) {
      dupe = parent[altKey];
      if (dupe) {
        this._log.trace("Mapped dupe using altKey " + altKey + ": " + dupe);
        return dupe;
      }
    }

    this._log.trace("No dupe found for key " + key + "/" + altKey + ".");
    return undefined;
  },

  _syncStartup: function _syncStart() {
    SyncEngine.prototype._syncStartup.call(this);

    let cb = Async.makeSpinningCallback();
    Task.spawn(function() {
      // For first-syncs, make a backup for the user to restore
      if (this.lastSync == 0) {
        this._log.debug("Bookmarks backup starting.");
        yield PlacesBackups.create(null, true);
        this._log.debug("Bookmarks backup done.");
      }
    }.bind(this)).then(
      cb, ex => {
        // Failure to create a backup is somewhat bad, but probably not bad
        // enough to prevent syncing of bookmarks - so just log the error and
        // continue.
        this._log.warn("Got exception \"" + Utils.exceptionStr(ex) +
                       "\" backing up bookmarks, but continuing with sync.");
        cb();
      }
    );

    cb.wait();

    this.__defineGetter__("_guidMap", function() {
      // Create a mapping of folder titles and separator positions to GUID.
      // We do this lazily so that we don't do any work unless we reconcile
      // incoming items.
      let guidMap;
      try {
        guidMap = this._buildGUIDMap();
      } catch (ex) {
        this._log.warn("Got exception \"" + Utils.exceptionStr(ex) +
                       "\" building GUID map." +
                       " Skipping all other incoming items.");
        throw {code: Engine.prototype.eEngineAbortApplyIncoming,
               cause: ex};
      }
      delete this._guidMap;
      return this._guidMap = guidMap;
    });

    this._store._childrenToOrder = {};
  },

  _processIncoming: function (newitems) {
    try {
      SyncEngine.prototype._processIncoming.call(this, newitems);
    } finally {
      // Reorder children.
      this._tracker.ignoreAll = true;
      this._store._orderChildren();
      this._tracker.ignoreAll = false;
      delete this._store._childrenToOrder;
    }
  },

  _syncFinish: function _syncFinish() {
    SyncEngine.prototype._syncFinish.call(this);
    this._tracker._ensureMobileQuery();
  },

  _syncCleanup: function _syncCleanup() {
    SyncEngine.prototype._syncCleanup.call(this);
    delete this._guidMap;
  },

  _createRecord: function _createRecord(id) {
    // Create the record as usual, but mark it as having dupes if necessary.
    let record = SyncEngine.prototype._createRecord.call(this, id);
    let entry = this._mapDupe(record);
    if (entry != null && entry.hasDupe) {
      record.hasDupe = true;
    }
    return record;
  },

  _findDupe: function _findDupe(item) {
    this._log.trace("Finding dupe for " + item.id +
                    " (already duped: " + item.hasDupe + ").");

    // Don't bother finding a dupe if the incoming item has duplicates.
    if (item.hasDupe) {
      this._log.trace(item.id + " already a dupe: not finding one.");
      return;
    }
    let mapped = this._mapDupe(item);
    this._log.debug(item.id + " mapped to " + mapped);
    return mapped;
  }
};

function BookmarksStore(name, engine) {
  Store.call(this, name, engine);

  // Explicitly nullify our references to our cached services so we don't leak
  Svc.Obs.add("places-shutdown", function() {
    for each (let [query, stmt] in Iterator(this._stmts)) {
      stmt.finalize();
    }
    this._stmts = {};
  }, this);
}
BookmarksStore.prototype = {
  __proto__: Store.prototype,

  itemExists: function BStore_itemExists(id) {
    return this.idForGUID(id, true) > 0;
  },

  /*
   * If the record is a tag query, rewrite it to refer to the local tag ID.
   *
   * Otherwise, just return.
   */
  preprocessTagQuery: function preprocessTagQuery(record) {
    if (record.type != "query" ||
        record.bmkUri == null ||
        !record.folderName)
      return;

    // Yes, this works without chopping off the "place:" prefix.
    let uri           = record.bmkUri
    let queriesRef    = {};
    let queryCountRef = {};
    let optionsRef    = {};
    PlacesUtils.history.queryStringToQueries(uri, queriesRef, queryCountRef,
                                             optionsRef);

    // We only process tag URIs.
    if (optionsRef.value.resultType != optionsRef.value.RESULTS_AS_TAG_CONTENTS)
      return;

    // Tag something to ensure that the tag exists.
    let tag = record.folderName;
    let dummyURI = Utils.makeURI("about:weave#BStore_preprocess");
    PlacesUtils.tagging.tagURI(dummyURI, [tag]);

    // Look for the id of the tag, which might just have been added.
    let tags = this._getNode(PlacesUtils.tagsFolderId);
    if (!(tags instanceof Ci.nsINavHistoryQueryResultNode)) {
      this._log.debug("tags isn't an nsINavHistoryQueryResultNode; aborting.");
      return;
    }

    tags.containerOpen = true;
    try {
      for (let i = 0; i < tags.childCount; i++) {
        let child = tags.getChild(i);
        if (child.title == tag) {
          // Found the tag, so fix up the query to use the right id.
          this._log.debug("Tag query folder: " + tag + " = " + child.itemId);

          this._log.trace("Replacing folders in: " + uri);
          for each (let q in queriesRef.value)
            q.setFolders([child.itemId], 1);

          record.bmkUri = PlacesUtils.history.queriesToQueryString(
            queriesRef.value, queryCountRef.value, optionsRef.value);
          return;
        }
      }
    }
    finally {
      tags.containerOpen = false;
    }
  },

  applyIncoming: function BStore_applyIncoming(record) {
    this._log.debug("Applying record " + record.id);
    let isSpecial = record.id in kSpecialIds;

    if (record.deleted) {
      if (isSpecial) {
        this._log.warn("Ignoring deletion for special record " + record.id);
        return;
      }

      // Don't bother with pre and post-processing for deletions.
      Store.prototype.applyIncoming.call(this, record);
      return;
    }

    // For special folders we're only interested in child ordering.
    if (isSpecial && record.children) {
      this._log.debug("Processing special node: " + record.id);
      // Reorder children later
      this._childrenToOrder[record.id] = record.children;
      return;
    }

    // Skip malformed records. (Bug 806460.)
    if (record.type == "query" &&
        !record.bmkUri) {
      this._log.warn("Skipping malformed query bookmark: " + record.id);
      return;
    }

    // Preprocess the record before doing the normal apply.
    this.preprocessTagQuery(record);

    // Figure out the local id of the parent GUID if available
    let parentGUID = record.parentid;
    if (!parentGUID) {
      throw "Record " + record.id + " has invalid parentid: " + parentGUID;
    }
    this._log.debug("Local parent is " + parentGUID);

    let parentId = this.idForGUID(parentGUID);
    if (parentId > 0) {
      // Save the parent id for modifying the bookmark later
      record._parent = parentId;
      record._orphan = false;
      this._log.debug("Record " + record.id + " is not an orphan.");
    } else {
      this._log.trace("Record " + record.id +
                      " is an orphan: could not find parent " + parentGUID);
      record._orphan = true;
    }

    // Do the normal processing of incoming records
    Store.prototype.applyIncoming.call(this, record);

    // Do some post-processing if we have an item
    let itemId = this.idForGUID(record.id);
    if (itemId > 0) {
      // Move any children that are looking for this folder as a parent
      if (record.type == "folder") {
        this._reparentOrphans(itemId);
        // Reorder children later
        if (record.children)
          this._childrenToOrder[record.id] = record.children;
      }

      // Create an annotation to remember that it needs reparenting.
      if (record._orphan) {
        PlacesUtils.annotations.setItemAnnotation(
          itemId, PARENT_ANNO, parentGUID, 0,
          PlacesUtils.annotations.EXPIRE_NEVER);
      }
    }
  },

  /**
   * Find all ids of items that have a given value for an annotation
   */
  _findAnnoItems: function BStore__findAnnoItems(anno, val) {
    return PlacesUtils.annotations.getItemsWithAnnotation(anno, {})
                      .filter(function(id) {
      return PlacesUtils.annotations.getItemAnnotation(id, anno) == val;
    });
  },

  /**
   * For the provided parent item, attach its children to it
   */
  _reparentOrphans: function _reparentOrphans(parentId) {
    // Find orphans and reunite with this folder parent
    let parentGUID = this.GUIDForId(parentId);
    let orphans = this._findAnnoItems(PARENT_ANNO, parentGUID);

    this._log.debug("Reparenting orphans " + orphans + " to " + parentId);
    orphans.forEach(function(orphan) {
      // Move the orphan to the parent and drop the missing parent annotation
      if (this._reparentItem(orphan, parentId)) {
        PlacesUtils.annotations.removeItemAnnotation(orphan, PARENT_ANNO);
      }
    }, this);
  },

  _reparentItem: function _reparentItem(itemId, parentId) {
    this._log.trace("Attempting to move item " + itemId + " to new parent " +
                    parentId);
    try {
      if (parentId > 0) {
        PlacesUtils.bookmarks.moveItem(itemId, parentId,
                                       PlacesUtils.bookmarks.DEFAULT_INDEX);
        return true;
      }
    } catch(ex) {
      this._log.debug("Failed to reparent item. " + Utils.exceptionStr(ex));
    }
    return false;
  },

  // Turn a record's nsINavBookmarksService constant and other attributes into
  // a granular type for comparison.
  _recordType: function _recordType(itemId) {
    let bms  = PlacesUtils.bookmarks;
    let type = bms.getItemType(itemId);

    switch (type) {
      case bms.TYPE_FOLDER:
        if (PlacesUtils.annotations
                       .itemHasAnnotation(itemId, PlacesUtils.LMANNO_FEEDURI)) {
          return "livemark";
        }
        return "folder";

      case bms.TYPE_BOOKMARK:
        let bmkUri = bms.getBookmarkURI(itemId).spec;
        if (bmkUri.indexOf("place:") == 0) {
          return "query";
        }
        return "bookmark";

      case bms.TYPE_SEPARATOR:
        return "separator";

      default:
        return null;
    }
  },

  create: function BStore_create(record) {
    // Default to unfiled if we don't have the parent yet.

    // Valid parent IDs are all positive integers. Other values -- undefined,
    // null, -1 -- all compare false for > 0, so this catches them all. We
    // don't just use <= without the !, because undefined and null compare
    // false for that, too!
    if (!(record._parent > 0)) {
      this._log.debug("Parent is " + record._parent + "; reparenting to unfiled.");
      record._parent = kSpecialIds.unfiled;
    }

    let newId;
    switch (record.type) {
    case "bookmark":
    case "query":
    case "microsummary": {
      let uri = Utils.makeURI(record.bmkUri);
      newId = PlacesUtils.bookmarks.insertBookmark(
        record._parent, uri, PlacesUtils.bookmarks.DEFAULT_INDEX, record.title);
      this._log.debug("created bookmark " + newId + " under " + record._parent
                      + " as " + record.title + " " + record.bmkUri);

      // Smart bookmark annotations are strings.
      if (record.queryId) {
        PlacesUtils.annotations.setItemAnnotation(
          newId, SMART_BOOKMARKS_ANNO, record.queryId, 0,
          PlacesUtils.annotations.EXPIRE_NEVER);
      }

      if (Array.isArray(record.tags)) {
        this._tagURI(uri, record.tags);
      }
      PlacesUtils.bookmarks.setKeywordForBookmark(newId, record.keyword);
      if (record.description) {
        PlacesUtils.annotations.setItemAnnotation(
          newId, DESCRIPTION_ANNO, record.description, 0,
          PlacesUtils.annotations.EXPIRE_NEVER);
      }

      if (record.loadInSidebar) {
        PlacesUtils.annotations.setItemAnnotation(
          newId, SIDEBAR_ANNO, true, 0,
          PlacesUtils.annotations.EXPIRE_NEVER);
      }

    } break;
    case "folder":
      newId = PlacesUtils.bookmarks.createFolder(
        record._parent, record.title, PlacesUtils.bookmarks.DEFAULT_INDEX);
      this._log.debug("created folder " + newId + " under " + record._parent
                      + " as " + record.title);

      if (record.description) {
        PlacesUtils.annotations.setItemAnnotation(
          newId, DESCRIPTION_ANNO, record.description, 0,
          PlacesUtils.annotations.EXPIRE_NEVER);
      }

      // record.children will be dealt with in _orderChildren.
      break;
    case "livemark":
      let siteURI = null;
      if (!record.feedUri) {
        this._log.debug("No feed URI: skipping livemark record " + record.id);
        return;
      }
      if (PlacesUtils.annotations
                     .itemHasAnnotation(record._parent, PlacesUtils.LMANNO_FEEDURI)) {
        this._log.debug("Invalid parent: skipping livemark record " + record.id);
        return;
      }

      if (record.siteUri != null)
        siteURI = Utils.makeURI(record.siteUri);

      // Until this engine can handle asynchronous error reporting, we need to
      // detect errors on creation synchronously.
      let spinningCb = Async.makeSpinningCallback();

      let livemarkObj = {title: record.title,
                         parentId: record._parent,
                         index: PlacesUtils.bookmarks.DEFAULT_INDEX,
                         feedURI: Utils.makeURI(record.feedUri),
                         siteURI: siteURI,
                         guid: record.id};
      PlacesUtils.livemarks.addLivemark(livemarkObj).then(
        aLivemark => { spinningCb(null, [Components.results.NS_OK, aLivemark]) },
        () => { spinningCb(null, [Components.results.NS_ERROR_UNEXPECTED, aLivemark]) }
      );

      let [status, livemark] = spinningCb.wait();
      if (!Components.isSuccessCode(status)) {
        throw status;
      }

      this._log.debug("Created livemark " + livemark.id + " under " +
                      livemark.parentId + " as " + livemark.title +
                      ", " + livemark.siteURI.spec + ", " +
                      livemark.feedURI.spec + ", GUID " +
                      livemark.guid);
      break;
    case "separator":
      newId = PlacesUtils.bookmarks.insertSeparator(
        record._parent, PlacesUtils.bookmarks.DEFAULT_INDEX);
      this._log.debug("created separator " + newId + " under " + record._parent);
      break;
    case "item":
      this._log.debug(" -> got a generic places item.. do nothing?");
      return;
    default:
      this._log.error("_create: Unknown item type: " + record.type);
      return;
    }

    if (newId) {
      // Livemarks can set the GUID through the API, so there's no need to
      // do that here.
      this._log.trace("Setting GUID of new item " + newId + " to " + record.id);
      this._setGUID(newId, record.id);
    }
  },

  // Factored out of `remove` to avoid redundant DB queries when the Places ID
  // is already known.
  removeById: function removeById(itemId, guid) {
    let type = PlacesUtils.bookmarks.getItemType(itemId);

    switch (type) {
    case PlacesUtils.bookmarks.TYPE_BOOKMARK:
      this._log.debug("  -> removing bookmark " + guid);
      PlacesUtils.bookmarks.removeItem(itemId);
      break;
    case PlacesUtils.bookmarks.TYPE_FOLDER:
      this._log.debug("  -> removing folder " + guid);
      PlacesUtils.bookmarks.removeItem(itemId);
      break;
    case PlacesUtils.bookmarks.TYPE_SEPARATOR:
      this._log.debug("  -> removing separator " + guid);
      PlacesUtils.bookmarks.removeItem(itemId);
      break;
    default:
      this._log.error("remove: Unknown item type: " + type);
      break;
    }
  },

  remove: function BStore_remove(record) {
    if (kSpecialIds.isSpecialGUID(record.id)) {
      this._log.warn("Refusing to remove special folder " + record.id);
      return;
    }

    let itemId = this.idForGUID(record.id);
    if (itemId <= 0) {
      this._log.debug("Item " + record.id + " already removed");
      return;
    }
    this.removeById(itemId, record.id);
  },

  _taggableTypes: ["bookmark", "microsummary", "query"],
  isTaggable: function isTaggable(recordType) {
    return this._taggableTypes.indexOf(recordType) != -1;
  },

  update: function BStore_update(record) {
    let itemId = this.idForGUID(record.id);

    if (itemId <= 0) {
      this._log.debug("Skipping update for unknown item: " + record.id);
      return;
    }

    // Two items are the same type if they have the same ItemType in Places,
    // and also share some key characteristics (e.g., both being livemarks).
    // We figure this out by examining the item to find the equivalent granular
    // (string) type.
    // If they're not the same type, we can't just update attributes. Delete
    // then recreate the record instead.
    let localItemType    = this._recordType(itemId);
    let remoteRecordType = record.type;
    this._log.trace("Local type: " + localItemType + ". " +
                    "Remote type: " + remoteRecordType + ".");

    if (localItemType != remoteRecordType) {
      this._log.debug("Local record and remote record differ in type. " +
                      "Deleting and recreating.");
      this.removeById(itemId, record.id);
      this.create(record);
      return;
    }

    this._log.trace("Updating " + record.id + " (" + itemId + ")");

    // Move the bookmark to a new parent or new position if necessary
    if (record._parent > 0 &&
        PlacesUtils.bookmarks.getFolderIdForItem(itemId) != record._parent) {
      this._reparentItem(itemId, record._parent);
    }

    for (let [key, val] in Iterator(record.cleartext)) {
      switch (key) {
      case "title":
        PlacesUtils.bookmarks.setItemTitle(itemId, val);
        break;
      case "bmkUri":
        PlacesUtils.bookmarks.changeBookmarkURI(itemId, Utils.makeURI(val));
        break;
      case "tags":
        if (Array.isArray(val)) {
          if (this.isTaggable(remoteRecordType)) {
            this._tagID(itemId, val);
          } else {
            this._log.debug("Remote record type is invalid for tags: " + remoteRecordType);
          }
        }
        break;
      case "keyword":
        PlacesUtils.bookmarks.setKeywordForBookmark(itemId, val);
        break;
      case "description":
        if (val) {
          PlacesUtils.annotations.setItemAnnotation(
            itemId, DESCRIPTION_ANNO, val, 0,
            PlacesUtils.annotations.EXPIRE_NEVER);
        } else {
          PlacesUtils.annotations.removeItemAnnotation(itemId, DESCRIPTION_ANNO);
        }
        break;
      case "loadInSidebar":
        if (val) {
          PlacesUtils.annotations.setItemAnnotation(
            itemId, SIDEBAR_ANNO, true, 0,
            PlacesUtils.annotations.EXPIRE_NEVER);
        } else {
          PlacesUtils.annotations.removeItemAnnotation(itemId, SIDEBAR_ANNO);
        }
        break;
      case "queryId":
        PlacesUtils.annotations.setItemAnnotation(
          itemId, SMART_BOOKMARKS_ANNO, val, 0,
          PlacesUtils.annotations.EXPIRE_NEVER);
        break;
      }
    }
  },

  _orderChildren: function _orderChildren() {
    for (let [guid, children] in Iterator(this._childrenToOrder)) {
      // Reorder children according to the GUID list. Gracefully deal
      // with missing items, e.g. locally deleted.
      let delta = 0;
      let parent = null;
      for (let idx = 0; idx < children.length; idx++) {
        let itemid = this.idForGUID(children[idx]);
        if (itemid == -1) {
          delta += 1;
          this._log.trace("Could not locate record " + children[idx]);
          continue;
        }
        try {
          // This code path could be optimized by caching the parent earlier.
          // Doing so should take in count any edge case due to reparenting
          // or parent invalidations though.
          if (!parent) {
            parent = PlacesUtils.bookmarks.getFolderIdForItem(itemid);
          }
          PlacesUtils.bookmarks.moveItem(itemid, parent, idx - delta);
        } catch (ex) {
          this._log.debug("Could not move item " + children[idx] + ": " + ex);
        }
      }
    }
  },

  changeItemID: function BStore_changeItemID(oldID, newID) {
    this._log.debug("Changing GUID " + oldID + " to " + newID);

    // Make sure there's an item to change GUIDs
    let itemId = this.idForGUID(oldID);
    if (itemId <= 0)
      return;

    this._setGUID(itemId, newID);
  },

  _getNode: function BStore__getNode(folder) {
    let query = PlacesUtils.history.getNewQuery();
    query.setFolders([folder], 1);
    return PlacesUtils.history.executeQuery(
      query, PlacesUtils.history.getNewQueryOptions()).root;
  },

  _getTags: function BStore__getTags(uri) {
    try {
      if (typeof(uri) == "string")
        uri = Utils.makeURI(uri);
    } catch(e) {
      this._log.warn("Could not parse URI \"" + uri + "\": " + e);
    }
    return PlacesUtils.tagging.getTagsForURI(uri, {});
  },

  _getDescription: function BStore__getDescription(id) {
    try {
      return PlacesUtils.annotations.getItemAnnotation(id, DESCRIPTION_ANNO);
    } catch (e) {
      return null;
    }
  },

  _isLoadInSidebar: function BStore__isLoadInSidebar(id) {
    return PlacesUtils.annotations.itemHasAnnotation(id, SIDEBAR_ANNO);
  },

  get _childGUIDsStm() {
    return this._getStmt(
      "SELECT id AS item_id, guid " +
      "FROM moz_bookmarks " +
      "WHERE parent = :parent " +
      "ORDER BY position");
  },
  _childGUIDsCols: ["item_id", "guid"],

  _getChildGUIDsForId: function _getChildGUIDsForId(itemid) {
    let stmt = this._childGUIDsStm;
    stmt.params.parent = itemid;
    let rows = Async.querySpinningly(stmt, this._childGUIDsCols);
    return rows.map(function (row) {
      if (row.guid) {
        return row.guid;
      }
      // A GUID hasn't been assigned to this item yet, do this now.
      return this.GUIDForId(row.item_id);
    }, this);
  },

  // Create a record starting from the weave id (places guid)
  createRecord: function createRecord(id, collection) {
    let placeId = this.idForGUID(id);
    let record;
    if (placeId <= 0) { // deleted item
      record = new PlacesItem(collection, id);
      record.deleted = true;
      return record;
    }

    let parent = PlacesUtils.bookmarks.getFolderIdForItem(placeId);
    switch (PlacesUtils.bookmarks.getItemType(placeId)) {
    case PlacesUtils.bookmarks.TYPE_BOOKMARK:
      let bmkUri = PlacesUtils.bookmarks.getBookmarkURI(placeId).spec;
      if (bmkUri.indexOf("place:") == 0) {
        record = new BookmarkQuery(collection, id);

        // Get the actual tag name instead of the local itemId
        let folder = bmkUri.match(/[:&]folder=(\d+)/);
        try {
          // There might not be the tag yet when creating on a new client
          if (folder != null) {
            folder = folder[1];
            record.folderName = PlacesUtils.bookmarks.getItemTitle(folder);
            this._log.trace("query id: " + folder + " = " + record.folderName);
          }
        }
        catch(ex) {}

        // Persist the Smart Bookmark anno, if found.
        try {
          let anno = PlacesUtils.annotations.getItemAnnotation(placeId, SMART_BOOKMARKS_ANNO);
          if (anno != null) {
            this._log.trace("query anno: " + SMART_BOOKMARKS_ANNO +
                            " = " + anno);
            record.queryId = anno;
          }
        }
        catch(ex) {}
      }
      else {
        record = new Bookmark(collection, id);
      }
      record.title = PlacesUtils.bookmarks.getItemTitle(placeId);

      record.parentName = PlacesUtils.bookmarks.getItemTitle(parent);
      record.bmkUri = bmkUri;
      record.tags = this._getTags(record.bmkUri);
      record.keyword = PlacesUtils.bookmarks.getKeywordForBookmark(placeId);
      record.description = this._getDescription(placeId);
      record.loadInSidebar = this._isLoadInSidebar(placeId);
      break;

    case PlacesUtils.bookmarks.TYPE_FOLDER:
      if (PlacesUtils.annotations
                     .itemHasAnnotation(placeId, PlacesUtils.LMANNO_FEEDURI)) {
        record = new Livemark(collection, id);
        let as = PlacesUtils.annotations;
        record.feedUri = as.getItemAnnotation(placeId, PlacesUtils.LMANNO_FEEDURI);
        try {
          record.siteUri = as.getItemAnnotation(placeId, PlacesUtils.LMANNO_SITEURI);
        } catch (ex) {}
      } else {
        record = new BookmarkFolder(collection, id);
      }

      if (parent > 0)
        record.parentName = PlacesUtils.bookmarks.getItemTitle(parent);
      record.title = PlacesUtils.bookmarks.getItemTitle(placeId);
      record.description = this._getDescription(placeId);
      record.children = this._getChildGUIDsForId(placeId);
      break;

    case PlacesUtils.bookmarks.TYPE_SEPARATOR:
      record = new BookmarkSeparator(collection, id);
      if (parent > 0)
        record.parentName = PlacesUtils.bookmarks.getItemTitle(parent);
      // Create a positioning identifier for the separator, used by _mapDupe
      record.pos = PlacesUtils.bookmarks.getItemIndex(placeId);
      break;

    default:
      record = new PlacesItem(collection, id);
      this._log.warn("Unknown item type, cannot serialize: " +
                     PlacesUtils.bookmarks.getItemType(placeId));
    }

    record.parentid = this.GUIDForId(parent);
    record.sortindex = this._calculateIndex(record);

    return record;
  },

  _stmts: {},
  _getStmt: function(query) {
    if (query in this._stmts) {
      return this._stmts[query];
    }

    this._log.trace("Creating SQL statement: " + query);
    let db = PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase)
                        .DBConnection;
    return this._stmts[query] = db.createAsyncStatement(query);
  },

  get _frecencyStm() {
    return this._getStmt(
        "SELECT frecency " +
        "FROM moz_places " +
        "WHERE url = :url " +
        "LIMIT 1");
  },
  _frecencyCols: ["frecency"],

  get _setGUIDStm() {
    return this._getStmt(
      "UPDATE moz_bookmarks " +
      "SET guid = :guid " +
      "WHERE id = :item_id");
  },

  // Some helper functions to handle GUIDs
  _setGUID: function _setGUID(id, guid) {
    if (!guid)
      guid = Utils.makeGUID();

    let stmt = this._setGUIDStm;
    stmt.params.guid = guid;
    stmt.params.item_id = id;
    Async.querySpinningly(stmt);
    return guid;
  },

  get _guidForIdStm() {
    return this._getStmt(
      "SELECT guid " +
      "FROM moz_bookmarks " +
      "WHERE id = :item_id");
  },
  _guidForIdCols: ["guid"],

  GUIDForId: function GUIDForId(id) {
    let special = kSpecialIds.specialGUIDForId(id);
    if (special)
      return special;

    let stmt = this._guidForIdStm;
    stmt.params.item_id = id;

    // Use the existing GUID if it exists
    let result = Async.querySpinningly(stmt, this._guidForIdCols)[0];
    if (result && result.guid)
      return result.guid;

    // Give the uri a GUID if it doesn't have one
    return this._setGUID(id);
  },

  get _idForGUIDStm() {
    return this._getStmt(
      "SELECT id AS item_id " +
      "FROM moz_bookmarks " +
      "WHERE guid = :guid");
  },
  _idForGUIDCols: ["item_id"],

  // noCreate is provided as an optional argument to prevent the creation of
  // non-existent special records, such as "mobile".
  idForGUID: function idForGUID(guid, noCreate) {
    if (kSpecialIds.isSpecialGUID(guid))
      return kSpecialIds.specialIdForGUID(guid, !noCreate);

    let stmt = this._idForGUIDStm;
    // guid might be a String object rather than a string.
    stmt.params.guid = guid.toString();

    let results = Async.querySpinningly(stmt, this._idForGUIDCols);
    this._log.trace("Number of rows matching GUID " + guid + ": "
                    + results.length);

    // Here's the one we care about: the first.
    let result = results[0];

    if (!result)
      return -1;

    return result.item_id;
  },

  _calculateIndex: function _calculateIndex(record) {
    // Ensure folders have a very high sort index so they're not synced last.
    if (record.type == "folder")
      return FOLDER_SORTINDEX;

    // For anything directly under the toolbar, give it a boost of more than an
    // unvisited bookmark
    let index = 0;
    if (record.parentid == "toolbar")
      index += 150;

    // Add in the bookmark's frecency if we have something.
    if (record.bmkUri != null) {
      this._frecencyStm.params.url = record.bmkUri;
      let result = Async.querySpinningly(this._frecencyStm, this._frecencyCols);
      if (result.length)
        index += result[0].frecency;
    }

    return index;
  },

  _getChildren: function BStore_getChildren(guid, items) {
    let node = guid; // the recursion case
    if (typeof(node) == "string") { // callers will give us the guid as the first arg
      let nodeID = this.idForGUID(guid, true);
      if (!nodeID) {
        this._log.debug("No node for GUID " + guid + "; returning no children.");
        return items;
      }
      node = this._getNode(nodeID);
    }

    if (node.type == node.RESULT_TYPE_FOLDER) {
      node.QueryInterface(Ci.nsINavHistoryQueryResultNode);
      node.containerOpen = true;
      try {
        // Remember all the children GUIDs and recursively get more
        for (let i = 0; i < node.childCount; i++) {
          let child = node.getChild(i);
          items[this.GUIDForId(child.itemId)] = true;
          this._getChildren(child, items);
        }
      }
      finally {
        node.containerOpen = false;
      }
    }

    return items;
  },

  /**
   * Associates the URI of the item with the provided ID with the
   * provided array of tags.
   * If the provided ID does not identify an item with a URI,
   * returns immediately.
   */
  _tagID: function _tagID(itemID, tags) {
    if (!itemID || !tags) {
      return;
    }

    try {
      let u = PlacesUtils.bookmarks.getBookmarkURI(itemID);
      this._tagURI(u, tags);
    } catch (e) {
      this._log.warn("Got exception fetching URI for " + itemID + ": not tagging. " +
                     Utils.exceptionStr(e));

      // I guess it doesn't have a URI. Don't try to tag it.
      return;
    }
  },

  /**
   * Associate the provided URI with the provided array of tags.
   * If the provided URI is falsy, returns immediately.
   */
  _tagURI: function _tagURI(bookmarkURI, tags) {
    if (!bookmarkURI || !tags) {
      return;
    }

    // Filter out any null/undefined/empty tags.
    tags = tags.filter(function(t) t);

    // Temporarily tag a dummy URI to preserve tag ids when untagging.
    let dummyURI = Utils.makeURI("about:weave#BStore_tagURI");
    PlacesUtils.tagging.tagURI(dummyURI, tags);
    PlacesUtils.tagging.untagURI(bookmarkURI, null);
    PlacesUtils.tagging.tagURI(bookmarkURI, tags);
    PlacesUtils.tagging.untagURI(dummyURI, null);
  },

  getAllIDs: function BStore_getAllIDs() {
    let items = {"menu": true,
                 "toolbar": true};
    for each (let guid in kSpecialIds.guids) {
      if (guid != "places" && guid != "tags")
        this._getChildren(guid, items);
    }
    return items;
  },

  wipe: function BStore_wipe() {
    let cb = Async.makeSpinningCallback();
    Task.spawn(function() {
      // Save a backup before clearing out all bookmarks.
      yield PlacesBackups.create(null, true);
      for each (let guid in kSpecialIds.guids)
        if (guid != "places") {
          let id = kSpecialIds.specialIdForGUID(guid);
          if (id)
            PlacesUtils.bookmarks.removeFolderChildren(id);
        }
      cb();
    });
    cb.wait();
  }
};

function BookmarksTracker(name, engine) {
  Tracker.call(this, name, engine);

  Svc.Obs.add("places-shutdown", this);
}
BookmarksTracker.prototype = {
  __proto__: Tracker.prototype,

  startTracking: function() {
    PlacesUtils.bookmarks.addObserver(this, true);
    Svc.Obs.add("bookmarks-restore-begin", this);
    Svc.Obs.add("bookmarks-restore-success", this);
    Svc.Obs.add("bookmarks-restore-failed", this);
  },

  stopTracking: function() {
    PlacesUtils.bookmarks.removeObserver(this);
    Svc.Obs.remove("bookmarks-restore-begin", this);
    Svc.Obs.remove("bookmarks-restore-success", this);
    Svc.Obs.remove("bookmarks-restore-failed", this);
  },

  observe: function observe(subject, topic, data) {
    Tracker.prototype.observe.call(this, subject, topic, data);

    switch (topic) {
      case "bookmarks-restore-begin":
        this._log.debug("Ignoring changes from importing bookmarks.");
        this.ignoreAll = true;
        break;
      case "bookmarks-restore-success":
        this._log.debug("Tracking all items on successful import.");
        this.ignoreAll = false;

        this._log.debug("Restore succeeded: wiping server and other clients.");
        this.engine.service.resetClient([this.name]);
        this.engine.service.wipeServer([this.name]);
        this.engine.service.clientsEngine.sendCommand("wipeEngine", [this.name]);
        break;
      case "bookmarks-restore-failed":
        this._log.debug("Tracking all items on failed import.");
        this.ignoreAll = false;
        break;
    }
  },

  QueryInterface: XPCOMUtils.generateQI([
    Ci.nsINavBookmarkObserver,
    Ci.nsINavBookmarkObserver_MOZILLA_1_9_1_ADDITIONS,
    Ci.nsISupportsWeakReference
  ]),

  /**
   * Add a bookmark GUID to be uploaded and bump up the sync score.
   *
   * @param itemGuid
   *        GUID of the bookmark to upload.
   */
  _add: function BMT__add(itemId, guid) {
    guid = kSpecialIds.specialGUIDForId(itemId) || guid;
    if (this.addChangedID(guid))
      this._upScore();
  },

  /* Every add/remove/change will trigger a sync for MULTI_DEVICE. */
  _upScore: function BMT__upScore() {
    this.score += SCORE_INCREMENT_XLARGE;
  },

  /**
   * Determine if a change should be ignored.
   *
   * @param itemId
   *        Item under consideration to ignore
   * @param folder (optional)
   *        Folder of the item being changed
   */
  _ignore: function BMT__ignore(itemId, folder, guid) {
    // Ignore unconditionally if the engine tells us to.
    if (this.ignoreAll)
      return true;

    // Get the folder id if we weren't given one.
    if (folder == null) {
      try {
        folder = PlacesUtils.bookmarks.getFolderIdForItem(itemId);
      } catch (ex) {
        this._log.debug("getFolderIdForItem(" + itemId +
                        ") threw; calling _ensureMobileQuery.");
        // I'm guessing that gFIFI can throw, and perhaps that's why
        // _ensureMobileQuery is here at all. Try not to call it.
        this._ensureMobileQuery();
        folder = PlacesUtils.bookmarks.getFolderIdForItem(itemId);
      }
    }

    // Ignore changes to tags (folders under the tags folder).
    let tags = kSpecialIds.tags;
    if (folder == tags)
      return true;

    // Ignore tag items (the actual instance of a tag for a bookmark).
    if (PlacesUtils.bookmarks.getFolderIdForItem(folder) == tags)
      return true;

    // Make sure to remove items that have the exclude annotation.
    if (PlacesUtils.annotations.itemHasAnnotation(itemId, EXCLUDEBACKUP_ANNO)) {
      this.removeChangedID(guid);
      return true;
    }

    return false;
  },

  onItemAdded: function BMT_onItemAdded(itemId, folder, index,
                                        itemType, uri, title, dateAdded,
                                        guid, parentGuid) {
    if (this._ignore(itemId, folder, guid))
      return;

    this._log.trace("onItemAdded: " + itemId);
    this._add(itemId, guid);
    this._add(folder, parentGuid);
  },

  onItemRemoved: function (itemId, parentId, index, type, uri,
                           guid, parentGuid) {
    if (this._ignore(itemId, parentId, guid)) {
      return;
    }

    this._log.trace("onItemRemoved: " + itemId);
    this._add(itemId, guid);
    this._add(parentId, parentGuid);
  },

  _ensureMobileQuery: function _ensureMobileQuery() {
    let find = function (val)
      PlacesUtils.annotations.getItemsWithAnnotation(ORGANIZERQUERY_ANNO, {}).filter(
        function (id) PlacesUtils.annotations.getItemAnnotation(id, ORGANIZERQUERY_ANNO) == val
      );

    // Don't continue if the Library isn't ready
    let all = find(ALLBOOKMARKS_ANNO);
    if (all.length == 0)
      return;

    // Disable handling of notifications while changing the mobile query
    this.ignoreAll = true;

    let mobile = find(MOBILE_ANNO);
    let queryURI = Utils.makeURI("place:folder=" + kSpecialIds.mobile);
    let title = Str.sync.get("mobile.label");

    // Don't add OR remove the mobile bookmarks if there's nothing.
    if (PlacesUtils.bookmarks.getIdForItemAt(kSpecialIds.mobile, 0) == -1) {
      if (mobile.length != 0)
        PlacesUtils.bookmarks.removeItem(mobile[0]);
    }
    // Add the mobile bookmarks query if it doesn't exist
    else if (mobile.length == 0) {
      let query = PlacesUtils.bookmarks.insertBookmark(all[0], queryURI, -1, title);
      PlacesUtils.annotations.setItemAnnotation(query, ORGANIZERQUERY_ANNO, MOBILE_ANNO, 0,
                                  PlacesUtils.annotations.EXPIRE_NEVER);
      PlacesUtils.annotations.setItemAnnotation(query, EXCLUDEBACKUP_ANNO, 1, 0,
                                  PlacesUtils.annotations.EXPIRE_NEVER);
    }
    // Make sure the existing title is correct
    else if (PlacesUtils.bookmarks.getItemTitle(mobile[0]) != title) {
      PlacesUtils.bookmarks.setItemTitle(mobile[0], title);
    }

    this.ignoreAll = false;
  },

  // This method is oddly structured, but the idea is to return as quickly as
  // possible -- this handler gets called *every time* a bookmark changes, for
  // *each change*.
  onItemChanged: function BMT_onItemChanged(itemId, property, isAnno, value,
                                            lastModified, itemType, parentId,
                                            guid, parentGuid) {
    // Quicker checks first.
    if (this.ignoreAll)
      return;

    if (isAnno && (ANNOS_TO_TRACK.indexOf(property) == -1))
      // Ignore annotations except for the ones that we sync.
      return;

    // Ignore favicon changes to avoid unnecessary churn.
    if (property == "favicon")
      return;

    if (this._ignore(itemId, parentId, guid))
      return;

    this._log.trace("onItemChanged: " + itemId +
                    (", " + property + (isAnno? " (anno)" : "")) +
                    (value ? (" = \"" + value + "\"") : ""));
    this._add(itemId, guid);
  },

  onItemMoved: function BMT_onItemMoved(itemId, oldParent, oldIndex,
                                        newParent, newIndex, itemType,
                                        guid, oldParentGuid, newParentGuid) {
    if (this._ignore(itemId, newParent, guid))
      return;

    this._log.trace("onItemMoved: " + itemId);
    this._add(oldParent, oldParentGuid);
    if (oldParent != newParent) {
      this._add(itemId, guid);
      this._add(newParent, newParentGuid);
    }

    // Remove any position annotations now that the user moved the item
    PlacesUtils.annotations.removeItemAnnotation(itemId, PARENT_ANNO);
  },

  onBeginUpdateBatch: function () {},
  onEndUpdateBatch: function () {},
  onItemVisited: function () {}
};


text:
<?php

namespace GroupMePHP;

class ImageClient extends Client
{
    protected $url = 'https://image.groupme.com';
}

redpajama_set_name: RedPajamaGithub


text:
<?php
require_once (dirname(__FILE__)."/ContentManager.php");
class DefaultContent extends Content{
	//3gphd ,3gp http://m.youku.com/wap/pvs?id=XNDIxOTcyMTU2&format=3gphd
	const BASE_URL="http://m.youku.com/wap/pvs?id={id}&format={format}";

	private $contentparmStart="var videoId2= '"; //
  	private $contentparaend="';";
  	private $htmlparmStart="id_";
  	private $htmlparaend=".html";
  	private $notfound='/wap/wrong';

  	private $p_code="UTF-8";
    public function parseAndroidVideoUrl($url,$p_coding,$p_script){
    	return "";
  	}
  	public function parseAndroidVideoUrlByContent($content, $p_coding,$p_script){
  		return "";
  	}

  	private function getAndroidVideoUrl($vid){
    	return "";
  	}

  	public function checkHtmlCanPlay($url,$p_coding){
//  		$content = getPage($url, $this->p_code);
  		return false;
  	}

    private $p_videocodeApiUrl="http://v.youku.com/player/getM3U8/vid/{PROD_ID}/type/{mType}/ts/{now_date}/useKeyframe/0/v.m3u8";
	private $p_videourlstart="videoId = '";
	private $p_videourlend="'";  //http://v.pptv.com/show/rOeRD3fdTYvubNQ.html
    public function parseIOSVideoUrl($url,$p_coding,$p_script){
    	return "";
  	}

  	public function parseIOSVideoUrlByContent($content, $p_coding,$p_script){
    	return "";
  	}

  }
?>


text:
require "mixi"
require "twitter_client"
require "options"

module Twitter2MixiVoice

  # This constants is Twitter2MixiVoice Application return code.
  Success, Error = 0, 1

  # This class provides mixi bot application.
  class Application

    # constants
    Posted_Tweets_Dir = File.join(ENV["HOME"], ".twitter2mixivoice")
    Posted_File_Name = "posted_tweets.yml"

    # Run Application.
    #
    # [<em>*args</em>]
    #   <tt>command line options.</tt>
    #
    def self.run(args)

      # parse arguments.
      options = Options.new(args, Twitter2MixiVoice::version)

      #
      # check options.
      #
      if options[:invalid_argument]
        $stderr.puts options[:invalid_argument]
        options[:show_help] = true
      end

      if options[:show_version]
        $stdout.puts options[:show_version]
        return Success
      end

      if options[:show_help]
        $stderr.puts options.opts.to_s
        return Error
      end

      result = Error
      begin

        # login to twitter.
        twitter = login_to_twitter(options[:twitter_id], options[:twitter_password])

        # login to mixi.
        mixi = login_to_mixi(options[:mixi_email], options[:mixi_password])

        # read cache tweets from YAML file.
        posted_tweets = read_tweets(Posted_Tweets_Dir, Posted_File_Name)

        # get tweets from twitter.
        tweets = twitter.get_tweets_from_timeline

        # post twitter tweet to mixi voice.
        tweets.each do |tweet|
          if (!posted_tweets.has_key?(tweet.id))
            mixi.post_voice(tweet.text)
            posted_tweets[tweet.id] = tweet
            $stdout.puts "tweet -> voice : id = #{tweet.id}, text = #{tweet.text}"
          end
        end

        # write YAML file from cache tweets.
        result = write_tweets(Posted_Tweets_Dir, Posted_File_Name, posted_tweets)

        result = Success

      rescue MixiException => e
        $stderr.puts "Raise MixiException : #{e.to_s}"
        result = Error
      rescue TwitterClientException => e
        $stderr.puts "Raise MixiException : #{e.to_s}"
        result = Error
      rescue Exception => e
        $stderr.puts "Raise Exception : #{e.to_s}"
        result = Error
      end

      return result

    end # end of 'self.run'

    # private code(s) block ...

    private

    def self.login_to_twitter(id, password)
      TwitterClient.new(id, password)
    end

    def self.login_to_mixi(email, password)
      Mixi.new(email, password)
    end

    def self.read_tweets(dir_path, file_name)
      tweets = {}
      path = File.join(dir_path, file_name)
      File.open(path) { |file| tweets = YAML.load(file) } if FileTest.exist?(path)
      tweets
    end

    def self.write_tweets(dir_path, file_name, tweets)
      Dir.mkdir(dir_path) unless FileTest.exist?(dir_path)
      path = File.join(dir_path, file_name)
      File.open(path, "w+") { |file| YAML.dump(tweets, file) }
    end

    # ... private code(s) block

  end # end of 'Application'

end # end of 'Twitter2MixiVoice'


text:
import React from 'react';
import cx from 'classnames';
import { Link } from 'phenomic';
import { Motion, spring, presets } from 'react-motion';

import s from './index.scss';

type propTypes = {
  className: string,
};

export default (props: propTypes) => (

    <Motion
      defaultStyle={{ opacity: 0 }}
      style={{ opacity: spring(1, presets.stiff) }}
    >
      {styl =>

            atfzl

            Atif Afzal

      }
    </Motion>
    <Motion
      defaultStyle={{ v: 400, opacity: 0 }}
      style={{ v: spring(0, { stiffness: 120, damping: 12 }), opacity: 1 }}
    >
      {styl =>
        <div
          className={s.links}
          style={{ transform: `translate(${styl.v}px)`, opacity: styl.opacity }}
        >
          Github
          <Link to="/posts">Blog</Link>
          LinkedIn
          Twitter

      }
    </Motion>

);


text:
require("grid")
require("tile")
require("dungen")
require("monsters")
world={}

function world.tileAt(x,y)
	return world[y*world.width+x]
end

function world.randomTile(t)
	local attempt=0
	local maxattempts=10000
	local x=0
	local y=0
	while attempt<maxattempts do
		x=math.random(0,world.width-1)
		y=math.random(0,world.height-1)
		if world.tileAt(x,y)==t then
			return x,y

		end
		attempt=attempt+1
	end
end

function world.init(width,height)
	world.width=width
	world.height=height
	for x=0,width-1 do
		for y=0,height-1 do
			local t=tile.floor
			if x==0 or x==width-1 or y==0 or y==height-1 then
				t=tile.wall
			end

			world[y*width+x]=t
		end
	end
	for i=1,1 do
		local mx,my=world.randomTile(tile.floor)
		monsters.newMonster("",mx,my)
		print("monster at: "..mx..","..my)
	end
end

function world.initFile(fileName)
	local file,err=love.filesystem.newFile(fileName,"r")
	print(err)

	local data={}

	for line in file:lines() do
		print(line)
		data[#data+1]=line
	end
	local width=0
	for i,v in ipairs(data) do
		local length=#v

		if length>width then
			width=length
		end

	end
	world.width=width
	world.height=#data
	for y,v in ipairs(data) do
		for x=1,#v do
			local c=v:sub(x,x)
			local t=tile.nothing
			if c=="X" then
				t=tile.wall
			elseif c=="." then
				t=tile.floor
			end
			world[(y-1)*width+(x-1)]=t
		end
	end

	file:close()
end

function world.initGen(width,height)
	local data=dungen.digGen(width,height)
	world.height=height
	world.width=width
	for x=0,width-1 do
		for y=0,height-1 do
			world[y*width+x]=data[y*width+x]
		end
	end
	for i=1,20 do
		local mx,my=world.randomTile(tile.floor)
		monsters.newMonster("",mx,my)
		--print("monster at: "..mx..","..my)
	end
	--[[local times={}
	for i=1,5000 do
		if i%100==0 then
			print(i)
		end
		local sx,sy=world.randomTile(tile.floor)
		local ex,ey=world.randomTile(tile.floor)
		local start=love.timer.getTime()
		pathfind.to(sx,sy,ex,ey)
		local stop=love.timer.getTime()
		times[#times+1]=stop-start
	end
	local sum=0
	for i,v in ipairs(times) do
		sum=sum+v
	end
	local average=sum/#times
	print(#times.." random paths found in: "..sum.." seconds. Average time: "..1000*average.." mils")
	]]--

end

function world.saveWorldAs(fileName)
	local file,err =love.filesystem.newFile(fileName,"w")

	local dat={}
	for y=0,world.height-1 do
		local str=""
		for x=0,world.width-1 do
			local t=world[y*world.width+x]
			if t==tile.wall then
				str=str.."X"
			elseif t==tile.floor then
				str=str.."."
			else
				str=str.." "
			end
		end
		dat[#dat+1]=str
	end
	for i,v in ipairs(dat) do

		file:write(v)
		if i<#dat then
			file:write("\n")
		end
	end
	file:close()

end

function world.isPassable(x,y)
	return world[y*world.width+x].passable
end
function world.isOpaque(x,y)
	return world[y*world.width+x].opaque
end

function world.toGrid(x1,y1,x2,y2)
	for x=x1,x2-1 do
		for y=y1,y2-1 do
			local tile=world[y*world.width+x]
			if tile then
				if player.maps.viewmap[y*world.width+x] then
					grid.setGlyph(x-x1,y-y1,world[y*world.width+x].glyph)
				elseif player.maps.remmap[y*world.width+x] then
					grid.setGlyph(x-x1,y-y1,world[y*world.width+x].remglyph)
				end

			end

		end
	end
end


text:
using System.Xml.Linq;

namespace XMetadata.MetadataDescriptors.Readers
{
    /// <summary>
    /// Definition of the <see cref="ULongMetadataReader"/> class.
    /// </summary>
    public class ULongMetadataReader : AMetadataReader
    {
        #region Properties

        /// <summary>
        /// Gets the metadata reader type.
        /// </summary>
        public override sealed string Type
        {
            get
            {
                return "ulong";
            }
        }

        #endregion // Properties.

        #region Methods

        /// <summary>
        /// Creates the meta data object.
        /// </summary>
        /// <param name="pId">The metadata identifier.</param>
        /// <returns>The new metadata.</returns>
        public override IMetadata Create(string pId)
        {
            return new ULongMetadata(pId);
        }

        /// <summary>
        /// Internal metadata read process.
        /// </summary>
        /// <param name="pToFill"></param>
        /// <param name="pElement"></param>
        protected override void InternalRead(ref IMetadata pToFill, XElement pElement)
        {
            ABoundableMetadata<ulong> lToFill = pToFill as ABoundableMetadata<ulong>;

            XAttribute lXMin = pElement.Attribute(cMetadataMinTag);
            if (lXMin != null)
            {
                ulong lMin;
                if (ulong.TryParse(lXMin.Value, out lMin))
                {
                    lToFill.Min = lMin;
                }
            }

            XAttribute lXMax = pElement.Attribute(cMetadataMaxTag);
            if (lXMax != null)
            {
                ulong lMax;
                if (ulong.TryParse(lXMax.Value, out lMax))
                {
                    lToFill.Max = lMax;
                }
            }
        }

        #endregion // Methods.
    }
}


text:
package com.ubirch.chain.model.db.bigchain

/**
  * author: cvandrei
  * since: 2017-06-29
  */
case class BigchainBlockInfo(id: String)


text:
package org.mwanzia.test;

import org.mwanzia.JsonInclude;

public enum State {
    CA("California"), NY("New York"), TX("Texas");

    private String name;

    private State(String name) {
        this.name = name;
    }

    @JsonInclude
    public String getName() {
        return this.name;
    }
}


text:
<!DOCTYPE html>

<link href="../prism/prism-coy.css" rel="stylesheet" />
<link href="jstijl.css" rel="stylesheet" />
<meta charset="UTF-8">

6. Het DOM model

Fundamenteel voor de mogelijkheid om binnen Javascript heel gericht onderdelen van een webpagina te kunnen beïnvloeden is het DOM model, het Document Object Model. Dit model geeft aan hoe een webbrowser intern een pagina bekijkt, welke objecten (alinea's, formulieren, koppen, div's) er op de pagina staan en in welke hierarchie deze objecten staan. Dit is onder andere van belang voor hoe css opmaak wordt doorgegeven. Maar Javascript maakt er dus ook gebruik van om attributen van html objecten mee te beinvloeden. DOM objecten hebben, zoals het echte objecten betaamt, attributen, maar ook methoden.

Het DOM Model is in de kern niets anders dan een representatie van de elementen van een webpagina:

Bron: washington.edu

Ieder punt in deze 'boom' heet een node.  Er zijn drie soorten nodes:

element nodes (in feite HTML tags, die 'kinderen' (=andere nodes binnen zichzelf) en 'attributen' kunnen hebben) In het voorbeeld hierboven bijvoorbeeld H1 en a (let op de groene kaders).

text nodes (die alleen maar uit tekst bestaan (geen tags dus) In het voorbeeld hierboven het 'welkom' binnen de H1 tag (let op de oranje kaders).

attribuut nodes (die een attribuut van het element benoemen) In het voorbeeld hierboven is href een voorbeeld van een attribuut node, met een waarde, nl. de link (blauwe kader).

Deze <a> tag bijvoorbeeld:  <a href="test.html">Klik hier</a> is zelf een element node, heeft als tekst 'klik hier' en als 'href' attribuut: test.html.

Tags binnen een tag kunnen allerlei aanduidingen krijgen ('firstChild, nextSibling,parentNode')  die duidelijk maken waar zij zich in de hierarchie bevinden. Ook kunnen met de methoden als appendChild(nod) en removeChild(node) nodes aan de boom gemanipuleerd worden. Voor deze reeks aantekeningen gaat het gedetailleerd navigeren in het DOM te ver en zal niet verder behandeld worden, tenzij het voor een specifieke oplossing nodig is.

Nodes kun je met Javascript benaderen via commando's als

document.getElementById("id")
document.getElementsByTagName("tag")

Bij de eerste mik je op één ding, bij het tweede kun je alle <p> tags op een pagina benaderen.

In een Javascript programma kun je verschillende globale objecten benaderen:

window  =  het browser scherm

navigator = informatie over de webbrowser die je gebruikt (welke is het, mogen cookies? enz.)

screen = informatie over de monitor (beschikbare resolutie e.d.)

history = de pagina's die de browser bezocht heeft (ook methodes als back en go)

location = de URL van de huidige pagina (host, protocol)

document = het DOM model van de huidige pagina.

In het eerder gegeven voorbeeld:

var melding = "Goedenacht!";
document.getElementById("melding").innerHTML = melding;

zie je dus het DOM model in actie. Op de pagina wordt gezocht naar het element dat een id "melding" heeft. Van dit element wordt de html in de tag zelf veranderd in de inhoud van de variabele melding.


text:
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
#include "./JPetOptionsTools.h"
#include "../JPetCommonTools/JPetCommonTools.h"
#include "../JPetLoggerInclude.h"
#include "../JPetOptionsGenerator/JPetOptionsTypeHandler.h"
#include <typeinfo>

namespace pt = boost::property_tree;
using boost::any_cast;

namespace jpet_options_tools
{

std::map<std::string, FileTypeChecker::FileType> FileTypeChecker::fStringToFileType = {
  {"", kNoType},
  {"root", kRoot},
  {"scope", kScope},
  {"hld", kHld},
  {"hldRoot", kHldRoot},
  {"zip", kZip}
};

bool isOptionSet(const OptsStrAny& opts, const std::string& optionName)
{
  return static_cast<bool>(opts.count(optionName));
}

boost::any getOptionValue(const OptsStrAny& opts, std::string optionName)
{
  return opts.at(optionName);
}

std::string getOptionAsString(const OptsStrAny& opts, std::string optionName)
{
  try {
    return any_cast<std::string>(getOptionValue(opts, optionName));
  } catch (const std::exception& excep) {
    ERROR("Bad option type:" + std::string(excep.what()));
    return "";
  }
}

int getOptionAsInt(const OptsStrAny& opts, std::string optionName)
{
  try {
    return any_cast<int>(getOptionValue(opts, optionName));
  } catch (const std::exception& excep) {
    ERROR("Bad option type:" + std::string(excep.what()));
    return -1;
  }
}

float getOptionAsFloat(const OptsStrAny& opts, std::string optionName)
{
  try {
    return any_cast<float>(getOptionValue(opts, optionName));
  } catch (const std::exception& excep) {
    ERROR("Bad option type:" + std::string(excep.what()));
    return -1.;
  }
}

double getOptionAsDouble(const OptsStrAny& opts, std::string optionName)
{
  try {
    return any_cast<double>(getOptionValue(opts, optionName));
  } catch (const std::exception& excep) {
    ERROR("Bad option type:" + std::string(excep.what()));
    return -1.;
  }
}

std::vector<std::string> getOptionAsVectorOfStrings(const OptsStrAny& opts, std::string optionName)
{
  try {
    return any_cast<std::vector<std::string>>(getOptionValue(opts, optionName));
  } catch (const std::exception& excep) {
    std::vector<std::string> emptyV;
    ERROR("Bad option type:" + std::string(excep.what()));
    return emptyV;
  }
}

bool getOptionAsBool(const OptsStrAny& opts, std::string optionName)
{
  try {
    return any_cast<bool>(getOptionValue(opts, optionName));
  } catch (const std::exception& excep) {
    ERROR("Bad option type:" + std::string(excep.what()));
    return false;
  }
}

std::vector<std::string> getInputFiles(const std::map<std::string, boost::any>& opts)
{
  std::vector<std::string> dummy;
  if (!isOptionSet(opts, "file_std::vector<std::string>")) {
    ERROR("key:file_std::vector<std::string> not found in options");
    return dummy;
  }
  return any_cast<std::vector<std::string>>(opts.at("file_std::vector<std::string>"));
}

const char* getInputFile(const std::map<std::string, boost::any>& opts)
{
  return any_cast<std::string>(opts.at("inputFile_std::string")).c_str();
}

const char* getScopeConfigFile(const std::map<std::string, boost::any>& opts)
{
  return any_cast<std::string>(opts.at("scopeConfigFile_std::string")).c_str();
}

const char* getScopeInputDirectory(const std::map<std::string, boost::any>& opts)
{
  return any_cast<std::string>(opts.at("scopeInputDirectory_std::string")).c_str();
}

const char* getOutputFile(const std::map<std::string, boost::any>& opts)
{
  return any_cast<std::string>(opts.at("outputFile_std::string")).c_str();
}

const char* getOutputPath(const std::map<std::string, boost::any>& opts)
{
  return any_cast<std::string>(opts.at("outputPath_std::string")).c_str();
}

long long getFirstEvent(const std::map<std::string, boost::any>& opts)
{
  return any_cast<int>(opts.at("firstEvent_int"));
}

long long getLastEvent(const std::map<std::string, boost::any>& opts)
{
  return any_cast<int>(opts.at("lastEvent_int"));
}

long long getTotalEvents(const std::map<std::string, boost::any>& opts)
{
  long long first = getFirstEvent(opts);
  long long last = getLastEvent(opts);
  long long diff = -1;
  if ((first >= 0) && (last >= 0) && ((last - first) >= 0)) {
    diff = last - first + 1;
  }
  return diff;
}

int getRunNumber(const std::map<std::string, boost::any>& opts)
{
  return any_cast<int>(opts.at("runId_int"));
}

bool isProgressBar(const std::map<std::string, boost::any>& opts)
{
  return any_cast<bool>(opts.at("progressBar_bool"));
}

bool isLocalDB(const std::map<std::string, boost::any>& opts)
{
  return (bool)opts.count("localDB_std::string");
}

std::string getLocalDB(const std::map<std::string, boost::any>& opts)
{
  std::string result("");
  if (isLocalDB(opts)) {
    result = any_cast<std::string>(opts.at("localDB_std::string"));
  }
  return result;
}
bool isLocalDBCreate(const std::map<std::string, boost::any>& opts)
{
  return (bool)opts.count("localDBCreate_std::string");
}

std::string getLocalDBCreate(const std::map<std::string, boost::any>& opts)
{
  std::string result("");
  if (isLocalDBCreate(opts)) {
    result = any_cast<std::string>(opts.at("localDBCreate_std::string"));
  }
  return result;
}

const char* getUnpackerConfigFile(const std::map<std::string, boost::any>& opts)
{
  return any_cast<std::string>(opts.at("unpackerConfigFile_std::string")).c_str();
}

const char* getUnpackerCalibFile(const std::map<std::string, boost::any>& opts)
{
  return any_cast<std::string>(opts.at("unpackerCalibFile_std::string")).c_str();
}

std::string getConfigFileName(const std::map<std::string, boost::any>& optsMap)
{
  if (optsMap.count("userCfg_std::string")) {
    return any_cast<std::string>(optsMap.at("userCfg_std::string"));
  } else {
    return "";
  }
}

void printOptions(const OptsStrAny& opts)
{
  std::cout << "Current options:" << std::endl;
  auto stringOptions = JPetOptionsTypeHandler::anyMapToStringMap(opts);
  for (const auto& el : stringOptions) {
    std::cout << el.first + "=" + el.second << std::endl;
  }
}

void printOptionsToLog(const OptsStrAny& opts, const std::string& firstLine)
{
  if (!firstLine.empty()) {
    INFO(firstLine.c_str());
  }
  INFO("Current options:");
  auto stringOptions = JPetOptionsTypeHandler::anyMapToStringMap(opts);
  for (const auto& el : stringOptions) {
    INFO(el.first + "=" + el.second);
  }
}

bool createConfigFileFromOptions(const OptsStrStr& options, const std::string& outFile)
{
  pt::ptree optionsTree;
  for (auto& entry : options)
    optionsTree.put(entry.first, entry.second);
  try {
    pt::write_json(outFile, optionsTree);
  } catch (pt::json_parser_error) {
    ERROR("ERROR IN WRITING OPTIONS TO JSON FILE");
    return false;
  }
  return true;
}

std::map<std::string, boost::any> createOptionsFromConfigFile(const std::string& filename)
{
  pt::ptree optionsTree;
  std::map<std::string, boost::any> mapOptions, emptyMap;
  if (JPetCommonTools::ifFileExisting(filename)) {
    try {
      pt::read_json(filename, optionsTree);
      for (auto& item : optionsTree) {
        auto key = item.first;
        std::string typeOfOption = JPetOptionsTypeHandler::getTypeOfOption(key);
        auto allowedTypes = JPetOptionsTypeHandler::getAllowedTypes();
        if (std::find(allowedTypes.begin(), allowedTypes.end(), typeOfOption) != allowedTypes.end()) {
          if (typeOfOption == "int") {
            auto value = item.second.get_value<int>();
            mapOptions.insert(std::make_pair(key, value));
          } else if (typeOfOption == "std::string") {
            auto value = item.second.get_value<std::string>();
            mapOptions.insert(std::make_pair(key, value));
          } else if (typeOfOption == "float") {
            auto value = item.second.get_value<float>();
            mapOptions.insert(std::make_pair(key, value));
          } else if (typeOfOption == "double") {
            auto value = item.second.get_value<double>();
            mapOptions.insert(std::make_pair(key, value));
          } else if (typeOfOption == "bool") {
            auto value = item.second.get_value<bool>();
            mapOptions.insert(std::make_pair(key, value));
          } else if (typeOfOption == "std::vector<std::string>") {
            std::vector<std::string> values;
            for (pt::ptree::value_type& value : optionsTree.get_child(key)) {
              values.push_back(value.second.get_value<std::string>());
            }
            mapOptions.insert(std::make_pair(key, values));
          } else if (typeOfOption == "std::vector<int>") {
            std::vector<int> values;
            for (pt::ptree::value_type& value : optionsTree.get_child(key)) {
              values.push_back(value.second.get_value<int>());
            }
            mapOptions.insert(std::make_pair(key, values));
          }
        }
      }
    } catch (pt::json_parser_error) {
      ERROR("ERROR IN READINIG OPTIONS FROM JSON FILE! FILENAME:" + filename );
      return emptyMap;
    }
  } else {
    ERROR("JSON CONFIG FILE DOES NOT EXIST! FILENAME:" + filename);
  }
  return mapOptions;
}

FileTypeChecker::FileType FileTypeChecker::getInputFileType(const std::map<std::string, boost::any>& opts)
{
  return getFileType(opts, "inputFileType_std::string");
}

FileTypeChecker::FileType FileTypeChecker::getOutputFileType(const std::map<std::string, boost::any>& opts)
{
  return getFileType(opts, "outputFileType_std::string");
}

void FileTypeChecker::handleErrorMessage(const std::string& errorMessage, const std::out_of_range& outOfRangeException)
{
  std::cerr << errorMessage << outOfRangeException.what() << '\n';
  ERROR(errorMessage);
}

FileTypeChecker::FileType FileTypeChecker::getFileType(const std::map<std::string, boost::any>& opts, const std::string& fileTypeName)
{
  try {
    auto option = any_cast<std::string>(opts.at(fileTypeName));
    try {
      return fStringToFileType.at(option);
    } catch (const std::out_of_range& outOfRangeFileTypeException) {
    }
  } catch (const std::out_of_range& outOfRangeOptionException) {
    std::string errorMessage = "Out of range error in Options container ";
    handleErrorMessage(errorMessage, outOfRangeOptionException);
  }
  return FileType::kUndefinedFileType;
}

}


text:
<?php

require_once __DIR__ . '/../../vendor/autoload.php';
require_once __DIR__ . '/RequeueListener.php';

$queue = MicroQueue\Queue::declareQueue('sms');

$eventDispatcher = new \Armadillo\EventDispatcher;

$eventDispatcher->registerEvent('message.requeue');
$eventDispatcher->addListenerToEvent('message.requeue', new RequeueListener('sms'));

$consumer = new MicroQueue\Consumer($queue, $eventDispatcher);

while(true) {
    $consumer->consume(function($message, $eventDispatcher) {
        if ('123' == $message) {
            $eventDispatcher->dispatchEvent('message.requeue', $message);
        } else {
            file_put_contents('/tmp/microqueue_messages', $message);
        }
    });
}


text:
<?php

//lets first check if IN_WOL is defined
if (!defined("IN_WOL")) { die(header("Location: ../index.php")); }

Class Online_list
{
    /******
     * User | Guest OR Not
     * @var
     */

    var $user;

    /******
     * The time the user is considered online
     * @var
     */

    var $time;

    /******
     * The page location the user is on
     * @var
     */

    var $page;

    /******
     * The domain of this site
     * @var
     */

    var $domain;

    /******
     * The IP of the user
     * @var
     */

    var $ip;

    //now construct the delicious cosntructor =D

    function __construct($time, $domain)
    {
        //define some sweeties
        $this->user   = @$user;
        $this->time   = @$time;
        $this->page   = @$page;
        $this->domain = @$domain;
        $this->ip     = @$ip;

        //now convert the time
        $this->time = ($this->time * 60);

    }

    /******
     * This locates the page the user is currently on
     * @return string
     */

    public function pageLocator()
    {
        //firstly, compare domains
        $grabbed_domain = @$_SERVER['HTTP_REFERER'];

        if($grabbed_domain == '')
        {
            $this->page = "http://".$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
        }

        else
        {
            $grabbed_domain = preg_match("^$this->domain^", $grabbed_domain);

            if($grabbed_domain != true)
            {
                //for security issues, let's return this as N/A
                $this->page = "N/A";
            }

            else
            {
                //lets continue
                $this->page = $_SERVER['HTTP_REFERER'];
            }
        }

        //for security purposes, let's do a slight clean up on the URL
        //it doesn't do much, but it helps. However, we did do a major security audit with the domain

        $this->page = strip_tags($this->page);

        //now output the page
        return $this->page;

    }

    /******
     * This grabs the users real IP
     * @return
     */

    function ipGrabber()
    {
        if(!empty($_SERVER['HTTP_CLIENT_IP']))
        {
          $ip = $_SERVER['HTTP_CLIENT_IP'];
        }
        elseif(!empty($_SERVER['HTTP_X_FORWARDED_FOR']))
        {
          $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
        }
        else
        {
          $ip = $_SERVER['REMOTE_ADDR'];
        }
        return $ip;
    }

    /******
     * Records new users online
     * @return
     * @param object $t_added
     * @param object $identify[optional]
     * @param object $location[optional]
     */

    public function userRecorder($t_added, $identify=false, $location=false)
    {
        global $db;

        //lets begin by some sanitization
        $t_added = intval($t_added);

        $this->user = htmlspecialchars($identify);
        $location   = strip_tags($location);

        //grab the IP Address
        $this->ip   = $this->ipGrabber();

        //do some checking

        if($this->user == false)
        {
            //the user is a guest
            $this->user = "Guest";
        }

        if($location == false)
        {
            //no location specified
            $this->page = "N/A";
        }

        //before we send the user as a new one, lets check if we have him/her in the db already
        $query = db_query("SELECT oid FROM online WHERE ip='$this->ip'");

        if(db_num_rows($query) < 1)
        {
            //now enter it into the database
            db_query("INSERT INTO online (user,page,time,ip)VALUES('$this->user','$location','$t_added','$this->ip')");
        }

        else
        {
            //looks like the user is in the database, we should just update the time and location, or, just remove it and re-add it - That's a better idea =P
            db_query("DELETE FROM online WHERE ip='$this->ip'");

            //now enter it into the database
            db_query("INSERT INTO online (user,page,time,ip)VALUES('$this->user','$location','$t_added','$this->ip')");

        }

        //run the record remover
        $this->recordRemover();
    }

    /******
     * Removes people who are past due (who are offline)
     * @return
     * @param object $ip[optional]
     */

    public function recordRemover($ip=false)
    {
        global $db;

        //set the vars
        $this->ip   = $ip;

        //for flexibilities sake, check if the ip is false
        if($this->ip == false)
        {
            //just remove whatever expired

            //lets select all records
            $query = db_query("SELECT ip, time FROM online");

            // no need to check if it returns results, chances are, when this script runs
            // someone will be online

            while($row = db_fetch_assoc($query))
            {
                $db_time = intval($row['time']);
                $db_ip   = htmlspecialchars($row['ip']);

                //add the time until offline to this time
                $db_time = $db_time + $this->time;

                // now time to compare it with now
                if(time() > $db_time)
                {
                    // It's Time Sire
                    // In other words, seems like its time to give them the boot

                    db_query("DELETE FROM online WHERE ip='$db_ip'");
                }
            }

        }

        else
        {
            //looks like we need to remove the record based on the IP provided
            db_query("DELETE FROM online WHERE ip='$this->ip'");
        }
    }

    /******
     * Displays the full WOL List
     * @return
     */

    public function displayWOL()
    {
        global $db, $total_guests, $total_users, $user, $page, $time,$onlinepath;

        //perform a select query

        //count the total guests online
        $query        = db_query("SELECT * FROM online WHERE user='Guest'");

        $total_guests = db_num_rows($query);

        //count the total users online
        $query2       = db_query("SELECT * FROM online WHERE user !='Guest'");

        $total_users  = db_num_rows($query2);

        //select everyone
        $query3       = db_query("SELECT * FROM online");

        include($onlinepath."templates/table_header.tpl");

        while($row = db_fetch_assoc($query3))
        {
            $user = htmlspecialchars($row['user']);
            $page = htmlspecialchars($row['page']);
            $time = relativeTime($row['time']);

            include($onlinepath."templates/table_body.tpl");
        }

        include($onlinepath."templates/table_footer.tpl");

    }

    /******
     * Displays a minimized WOL
     * @return
     */

    public function minimized()
    {
        global $db, $total_guests, $total_users,$onlinepath;

        //perform a select query

        //count the total guests online
        $query        = db_query("SELECT * FROM online WHERE user='Guest'");

        $total_guests = db_num_rows($query);

        //count the total users online
        $query2       = db_query("SELECT * FROM online WHERE user !='Guest'");

        $total_users  = db_num_rows($query2);

        //grab template

        include($onlinepath."templates/minimized.tpl");

    }
}


text:
<?php if ($communityMembersCount): ?>

<?php echo __('You\'ve gotten %1% one\'s %community% joining requests', array('%1%' => $communityMembersCount)); ?>

<?php echo link_to(__('Go to Confirmation Page'), '@confirmation_list?category=community_confirm') ?>

<?php endif; ?>


text:
<?php
	defined('C5_EXECUTE') or die(_("Access Denied."));
	Loader::block('library_file');
	class PaypalTipjarBlockController extends BlockController {

		var $pobj;

		protected $btTable = 'btPaypalTipjar';
		protected $btInterfaceWidth = "400";
		protected $btInterfaceHeight = "300";

		public $paypal_url = "https://www.paypal.com/cgi-bin/webscr";
		public $paypal_url_sandbox = "https://www.sandbox.paypal.com/cgi-bin/webscr";

		public $paypal_user = '';
		public $useSandbox = 0;
		public $currency_code = 'USD';
		public $currency_symbol = '$';

		//<field name="donateButton_fID" type="C" size="255"></field>

		function __construct($obj = null) {
			parent::__construct($obj);
			if($this->useSandbox) {
				$this->paypal_url = $this->paypal_url_sandbox;
			}
		}

		/**
		 * Used for localization. If we want to localize the name/description we have to include this
		 */
		public function getBlockTypeDescription() {
			return t("Take paypal donations on your site.");
		}

		public function getBlockTypeName() {
			return t("Paypal Donations Box");
		}

		public function getJavaScriptStrings() {
			return array('paypal-email-required' => t('Paypal Account Email/Merchant ID is required'));
		}

		public function getAmountField() {
			if(strlen($this->amount)) {
				$amounts = explode('
',nl2br($this->amount));
				if(is_array($amounts) && count($amounts) > 1) {
					$select = '<select name="amount">';
						foreach($amounts as $v) {
							if(is_numeric($v)) {
								$select.='<option value="'.number_format($v,2).'">'.$this->currency_symbol.number_format($v,2).'</option>';
							} else {
								$select.='<option value="">'.$v.'</option>';
							}
						}
					$select .="</select>";

					return '
'.t('Amount')." ". $select .'
';
				} else {
					if(is_numeric($amounts[0])) {
						return '<input type="hidden" name="amount" value="'.number_format($amounts[0],2).'"/>';
					}
				}
			}
			return '';
		}

		public function getTitle() {
			if(strlen($this->title)) {
				return "
".$this->title."
";
			} else {
				return "";
			}
		}

		public function getSubmitButton() {
			if(is_numeric($this->donateButton_fID) && $this->donateButton_fID > 0) {
				$fo = File::getByID($this->donateButton_fID);
				if($fo) {
					return '<input type="image" name="submit" border="0"
					src="'.$fo->getRelativePath().'"
					alt="PayPal - The safer, easier way to pay online">';
				}
			}
			return '<input type="image" name="submit" border="0"
					src="https://www.paypal.com/en_US/i/btn/btn_donate_LG.gif"
					alt="PayPal - The safer, easier way to pay online">';

		}

		public function getItemNameField() {
			if(strlen($this->item_name)) {
				return '<input type="hidden" name="item_name" value="'.$this->item_name.'">';
			} else {
				return '';
			}
		}

		public function getItemNumberField() {
			if(strlen($this->item_number)) {
				return '<input type="hidden" name="item_number" value="'.$this->item_number.'">';
			} else {
				return '';
			}
		}

		function view() {

		}
		/*
		function save($data) {
			parent::save($args);
		}
		*/
	}

?>


text:
/*String s = "Hello";
		String b = "Hello";
		String t = new String(s);
		String p = new String(t);

		if("Hello".equals(s))
			out.println("one");
		if("Hello".equals(t))
			out.println("two");
		if("Hello" == t)
			out.println("three");
		if("Hello" == s)
			out.println("four");
		if(t == p)
			out.println("t == p");
		if(t.equals(p))
			out.println("t.equals(p)");
		if(s == b)
			out.println("s == b");*/
import static java.lang.System.out;
import java.util.List;
import java.util.Arrays;

public class TestingQuestions {

	public static void main (String ... args) {
		//                0,1,2,3,4,5
		/*int [] ordered = {1,2,3,6,8,10};
		int [] unordered = {0,3,2,5,9,7,6,7};
		int x = 11;
		int y = Arrays.binarySearch(ordered, x);
		out.println(y);*/

		List<Integer> list = Arrays.asList(10, 4, -1, 0b1010);
		out.println(list.get(3));

	}
}

// Test Cases Facts
/*

1.  Comparing by "==" your are comparing by reference equality between two objects.
	But otherwise String.equals compare as reference equality and even values of two string against each other.

	Also, when you declare two String like this:

	String a = "Olivia";
	String b = "Olivia";

	if (a == b)	They are equals. Because both point to the same value in the Java String pool

2. How substrings work:

	Substring method allowed you call with just one value what meaning begin at.

	For example:
	String a = "0123456789"; a.substring(5) = 56789

	Even, you can call this using the length where the result would be nothing = ""

	String a = "0123456789"; out.println(a.substring(10)); = ""

	** substring(int beginIndex)
     * Returns a string that is a substring of this string. The
     * substring begins with the character at the specified index and
     * extends to the end of this string.

     * Examples:
     *

     * "unhappy".substring(2) returns "happy"
     * "Harbison".substring(3) returns "bison"
        012345678
     * "emptiness".substring(9) returns "" (an empty string)
     *

     *
     * @param      beginIndex   the beginning index, inclusive.

	** substring(int beginIndex, int endIndex)
     * Returns a string that is a substring of this string. The
     * substring begins at the specified {@code beginIndex} and
     * extends to the character at index {@code endIndex - 1}.
     * Thus the length of the substring is {@code endIndex-beginIndex}.
     *

     * Examples:
     *

     * "hamburger".substring(4, 8) returns "urge"
     * "smiles".substring(1, 5) returns "mile"
     *

     *
     * @param      beginIndex   the beginning index, inclusive.
     * @param      endIndex     the ending index, exclusive.

3. Java does not allow you to compare different types using ==. For example String and StringBuilder.

4. A String concatenated with any other type gives a String.d
	For example

	String a = "a";
	a += false; // afalse
	a += 0L; // afalse0
	a += 0d; // afalse00

5. Strings from the pool are different the string build with String from the pool.
	One comes directly from the string pool and the other comes from building using String operations.

6. Array in java:

	- Array is an ordered list
	- Arrays is an object.
	- int[] numbers1 = new int[3] When using this form to instantiate an array, set all the elements to the default value for
	  that type.
	- You can initialize an array like this "int[] numbers2 = new int[] {42, 55, 99}" for this case you don't need to
	  specify the size because java knows what is the size by the array on the left side of equal sign

	  Also, As a shortcut, Java lets you write this: int[] numbers2 = {42, 55, 99};

	- Multiple arryas in declaration:

		int[] ids, types; = int [] ids; int types [];

		but this case is different:

		int ids[], types; = int ids[]; int types;
	- Arrays can be cast like a primitiv type or reference type.
	- If initialize an array you must specified the size of it. Although it is legal to leave out the size for later
	dimensions of a multidimensional array, the first one is required. For example:

	int [][] scores = new int[5][];
	int [][] scores = new int[5][5];

7. An array is not able to change its size. Both an Array and an ArrayList are ordered and have indexes.
	Neither is immutable because their elements can change.

8. An array does not override equals() and so uses object equality. ArrayList does
	override equals() and defines it as the same elements in the same order.

9. About Arrays class:

	Its method "int binarySearch(int[] a, int key)":

		They array "a" must be sorted prior to making this call. If it is not sorted. The result will be undefined.

		Returns: It will be the index of the search key, if it is contained in the array. Otherwise, (-(insertion point) - 1)

10. Collections API

	Sort:

		This method can sort either a List of numbers and a List of String.
		In case of a list of numbers, the numbers are sort in the normal way. But in case of a List of String
		, the sort would be alphabetically which mean that the numbers will be first in their natural order
		regardless any contain letters. For example:

		For this: List<String> hex = new Arrays.asList({"30", "8", "3A", "FF"});
		The output would be = {"30", "3A", "8", "FF"}

11. ArraysList class:

	- ArrayList implements equality to mean the same elements in the same order are equals.

12. LocalDate API

	- You cannot get an instance from LocalDate. You must to use LocalDate.of(YYYY, MM, DD).
	- Month stars counting with 1 rather than 0(The old way using Calendar.FIELD used to start with 0).
	- A LocalDate does not have a time element. Therefore, it has no method to add hours and the code does not compile.
	- Dates are immutable. Therefore plus methods have to assign their return values or will be ignored.

13. LocalDateTime API (TODO: For study it)

14. Period

	- Doesn't Allow method chaining. Because it always create a new object in its way.
	For example:
		Period period = Period.ofDays(5).ofYears(5);
	Will just stay with: 5 years. Because the method works in this way

		return create(years, 0, 0);:

*/


text:
Favorite Teams

    {{team.name}}


text:
package com.amazonaws.services.ec2.model.transform;

import java.util.ArrayList;

import javax.xml.stream.events.XMLEvent;
import javax.annotation.Generated;

import com.amazonaws.services.ec2.model.*;
import com.amazonaws.transform.Unmarshaller;

import com.amazonaws.transform.StaxUnmarshallerContext;
import com.amazonaws.transform.SimpleTypeStaxUnmarshallers.*;

/**
 * IpPermission StAX Unmarshaller
 */

@Generated("com.amazonaws:aws-java-sdk-code-generator")
public class IpPermissionStaxUnmarshaller implements Unmarshaller<IpPermission, StaxUnmarshallerContext> {

    public IpPermission unmarshall(StaxUnmarshallerContext context) throws Exception {
        IpPermission ipPermission = new IpPermission();
        int originalDepth = context.getCurrentDepth();
        int targetDepth = originalDepth + 1;

        if (context.isStartOfDocument())
            targetDepth += 1;

        while (true) {
            XMLEvent xmlEvent = context.nextEvent();
            if (xmlEvent.isEndDocument())
                return ipPermission;

            if (xmlEvent.isAttribute() || xmlEvent.isStartElement()) {

                if (context.testExpression("fromPort", targetDepth)) {
                    ipPermission.setFromPort(IntegerStaxUnmarshaller.getInstance().unmarshall(context));
                    continue;
                }

                if (context.testExpression("ipProtocol", targetDepth)) {
                    ipPermission.setIpProtocol(StringStaxUnmarshaller.getInstance().unmarshall(context));
                    continue;
                }

                if (context.testExpression("ipv6Ranges", targetDepth)) {
                    ipPermission.withIpv6Ranges(new ArrayList<Ipv6Range>());
                    continue;
                }

                if (context.testExpression("ipv6Ranges/item", targetDepth)) {
                    ipPermission.withIpv6Ranges(Ipv6RangeStaxUnmarshaller.getInstance().unmarshall(context));
                    continue;
                }

                if (context.testExpression("prefixListIds", targetDepth)) {
                    ipPermission.withPrefixListIds(new ArrayList<PrefixListId>());
                    continue;
                }

                if (context.testExpression("prefixListIds/item", targetDepth)) {
                    ipPermission.withPrefixListIds(PrefixListIdStaxUnmarshaller.getInstance().unmarshall(context));
                    continue;
                }

                if (context.testExpression("toPort", targetDepth)) {
                    ipPermission.setToPort(IntegerStaxUnmarshaller.getInstance().unmarshall(context));
                    continue;
                }

                if (context.testExpression("groups", targetDepth)) {
                    ipPermission.withUserIdGroupPairs(new ArrayList<UserIdGroupPair>());
                    continue;
                }

                if (context.testExpression("groups/item", targetDepth)) {
                    ipPermission.withUserIdGroupPairs(UserIdGroupPairStaxUnmarshaller.getInstance().unmarshall(context));
                    continue;
                }

                if (context.testExpression("ipRanges", targetDepth)) {
                    ipPermission.withIpv4Ranges(new ArrayList<IpRange>());
                    continue;
                }

                if (context.testExpression("ipRanges/item", targetDepth)) {
                    ipPermission.withIpv4Ranges(IpRangeStaxUnmarshaller.getInstance().unmarshall(context));
                    continue;
                }

            } else if (xmlEvent.isEndElement()) {
                if (context.getCurrentDepth() < originalDepth) {
                    return ipPermission;
                }
            }
        }
    }

    private static IpPermissionStaxUnmarshaller instance;

    public static IpPermissionStaxUnmarshaller getInstance() {
        if (instance == null)
            instance = new IpPermissionStaxUnmarshaller();
        return instance;
    }
}


text: export * from './Logout.component';


text:
import Bootable from '../../mixins/bootable'

import {
  VTabTransition,
  VTabReverseTransition
} from '../transitions'

export default {
  name: 'v-tabs-content',

  mixins: [Bootable],

  inject: ['registerContent', 'unregisterContent'],

  components: {
    VTabTransition,
    VTabReverseTransition
  },

  data () {
    return {
      isActive: false,
      reverse: false
    }
  },

  props: {
    id: {
      type: String,
      required: true
    },
    lazy: Boolean,
    transition: {
      type: [Boolean, String],
      default: 'tab-transition'
    },
    reverseTransition: {
      type: [Boolean, String],
      default: 'tab-reverse-transition'
    }
  },

  computed: {
    computedTransition () {
      return this.reverse ? this.reverseTransition : this.transition
    }
  },

  methods: {
    toggle (target, reverse, showTransition) {
      this.$el.style.transition = !showTransition ? 'none' : null
      this.reverse = reverse
      this.isActive = this.id === target
    }
  },

  mounted () {
    this.registerContent(this.id, this.toggle)
  },

  beforeDestroy () {
    this.unregisterContent(this.id)
  },

  render (h) {
    const div = h('div', {
      'class': 'tabs__content',
      domProps: { id: this.id },
      directives: [{
        name: 'show',
        value: this.isActive
      }],
      on: this.$listeners
    }, this.showLazyContent(this.$slots.default))

    if (!this.computedTransition) {
      return div
    }

    return h('transition', {
      props: {
        name: this.computedTransition
      }
    }, [div])
  }
}