<commit_before>class SyncManager {

  constructor($rootScope, modelManager, authManager, dbManager, httpManager, $interval, $timeout, storageManager, passcodeManager) {
    this.$rootScope = $rootScope;
    this.httpManager = httpManager;
    this.modelManager = modelManager;
    this.authManager = authManager;
    this.dbManager = dbManager;
    this.$interval = $interval;
    this.$timeout = $timeout;
    this.storageManager = storageManager;
    this.passcodeManager = passcodeManager;
    this.syncStatus = {};
  }

  get serverURL() {
    return this.storageManager.getItem("server") || window._default_sf_server;
  }

  get masterKey() {
    return this.storageManager.getItem("mk");
  }

  get serverPassword() {
    return this.storageManager.getItem("pw");
  }

  writeItemsToLocalStorage(items, offlineOnly, callback) {
    if(items.length == 0) {
      callback && callback();
      return;
    }
    // Use null to use the latest protocol version if offline
    var version = this.authManager.offline() ? null : this.authManager.protocolVersion();
    var keys = this.authManager.offline() ? this.passcodeManager.keys() : this.authManager.keys();
    var params = items.map(function(item) {
      var itemParams = new ItemParams(item, keys, version);
      itemParams = itemParams.paramsForLocalStorage();
      if(offlineOnly) {
        delete itemParams.dirty;
      }
      return itemParams;
    }.bind(this));

    this.storageManager.saveModels(params, callback);
  }

  loadLocalItems(callback) {
    var params = this.storageManager.getAllModels(function(items){
      var items = this.handleItemsResponse(items, null);
      Item.sortItemsByDate(items);
      callback(items);
    }.bind(this))
  }

  syncOffline(items, callback) {
    this.writeItemsToLocalStorage(items, true, function(responseItems){
      // delete anything needing to be deleted
      for(var item of items) {
        if(item.deleted) {
          this.modelManager.removeItemLocally(item);
        }
      }

      if(callback) {
        callback({success: true});
      }
    }.bind(this))

  }

  /*
    In the case of signing in and merging local data, we alternative UUIDs
    to avoid overwriting data a user may retrieve that has the same UUID.
    Alternating here forces us to to create duplicates of the items instead.
   */
  markAllItemsDirtyAndSaveOffline(callback, alternateUUIDs) {

    // use a copy, as alternating uuid will affect array
    var originalItems = this.modelManager.allItems.slice();

    var block = () => {
      var allItems = this.modelManager.allItems;
      for(var item of allItems) {
        item.setDirty(true);
      }
      this.writeItemsToLocalStorage(allItems, false, callback);
    }

    if(alternateUUIDs) {
      var index = 0;

      let alternateNextItem = () => {
        if(index >= originalItems.length) {
          // We don't use originalItems as altnerating UUID will have deleted them.
          block();
          return;
        }

        var item = originalItems[index];
        index++;
        // false => dont remove original. We want to keep both copies
        this.modelManager.alternateUUIDForItem(item, alternateNextItem, false);
      }

      alternateNextItem();
    } else {
      block();
    }
  }

  get syncURL() {
    return this.serverURL + "/items/sync";
  }

  set syncToken(token) {
    this._syncToken = token;
    this.storageManager.setItem("syncToken", token);
  }

  get syncToken() {
    if(!this._syncToken) {
      this._syncToken = this.storageManager.getItem("syncToken");
    }
    return this._syncToken;
  }
<commit_msg>Comment regarding alternate uuids during sign in<commit_after>class SyncManager {

  constructor($rootScope, modelManager, authManager, dbManager, httpManager, $interval, $timeout, storageManager, passcodeManager) {
    this.$rootScope = $rootScope;
    this.httpManager = httpManager;
    this.modelManager = modelManager;
    this.authManager = authManager;
    this.dbManager = dbManager;
    this.$interval = $interval;
    this.$timeout = $timeout;
    this.storageManager = storageManager;
    this.passcodeManager = passcodeManager;
    this.syncStatus = {};
  }

  get serverURL() {
    return this.storageManager.getItem("server") || window._default_sf_server;
  }

  get masterKey() {
    return this.storageManager.getItem("mk");
  }

  get serverPassword() {
    return this.storageManager.getItem("pw");
  }

  writeItemsToLocalStorage(items, offlineOnly, callback) {
    if(items.length == 0) {
      callback && callback();
      return;
    }
    // Use null to use the latest protocol version if offline
    var version = this.authManager.offline() ? null : this.authManager.protocolVersion();
    var keys = this.authManager.offline() ? this.passcodeManager.keys() : this.authManager.keys();
    var params = items.map(function(item) {
      var itemParams = new ItemParams(item, keys, version);
      itemParams = itemParams.paramsForLocalStorage();
      if(offlineOnly) {
        delete itemParams.dirty;
      }
      return itemParams;
    }.bind(this));

    this.storageManager.saveModels(params, callback);
  }

  loadLocalItems(callback) {
    var params = this.storageManager.getAllModels(function(items){
      var items = this.handleItemsResponse(items, null);
      Item.sortItemsByDate(items);
      callback(items);
    }.bind(this))
  }

  syncOffline(items, callback) {
    this.writeItemsToLocalStorage(items, true, function(responseItems){
      // delete anything needing to be deleted
      for(var item of items) {
        if(item.deleted) {
          this.modelManager.removeItemLocally(item);
        }
      }

      if(callback) {
        callback({success: true});
      }
    }.bind(this))

  }

  /*
    In the case of signing in and merging local data, we alternative UUIDs
    to avoid overwriting data a user may retrieve that has the same UUID.
    Alternating here forces us to to create duplicates of the items instead.
   */
  markAllItemsDirtyAndSaveOffline(callback, alternateUUIDs) {

    // use a copy, as alternating uuid will affect array
    var originalItems = this.modelManager.allItems.slice();

    var block = () => {
      var allItems = this.modelManager.allItems;
      for(var item of allItems) {
        item.setDirty(true);
      }
      this.writeItemsToLocalStorage(allItems, false, callback);
    }

    if(alternateUUIDs) {
      var index = 0;

      let alternateNextItem = () => {
        if(index >= originalItems.length) {
          // We don't use originalItems as altnerating UUID will have deleted them.
          block();
          return;
        }

        var item = originalItems[index];
        index++;

        // alternateUUIDForItem last param is a boolean that controls whether the original item
        // should be removed locally after new item is created. We set this to true, since during sign in,
        // all item ids are alternated, and we only want one final copy of the entire data set.
        // Passing false can be desired sometimes, when for example the app has signed out the user,
        // but for some reason retained their data (This happens in Firefox when using private mode).
        // In this case, we should pass false so that both copies are kept. However, it's difficult to
        // detect when the app has entered this state. We will just use true to remove original items for now.
        this.modelManager.alternateUUIDForItem(item, alternateNextItem, true);
      }

      alternateNextItem();
    } else {
      block();
    }
  }

  get syncURL() {
    return this.serverURL + "/items/sync";
  }

  set syncToken(token) {
    this._syncToken = token;
    this.storageManager.setItem("syncToken", token);
  }

  get syncToken() {
    if(!this._syncToken) {
      this._syncToken = this.storageManager.getItem("syncToken");
    }
    return this._syncToken;
  }

{'fraction_non_alphanumeric': 0.10408498798532946, 'fraction_numerical': 0.0005058808650562792, 'mean_word_length': 2.861328125, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 10, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6954247', 'n_tokens_mistral': 2260, 'n_tokens_neox': 2213, 'n_words': 602}