From de70b05c1b2fd65e6ba314ca4824b29547220118 Mon Sep 17 00:00:00 2001
From: milaGGL <107142260+milaGGL@users.noreply.github.com>
Date: Wed, 4 Jan 2023 22:18:34 -0800
Subject: [PATCH 01/27] Implement BloomFilter class
---
.../firestore/remote/BloomFilter.java | 151 ++++++++++++++++++
.../firestore/remote/BloomFilterTest.java | 98 ++++++++++++
2 files changed, 249 insertions(+)
create mode 100644 firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java
create mode 100644 firebase-firestore/src/test/java/com/google/firebase/firestore/remote/BloomFilterTest.java
diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java
new file mode 100644
index 00000000000..2e6235f60e6
--- /dev/null
+++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java
@@ -0,0 +1,151 @@
+// Copyright 2022 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.firebase.firestore.remote;
+
+import androidx.annotation.NonNull;
+import com.google.firebase.firestore.util.Logger;
+import java.math.BigInteger;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+
+public class BloomFilter {
+ private static final String TAG = "BloomFilter";
+ private static final BigInteger MAX_64_BIT_UNSIGNED_INTEGER =
+ new BigInteger("ffffffffffffffff", 16);
+
+ private final int size;
+ private final byte[] bitmap;
+ private final int hashCount;
+
+ public BloomFilter(@NonNull byte[] bitmap, @NonNull int padding, @NonNull int hashCount) {
+ if (padding < 0 || padding >= 8) {
+ throw new IllegalArgumentException("Invalid padding: " + padding);
+ }
+
+ if (bitmap.length > 0) {
+ // Only empty bloom filter can have 0 hash count.
+ if (hashCount <= 0) {
+ throw new IllegalArgumentException("Invalid hash count: " + hashCount);
+ }
+ } else {
+ if (hashCount < 0) {
+ throw new IllegalArgumentException("Invalid hash count: " + hashCount);
+ }
+
+ // Empty bloom filter should have 0 padding.
+ if (padding != 0) {
+ throw new IllegalArgumentException("Invalid padding when bitmap length is 0: " + padding);
+ }
+ }
+ this.bitmap = bitmap;
+ this.hashCount = hashCount;
+ this.size = bitmap.length * 8 - padding;
+ }
+
+ @NonNull
+ public int getSize() {
+ return this.size;
+ }
+
+ public boolean isEmpty() {
+ return this.size == 0;
+ }
+
+ public boolean mightContain(@NonNull String value) {
+ // Empty bitmap or empty value should always return false on membership check.
+ if (this.isEmpty() || value.isEmpty()) {
+ return false;
+ }
+
+ byte[] md5HashedValue = this.MD5Hash(value);
+ if (md5HashedValue == null || md5HashedValue.length != 16) {
+ //
+ return false;
+ }
+
+ long[] hashedValues = get64BitUnsignedInt(md5HashedValue);
+
+ for (int i = 0; i < this.hashCount; i++) {
+ int index = this.getBitIndex(hashedValues, i);
+ if (!this.isBitSet(index)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public static byte[] MD5Hash(String value) {
+ try {
+ MessageDigest digest = MessageDigest.getInstance("MD5");
+ digest.update(value.getBytes());
+ return digest.digest();
+ } catch (NoSuchAlgorithmException e) {
+ Logger.warn(TAG, "Could not create hashing algorithm: MD5.", e);
+ return null;
+ }
+ }
+
+ // Interpret the 16 bytes array as two 64-bit unsigned integers, encoded using
+ // 2’s complement using little endian.
+ private static long[] get64BitUnsignedInt(byte[] bytes) {
+ byte[] chunk1 = Arrays.copyOfRange(bytes, 0, 8);
+ byte[] chunk2 = Arrays.copyOfRange(bytes, 8, 16);
+
+ long num1 = ByteBuffer.wrap(chunk1).order(ByteOrder.LITTLE_ENDIAN).getLong();
+ long num2 = ByteBuffer.wrap(chunk2).order(ByteOrder.LITTLE_ENDIAN).getLong();
+
+ return new long[] {num1, num2};
+ }
+
+ // Calculate the ith hash value based on the hashed 64bit integers,
+ // and calculate its corresponding bit index in the bitmap to be checked.
+ private int getBitIndex(long[] numbers, int index) {
+ BigInteger num1 = new BigInteger(Long.toUnsignedString(numbers[0]));
+ BigInteger num2 = new BigInteger(Long.toUnsignedString(numbers[1]));
+
+ // Calculate hashed value h(i) = h1 + (i * h2).
+ BigInteger hashValue = num1.add(num2.multiply(BigInteger.valueOf(index)));
+
+ // Wrap if hash value overflow 64bit.
+ if (hashValue.compareTo(this.MAX_64_BIT_UNSIGNED_INTEGER) == 1) {
+ hashValue = new BigInteger(Long.toUnsignedString(hashValue.longValue()));
+ }
+
+ return hashValue.mod(BigInteger.valueOf(this.size)).intValue();
+ }
+
+ // Return whether the bit on the given index in the bitmap is set to 1.
+ private boolean isBitSet(int index) {
+ // To retrieve bit n, calculate: (bitmap[n / 8] & (0x01 << (n % 8))).
+ byte byteAtIndex = this.bitmap[(index / 8)];
+ int offset = index % 8;
+ return (byteAtIndex & (0x01 << offset)) != 0;
+ }
+
+ @Override
+ public String toString() {
+ return "BloomFilter{"
+ + "bitmap="
+ + Arrays.toString(bitmap)
+ + ", hashCount="
+ + hashCount
+ + ", size="
+ + size
+ + '}';
+ }
+}
diff --git a/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/BloomFilterTest.java b/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/BloomFilterTest.java
new file mode 100644
index 00000000000..f41c9c9137a
--- /dev/null
+++ b/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/BloomFilterTest.java
@@ -0,0 +1,98 @@
+// Copyright 2022 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.firebase.firestore.remote;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(manifest = Config.NONE)
+public class BloomFilterTest {
+
+ @Test
+ public void testEmptyBloomFilter() {
+ BloomFilter bloomFilter = new BloomFilter(new byte[0], 0, 0);
+ assertEquals(bloomFilter.getSize(), 0);
+ }
+
+ @Test
+ public void testEmptyBloomFilterThrowException() {
+ IllegalArgumentException paddingException =
+ assertThrows(IllegalArgumentException.class, () -> new BloomFilter(new byte[0], 1, 0));
+ assertThat(paddingException)
+ .hasMessageThat()
+ .contains("Invalid padding when bitmap length is 0: 1");
+ IllegalArgumentException hashCountException =
+ assertThrows(IllegalArgumentException.class, () -> new BloomFilter(new byte[0], 0, -1));
+ assertThat(hashCountException).hasMessageThat().contains("Invalid hash count: -1");
+ }
+
+ @Test
+ public void testNonEmptyBloomFilter() {
+ BloomFilter bloomFilter1 = new BloomFilter(new byte[1], 0, 1);
+ assertEquals(bloomFilter1.getSize(), 8);
+ BloomFilter bloomFilter2 = new BloomFilter(new byte[1], 7, 1);
+ assertEquals(bloomFilter2.getSize(), 1);
+ }
+
+ @Test
+ public void testNonEmptyBloomFilterThrowException() {
+ IllegalArgumentException negativePaddingException =
+ assertThrows(IllegalArgumentException.class, () -> new BloomFilter(new byte[1], -1, 1));
+ assertThat(negativePaddingException).hasMessageThat().contains("Invalid padding: -1");
+ IllegalArgumentException overflowPaddingException =
+ assertThrows(IllegalArgumentException.class, () -> new BloomFilter(new byte[1], 8, 1));
+ assertThat(overflowPaddingException).hasMessageThat().contains("Invalid padding: 8");
+
+ IllegalArgumentException negativeHashCountException =
+ assertThrows(IllegalArgumentException.class, () -> new BloomFilter(new byte[1], 1, -1));
+ assertThat(negativeHashCountException).hasMessageThat().contains("Invalid hash count: -1");
+ IllegalArgumentException zeroHashCountException =
+ assertThrows(IllegalArgumentException.class, () -> new BloomFilter(new byte[1], 1, 0));
+ assertThat(zeroHashCountException).hasMessageThat().contains("Invalid hash count: 0");
+ }
+
+ @Test
+ public void testBloomFilterProcessNonStandardCharacters() {
+ // A non-empty BloomFilter object with 1 insertion : "ÀÒ∑"
+ BloomFilter bloomFilter = new BloomFilter(new byte[] {(byte) 237, 5}, 5, 8);
+ assertTrue(bloomFilter.mightContain("ÀÒ∑"));
+ assertFalse(bloomFilter.mightContain("Ò∑À"));
+ }
+
+ @Test
+ public void testEmptyBloomFilterMightContainAlwaysReturnFalse() {
+ BloomFilter bloomFilter = new BloomFilter(new byte[0], 0, 0);
+ assertFalse(bloomFilter.mightContain("abc"));
+ }
+
+ @Test
+ public void testBloomFilterMightContainOnEmptyStringAlwaysReturnFalse() {
+ BloomFilter emptyBloomFilter = new BloomFilter(new byte[0], 0, 0);
+ BloomFilter nonEmptyBloomFilter =
+ new BloomFilter(new byte[] {(byte) 255, (byte) 255, (byte) 255}, 1, 16);
+
+ assertFalse(emptyBloomFilter.mightContain(""));
+ assertFalse(nonEmptyBloomFilter.mightContain(""));
+ }
+}
From 44299ec27edbc3cbc40f94d3db23201091379597 Mon Sep 17 00:00:00 2001
From: milaGGL <107142260+milaGGL@users.noreply.github.com>
Date: Thu, 5 Jan 2023 16:02:02 -0800
Subject: [PATCH 02/27] add golden test
---
.../firestore/remote/BloomFilter.java | 33 ++++-----
.../firestore/remote/BloomFilterTest.java | 71 +++++++++++++++++++
...terTest_MD5_1_0001_bloom_filter_proto.json | 1 +
...est_MD5_1_0001_membership_test_result.json | 1 +
...ilterTest_MD5_1_01_bloom_filter_proto.json | 1 +
...rTest_MD5_1_01_membership_test_result.json | 1 +
...FilterTest_MD5_1_1_bloom_filter_proto.json | 1 +
...erTest_MD5_1_1_membership_test_result.json | 1 +
...est_MD5_50000_0001_bloom_filter_proto.json | 7 ++
...MD5_50000_0001_membership_test_result.json | 1 +
...rTest_MD5_50000_01_bloom_filter_proto.json | 1 +
...t_MD5_50000_01_membership_test_result.json | 1 +
...erTest_MD5_50000_1_bloom_filter_proto.json | 1 +
...st_MD5_50000_1_membership_test_result.json | 1 +
...Test_MD5_5000_0001_bloom_filter_proto.json | 1 +
..._MD5_5000_0001_membership_test_result.json | 1 +
...erTest_MD5_5000_01_bloom_filter_proto.json | 1 +
...st_MD5_5000_01_membership_test_result.json | 1 +
...terTest_MD5_5000_1_bloom_filter_proto.json | 1 +
...est_MD5_5000_1_membership_test_result.json | 1 +
...rTest_MD5_500_0001_bloom_filter_proto.json | 1 +
...t_MD5_500_0001_membership_test_result.json | 1 +
...terTest_MD5_500_01_bloom_filter_proto.json | 1 +
...est_MD5_500_01_membership_test_result.json | 1 +
...lterTest_MD5_500_1_bloom_filter_proto.json | 1 +
...Test_MD5_500_1_membership_test_result.json | 1 +
26 files changed, 115 insertions(+), 19 deletions(-)
create mode 100644 firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_1_0001_bloom_filter_proto.json
create mode 100644 firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_1_0001_membership_test_result.json
create mode 100644 firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_1_01_bloom_filter_proto.json
create mode 100644 firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_1_01_membership_test_result.json
create mode 100644 firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_1_1_bloom_filter_proto.json
create mode 100644 firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_1_1_membership_test_result.json
create mode 100644 firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_50000_0001_bloom_filter_proto.json
create mode 100644 firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_50000_0001_membership_test_result.json
create mode 100644 firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_50000_01_bloom_filter_proto.json
create mode 100644 firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_50000_01_membership_test_result.json
create mode 100644 firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_50000_1_bloom_filter_proto.json
create mode 100644 firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_50000_1_membership_test_result.json
create mode 100644 firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_5000_0001_bloom_filter_proto.json
create mode 100644 firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_5000_0001_membership_test_result.json
create mode 100644 firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_5000_01_bloom_filter_proto.json
create mode 100644 firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_5000_01_membership_test_result.json
create mode 100644 firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_5000_1_bloom_filter_proto.json
create mode 100644 firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_5000_1_membership_test_result.json
create mode 100644 firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_500_0001_bloom_filter_proto.json
create mode 100644 firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_500_0001_membership_test_result.json
create mode 100644 firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_500_01_bloom_filter_proto.json
create mode 100644 firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_500_01_membership_test_result.json
create mode 100644 firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_500_1_bloom_filter_proto.json
create mode 100644 firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_500_1_membership_test_result.json
diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java
index 2e6235f60e6..42340307ab4 100644
--- a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java
+++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java
@@ -17,8 +17,6 @@
import androidx.annotation.NonNull;
import com.google.firebase.firestore.util.Logger;
import java.math.BigInteger;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
@@ -74,14 +72,14 @@ public boolean mightContain(@NonNull String value) {
byte[] md5HashedValue = this.MD5Hash(value);
if (md5HashedValue == null || md5HashedValue.length != 16) {
- //
return false;
}
- long[] hashedValues = get64BitUnsignedInt(md5HashedValue);
+ long hash1 = this.getLongLittleEndian(md5HashedValue, 0);
+ long hash2 = this.getLongLittleEndian(md5HashedValue, 8);
for (int i = 0; i < this.hashCount; i++) {
- int index = this.getBitIndex(hashedValues, i);
+ int index = this.getBitIndex(hash1, hash2, i);
if (!this.isBitSet(index)) {
return false;
}
@@ -100,26 +98,23 @@ public static byte[] MD5Hash(String value) {
}
}
- // Interpret the 16 bytes array as two 64-bit unsigned integers, encoded using
- // 2’s complement using little endian.
- private static long[] get64BitUnsignedInt(byte[] bytes) {
- byte[] chunk1 = Arrays.copyOfRange(bytes, 0, 8);
- byte[] chunk2 = Arrays.copyOfRange(bytes, 8, 16);
-
- long num1 = ByteBuffer.wrap(chunk1).order(ByteOrder.LITTLE_ENDIAN).getLong();
- long num2 = ByteBuffer.wrap(chunk2).order(ByteOrder.LITTLE_ENDIAN).getLong();
-
- return new long[] {num1, num2};
+ // Interpret 8 bytes into a long, using little endian 2’s complement.
+ public static long getLongLittleEndian(byte[] bytes, int offset) {
+ long result = 0;
+ for (int i = 0; i < 8 && i < bytes.length; i++) {
+ result |= (bytes[offset + i] & 0xFFL) << (i * 8);
+ }
+ return result;
}
// Calculate the ith hash value based on the hashed 64bit integers,
// and calculate its corresponding bit index in the bitmap to be checked.
- private int getBitIndex(long[] numbers, int index) {
- BigInteger num1 = new BigInteger(Long.toUnsignedString(numbers[0]));
- BigInteger num2 = new BigInteger(Long.toUnsignedString(numbers[1]));
+ private int getBitIndex(long num1, long num2, int index) {
+ BigInteger bigInteger1 = new BigInteger(Long.toUnsignedString(num1));
+ BigInteger bigInteger2 = new BigInteger(Long.toUnsignedString(num2));
// Calculate hashed value h(i) = h1 + (i * h2).
- BigInteger hashValue = num1.add(num2.multiply(BigInteger.valueOf(index)));
+ BigInteger hashValue = bigInteger1.add(bigInteger2.multiply(BigInteger.valueOf(index)));
// Wrap if hash value overflow 64bit.
if (hashValue.compareTo(this.MAX_64_BIT_UNSIGNED_INTEGER) == 1) {
diff --git a/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/BloomFilterTest.java b/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/BloomFilterTest.java
index f41c9c9137a..5bbc17e4969 100644
--- a/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/BloomFilterTest.java
+++ b/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/BloomFilterTest.java
@@ -20,6 +20,13 @@
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.util.Base64;
+import java.util.HashMap;
+import java.util.stream.Stream;
+import org.json.JSONObject;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
@@ -95,4 +102,68 @@ public void testBloomFilterMightContainOnEmptyStringAlwaysReturnFalse() {
assertFalse(emptyBloomFilter.mightContain(""));
assertFalse(nonEmptyBloomFilter.mightContain(""));
}
+
+ /**
+ * Golden tests are generated by backend based on inserting n number of document paths into a
+ * bloom filter.
+ *
+ *
Full document path is generated by concatenating documentPrefix and number n, eg,
+ * projects/project-1/databases/database-1/documents/coll/doc12.
+ *
+ *
The test result is generated by checking the membership of documents from documentPrefix+0
+ * to documentPrefix+2n. The membership results from 0 to n is expected to be true, and the
+ * membership results from n to 2n is expected to be false with some false positive results.
+ */
+ @Test
+ @SuppressWarnings("DefaultCharset")
+ public void testBloomFilterGoldenTest() throws Exception {
+ String documentPrefix = "projects/project-1/databases/database-1/documents/coll/doc";
+
+ // Import the golden test files for bloom filter
+ HashMap parsedSpecFiles = new HashMap<>();
+ File jsonDir = new File("src/test/resources/bloom_filter_golden_test_data");
+ File[] jsonFiles = jsonDir.listFiles();
+ for (File f : jsonFiles) {
+ if (!f.toString().endsWith(".json")) {
+ continue;
+ }
+
+ // Read the files into a map.
+ StringBuilder builder = new StringBuilder();
+ BufferedReader reader = new BufferedReader(new FileReader(f));
+ Stream lines = reader.lines();
+ lines.forEach(builder::append);
+ String json = builder.toString();
+ JSONObject fileJSON = new JSONObject(json);
+ parsedSpecFiles.put(f.getName(), fileJSON);
+ }
+
+ // Loop and test the files
+ for (String fileName : parsedSpecFiles.keySet()) {
+ if (fileName.contains("membership_test_result")) {
+ continue;
+ }
+
+ // Read test data and instantiate a BloomFilter object
+ JSONObject fileJSON = parsedSpecFiles.get(fileName);
+ JSONObject bits = fileJSON.getJSONObject("bits");
+ String bitmap = bits.getString("bitmap");
+ int padding = bits.getInt("padding");
+ int hashCount = fileJSON.getInt("hashCount");
+ BloomFilter bloomFilter =
+ new BloomFilter(Base64.getDecoder().decode(bitmap), padding, hashCount);
+
+ // Find corresponding membership test result.
+ JSONObject resultJSON =
+ parsedSpecFiles.get(fileName.replace("bloom_filter_proto", "membership_test_result"));
+ String membershipTestResults = resultJSON.getString("membershipTestResults");
+
+ // Run and compare mightContain result with the expectation.
+ for (int i = 0; i < membershipTestResults.length(); i++) {
+ boolean expectedMembershipResult = membershipTestResults.charAt(i) == '1';
+ boolean mightContain = bloomFilter.mightContain(documentPrefix + i);
+ assertEquals(mightContain, expectedMembershipResult);
+ }
+ }
+ }
}
diff --git a/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_1_0001_bloom_filter_proto.json b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_1_0001_bloom_filter_proto.json
new file mode 100644
index 00000000000..23f0f12b267
--- /dev/null
+++ b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_1_0001_bloom_filter_proto.json
@@ -0,0 +1 @@
+{ "bits": { "bitmap": "RswZ", "padding": 1 }, "hashCount": 16 }
diff --git a/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_1_0001_membership_test_result.json b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_1_0001_membership_test_result.json
new file mode 100644
index 00000000000..5a41f842376
--- /dev/null
+++ b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_1_0001_membership_test_result.json
@@ -0,0 +1 @@
+{"membershipTestResults" : "10"}
diff --git a/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_1_01_bloom_filter_proto.json b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_1_01_bloom_filter_proto.json
new file mode 100644
index 00000000000..43d07db5e6d
--- /dev/null
+++ b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_1_01_bloom_filter_proto.json
@@ -0,0 +1 @@
+{"bits":{"bitmap":"mwE=","padding":5},"hashCount":8}
\ No newline at end of file
diff --git a/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_1_01_membership_test_result.json b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_1_01_membership_test_result.json
new file mode 100644
index 00000000000..5a41f842376
--- /dev/null
+++ b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_1_01_membership_test_result.json
@@ -0,0 +1 @@
+{"membershipTestResults" : "10"}
diff --git a/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_1_1_bloom_filter_proto.json b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_1_1_bloom_filter_proto.json
new file mode 100644
index 00000000000..c03535eafc3
--- /dev/null
+++ b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_1_1_bloom_filter_proto.json
@@ -0,0 +1 @@
+{"bits":{"bitmap":"","padding":0},"hashCount":0}
\ No newline at end of file
diff --git a/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_1_1_membership_test_result.json b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_1_1_membership_test_result.json
new file mode 100644
index 00000000000..fcbc34d14ac
--- /dev/null
+++ b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_1_1_membership_test_result.json
@@ -0,0 +1 @@
+{"membershipTestResults" : "00"}
\ No newline at end of file
diff --git a/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_50000_0001_bloom_filter_proto.json b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_50000_0001_bloom_filter_proto.json
new file mode 100644
index 00000000000..04b77bf83ab
--- /dev/null
+++ b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_50000_0001_bloom_filter_proto.json
@@ -0,0 +1,7 @@
+{
+ "bits": {
+ "bitmap": "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",
+ "padding": 1
+ },
+ "hashCount": 13
+}
diff --git a/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_50000_0001_membership_test_result.json b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_50000_0001_membership_test_result.json
new file mode 100644
index 00000000000..25628a9889d
--- /dev/null
+++ b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_50000_0001_membership_test_result.json
@@ -0,0 +1 @@
+{"membershipTestResults" : "1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}
\ No newline at end of file
diff --git a/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_50000_01_bloom_filter_proto.json b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_50000_01_bloom_filter_proto.json
new file mode 100644
index 00000000000..d1448123cdc
--- /dev/null
+++ b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_50000_01_bloom_filter_proto.json
@@ -0,0 +1 @@
+{"bits":{"bitmap":"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","padding":1},"hashCount":7}
\ No newline at end of file
diff --git a/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_50000_01_membership_test_result.json b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_50000_01_membership_test_result.json
new file mode 100644
index 00000000000..c8bef092c6b
--- /dev/null
+++ b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_50000_01_membership_test_result.json
@@ -0,0 +1 @@
+{"membershipTestResults" : "1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000100000000000000000000000000000000000000000000000000100000000000000000000000000000000000010000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000010010000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000010000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000001000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000010000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000100000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000100000000000000000000000000000000001000000000000000000000000101000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000100000000001000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000100000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000010000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010001000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000010000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000100000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000100000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000100000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000001000000000001000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000001000000001000000000000000000000000000000000000000000000000000000001000000000000000000001000000000000001000000000000100000000000000000000000000000000000000001100000000010000000000000000000000000000000000000000000000000000010001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000100000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000010000000000000000000010000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000100000000000000000100100000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000001000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000100000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000010000000000000000000010000000000000000000000000000000000000000000000000000000000000000000001000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000100000000000000000000000000000100000010000000000000000000000000000000000001000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000001000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000100000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000001000000000000000000000000000000000000000000000000000000000000000001000000000000000000000001000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000001000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000010000000000001000000000000000000000000000010000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000100000001000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000001100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000000000000000000000000000000000000000000000000010000000000000000000000000100000000000000000000000000000000000000000000000100000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000001000000000000000000000000000000000000001000000000000000000000000010000000000000000000000000000000000000001000000000000000000000000000000001000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000010010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000100000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100001000000000000000000010000000000000000000000000000000000000000000000001000001000000000000000000000000000000000000000000001000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000010000000000010000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000001000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000001000000000000000000000100000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000010000000000010010000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010100000000001000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000010010000000010000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100100000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000100000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000001000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100100000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000100010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000010000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000010000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000010000000000000000000000000000000000000100000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000010000000000000000000000000000000000000000000001000010000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000100000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000000000000000010000000000000000010000000000000000000000000000000000000000000000000000001000000000000000000000000001000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000100000000000100000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000001000000000000000000000000000000000000000000000000000001000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000100000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000100000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000010000000001000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000010000000000000000000000000000010000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000010010000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000001000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}
diff --git a/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_50000_1_bloom_filter_proto.json b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_50000_1_bloom_filter_proto.json
new file mode 100644
index 00000000000..c03535eafc3
--- /dev/null
+++ b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_50000_1_bloom_filter_proto.json
@@ -0,0 +1 @@
+{"bits":{"bitmap":"","padding":0},"hashCount":0}
\ No newline at end of file
diff --git a/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_50000_1_membership_test_result.json b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_50000_1_membership_test_result.json
new file mode 100644
index 00000000000..8872f804c6c
--- /dev/null
+++ b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_50000_1_membership_test_result.json
@@ -0,0 +1 @@
+{"membershipTestResults" : "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}
\ No newline at end of file
diff --git a/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_5000_0001_bloom_filter_proto.json b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_5000_0001_bloom_filter_proto.json
new file mode 100644
index 00000000000..41f4c45b813
--- /dev/null
+++ b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_5000_0001_bloom_filter_proto.json
@@ -0,0 +1 @@
+{"bits":{"bitmap":"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","padding":7},"hashCount":13}
diff --git a/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_5000_0001_membership_test_result.json b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_5000_0001_membership_test_result.json
new file mode 100644
index 00000000000..e93415cc7e6
--- /dev/null
+++ b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_5000_0001_membership_test_result.json
@@ -0,0 +1 @@
+{"membershipTestResults" : "1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}
diff --git a/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_5000_01_bloom_filter_proto.json b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_5000_01_bloom_filter_proto.json
new file mode 100644
index 00000000000..0cd630436d1
--- /dev/null
+++ b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_5000_01_bloom_filter_proto.json
@@ -0,0 +1 @@
+{"bits":{"bitmap":"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","padding":3},"hashCount":7}
diff --git a/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_5000_01_membership_test_result.json b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_5000_01_membership_test_result.json
new file mode 100644
index 00000000000..416b190ec53
--- /dev/null
+++ b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_5000_01_membership_test_result.json
@@ -0,0 +1 @@
+{"membershipTestResults" : "1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000100000000000000000000000000000000110000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000001000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000010000000000000000000000000100000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000001000000000000000000000000000000000000000000000010100000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000010000000000000000000000000000000000000000000000000100000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000"}
\ No newline at end of file
diff --git a/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_5000_1_bloom_filter_proto.json b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_5000_1_bloom_filter_proto.json
new file mode 100644
index 00000000000..c03535eafc3
--- /dev/null
+++ b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_5000_1_bloom_filter_proto.json
@@ -0,0 +1 @@
+{"bits":{"bitmap":"","padding":0},"hashCount":0}
\ No newline at end of file
diff --git a/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_5000_1_membership_test_result.json b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_5000_1_membership_test_result.json
new file mode 100644
index 00000000000..d568ff095e5
--- /dev/null
+++ b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_5000_1_membership_test_result.json
@@ -0,0 +1 @@
+{"membershipTestResults" : "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}
diff --git a/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_500_0001_bloom_filter_proto.json b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_500_0001_bloom_filter_proto.json
new file mode 100644
index 00000000000..b206a483c54
--- /dev/null
+++ b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_500_0001_bloom_filter_proto.json
@@ -0,0 +1 @@
+{"bits":{"bitmap":"vusW6Yc2oIsxmEapab4xh7Qqznx2LAVmFrA3SquH85kFR8l+/MpCIokPAAMuIAmKqcrwBtx/I8ds9Uw9ApHW2KZ/BMTbijPDac2Hm0oQvWFkUjycX7gNQrkjDIsRBdO/IaYDwAh74QwofDQLYxrSNgAdT+stIC7UKnpxZl1tRKTnIa0JQXrRChmxvO4r6WQI9QR76uk55KNZFQ5YmgvT6uYeTafiJEZb61Q9V3OOks44hV83F/8/rgPvRoweLHFJ+ezSJ04P9A+a1DHlMtpriDsxVIAgJm/CKuPkBC1jitppF9CagnLPidC65F1OPSE+8RAzHaEfuic32yNJEuQZfb1hq4pwE62hQ0/ulczuNFsQykikNcGBAWWDHWK4ur6dwjQSP7tOq3m4fLK3xYQt41OpIdPzPfn1Y4NC+BFdKQZUhIxEpTX2TPFoGsW9iSqRvF2zzWstAjcOyvT/yJ36ijEjVV9O+/NWfZvxUft26/NNDRPhpnxXHFGei10qKGMYym/seFr5+Hm2bpczLfpZtfQt/IHKg8Lyr8uMoAK5YhYrTqKY5DDo2jCPGnIbgwYJUDQRL34Eegvnd6T0A6XaU0y+SXbbfbk2vHybVZwuGEobTYZabE2bNg0rmdYx4LJvODl2ZFN7WZ5isyUAtBJJa16Py2PfLBxfrCScVpQJr6Xdka6eUrHA4wAT7V+r3NCZslUJyQky4lDjtacCVsRo2ONMGuWkUh9xqynRCQ85d21St+xAo4pl/V0ld1FeU6sOVGzV5oHosji3S4DFZZ+UZbKdAQwqR+UY+DRN0Vt51MZheZ1YYJd80ZX4DTshs6feSJpktuOBWJGftFzdbIIclJG29KKbwSpR25wGKnFafI2rwItNizCTVkxa/aQnTYF4PGhBmLu0zfEpaIz3pmpMUO7TPE1aYjyV8xakSJA4iDMQI3Z7n/6eF7PFxy/qUNuzHzmV3PoyvOjIC8GNnWaUdw9SlwTr/2LUzQ4fhucCykIAHcgawtcD/7whga1Z/LfOPROF1JfKw7a8H0vERX3WC427LHjbvbhAw0KnSfyIPMok49H20i3oZOdHQE0wxYj/1APD8JfU/TlMW1umRVARZ8ohWLF0oZcohEqexajnKREArfVvvBroyFvI5yRgR4vQapTI0RPCmi4tNbw11Zgy43snKG2pVYR2S4I/Dg9rcK4Plr301TIbFRAT0CE+vqUAjg56lkxcDnUxMW/p9qDU2bILaypkXyr16SiZxc9bMvYEVVBztcbyU6uI+JLFruiPl4mHHv6IylJIc7HJ1vL1gnRTP3bBBvw5qyEl0KS6woregx1RAbPszwxRrTR+zfxV9tUKuC59BZHlmpC5YFAK2wLyU1d5rQyhMN4ySA8POYD6rj80DEZHXQzoTvfQIitPp42unEQRGMKQt/PqljT8A/lBU5DZcc8M3hkFklDpDyIXKuwLkd1zuiPrwzkC27GZ0SZEvQvUi3xVefevyFdY8lAeAlP17z57E+vKDjG9Guo+sX7I1qByNUBpMSO4UkOMP9otRBToRjxD1Rb+lEdGCUwcFm677KL6hR9e3Om9PWkZF6LpWqH+qnt9+lPVxgY=","padding":5},"hashCount":13}
diff --git a/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_500_0001_membership_test_result.json b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_500_0001_membership_test_result.json
new file mode 100644
index 00000000000..3bcbf418c24
--- /dev/null
+++ b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_500_0001_membership_test_result.json
@@ -0,0 +1 @@
+{"membershipTestResults" : "1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}
\ No newline at end of file
diff --git a/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_500_01_bloom_filter_proto.json b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_500_01_bloom_filter_proto.json
new file mode 100644
index 00000000000..35de64eee0a
--- /dev/null
+++ b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_500_01_bloom_filter_proto.json
@@ -0,0 +1 @@
+{"bits":{"bitmap":"n+36qf4UgWXLxRabHwqwva8jpXlZ7yfdCjRNwHQ5MBmgc35tGNWFvTgrWyfmznuz1j0wMabH29pR84MjjWGgAxLhDXU3dyYTY505812+BYTO5GXEAyGoUZhcBlUZPK+RAqSZ+9e3q9Gxpmoes/4iCbxJFc5eew0+95v5Z0h5fvlF2Y9iRBDu2PWC1pVGuc/j3W+34+5IwPtDLPbtfvYhnohTfXP02vsf2/77YqEtfmMVFfIMZJ5e7uLOA+rcmQC5fFfxjubJfKR5R+Rzw/UWd0Eg3gi+FCUIk/WUP5938R4tPH3fnrtQjclvsZhtj5dak7WWw1Ph4ZFdJE2XdFBH1JSvggI5tFKH5WUeIBlHYj+V3HomQ2gDrwMXGsIJokcwQi1qTUjECnwYGlOl/FRjZQg7h3QoSkyxgBnp6w7XKttc/EJf+279WLkvm6K/sTuQiFsOGqdQQ+c6osu9SzICn7Rtu4+RzmfxgCx1i2rX1OvVt+DLWa8/K5TlLvVM7GqXiHeaLuvkaz4uR754T1Iurp8/Ps2yJdXYHLyGndJa+7DJ1BPsGK8ZYbYFN7jGamHF9de+3K/syp1raDltsNUxUGAaMBghK1nIRDtHLSHBtVkuxvUkP3iVIkm6pEp0K/2npYUEAsbYVkug4Iv7qhnLTGwMUXP3piTMySLLoZ9bGY0k13FMX7h/s79dJDcIIf4fR9S0SN6fWXKdZOBLFzyXGcxbD+o0o3NO/UOZDgmTet2or8rvipr4tGDyGluUnW1o/fWPlGvEIo/7Ep6avGyw7jilLKYiunAA","padding":7},"hashCount":7}
\ No newline at end of file
diff --git a/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_500_01_membership_test_result.json b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_500_01_membership_test_result.json
new file mode 100644
index 00000000000..2a851465e72
--- /dev/null
+++ b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_500_01_membership_test_result.json
@@ -0,0 +1 @@
+{"membershipTestResults" : "1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111100000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}
diff --git a/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_500_1_bloom_filter_proto.json b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_500_1_bloom_filter_proto.json
new file mode 100644
index 00000000000..c03535eafc3
--- /dev/null
+++ b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_500_1_bloom_filter_proto.json
@@ -0,0 +1 @@
+{"bits":{"bitmap":"","padding":0},"hashCount":0}
\ No newline at end of file
diff --git a/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_500_1_membership_test_result.json b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_500_1_membership_test_result.json
new file mode 100644
index 00000000000..d59b3592362
--- /dev/null
+++ b/firebase-firestore/src/test/resources/bloom_filter_golden_test_data/Validation_BloomFilterTest_MD5_500_1_membership_test_result.json
@@ -0,0 +1 @@
+{"membershipTestResults" : "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}
\ No newline at end of file
From 3e3d2b00dbd581bf7f5a3e1e42ec7fb78ed3c68a Mon Sep 17 00:00:00 2001
From: milaGGL <107142260+milaGGL@users.noreply.github.com>
Date: Thu, 5 Jan 2023 16:54:58 -0800
Subject: [PATCH 03/27] Remove BigInteger
---
.../firebase/firestore/remote/BloomFilter.java | 16 ++--------------
1 file changed, 2 insertions(+), 14 deletions(-)
diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java
index 42340307ab4..9f972466a84 100644
--- a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java
+++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java
@@ -16,15 +16,12 @@
import androidx.annotation.NonNull;
import com.google.firebase.firestore.util.Logger;
-import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
public class BloomFilter {
private static final String TAG = "BloomFilter";
- private static final BigInteger MAX_64_BIT_UNSIGNED_INTEGER =
- new BigInteger("ffffffffffffffff", 16);
private final int size;
private final byte[] bitmap;
@@ -110,18 +107,9 @@ public static long getLongLittleEndian(byte[] bytes, int offset) {
// Calculate the ith hash value based on the hashed 64bit integers,
// and calculate its corresponding bit index in the bitmap to be checked.
private int getBitIndex(long num1, long num2, int index) {
- BigInteger bigInteger1 = new BigInteger(Long.toUnsignedString(num1));
- BigInteger bigInteger2 = new BigInteger(Long.toUnsignedString(num2));
-
// Calculate hashed value h(i) = h1 + (i * h2).
- BigInteger hashValue = bigInteger1.add(bigInteger2.multiply(BigInteger.valueOf(index)));
-
- // Wrap if hash value overflow 64bit.
- if (hashValue.compareTo(this.MAX_64_BIT_UNSIGNED_INTEGER) == 1) {
- hashValue = new BigInteger(Long.toUnsignedString(hashValue.longValue()));
- }
-
- return hashValue.mod(BigInteger.valueOf(this.size)).intValue();
+ Long hashValue2 = num1 + num2 * index;
+ return (int) Long.remainderUnsigned(hashValue2, this.size);
}
// Return whether the bit on the given index in the bitmap is set to 1.
From 0a3c6f9a96100e1342f9c5410a42431f8fc9d5df Mon Sep 17 00:00:00 2001
From: milaGGL <107142260+milaGGL@users.noreply.github.com>
Date: Fri, 6 Jan 2023 13:29:46 -0800
Subject: [PATCH 04/27] resolve comments
---
.../firestore/remote/BloomFilter.java | 53 ++++++-------
.../firestore/remote/UnsignedLong.java | 79 +++++++++++++++++++
.../firestore/remote/BloomFilterTest.java | 27 ++++---
3 files changed, 122 insertions(+), 37 deletions(-)
create mode 100644 firebase-firestore/src/main/java/com/google/firebase/firestore/remote/UnsignedLong.java
diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java
index 9f972466a84..54eb5206177 100644
--- a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java
+++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java
@@ -14,20 +14,18 @@
package com.google.firebase.firestore.remote;
+import android.util.Base64;
import androidx.annotation.NonNull;
-import com.google.firebase.firestore.util.Logger;
+import androidx.annotation.VisibleForTesting;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
-import java.util.Arrays;
public class BloomFilter {
- private static final String TAG = "BloomFilter";
-
private final int size;
private final byte[] bitmap;
private final int hashCount;
- public BloomFilter(@NonNull byte[] bitmap, @NonNull int padding, @NonNull int hashCount) {
+ public BloomFilter(@NonNull byte[] bitmap, int padding, int hashCount) {
if (padding < 0 || padding >= 8) {
throw new IllegalArgumentException("Invalid padding: " + padding);
}
@@ -52,12 +50,9 @@ public BloomFilter(@NonNull byte[] bitmap, @NonNull int padding, @NonNull int ha
this.size = bitmap.length * 8 - padding;
}
- @NonNull
- public int getSize() {
- return this.size;
- }
-
- public boolean isEmpty() {
+ /** Return if a bloom filter is empty. */
+ @VisibleForTesting
+ boolean isEmpty() {
return this.size == 0;
}
@@ -67,13 +62,14 @@ public boolean mightContain(@NonNull String value) {
return false;
}
- byte[] md5HashedValue = this.MD5Hash(value);
- if (md5HashedValue == null || md5HashedValue.length != 16) {
- return false;
+ byte[] md5HashedValue = md5Hash(value);
+ if (md5HashedValue.length != 16) {
+ throw new RuntimeException(
+ "Invalid md5HashedValue.length: " + md5HashedValue.length + " (expected 16)");
}
- long hash1 = this.getLongLittleEndian(md5HashedValue, 0);
- long hash2 = this.getLongLittleEndian(md5HashedValue, 8);
+ long hash1 = getLongLittleEndian(md5HashedValue, 0);
+ long hash2 = getLongLittleEndian(md5HashedValue, 8);
for (int i = 0; i < this.hashCount; i++) {
int index = this.getBitIndex(hash1, hash2, i);
@@ -84,19 +80,19 @@ public boolean mightContain(@NonNull String value) {
return true;
}
- public static byte[] MD5Hash(String value) {
+ @NonNull
+ public static byte[] md5Hash(@NonNull String value) {
+ MessageDigest digest;
try {
- MessageDigest digest = MessageDigest.getInstance("MD5");
- digest.update(value.getBytes());
- return digest.digest();
+ digest = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
- Logger.warn(TAG, "Could not create hashing algorithm: MD5.", e);
- return null;
+ throw new RuntimeException("Missing MD5 MessageDigest provider.", e);
}
+ return digest.digest(value.getBytes());
}
// Interpret 8 bytes into a long, using little endian 2’s complement.
- public static long getLongLittleEndian(byte[] bytes, int offset) {
+ public static long getLongLittleEndian(@NonNull byte[] bytes, int offset) {
long result = 0;
for (int i = 0; i < 8 && i < bytes.length; i++) {
result |= (bytes[offset + i] & 0xFFL) << (i * 8);
@@ -106,10 +102,11 @@ public static long getLongLittleEndian(byte[] bytes, int offset) {
// Calculate the ith hash value based on the hashed 64bit integers,
// and calculate its corresponding bit index in the bitmap to be checked.
- private int getBitIndex(long num1, long num2, int index) {
+ private int getBitIndex(long hash1, long hash2, int index) {
// Calculate hashed value h(i) = h1 + (i * h2).
- Long hashValue2 = num1 + num2 * index;
- return (int) Long.remainderUnsigned(hashValue2, this.size);
+ long combinedHash = hash1 + (hash2 * index);
+ long mod = UnsignedLong.remainder(combinedHash, this.size);
+ return (int) mod;
}
// Return whether the bit on the given index in the bitmap is set to 1.
@@ -123,12 +120,12 @@ private boolean isBitSet(int index) {
@Override
public String toString() {
return "BloomFilter{"
- + "bitmap="
- + Arrays.toString(bitmap)
+ ", hashCount="
+ hashCount
+ ", size="
+ size
+ + "bitmap="
+ + Base64.encodeToString(bitmap, Base64.NO_WRAP)
+ '}';
}
}
diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/UnsignedLong.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/UnsignedLong.java
new file mode 100644
index 00000000000..b9c9daf8476
--- /dev/null
+++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/UnsignedLong.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2008 The Guava Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License
+ * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.google.firebase.firestore.remote;
+
+public class UnsignedLong {
+
+ /**
+ * Returns dividend % divisor, where the dividend and divisor are treated as unsigned 64-bit
+ * quantities.
+ *
+ * Java 8 users: use {@link Long#remainderUnsigned(long, long)} instead.
+ *
+ * @param dividend the dividend (numerator)
+ * @param divisor the divisor (denominator)
+ * @throws ArithmeticException if divisor is 0
+ * @since 11.0
+ */
+ public static long remainder(long dividend, long divisor) {
+ if (divisor < 0) { // i.e., divisor >= 2^63:
+ if (compare(dividend, divisor) < 0) {
+ return dividend; // dividend < divisor
+ } else {
+ return dividend - divisor; // dividend >= divisor
+ }
+ }
+
+ // Optimization - use signed modulus if dividend < 2^63
+ if (dividend >= 0) {
+ return dividend % divisor;
+ }
+
+ /*
+ * Otherwise, approximate the quotient, check, and correct if necessary. Our approximation is
+ * guaranteed to be either exact or one less than the correct value. This follows from the fact
+ * that floor(floor(x)/i) == floor(x/i) for any real x and integer i != 0. The proof is not
+ * quite trivial.
+ */
+ long quotient = ((dividend >>> 1) / divisor) << 1;
+ long rem = dividend - quotient * divisor;
+ return rem - (compare(rem, divisor) >= 0 ? divisor : 0);
+ }
+
+ /**
+ * Compares the two specified {@code long} values, treating them as unsigned values between {@code
+ * 0} and {@code 2^64 - 1} inclusive.
+ *
+ *
Java 8 users: use {@link Long#compareUnsigned(long, long)} instead.
+ *
+ * @param a the first unsigned {@code long} to compare
+ * @param b the second unsigned {@code long} to compare
+ * @return a negative value if {@code a} is less than {@code b}; a positive value if {@code a} is
+ * greater than {@code b}; or zero if they are equal
+ */
+ public static int compare(long a, long b) {
+ a = flip(a);
+ b = flip(b);
+ return Long.compare(a, b);
+ }
+
+ /**
+ * A (self-inverse) bijection which converts the ordering on unsigned longs to the ordering on
+ * longs, that is, {@code a <= b} as unsigned longs if and only if {@code flip(a) <= flip(b)} as
+ * signed longs.
+ */
+ private static long flip(long a) {
+ return a ^ Long.MIN_VALUE;
+ }
+}
diff --git a/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/BloomFilterTest.java b/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/BloomFilterTest.java
index 5bbc17e4969..0840a34815b 100644
--- a/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/BloomFilterTest.java
+++ b/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/BloomFilterTest.java
@@ -39,7 +39,7 @@ public class BloomFilterTest {
@Test
public void testEmptyBloomFilter() {
BloomFilter bloomFilter = new BloomFilter(new byte[0], 0, 0);
- assertEquals(bloomFilter.getSize(), 0);
+ assertTrue(bloomFilter.isEmpty());
}
@Test
@@ -57,9 +57,9 @@ public void testEmptyBloomFilterThrowException() {
@Test
public void testNonEmptyBloomFilter() {
BloomFilter bloomFilter1 = new BloomFilter(new byte[1], 0, 1);
- assertEquals(bloomFilter1.getSize(), 8);
+ assertFalse(bloomFilter1.isEmpty());
BloomFilter bloomFilter2 = new BloomFilter(new byte[1], 7, 1);
- assertEquals(bloomFilter2.getSize(), 1);
+ assertFalse(bloomFilter2.isEmpty());
}
@Test
@@ -115,7 +115,6 @@ public void testBloomFilterMightContainOnEmptyStringAlwaysReturnFalse() {
* membership results from n to 2n is expected to be false with some false positive results.
*/
@Test
- @SuppressWarnings("DefaultCharset")
public void testBloomFilterGoldenTest() throws Exception {
String documentPrefix = "projects/project-1/databases/database-1/documents/coll/doc";
@@ -123,19 +122,20 @@ public void testBloomFilterGoldenTest() throws Exception {
HashMap parsedSpecFiles = new HashMap<>();
File jsonDir = new File("src/test/resources/bloom_filter_golden_test_data");
File[] jsonFiles = jsonDir.listFiles();
- for (File f : jsonFiles) {
- if (!f.toString().endsWith(".json")) {
+ assert jsonFiles != null;
+ for (File file : jsonFiles) {
+ if (!file.toString().endsWith(".json")) {
continue;
}
// Read the files into a map.
StringBuilder builder = new StringBuilder();
- BufferedReader reader = new BufferedReader(new FileReader(f));
+ BufferedReader reader = new BufferedReader(new FileReader(file));
Stream lines = reader.lines();
lines.forEach(builder::append);
String json = builder.toString();
JSONObject fileJSON = new JSONObject(json);
- parsedSpecFiles.put(f.getName(), fileJSON);
+ parsedSpecFiles.put(file.getName(), fileJSON);
}
// Loop and test the files
@@ -146,6 +146,7 @@ public void testBloomFilterGoldenTest() throws Exception {
// Read test data and instantiate a BloomFilter object
JSONObject fileJSON = parsedSpecFiles.get(fileName);
+ assert fileJSON != null;
JSONObject bits = fileJSON.getJSONObject("bits");
String bitmap = bits.getString("bitmap");
int padding = bits.getInt("padding");
@@ -156,13 +157,21 @@ public void testBloomFilterGoldenTest() throws Exception {
// Find corresponding membership test result.
JSONObject resultJSON =
parsedSpecFiles.get(fileName.replace("bloom_filter_proto", "membership_test_result"));
+ assert resultJSON != null;
String membershipTestResults = resultJSON.getString("membershipTestResults");
// Run and compare mightContain result with the expectation.
for (int i = 0; i < membershipTestResults.length(); i++) {
boolean expectedMembershipResult = membershipTestResults.charAt(i) == '1';
boolean mightContain = bloomFilter.mightContain(documentPrefix + i);
- assertEquals(mightContain, expectedMembershipResult);
+ assertEquals(
+ "MightContain result doesn't match the expectation. File: "
+ + fileName
+ + ". Document: "
+ + documentPrefix
+ + i,
+ mightContain,
+ expectedMembershipResult);
}
}
}
From be7071cf11ca451bd914ba018a5bba09106798b8 Mon Sep 17 00:00:00 2001
From: milaGGL <107142260+milaGGL@users.noreply.github.com>
Date: Fri, 6 Jan 2023 14:41:06 -0800
Subject: [PATCH 05/27] removed UnsignedLong class
---
.../firestore/remote/BloomFilter.java | 8 +-
.../firestore/remote/UnsignedLong.java | 79 -------------------
2 files changed, 7 insertions(+), 80 deletions(-)
delete mode 100644 firebase-firestore/src/main/java/com/google/firebase/firestore/remote/UnsignedLong.java
diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java
index 54eb5206177..a66a3688e86 100644
--- a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java
+++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java
@@ -105,10 +105,16 @@ public static long getLongLittleEndian(@NonNull byte[] bytes, int offset) {
private int getBitIndex(long hash1, long hash2, int index) {
// Calculate hashed value h(i) = h1 + (i * h2).
long combinedHash = hash1 + (hash2 * index);
- long mod = UnsignedLong.remainder(combinedHash, this.size);
+ long mod = unsignedRemainder(combinedHash, this.size);
return (int) mod;
}
+ public static long unsignedRemainder(long dividend, int divisor) {
+ long quotient = ((dividend >>> 1) / divisor) << 1;
+ long remainder = dividend - quotient * divisor;
+ return remainder - (remainder >= divisor ? divisor : 0);
+ }
+
// Return whether the bit on the given index in the bitmap is set to 1.
private boolean isBitSet(int index) {
// To retrieve bit n, calculate: (bitmap[n / 8] & (0x01 << (n % 8))).
diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/UnsignedLong.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/UnsignedLong.java
deleted file mode 100644
index b9c9daf8476..00000000000
--- a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/UnsignedLong.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 2008 The Guava Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
- * in compliance with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software distributed under the License
- * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
- * or implied. See the License for the specific language governing permissions and limitations under
- * the License.
- */
-package com.google.firebase.firestore.remote;
-
-public class UnsignedLong {
-
- /**
- * Returns dividend % divisor, where the dividend and divisor are treated as unsigned 64-bit
- * quantities.
- *
- * Java 8 users: use {@link Long#remainderUnsigned(long, long)} instead.
- *
- * @param dividend the dividend (numerator)
- * @param divisor the divisor (denominator)
- * @throws ArithmeticException if divisor is 0
- * @since 11.0
- */
- public static long remainder(long dividend, long divisor) {
- if (divisor < 0) { // i.e., divisor >= 2^63:
- if (compare(dividend, divisor) < 0) {
- return dividend; // dividend < divisor
- } else {
- return dividend - divisor; // dividend >= divisor
- }
- }
-
- // Optimization - use signed modulus if dividend < 2^63
- if (dividend >= 0) {
- return dividend % divisor;
- }
-
- /*
- * Otherwise, approximate the quotient, check, and correct if necessary. Our approximation is
- * guaranteed to be either exact or one less than the correct value. This follows from the fact
- * that floor(floor(x)/i) == floor(x/i) for any real x and integer i != 0. The proof is not
- * quite trivial.
- */
- long quotient = ((dividend >>> 1) / divisor) << 1;
- long rem = dividend - quotient * divisor;
- return rem - (compare(rem, divisor) >= 0 ? divisor : 0);
- }
-
- /**
- * Compares the two specified {@code long} values, treating them as unsigned values between {@code
- * 0} and {@code 2^64 - 1} inclusive.
- *
- *
Java 8 users: use {@link Long#compareUnsigned(long, long)} instead.
- *
- * @param a the first unsigned {@code long} to compare
- * @param b the second unsigned {@code long} to compare
- * @return a negative value if {@code a} is less than {@code b}; a positive value if {@code a} is
- * greater than {@code b}; or zero if they are equal
- */
- public static int compare(long a, long b) {
- a = flip(a);
- b = flip(b);
- return Long.compare(a, b);
- }
-
- /**
- * A (self-inverse) bijection which converts the ordering on unsigned longs to the ordering on
- * longs, that is, {@code a <= b} as unsigned longs if and only if {@code flip(a) <= flip(b)} as
- * signed longs.
- */
- private static long flip(long a) {
- return a ^ Long.MIN_VALUE;
- }
-}
From ffe0a1dc97ba78dd5f84127cff7ffb01a1a80853 Mon Sep 17 00:00:00 2001
From: milaGGL <107142260+milaGGL@users.noreply.github.com>
Date: Fri, 6 Jan 2023 14:44:04 -0800
Subject: [PATCH 06/27] make methods private
---
.../com/google/firebase/firestore/remote/BloomFilter.java | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java
index a66a3688e86..32e6a6375d5 100644
--- a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java
+++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java
@@ -81,7 +81,7 @@ public boolean mightContain(@NonNull String value) {
}
@NonNull
- public static byte[] md5Hash(@NonNull String value) {
+ private static byte[] md5Hash(@NonNull String value) {
MessageDigest digest;
try {
digest = MessageDigest.getInstance("MD5");
@@ -92,7 +92,7 @@ public static byte[] md5Hash(@NonNull String value) {
}
// Interpret 8 bytes into a long, using little endian 2’s complement.
- public static long getLongLittleEndian(@NonNull byte[] bytes, int offset) {
+ private static long getLongLittleEndian(@NonNull byte[] bytes, int offset) {
long result = 0;
for (int i = 0; i < 8 && i < bytes.length; i++) {
result |= (bytes[offset + i] & 0xFFL) << (i * 8);
@@ -109,7 +109,7 @@ private int getBitIndex(long hash1, long hash2, int index) {
return (int) mod;
}
- public static long unsignedRemainder(long dividend, int divisor) {
+ private static long unsignedRemainder(long dividend, int divisor) {
long quotient = ((dividend >>> 1) / divisor) << 1;
long remainder = dividend - quotient * divisor;
return remainder - (remainder >= divisor ? divisor : 0);
From b50b49a787d23e603f3bd68d7083acd42beb07ef Mon Sep 17 00:00:00 2001
From: milaGGL <107142260+milaGGL@users.noreply.github.com>
Date: Fri, 6 Jan 2023 15:16:28 -0800
Subject: [PATCH 07/27] add javadocs
---
.../firestore/remote/BloomFilter.java | 22 ++++++++++++++-----
1 file changed, 17 insertions(+), 5 deletions(-)
diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java
index 32e6a6375d5..beb77f858ce 100644
--- a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java
+++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java
@@ -56,6 +56,14 @@ boolean isEmpty() {
return this.size == 0;
}
+ /**
+ * Check whether the document path is a possible member of the bloom filter. It might return false
+ * positive result, ie, a document path is not a member of the bloom filter, but the method
+ * returned true.
+ *
+ * @param value a string representation of the document path.
+ * @return true if the document path might be contained in the bloom filter.
+ */
public boolean mightContain(@NonNull String value) {
// Empty bitmap or empty value should always return false on membership check.
if (this.isEmpty() || value.isEmpty()) {
@@ -80,6 +88,7 @@ public boolean mightContain(@NonNull String value) {
return true;
}
+ /** Hash a string using md5 hashing algorithm, and return an array of 16 bytes. */
@NonNull
private static byte[] md5Hash(@NonNull String value) {
MessageDigest digest;
@@ -91,7 +100,7 @@ private static byte[] md5Hash(@NonNull String value) {
return digest.digest(value.getBytes());
}
- // Interpret 8 bytes into a long, using little endian 2’s complement.
+ /** Interpret 8 bytes into a long, using little endian 2’s complement. */
private static long getLongLittleEndian(@NonNull byte[] bytes, int offset) {
long result = 0;
for (int i = 0; i < 8 && i < bytes.length; i++) {
@@ -100,8 +109,10 @@ private static long getLongLittleEndian(@NonNull byte[] bytes, int offset) {
return result;
}
- // Calculate the ith hash value based on the hashed 64bit integers,
- // and calculate its corresponding bit index in the bitmap to be checked.
+ /**
+ * Calculate the ith hash value based on the hashed 64bit integers, and calculate its
+ * corresponding bit index in the bitmap to be checked.
+ */
private int getBitIndex(long hash1, long hash2, int index) {
// Calculate hashed value h(i) = h1 + (i * h2).
long combinedHash = hash1 + (hash2 * index);
@@ -109,13 +120,14 @@ private int getBitIndex(long hash1, long hash2, int index) {
return (int) mod;
}
- private static long unsignedRemainder(long dividend, int divisor) {
+ /** Calculate module, where the dividend and divisor are treated as unsigned 64-bit longs. */
+ private static long unsignedRemainder(long dividend, long divisor) {
long quotient = ((dividend >>> 1) / divisor) << 1;
long remainder = dividend - quotient * divisor;
return remainder - (remainder >= divisor ? divisor : 0);
}
- // Return whether the bit on the given index in the bitmap is set to 1.
+ /** Return whether the bit on the given index in the bitmap is set to 1. */
private boolean isBitSet(int index) {
// To retrieve bit n, calculate: (bitmap[n / 8] & (0x01 << (n % 8))).
byte byteAtIndex = this.bitmap[(index / 8)];
From 1099d179111c77d68750590d7cf21a5b124d63c5 Mon Sep 17 00:00:00 2001
From: milaGGL <107142260+milaGGL@users.noreply.github.com>
Date: Mon, 9 Jan 2023 23:19:53 -0800
Subject: [PATCH 08/27] resolve comments
---
.../firestore/remote/BloomFilter.java | 63 +++--
.../firestore/remote/BloomFilterTest.java | 264 +++++++++++-------
2 files changed, 213 insertions(+), 114 deletions(-)
diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java
index beb77f858ce..fee1a49f4df 100644
--- a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java
+++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java
@@ -17,6 +17,7 @@
import android.util.Base64;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
+import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
@@ -24,8 +25,12 @@ public class BloomFilter {
private final int size;
private final byte[] bitmap;
private final int hashCount;
+ private static MessageDigest md5HashMessageDigest;
public BloomFilter(@NonNull byte[] bitmap, int padding, int hashCount) {
+ if (bitmap == null) {
+ throw new NullPointerException("Bitmap cannot be null.");
+ }
if (padding < 0 || padding >= 8) {
throw new IllegalArgumentException("Invalid padding: " + padding);
}
@@ -48,21 +53,26 @@ public BloomFilter(@NonNull byte[] bitmap, int padding, int hashCount) {
this.bitmap = bitmap;
this.hashCount = hashCount;
this.size = bitmap.length * 8 - padding;
+ this.md5HashMessageDigest = getMd5HashMessageDigest();
}
- /** Return if a bloom filter is empty. */
- @VisibleForTesting
- boolean isEmpty() {
+ private boolean isEmpty() {
return this.size == 0;
}
+ /** Returns the number of bits in the bloom filter. */
+ @VisibleForTesting
+ int getSize() {
+ return this.size;
+ }
+
/**
- * Check whether the document path is a possible member of the bloom filter. It might return false
- * positive result, ie, a document path is not a member of the bloom filter, but the method
+ * Check whether the given string is a possible member of the bloom filter. It might return false
+ * positive result, ie, the given string is not a member of the bloom filter, but the method
* returned true.
*
- * @param value a string representation of the document path.
- * @return true if the document path might be contained in the bloom filter.
+ * @param value the string to be tested membership.
+ * @return true if the given string might be contained in the bloom filter.
*/
public boolean mightContain(@NonNull String value) {
// Empty bitmap or empty value should always return false on membership check.
@@ -70,14 +80,14 @@ public boolean mightContain(@NonNull String value) {
return false;
}
- byte[] md5HashedValue = md5Hash(value);
- if (md5HashedValue.length != 16) {
+ byte[] hashedValue = md5HashDigest(value);
+ if (hashedValue.length != 16) {
throw new RuntimeException(
- "Invalid md5HashedValue.length: " + md5HashedValue.length + " (expected 16)");
+ "Invalid md5HashedValue.length: " + hashedValue.length + " (expected 16)");
}
- long hash1 = getLongLittleEndian(md5HashedValue, 0);
- long hash2 = getLongLittleEndian(md5HashedValue, 8);
+ long hash1 = getLongLittleEndian(hashedValue, 0);
+ long hash2 = getLongLittleEndian(hashedValue, 8);
for (int i = 0; i < this.hashCount; i++) {
int index = this.getBitIndex(hash1, hash2, i);
@@ -90,20 +100,25 @@ public boolean mightContain(@NonNull String value) {
/** Hash a string using md5 hashing algorithm, and return an array of 16 bytes. */
@NonNull
- private static byte[] md5Hash(@NonNull String value) {
+ private static byte[] md5HashDigest(@NonNull String value) {
+ return md5HashMessageDigest.digest(value.getBytes(StandardCharsets.UTF_8));
+ }
+
+ @NonNull
+ private static MessageDigest getMd5HashMessageDigest() {
MessageDigest digest;
try {
digest = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("Missing MD5 MessageDigest provider.", e);
}
- return digest.digest(value.getBytes());
+ return digest;
}
/** Interpret 8 bytes into a long, using little endian 2’s complement. */
private static long getLongLittleEndian(@NonNull byte[] bytes, int offset) {
long result = 0;
- for (int i = 0; i < 8 && i < bytes.length; i++) {
+ for (int i = 0; i < 8; i++) {
result |= (bytes[offset + i] & 0xFFL) << (i * 8);
}
return result;
@@ -120,14 +135,22 @@ private int getBitIndex(long hash1, long hash2, int index) {
return (int) mod;
}
- /** Calculate module, where the dividend and divisor are treated as unsigned 64-bit longs. */
+ /**
+ * Calculate modulo, where the dividend and divisor are treated as unsigned 64-bit longs.
+ *
+ *
The implementation is taken from Dagger2,
+ * simplified to our needs.
+ *
+ *
+ */
private static long unsignedRemainder(long dividend, long divisor) {
long quotient = ((dividend >>> 1) / divisor) << 1;
long remainder = dividend - quotient * divisor;
return remainder - (remainder >= divisor ? divisor : 0);
}
- /** Return whether the bit on the given index in the bitmap is set to 1. */
+ /** Return whether the bit at the given index in the bitmap is set to 1. */
private boolean isBitSet(int index) {
// To retrieve bit n, calculate: (bitmap[n / 8] & (0x01 << (n % 8))).
byte byteAtIndex = this.bitmap[(index / 8)];
@@ -138,12 +161,12 @@ private boolean isBitSet(int index) {
@Override
public String toString() {
return "BloomFilter{"
- + ", hashCount="
+ + "hashCount="
+ hashCount
+ ", size="
+ size
- + "bitmap="
+ + ", bitmap=\""
+ Base64.encodeToString(bitmap, Base64.NO_WRAP)
- + '}';
+ + "\"}";
}
}
diff --git a/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/BloomFilterTest.java b/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/BloomFilterTest.java
index 0840a34815b..d56ed0c7ce2 100644
--- a/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/BloomFilterTest.java
+++ b/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/BloomFilterTest.java
@@ -21,10 +21,10 @@
import static org.junit.Assert.assertTrue;
import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileReader;
+import java.io.FileInputStream;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
import java.util.Base64;
-import java.util.HashMap;
import java.util.stream.Stream;
import org.json.JSONObject;
import org.junit.Test;
@@ -35,52 +35,78 @@
@RunWith(RobolectricTestRunner.class)
@Config(manifest = Config.NONE)
public class BloomFilterTest {
+ private static final String GOLDEN_DOCUMENT_PREFIX =
+ "projects/project-1/databases/database-1/documents/coll/doc";
+ private static final String GOLDEN_TEST_LOCATION =
+ "src/test/resources/bloom_filter_golden_test_data/";
@Test
- public void testEmptyBloomFilter() {
+ public void instantiateEmptyBloomFilter() {
BloomFilter bloomFilter = new BloomFilter(new byte[0], 0, 0);
- assertTrue(bloomFilter.isEmpty());
+ assertEquals(bloomFilter.getSize(), 0);
}
@Test
- public void testEmptyBloomFilterThrowException() {
- IllegalArgumentException paddingException =
- assertThrows(IllegalArgumentException.class, () -> new BloomFilter(new byte[0], 1, 0));
- assertThat(paddingException)
- .hasMessageThat()
- .contains("Invalid padding when bitmap length is 0: 1");
- IllegalArgumentException hashCountException =
- assertThrows(IllegalArgumentException.class, () -> new BloomFilter(new byte[0], 0, -1));
- assertThat(hashCountException).hasMessageThat().contains("Invalid hash count: -1");
+ public void instantiateNonEmptyBloomFilter() {
+ BloomFilter bloomFilter1 = new BloomFilter(new byte[] {1}, 0, 1);
+ assertEquals(bloomFilter1.getSize(), 8);
+ BloomFilter bloomFilter2 = new BloomFilter(new byte[] {1}, 7, 1);
+ assertEquals(bloomFilter2.getSize(), 1);
}
@Test
- public void testNonEmptyBloomFilter() {
- BloomFilter bloomFilter1 = new BloomFilter(new byte[1], 0, 1);
- assertFalse(bloomFilter1.isEmpty());
- BloomFilter bloomFilter2 = new BloomFilter(new byte[1], 7, 1);
- assertFalse(bloomFilter2.isEmpty());
+ public void constructorShouldThrowNPEOnNullBitmap() {
+ NullPointerException emptyBloomFilterException =
+ assertThrows(NullPointerException.class, () -> new BloomFilter(null, 0, 0));
+ assertThat(emptyBloomFilterException).hasMessageThat().contains("Bitmap cannot be null.");
+ NullPointerException nonEmptyBloomFilterException =
+ assertThrows(NullPointerException.class, () -> new BloomFilter(null, 1, 1));
+ assertThat(nonEmptyBloomFilterException).hasMessageThat().contains("Bitmap cannot be null.");
}
@Test
- public void testNonEmptyBloomFilterThrowException() {
- IllegalArgumentException negativePaddingException =
- assertThrows(IllegalArgumentException.class, () -> new BloomFilter(new byte[1], -1, 1));
- assertThat(negativePaddingException).hasMessageThat().contains("Invalid padding: -1");
- IllegalArgumentException overflowPaddingException =
- assertThrows(IllegalArgumentException.class, () -> new BloomFilter(new byte[1], 8, 1));
- assertThat(overflowPaddingException).hasMessageThat().contains("Invalid padding: 8");
+ public void constructorShouldThrowIAEOnEmptyBloomFilterWithNonZeroPadding() {
+ IllegalArgumentException exception =
+ assertThrows(IllegalArgumentException.class, () -> new BloomFilter(new byte[0], 1, 0));
+ assertThat(exception).hasMessageThat().contains("Invalid padding when bitmap length is 0: 1");
+ }
- IllegalArgumentException negativeHashCountException =
- assertThrows(IllegalArgumentException.class, () -> new BloomFilter(new byte[1], 1, -1));
- assertThat(negativeHashCountException).hasMessageThat().contains("Invalid hash count: -1");
+ @Test
+ public void constructorShouldThrowIAEOnNonEmptyBloomFilterWithZeroHashCount() {
IllegalArgumentException zeroHashCountException =
- assertThrows(IllegalArgumentException.class, () -> new BloomFilter(new byte[1], 1, 0));
+ assertThrows(IllegalArgumentException.class, () -> new BloomFilter(new byte[] {1}, 1, 0));
assertThat(zeroHashCountException).hasMessageThat().contains("Invalid hash count: 0");
}
@Test
- public void testBloomFilterProcessNonStandardCharacters() {
+ public void constructorShouldThrowIAEOnNegativePadding() {
+ IllegalArgumentException emptyBloomFilterException =
+ assertThrows(IllegalArgumentException.class, () -> new BloomFilter(new byte[0], -1, 0));
+ assertThat(emptyBloomFilterException).hasMessageThat().contains("Invalid padding: -1");
+ IllegalArgumentException nonEmptyBloomFilterException =
+ assertThrows(IllegalArgumentException.class, () -> new BloomFilter(new byte[] {1}, -1, 1));
+ assertThat(nonEmptyBloomFilterException).hasMessageThat().contains("Invalid padding: -1");
+ }
+
+ @Test
+ public void constructorShouldThrowIAEOnNegativeHashValue() {
+ IllegalArgumentException emptyBloomFilterException =
+ assertThrows(IllegalArgumentException.class, () -> new BloomFilter(new byte[0], 0, -1));
+ assertThat(emptyBloomFilterException).hasMessageThat().contains("Invalid hash count: -1");
+ IllegalArgumentException nonEmptyBloomFilterException =
+ assertThrows(IllegalArgumentException.class, () -> new BloomFilter(new byte[] {1}, 1, -1));
+ assertThat(nonEmptyBloomFilterException).hasMessageThat().contains("Invalid hash count: -1");
+ }
+
+ @Test
+ public void constructorShouldThrowIAEOnOverflowPadding() {
+ IllegalArgumentException exception =
+ assertThrows(IllegalArgumentException.class, () -> new BloomFilter(new byte[] {1}, 8, 1));
+ assertThat(exception).hasMessageThat().contains("Invalid padding: 8");
+ }
+
+ @Test
+ public void mightContainCanProcessNonStandardCharacters() {
// A non-empty BloomFilter object with 1 insertion : "ÀÒ∑"
BloomFilter bloomFilter = new BloomFilter(new byte[] {(byte) 237, 5}, 5, 8);
assertTrue(bloomFilter.mightContain("ÀÒ∑"));
@@ -88,21 +114,30 @@ public void testBloomFilterProcessNonStandardCharacters() {
}
@Test
- public void testEmptyBloomFilterMightContainAlwaysReturnFalse() {
+ public void mightContainOnEmptyBloomFilterShouldReturnFalse() {
BloomFilter bloomFilter = new BloomFilter(new byte[0], 0, 0);
- assertFalse(bloomFilter.mightContain("abc"));
+ assertFalse(bloomFilter.mightContain("a"));
}
@Test
- public void testBloomFilterMightContainOnEmptyStringAlwaysReturnFalse() {
+ public void mightContainWithEmptyStringShouldReturnFalse() {
BloomFilter emptyBloomFilter = new BloomFilter(new byte[0], 0, 0);
- BloomFilter nonEmptyBloomFilter =
- new BloomFilter(new byte[] {(byte) 255, (byte) 255, (byte) 255}, 1, 16);
+ BloomFilter nonEmptyBloomFilter = new BloomFilter(new byte[] {(byte) 255}, 0, 1);
assertFalse(emptyBloomFilter.mightContain(""));
assertFalse(nonEmptyBloomFilter.mightContain(""));
}
+ @Test
+ public void bloomFilterToString() {
+ BloomFilter emptyBloomFilter = new BloomFilter(new byte[0], 0, 0);
+ assertEquals(emptyBloomFilter.toString(), "BloomFilter{hashCount=0, size=0, bitmap=\"\"}");
+
+ BloomFilter nonEmptyBloomFilter = new BloomFilter(new byte[] {1}, 1, 1);
+ assertEquals(
+ nonEmptyBloomFilter.toString(), "BloomFilter{hashCount=1, size=7, bitmap=\"AQ==\"}");
+ }
+
/**
* Golden tests are generated by backend based on inserting n number of document paths into a
* bloom filter.
@@ -114,65 +149,106 @@ public void testBloomFilterMightContainOnEmptyStringAlwaysReturnFalse() {
* to documentPrefix+2n. The membership results from 0 to n is expected to be true, and the
* membership results from n to 2n is expected to be false with some false positive results.
*/
- @Test
- public void testBloomFilterGoldenTest() throws Exception {
- String documentPrefix = "projects/project-1/databases/database-1/documents/coll/doc";
-
- // Import the golden test files for bloom filter
- HashMap parsedSpecFiles = new HashMap<>();
- File jsonDir = new File("src/test/resources/bloom_filter_golden_test_data");
- File[] jsonFiles = jsonDir.listFiles();
- assert jsonFiles != null;
- for (File file : jsonFiles) {
- if (!file.toString().endsWith(".json")) {
- continue;
- }
-
- // Read the files into a map.
- StringBuilder builder = new StringBuilder();
- BufferedReader reader = new BufferedReader(new FileReader(file));
- Stream lines = reader.lines();
- lines.forEach(builder::append);
- String json = builder.toString();
- JSONObject fileJSON = new JSONObject(json);
- parsedSpecFiles.put(file.getName(), fileJSON);
+ private void runGoldenTest(String testFile) throws Exception {
+ String resultFile = testFile.replace("bloom_filter_proto", "membership_test_result");
+
+ JSONObject testJson = readJsonFile(testFile);
+ JSONObject resultJSON = readJsonFile(resultFile);
+
+ JSONObject bits = testJson.getJSONObject("bits");
+ String bitmap = bits.getString("bitmap");
+ int padding = bits.getInt("padding");
+ int hashCount = testJson.getInt("hashCount");
+ BloomFilter bloomFilter =
+ new BloomFilter(Base64.getDecoder().decode(bitmap), padding, hashCount);
+
+ String membershipTestResults = resultJSON.getString("membershipTestResults");
+
+ // Run and compare mightContain result with the expectation.
+ for (int i = 0; i < membershipTestResults.length(); i++) {
+ boolean expectedMembershipResult = membershipTestResults.charAt(i) == '1';
+ boolean mightContain = bloomFilter.mightContain(GOLDEN_DOCUMENT_PREFIX + i);
+ assertEquals(
+ "mightContain() result doesn't match the expectation. File: "
+ + testFile
+ + ". Document: "
+ + GOLDEN_DOCUMENT_PREFIX
+ + i,
+ mightContain,
+ expectedMembershipResult);
}
+ }
- // Loop and test the files
- for (String fileName : parsedSpecFiles.keySet()) {
- if (fileName.contains("membership_test_result")) {
- continue;
- }
-
- // Read test data and instantiate a BloomFilter object
- JSONObject fileJSON = parsedSpecFiles.get(fileName);
- assert fileJSON != null;
- JSONObject bits = fileJSON.getJSONObject("bits");
- String bitmap = bits.getString("bitmap");
- int padding = bits.getInt("padding");
- int hashCount = fileJSON.getInt("hashCount");
- BloomFilter bloomFilter =
- new BloomFilter(Base64.getDecoder().decode(bitmap), padding, hashCount);
-
- // Find corresponding membership test result.
- JSONObject resultJSON =
- parsedSpecFiles.get(fileName.replace("bloom_filter_proto", "membership_test_result"));
- assert resultJSON != null;
- String membershipTestResults = resultJSON.getString("membershipTestResults");
-
- // Run and compare mightContain result with the expectation.
- for (int i = 0; i < membershipTestResults.length(); i++) {
- boolean expectedMembershipResult = membershipTestResults.charAt(i) == '1';
- boolean mightContain = bloomFilter.mightContain(documentPrefix + i);
- assertEquals(
- "MightContain result doesn't match the expectation. File: "
- + fileName
- + ". Document: "
- + documentPrefix
- + i,
- mightContain,
- expectedMembershipResult);
- }
- }
+ private JSONObject readJsonFile(String fileName) throws Exception {
+ // Read the file into JSON object.
+ StringBuilder builder = new StringBuilder();
+ InputStreamReader streamReader =
+ new InputStreamReader(
+ new FileInputStream(GOLDEN_TEST_LOCATION + fileName), StandardCharsets.UTF_8);
+ BufferedReader reader = new BufferedReader(streamReader);
+ Stream lines = reader.lines();
+ lines.forEach(builder::append);
+ String json = builder.toString();
+ return new JSONObject(json);
+ }
+
+ @Test
+ public void goldenTest_1Document_1FalsePositiveRate() throws Exception {
+ runGoldenTest("Validation_BloomFilterTest_MD5_1_1_bloom_filter_proto.json");
+ }
+
+ @Test
+ public void goldenTest_1Document_01FalsePositiveRate() throws Exception {
+ runGoldenTest("Validation_BloomFilterTest_MD5_1_01_bloom_filter_proto.json");
+ }
+
+ @Test
+ public void goldenTest_1Document_0001FalsePositiveRate() throws Exception {
+ runGoldenTest("Validation_BloomFilterTest_MD5_1_0001_bloom_filter_proto.json");
+ }
+
+ @Test
+ public void goldenTest_500Document_1FalsePositiveRate() throws Exception {
+ runGoldenTest("Validation_BloomFilterTest_MD5_500_1_bloom_filter_proto.json");
+ }
+
+ @Test
+ public void goldenTest_500Document_01FalsePositiveRate() throws Exception {
+ runGoldenTest("Validation_BloomFilterTest_MD5_500_01_bloom_filter_proto.json");
+ }
+
+ @Test
+ public void goldenTest_500Document_0001FalsePositiveRate() throws Exception {
+ runGoldenTest("Validation_BloomFilterTest_MD5_500_0001_bloom_filter_proto.json");
+ }
+
+ @Test
+ public void goldenTest_5000Document_1FalsePositiveRate() throws Exception {
+ runGoldenTest("Validation_BloomFilterTest_MD5_5000_1_bloom_filter_proto.json");
+ }
+
+ @Test
+ public void goldenTest_5000Document_01FalsePositiveRate() throws Exception {
+ runGoldenTest("Validation_BloomFilterTest_MD5_5000_01_bloom_filter_proto.json");
+ }
+
+ @Test
+ public void goldenTest_5000Document_0001FalsePositiveRate() throws Exception {
+ runGoldenTest("Validation_BloomFilterTest_MD5_5000_0001_bloom_filter_proto.json");
+ }
+
+ @Test
+ public void goldenTest_50000Document_1FalsePositiveRate() throws Exception {
+ runGoldenTest("Validation_BloomFilterTest_MD5_50000_1_bloom_filter_proto.json");
+ }
+
+ @Test
+ public void goldenTest_50000Document_01FalsePositiveRate() throws Exception {
+ runGoldenTest("Validation_BloomFilterTest_MD5_50000_01_bloom_filter_proto.json");
+ }
+
+ @Test
+ public void goldenTest_50000Document_0001FalsePositiveRate() throws Exception {
+ runGoldenTest("Validation_BloomFilterTest_MD5_50000_0001_bloom_filter_proto.json");
}
}
From 2f5d335d2eac3745f73bb6ad6b4ec274721cce4b Mon Sep 17 00:00:00 2001
From: milaGGL <107142260+milaGGL@users.noreply.github.com>
Date: Tue, 10 Jan 2023 13:16:11 -0800
Subject: [PATCH 09/27] format
---
.../com/google/firebase/firestore/remote/BloomFilter.java | 2 +-
.../com/google/firebase/firestore/remote/BloomFilterTest.java | 4 +---
2 files changed, 2 insertions(+), 4 deletions(-)
diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java
index fee1a49f4df..b174f32547f 100644
--- a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java
+++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java
@@ -139,7 +139,7 @@ private int getBitIndex(long hash1, long hash2, int index) {
* Calculate modulo, where the dividend and divisor are treated as unsigned 64-bit longs.
*
* The implementation is taken from Dagger2,
+ * href="https://github.com/google/guava/blob/553037486901cc60820ab7dcb38a25b6f34eba43/android/guava/src/com/google/common/primitives/UnsignedLongs.java">Guava,
* simplified to our needs.
*
*
diff --git a/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/BloomFilterTest.java b/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/BloomFilterTest.java
index d56ed0c7ce2..dfeb857b435 100644
--- a/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/BloomFilterTest.java
+++ b/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/BloomFilterTest.java
@@ -122,9 +122,8 @@ public void mightContainOnEmptyBloomFilterShouldReturnFalse() {
@Test
public void mightContainWithEmptyStringShouldReturnFalse() {
BloomFilter emptyBloomFilter = new BloomFilter(new byte[0], 0, 0);
- BloomFilter nonEmptyBloomFilter = new BloomFilter(new byte[] {(byte) 255}, 0, 1);
-
assertFalse(emptyBloomFilter.mightContain(""));
+ BloomFilter nonEmptyBloomFilter = new BloomFilter(new byte[] {(byte) 255}, 0, 1);
assertFalse(nonEmptyBloomFilter.mightContain(""));
}
@@ -132,7 +131,6 @@ public void mightContainWithEmptyStringShouldReturnFalse() {
public void bloomFilterToString() {
BloomFilter emptyBloomFilter = new BloomFilter(new byte[0], 0, 0);
assertEquals(emptyBloomFilter.toString(), "BloomFilter{hashCount=0, size=0, bitmap=\"\"}");
-
BloomFilter nonEmptyBloomFilter = new BloomFilter(new byte[] {1}, 1, 1);
assertEquals(
nonEmptyBloomFilter.toString(), "BloomFilter{hashCount=1, size=7, bitmap=\"AQ==\"}");
From 3c81c7d7968a1afbd628808a2a767d13b7277d53 Mon Sep 17 00:00:00 2001
From: milaGGL <107142260+milaGGL@users.noreply.github.com>
Date: Mon, 16 Jan 2023 12:26:51 -0800
Subject: [PATCH 10/27] resolve comments
---
.../firestore/remote/BloomFilter.java | 46 +++++++++----------
.../firestore/remote/BloomFilterTest.java | 8 ++--
2 files changed, 25 insertions(+), 29 deletions(-)
diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java
index b174f32547f..80089e617f3 100644
--- a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java
+++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java
@@ -22,10 +22,10 @@
import java.security.NoSuchAlgorithmException;
public class BloomFilter {
- private final int size;
+ private final int bitCount;
private final byte[] bitmap;
private final int hashCount;
- private static MessageDigest md5HashMessageDigest;
+ private final MessageDigest md5HashMessageDigest;
public BloomFilter(@NonNull byte[] bitmap, int padding, int hashCount) {
if (bitmap == null) {
@@ -52,18 +52,13 @@ public BloomFilter(@NonNull byte[] bitmap, int padding, int hashCount) {
}
this.bitmap = bitmap;
this.hashCount = hashCount;
- this.size = bitmap.length * 8 - padding;
- this.md5HashMessageDigest = getMd5HashMessageDigest();
+ this.bitCount = bitmap.length * 8 - padding;
+ this.md5HashMessageDigest = createMd5HashMessageDigest();
}
- private boolean isEmpty() {
- return this.size == 0;
- }
-
- /** Returns the number of bits in the bloom filter. */
@VisibleForTesting
- int getSize() {
- return this.size;
+ int getBitCount() {
+ return this.bitCount;
}
/**
@@ -71,19 +66,19 @@ int getSize() {
* positive result, ie, the given string is not a member of the bloom filter, but the method
* returned true.
*
- * @param value the string to be tested membership.
+ * @param value the string to be tested for membership.
* @return true if the given string might be contained in the bloom filter.
*/
public boolean mightContain(@NonNull String value) {
// Empty bitmap or empty value should always return false on membership check.
- if (this.isEmpty() || value.isEmpty()) {
+ if (this.bitCount == 0 || value.isEmpty()) {
return false;
}
byte[] hashedValue = md5HashDigest(value);
if (hashedValue.length != 16) {
throw new RuntimeException(
- "Invalid md5HashedValue.length: " + hashedValue.length + " (expected 16)");
+ "Invalid md5 hash array length: " + hashedValue.length + " (expected 16)");
}
long hash1 = getLongLittleEndian(hashedValue, 0);
@@ -100,19 +95,17 @@ public boolean mightContain(@NonNull String value) {
/** Hash a string using md5 hashing algorithm, and return an array of 16 bytes. */
@NonNull
- private static byte[] md5HashDigest(@NonNull String value) {
+ private byte[] md5HashDigest(@NonNull String value) {
return md5HashMessageDigest.digest(value.getBytes(StandardCharsets.UTF_8));
}
@NonNull
- private static MessageDigest getMd5HashMessageDigest() {
- MessageDigest digest;
+ private MessageDigest createMd5HashMessageDigest() {
try {
- digest = MessageDigest.getInstance("MD5");
+ return MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("Missing MD5 MessageDigest provider.", e);
}
- return digest;
}
/** Interpret 8 bytes into a long, using little endian 2’s complement. */
@@ -125,14 +118,18 @@ private static long getLongLittleEndian(@NonNull byte[] bytes, int offset) {
}
/**
- * Calculate the ith hash value based on the hashed 64bit integers, and calculate its
+ * Calculate the ith hash value based on the hashed 64 bit unsigned integers, and calculate its
* corresponding bit index in the bitmap to be checked.
*/
private int getBitIndex(long hash1, long hash2, int index) {
- // Calculate hashed value h(i) = h1 + (i * h2).
+ /**
+ * Calculate hashed value h(i) = h1 + (i * h2).
+ * Even though we are interpreting hash1 and hash2 as unsigned, the addition and multiplication
+ * operators still perform the correct operation and give the desired overflow behavior.
+ */
long combinedHash = hash1 + (hash2 * index);
- long mod = unsignedRemainder(combinedHash, this.size);
- return (int) mod;
+ long modulo = unsignedRemainder(combinedHash, this.bitCount);
+ return (int) modulo;
}
/**
@@ -141,7 +138,6 @@ private int getBitIndex(long hash1, long hash2, int index) {
*
The implementation is taken from Guava,
* simplified to our needs.
- *
*
*/
private static long unsignedRemainder(long dividend, long divisor) {
@@ -164,7 +160,7 @@ public String toString() {
+ "hashCount="
+ hashCount
+ ", size="
- + size
+ + bitCount
+ ", bitmap=\""
+ Base64.encodeToString(bitmap, Base64.NO_WRAP)
+ "\"}";
diff --git a/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/BloomFilterTest.java b/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/BloomFilterTest.java
index dfeb857b435..dfdb21b7cfd 100644
--- a/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/BloomFilterTest.java
+++ b/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/BloomFilterTest.java
@@ -43,15 +43,15 @@ public class BloomFilterTest {
@Test
public void instantiateEmptyBloomFilter() {
BloomFilter bloomFilter = new BloomFilter(new byte[0], 0, 0);
- assertEquals(bloomFilter.getSize(), 0);
+ assertEquals(bloomFilter.getBitCount(), 0);
}
@Test
public void instantiateNonEmptyBloomFilter() {
BloomFilter bloomFilter1 = new BloomFilter(new byte[] {1}, 0, 1);
- assertEquals(bloomFilter1.getSize(), 8);
+ assertEquals(bloomFilter1.getBitCount(), 8);
BloomFilter bloomFilter2 = new BloomFilter(new byte[] {1}, 7, 1);
- assertEquals(bloomFilter2.getSize(), 1);
+ assertEquals(bloomFilter2.getBitCount(), 1);
}
@Test
@@ -89,7 +89,7 @@ public void constructorShouldThrowIAEOnNegativePadding() {
}
@Test
- public void constructorShouldThrowIAEOnNegativeHashValue() {
+ public void constructorShouldThrowIAEOnNegativeHashCount() {
IllegalArgumentException emptyBloomFilterException =
assertThrows(IllegalArgumentException.class, () -> new BloomFilter(new byte[0], 0, -1));
assertThat(emptyBloomFilterException).hasMessageThat().contains("Invalid hash count: -1");
From 5f66d921684f7333f1fcb4a085f7d6fb1dea6503 Mon Sep 17 00:00:00 2001
From: milaGGL <107142260+milaGGL@users.noreply.github.com>
Date: Wed, 18 Jan 2023 09:39:13 -0800
Subject: [PATCH 11/27] resolve comments
---
.../firestore/remote/BloomFilter.java | 46 +++++++++++--------
.../firestore/remote/BloomFilterTest.java | 39 ++++++++--------
2 files changed, 47 insertions(+), 38 deletions(-)
diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java
index 80089e617f3..3cf73c7ba15 100644
--- a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java
+++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java
@@ -47,7 +47,8 @@ public BloomFilter(@NonNull byte[] bitmap, int padding, int hashCount) {
// Empty bloom filter should have 0 padding.
if (padding != 0) {
- throw new IllegalArgumentException("Invalid padding when bitmap length is 0: " + padding);
+ throw new IllegalArgumentException("Expected padding of 0 when bitmap " +
+ "length is 0, but got " + padding);
}
}
this.bitmap = bitmap;
@@ -62,15 +63,16 @@ int getBitCount() {
}
/**
- * Check whether the given string is a possible member of the bloom filter. It might return false
- * positive result, ie, the given string is not a member of the bloom filter, but the method
- * returned true.
+ * Check whether the given string is a possible member of the bloom filter. It
+ * might return false positive result, ie, the given string is not a member of
+ * the bloom filter, but the method returned true.
*
* @param value the string to be tested for membership.
- * @return true if the given string might be contained in the bloom filter.
+ * @return true if the given string might be contained in the bloom filter, or
+ * false if the given string is definitely not contained in the bloom filter.
*/
public boolean mightContain(@NonNull String value) {
- // Empty bitmap or empty value should always return false on membership check.
+ // Empty bitmap or empty value should return false on membership check.
if (this.bitCount == 0 || value.isEmpty()) {
return false;
}
@@ -93,16 +95,19 @@ public boolean mightContain(@NonNull String value) {
return true;
}
- /** Hash a string using md5 hashing algorithm, and return an array of 16 bytes. */
+ /**
+ * Hash a string using md5 hashing algorithm, and return an array of 16
+ * bytes.
+ */
@NonNull
private byte[] md5HashDigest(@NonNull String value) {
return md5HashMessageDigest.digest(value.getBytes(StandardCharsets.UTF_8));
}
@NonNull
- private MessageDigest createMd5HashMessageDigest() {
+ private static MessageDigest createMd5HashMessageDigest() {
try {
- return MessageDigest.getInstance("MD5");
+ return MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("Missing MD5 MessageDigest provider.", e);
}
@@ -118,22 +123,23 @@ private static long getLongLittleEndian(@NonNull byte[] bytes, int offset) {
}
/**
- * Calculate the ith hash value based on the hashed 64 bit unsigned integers, and calculate its
- * corresponding bit index in the bitmap to be checked.
+ * Calculate the ith hash value based on the hashed 64 bit unsigned integers,
+ * and calculate its corresponding bit index in the bitmap to be checked.
*/
- private int getBitIndex(long hash1, long hash2, int index) {
- /**
- * Calculate hashed value h(i) = h1 + (i * h2).
- * Even though we are interpreting hash1 and hash2 as unsigned, the addition and multiplication
- * operators still perform the correct operation and give the desired overflow behavior.
- */
- long combinedHash = hash1 + (hash2 * index);
+ private int getBitIndex(long hash1, long hash2, int hashIndex) {
+
+ // Calculate hashed value h(i) = h1 + (i * h2).
+ // Even though we are interpreting hash1 and hash2 as unsigned, the addition
+ // and multiplication operators still perform the correct operation and give
+ // the desired overflow behavior.
+ long combinedHash = hash1 + (hash2 * hashIndex);
long modulo = unsignedRemainder(combinedHash, this.bitCount);
return (int) modulo;
}
/**
- * Calculate modulo, where the dividend and divisor are treated as unsigned 64-bit longs.
+ * Calculate modulo, where the dividend and divisor are treated as unsigned
+ * 64-bit longs.
*
*
The implementation is taken from Guava,
@@ -149,7 +155,7 @@ private static long unsignedRemainder(long dividend, long divisor) {
/** Return whether the bit at the given index in the bitmap is set to 1. */
private boolean isBitSet(int index) {
// To retrieve bit n, calculate: (bitmap[n / 8] & (0x01 << (n % 8))).
- byte byteAtIndex = this.bitmap[(index / 8)];
+ byte byteAtIndex = this.bitmap[index / 8];
int offset = index % 8;
return (byteAtIndex & (0x01 << offset)) != 0;
}
diff --git a/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/BloomFilterTest.java b/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/BloomFilterTest.java
index dfdb21b7cfd..6cc46eab46d 100644
--- a/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/BloomFilterTest.java
+++ b/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/BloomFilterTest.java
@@ -48,10 +48,14 @@ public void instantiateEmptyBloomFilter() {
@Test
public void instantiateNonEmptyBloomFilter() {
- BloomFilter bloomFilter1 = new BloomFilter(new byte[] {1}, 0, 1);
- assertEquals(bloomFilter1.getBitCount(), 8);
- BloomFilter bloomFilter2 = new BloomFilter(new byte[] {1}, 7, 1);
- assertEquals(bloomFilter2.getBitCount(), 1);
+ {
+ BloomFilter bloomFilter1 = new BloomFilter(new byte[] {1}, 0, 1);
+ assertEquals(bloomFilter1.getBitCount(), 8);
+ }
+ {
+ BloomFilter bloomFilter2 = new BloomFilter(new byte[] {1}, 7, 1);
+ assertEquals(bloomFilter2.getBitCount(), 1);
+ }
}
@Test
@@ -68,7 +72,7 @@ public void constructorShouldThrowNPEOnNullBitmap() {
public void constructorShouldThrowIAEOnEmptyBloomFilterWithNonZeroPadding() {
IllegalArgumentException exception =
assertThrows(IllegalArgumentException.class, () -> new BloomFilter(new byte[0], 1, 0));
- assertThat(exception).hasMessageThat().contains("Invalid padding when bitmap length is 0: 1");
+ assertThat(exception).hasMessageThat().contains("Expected padding of 0 when bitmap length is 0, but got 1");
}
@Test
@@ -99,7 +103,7 @@ public void constructorShouldThrowIAEOnNegativeHashCount() {
}
@Test
- public void constructorShouldThrowIAEOnOverflowPadding() {
+ public void constructorShouldThrowIAEIfPaddingIsTooLarge() {
IllegalArgumentException exception =
assertThrows(IllegalArgumentException.class, () -> new BloomFilter(new byte[] {1}, 8, 1));
assertThat(exception).hasMessageThat().contains("Invalid padding: 8");
@@ -147,8 +151,11 @@ public void bloomFilterToString() {
* to documentPrefix+2n. The membership results from 0 to n is expected to be true, and the
* membership results from n to 2n is expected to be false with some false positive results.
*/
- private void runGoldenTest(String testFile) throws Exception {
+ private static void runGoldenTest(String testFile) throws Exception {
String resultFile = testFile.replace("bloom_filter_proto", "membership_test_result");
+ if(resultFile.equals(testFile)){
+ throw new IllegalArgumentException("Cannot find corresponding result file for " + testFile);
+ }
JSONObject testJson = readJsonFile(testFile);
JSONObject resultJSON = readJsonFile(resultFile);
@@ -164,21 +171,17 @@ private void runGoldenTest(String testFile) throws Exception {
// Run and compare mightContain result with the expectation.
for (int i = 0; i < membershipTestResults.length(); i++) {
- boolean expectedMembershipResult = membershipTestResults.charAt(i) == '1';
- boolean mightContain = bloomFilter.mightContain(GOLDEN_DOCUMENT_PREFIX + i);
+ boolean expectedResult = membershipTestResults.charAt(i) == '1';
+ boolean mightContainResult = bloomFilter.mightContain(GOLDEN_DOCUMENT_PREFIX + i);
assertEquals(
- "mightContain() result doesn't match the expectation. File: "
- + testFile
- + ". Document: "
- + GOLDEN_DOCUMENT_PREFIX
- + i,
- mightContain,
- expectedMembershipResult);
+ "For document " + GOLDEN_DOCUMENT_PREFIX + i + " mightContain() returned " + mightContainResult
+ + ", but expected " + expectedResult,
+ mightContainResult,
+ expectedResult);
}
}
- private JSONObject readJsonFile(String fileName) throws Exception {
- // Read the file into JSON object.
+ private static JSONObject readJsonFile(String fileName) throws Exception {
StringBuilder builder = new StringBuilder();
InputStreamReader streamReader =
new InputStreamReader(
From be8ebed171517ac8eceb025e5b47aa67505c7e4d Mon Sep 17 00:00:00 2001
From: milaGGL <107142260+milaGGL@users.noreply.github.com>
Date: Wed, 18 Jan 2023 10:41:51 -0800
Subject: [PATCH 12/27] format
---
.../firestore/remote/BloomFilter.java | 33 +++++++++----------
.../firestore/remote/BloomFilterTest.java | 26 ++++++++++-----
2 files changed, 32 insertions(+), 27 deletions(-)
diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java
index 3cf73c7ba15..e5ac3529710 100644
--- a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java
+++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java
@@ -47,8 +47,8 @@ public BloomFilter(@NonNull byte[] bitmap, int padding, int hashCount) {
// Empty bloom filter should have 0 padding.
if (padding != 0) {
- throw new IllegalArgumentException("Expected padding of 0 when bitmap " +
- "length is 0, but got " + padding);
+ throw new IllegalArgumentException(
+ "Expected padding of 0 when bitmap length is 0, but got " + padding);
}
}
this.bitmap = bitmap;
@@ -63,17 +63,17 @@ int getBitCount() {
}
/**
- * Check whether the given string is a possible member of the bloom filter. It
- * might return false positive result, ie, the given string is not a member of
- * the bloom filter, but the method returned true.
+ * Check whether the given string is a possible member of the bloom filter. It might return false
+ * positive result, ie, the given string is not a member of the bloom filter, but the method
+ * returned true.
*
* @param value the string to be tested for membership.
- * @return true if the given string might be contained in the bloom filter, or
- * false if the given string is definitely not contained in the bloom filter.
+ * @return true if the given string might be contained in the bloom filter, or false if the given
+ * string is definitely not contained in the bloom filter.
*/
public boolean mightContain(@NonNull String value) {
- // Empty bitmap or empty value should return false on membership check.
- if (this.bitCount == 0 || value.isEmpty()) {
+ // Empty bitmap should return false on membership check.
+ if (this.bitCount == 0) {
return false;
}
@@ -95,10 +95,7 @@ public boolean mightContain(@NonNull String value) {
return true;
}
- /**
- * Hash a string using md5 hashing algorithm, and return an array of 16
- * bytes.
- */
+ /** Hash a string using md5 hashing algorithm, and return an array of 16 bytes. */
@NonNull
private byte[] md5HashDigest(@NonNull String value) {
return md5HashMessageDigest.digest(value.getBytes(StandardCharsets.UTF_8));
@@ -123,11 +120,11 @@ private static long getLongLittleEndian(@NonNull byte[] bytes, int offset) {
}
/**
- * Calculate the ith hash value based on the hashed 64 bit unsigned integers,
- * and calculate its corresponding bit index in the bitmap to be checked.
+ * Calculate the ith hash value based on the hashed 64 bit unsigned integers, and calculate its
+ * corresponding bit index in the bitmap to be checked.
*/
private int getBitIndex(long hash1, long hash2, int hashIndex) {
-
+
// Calculate hashed value h(i) = h1 + (i * h2).
// Even though we are interpreting hash1 and hash2 as unsigned, the addition
// and multiplication operators still perform the correct operation and give
@@ -138,12 +135,12 @@ private int getBitIndex(long hash1, long hash2, int hashIndex) {
}
/**
- * Calculate modulo, where the dividend and divisor are treated as unsigned
- * 64-bit longs.
+ * Calculate modulo, where the dividend and divisor are treated as unsigned 64-bit longs.
*
*
The implementation is taken from Guava,
* simplified to our needs.
+ *
*
*/
private static long unsignedRemainder(long dividend, long divisor) {
diff --git a/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/BloomFilterTest.java b/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/BloomFilterTest.java
index 6cc46eab46d..5002a8f8486 100644
--- a/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/BloomFilterTest.java
+++ b/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/BloomFilterTest.java
@@ -72,7 +72,9 @@ public void constructorShouldThrowNPEOnNullBitmap() {
public void constructorShouldThrowIAEOnEmptyBloomFilterWithNonZeroPadding() {
IllegalArgumentException exception =
assertThrows(IllegalArgumentException.class, () -> new BloomFilter(new byte[0], 1, 0));
- assertThat(exception).hasMessageThat().contains("Expected padding of 0 when bitmap length is 0, but got 1");
+ assertThat(exception)
+ .hasMessageThat()
+ .contains("Expected padding of 0 when bitmap length is 0, but got 1");
}
@Test
@@ -120,15 +122,16 @@ public void mightContainCanProcessNonStandardCharacters() {
@Test
public void mightContainOnEmptyBloomFilterShouldReturnFalse() {
BloomFilter bloomFilter = new BloomFilter(new byte[0], 0, 0);
+ assertFalse(bloomFilter.mightContain(""));
assertFalse(bloomFilter.mightContain("a"));
}
@Test
- public void mightContainWithEmptyStringShouldReturnFalse() {
- BloomFilter emptyBloomFilter = new BloomFilter(new byte[0], 0, 0);
- assertFalse(emptyBloomFilter.mightContain(""));
- BloomFilter nonEmptyBloomFilter = new BloomFilter(new byte[] {(byte) 255}, 0, 1);
- assertFalse(nonEmptyBloomFilter.mightContain(""));
+ public void mightContainWithEmptyStringMightReturnFalsePositiveResult() {
+ BloomFilter bloomFilter1 = new BloomFilter(new byte[] {1}, 1, 1);
+ assertFalse(bloomFilter1.mightContain(""));
+ BloomFilter bloomFilter2 = new BloomFilter(new byte[] {(byte) 255}, 0, 16);
+ assertTrue(bloomFilter2.mightContain(""));
}
@Test
@@ -153,7 +156,7 @@ public void bloomFilterToString() {
*/
private static void runGoldenTest(String testFile) throws Exception {
String resultFile = testFile.replace("bloom_filter_proto", "membership_test_result");
- if(resultFile.equals(testFile)){
+ if (resultFile.equals(testFile)) {
throw new IllegalArgumentException("Cannot find corresponding result file for " + testFile);
}
@@ -174,8 +177,13 @@ private static void runGoldenTest(String testFile) throws Exception {
boolean expectedResult = membershipTestResults.charAt(i) == '1';
boolean mightContainResult = bloomFilter.mightContain(GOLDEN_DOCUMENT_PREFIX + i);
assertEquals(
- "For document " + GOLDEN_DOCUMENT_PREFIX + i + " mightContain() returned " + mightContainResult
- + ", but expected " + expectedResult,
+ "For document "
+ + GOLDEN_DOCUMENT_PREFIX
+ + i
+ + " mightContain() returned "
+ + mightContainResult
+ + ", but expected "
+ + expectedResult,
mightContainResult,
expectedResult);
}
From 7eb326fe4db361581d054212f7094d910add05e5 Mon Sep 17 00:00:00 2001
From: milaGGL <107142260+milaGGL@users.noreply.github.com>
Date: Wed, 18 Jan 2023 12:42:45 -0800
Subject: [PATCH 13/27] fix format
---
.../firestore/remote/BloomFilter.java | 28 ++++++++-----------
.../firestore/remote/BloomFilterTest.java | 2 +-
2 files changed, 13 insertions(+), 17 deletions(-)
diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java
index e5ac3529710..9eba0f3f07b 100644
--- a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java
+++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java
@@ -1,4 +1,4 @@
-// Copyright 2022 Google LLC
+// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -34,23 +34,21 @@ public BloomFilter(@NonNull byte[] bitmap, int padding, int hashCount) {
if (padding < 0 || padding >= 8) {
throw new IllegalArgumentException("Invalid padding: " + padding);
}
-
- if (bitmap.length > 0) {
+ if (hashCount < 0) {
+ throw new IllegalArgumentException("Invalid hash count: " + hashCount);
+ }
+ if (bitmap.length > 0 && hashCount == 0) {
// Only empty bloom filter can have 0 hash count.
- if (hashCount <= 0) {
- throw new IllegalArgumentException("Invalid hash count: " + hashCount);
- }
- } else {
- if (hashCount < 0) {
- throw new IllegalArgumentException("Invalid hash count: " + hashCount);
- }
-
+ throw new IllegalArgumentException("Invalid hash count: " + hashCount);
+ }
+ if (bitmap.length == 0) {
// Empty bloom filter should have 0 padding.
if (padding != 0) {
throw new IllegalArgumentException(
"Expected padding of 0 when bitmap length is 0, but got " + padding);
}
}
+
this.bitmap = bitmap;
this.hashCount = hashCount;
this.bitCount = bitmap.length * 8 - padding;
@@ -106,7 +104,7 @@ private static MessageDigest createMd5HashMessageDigest() {
try {
return MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
- throw new RuntimeException("Missing MD5 MessageDigest provider.", e);
+ throw new RuntimeException("Missing MD5 MessageDigest provider: ", e);
}
}
@@ -124,11 +122,9 @@ private static long getLongLittleEndian(@NonNull byte[] bytes, int offset) {
* corresponding bit index in the bitmap to be checked.
*/
private int getBitIndex(long hash1, long hash2, int hashIndex) {
-
// Calculate hashed value h(i) = h1 + (i * h2).
- // Even though we are interpreting hash1 and hash2 as unsigned, the addition
- // and multiplication operators still perform the correct operation and give
- // the desired overflow behavior.
+ // Even though we are interpreting hash1 and hash2 as unsigned, the addition and multiplication
+ // operators still perform the correct operation and give the desired overflow behavior.
long combinedHash = hash1 + (hash2 * hashIndex);
long modulo = unsignedRemainder(combinedHash, this.bitCount);
return (int) modulo;
diff --git a/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/BloomFilterTest.java b/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/BloomFilterTest.java
index 5002a8f8486..25d3b7ce10c 100644
--- a/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/BloomFilterTest.java
+++ b/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/BloomFilterTest.java
@@ -1,4 +1,4 @@
-// Copyright 2022 Google LLC
+// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
From ff97c006523343c87781965d955d3822c30ff0ae Mon Sep 17 00:00:00 2001
From: milaGGL <107142260+milaGGL@users.noreply.github.com>
Date: Wed, 18 Jan 2023 22:25:19 -0800
Subject: [PATCH 14/27] upload initial code
---
.../firebase/firestore/core/SyncEngine.java | 3 +-
.../firestore/local/LocalSerializer.java | 3 +-
.../firebase/firestore/local/TargetData.java | 44 ++++++++++++++++---
.../firestore/remote/RemoteSerializer.java | 4 ++
.../firestore/remote/RemoteStore.java | 9 +++-
.../firestore/local/LocalSerializerTest.java | 3 +-
.../firestore/local/TargetCacheTestCase.java | 3 +-
7 files changed, 58 insertions(+), 11 deletions(-)
diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/core/SyncEngine.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/core/SyncEngine.java
index c7da9e27e18..b8655d91656 100644
--- a/firebase-firestore/src/main/java/com/google/firebase/firestore/core/SyncEngine.java
+++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/core/SyncEngine.java
@@ -203,13 +203,14 @@ public int listen(Query query) {
hardAssert(!queryViewsByQuery.containsKey(query), "We already listen to query: %s", query);
TargetData targetData = localStore.allocateTarget(query.toTarget());
- remoteStore.listen(targetData);
ViewSnapshot viewSnapshot =
initializeViewAndComputeSnapshot(
query, targetData.getTargetId(), targetData.getResumeToken());
syncEngineListener.onViewSnapshots(Collections.singletonList(viewSnapshot));
+ remoteStore.listen(targetData);
+
return targetData.getTargetId();
}
diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/local/LocalSerializer.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/local/LocalSerializer.java
index fb4e476b411..98fb7230821 100644
--- a/firebase-firestore/src/main/java/com/google/firebase/firestore/local/LocalSerializer.java
+++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/local/LocalSerializer.java
@@ -260,7 +260,8 @@ TargetData decodeTargetData(com.google.firebase.firestore.proto.Target targetPro
QueryPurpose.LISTEN,
version,
lastLimboFreeSnapshotVersion,
- resumeToken);
+ resumeToken,
+ null);
}
public com.google.firestore.bundle.BundledQuery encodeBundledQuery(BundledQuery bundledQuery) {
diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/local/TargetData.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/local/TargetData.java
index 18375731fe0..60413198c15 100644
--- a/firebase-firestore/src/main/java/com/google/firebase/firestore/local/TargetData.java
+++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/local/TargetData.java
@@ -16,6 +16,7 @@
import static com.google.firebase.firestore.util.Preconditions.checkNotNull;
+import androidx.annotation.Nullable;
import com.google.firebase.firestore.core.Target;
import com.google.firebase.firestore.model.SnapshotVersion;
import com.google.firebase.firestore.remote.WatchStream;
@@ -30,6 +31,7 @@ public final class TargetData {
private final SnapshotVersion snapshotVersion;
private final SnapshotVersion lastLimboFreeSnapshotVersion;
private final ByteString resumeToken;
+ private final @Nullable Integer expectedCount;
/**
* Creates a new TargetData with the given values.
@@ -45,6 +47,9 @@ public final class TargetData {
* @param resumeToken An opaque, server-assigned token that allows watching a target to be resumed
* after disconnecting without retransmitting all the data that matches the target. The resume
* token essentially identifies a point in time from which the server should resume sending
+ * @param expectedCount The number of documents that last matched the query at the resume token or
+ * read time. Documents are counted only when making a listen request with resume token or
+ * read time, otherwise, keep it null.
*/
TargetData(
Target target,
@@ -53,7 +58,8 @@ public final class TargetData {
QueryPurpose purpose,
SnapshotVersion snapshotVersion,
SnapshotVersion lastLimboFreeSnapshotVersion,
- ByteString resumeToken) {
+ ByteString resumeToken,
+ @Nullable Integer expectedCount) {
this.target = checkNotNull(target);
this.targetId = targetId;
this.sequenceNumber = sequenceNumber;
@@ -61,6 +67,7 @@ public final class TargetData {
this.purpose = purpose;
this.snapshotVersion = checkNotNull(snapshotVersion);
this.resumeToken = checkNotNull(resumeToken);
+ this.expectedCount = expectedCount;
}
/** Convenience constructor for use when creating a TargetData for the first time. */
@@ -72,7 +79,8 @@ public TargetData(Target target, int targetId, long sequenceNumber, QueryPurpose
purpose,
SnapshotVersion.NONE,
SnapshotVersion.NONE,
- WatchStream.EMPTY_RESUME_TOKEN);
+ WatchStream.EMPTY_RESUME_TOKEN,
+ null);
}
/** Creates a new target data instance with an updated sequence number. */
@@ -84,7 +92,8 @@ public TargetData withSequenceNumber(long sequenceNumber) {
purpose,
snapshotVersion,
lastLimboFreeSnapshotVersion,
- resumeToken);
+ resumeToken,
+ expectedCount);
}
/** Creates a new target data instance with an updated resume token and snapshot version. */
@@ -96,7 +105,21 @@ public TargetData withResumeToken(ByteString resumeToken, SnapshotVersion snapsh
purpose,
snapshotVersion,
lastLimboFreeSnapshotVersion,
- resumeToken);
+ resumeToken,
+ expectedCount);
+ }
+
+ /** Creates a new target data instance with an updated expected count. */
+ public TargetData withExpectedCount(Integer expectedCount) {
+ return new TargetData(
+ target,
+ targetId,
+ sequenceNumber,
+ purpose,
+ snapshotVersion,
+ lastLimboFreeSnapshotVersion,
+ resumeToken,
+ expectedCount);
}
/** Creates a new target data instance with an updated last limbo free snapshot version number. */
@@ -108,7 +131,8 @@ public TargetData withLastLimboFreeSnapshotVersion(SnapshotVersion lastLimboFree
purpose,
snapshotVersion,
lastLimboFreeSnapshotVersion,
- resumeToken);
+ resumeToken,
+ expectedCount);
}
public Target getTarget() {
@@ -135,6 +159,10 @@ public ByteString getResumeToken() {
return resumeToken;
}
+ public Integer getExpectedCount() {
+ return expectedCount;
+ }
+
/**
* Returns the last snapshot version for which the associated view contained no limbo documents.
*/
@@ -158,7 +186,8 @@ public boolean equals(Object o) {
&& purpose.equals(targetData.purpose)
&& snapshotVersion.equals(targetData.snapshotVersion)
&& lastLimboFreeSnapshotVersion.equals(targetData.lastLimboFreeSnapshotVersion)
- && resumeToken.equals(targetData.resumeToken);
+ && resumeToken.equals(targetData.resumeToken)
+ && (expectedCount==null && expectedCount.equals(targetData.expectedCount));
}
@Override
@@ -170,6 +199,7 @@ public int hashCode() {
result = 31 * result + snapshotVersion.hashCode();
result = 31 * result + lastLimboFreeSnapshotVersion.hashCode();
result = 31 * result + resumeToken.hashCode();
+ result = 31 * result + expectedCount.hashCode();
return result;
}
@@ -190,6 +220,8 @@ public String toString() {
+ lastLimboFreeSnapshotVersion
+ ", resumeToken="
+ resumeToken
+ + ", expectedCount="
+ + expectedCount
+ '}';
}
}
diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteSerializer.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteSerializer.java
index 57f51a7b8cc..74ba575386b 100644
--- a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteSerializer.java
+++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteSerializer.java
@@ -499,6 +499,10 @@ public Target encodeTarget(TargetData targetData) {
builder.setResumeToken(targetData.getResumeToken());
}
+ if (targetData.getExpectedCount() != null) {
+ builder.setExpectedCount(Int32Value.newBuilder().setValue(targetData.getExpectedCount()));
+ }
+
return builder.build();
}
diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteStore.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteStore.java
index 3999f22a939..cc52fa6f6cb 100644
--- a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteStore.java
+++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteStore.java
@@ -369,7 +369,14 @@ public void listen(TargetData targetData) {
private void sendWatchRequest(TargetData targetData) {
watchChangeAggregator.recordPendingTargetRequest(targetData.getTargetId());
- watchStream.watchQuery(targetData);
+ if (!targetData.getResumeToken().isEmpty()
+ || targetData.getSnapshotVersion().compareTo(SnapshotVersion.NONE) > 0) {
+ int expectedCount = this.getRemoteKeysForTarget(targetData.getTargetId()).size();
+ TargetData newTargetData = targetData.withExpectedCount(expectedCount);
+ watchStream.watchQuery(newTargetData);
+ } else {
+ watchStream.watchQuery(targetData);
+ }
}
/**
diff --git a/firebase-firestore/src/test/java/com/google/firebase/firestore/local/LocalSerializerTest.java b/firebase-firestore/src/test/java/com/google/firebase/firestore/local/LocalSerializerTest.java
index 124727f5681..c7fbf4a9d5a 100644
--- a/firebase-firestore/src/test/java/com/google/firebase/firestore/local/LocalSerializerTest.java
+++ b/firebase-firestore/src/test/java/com/google/firebase/firestore/local/LocalSerializerTest.java
@@ -378,7 +378,8 @@ public void testEncodesTargetData() {
QueryPurpose.LISTEN,
snapshotVersion,
limboFreeVersion,
- resumeToken);
+ resumeToken,
+ null);
// Let the RPC serializer test various permutations of query serialization.
com.google.firestore.v1.Target.QueryTarget queryTarget =
diff --git a/firebase-firestore/src/test/java/com/google/firebase/firestore/local/TargetCacheTestCase.java b/firebase-firestore/src/test/java/com/google/firebase/firestore/local/TargetCacheTestCase.java
index e098f7666f1..9a25afa94cc 100644
--- a/firebase-firestore/src/test/java/com/google/firebase/firestore/local/TargetCacheTestCase.java
+++ b/firebase-firestore/src/test/java/com/google/firebase/firestore/local/TargetCacheTestCase.java
@@ -331,7 +331,8 @@ private TargetData newTargetData(Query query, int targetId, long version) {
QueryPurpose.LISTEN,
version(version),
version(version),
- resumeToken(version));
+ resumeToken(version),
+ null);
}
/** Adds the given query data to the targetCache under test, committing immediately. */
From f8768249a92516fd839aa564cc4762aea0fee799 Mon Sep 17 00:00:00 2001
From: milaGGL <107142260+milaGGL@users.noreply.github.com>
Date: Wed, 18 Jan 2023 22:49:15 -0800
Subject: [PATCH 15/27] format
---
.../java/com/google/firebase/firestore/local/TargetData.java | 3 +--
.../google/firebase/firestore/local/LocalSerializerTest.java | 2 +-
.../google/firebase/firestore/local/TargetCacheTestCase.java | 2 +-
3 files changed, 3 insertions(+), 4 deletions(-)
diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/local/TargetData.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/local/TargetData.java
index 60413198c15..a0bec3e3e17 100644
--- a/firebase-firestore/src/main/java/com/google/firebase/firestore/local/TargetData.java
+++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/local/TargetData.java
@@ -186,8 +186,7 @@ public boolean equals(Object o) {
&& purpose.equals(targetData.purpose)
&& snapshotVersion.equals(targetData.snapshotVersion)
&& lastLimboFreeSnapshotVersion.equals(targetData.lastLimboFreeSnapshotVersion)
- && resumeToken.equals(targetData.resumeToken)
- && (expectedCount==null && expectedCount.equals(targetData.expectedCount));
+ && resumeToken.equals(targetData.resumeToken);
}
@Override
diff --git a/firebase-firestore/src/test/java/com/google/firebase/firestore/local/LocalSerializerTest.java b/firebase-firestore/src/test/java/com/google/firebase/firestore/local/LocalSerializerTest.java
index c7fbf4a9d5a..20223e78dec 100644
--- a/firebase-firestore/src/test/java/com/google/firebase/firestore/local/LocalSerializerTest.java
+++ b/firebase-firestore/src/test/java/com/google/firebase/firestore/local/LocalSerializerTest.java
@@ -379,7 +379,7 @@ public void testEncodesTargetData() {
snapshotVersion,
limboFreeVersion,
resumeToken,
- null);
+ null);
// Let the RPC serializer test various permutations of query serialization.
com.google.firestore.v1.Target.QueryTarget queryTarget =
diff --git a/firebase-firestore/src/test/java/com/google/firebase/firestore/local/TargetCacheTestCase.java b/firebase-firestore/src/test/java/com/google/firebase/firestore/local/TargetCacheTestCase.java
index 9a25afa94cc..58a3a57ba69 100644
--- a/firebase-firestore/src/test/java/com/google/firebase/firestore/local/TargetCacheTestCase.java
+++ b/firebase-firestore/src/test/java/com/google/firebase/firestore/local/TargetCacheTestCase.java
@@ -332,7 +332,7 @@ private TargetData newTargetData(Query query, int targetId, long version) {
version(version),
version(version),
resumeToken(version),
- null);
+ null);
}
/** Adds the given query data to the targetCache under test, committing immediately. */
From d7806f38533eee2e0f8572facbac73fb7aa29b58 Mon Sep 17 00:00:00 2001
From: milaGGL <107142260+milaGGL@users.noreply.github.com>
Date: Thu, 19 Jan 2023 10:26:50 -0800
Subject: [PATCH 16/27] add expectedCount assertion to spec test
---
.../com/google/firebase/firestore/local/TargetData.java | 6 ++++--
.../com/google/firebase/firestore/spec/SpecTestCase.java | 3 +++
2 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/local/TargetData.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/local/TargetData.java
index a0bec3e3e17..836c014338a 100644
--- a/firebase-firestore/src/main/java/com/google/firebase/firestore/local/TargetData.java
+++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/local/TargetData.java
@@ -159,6 +159,7 @@ public ByteString getResumeToken() {
return resumeToken;
}
+ @Nullable
public Integer getExpectedCount() {
return expectedCount;
}
@@ -186,7 +187,8 @@ public boolean equals(Object o) {
&& purpose.equals(targetData.purpose)
&& snapshotVersion.equals(targetData.snapshotVersion)
&& lastLimboFreeSnapshotVersion.equals(targetData.lastLimboFreeSnapshotVersion)
- && resumeToken.equals(targetData.resumeToken);
+ && resumeToken.equals(targetData.resumeToken)
+ && expectedCount == targetData.expectedCount;
}
@Override
@@ -198,7 +200,7 @@ public int hashCode() {
result = 31 * result + snapshotVersion.hashCode();
result = 31 * result + lastLimboFreeSnapshotVersion.hashCode();
result = 31 * result + resumeToken.hashCode();
- result = 31 * result + expectedCount.hashCode();
+ result = 31 * result + (expectedCount != null ? expectedCount.hashCode() : 0);
return result;
}
diff --git a/firebase-firestore/src/test/java/com/google/firebase/firestore/spec/SpecTestCase.java b/firebase-firestore/src/test/java/com/google/firebase/firestore/spec/SpecTestCase.java
index cf136ab45d8..659c3cc3f18 100644
--- a/firebase-firestore/src/test/java/com/google/firebase/firestore/spec/SpecTestCase.java
+++ b/firebase-firestore/src/test/java/com/google/firebase/firestore/spec/SpecTestCase.java
@@ -1143,6 +1143,9 @@ private void validateActiveTargets() {
assertEquals(
expectedTarget.getResumeToken().toStringUtf8(),
actualTarget.getResumeToken().toStringUtf8());
+ if (expectedTarget.getExpectedCount() != null) {
+ assertEquals(expectedTarget.getExpectedCount(), actualTarget.getExpectedCount());
+ }
actualTargets.remove(expected.getKey());
}
From e0c6fc03710cf7ee031c192d86905ca519eaf81b Mon Sep 17 00:00:00 2001
From: milaGGL <107142260+milaGGL@users.noreply.github.com>
Date: Fri, 20 Jan 2023 09:25:15 -0800
Subject: [PATCH 17/27] resolve comments
---
.../firestore/remote/BloomFilterTest.java | 76 ++++++++++++-------
1 file changed, 49 insertions(+), 27 deletions(-)
diff --git a/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/BloomFilterTest.java b/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/BloomFilterTest.java
index 25d3b7ce10c..0e851a0fc4f 100644
--- a/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/BloomFilterTest.java
+++ b/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/BloomFilterTest.java
@@ -60,12 +60,16 @@ public void instantiateNonEmptyBloomFilter() {
@Test
public void constructorShouldThrowNPEOnNullBitmap() {
- NullPointerException emptyBloomFilterException =
- assertThrows(NullPointerException.class, () -> new BloomFilter(null, 0, 0));
- assertThat(emptyBloomFilterException).hasMessageThat().contains("Bitmap cannot be null.");
- NullPointerException nonEmptyBloomFilterException =
- assertThrows(NullPointerException.class, () -> new BloomFilter(null, 1, 1));
- assertThat(nonEmptyBloomFilterException).hasMessageThat().contains("Bitmap cannot be null.");
+ {
+ NullPointerException emptyBloomFilterException =
+ assertThrows(NullPointerException.class, () -> new BloomFilter(null, 0, 0));
+ assertThat(emptyBloomFilterException).hasMessageThat().contains("Bitmap cannot be null.");
+ }
+ {
+ NullPointerException nonEmptyBloomFilterException =
+ assertThrows(NullPointerException.class, () -> new BloomFilter(null, 1, 1));
+ assertThat(nonEmptyBloomFilterException).hasMessageThat().contains("Bitmap cannot be null.");
+ }
}
@Test
@@ -86,22 +90,32 @@ public void constructorShouldThrowIAEOnNonEmptyBloomFilterWithZeroHashCount() {
@Test
public void constructorShouldThrowIAEOnNegativePadding() {
- IllegalArgumentException emptyBloomFilterException =
- assertThrows(IllegalArgumentException.class, () -> new BloomFilter(new byte[0], -1, 0));
- assertThat(emptyBloomFilterException).hasMessageThat().contains("Invalid padding: -1");
- IllegalArgumentException nonEmptyBloomFilterException =
- assertThrows(IllegalArgumentException.class, () -> new BloomFilter(new byte[] {1}, -1, 1));
- assertThat(nonEmptyBloomFilterException).hasMessageThat().contains("Invalid padding: -1");
+ {
+ IllegalArgumentException emptyBloomFilterException =
+ assertThrows(IllegalArgumentException.class, () -> new BloomFilter(new byte[0], -1, 0));
+ assertThat(emptyBloomFilterException).hasMessageThat().contains("Invalid padding: -1");
+ }
+ {
+ IllegalArgumentException nonEmptyBloomFilterException =
+ assertThrows(
+ IllegalArgumentException.class, () -> new BloomFilter(new byte[] {1}, -1, 1));
+ assertThat(nonEmptyBloomFilterException).hasMessageThat().contains("Invalid padding: -1");
+ }
}
@Test
public void constructorShouldThrowIAEOnNegativeHashCount() {
- IllegalArgumentException emptyBloomFilterException =
- assertThrows(IllegalArgumentException.class, () -> new BloomFilter(new byte[0], 0, -1));
- assertThat(emptyBloomFilterException).hasMessageThat().contains("Invalid hash count: -1");
- IllegalArgumentException nonEmptyBloomFilterException =
- assertThrows(IllegalArgumentException.class, () -> new BloomFilter(new byte[] {1}, 1, -1));
- assertThat(nonEmptyBloomFilterException).hasMessageThat().contains("Invalid hash count: -1");
+ {
+ IllegalArgumentException emptyBloomFilterException =
+ assertThrows(IllegalArgumentException.class, () -> new BloomFilter(new byte[0], 0, -1));
+ assertThat(emptyBloomFilterException).hasMessageThat().contains("Invalid hash count: -1");
+ }
+ {
+ IllegalArgumentException nonEmptyBloomFilterException =
+ assertThrows(
+ IllegalArgumentException.class, () -> new BloomFilter(new byte[] {1}, 1, -1));
+ assertThat(nonEmptyBloomFilterException).hasMessageThat().contains("Invalid hash count: -1");
+ }
}
@Test
@@ -128,19 +142,27 @@ public void mightContainOnEmptyBloomFilterShouldReturnFalse() {
@Test
public void mightContainWithEmptyStringMightReturnFalsePositiveResult() {
- BloomFilter bloomFilter1 = new BloomFilter(new byte[] {1}, 1, 1);
- assertFalse(bloomFilter1.mightContain(""));
- BloomFilter bloomFilter2 = new BloomFilter(new byte[] {(byte) 255}, 0, 16);
- assertTrue(bloomFilter2.mightContain(""));
+ {
+ BloomFilter bloomFilter1 = new BloomFilter(new byte[] {1}, 1, 1);
+ assertFalse(bloomFilter1.mightContain(""));
+ }
+ {
+ BloomFilter bloomFilter2 = new BloomFilter(new byte[] {(byte) 255}, 0, 16);
+ assertTrue(bloomFilter2.mightContain(""));
+ }
}
@Test
public void bloomFilterToString() {
- BloomFilter emptyBloomFilter = new BloomFilter(new byte[0], 0, 0);
- assertEquals(emptyBloomFilter.toString(), "BloomFilter{hashCount=0, size=0, bitmap=\"\"}");
- BloomFilter nonEmptyBloomFilter = new BloomFilter(new byte[] {1}, 1, 1);
- assertEquals(
- nonEmptyBloomFilter.toString(), "BloomFilter{hashCount=1, size=7, bitmap=\"AQ==\"}");
+ {
+ BloomFilter emptyBloomFilter = new BloomFilter(new byte[0], 0, 0);
+ assertEquals(emptyBloomFilter.toString(), "BloomFilter{hashCount=0, size=0, bitmap=\"\"}");
+ }
+ {
+ BloomFilter nonEmptyBloomFilter = new BloomFilter(new byte[] {1}, 1, 1);
+ assertEquals(
+ nonEmptyBloomFilter.toString(), "BloomFilter{hashCount=1, size=7, bitmap=\"AQ==\"}");
+ }
}
/**
From ae7edd0ae022bad5cbabec4b7c67f9a28882e07e Mon Sep 17 00:00:00 2001
From: milaGGL <107142260+milaGGL@users.noreply.github.com>
Date: Fri, 20 Jan 2023 15:41:22 -0800
Subject: [PATCH 18/27] port spec tests
---
.../firebase/firestore/spec/SpecTestCase.java | 4 +
.../test/resources/json/listen_spec_test.json | 930 ++++++++++++++++++
2 files changed, 934 insertions(+)
diff --git a/firebase-firestore/src/test/java/com/google/firebase/firestore/spec/SpecTestCase.java b/firebase-firestore/src/test/java/com/google/firebase/firestore/spec/SpecTestCase.java
index 659c3cc3f18..7be9479da3b 100644
--- a/firebase-firestore/src/test/java/com/google/firebase/firestore/spec/SpecTestCase.java
+++ b/firebase-firestore/src/test/java/com/google/firebase/firestore/spec/SpecTestCase.java
@@ -1006,6 +1006,9 @@ private void validateExpectedState(@Nullable JSONObject expectedState) throws JS
targetData.withResumeToken(
ByteString.EMPTY, version(queryDataJson.getInt("readTime")));
}
+ if (queryDataJson.has("expectedCount")) {
+ targetData = targetData.withExpectedCount(queryDataJson.getInt("expectedCount"));
+ }
expectedActiveTargets.get(targetId).add(targetData);
}
@@ -1143,6 +1146,7 @@ private void validateActiveTargets() {
assertEquals(
expectedTarget.getResumeToken().toStringUtf8(),
actualTarget.getResumeToken().toStringUtf8());
+
if (expectedTarget.getExpectedCount() != null) {
assertEquals(expectedTarget.getExpectedCount(), actualTarget.getExpectedCount());
}
diff --git a/firebase-firestore/src/test/resources/json/listen_spec_test.json b/firebase-firestore/src/test/resources/json/listen_spec_test.json
index 5755019b048..57d253e6e43 100644
--- a/firebase-firestore/src/test/resources/json/listen_spec_test.json
+++ b/firebase-firestore/src/test/resources/json/listen_spec_test.json
@@ -99,6 +99,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -139,6 +140,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -221,6 +223,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -438,6 +441,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -449,6 +453,7 @@
"version": 1000
},
{
+ "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -483,6 +488,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -494,6 +500,7 @@
"version": 1000
},
{
+ "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -525,6 +532,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -536,6 +544,7 @@
"version": 1000
},
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -610,6 +619,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/c",
"options": {
"hasCommittedMutations": false,
@@ -644,6 +654,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/c",
"options": {
"hasCommittedMutations": false,
@@ -673,6 +684,7 @@
},
"removed": [
{
+ "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -708,6 +720,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/c",
"options": {
"hasCommittedMutations": false,
@@ -719,6 +732,7 @@
"version": 2000
},
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -887,6 +901,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -921,6 +936,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -1038,6 +1054,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -1072,6 +1089,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -1100,6 +1118,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -1126,6 +1145,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -1219,6 +1239,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -1230,6 +1251,7 @@
"version": 1000
},
{
+ "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -1264,6 +1286,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -1319,6 +1342,7 @@
},
"removed": [
{
+ "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -1534,6 +1558,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"value": null,
"version": 1000
@@ -1629,6 +1654,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -1655,6 +1681,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -1739,6 +1766,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -1822,6 +1850,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/exists",
"options": {
"hasCommittedMutations": false,
@@ -1911,6 +1940,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -1945,6 +1975,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -1985,6 +2016,7 @@
},
"removed": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -2017,6 +2049,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"value": null,
"version": 2000
@@ -2188,6 +2221,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection2/a",
"options": {
"hasCommittedMutations": false,
@@ -2231,6 +2265,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection2/a",
"options": {
"hasCommittedMutations": false,
@@ -2731,6 +2766,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -2765,6 +2801,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -2914,6 +2951,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -2950,6 +2988,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -3096,6 +3135,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"value": null,
"version": 2000
@@ -3193,6 +3233,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -3204,6 +3245,7 @@
"version": 1000
},
{
+ "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -3238,6 +3280,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -3279,6 +3322,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -3337,6 +3381,160 @@
}
]
},
+ "ExpectedCount in listen request should work after coming back online": {
+ "describeName": "Listens:",
+ "itName": "ExpectedCount in listen request should work after coming back online",
+ "tags": [
+ ],
+ "config": {
+ "numClients": 1,
+ "useGarbageCollection": false
+ },
+ "steps": [
+ {
+ "userListen": {
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ },
+ "targetId": 2
+ },
+ "expectedState": {
+ "activeTargets": {
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": ""
+ }
+ }
+ }
+ },
+ {
+ "watchAck": [
+ 2
+ ]
+ },
+ {
+ "watchEntity": {
+ "docs": [
+ {
+ "createTime": 0,
+ "key": "collection/a",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "key": "a"
+ },
+ "version": 1000
+ }
+ ],
+ "targets": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchCurrent": [
+ [
+ 2
+ ],
+ "resume-token-1000"
+ ]
+ },
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 1000
+ },
+ "expectedSnapshotEvents": [
+ {
+ "added": [
+ {
+ "createTime": 0,
+ "key": "collection/a",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "key": "a"
+ },
+ "version": 1000
+ }
+ ],
+ "errorCode": 0,
+ "fromCache": false,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ }
+ ]
+ },
+ {
+ "enableNetwork": false,
+ "expectedSnapshotEvents": [
+ {
+ "errorCode": 0,
+ "fromCache": true,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ }
+ ],
+ "expectedState": {
+ "activeLimboDocs": [
+ ],
+ "activeTargets": {
+ },
+ "enqueuedLimboDocs": [
+ ]
+ }
+ },
+ {
+ "enableNetwork": true,
+ "expectedState": {
+ "activeTargets": {
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": "resume-token-1000",
+ "expectedCount": 1
+ }
+ }
+ }
+ }
+ ]
+ },
"Ignores update from inactive target": {
"describeName": "Listens:",
"itName": "Ignores update from inactive target",
@@ -3384,6 +3582,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -3418,6 +3617,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -3462,6 +3662,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -3507,6 +3708,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -3606,6 +3808,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -3641,6 +3844,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -3714,6 +3918,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -3764,6 +3969,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"value": null,
"version": 3000
@@ -3802,6 +4008,7 @@
},
"removed": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -3906,6 +4113,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -4129,6 +4337,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -4164,6 +4373,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -4237,6 +4447,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -4287,6 +4498,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -4325,6 +4537,7 @@
"hasPendingWrites": false,
"modified": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -4436,6 +4649,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -4530,6 +4744,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -4674,6 +4889,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -4710,6 +4926,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -4758,6 +4975,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -4850,6 +5068,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -4890,6 +5109,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -4998,6 +5218,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -5038,6 +5259,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -5110,6 +5332,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -5150,6 +5373,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -5258,6 +5482,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -5298,6 +5523,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -5342,6 +5568,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -5434,6 +5661,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -5470,6 +5698,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -5501,6 +5730,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -5575,6 +5805,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -5609,6 +5840,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -5687,6 +5919,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -5721,6 +5954,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -5908,6 +6142,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -5919,6 +6154,7 @@
"version": 1000
},
{
+ "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -5959,6 +6195,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -5970,6 +6207,7 @@
"version": 1000
},
{
+ "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -6007,6 +6245,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -6018,6 +6257,7 @@
"version": 1000
},
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -6102,6 +6342,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/c",
"options": {
"hasCommittedMutations": false,
@@ -6133,6 +6374,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/c",
"options": {
"hasCommittedMutations": false,
@@ -6162,6 +6404,7 @@
},
"removed": [
{
+ "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -6335,6 +6578,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -6346,6 +6590,7 @@
"version": 1000
},
{
+ "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -6382,6 +6627,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -6393,6 +6639,7 @@
"version": 1000
},
{
+ "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -6430,6 +6677,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -6441,6 +6689,7 @@
"version": 1000
},
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -6525,6 +6774,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/c",
"options": {
"hasCommittedMutations": false,
@@ -6552,6 +6802,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/c",
"options": {
"hasCommittedMutations": false,
@@ -6581,6 +6832,7 @@
},
"removed": [
{
+ "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -6621,6 +6873,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/c",
"options": {
"hasCommittedMutations": false,
@@ -6632,6 +6885,7 @@
"version": 2000
},
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -6769,6 +7023,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/d",
"options": {
"hasCommittedMutations": false,
@@ -6800,6 +7055,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/d",
"options": {
"hasCommittedMutations": false,
@@ -6829,6 +7085,7 @@
},
"removed": [
{
+ "createTime": 0,
"key": "collection/c",
"options": {
"hasCommittedMutations": false,
@@ -7046,6 +7303,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -7057,6 +7315,7 @@
"version": 1000
},
{
+ "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -7097,6 +7356,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -7108,6 +7368,7 @@
"version": 1000
},
{
+ "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -7139,6 +7400,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -7150,6 +7412,7 @@
"version": 1000
},
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -7252,6 +7515,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/c",
"options": {
"hasCommittedMutations": false,
@@ -7283,6 +7547,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/c",
"options": {
"hasCommittedMutations": false,
@@ -7312,6 +7577,7 @@
},
"removed": [
{
+ "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -8074,6 +8340,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -8108,6 +8375,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -8166,6 +8434,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -8290,6 +8559,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -8324,6 +8594,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -8382,6 +8653,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -8505,6 +8777,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -8539,6 +8812,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -8609,6 +8883,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -8770,6 +9045,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -8805,6 +9081,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -8867,6 +9144,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -9081,6 +9359,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -9140,6 +9419,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -9265,6 +9545,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -9305,6 +9586,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -9382,6 +9664,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -9422,6 +9705,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -9484,6 +9768,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/c",
"options": {
"hasCommittedMutations": false,
@@ -9524,6 +9809,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/c",
"options": {
"hasCommittedMutations": false,
@@ -9635,6 +9921,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -9666,6 +9953,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -9813,6 +10101,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -9853,6 +10142,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -9886,6 +10176,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -9926,6 +10217,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -9937,6 +10229,7 @@
"version": 1000
},
{
+ "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -9982,6 +10275,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/c",
"options": {
"hasCommittedMutations": false,
@@ -10009,6 +10303,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/c",
"options": {
"hasCommittedMutations": false,
@@ -10040,6 +10335,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -10065,6 +10361,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/c",
"options": {
"hasCommittedMutations": false,
@@ -10633,6 +10930,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -10673,6 +10971,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -10750,6 +11049,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -10821,6 +11121,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -10861,6 +11162,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -10948,6 +11250,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -10984,6 +11287,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -11028,6 +11332,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -11088,6 +11393,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -11137,6 +11443,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -11164,6 +11471,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -11195,6 +11503,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -11226,6 +11535,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -11313,6 +11623,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -11349,6 +11660,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -11393,6 +11705,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -11471,6 +11784,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -11502,6 +11816,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -11675,6 +11990,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -11719,6 +12035,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -11750,6 +12067,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -11834,6 +12152,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -11870,6 +12189,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -11914,6 +12234,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -11988,6 +12309,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -12024,6 +12346,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -12061,6 +12384,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/c",
"options": {
"hasCommittedMutations": false,
@@ -12088,6 +12412,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/c",
"options": {
"hasCommittedMutations": false,
@@ -12123,6 +12448,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -12134,6 +12460,7 @@
"version": 2000
},
{
+ "createTime": 0,
"key": "collection/c",
"options": {
"hasCommittedMutations": false,
@@ -12210,6 +12537,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -12244,6 +12572,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -12306,6 +12635,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -12355,6 +12685,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"value": null,
"version": 2000
@@ -12393,6 +12724,7 @@
},
"removed": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -12409,6 +12741,535 @@
}
]
},
+ "Resuming a query should specify expectedCount that does not include pending mutations": {
+ "describeName": "Listens:",
+ "itName": "Resuming a query should specify expectedCount that does not include pending mutations",
+ "tags": [
+ ],
+ "config": {
+ "numClients": 1,
+ "useGarbageCollection": false
+ },
+ "steps": [
+ {
+ "userListen": {
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ },
+ "targetId": 2
+ },
+ "expectedState": {
+ "activeTargets": {
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": ""
+ }
+ }
+ }
+ },
+ {
+ "watchAck": [
+ 2
+ ]
+ },
+ {
+ "watchEntity": {
+ "docs": [
+ {
+ "createTime": 0,
+ "key": "collection/a",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "key": "a"
+ },
+ "version": 1000
+ }
+ ],
+ "targets": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchCurrent": [
+ [
+ 2
+ ],
+ "resume-token-1000"
+ ]
+ },
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 1000
+ },
+ "expectedSnapshotEvents": [
+ {
+ "added": [
+ {
+ "createTime": 0,
+ "key": "collection/a",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "key": "a"
+ },
+ "version": 1000
+ }
+ ],
+ "errorCode": 0,
+ "fromCache": false,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ }
+ ]
+ },
+ {
+ "userUnlisten": [
+ 2,
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "expectedState": {
+ "activeTargets": {
+ }
+ }
+ },
+ {
+ "userSet": [
+ "collection/b",
+ {
+ "key": "b"
+ }
+ ]
+ },
+ {
+ "userListen": {
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ },
+ "targetId": 2
+ },
+ "expectedSnapshotEvents": [
+ {
+ "added": [
+ {
+ "createTime": 0,
+ "key": "collection/a",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "key": "a"
+ },
+ "version": 1000
+ },
+ {
+ "createTime": 0,
+ "key": "collection/b",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": true
+ },
+ "value": {
+ "key": "b"
+ },
+ "version": 0
+ }
+ ],
+ "errorCode": 0,
+ "fromCache": true,
+ "hasPendingWrites": true,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ }
+ ],
+ "expectedState": {
+ "activeTargets": {
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": "resume-token-1000",
+ "expectedCount": 1
+ }
+ }
+ }
+ }
+ ]
+ },
+ "Resuming a query should specify expectedCount when adding the target": {
+ "describeName": "Listens:",
+ "itName": "Resuming a query should specify expectedCount when adding the target",
+ "tags": [
+ ],
+ "config": {
+ "numClients": 1,
+ "useGarbageCollection": false
+ },
+ "steps": [
+ {
+ "userListen": {
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ },
+ "targetId": 2
+ },
+ "expectedState": {
+ "activeTargets": {
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": ""
+ }
+ }
+ }
+ },
+ {
+ "watchAck": [
+ 2
+ ]
+ },
+ {
+ "watchEntity": {
+ "docs": [
+ ],
+ "targets": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchCurrent": [
+ [
+ 2
+ ],
+ "resume-token-1000"
+ ]
+ },
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 1000
+ },
+ "expectedSnapshotEvents": [
+ {
+ "errorCode": 0,
+ "fromCache": false,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ }
+ ]
+ },
+ {
+ "userUnlisten": [
+ 2,
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "expectedState": {
+ "activeTargets": {
+ }
+ }
+ },
+ {
+ "watchRemove": {
+ "targetIds": [
+ 2
+ ]
+ }
+ },
+ {
+ "userListen": {
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ },
+ "targetId": 2
+ },
+ "expectedSnapshotEvents": [
+ {
+ "errorCode": 0,
+ "fromCache": true,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ }
+ ],
+ "expectedState": {
+ "activeTargets": {
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": "resume-token-1000",
+ "expectedCount": 0
+ }
+ }
+ }
+ },
+ {
+ "watchAck": [
+ 2
+ ]
+ },
+ {
+ "watchEntity": {
+ "docs": [
+ {
+ "createTime": 0,
+ "key": "collection/a",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "key": "a"
+ },
+ "version": 1000
+ },
+ {
+ "createTime": 0,
+ "key": "collection/b",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "key": "b"
+ },
+ "version": 1000
+ }
+ ],
+ "targets": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchCurrent": [
+ [
+ 2
+ ],
+ "resume-token-2000"
+ ]
+ },
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 2000
+ },
+ "expectedSnapshotEvents": [
+ {
+ "added": [
+ {
+ "createTime": 0,
+ "key": "collection/a",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "key": "a"
+ },
+ "version": 1000
+ },
+ {
+ "createTime": 0,
+ "key": "collection/b",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "key": "b"
+ },
+ "version": 1000
+ }
+ ],
+ "errorCode": 0,
+ "fromCache": false,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ }
+ ]
+ },
+ {
+ "userUnlisten": [
+ 2,
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "expectedState": {
+ "activeTargets": {
+ }
+ }
+ },
+ {
+ "userListen": {
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ },
+ "targetId": 2
+ },
+ "expectedSnapshotEvents": [
+ {
+ "added": [
+ {
+ "createTime": 0,
+ "key": "collection/a",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "key": "a"
+ },
+ "version": 1000
+ },
+ {
+ "createTime": 0,
+ "key": "collection/b",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "key": "b"
+ },
+ "version": 1000
+ }
+ ],
+ "errorCode": 0,
+ "fromCache": true,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ }
+ ],
+ "expectedState": {
+ "activeTargets": {
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": "resume-token-2000",
+ "expectedCount": 2
+ }
+ }
+ }
+ }
+ ]
+ },
"Secondary client advances query state with global snapshot from primary": {
"describeName": "Listens:",
"itName": "Secondary client advances query state with global snapshot from primary",
@@ -12473,6 +13334,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -12509,6 +13371,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -12578,6 +13441,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -12649,6 +13513,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -12725,6 +13590,7 @@
},
"removed": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -12769,6 +13635,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"value": null,
"version": 2000
@@ -12820,6 +13687,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -12910,6 +13778,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -12946,6 +13815,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -13015,6 +13885,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -13086,6 +13957,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -13160,6 +14032,7 @@
"hasPendingWrites": true,
"modified": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -13565,6 +14438,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -13596,6 +14470,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -13707,6 +14582,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -13718,6 +14594,7 @@
"version": 1000
},
{
+ "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -13752,6 +14629,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -13763,6 +14641,7 @@
"version": 1000
},
{
+ "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -13825,6 +14704,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -13836,6 +14716,7 @@
"version": 1000
},
{
+ "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -13907,6 +14788,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -13980,6 +14862,7 @@
},
"removed": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -14032,6 +14915,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -14173,6 +15057,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -14237,6 +15122,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -14273,6 +15159,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -14346,6 +15233,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -14380,6 +15268,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -14420,6 +15309,7 @@
},
"removed": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -14438,6 +15328,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -14479,6 +15370,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -14506,6 +15398,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -14532,6 +15425,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -14605,6 +15499,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -14639,6 +15534,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -14667,6 +15563,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -14696,6 +15593,7 @@
"hasPendingWrites": false,
"modified": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -14755,6 +15653,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -14804,6 +15703,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -14839,6 +15739,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -14926,6 +15827,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -14960,6 +15862,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -14988,6 +15891,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -15017,6 +15921,7 @@
"hasPendingWrites": false,
"modified": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -15064,6 +15969,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -15113,6 +16019,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -15148,6 +16055,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -15279,6 +16187,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection1/a",
"options": {
"hasCommittedMutations": false,
@@ -15299,6 +16208,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection2/a",
"options": {
"hasCommittedMutations": false,
@@ -15373,6 +16283,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection2/a",
"options": {
"hasCommittedMutations": false,
@@ -15663,6 +16574,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -15697,6 +16609,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -15739,6 +16652,7 @@
"hasPendingWrites": true,
"modified": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -15765,6 +16679,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -15799,6 +16714,7 @@
"hasPendingWrites": false,
"metadata": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -15879,6 +16795,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -15913,6 +16830,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -15955,6 +16873,7 @@
"hasPendingWrites": true,
"modified": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -15999,6 +16918,7 @@
"hasPendingWrites": true,
"modified": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -16038,6 +16958,7 @@
"hasPendingWrites": true,
"modified": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -16109,6 +17030,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -16143,6 +17065,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -16182,6 +17105,7 @@
{
"added": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -16243,6 +17167,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -16306,6 +17231,7 @@
"hasPendingWrites": true,
"modified": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -16331,6 +17257,7 @@
"hasPendingWrites": true,
"modified": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -16357,6 +17284,7 @@
"watchEntity": {
"docs": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -16392,6 +17320,7 @@
"hasPendingWrites": false,
"metadata": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -16417,6 +17346,7 @@
"hasPendingWrites": false,
"metadata": [
{
+ "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
From 4e6fb97dc916293ee8fce6c746d0b21b3e3c3940 Mon Sep 17 00:00:00 2001
From: milaGGL <107142260+milaGGL@users.noreply.github.com>
Date: Thu, 26 Jan 2023 17:57:10 -0800
Subject: [PATCH 19/27] upload initial code
---
.../firestore/remote/BloomFilter.java | 17 +-
.../remote/BloomFilterException.java | 9 +
.../firestore/remote/ExistenceFilter.java | 16 +-
.../firestore/remote/RemoteSerializer.java | 3 +-
.../remote/WatchChangeAggregator.java | 67 +-
.../firestore/remote/BloomFilterTest.java | 55 +-
.../firebase/firestore/spec/SpecTestCase.java | 52 +-
.../json/existence_filter_spec_test.json | 6902 +++++++++++++++--
.../test/resources/json/limbo_spec_test.json | 402 +-
.../test/resources/json/limit_spec_test.json | 12 +-
.../test/resources/json/listen_spec_test.json | 259 -
11 files changed, 6752 insertions(+), 1042 deletions(-)
create mode 100644 firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilterException.java
diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java
index 9eba0f3f07b..d1903fac8d2 100644
--- a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java
+++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java
@@ -27,26 +27,25 @@ public class BloomFilter {
private final int hashCount;
private final MessageDigest md5HashMessageDigest;
- public BloomFilter(@NonNull byte[] bitmap, int padding, int hashCount) {
+ public BloomFilter(@NonNull byte[] bitmap, int padding, int hashCount)
+ throws BloomFilterException {
if (bitmap == null) {
throw new NullPointerException("Bitmap cannot be null.");
}
if (padding < 0 || padding >= 8) {
- throw new IllegalArgumentException("Invalid padding: " + padding);
+ throw new BloomFilterException("Invalid padding: " + padding);
}
if (hashCount < 0) {
- throw new IllegalArgumentException("Invalid hash count: " + hashCount);
+ throw new BloomFilterException("Invalid hash count: " + hashCount);
}
if (bitmap.length > 0 && hashCount == 0) {
// Only empty bloom filter can have 0 hash count.
- throw new IllegalArgumentException("Invalid hash count: " + hashCount);
+ throw new BloomFilterException("Invalid hash count: " + hashCount);
}
- if (bitmap.length == 0) {
+ if (bitmap.length == 0 && padding != 0) {
// Empty bloom filter should have 0 padding.
- if (padding != 0) {
- throw new IllegalArgumentException(
- "Expected padding of 0 when bitmap length is 0, but got " + padding);
- }
+ throw new BloomFilterException(
+ "Expected padding of 0 when bitmap length is 0, but got " + padding);
}
this.bitmap = bitmap;
diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilterException.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilterException.java
new file mode 100644
index 00000000000..5afd59e3824
--- /dev/null
+++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilterException.java
@@ -0,0 +1,9 @@
+package com.google.firebase.firestore.remote;
+
+import androidx.annotation.NonNull;
+
+public class BloomFilterException extends Exception {
+ public BloomFilterException(@NonNull String detailMessage) {
+ super(detailMessage);
+ }
+}
diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/ExistenceFilter.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/ExistenceFilter.java
index 7be1ca4744a..4d56b655620 100644
--- a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/ExistenceFilter.java
+++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/ExistenceFilter.java
@@ -14,20 +14,34 @@
package com.google.firebase.firestore.remote;
+import androidx.annotation.Nullable;
+import com.google.firestore.v1.BloomFilter;
+
/** Simplest form of existence filter */
public final class ExistenceFilter {
private final int count;
+ private BloomFilter unchangedNames;
public ExistenceFilter(int count) {
this.count = count;
}
+ public ExistenceFilter(int count, BloomFilter unchangedNames) {
+ this.count = count;
+ this.unchangedNames = unchangedNames;
+ }
+
public int getCount() {
return count;
}
+ @Nullable
+ public BloomFilter getUnchangedNames() {
+ return unchangedNames;
+ }
+
@Override
public String toString() {
- return "ExistenceFilter{count=" + count + '}';
+ return "ExistenceFilter{count=" + count + "unchangedNames=" + unchangedNames + '}';
}
}
diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteSerializer.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteSerializer.java
index 74ba575386b..6cef47e89d1 100644
--- a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteSerializer.java
+++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteSerializer.java
@@ -943,7 +943,8 @@ public WatchChange decodeWatchChange(ListenResponse protoChange) {
case FILTER:
com.google.firestore.v1.ExistenceFilter protoFilter = protoChange.getFilter();
// TODO: implement existence filter parsing (see b/33076578)
- ExistenceFilter filter = new ExistenceFilter(protoFilter.getCount());
+ ExistenceFilter filter =
+ new ExistenceFilter(protoFilter.getCount(), protoFilter.getUnchangedNames());
int targetId = protoFilter.getTargetId();
watchChange = new ExistenceFilterWatchChange(targetId, filter);
break;
diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/WatchChangeAggregator.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/WatchChangeAggregator.java
index 1086af504db..00d5532a827 100644
--- a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/WatchChangeAggregator.java
+++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/WatchChangeAggregator.java
@@ -29,6 +29,7 @@
import com.google.firebase.firestore.remote.WatchChange.DocumentChange;
import com.google.firebase.firestore.remote.WatchChange.ExistenceFilterWatchChange;
import com.google.firebase.firestore.remote.WatchChange.WatchTargetChange;
+import com.google.firebase.firestore.util.Logger;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -196,17 +197,73 @@ public void handleExistenceFilter(ExistenceFilterWatchChange watchChange) {
expectedCount == 1, "Single document existence filter with count: %d", expectedCount);
}
} else {
- long currentSize = getCurrentDocumentCountForTarget(targetId);
+ int currentSize = getCurrentDocumentCountForTarget(targetId);
if (currentSize != expectedCount) {
- // Existence filter mismatch: We reset the mapping and raise a new snapshot with
- // `isFromCache:true`.
- resetTarget(targetId);
- pendingTargetResets.add(targetId);
+
+ // Apply bloom filter to identify and mark removed documents.
+ boolean bloomFilterApplied =
+ this.applyBloomFilter(watchChange.getExistenceFilter(), targetId, currentSize);
+
+ if (!bloomFilterApplied) {
+ // If bloom filter application fails, we reset the mapping and
+ // trigger re-run of the query.
+ resetTarget(targetId);
+ pendingTargetResets.add(targetId);
+ }
}
}
}
}
+ /** Returns whether a bloom filter removed the deleted documents successfully. */
+ private boolean applyBloomFilter(
+ ExistenceFilter existenceFilter, int targetId, int currentCount) {
+ int expectedCount = existenceFilter.getCount();
+ com.google.firestore.v1.BloomFilter unchangedNames = existenceFilter.getUnchangedNames();
+
+ if (unchangedNames == null || unchangedNames.getBits() == null) {
+ return false;
+ }
+
+ byte[] bitmap = unchangedNames.getBits().getBitmap().toByteArray();
+ BloomFilter bloomFilter;
+ System.out.println("bitmap");
+ try {
+ bloomFilter =
+ new BloomFilter(
+ bitmap, unchangedNames.getBits().getPadding() | 0, unchangedNames.getHashCount() | 0);
+ } catch (Exception e) {
+ if (e instanceof BloomFilterException) {
+ Logger.warn("Firestore", "BloomFilter error: %s", e);
+ } else {
+ Logger.warn("Firestore", "Applying bloom filter failed: %s", e);
+ }
+ return false;
+ }
+
+ int removedDocumentCount = this.filterRemovedDocuments(bloomFilter, targetId);
+
+ return expectedCount == (currentCount - removedDocumentCount);
+ }
+
+ /**
+ * Filter out removed documents based on bloom filter membership result and return number of
+ * documents removed.
+ */
+ private int filterRemovedDocuments(BloomFilter bloomFilter, int targetId) {
+ ImmutableSortedSet existingKeys =
+ targetMetadataProvider.getRemoteKeysForTarget(targetId);
+ int removalCount = 0;
+ for (DocumentKey key : existingKeys) {
+ if (!bloomFilter.mightContain(
+ "projects/test-project/databases/(default)/documents/"
+ + key.getPath().canonicalString())) {
+ this.removeDocumentFromTarget(targetId, key, /*updatedDocument=*/ null);
+ removalCount++;
+ }
+ }
+ return removalCount;
+ }
/**
* Converts the currently accumulated state into a remote event at the provided snapshot version.
* Resets the accumulated changes before returning.
diff --git a/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/BloomFilterTest.java b/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/BloomFilterTest.java
index 0e851a0fc4f..b56538dde01 100644
--- a/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/BloomFilterTest.java
+++ b/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/BloomFilterTest.java
@@ -41,13 +41,13 @@ public class BloomFilterTest {
"src/test/resources/bloom_filter_golden_test_data/";
@Test
- public void instantiateEmptyBloomFilter() {
+ public void instantiateEmptyBloomFilter() throws BloomFilterException {
BloomFilter bloomFilter = new BloomFilter(new byte[0], 0, 0);
assertEquals(bloomFilter.getBitCount(), 0);
}
@Test
- public void instantiateNonEmptyBloomFilter() {
+ public void instantiateNonEmptyBloomFilter() throws BloomFilterException {
{
BloomFilter bloomFilter1 = new BloomFilter(new byte[] {1}, 0, 1);
assertEquals(bloomFilter1.getBitCount(), 8);
@@ -73,60 +73,58 @@ public void constructorShouldThrowNPEOnNullBitmap() {
}
@Test
- public void constructorShouldThrowIAEOnEmptyBloomFilterWithNonZeroPadding() {
- IllegalArgumentException exception =
- assertThrows(IllegalArgumentException.class, () -> new BloomFilter(new byte[0], 1, 0));
+ public void constructorShouldThrowBFEOnEmptyBloomFilterWithNonZeroPadding() {
+ BloomFilterException exception =
+ assertThrows(BloomFilterException.class, () -> new BloomFilter(new byte[0], 1, 0));
assertThat(exception)
.hasMessageThat()
.contains("Expected padding of 0 when bitmap length is 0, but got 1");
}
@Test
- public void constructorShouldThrowIAEOnNonEmptyBloomFilterWithZeroHashCount() {
- IllegalArgumentException zeroHashCountException =
- assertThrows(IllegalArgumentException.class, () -> new BloomFilter(new byte[] {1}, 1, 0));
+ public void constructorShouldThrowBFEOnNonEmptyBloomFilterWithZeroHashCount() {
+ BloomFilterException zeroHashCountException =
+ assertThrows(BloomFilterException.class, () -> new BloomFilter(new byte[] {1}, 1, 0));
assertThat(zeroHashCountException).hasMessageThat().contains("Invalid hash count: 0");
}
@Test
- public void constructorShouldThrowIAEOnNegativePadding() {
+ public void constructorShouldThrowBFEOnNegativePadding() {
{
- IllegalArgumentException emptyBloomFilterException =
- assertThrows(IllegalArgumentException.class, () -> new BloomFilter(new byte[0], -1, 0));
+ BloomFilterException emptyBloomFilterException =
+ assertThrows(BloomFilterException.class, () -> new BloomFilter(new byte[0], -1, 0));
assertThat(emptyBloomFilterException).hasMessageThat().contains("Invalid padding: -1");
}
{
- IllegalArgumentException nonEmptyBloomFilterException =
- assertThrows(
- IllegalArgumentException.class, () -> new BloomFilter(new byte[] {1}, -1, 1));
+ BloomFilterException nonEmptyBloomFilterException =
+ assertThrows(BloomFilterException.class, () -> new BloomFilter(new byte[] {1}, -1, 1));
assertThat(nonEmptyBloomFilterException).hasMessageThat().contains("Invalid padding: -1");
}
}
@Test
- public void constructorShouldThrowIAEOnNegativeHashCount() {
+ public void constructorShouldThrowBFEOnNegativeHashCount() {
{
- IllegalArgumentException emptyBloomFilterException =
- assertThrows(IllegalArgumentException.class, () -> new BloomFilter(new byte[0], 0, -1));
+ BloomFilterException emptyBloomFilterException =
+ assertThrows(BloomFilterException.class, () -> new BloomFilter(new byte[0], 0, -1));
assertThat(emptyBloomFilterException).hasMessageThat().contains("Invalid hash count: -1");
}
{
- IllegalArgumentException nonEmptyBloomFilterException =
- assertThrows(
- IllegalArgumentException.class, () -> new BloomFilter(new byte[] {1}, 1, -1));
+ BloomFilterException nonEmptyBloomFilterException =
+ assertThrows(BloomFilterException.class, () -> new BloomFilter(new byte[] {1}, 1, -1));
assertThat(nonEmptyBloomFilterException).hasMessageThat().contains("Invalid hash count: -1");
}
}
@Test
- public void constructorShouldThrowIAEIfPaddingIsTooLarge() {
- IllegalArgumentException exception =
- assertThrows(IllegalArgumentException.class, () -> new BloomFilter(new byte[] {1}, 8, 1));
+ public void constructorShouldThrowBFEIfPaddingIsTooLarge() {
+ BloomFilterException exception =
+ assertThrows(BloomFilterException.class, () -> new BloomFilter(new byte[] {1}, 8, 1));
assertThat(exception).hasMessageThat().contains("Invalid padding: 8");
}
@Test
- public void mightContainCanProcessNonStandardCharacters() {
+ public void mightContainCanProcessNonStandardCharacters() throws BloomFilterException {
// A non-empty BloomFilter object with 1 insertion : "ÀÒ∑"
BloomFilter bloomFilter = new BloomFilter(new byte[] {(byte) 237, 5}, 5, 8);
assertTrue(bloomFilter.mightContain("ÀÒ∑"));
@@ -134,14 +132,15 @@ public void mightContainCanProcessNonStandardCharacters() {
}
@Test
- public void mightContainOnEmptyBloomFilterShouldReturnFalse() {
+ public void mightContainOnEmptyBloomFilterShouldReturnFalse() throws BloomFilterException {
BloomFilter bloomFilter = new BloomFilter(new byte[0], 0, 0);
assertFalse(bloomFilter.mightContain(""));
assertFalse(bloomFilter.mightContain("a"));
}
@Test
- public void mightContainWithEmptyStringMightReturnFalsePositiveResult() {
+ public void mightContainWithEmptyStringMightReturnFalsePositiveResult()
+ throws BloomFilterException {
{
BloomFilter bloomFilter1 = new BloomFilter(new byte[] {1}, 1, 1);
assertFalse(bloomFilter1.mightContain(""));
@@ -153,7 +152,7 @@ public void mightContainWithEmptyStringMightReturnFalsePositiveResult() {
}
@Test
- public void bloomFilterToString() {
+ public void bloomFilterToString() throws BloomFilterException {
{
BloomFilter emptyBloomFilter = new BloomFilter(new byte[0], 0, 0);
assertEquals(emptyBloomFilter.toString(), "BloomFilter{hashCount=0, size=0, bitmap=\"\"}");
@@ -179,7 +178,7 @@ public void bloomFilterToString() {
private static void runGoldenTest(String testFile) throws Exception {
String resultFile = testFile.replace("bloom_filter_proto", "membership_test_result");
if (resultFile.equals(testFile)) {
- throw new IllegalArgumentException("Cannot find corresponding result file for " + testFile);
+ throw new BloomFilterException("Cannot find corresponding result file for " + testFile);
}
JSONObject testJson = readJsonFile(testFile);
diff --git a/firebase-firestore/src/test/java/com/google/firebase/firestore/spec/SpecTestCase.java b/firebase-firestore/src/test/java/com/google/firebase/firestore/spec/SpecTestCase.java
index 7be9479da3b..7bfd3dafe7c 100644
--- a/firebase-firestore/src/test/java/com/google/firebase/firestore/spec/SpecTestCase.java
+++ b/firebase-firestore/src/test/java/com/google/firebase/firestore/spec/SpecTestCase.java
@@ -31,6 +31,7 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import android.util.Base64;
import android.util.Pair;
import androidx.test.core.app.ApplicationProvider;
import com.google.android.gms.tasks.Task;
@@ -81,6 +82,8 @@
import com.google.firebase.firestore.util.Assert;
import com.google.firebase.firestore.util.AsyncQueue;
import com.google.firebase.firestore.util.AsyncQueue.TimerId;
+import com.google.firestore.v1.BitSequence;
+import com.google.firestore.v1.BloomFilter;
import com.google.protobuf.ByteString;
import io.grpc.Status;
import java.io.BufferedReader;
@@ -468,10 +471,33 @@ private List parseIntList(@Nullable JSONArray arr) throws JSONException
return result;
}
+ /** Deeply parses a JSONObject into a bloom filter proto type. */
+ private BloomFilter parseBloomFilter(JSONObject obj) throws JSONException {
+ BitSequence.Builder bitSequence = BitSequence.newBuilder();
+ JSONObject bits = obj.getJSONObject("bits");
+ if (bits.has("padding")) {
+ bitSequence.setPadding(bits.getInt("padding"));
+ }
+ if (bits.has("bitmap")) {
+ try {
+ bitSequence.setBitmap(
+ ByteString.copyFrom(Base64.decode(bits.getString("bitmap"), Base64.DEFAULT)));
+ } catch (Exception e) {
+ bitSequence.setBitmap(ByteString.EMPTY);
+ }
+ }
+
+ BloomFilter.Builder bloomFilter = BloomFilter.newBuilder();
+ bloomFilter.setBits(bitSequence);
+ if (obj.has("hashCount")) {
+ bloomFilter.setHashCount(obj.getInt("hashCount"));
+ }
+ return bloomFilter.build();
+ }
+
//
// Methods for doing the steps of the spec test.
//
-
private void doListen(JSONObject listenSpec) throws Exception {
int expectedId = listenSpec.getInt("targetId");
Query query = parseQuery(listenSpec.getJSONObject("query"));
@@ -654,15 +680,19 @@ private void doWatchEntity(JSONObject watchEntity) throws Exception {
}
}
- private void doWatchFilter(JSONArray watchFilter) throws Exception {
- List targets = parseIntList(watchFilter.getJSONArray(0));
+ private void doWatchFilter(JSONObject watchFilter) throws Exception {
+ List targets = parseIntList(watchFilter.getJSONArray("targetIds"));
Assert.hardAssert(
targets.size() == 1, "ExistenceFilters currently support exactly one target only.");
- int keyCount = watchFilter.length() == 0 ? 0 : watchFilter.length() - 1;
+ int keyCount = watchFilter.getJSONArray("keys").length();
+ BloomFilter bloomFilterProto = null;
+ if (watchFilter.has("bloomFilter")) {
+ bloomFilterProto = parseBloomFilter(watchFilter.getJSONObject("bloomFilter"));
+ }
// TODO: extend this with different existence filters over time.
- ExistenceFilter filter = new ExistenceFilter(keyCount);
+ ExistenceFilter filter = new ExistenceFilter(keyCount, bloomFilterProto);
ExistenceFilterWatchChange change = new ExistenceFilterWatchChange(targets.get(0), filter);
writeWatchChange(change, SnapshotVersion.NONE);
}
@@ -830,7 +860,7 @@ private void doStep(JSONObject step) throws Exception {
} else if (step.has("watchEntity")) {
doWatchEntity(step.getJSONObject("watchEntity"));
} else if (step.has("watchFilter")) {
- doWatchFilter(step.getJSONArray("watchFilter"));
+ doWatchFilter(step.getJSONObject("watchFilter"));
} else if (step.has("watchReset")) {
doWatchReset(step.getJSONArray("watchReset"));
} else if (step.has("watchSnapshot")) {
@@ -899,7 +929,14 @@ private void assertEventMatches(JSONObject expected, QueryEvent actual) throws J
for (int i = 0; metadata != null && i < metadata.length(); ++i) {
expectedChanges.add(parseChange(metadata.getJSONObject(i), Type.METADATA));
}
- assertEquals(expectedChanges, actual.view.getChanges());
+
+ List actualChanges = actual.view.getChanges();
+ Collections.sort(
+ expectedChanges, (a, b) -> a.getDocument().getKey().compareTo(b.getDocument().getKey()));
+ Collections.sort(
+ actualChanges, (a, b) -> a.getDocument().getKey().compareTo(b.getDocument().getKey()));
+
+ assertEquals(expectedChanges, actualChanges);
boolean expectedHasPendingWrites = expected.optBoolean("hasPendingWrites", false);
boolean expectedFromCache = expected.optBoolean("fromCache", false);
@@ -1160,6 +1197,7 @@ private void validateActiveTargets() {
private void runSteps(JSONArray steps, JSONObject config) throws Exception {
try {
specSetUp(config);
+
for (int i = 0; i < steps.length(); ++i) {
JSONObject step = steps.getJSONObject(i);
@Nullable JSONArray expectedSnapshotEvents = step.optJSONArray("expectedSnapshotEvents");
diff --git a/firebase-firestore/src/test/resources/json/existence_filter_spec_test.json b/firebase-firestore/src/test/resources/json/existence_filter_spec_test.json
index 3083b762224..04912cd923d 100644
--- a/firebase-firestore/src/test/resources/json/existence_filter_spec_test.json
+++ b/firebase-firestore/src/test/resources/json/existence_filter_spec_test.json
@@ -1,9 +1,8 @@
{
- "Existence filter clears resume token": {
+ "Bloom filter can process special characters in document name": {
"describeName": "Existence Filters:",
- "itName": "Existence filter clears resume token",
+ "itName": "Bloom filter can process special characters in document name",
"tags": [
- "durable-persistence"
],
"config": {
"numClients": 1,
@@ -47,7 +46,7 @@
"watchEntity": {
"docs": [
{
- "key": "collection/1",
+ "key": "collection/ÀÒ∑",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
@@ -58,13 +57,13 @@
"version": 1000
},
{
- "key": "collection/2",
+ "key": "collection/À∑Ò",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
},
"value": {
- "v": 2
+ "v": 1
},
"version": 1000
}
@@ -92,7 +91,7 @@
{
"added": [
{
- "key": "collection/1",
+ "key": "collection/ÀÒ∑",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
@@ -103,13 +102,13 @@
"version": 1000
},
{
- "key": "collection/2",
+ "key": "collection/À∑Ò",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
},
"value": {
- "v": 2
+ "v": 1
},
"version": 1000
}
@@ -128,12 +127,21 @@
]
},
{
- "watchFilter": [
- [
- 2
+ "watchFilter": {
+ "bloomFilter": {
+ "bits": {
+ "bitmap": "IIAAIIAIIAAIIAIIAA==",
+ "padding": 4
+ },
+ "hashCount": 10
+ },
+ "keys": [
+ "collection/ÀÒ∑"
],
- "collection/1"
- ]
+ "targetIds": [
+ 2
+ ]
+ }
},
{
"watchSnapshot": {
@@ -154,19 +162,51 @@
"path": "collection"
}
}
- ]
- },
- {
- "restart": true,
+ ],
"expectedState": {
"activeLimboDocs": [
+ "collection/À∑Ò"
],
"activeTargets": {
- },
- "enqueuedLimboDocs": [
- ]
+ "1": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/À∑Ò"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": ""
+ }
+ }
}
- },
+ }
+ ]
+ },
+ "Bloom filter fills in default values for undefined padding and hashCount": {
+ "describeName": "Existence Filters:",
+ "itName": "Bloom filter fills in default values for undefined padding and hashCount",
+ "tags": [
+ ],
+ "config": {
+ "numClients": 1,
+ "useGarbageCollection": true
+ },
+ "steps": [
{
"userListen": {
"query": {
@@ -178,11 +218,78 @@
},
"targetId": 2
},
+ "expectedState": {
+ "activeTargets": {
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": ""
+ }
+ }
+ }
+ },
+ {
+ "watchAck": [
+ 2
+ ]
+ },
+ {
+ "watchEntity": {
+ "docs": [
+ {
+ "key": "collection/a",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/b",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 2
+ },
+ "version": 1000
+ }
+ ],
+ "targets": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchCurrent": [
+ [
+ 2
+ ],
+ "resume-token-1000"
+ ]
+ },
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 1000
+ },
"expectedSnapshotEvents": [
{
"added": [
{
- "key": "collection/1",
+ "key": "collection/a",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
@@ -193,7 +300,7 @@
"version": 1000
},
{
- "key": "collection/2",
+ "key": "collection/b",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
@@ -204,6 +311,42 @@
"version": 1000
}
],
+ "errorCode": 0,
+ "fromCache": false,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ }
+ ]
+ },
+ {
+ "watchFilter": {
+ "bloomFilter": {
+ "bits": {
+ "bitmap": "AhAAApAAAIAEBIAABA=="
+ }
+ },
+ "keys": [
+ "collection/a"
+ ],
+ "targetIds": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 2000
+ },
+ "expectedSnapshotEvents": [
+ {
"errorCode": 0,
"fromCache": true,
"hasPendingWrites": false,
@@ -235,9 +378,9 @@
}
]
},
- "Existence filter handled at global snapshot": {
+ "Bloom filter is handled at global snapshot": {
"describeName": "Existence Filters:",
- "itName": "Existence filter handled at global snapshot",
+ "itName": "Bloom filter is handled at global snapshot",
"tags": [
],
"config": {
@@ -282,7 +425,7 @@
"watchEntity": {
"docs": [
{
- "key": "collection/1",
+ "key": "collection/a",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
@@ -291,6 +434,17 @@
"v": 1
},
"version": 1000
+ },
+ {
+ "key": "collection/b",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 2
+ },
+ "version": 2000
}
],
"targets": [
@@ -316,7 +470,7 @@
{
"added": [
{
- "key": "collection/1",
+ "key": "collection/a",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
@@ -325,6 +479,17 @@
"v": 1
},
"version": 1000
+ },
+ {
+ "key": "collection/b",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 2
+ },
+ "version": 2000
}
],
"errorCode": 0,
@@ -341,19 +506,27 @@
]
},
{
- "watchFilter": [
- [
- 2
+ "watchFilter": {
+ "bloomFilter": {
+ "bits": {
+ "bitmap": "AhAAApAAAIAEBIAABA==",
+ "padding": 4
+ },
+ "hashCount": 10
+ },
+ "keys": [
+ "collection/a"
],
- "collection/1",
- "collection/2"
- ]
+ "targetIds": [
+ 2
+ ]
+ }
},
{
"watchEntity": {
"docs": [
{
- "key": "collection/3",
+ "key": "collection/c",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
@@ -379,7 +552,7 @@
{
"added": [
{
- "key": "collection/3",
+ "key": "collection/c",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
@@ -403,7 +576,22 @@
}
],
"expectedState": {
+ "activeLimboDocs": [
+ "collection/b"
+ ],
"activeTargets": {
+ "1": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/b"
+ }
+ ],
+ "resumeToken": ""
+ },
"2": {
"queries": [
{
@@ -418,12 +606,45 @@
}
}
}
- },
+ }
+ ]
+ },
+ "Bloom filter limbo resolution is denied": {
+ "describeName": "Existence Filters:",
+ "itName": "Bloom filter limbo resolution is denied",
+ "tags": [
+ ],
+ "config": {
+ "numClients": 1,
+ "useGarbageCollection": true
+ },
+ "steps": [
{
- "watchRemove": {
- "targetIds": [
- 2
- ]
+ "userListen": {
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ },
+ "targetId": 2
+ },
+ "expectedState": {
+ "activeTargets": {
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": ""
+ }
+ }
}
},
{
@@ -435,7 +656,7 @@
"watchEntity": {
"docs": [
{
- "key": "collection/1",
+ "key": "collection/a",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
@@ -446,26 +667,15 @@
"version": 1000
},
{
- "key": "collection/2",
+ "key": "collection/b",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
},
"value": {
- "v": 2
+ "v": 1
},
- "version": 2000
- },
- {
- "key": "collection/3",
- "options": {
- "hasCommittedMutations": false,
- "hasLocalMutations": false
- },
- "value": {
- "v": 3
- },
- "version": 3000
+ "version": 1000
}
],
"targets": [
@@ -478,135 +688,39 @@
[
2
],
- "resume-token-3000"
+ "resume-token-1000"
]
},
{
"watchSnapshot": {
"targetIds": [
],
- "version": 3000
+ "version": 1000
},
"expectedSnapshotEvents": [
{
"added": [
{
- "key": "collection/2",
+ "key": "collection/a",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
},
"value": {
- "v": 2
+ "v": 1
},
- "version": 2000
- }
- ],
- "errorCode": 0,
- "fromCache": false,
- "hasPendingWrites": false,
- "query": {
- "filters": [
- ],
- "orderBys": [
- ],
- "path": "collection"
- }
- }
- ]
- }
- ]
- },
- "Existence filter ignored with pending target": {
- "describeName": "Existence Filters:",
- "itName": "Existence filter ignored with pending target",
- "tags": [
- ],
- "config": {
- "numClients": 1,
- "useGarbageCollection": false
- },
- "steps": [
- {
- "userListen": {
- "query": {
- "filters": [
- ],
- "orderBys": [
- ],
- "path": "collection"
- },
- "targetId": 2
- },
- "expectedState": {
- "activeTargets": {
- "2": {
- "queries": [
- {
- "filters": [
- ],
- "orderBys": [
- ],
- "path": "collection"
- }
- ],
- "resumeToken": ""
- }
- }
- }
- },
- {
- "watchAck": [
- 2
- ]
- },
- {
- "watchEntity": {
- "docs": [
- {
- "key": "collection/1",
- "options": {
- "hasCommittedMutations": false,
- "hasLocalMutations": false
- },
- "value": {
- "v": 2
+ "version": 1000
},
- "version": 2000
- }
- ],
- "targets": [
- 2
- ]
- }
- },
- {
- "watchCurrent": [
- [
- 2
- ],
- "resume-token-1000"
- ]
- },
- {
- "watchSnapshot": {
- "targetIds": [
- ],
- "version": 1000
- },
- "expectedSnapshotEvents": [
- {
- "added": [
{
- "key": "collection/1",
+ "key": "collection/b",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
},
"value": {
- "v": 2
+ "v": 1
},
- "version": 2000
+ "version": 1000
}
],
"errorCode": 0,
@@ -623,47 +737,30 @@
]
},
{
- "userUnlisten": [
- 2,
- {
- "filters": [
- ],
- "orderBys": [
- ],
- "path": "collection"
- }
- ],
- "expectedState": {
- "activeTargets": {
- }
+ "watchFilter": {
+ "bloomFilter": {
+ "bits": {
+ "bitmap": "AhAAApAAAIAEBIAABA==",
+ "padding": 4
+ },
+ "hashCount": 10
+ },
+ "keys": [
+ "collection/a"
+ ],
+ "targetIds": [
+ 2
+ ]
}
},
{
- "userListen": {
- "query": {
- "filters": [
- ],
- "orderBys": [
- ],
- "path": "collection"
- },
- "targetId": 2
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 2000
},
"expectedSnapshotEvents": [
{
- "added": [
- {
- "key": "collection/1",
- "options": {
- "hasCommittedMutations": false,
- "hasLocalMutations": false
- },
- "value": {
- "v": 2
- },
- "version": 2000
- }
- ],
"errorCode": 0,
"fromCache": true,
"hasPendingWrites": false,
@@ -677,7 +774,22 @@
}
],
"expectedState": {
+ "activeLimboDocs": [
+ "collection/b"
+ ],
"activeTargets": {
+ "1": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/b"
+ }
+ ],
+ "resumeToken": ""
+ },
"2": {
"queries": [
{
@@ -688,43 +800,19 @@
"path": "collection"
}
],
- "resumeToken": "resume-token-1000"
+ "resumeToken": ""
}
}
}
},
- {
- "watchFilter": [
- [
- 2
- ]
- ]
- },
{
"watchRemove": {
+ "cause": {
+ "code": 7
+ },
"targetIds": [
- 2
+ 1
]
- }
- },
- {
- "watchAck": [
- 2
- ]
- },
- {
- "watchCurrent": [
- [
- 2
- ],
- "resume-token-2000"
- ]
- },
- {
- "watchSnapshot": {
- "targetIds": [
- ],
- "version": 2000
},
"expectedSnapshotEvents": [
{
@@ -737,15 +825,46 @@
"orderBys": [
],
"path": "collection"
+ },
+ "removed": [
+ {
+ "key": "collection/b",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ }
+ ]
+ }
+ ],
+ "expectedState": {
+ "activeLimboDocs": [
+ ],
+ "activeTargets": {
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": ""
}
}
- ]
+ }
}
]
},
- "Existence filter limbo resolution is denied": {
+ "Bloom filter with large size works as expected": {
"describeName": "Existence Filters:",
- "itName": "Existence filter limbo resolution is denied",
+ "itName": "Bloom filter with large size works as expected",
"tags": [
],
"config": {
@@ -790,7 +909,7 @@
"watchEntity": {
"docs": [
{
- "key": "collection/1",
+ "key": "collection/doc0",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
@@ -801,27 +920,4388 @@
"version": 1000
},
{
- "key": "collection/2",
+ "key": "collection/doc1",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
},
"value": {
- "v": 2
+ "v": 1
},
"version": 1000
- }
- ],
- "targets": [
- 2
- ]
- }
- },
- {
- "watchCurrent": [
- [
- 2
- ],
+ },
+ {
+ "key": "collection/doc2",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc3",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc4",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc5",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc6",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc7",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc8",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc9",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc10",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc11",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc12",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc13",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc14",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc15",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc16",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc17",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc18",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc19",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc20",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc21",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc22",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc23",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc24",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc25",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc26",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc27",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc28",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc29",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc30",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc31",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc32",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc33",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc34",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc35",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc36",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc37",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc38",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc39",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc40",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc41",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc42",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc43",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc44",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc45",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc46",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc47",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc48",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc49",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc50",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc51",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc52",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc53",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc54",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc55",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc56",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc57",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc58",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc59",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc60",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc61",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc62",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc63",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc64",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc65",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc66",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc67",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc68",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc69",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc70",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc71",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc72",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc73",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc74",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc75",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc76",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc77",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc78",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc79",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc80",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc81",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc82",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc83",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc84",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc85",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc86",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc87",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc88",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc89",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc90",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc91",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc92",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc93",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc94",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc95",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc96",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc97",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc98",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc99",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ }
+ ],
+ "targets": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchCurrent": [
+ [
+ 2
+ ],
+ "resume-token-1000"
+ ]
+ },
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 1000
+ },
+ "expectedSnapshotEvents": [
+ {
+ "added": [
+ {
+ "key": "collection/doc0",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc1",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc2",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc3",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc4",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc5",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc6",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc7",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc8",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc9",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc10",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc11",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc12",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc13",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc14",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc15",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc16",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc17",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc18",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc19",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc20",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc21",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc22",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc23",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc24",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc25",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc26",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc27",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc28",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc29",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc30",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc31",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc32",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc33",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc34",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc35",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc36",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc37",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc38",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc39",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc40",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc41",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc42",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc43",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc44",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc45",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc46",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc47",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc48",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc49",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc50",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc51",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc52",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc53",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc54",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc55",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc56",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc57",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc58",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc59",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc60",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc61",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc62",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc63",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc64",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc65",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc66",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc67",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc68",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc69",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc70",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc71",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc72",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc73",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc74",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc75",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc76",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc77",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc78",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc79",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc80",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc81",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc82",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc83",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc84",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc85",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc86",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc87",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc88",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc89",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc90",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc91",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc92",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc93",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc94",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc95",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc96",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc97",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc98",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/doc99",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ }
+ ],
+ "errorCode": 0,
+ "fromCache": false,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ }
+ ]
+ },
+ {
+ "watchFilter": {
+ "bloomFilter": {
+ "bits": {
+ "bitmap": "+9oMQXUptl274DOaET8sfebQ4aCu0Roiddbja3z8TfadKuyPV/9XWV5Ksv+vywRXTfZSNIn8z+xk/oq1+cbOPepeNvbXVOF6H92fCOAz/KiS3Mcw338R9tXE3Y7QB1L2kbvbvVHW3Kn/k3Vx8k9Oa19eWX6RYE97Q+oCcVU=",
+ "padding": 0
+ },
+ "hashCount": 16
+ },
+ "keys": [
+ "collection/doc0",
+ "collection/doc1",
+ "collection/doc2",
+ "collection/doc3",
+ "collection/doc4",
+ "collection/doc5",
+ "collection/doc6",
+ "collection/doc7",
+ "collection/doc8",
+ "collection/doc9",
+ "collection/doc10",
+ "collection/doc11",
+ "collection/doc12",
+ "collection/doc13",
+ "collection/doc14",
+ "collection/doc15",
+ "collection/doc16",
+ "collection/doc17",
+ "collection/doc18",
+ "collection/doc19",
+ "collection/doc20",
+ "collection/doc21",
+ "collection/doc22",
+ "collection/doc23",
+ "collection/doc24",
+ "collection/doc25",
+ "collection/doc26",
+ "collection/doc27",
+ "collection/doc28",
+ "collection/doc29",
+ "collection/doc30",
+ "collection/doc31",
+ "collection/doc32",
+ "collection/doc33",
+ "collection/doc34",
+ "collection/doc35",
+ "collection/doc36",
+ "collection/doc37",
+ "collection/doc38",
+ "collection/doc39",
+ "collection/doc40",
+ "collection/doc41",
+ "collection/doc42",
+ "collection/doc43",
+ "collection/doc44",
+ "collection/doc45",
+ "collection/doc46",
+ "collection/doc47",
+ "collection/doc48",
+ "collection/doc49"
+ ],
+ "targetIds": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 2000
+ },
+ "expectedSnapshotEvents": [
+ {
+ "errorCode": 0,
+ "fromCache": true,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ }
+ ],
+ "expectedState": {
+ "activeLimboDocs": [
+ "collection/doc50",
+ "collection/doc51",
+ "collection/doc52",
+ "collection/doc53",
+ "collection/doc54",
+ "collection/doc55",
+ "collection/doc56",
+ "collection/doc57",
+ "collection/doc58",
+ "collection/doc59",
+ "collection/doc60",
+ "collection/doc61",
+ "collection/doc62",
+ "collection/doc63",
+ "collection/doc64",
+ "collection/doc65",
+ "collection/doc66",
+ "collection/doc67",
+ "collection/doc68",
+ "collection/doc69",
+ "collection/doc70",
+ "collection/doc71",
+ "collection/doc72",
+ "collection/doc73",
+ "collection/doc74",
+ "collection/doc75",
+ "collection/doc76",
+ "collection/doc77",
+ "collection/doc78",
+ "collection/doc79",
+ "collection/doc80",
+ "collection/doc81",
+ "collection/doc82",
+ "collection/doc83",
+ "collection/doc84",
+ "collection/doc85",
+ "collection/doc86",
+ "collection/doc87",
+ "collection/doc88",
+ "collection/doc89",
+ "collection/doc90",
+ "collection/doc91",
+ "collection/doc92",
+ "collection/doc93",
+ "collection/doc94",
+ "collection/doc95",
+ "collection/doc96",
+ "collection/doc97",
+ "collection/doc98",
+ "collection/doc99"
+ ],
+ "activeTargets": {
+ "1": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc50"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "11": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc55"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "13": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc56"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "15": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc57"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "17": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc58"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "19": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc59"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "21": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc60"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "23": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc61"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "25": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc62"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "27": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc63"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "29": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc64"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "3": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc51"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "31": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc65"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "33": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc66"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "35": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc67"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "37": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc68"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "39": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc69"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "41": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc70"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "43": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc71"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "45": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc72"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "47": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc73"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "49": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc74"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "5": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc52"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "51": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc75"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "53": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc76"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "55": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc77"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "57": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc78"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "59": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc79"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "61": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc80"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "63": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc81"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "65": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc82"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "67": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc83"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "69": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc84"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "7": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc53"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "71": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc85"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "73": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc86"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "75": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc87"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "77": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc88"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "79": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc89"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "81": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc90"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "83": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc91"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "85": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc92"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "87": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc93"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "89": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc94"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "9": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc54"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "91": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc95"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "93": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc96"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "95": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc97"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "97": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc98"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "99": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/doc99"
+ }
+ ],
+ "resumeToken": ""
+ }
+ }
+ }
+ }
+ ]
+ },
+ "Existence filter clears resume token": {
+ "describeName": "Existence Filters:",
+ "itName": "Existence filter clears resume token",
+ "tags": [
+ "durable-persistence"
+ ],
+ "config": {
+ "numClients": 1,
+ "useGarbageCollection": true
+ },
+ "steps": [
+ {
+ "userListen": {
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ },
+ "targetId": 2
+ },
+ "expectedState": {
+ "activeTargets": {
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": ""
+ }
+ }
+ }
+ },
+ {
+ "watchAck": [
+ 2
+ ]
+ },
+ {
+ "watchEntity": {
+ "docs": [
+ {
+ "key": "collection/1",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/2",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 2
+ },
+ "version": 1000
+ }
+ ],
+ "targets": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchCurrent": [
+ [
+ 2
+ ],
+ "resume-token-1000"
+ ]
+ },
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 1000
+ },
+ "expectedSnapshotEvents": [
+ {
+ "added": [
+ {
+ "key": "collection/1",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/2",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 2
+ },
+ "version": 1000
+ }
+ ],
+ "errorCode": 0,
+ "fromCache": false,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ }
+ ]
+ },
+ {
+ "watchFilter": {
+ "keys": [
+ "collection/1"
+ ],
+ "targetIds": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 2000
+ },
+ "expectedSnapshotEvents": [
+ {
+ "errorCode": 0,
+ "fromCache": true,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ }
+ ]
+ },
+ {
+ "restart": true,
+ "expectedState": {
+ "activeLimboDocs": [
+ ],
+ "activeTargets": {
+ },
+ "enqueuedLimboDocs": [
+ ]
+ }
+ },
+ {
+ "userListen": {
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ },
+ "targetId": 2
+ },
+ "expectedSnapshotEvents": [
+ {
+ "added": [
+ {
+ "key": "collection/1",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/2",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 2
+ },
+ "version": 1000
+ }
+ ],
+ "errorCode": 0,
+ "fromCache": true,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ }
+ ],
+ "expectedState": {
+ "activeTargets": {
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": ""
+ }
+ }
+ }
+ }
+ ]
+ },
+ "Existence filter handled at global snapshot": {
+ "describeName": "Existence Filters:",
+ "itName": "Existence filter handled at global snapshot",
+ "tags": [
+ ],
+ "config": {
+ "numClients": 1,
+ "useGarbageCollection": true
+ },
+ "steps": [
+ {
+ "userListen": {
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ },
+ "targetId": 2
+ },
+ "expectedState": {
+ "activeTargets": {
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": ""
+ }
+ }
+ }
+ },
+ {
+ "watchAck": [
+ 2
+ ]
+ },
+ {
+ "watchEntity": {
+ "docs": [
+ {
+ "key": "collection/1",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ }
+ ],
+ "targets": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchCurrent": [
+ [
+ 2
+ ],
+ "resume-token-1000"
+ ]
+ },
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 1000
+ },
+ "expectedSnapshotEvents": [
+ {
+ "added": [
+ {
+ "key": "collection/1",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ }
+ ],
+ "errorCode": 0,
+ "fromCache": false,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ }
+ ]
+ },
+ {
+ "watchFilter": {
+ "keys": [
+ "collection/1",
+ "collection/2"
+ ],
+ "targetIds": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchEntity": {
+ "docs": [
+ {
+ "key": "collection/3",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 3
+ },
+ "version": 3000
+ }
+ ],
+ "targets": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 2000
+ },
+ "expectedSnapshotEvents": [
+ {
+ "added": [
+ {
+ "key": "collection/3",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 3
+ },
+ "version": 3000
+ }
+ ],
+ "errorCode": 0,
+ "fromCache": true,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ }
+ ],
+ "expectedState": {
+ "activeTargets": {
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": ""
+ }
+ }
+ }
+ },
+ {
+ "watchRemove": {
+ "targetIds": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchAck": [
+ 2
+ ]
+ },
+ {
+ "watchEntity": {
+ "docs": [
+ {
+ "key": "collection/1",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/2",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 2
+ },
+ "version": 2000
+ },
+ {
+ "key": "collection/3",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 3
+ },
+ "version": 3000
+ }
+ ],
+ "targets": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchCurrent": [
+ [
+ 2
+ ],
+ "resume-token-3000"
+ ]
+ },
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 3000
+ },
+ "expectedSnapshotEvents": [
+ {
+ "added": [
+ {
+ "key": "collection/2",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 2
+ },
+ "version": 2000
+ }
+ ],
+ "errorCode": 0,
+ "fromCache": false,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ "Existence filter ignored with pending target": {
+ "describeName": "Existence Filters:",
+ "itName": "Existence filter ignored with pending target",
+ "tags": [
+ ],
+ "config": {
+ "numClients": 1,
+ "useGarbageCollection": false
+ },
+ "steps": [
+ {
+ "userListen": {
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ },
+ "targetId": 2
+ },
+ "expectedState": {
+ "activeTargets": {
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": ""
+ }
+ }
+ }
+ },
+ {
+ "watchAck": [
+ 2
+ ]
+ },
+ {
+ "watchEntity": {
+ "docs": [
+ {
+ "key": "collection/1",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 2
+ },
+ "version": 2000
+ }
+ ],
+ "targets": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchCurrent": [
+ [
+ 2
+ ],
+ "resume-token-1000"
+ ]
+ },
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 1000
+ },
+ "expectedSnapshotEvents": [
+ {
+ "added": [
+ {
+ "key": "collection/1",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 2
+ },
+ "version": 2000
+ }
+ ],
+ "errorCode": 0,
+ "fromCache": false,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ }
+ ]
+ },
+ {
+ "userUnlisten": [
+ 2,
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "expectedState": {
+ "activeTargets": {
+ }
+ }
+ },
+ {
+ "userListen": {
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ },
+ "targetId": 2
+ },
+ "expectedSnapshotEvents": [
+ {
+ "added": [
+ {
+ "key": "collection/1",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 2
+ },
+ "version": 2000
+ }
+ ],
+ "errorCode": 0,
+ "fromCache": true,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ }
+ ],
+ "expectedState": {
+ "activeTargets": {
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": "resume-token-1000"
+ }
+ }
+ }
+ },
+ {
+ "watchFilter": {
+ "keys": [
+ ],
+ "targetIds": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchRemove": {
+ "targetIds": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchAck": [
+ 2
+ ]
+ },
+ {
+ "watchCurrent": [
+ [
+ 2
+ ],
+ "resume-token-2000"
+ ]
+ },
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 2000
+ },
+ "expectedSnapshotEvents": [
+ {
+ "errorCode": 0,
+ "fromCache": false,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ "Existence filter limbo resolution is denied": {
+ "describeName": "Existence Filters:",
+ "itName": "Existence filter limbo resolution is denied",
+ "tags": [
+ ],
+ "config": {
+ "numClients": 1,
+ "useGarbageCollection": true
+ },
+ "steps": [
+ {
+ "userListen": {
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ },
+ "targetId": 2
+ },
+ "expectedState": {
+ "activeTargets": {
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": ""
+ }
+ }
+ }
+ },
+ {
+ "watchAck": [
+ 2
+ ]
+ },
+ {
+ "watchEntity": {
+ "docs": [
+ {
+ "key": "collection/1",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/2",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 2
+ },
+ "version": 1000
+ }
+ ],
+ "targets": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchCurrent": [
+ [
+ 2
+ ],
+ "resume-token-1000"
+ ]
+ },
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 1000
+ },
+ "expectedSnapshotEvents": [
+ {
+ "added": [
+ {
+ "key": "collection/1",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/2",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 2
+ },
+ "version": 1000
+ }
+ ],
+ "errorCode": 0,
+ "fromCache": false,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ }
+ ]
+ },
+ {
+ "watchFilter": {
+ "keys": [
+ "collection/1"
+ ],
+ "targetIds": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 2000
+ },
+ "expectedSnapshotEvents": [
+ {
+ "errorCode": 0,
+ "fromCache": true,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ }
+ ],
+ "expectedState": {
+ "activeTargets": {
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": ""
+ }
+ }
+ }
+ },
+ {
+ "watchRemove": {
+ "targetIds": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchAck": [
+ 2
+ ]
+ },
+ {
+ "watchEntity": {
+ "docs": [
+ {
+ "key": "collection/1",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ }
+ ],
+ "targets": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchCurrent": [
+ [
+ 2
+ ],
+ "resume-token-2000"
+ ]
+ },
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 2000
+ },
+ "expectedState": {
+ "activeLimboDocs": [
+ "collection/2"
+ ],
+ "activeTargets": {
+ "1": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/2"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": ""
+ }
+ }
+ }
+ },
+ {
+ "watchRemove": {
+ "cause": {
+ "code": 7
+ },
+ "targetIds": [
+ 1
+ ]
+ },
+ "expectedSnapshotEvents": [
+ {
+ "errorCode": 0,
+ "fromCache": false,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ },
+ "removed": [
+ {
+ "key": "collection/2",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 2
+ },
+ "version": 1000
+ }
+ ]
+ }
+ ],
+ "expectedState": {
+ "activeLimboDocs": [
+ ],
+ "activeTargets": {
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": ""
+ }
+ }
+ }
+ }
+ ]
+ },
+ "Existence filter match": {
+ "describeName": "Existence Filters:",
+ "itName": "Existence filter match",
+ "tags": [
+ ],
+ "config": {
+ "numClients": 1,
+ "useGarbageCollection": true
+ },
+ "steps": [
+ {
+ "userListen": {
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ },
+ "targetId": 2
+ },
+ "expectedState": {
+ "activeTargets": {
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": ""
+ }
+ }
+ }
+ },
+ {
+ "watchAck": [
+ 2
+ ]
+ },
+ {
+ "watchEntity": {
+ "docs": [
+ {
+ "key": "collection/1",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ }
+ ],
+ "targets": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchCurrent": [
+ [
+ 2
+ ],
+ "resume-token-1000"
+ ]
+ },
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 1000
+ },
+ "expectedSnapshotEvents": [
+ {
+ "added": [
+ {
+ "key": "collection/1",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ }
+ ],
+ "errorCode": 0,
+ "fromCache": false,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ }
+ ]
+ },
+ {
+ "watchFilter": {
+ "keys": [
+ "collection/1"
+ ],
+ "targetIds": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 2000
+ }
+ }
+ ]
+ },
+ "Existence filter match after pending update": {
+ "describeName": "Existence Filters:",
+ "itName": "Existence filter match after pending update",
+ "tags": [
+ ],
+ "config": {
+ "numClients": 1,
+ "useGarbageCollection": true
+ },
+ "steps": [
+ {
+ "userListen": {
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ },
+ "targetId": 2
+ },
+ "expectedState": {
+ "activeTargets": {
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": ""
+ }
+ }
+ }
+ },
+ {
+ "watchAck": [
+ 2
+ ]
+ },
+ {
+ "watchCurrent": [
+ [
+ 2
+ ],
+ "resume-token-1000"
+ ]
+ },
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 2000
+ },
+ "expectedSnapshotEvents": [
+ {
+ "errorCode": 0,
+ "fromCache": false,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ }
+ ]
+ },
+ {
+ "watchEntity": {
+ "docs": [
+ {
+ "key": "collection/1",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 2
+ },
+ "version": 2000
+ }
+ ],
+ "targets": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchFilter": {
+ "keys": [
+ "collection/1"
+ ],
+ "targetIds": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 2000
+ },
+ "expectedSnapshotEvents": [
+ {
+ "added": [
+ {
+ "key": "collection/1",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 2
+ },
+ "version": 2000
+ }
+ ],
+ "errorCode": 0,
+ "fromCache": false,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ }
+ ]
+ }
+ ]
+ },
+ "Existence filter mismatch triggers re-run of query": {
+ "describeName": "Existence Filters:",
+ "itName": "Existence filter mismatch triggers re-run of query",
+ "tags": [
+ ],
+ "config": {
+ "numClients": 1,
+ "useGarbageCollection": true
+ },
+ "steps": [
+ {
+ "userListen": {
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ },
+ "targetId": 2
+ },
+ "expectedState": {
+ "activeTargets": {
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": ""
+ }
+ }
+ }
+ },
+ {
+ "watchAck": [
+ 2
+ ]
+ },
+ {
+ "watchEntity": {
+ "docs": [
+ {
+ "key": "collection/1",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/2",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 2
+ },
+ "version": 1000
+ }
+ ],
+ "targets": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchCurrent": [
+ [
+ 2
+ ],
"resume-token-1000"
]
},
@@ -829,30 +5309,676 @@
"watchSnapshot": {
"targetIds": [
],
- "version": 1000
+ "version": 1000
+ },
+ "expectedSnapshotEvents": [
+ {
+ "added": [
+ {
+ "key": "collection/1",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/2",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 2
+ },
+ "version": 1000
+ }
+ ],
+ "errorCode": 0,
+ "fromCache": false,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ }
+ ]
+ },
+ {
+ "watchFilter": {
+ "keys": [
+ "collection/1"
+ ],
+ "targetIds": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 2000
+ },
+ "expectedSnapshotEvents": [
+ {
+ "errorCode": 0,
+ "fromCache": true,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ }
+ ],
+ "expectedState": {
+ "activeTargets": {
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": ""
+ }
+ }
+ }
+ },
+ {
+ "watchRemove": {
+ "targetIds": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchAck": [
+ 2
+ ]
+ },
+ {
+ "watchEntity": {
+ "docs": [
+ {
+ "key": "collection/1",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ }
+ ],
+ "targets": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchCurrent": [
+ [
+ 2
+ ],
+ "resume-token-2000"
+ ]
+ },
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 2000
+ },
+ "expectedState": {
+ "activeLimboDocs": [
+ "collection/2"
+ ],
+ "activeTargets": {
+ "1": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/2"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": ""
+ }
+ }
+ }
+ },
+ {
+ "watchAck": [
+ 1
+ ]
+ },
+ {
+ "watchCurrent": [
+ [
+ 1
+ ],
+ "resume-token-2000"
+ ]
+ },
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 2000
+ },
+ "expectedSnapshotEvents": [
+ {
+ "errorCode": 0,
+ "fromCache": false,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ },
+ "removed": [
+ {
+ "key": "collection/2",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 2
+ },
+ "version": 1000
+ }
+ ]
+ }
+ ],
+ "expectedState": {
+ "activeLimboDocs": [
+ ],
+ "activeTargets": {
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": ""
+ }
+ }
+ }
+ }
+ ]
+ },
+ "Existence filter mismatch will drop resume token": {
+ "describeName": "Existence Filters:",
+ "itName": "Existence filter mismatch will drop resume token",
+ "tags": [
+ ],
+ "config": {
+ "numClients": 1,
+ "useGarbageCollection": true
+ },
+ "steps": [
+ {
+ "userListen": {
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ },
+ "targetId": 2
+ },
+ "expectedState": {
+ "activeTargets": {
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": ""
+ }
+ }
+ }
+ },
+ {
+ "watchAck": [
+ 2
+ ]
+ },
+ {
+ "watchEntity": {
+ "docs": [
+ {
+ "key": "collection/1",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/2",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 2
+ },
+ "version": 1000
+ }
+ ],
+ "targets": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchCurrent": [
+ [
+ 2
+ ],
+ "existence-filter-resume-token"
+ ]
+ },
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 1000
+ },
+ "expectedSnapshotEvents": [
+ {
+ "added": [
+ {
+ "key": "collection/1",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/2",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 2
+ },
+ "version": 1000
+ }
+ ],
+ "errorCode": 0,
+ "fromCache": false,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ }
+ ]
+ },
+ {
+ "watchStreamClose": {
+ "error": {
+ "code": 14,
+ "message": "Simulated Backend Error"
+ },
+ "runBackoffTimer": true
+ },
+ "expectedState": {
+ "activeTargets": {
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": "existence-filter-resume-token"
+ }
+ }
+ }
+ },
+ {
+ "watchAck": [
+ 2
+ ]
+ },
+ {
+ "watchFilter": {
+ "keys": [
+ "collection/1"
+ ],
+ "targetIds": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 2000
+ },
+ "expectedSnapshotEvents": [
+ {
+ "errorCode": 0,
+ "fromCache": true,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ }
+ ],
+ "expectedState": {
+ "activeTargets": {
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": ""
+ }
+ }
+ }
+ },
+ {
+ "watchRemove": {
+ "targetIds": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchAck": [
+ 2
+ ]
+ },
+ {
+ "watchEntity": {
+ "docs": [
+ {
+ "key": "collection/1",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ }
+ ],
+ "targets": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchCurrent": [
+ [
+ 2
+ ],
+ "resume-token-2000"
+ ]
+ },
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 2000
+ },
+ "expectedState": {
+ "activeLimboDocs": [
+ "collection/2"
+ ],
+ "activeTargets": {
+ "1": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/2"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": ""
+ }
+ }
+ }
+ },
+ {
+ "watchAck": [
+ 1
+ ]
+ },
+ {
+ "watchCurrent": [
+ [
+ 1
+ ],
+ "resume-token-2000"
+ ]
+ },
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 2000
},
"expectedSnapshotEvents": [
{
- "added": [
+ "errorCode": 0,
+ "fromCache": false,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ },
+ "removed": [
{
- "key": "collection/1",
+ "key": "collection/2",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
},
"value": {
- "v": 1
+ "v": 2
},
"version": 1000
+ }
+ ]
+ }
+ ],
+ "expectedState": {
+ "activeLimboDocs": [
+ ],
+ "activeTargets": {
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": ""
+ }
+ }
+ }
+ }
+ ]
+ },
+ "Existence filter synthesizes deletes": {
+ "describeName": "Existence Filters:",
+ "itName": "Existence filter synthesizes deletes",
+ "tags": [
+ ],
+ "config": {
+ "numClients": 1,
+ "useGarbageCollection": true
+ },
+ "steps": [
+ {
+ "userListen": {
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/a"
+ },
+ "targetId": 2
+ },
+ "expectedState": {
+ "activeTargets": {
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/a"
+ }
+ ],
+ "resumeToken": ""
+ }
+ }
+ }
+ },
+ {
+ "watchAck": [
+ 2
+ ]
+ },
+ {
+ "watchEntity": {
+ "docs": [
+ {
+ "key": "collection/a",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
},
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ }
+ ],
+ "targets": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchCurrent": [
+ [
+ 2
+ ],
+ "resume-token-1000"
+ ]
+ },
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 1000
+ },
+ "expectedSnapshotEvents": [
+ {
+ "added": [
{
- "key": "collection/2",
+ "key": "collection/a",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
},
"value": {
- "v": 2
+ "v": 1
},
"version": 1000
}
@@ -865,18 +5991,19 @@
],
"orderBys": [
],
- "path": "collection"
+ "path": "collection/a"
}
}
]
},
{
- "watchFilter": [
- [
- 2
+ "watchFilter": {
+ "keys": [
],
- "collection/1"
- ]
+ "targetIds": [
+ 2
+ ]
+ }
},
{
"watchSnapshot": {
@@ -887,17 +6014,54 @@
"expectedSnapshotEvents": [
{
"errorCode": 0,
- "fromCache": true,
+ "fromCache": false,
"hasPendingWrites": false,
"query": {
"filters": [
],
"orderBys": [
],
- "path": "collection"
- }
+ "path": "collection/a"
+ },
+ "removed": [
+ {
+ "key": "collection/a",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ }
+ ]
}
- ],
+ ]
+ }
+ ]
+ },
+ "Existence filter with empty target": {
+ "describeName": "Existence Filters:",
+ "itName": "Existence filter with empty target",
+ "tags": [
+ ],
+ "config": {
+ "numClients": 1,
+ "useGarbageCollection": true
+ },
+ "steps": [
+ {
+ "userListen": {
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ },
+ "targetId": 2
+ },
"expectedState": {
"activeTargets": {
"2": {
@@ -915,44 +6079,17 @@
}
}
},
- {
- "watchRemove": {
- "targetIds": [
- 2
- ]
- }
- },
{
"watchAck": [
2
]
},
- {
- "watchEntity": {
- "docs": [
- {
- "key": "collection/1",
- "options": {
- "hasCommittedMutations": false,
- "hasLocalMutations": false
- },
- "value": {
- "v": 1
- },
- "version": 1000
- }
- ],
- "targets": [
- 2
- ]
- }
- },
{
"watchCurrent": [
[
2
],
- "resume-token-2000"
+ "resume-token-1000"
]
},
{
@@ -961,51 +6098,41 @@
],
"version": 2000
},
- "expectedState": {
- "activeLimboDocs": [
- "collection/2"
- ],
- "activeTargets": {
- "1": {
- "queries": [
- {
- "filters": [
- ],
- "orderBys": [
- ],
- "path": "collection/2"
- }
+ "expectedSnapshotEvents": [
+ {
+ "errorCode": 0,
+ "fromCache": false,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
],
- "resumeToken": ""
- },
- "2": {
- "queries": [
- {
- "filters": [
- ],
- "orderBys": [
- ],
- "path": "collection"
- }
+ "orderBys": [
],
- "resumeToken": ""
+ "path": "collection"
}
}
- }
+ ]
},
{
- "watchRemove": {
- "cause": {
- "code": 7
- },
+ "watchFilter": {
+ "keys": [
+ "collection/1"
+ ],
"targetIds": [
- 1
+ 2
]
+ }
+ },
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 2000
},
"expectedSnapshotEvents": [
{
"errorCode": 0,
- "fromCache": false,
+ "fromCache": true,
"hasPendingWrites": false,
"query": {
"filters": [
@@ -1013,46 +6140,15 @@
"orderBys": [
],
"path": "collection"
- },
- "removed": [
- {
- "key": "collection/2",
- "options": {
- "hasCommittedMutations": false,
- "hasLocalMutations": false
- },
- "value": {
- "v": 2
- },
- "version": 1000
- }
- ]
- }
- ],
- "expectedState": {
- "activeLimboDocs": [
- ],
- "activeTargets": {
- "2": {
- "queries": [
- {
- "filters": [
- ],
- "orderBys": [
- ],
- "path": "collection"
- }
- ],
- "resumeToken": ""
}
}
- }
+ ]
}
]
},
- "Existence filter match": {
+ "Full re-query is skipped when bloom filter can identify documents deleted": {
"describeName": "Existence Filters:",
- "itName": "Existence filter match",
+ "itName": "Full re-query is skipped when bloom filter can identify documents deleted",
"tags": [
],
"config": {
@@ -1097,7 +6193,7 @@
"watchEntity": {
"docs": [
{
- "key": "collection/1",
+ "key": "collection/a",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
@@ -1106,6 +6202,17 @@
"v": 1
},
"version": 1000
+ },
+ {
+ "key": "collection/b",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 2
+ },
+ "version": 1000
}
],
"targets": [
@@ -1131,7 +6238,7 @@
{
"added": [
{
- "key": "collection/1",
+ "key": "collection/a",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
@@ -1140,6 +6247,17 @@
"v": 1
},
"version": 1000
+ },
+ {
+ "key": "collection/b",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 2
+ },
+ "version": 1000
}
],
"errorCode": 0,
@@ -1156,11 +6274,85 @@
]
},
{
- "watchFilter": [
- [
+ "watchFilter": {
+ "bloomFilter": {
+ "bits": {
+ "bitmap": "AhAAApAAAIAEBIAABA==",
+ "padding": 4
+ },
+ "hashCount": 10
+ },
+ "keys": [
+ "collection/a"
+ ],
+ "targetIds": [
2
+ ]
+ }
+ },
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 2000
+ },
+ "expectedSnapshotEvents": [
+ {
+ "errorCode": 0,
+ "fromCache": true,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ }
+ ],
+ "expectedState": {
+ "activeLimboDocs": [
+ "collection/b"
+ ],
+ "activeTargets": {
+ "1": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/b"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": ""
+ }
+ }
+ }
+ },
+ {
+ "watchAck": [
+ 1
+ ]
+ },
+ {
+ "watchCurrent": [
+ [
+ 1
],
- "collection/1"
+ "resume-token-2000"
]
},
{
@@ -1168,13 +6360,58 @@
"targetIds": [
],
"version": 2000
+ },
+ "expectedSnapshotEvents": [
+ {
+ "errorCode": 0,
+ "fromCache": false,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ },
+ "removed": [
+ {
+ "key": "collection/b",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 2
+ },
+ "version": 1000
+ }
+ ]
+ }
+ ],
+ "expectedState": {
+ "activeLimboDocs": [
+ ],
+ "activeTargets": {
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": ""
+ }
+ }
}
}
]
},
- "Existence filter match after pending update": {
+ "Full re-query is triggered when bloom filter bitmap is invalid": {
"describeName": "Existence Filters:",
- "itName": "Existence filter match after pending update",
+ "itName": "Full re-query is triggered when bloom filter bitmap is invalid",
"tags": [
],
"config": {
@@ -1215,48 +6452,30 @@
2
]
},
- {
- "watchCurrent": [
- [
- 2
- ],
- "resume-token-1000"
- ]
- },
- {
- "watchSnapshot": {
- "targetIds": [
- ],
- "version": 2000
- },
- "expectedSnapshotEvents": [
- {
- "errorCode": 0,
- "fromCache": false,
- "hasPendingWrites": false,
- "query": {
- "filters": [
- ],
- "orderBys": [
- ],
- "path": "collection"
- }
- }
- ]
- },
{
"watchEntity": {
"docs": [
{
- "key": "collection/1",
+ "key": "collection/a",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
},
"value": {
- "v": 2
+ "v": 1
},
- "version": 2000
+ "version": 1000
+ },
+ {
+ "key": "collection/b",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
}
],
"targets": [
@@ -1265,32 +6484,43 @@
}
},
{
- "watchFilter": [
+ "watchCurrent": [
[
2
],
- "collection/1"
+ "resume-token-1000"
]
},
{
"watchSnapshot": {
"targetIds": [
],
- "version": 2000
+ "version": 1000
},
"expectedSnapshotEvents": [
{
"added": [
{
- "key": "collection/1",
+ "key": "collection/a",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
},
"value": {
- "v": 2
+ "v": 1
},
- "version": 2000
+ "version": 1000
+ },
+ {
+ "key": "collection/b",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
}
],
"errorCode": 0,
@@ -1305,12 +6535,66 @@
}
}
]
+ },
+ {
+ "watchFilter": {
+ "bloomFilter": {
+ "bits": {
+ "bitmap": "INVALID_BASE_64",
+ "padding": 4
+ },
+ "hashCount": 10
+ },
+ "keys": [
+ "collection/a"
+ ],
+ "targetIds": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 2000
+ },
+ "expectedSnapshotEvents": [
+ {
+ "errorCode": 0,
+ "fromCache": true,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ }
+ ],
+ "expectedState": {
+ "activeTargets": {
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": ""
+ }
+ }
+ }
}
]
},
- "Existence filter mismatch triggers re-run of query": {
+ "Full re-query is triggered when bloom filter can not identify documents deleted": {
"describeName": "Existence Filters:",
- "itName": "Existence filter mismatch triggers re-run of query",
+ "itName": "Full re-query is triggered when bloom filter can not identify documents deleted",
"tags": [
],
"config": {
@@ -1355,7 +6639,7 @@
"watchEntity": {
"docs": [
{
- "key": "collection/1",
+ "key": "collection/a",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
@@ -1366,7 +6650,18 @@
"version": 1000
},
{
- "key": "collection/2",
+ "key": "collection/b",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 2
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/c",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
@@ -1400,7 +6695,7 @@
{
"added": [
{
- "key": "collection/1",
+ "key": "collection/a",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
@@ -1411,7 +6706,18 @@
"version": 1000
},
{
- "key": "collection/2",
+ "key": "collection/b",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 2
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/c",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
@@ -1436,12 +6742,21 @@
]
},
{
- "watchFilter": [
- [
- 2
+ "watchFilter": {
+ "bloomFilter": {
+ "bits": {
+ "bitmap": "AxBIApBIAIAWBoCQBA==",
+ "padding": 4
+ },
+ "hashCount": 10
+ },
+ "keys": [
+ "collection/a"
],
- "collection/1"
- ]
+ "targetIds": [
+ 2
+ ]
+ }
},
{
"watchSnapshot": {
@@ -1462,7 +6777,14 @@
"path": "collection"
}
}
- ],
+ ]
+ },
+ {
+ "watchRemove": {
+ "targetIds": [
+ 2
+ ]
+ },
"expectedState": {
"activeTargets": {
"2": {
@@ -1479,12 +6801,45 @@
}
}
}
- },
+ }
+ ]
+ },
+ "Full re-query is triggered when bloom filter hashCount is invalid": {
+ "describeName": "Existence Filters:",
+ "itName": "Full re-query is triggered when bloom filter hashCount is invalid",
+ "tags": [
+ ],
+ "config": {
+ "numClients": 1,
+ "useGarbageCollection": true
+ },
+ "steps": [
{
- "watchRemove": {
- "targetIds": [
- 2
- ]
+ "userListen": {
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ },
+ "targetId": 2
+ },
+ "expectedState": {
+ "activeTargets": {
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": ""
+ }
+ }
}
},
{
@@ -1496,7 +6851,7 @@
"watchEntity": {
"docs": [
{
- "key": "collection/1",
+ "key": "collection/a",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
@@ -1505,80 +6860,64 @@
"v": 1
},
"version": 1000
- }
- ],
- "targets": [
- 2
- ]
- }
- },
- {
- "watchCurrent": [
- [
- 2
- ],
- "resume-token-2000"
- ]
- },
- {
- "watchSnapshot": {
- "targetIds": [
- ],
- "version": 2000
- },
- "expectedState": {
- "activeLimboDocs": [
- "collection/2"
- ],
- "activeTargets": {
- "1": {
- "queries": [
- {
- "filters": [
- ],
- "orderBys": [
- ],
- "path": "collection/2"
- }
- ],
- "resumeToken": ""
},
- "2": {
- "queries": [
- {
- "filters": [
- ],
- "orderBys": [
- ],
- "path": "collection"
- }
- ],
- "resumeToken": ""
+ {
+ "key": "collection/b",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
}
- }
+ ],
+ "targets": [
+ 2
+ ]
}
},
- {
- "watchAck": [
- 1
- ]
- },
{
"watchCurrent": [
[
- 1
+ 2
],
- "resume-token-2000"
+ "resume-token-1000"
]
},
{
"watchSnapshot": {
"targetIds": [
],
- "version": 2000
+ "version": 1000
},
"expectedSnapshotEvents": [
{
+ "added": [
+ {
+ "key": "collection/a",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/b",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ }
+ ],
"errorCode": 0,
"fromCache": false,
"hasPendingWrites": false,
@@ -1588,25 +6927,48 @@
"orderBys": [
],
"path": "collection"
+ }
+ }
+ ]
+ },
+ {
+ "watchFilter": {
+ "bloomFilter": {
+ "bits": {
+ "bitmap": "AhAAApAAAIAEBIAABA==",
+ "padding": 4
},
- "removed": [
- {
- "key": "collection/2",
- "options": {
- "hasCommittedMutations": false,
- "hasLocalMutations": false
- },
- "value": {
- "v": 2
- },
- "version": 1000
- }
- ]
+ "hashCount": -1
+ },
+ "keys": [
+ "collection/a"
+ ],
+ "targetIds": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 2000
+ },
+ "expectedSnapshotEvents": [
+ {
+ "errorCode": 0,
+ "fromCache": true,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
}
],
"expectedState": {
- "activeLimboDocs": [
- ],
"activeTargets": {
"2": {
"queries": [
@@ -1625,9 +6987,9 @@
}
]
},
- "Existence filter mismatch will drop resume token": {
+ "Full re-query is triggered when bloom filter is empty": {
"describeName": "Existence Filters:",
- "itName": "Existence filter mismatch will drop resume token",
+ "itName": "Full re-query is triggered when bloom filter is empty",
"tags": [
],
"config": {
@@ -1672,7 +7034,7 @@
"watchEntity": {
"docs": [
{
- "key": "collection/1",
+ "key": "collection/a",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
@@ -1683,13 +7045,13 @@
"version": 1000
},
{
- "key": "collection/2",
+ "key": "collection/b",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
},
"value": {
- "v": 2
+ "v": 1
},
"version": 1000
}
@@ -1704,7 +7066,7 @@
[
2
],
- "existence-filter-resume-token"
+ "resume-token-1000"
]
},
{
@@ -1717,7 +7079,7 @@
{
"added": [
{
- "key": "collection/1",
+ "key": "collection/a",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
@@ -1728,13 +7090,13 @@
"version": 1000
},
{
- "key": "collection/2",
+ "key": "collection/b",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
},
"value": {
- "v": 2
+ "v": 1
},
"version": 1000
}
@@ -1753,42 +7115,21 @@
]
},
{
- "watchStreamClose": {
- "error": {
- "code": 14,
- "message": "Simulated Backend Error"
+ "watchFilter": {
+ "bloomFilter": {
+ "bits": {
+ "bitmap": "",
+ "padding": 0
+ },
+ "hashCount": 0
},
- "runBackoffTimer": true
- },
- "expectedState": {
- "activeTargets": {
- "2": {
- "queries": [
- {
- "filters": [
- ],
- "orderBys": [
- ],
- "path": "collection"
- }
- ],
- "resumeToken": "existence-filter-resume-token"
- }
- }
- }
- },
- {
- "watchAck": [
- 2
- ]
- },
- {
- "watchFilter": [
- [
- 2
+ "keys": [
+ "collection/a"
],
- "collection/1"
- ]
+ "targetIds": [
+ 2
+ ]
+ }
},
{
"watchSnapshot": {
@@ -1826,12 +7167,55 @@
}
}
}
- },
+ }
+ ]
+ },
+ "Same documents can have different bloom filters": {
+ "describeName": "Existence Filters:",
+ "itName": "Same documents can have different bloom filters",
+ "tags": [
+ ],
+ "config": {
+ "numClients": 1,
+ "useGarbageCollection": true
+ },
+ "steps": [
{
- "watchRemove": {
- "targetIds": [
- 2
- ]
+ "userListen": {
+ "query": {
+ "filters": [
+ [
+ "v",
+ "<=",
+ 2
+ ]
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ },
+ "targetId": 2
+ },
+ "expectedState": {
+ "activeTargets": {
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ [
+ "v",
+ "<=",
+ 2
+ ]
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": ""
+ }
+ }
}
},
{
@@ -1843,7 +7227,7 @@
"watchEntity": {
"docs": [
{
- "key": "collection/1",
+ "key": "collection/a",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
@@ -1852,6 +7236,17 @@
"v": 1
},
"version": 1000
+ },
+ {
+ "key": "collection/b",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 2
+ },
+ "version": 1000
}
],
"targets": [
@@ -1864,81 +7259,80 @@
[
2
],
- "resume-token-2000"
- ]
- },
- {
- "watchSnapshot": {
- "targetIds": [
- ],
- "version": 2000
- },
- "expectedState": {
- "activeLimboDocs": [
- "collection/2"
- ],
- "activeTargets": {
- "1": {
- "queries": [
- {
- "filters": [
- ],
- "orderBys": [
- ],
- "path": "collection/2"
- }
- ],
- "resumeToken": ""
- },
- "2": {
- "queries": [
- {
- "filters": [
- ],
- "orderBys": [
- ],
- "path": "collection"
- }
- ],
- "resumeToken": ""
- }
- }
- }
- },
- {
- "watchAck": [
- 1
- ]
- },
- {
- "watchCurrent": [
- [
- 1
- ],
- "resume-token-2000"
+ "resume-token-1000"
]
},
{
"watchSnapshot": {
"targetIds": [
],
- "version": 2000
+ "version": 1000
},
"expectedSnapshotEvents": [
{
+ "added": [
+ {
+ "key": "collection/a",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 1
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/b",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 2
+ },
+ "version": 1000
+ }
+ ],
"errorCode": 0,
"fromCache": false,
"hasPendingWrites": false,
"query": {
"filters": [
+ [
+ "v",
+ "<=",
+ 2
+ ]
],
"orderBys": [
],
"path": "collection"
- },
- "removed": [
+ }
+ }
+ ]
+ },
+ {
+ "userListen": {
+ "query": {
+ "filters": [
+ [
+ "v",
+ ">=",
+ 2
+ ]
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ },
+ "targetId": 4
+ },
+ "expectedSnapshotEvents": [
+ {
+ "added": [
{
- "key": "collection/2",
+ "key": "collection/b",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
@@ -1948,17 +7342,35 @@
},
"version": 1000
}
- ]
+ ],
+ "errorCode": 0,
+ "fromCache": true,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ [
+ "v",
+ ">=",
+ 2
+ ]
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
}
],
"expectedState": {
- "activeLimboDocs": [
- ],
"activeTargets": {
"2": {
"queries": [
{
"filters": [
+ [
+ "v",
+ "<=",
+ 2
+ ]
],
"orderBys": [
],
@@ -1966,43 +7378,20 @@
}
],
"resumeToken": ""
- }
- }
- }
- }
- ]
- },
- "Existence filter synthesizes deletes": {
- "describeName": "Existence Filters:",
- "itName": "Existence filter synthesizes deletes",
- "tags": [
- ],
- "config": {
- "numClients": 1,
- "useGarbageCollection": true
- },
- "steps": [
- {
- "userListen": {
- "query": {
- "filters": [
- ],
- "orderBys": [
- ],
- "path": "collection/a"
- },
- "targetId": 2
- },
- "expectedState": {
- "activeTargets": {
- "2": {
+ },
+ "4": {
"queries": [
{
"filters": [
+ [
+ "v",
+ ">=",
+ 2
+ ]
],
"orderBys": [
],
- "path": "collection/a"
+ "path": "collection"
}
],
"resumeToken": ""
@@ -2012,54 +7401,65 @@
},
{
"watchAck": [
- 2
+ 4
]
},
{
"watchEntity": {
"docs": [
{
- "key": "collection/a",
+ "key": "collection/b",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
},
"value": {
- "v": 1
+ "v": 2
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/c",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "v": 3
},
"version": 1000
}
],
"targets": [
- 2
+ 4
]
}
},
{
"watchCurrent": [
[
- 2
+ 4
],
- "resume-token-1000"
+ "resume-token-1001"
]
},
{
"watchSnapshot": {
"targetIds": [
],
- "version": 1000
+ "version": 1001
},
"expectedSnapshotEvents": [
{
"added": [
{
- "key": "collection/a",
+ "key": "collection/c",
"options": {
"hasCommittedMutations": false,
"hasLocalMutations": false
},
"value": {
- "v": 1
+ "v": 3
},
"version": 1000
}
@@ -2069,20 +7469,35 @@
"hasPendingWrites": false,
"query": {
"filters": [
+ [
+ "v",
+ ">=",
+ 2
+ ]
],
"orderBys": [
],
- "path": "collection/a"
+ "path": "collection"
}
}
]
},
{
- "watchFilter": [
- [
+ "watchFilter": {
+ "bloomFilter": {
+ "bits": {
+ "bitmap": "CQ==",
+ "padding": 3
+ },
+ "hashCount": 2
+ },
+ "keys": [
+ "collection/b"
+ ],
+ "targetIds": [
2
]
- ]
+ }
},
{
"watchSnapshot": {
@@ -2093,60 +7508,65 @@
"expectedSnapshotEvents": [
{
"errorCode": 0,
- "fromCache": false,
+ "fromCache": true,
"hasPendingWrites": false,
"query": {
"filters": [
+ [
+ "v",
+ "<=",
+ 2
+ ]
],
"orderBys": [
],
- "path": "collection/a"
- },
- "removed": [
- {
- "key": "collection/a",
- "options": {
- "hasCommittedMutations": false,
- "hasLocalMutations": false
- },
- "value": {
- "v": 1
- },
- "version": 1000
- }
- ]
+ "path": "collection"
+ }
}
- ]
- }
- ]
- },
- "Existence filter with empty target": {
- "describeName": "Existence Filters:",
- "itName": "Existence filter with empty target",
- "tags": [
- ],
- "config": {
- "numClients": 1,
- "useGarbageCollection": true
- },
- "steps": [
- {
- "userListen": {
- "query": {
- "filters": [
- ],
- "orderBys": [
- ],
- "path": "collection"
- },
- "targetId": 2
- },
+ ],
"expectedState": {
+ "activeLimboDocs": [
+ "collection/a"
+ ],
"activeTargets": {
+ "1": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/a"
+ }
+ ],
+ "resumeToken": ""
+ },
"2": {
"queries": [
{
"filters": [
+ [
+ "v",
+ "<=",
+ 2
+ ]
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "4": {
+ "queries": [
+ {
+ "filters": [
+ [
+ "v",
+ ">=",
+ 2
+ ]
],
"orderBys": [
],
@@ -2159,67 +7579,113 @@
}
},
{
- "watchAck": [
- 2
- ]
- },
- {
- "watchCurrent": [
- [
- 2
+ "watchFilter": {
+ "bloomFilter": {
+ "bits": {
+ "bitmap": "CA==",
+ "padding": 4
+ },
+ "hashCount": 1
+ },
+ "keys": [
+ "collection/b"
],
- "resume-token-1000"
- ]
+ "targetIds": [
+ 4
+ ]
+ }
},
{
"watchSnapshot": {
"targetIds": [
],
- "version": 2000
+ "version": 3000
},
"expectedSnapshotEvents": [
{
"errorCode": 0,
- "fromCache": false,
+ "fromCache": true,
"hasPendingWrites": false,
"query": {
"filters": [
+ [
+ "v",
+ ">=",
+ 2
+ ]
],
"orderBys": [
],
"path": "collection"
}
}
- ]
- },
- {
- "watchFilter": [
- [
- 2
- ],
- "collection/1"
- ]
- },
- {
- "watchSnapshot": {
- "targetIds": [
+ ],
+ "expectedState": {
+ "activeLimboDocs": [
+ "collection/a",
+ "collection/c"
],
- "version": 2000
- },
- "expectedSnapshotEvents": [
- {
- "errorCode": 0,
- "fromCache": true,
- "hasPendingWrites": false,
- "query": {
- "filters": [
+ "activeTargets": {
+ "1": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/a"
+ }
],
- "orderBys": [
+ "resumeToken": ""
+ },
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ [
+ "v",
+ "<=",
+ 2
+ ]
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
],
- "path": "collection"
+ "resumeToken": ""
+ },
+ "3": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/c"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "4": {
+ "queries": [
+ {
+ "filters": [
+ [
+ "v",
+ ">=",
+ 2
+ ]
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": ""
}
}
- ]
+ }
}
]
}
diff --git a/firebase-firestore/src/test/resources/json/limbo_spec_test.json b/firebase-firestore/src/test/resources/json/limbo_spec_test.json
index 0b6abe08a2b..7babd7364f5 100644
--- a/firebase-firestore/src/test/resources/json/limbo_spec_test.json
+++ b/firebase-firestore/src/test/resources/json/limbo_spec_test.json
@@ -3386,11 +3386,13 @@
]
},
{
- "watchFilter": [
- [
+ "watchFilter": {
+ "keys": [
+ ],
+ "targetIds": [
1
]
- ]
+ }
},
{
"watchCurrent": [
@@ -7794,9 +7796,9 @@
}
]
},
- "Limbo resolution throttling with existence filter mismatch": {
+ "Limbo resolution throttling with bloom filter application": {
"describeName": "Limbo Documents:",
- "itName": "Limbo resolution throttling with existence filter mismatch",
+ "itName": "Limbo resolution throttling with bloom filter application",
"tags": [
],
"config": {
@@ -8036,15 +8038,397 @@
}
},
{
- "watchFilter": [
+ "watchFilter": {
+ "bloomFilter": {
+ "bits": {
+ "bitmap": "yABCEAeZURNRGAkgAQ==",
+ "padding": 4
+ },
+ "hashCount": 10
+ },
+ "keys": [
+ "collection/b1",
+ "collection/b2",
+ "collection/b3"
+ ],
+ "targetIds": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 1001
+ },
+ "expectedSnapshotEvents": [
+ {
+ "added": [
+ {
+ "key": "collection/b1",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "key": "b1"
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/b2",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "key": "b2"
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/b3",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "key": "b3"
+ },
+ "version": 1000
+ }
+ ],
+ "errorCode": 0,
+ "fromCache": true,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ }
+ ]
+ },
+ {
+ "watchCurrent": [
+ [
+ 2
+ ],
+ "resume-token-1002"
+ ]
+ },
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 1002
+ },
+ "expectedState": {
+ "activeLimboDocs": [
+ "collection/a1",
+ "collection/a2"
+ ],
+ "activeTargets": {
+ "1": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/a1"
+ }
+ ],
+ "resumeToken": ""
+ },
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": "resume-token-1000"
+ },
+ "3": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection/a2"
+ }
+ ],
+ "resumeToken": ""
+ }
+ },
+ "enqueuedLimboDocs": [
+ "collection/a3"
+ ]
+ }
+ }
+ ]
+ },
+ "Limbo resolution throttling with existence filter mismatch": {
+ "describeName": "Limbo Documents:",
+ "itName": "Limbo resolution throttling with existence filter mismatch",
+ "tags": [
+ ],
+ "config": {
+ "maxConcurrentLimboResolutions": 2,
+ "numClients": 1,
+ "useGarbageCollection": true
+ },
+ "steps": [
+ {
+ "userListen": {
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ },
+ "targetId": 2
+ },
+ "expectedState": {
+ "activeTargets": {
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": ""
+ }
+ }
+ }
+ },
+ {
+ "watchAck": [
+ 2
+ ]
+ },
+ {
+ "watchEntity": {
+ "docs": [
+ {
+ "key": "collection/a1",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "key": "a1"
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/a2",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "key": "a2"
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/a3",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "key": "a3"
+ },
+ "version": 1000
+ }
+ ],
+ "targets": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchCurrent": [
[
2
],
- "collection/b1",
- "collection/b2",
- "collection/b3"
+ "resume-token-1000"
]
},
+ {
+ "watchSnapshot": {
+ "targetIds": [
+ ],
+ "version": 1000
+ },
+ "expectedSnapshotEvents": [
+ {
+ "added": [
+ {
+ "key": "collection/a1",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "key": "a1"
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/a2",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "key": "a2"
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/a3",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "key": "a3"
+ },
+ "version": 1000
+ }
+ ],
+ "errorCode": 0,
+ "fromCache": false,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ }
+ ]
+ },
+ {
+ "enableNetwork": false,
+ "expectedSnapshotEvents": [
+ {
+ "errorCode": 0,
+ "fromCache": true,
+ "hasPendingWrites": false,
+ "query": {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ }
+ ],
+ "expectedState": {
+ "activeLimboDocs": [
+ ],
+ "activeTargets": {
+ },
+ "enqueuedLimboDocs": [
+ ]
+ }
+ },
+ {
+ "enableNetwork": true,
+ "expectedState": {
+ "activeTargets": {
+ "2": {
+ "queries": [
+ {
+ "filters": [
+ ],
+ "orderBys": [
+ ],
+ "path": "collection"
+ }
+ ],
+ "resumeToken": "resume-token-1000"
+ }
+ }
+ }
+ },
+ {
+ "watchAck": [
+ 2
+ ]
+ },
+ {
+ "watchEntity": {
+ "docs": [
+ {
+ "key": "collection/b1",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "key": "b1"
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/b2",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "key": "b2"
+ },
+ "version": 1000
+ },
+ {
+ "key": "collection/b3",
+ "options": {
+ "hasCommittedMutations": false,
+ "hasLocalMutations": false
+ },
+ "value": {
+ "key": "b3"
+ },
+ "version": 1000
+ }
+ ],
+ "targets": [
+ 2
+ ]
+ }
+ },
+ {
+ "watchFilter": {
+ "keys": [
+ "collection/b1",
+ "collection/b2",
+ "collection/b3"
+ ],
+ "targetIds": [
+ 2
+ ]
+ }
+ },
{
"watchSnapshot": {
"targetIds": [
diff --git a/firebase-firestore/src/test/resources/json/limit_spec_test.json b/firebase-firestore/src/test/resources/json/limit_spec_test.json
index 40e48205956..856e0505d91 100644
--- a/firebase-firestore/src/test/resources/json/limit_spec_test.json
+++ b/firebase-firestore/src/test/resources/json/limit_spec_test.json
@@ -5455,12 +5455,14 @@
}
},
{
- "watchFilter": [
- [
- 2
+ "watchFilter": {
+ "keys": [
+ "collection/b"
],
- "collection/b"
- ]
+ "targetIds": [
+ 2
+ ]
+ }
},
{
"watchSnapshot": {
diff --git a/firebase-firestore/src/test/resources/json/listen_spec_test.json b/firebase-firestore/src/test/resources/json/listen_spec_test.json
index 57d253e6e43..85170a91d71 100644
--- a/firebase-firestore/src/test/resources/json/listen_spec_test.json
+++ b/firebase-firestore/src/test/resources/json/listen_spec_test.json
@@ -99,7 +99,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -140,7 +139,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -223,7 +221,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -441,7 +438,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -453,7 +449,6 @@
"version": 1000
},
{
- "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -488,7 +483,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -500,7 +494,6 @@
"version": 1000
},
{
- "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -532,7 +525,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -544,7 +536,6 @@
"version": 1000
},
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -619,7 +610,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/c",
"options": {
"hasCommittedMutations": false,
@@ -654,7 +644,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/c",
"options": {
"hasCommittedMutations": false,
@@ -684,7 +673,6 @@
},
"removed": [
{
- "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -720,7 +708,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/c",
"options": {
"hasCommittedMutations": false,
@@ -732,7 +719,6 @@
"version": 2000
},
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -901,7 +887,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -936,7 +921,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -1054,7 +1038,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -1089,7 +1072,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -1118,7 +1100,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -1145,7 +1126,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -1239,7 +1219,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -1251,7 +1230,6 @@
"version": 1000
},
{
- "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -1286,7 +1264,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -1342,7 +1319,6 @@
},
"removed": [
{
- "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -1558,7 +1534,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"value": null,
"version": 1000
@@ -1654,7 +1629,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -1681,7 +1655,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -1766,7 +1739,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -1850,7 +1822,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/exists",
"options": {
"hasCommittedMutations": false,
@@ -1940,7 +1911,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -1975,7 +1945,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -2016,7 +1985,6 @@
},
"removed": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -2049,7 +2017,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"value": null,
"version": 2000
@@ -2221,7 +2188,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection2/a",
"options": {
"hasCommittedMutations": false,
@@ -2265,7 +2231,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection2/a",
"options": {
"hasCommittedMutations": false,
@@ -2766,7 +2731,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -2801,7 +2765,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -2951,7 +2914,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -2988,7 +2950,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -3135,7 +3096,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"value": null,
"version": 2000
@@ -3233,7 +3193,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -3245,7 +3204,6 @@
"version": 1000
},
{
- "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -3280,7 +3238,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -3322,7 +3279,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -3428,7 +3384,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -3463,7 +3418,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -3582,7 +3536,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -3617,7 +3570,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -3662,7 +3614,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -3708,7 +3659,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -3808,7 +3758,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -3844,7 +3793,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -3918,7 +3866,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -3969,7 +3916,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"value": null,
"version": 3000
@@ -4008,7 +3954,6 @@
},
"removed": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -4113,7 +4058,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -4337,7 +4281,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -4373,7 +4316,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -4447,7 +4389,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -4498,7 +4439,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -4537,7 +4477,6 @@
"hasPendingWrites": false,
"modified": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -4649,7 +4588,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -4744,7 +4682,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -4889,7 +4826,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -4926,7 +4862,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -4975,7 +4910,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -5068,7 +5002,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -5109,7 +5042,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -5218,7 +5150,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -5259,7 +5190,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -5332,7 +5262,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -5373,7 +5302,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -5482,7 +5410,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -5523,7 +5450,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -5568,7 +5494,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -5661,7 +5586,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -5698,7 +5622,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -5730,7 +5653,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -5805,7 +5727,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -5840,7 +5761,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -5919,7 +5839,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -5954,7 +5873,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -6142,7 +6060,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -6154,7 +6071,6 @@
"version": 1000
},
{
- "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -6195,7 +6111,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -6207,7 +6122,6 @@
"version": 1000
},
{
- "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -6245,7 +6159,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -6257,7 +6170,6 @@
"version": 1000
},
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -6342,7 +6254,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/c",
"options": {
"hasCommittedMutations": false,
@@ -6374,7 +6285,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/c",
"options": {
"hasCommittedMutations": false,
@@ -6404,7 +6314,6 @@
},
"removed": [
{
- "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -6578,7 +6487,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -6590,7 +6498,6 @@
"version": 1000
},
{
- "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -6627,7 +6534,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -6639,7 +6545,6 @@
"version": 1000
},
{
- "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -6677,7 +6582,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -6689,7 +6593,6 @@
"version": 1000
},
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -6774,7 +6677,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/c",
"options": {
"hasCommittedMutations": false,
@@ -6802,7 +6704,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/c",
"options": {
"hasCommittedMutations": false,
@@ -6832,7 +6733,6 @@
},
"removed": [
{
- "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -6873,7 +6773,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/c",
"options": {
"hasCommittedMutations": false,
@@ -6885,7 +6784,6 @@
"version": 2000
},
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -7023,7 +6921,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/d",
"options": {
"hasCommittedMutations": false,
@@ -7055,7 +6952,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/d",
"options": {
"hasCommittedMutations": false,
@@ -7085,7 +6981,6 @@
},
"removed": [
{
- "createTime": 0,
"key": "collection/c",
"options": {
"hasCommittedMutations": false,
@@ -7303,7 +7198,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -7315,7 +7209,6 @@
"version": 1000
},
{
- "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -7356,7 +7249,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -7368,7 +7260,6 @@
"version": 1000
},
{
- "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -7400,7 +7291,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -7412,7 +7302,6 @@
"version": 1000
},
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -7515,7 +7404,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/c",
"options": {
"hasCommittedMutations": false,
@@ -7547,7 +7435,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/c",
"options": {
"hasCommittedMutations": false,
@@ -7577,7 +7464,6 @@
},
"removed": [
{
- "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -8340,7 +8226,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -8375,7 +8260,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -8434,7 +8318,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -8559,7 +8442,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -8594,7 +8476,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -8653,7 +8534,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -8777,7 +8657,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -8812,7 +8691,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -8883,7 +8761,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -9045,7 +8922,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -9081,7 +8957,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -9144,7 +9019,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -9359,7 +9233,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -9419,7 +9292,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -9545,7 +9417,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -9586,7 +9457,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -9664,7 +9534,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -9705,7 +9574,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -9768,7 +9636,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/c",
"options": {
"hasCommittedMutations": false,
@@ -9809,7 +9676,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/c",
"options": {
"hasCommittedMutations": false,
@@ -9921,7 +9787,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -9953,7 +9818,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -10101,7 +9965,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -10142,7 +10005,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -10176,7 +10038,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -10217,7 +10078,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -10229,7 +10089,6 @@
"version": 1000
},
{
- "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -10275,7 +10134,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/c",
"options": {
"hasCommittedMutations": false,
@@ -10303,7 +10161,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/c",
"options": {
"hasCommittedMutations": false,
@@ -10335,7 +10192,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -10361,7 +10217,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/c",
"options": {
"hasCommittedMutations": false,
@@ -10930,7 +10785,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -10971,7 +10825,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -11049,7 +10902,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -11121,7 +10973,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -11162,7 +11013,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -11250,7 +11100,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -11287,7 +11136,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -11332,7 +11180,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -11393,7 +11240,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -11443,7 +11289,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -11471,7 +11316,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -11503,7 +11347,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -11535,7 +11378,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -11623,7 +11465,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -11660,7 +11501,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -11705,7 +11545,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -11784,7 +11623,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -11816,7 +11654,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -11990,7 +11827,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -12035,7 +11871,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -12067,7 +11902,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -12152,7 +11986,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -12189,7 +12022,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -12234,7 +12066,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -12309,7 +12140,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -12346,7 +12176,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -12384,7 +12213,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/c",
"options": {
"hasCommittedMutations": false,
@@ -12412,7 +12240,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/c",
"options": {
"hasCommittedMutations": false,
@@ -12448,7 +12275,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -12460,7 +12286,6 @@
"version": 2000
},
{
- "createTime": 0,
"key": "collection/c",
"options": {
"hasCommittedMutations": false,
@@ -12537,7 +12362,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -12572,7 +12396,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -12635,7 +12458,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -12685,7 +12507,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"value": null,
"version": 2000
@@ -12724,7 +12545,6 @@
},
"removed": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -12788,7 +12608,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -12823,7 +12642,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -12887,7 +12705,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -12899,7 +12716,6 @@
"version": 1000
},
{
- "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -13099,7 +12915,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -13111,7 +12926,6 @@
"version": 1000
},
{
- "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -13146,7 +12960,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -13158,7 +12971,6 @@
"version": 1000
},
{
- "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -13214,7 +13026,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -13226,7 +13037,6 @@
"version": 1000
},
{
- "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -13334,7 +13144,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -13371,7 +13180,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -13441,7 +13249,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -13513,7 +13320,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -13590,7 +13396,6 @@
},
"removed": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -13635,7 +13440,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"value": null,
"version": 2000
@@ -13687,7 +13491,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -13778,7 +13581,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -13815,7 +13617,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -13885,7 +13686,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -13957,7 +13757,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -14032,7 +13831,6 @@
"hasPendingWrites": true,
"modified": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -14438,7 +14236,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -14470,7 +14267,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -14582,7 +14378,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -14594,7 +14389,6 @@
"version": 1000
},
{
- "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -14629,7 +14423,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -14641,7 +14434,6 @@
"version": 1000
},
{
- "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -14704,7 +14496,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -14716,7 +14507,6 @@
"version": 1000
},
{
- "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -14788,7 +14578,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -14862,7 +14651,6 @@
},
"removed": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -14915,7 +14703,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/b",
"options": {
"hasCommittedMutations": false,
@@ -15057,7 +14844,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -15122,7 +14908,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -15159,7 +14944,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -15233,7 +15017,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -15268,7 +15051,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -15309,7 +15091,6 @@
},
"removed": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -15328,7 +15109,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -15370,7 +15150,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -15398,7 +15177,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -15425,7 +15203,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -15499,7 +15276,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -15534,7 +15310,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -15563,7 +15338,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -15593,7 +15367,6 @@
"hasPendingWrites": false,
"modified": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -15653,7 +15426,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -15703,7 +15475,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -15739,7 +15510,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -15827,7 +15597,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -15862,7 +15631,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -15891,7 +15659,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -15921,7 +15688,6 @@
"hasPendingWrites": false,
"modified": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -15969,7 +15735,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -16019,7 +15784,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -16055,7 +15819,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -16187,7 +15950,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection1/a",
"options": {
"hasCommittedMutations": false,
@@ -16208,7 +15970,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection2/a",
"options": {
"hasCommittedMutations": false,
@@ -16283,7 +16044,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection2/a",
"options": {
"hasCommittedMutations": false,
@@ -16574,7 +16334,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -16609,7 +16368,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -16652,7 +16410,6 @@
"hasPendingWrites": true,
"modified": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -16679,7 +16436,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -16714,7 +16470,6 @@
"hasPendingWrites": false,
"metadata": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -16795,7 +16550,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -16830,7 +16584,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -16873,7 +16626,6 @@
"hasPendingWrites": true,
"modified": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -16918,7 +16670,6 @@
"hasPendingWrites": true,
"modified": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -16958,7 +16709,6 @@
"hasPendingWrites": true,
"modified": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -17030,7 +16780,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -17065,7 +16814,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -17105,7 +16853,6 @@
{
"added": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -17167,7 +16914,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -17231,7 +16977,6 @@
"hasPendingWrites": true,
"modified": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -17257,7 +17002,6 @@
"hasPendingWrites": true,
"modified": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -17284,7 +17028,6 @@
"watchEntity": {
"docs": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -17320,7 +17063,6 @@
"hasPendingWrites": false,
"metadata": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
@@ -17346,7 +17088,6 @@
"hasPendingWrites": false,
"metadata": [
{
- "createTime": 0,
"key": "collection/a",
"options": {
"hasCommittedMutations": false,
From 2cee1abedd8b81ca5e1d4e7f53a9d331a2ebaf7c Mon Sep 17 00:00:00 2001
From: milaGGL <107142260+milaGGL@users.noreply.github.com>
Date: Thu, 26 Jan 2023 21:36:30 -0800
Subject: [PATCH 20/27] format
---
.../firestore/remote/BloomFilterException.java | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilterException.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilterException.java
index 5afd59e3824..966707e511c 100644
--- a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilterException.java
+++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilterException.java
@@ -1,3 +1,17 @@
+// Copyright 2023 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
package com.google.firebase.firestore.remote;
import androidx.annotation.NonNull;
From 091741836b31f4b17c59a1a44e7a23ce35a73bda Mon Sep 17 00:00:00 2001
From: milaGGL <107142260+milaGGL@users.noreply.github.com>
Date: Fri, 27 Jan 2023 13:10:58 -0800
Subject: [PATCH 21/27] replace null check to hasBits()
---
.../firestore/remote/WatchChangeAggregator.java | 14 +++++---------
.../firebase/firestore/spec/SpecTestCase.java | 17 ++++++++++-------
2 files changed, 15 insertions(+), 16 deletions(-)
diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/WatchChangeAggregator.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/WatchChangeAggregator.java
index 00d5532a827..51b3ebd46da 100644
--- a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/WatchChangeAggregator.java
+++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/WatchChangeAggregator.java
@@ -221,23 +221,19 @@ private boolean applyBloomFilter(
int expectedCount = existenceFilter.getCount();
com.google.firestore.v1.BloomFilter unchangedNames = existenceFilter.getUnchangedNames();
- if (unchangedNames == null || unchangedNames.getBits() == null) {
+ if (unchangedNames == null || !unchangedNames.hasBits()) {
return false;
}
byte[] bitmap = unchangedNames.getBits().getBitmap().toByteArray();
BloomFilter bloomFilter;
- System.out.println("bitmap");
+
try {
bloomFilter =
new BloomFilter(
- bitmap, unchangedNames.getBits().getPadding() | 0, unchangedNames.getHashCount() | 0);
- } catch (Exception e) {
- if (e instanceof BloomFilterException) {
- Logger.warn("Firestore", "BloomFilter error: %s", e);
- } else {
- Logger.warn("Firestore", "Applying bloom filter failed: %s", e);
- }
+ bitmap, unchangedNames.getBits().getPadding(), unchangedNames.getHashCount());
+ } catch (BloomFilterException e) {
+ Logger.warn("Firestore", "BloomFilter error: %s", e);
return false;
}
diff --git a/firebase-firestore/src/test/java/com/google/firebase/firestore/spec/SpecTestCase.java b/firebase-firestore/src/test/java/com/google/firebase/firestore/spec/SpecTestCase.java
index 7bfd3dafe7c..0a22fb8aee7 100644
--- a/firebase-firestore/src/test/java/com/google/firebase/firestore/spec/SpecTestCase.java
+++ b/firebase-firestore/src/test/java/com/google/firebase/firestore/spec/SpecTestCase.java
@@ -930,13 +930,16 @@ private void assertEventMatches(JSONObject expected, QueryEvent actual) throws J
expectedChanges.add(parseChange(metadata.getJSONObject(i), Type.METADATA));
}
- List actualChanges = actual.view.getChanges();
- Collections.sort(
- expectedChanges, (a, b) -> a.getDocument().getKey().compareTo(b.getDocument().getKey()));
- Collections.sort(
- actualChanges, (a, b) -> a.getDocument().getKey().compareTo(b.getDocument().getKey()));
-
- assertEquals(expectedChanges, actualChanges);
+ List sortedActualChanges =
+ actual.view.getChanges().stream()
+ .sorted((a, b) -> a.getDocument().getKey().compareTo(b.getDocument().getKey()))
+ .collect(Collectors.toList());
+ List sortedExpectedChanges =
+ expectedChanges.stream()
+ .sorted((a, b) -> a.getDocument().getKey().compareTo(b.getDocument().getKey()))
+ .collect(Collectors.toList());
+
+ assertEquals(sortedExpectedChanges, sortedActualChanges);
boolean expectedHasPendingWrites = expected.optBoolean("hasPendingWrites", false);
boolean expectedFromCache = expected.optBoolean("fromCache", false);
From 1c4ed44be818b8757268b4cf1014e7967f63dd1e Mon Sep 17 00:00:00 2001
From: milaGGL <107142260+milaGGL@users.noreply.github.com>
Date: Thu, 2 Feb 2023 16:54:52 -0800
Subject: [PATCH 22/27] get full path using databaseId
---
.../firebase/firestore/model/DatabaseId.java | 4 +++
.../firestore/remote/ExistenceFilter.java | 2 +-
.../firestore/remote/RemoteStore.java | 6 ++++
.../remote/WatchChangeAggregator.java | 34 ++++++++++++-------
.../firebase/firestore/spec/SpecTestCase.java | 15 ++++----
.../testutil/TestTargetMetadataProvider.java | 12 +++++++
.../firebase/firestore/testutil/TestUtil.java | 13 +++++++
7 files changed, 67 insertions(+), 19 deletions(-)
diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/model/DatabaseId.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/model/DatabaseId.java
index 24a057c5b0c..04f725e5a34 100644
--- a/firebase-firestore/src/main/java/com/google/firebase/firestore/model/DatabaseId.java
+++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/model/DatabaseId.java
@@ -60,6 +60,10 @@ public String getDatabaseId() {
return databaseId;
}
+ public String canonicalString() {
+ return "projects/" + projectId + "/databases/" + databaseId;
+ }
+
@Override
public String toString() {
return "DatabaseId(" + projectId + ", " + databaseId + ")";
diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/ExistenceFilter.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/ExistenceFilter.java
index 4d56b655620..9ff6a8f8c22 100644
--- a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/ExistenceFilter.java
+++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/ExistenceFilter.java
@@ -42,6 +42,6 @@ public BloomFilter getUnchangedNames() {
@Override
public String toString() {
- return "ExistenceFilter{count=" + count + "unchangedNames=" + unchangedNames + '}';
+ return "ExistenceFilter{count=" + count + ", unchangedNames=" + unchangedNames + '}';
}
}
diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteStore.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteStore.java
index 965ceee35da..1f5ad514b46 100644
--- a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteStore.java
+++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteStore.java
@@ -28,6 +28,7 @@
import com.google.firebase.firestore.local.LocalStore;
import com.google.firebase.firestore.local.QueryPurpose;
import com.google.firebase.firestore.local.TargetData;
+import com.google.firebase.firestore.model.DatabaseId;
import com.google.firebase.firestore.model.DocumentKey;
import com.google.firebase.firestore.model.SnapshotVersion;
import com.google.firebase.firestore.model.mutation.MutationBatch;
@@ -758,6 +759,11 @@ public TargetData getTargetDataForTarget(int targetId) {
return this.listenTargets.get(targetId);
}
+ @Override
+ public DatabaseId getDatabaseId() {
+ return this.datastore.getDatabaseInfo().getDatabaseId();
+ }
+
public Task runCountQuery(Query query) {
if (canUseNetwork()) {
return datastore.runCountQuery(query);
diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/WatchChangeAggregator.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/WatchChangeAggregator.java
index 51b3ebd46da..96601edcbb8 100644
--- a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/WatchChangeAggregator.java
+++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/WatchChangeAggregator.java
@@ -23,6 +23,7 @@
import com.google.firebase.firestore.core.Target;
import com.google.firebase.firestore.local.QueryPurpose;
import com.google.firebase.firestore.local.TargetData;
+import com.google.firebase.firestore.model.DatabaseId;
import com.google.firebase.firestore.model.DocumentKey;
import com.google.firebase.firestore.model.MutableDocument;
import com.google.firebase.firestore.model.SnapshotVersion;
@@ -57,6 +58,9 @@ public interface TargetMetadataProvider {
*/
@Nullable
TargetData getTargetDataForTarget(int targetId);
+
+ /** Returns the database ID of the Firestore instance. */
+ DatabaseId getDatabaseId();
}
private final TargetMetadataProvider targetMetadataProvider;
@@ -201,8 +205,7 @@ public void handleExistenceFilter(ExistenceFilterWatchChange watchChange) {
if (currentSize != expectedCount) {
// Apply bloom filter to identify and mark removed documents.
- boolean bloomFilterApplied =
- this.applyBloomFilter(watchChange.getExistenceFilter(), targetId, currentSize);
+ boolean bloomFilterApplied = this.applyBloomFilter(watchChange, currentSize);
if (!bloomFilterApplied) {
// If bloom filter application fails, we reset the mapping and
@@ -216,10 +219,10 @@ public void handleExistenceFilter(ExistenceFilterWatchChange watchChange) {
}
/** Returns whether a bloom filter removed the deleted documents successfully. */
- private boolean applyBloomFilter(
- ExistenceFilter existenceFilter, int targetId, int currentCount) {
- int expectedCount = existenceFilter.getCount();
- com.google.firestore.v1.BloomFilter unchangedNames = existenceFilter.getUnchangedNames();
+ private boolean applyBloomFilter(ExistenceFilterWatchChange watchChange, int currentCount) {
+ int expectedCount = watchChange.getExistenceFilter().getCount();
+ com.google.firestore.v1.BloomFilter unchangedNames =
+ watchChange.getExistenceFilter().getUnchangedNames();
if (unchangedNames == null || !unchangedNames.hasBits()) {
return false;
@@ -232,12 +235,17 @@ private boolean applyBloomFilter(
bloomFilter =
new BloomFilter(
bitmap, unchangedNames.getBits().getPadding(), unchangedNames.getHashCount());
- } catch (BloomFilterException e) {
- Logger.warn("Firestore", "BloomFilter error: %s", e);
+ } catch (Exception e) {
+ if (e instanceof BloomFilterException) {
+ Logger.warn("Firestore", "BloomFilter error: %s", e);
+
+ } else {
+ Logger.warn("Firestore", "Applying bloom filter failed: %s", e);
+ }
return false;
}
- int removedDocumentCount = this.filterRemovedDocuments(bloomFilter, targetId);
+ int removedDocumentCount = this.filterRemovedDocuments(bloomFilter, watchChange.getTargetId());
return expectedCount == (currentCount - removedDocumentCount);
}
@@ -251,9 +259,11 @@ private int filterRemovedDocuments(BloomFilter bloomFilter, int targetId) {
targetMetadataProvider.getRemoteKeysForTarget(targetId);
int removalCount = 0;
for (DocumentKey key : existingKeys) {
- if (!bloomFilter.mightContain(
- "projects/test-project/databases/(default)/documents/"
- + key.getPath().canonicalString())) {
+ String documentPath =
+ targetMetadataProvider.getDatabaseId().canonicalString()
+ + "/documents/"
+ + key.getPath().canonicalString();
+ if (!bloomFilter.mightContain(documentPath)) {
this.removeDocumentFromTarget(targetId, key, /*updatedDocument=*/ null);
removalCount++;
}
diff --git a/firebase-firestore/src/test/java/com/google/firebase/firestore/spec/SpecTestCase.java b/firebase-firestore/src/test/java/com/google/firebase/firestore/spec/SpecTestCase.java
index 0a22fb8aee7..795859ef5b5 100644
--- a/firebase-firestore/src/test/java/com/google/firebase/firestore/spec/SpecTestCase.java
+++ b/firebase-firestore/src/test/java/com/google/firebase/firestore/spec/SpecTestCase.java
@@ -681,15 +681,18 @@ private void doWatchEntity(JSONObject watchEntity) throws Exception {
}
private void doWatchFilter(JSONObject watchFilter) throws Exception {
- List targets = parseIntList(watchFilter.getJSONArray("targetIds"));
+ List targets =
+ watchFilter.has("targetIds")
+ ? parseIntList(watchFilter.getJSONArray("targetIds"))
+ : Collections.emptyList();
Assert.hardAssert(
targets.size() == 1, "ExistenceFilters currently support exactly one target only.");
- int keyCount = watchFilter.getJSONArray("keys").length();
- BloomFilter bloomFilterProto = null;
- if (watchFilter.has("bloomFilter")) {
- bloomFilterProto = parseBloomFilter(watchFilter.getJSONObject("bloomFilter"));
- }
+ int keyCount = watchFilter.has("keys") ? watchFilter.getJSONArray("keys").length() : 0;
+ BloomFilter bloomFilterProto =
+ watchFilter.has("bloomFilter")
+ ? parseBloomFilter(watchFilter.getJSONObject("bloomFilter"))
+ : null;
// TODO: extend this with different existence filters over time.
ExistenceFilter filter = new ExistenceFilter(keyCount, bloomFilterProto);
diff --git a/firebase-firestore/src/testUtil/java/com/google/firebase/firestore/testutil/TestTargetMetadataProvider.java b/firebase-firestore/src/testUtil/java/com/google/firebase/firestore/testutil/TestTargetMetadataProvider.java
index 71cb84b9de8..d12a29ad1bf 100644
--- a/firebase-firestore/src/testUtil/java/com/google/firebase/firestore/testutil/TestTargetMetadataProvider.java
+++ b/firebase-firestore/src/testUtil/java/com/google/firebase/firestore/testutil/TestTargetMetadataProvider.java
@@ -16,6 +16,7 @@
import com.google.firebase.database.collection.ImmutableSortedSet;
import com.google.firebase.firestore.local.TargetData;
+import com.google.firebase.firestore.model.DatabaseId;
import com.google.firebase.firestore.model.DocumentKey;
import com.google.firebase.firestore.remote.WatchChangeAggregator;
import java.util.HashMap;
@@ -29,6 +30,7 @@
public class TestTargetMetadataProvider implements WatchChangeAggregator.TargetMetadataProvider {
final Map> syncedKeys = new HashMap<>();
final Map queryData = new HashMap<>();
+ DatabaseId databaseId = null;
@Override
public ImmutableSortedSet getRemoteKeysForTarget(int targetId) {
@@ -41,9 +43,19 @@ public TargetData getTargetDataForTarget(int targetId) {
return queryData.get(targetId);
}
+ @Override
+ public DatabaseId getDatabaseId() {
+ return databaseId;
+ }
+
/** Sets or replaces the local state for the provided query data. */
public void setSyncedKeys(TargetData targetData, ImmutableSortedSet keys) {
this.queryData.put(targetData.getTargetId(), targetData);
this.syncedKeys.put(targetData.getTargetId(), keys);
}
+
+ /** Sets or replaces the databaseId */
+ public void setDatabaseId(DatabaseId databaseId) {
+ this.databaseId = databaseId;
+ }
}
diff --git a/firebase-firestore/src/testUtil/java/com/google/firebase/firestore/testutil/TestUtil.java b/firebase-firestore/src/testUtil/java/com/google/firebase/firestore/testutil/TestUtil.java
index 55f846f9270..b8baecfb2cc 100644
--- a/firebase-firestore/src/testUtil/java/com/google/firebase/firestore/testutil/TestUtil.java
+++ b/firebase-firestore/src/testUtil/java/com/google/firebase/firestore/testutil/TestUtil.java
@@ -439,6 +439,7 @@ public static RemoteEvent noChangeEvent(int targetId, int version, ByteString re
TargetData targetData = TestUtil.targetData(targetId, QueryPurpose.LISTEN, "foo/bar");
TestTargetMetadataProvider testTargetMetadataProvider = new TestTargetMetadataProvider();
testTargetMetadataProvider.setSyncedKeys(targetData, DocumentKey.emptyKeySet());
+ testTargetMetadataProvider.setDatabaseId(DatabaseId.forProject("test-project"));
WatchChangeAggregator aggregator = new WatchChangeAggregator(testTargetMetadataProvider);
@@ -459,6 +460,8 @@ public static RemoteEvent existenceFilterEvent(
TargetData targetData = TestUtil.targetData(targetId, QueryPurpose.LISTEN, "foo");
TestTargetMetadataProvider testTargetMetadataProvider = new TestTargetMetadataProvider();
testTargetMetadataProvider.setSyncedKeys(targetData, syncedKeys);
+ testTargetMetadataProvider.setDatabaseId(DatabaseId.forProject("test-project"));
+
ExistenceFilter existenceFilter = new ExistenceFilter(remoteCount);
WatchChangeAggregator aggregator = new WatchChangeAggregator(testTargetMetadataProvider);
@@ -488,6 +491,11 @@ public TargetData getTargetDataForTarget(int targetId) {
ResourcePath collectionPath = docs.get(0).getKey().getCollectionPath();
return targetData(targetId, QueryPurpose.LISTEN, collectionPath.toString());
}
+
+ @Override
+ public DatabaseId getDatabaseId() {
+ return DatabaseId.forProject("test-project");
+ }
});
SnapshotVersion version = SnapshotVersion.NONE;
@@ -535,6 +543,11 @@ public TargetData getTargetDataForTarget(int targetId) {
? targetData(targetId, QueryPurpose.LISTEN, doc.getKey().toString())
: null;
}
+
+ @Override
+ public DatabaseId getDatabaseId() {
+ return DatabaseId.forProject("test-project");
+ }
});
aggregator.handleDocumentChange(change);
return aggregator.createRemoteEvent(doc.getVersion());
From 9bebd98980bc40a55460df4d174366412ff1c7de Mon Sep 17 00:00:00 2001
From: milaGGL <107142260+milaGGL@users.noreply.github.com>
Date: Thu, 2 Feb 2023 17:07:30 -0800
Subject: [PATCH 23/27] remove unnecessary code
---
.../java/com/google/firebase/firestore/testutil/TestUtil.java | 3 ---
1 file changed, 3 deletions(-)
diff --git a/firebase-firestore/src/testUtil/java/com/google/firebase/firestore/testutil/TestUtil.java b/firebase-firestore/src/testUtil/java/com/google/firebase/firestore/testutil/TestUtil.java
index b8baecfb2cc..7427bc949a5 100644
--- a/firebase-firestore/src/testUtil/java/com/google/firebase/firestore/testutil/TestUtil.java
+++ b/firebase-firestore/src/testUtil/java/com/google/firebase/firestore/testutil/TestUtil.java
@@ -439,7 +439,6 @@ public static RemoteEvent noChangeEvent(int targetId, int version, ByteString re
TargetData targetData = TestUtil.targetData(targetId, QueryPurpose.LISTEN, "foo/bar");
TestTargetMetadataProvider testTargetMetadataProvider = new TestTargetMetadataProvider();
testTargetMetadataProvider.setSyncedKeys(targetData, DocumentKey.emptyKeySet());
- testTargetMetadataProvider.setDatabaseId(DatabaseId.forProject("test-project"));
WatchChangeAggregator aggregator = new WatchChangeAggregator(testTargetMetadataProvider);
@@ -460,8 +459,6 @@ public static RemoteEvent existenceFilterEvent(
TargetData targetData = TestUtil.targetData(targetId, QueryPurpose.LISTEN, "foo");
TestTargetMetadataProvider testTargetMetadataProvider = new TestTargetMetadataProvider();
testTargetMetadataProvider.setSyncedKeys(targetData, syncedKeys);
- testTargetMetadataProvider.setDatabaseId(DatabaseId.forProject("test-project"));
-
ExistenceFilter existenceFilter = new ExistenceFilter(remoteCount);
WatchChangeAggregator aggregator = new WatchChangeAggregator(testTargetMetadataProvider);
From 66bfff905088984faf977b0e3c6cae7db690e32f Mon Sep 17 00:00:00 2001
From: milaGGL <107142260+milaGGL@users.noreply.github.com>
Date: Fri, 3 Feb 2023 11:02:10 -0800
Subject: [PATCH 24/27] skip invalid_base64_bitmap spec test
---
.../firebase/firestore/spec/SpecTestCase.java | 10 ++--------
.../resources/json/existence_filter_spec_test.json | 2 ++
.../testutil/TestTargetMetadataProvider.java | 8 +-------
.../firebase/firestore/testutil/TestUtil.java | 13 +++++++------
4 files changed, 12 insertions(+), 21 deletions(-)
diff --git a/firebase-firestore/src/test/java/com/google/firebase/firestore/spec/SpecTestCase.java b/firebase-firestore/src/test/java/com/google/firebase/firestore/spec/SpecTestCase.java
index 795859ef5b5..e001e9dcdac 100644
--- a/firebase-firestore/src/test/java/com/google/firebase/firestore/spec/SpecTestCase.java
+++ b/firebase-firestore/src/test/java/com/google/firebase/firestore/spec/SpecTestCase.java
@@ -478,14 +478,8 @@ private BloomFilter parseBloomFilter(JSONObject obj) throws JSONException {
if (bits.has("padding")) {
bitSequence.setPadding(bits.getInt("padding"));
}
- if (bits.has("bitmap")) {
- try {
- bitSequence.setBitmap(
- ByteString.copyFrom(Base64.decode(bits.getString("bitmap"), Base64.DEFAULT)));
- } catch (Exception e) {
- bitSequence.setBitmap(ByteString.EMPTY);
- }
- }
+ bitSequence.setBitmap(
+ ByteString.copyFrom(Base64.decode(bits.getString("bitmap"), Base64.DEFAULT)));
BloomFilter.Builder bloomFilter = BloomFilter.newBuilder();
bloomFilter.setBits(bitSequence);
diff --git a/firebase-firestore/src/test/resources/json/existence_filter_spec_test.json b/firebase-firestore/src/test/resources/json/existence_filter_spec_test.json
index 04912cd923d..a66a08bce17 100644
--- a/firebase-firestore/src/test/resources/json/existence_filter_spec_test.json
+++ b/firebase-firestore/src/test/resources/json/existence_filter_spec_test.json
@@ -6413,6 +6413,8 @@
"describeName": "Existence Filters:",
"itName": "Full re-query is triggered when bloom filter bitmap is invalid",
"tags": [
+ "no-ios",
+ "no-android"
],
"config": {
"numClients": 1,
diff --git a/firebase-firestore/src/testUtil/java/com/google/firebase/firestore/testutil/TestTargetMetadataProvider.java b/firebase-firestore/src/testUtil/java/com/google/firebase/firestore/testutil/TestTargetMetadataProvider.java
index d12a29ad1bf..21394a90269 100644
--- a/firebase-firestore/src/testUtil/java/com/google/firebase/firestore/testutil/TestTargetMetadataProvider.java
+++ b/firebase-firestore/src/testUtil/java/com/google/firebase/firestore/testutil/TestTargetMetadataProvider.java
@@ -30,7 +30,6 @@
public class TestTargetMetadataProvider implements WatchChangeAggregator.TargetMetadataProvider {
final Map> syncedKeys = new HashMap<>();
final Map queryData = new HashMap<>();
- DatabaseId databaseId = null;
@Override
public ImmutableSortedSet getRemoteKeysForTarget(int targetId) {
@@ -45,7 +44,7 @@ public TargetData getTargetDataForTarget(int targetId) {
@Override
public DatabaseId getDatabaseId() {
- return databaseId;
+ return DatabaseId.forProject("test-project");
}
/** Sets or replaces the local state for the provided query data. */
@@ -53,9 +52,4 @@ public void setSyncedKeys(TargetData targetData, ImmutableSortedSet
this.queryData.put(targetData.getTargetId(), targetData);
this.syncedKeys.put(targetData.getTargetId(), keys);
}
-
- /** Sets or replaces the databaseId */
- public void setDatabaseId(DatabaseId databaseId) {
- this.databaseId = databaseId;
- }
}
diff --git a/firebase-firestore/src/testUtil/java/com/google/firebase/firestore/testutil/TestUtil.java b/firebase-firestore/src/testUtil/java/com/google/firebase/firestore/testutil/TestUtil.java
index 7427bc949a5..daf64c9b3e3 100644
--- a/firebase-firestore/src/testUtil/java/com/google/firebase/firestore/testutil/TestUtil.java
+++ b/firebase-firestore/src/testUtil/java/com/google/firebase/firestore/testutil/TestUtil.java
@@ -108,6 +108,8 @@ public class TestUtil {
public static final long ARBITRARY_SEQUENCE_NUMBER = 2;
+ private static final DatabaseId TEST_PROJECT = DatabaseId.forProject("project");
+
@SuppressWarnings("unchecked")
public static Map map(Object... entries) {
Map res = new LinkedHashMap<>();
@@ -140,8 +142,7 @@ public static FieldMask fieldMask(String... fields) {
public static final Map EMPTY_MAP = new HashMap<>();
public static Value wrap(Object value) {
- DatabaseId databaseId = DatabaseId.forProject("project");
- UserDataReader dataReader = new UserDataReader(databaseId);
+ UserDataReader dataReader = new UserDataReader(TEST_PROJECT);
// HACK: We use parseQueryValue() since it accepts scalars as well as arrays / objects, and
// our tests currently use wrap() pretty generically so we don't know the intent.
return dataReader.parseQueryValue(value);
@@ -491,7 +492,7 @@ public TargetData getTargetDataForTarget(int targetId) {
@Override
public DatabaseId getDatabaseId() {
- return DatabaseId.forProject("test-project");
+ return TEST_PROJECT;
}
});
@@ -543,7 +544,7 @@ public TargetData getTargetDataForTarget(int targetId) {
@Override
public DatabaseId getDatabaseId() {
- return DatabaseId.forProject("test-project");
+ return TEST_PROJECT;
}
});
aggregator.handleDocumentChange(change);
@@ -551,7 +552,7 @@ public DatabaseId getDatabaseId() {
}
public static SetMutation setMutation(String path, Map values) {
- UserDataReader dataReader = new UserDataReader(DatabaseId.forProject("project"));
+ UserDataReader dataReader = new UserDataReader(TEST_PROJECT);
ParsedSetData parsed = dataReader.parseSetData(values);
// The order of the transforms doesn't matter, but we sort them so tests can assume a particular
@@ -584,7 +585,7 @@ private static PatchMutation patchMutationHelper(
}
}
- UserDataReader dataReader = new UserDataReader(DatabaseId.forProject("project"));
+ UserDataReader dataReader = new UserDataReader(TEST_PROJECT);
ParsedUpdateData parsed = dataReader.parseUpdateData(values);
// `mergeMutation()` provides an update mask for the merged fields, whereas `patchMutation()`
From 44e03bf0d148b381dbc5420776f7586bdb88d2b7 Mon Sep 17 00:00:00 2001
From: milaGGL <107142260+milaGGL@users.noreply.github.com>
Date: Tue, 7 Feb 2023 16:38:11 -0800
Subject: [PATCH 25/27] resolve comments
---
.../firebase/firestore/model/DatabaseId.java | 4 -
.../firestore/remote/BloomFilter.java | 10 +-
.../remote/BloomFilterException.java | 2 +-
.../firestore/remote/ExistenceFilter.java | 2 +-
.../firestore/remote/RemoteSerializer.java | 1 -
.../remote/WatchChangeAggregator.java | 11 ++-
.../firestore/remote/BloomFilterTest.java | 13 ++-
.../firebase/firestore/spec/SpecTestCase.java | 91 ++++++++++++-------
8 files changed, 78 insertions(+), 56 deletions(-)
diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/model/DatabaseId.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/model/DatabaseId.java
index 04f725e5a34..24a057c5b0c 100644
--- a/firebase-firestore/src/main/java/com/google/firebase/firestore/model/DatabaseId.java
+++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/model/DatabaseId.java
@@ -60,10 +60,6 @@ public String getDatabaseId() {
return databaseId;
}
- public String canonicalString() {
- return "projects/" + projectId + "/databases/" + databaseId;
- }
-
@Override
public String toString() {
return "DatabaseId(" + projectId + ", " + databaseId + ")";
diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java
index d1903fac8d2..109b80d6e6f 100644
--- a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java
+++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java
@@ -122,8 +122,10 @@ private static long getLongLittleEndian(@NonNull byte[] bytes, int offset) {
*/
private int getBitIndex(long hash1, long hash2, int hashIndex) {
// Calculate hashed value h(i) = h1 + (i * h2).
- // Even though we are interpreting hash1 and hash2 as unsigned, the addition and multiplication
- // operators still perform the correct operation and give the desired overflow behavior.
+ // Even though we are interpreting hash1 and hash2 as unsigned, the addition and
+ // multiplication
+ // operators still perform the correct operation and give the desired overflow
+ // behavior.
long combinedHash = hash1 + (hash2 * hashIndex);
long modulo = unsignedRemainder(combinedHash, this.bitCount);
return (int) modulo;
@@ -132,8 +134,8 @@ private int getBitIndex(long hash1, long hash2, int hashIndex) {
/**
* Calculate modulo, where the dividend and divisor are treated as unsigned 64-bit longs.
*
- * The implementation is taken from Guava,
+ *
The implementation is taken from Guava,
* simplified to our needs.
*
*
diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilterException.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilterException.java
index 966707e511c..429b501ed47 100644
--- a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilterException.java
+++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilterException.java
@@ -16,7 +16,7 @@
import androidx.annotation.NonNull;
-public class BloomFilterException extends Exception {
+public class BloomFilterException extends RuntimeException {
public BloomFilterException(@NonNull String detailMessage) {
super(detailMessage);
}
diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/ExistenceFilter.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/ExistenceFilter.java
index 9ff6a8f8c22..06d2d5f924e 100644
--- a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/ExistenceFilter.java
+++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/ExistenceFilter.java
@@ -26,7 +26,7 @@ public ExistenceFilter(int count) {
this.count = count;
}
- public ExistenceFilter(int count, BloomFilter unchangedNames) {
+ public ExistenceFilter(int count, @Nullable BloomFilter unchangedNames) {
this.count = count;
this.unchangedNames = unchangedNames;
}
diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteSerializer.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteSerializer.java
index 7d83a008a1b..655842a73af 100644
--- a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteSerializer.java
+++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/RemoteSerializer.java
@@ -945,7 +945,6 @@ public WatchChange decodeWatchChange(ListenResponse protoChange) {
break;
case FILTER:
com.google.firestore.v1.ExistenceFilter protoFilter = protoChange.getFilter();
- // TODO: implement existence filter parsing (see b/33076578)
ExistenceFilter filter =
new ExistenceFilter(protoFilter.getCount(), protoFilter.getUnchangedNames());
int targetId = protoFilter.getTargetId();
diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/WatchChangeAggregator.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/WatchChangeAggregator.java
index 96601edcbb8..c2ab5bd31b1 100644
--- a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/WatchChangeAggregator.java
+++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/WatchChangeAggregator.java
@@ -235,12 +235,9 @@ private boolean applyBloomFilter(ExistenceFilterWatchChange watchChange, int cur
bloomFilter =
new BloomFilter(
bitmap, unchangedNames.getBits().getPadding(), unchangedNames.getHashCount());
- } catch (Exception e) {
+ } catch (BloomFilterException e) {
if (e instanceof BloomFilterException) {
Logger.warn("Firestore", "BloomFilter error: %s", e);
-
- } else {
- Logger.warn("Firestore", "Applying bloom filter failed: %s", e);
}
return false;
}
@@ -259,8 +256,12 @@ private int filterRemovedDocuments(BloomFilter bloomFilter, int targetId) {
targetMetadataProvider.getRemoteKeysForTarget(targetId);
int removalCount = 0;
for (DocumentKey key : existingKeys) {
+ DatabaseId databaseId = targetMetadataProvider.getDatabaseId();
String documentPath =
- targetMetadataProvider.getDatabaseId().canonicalString()
+ "projects/"
+ + databaseId.getProjectId()
+ + "/databases/"
+ + databaseId.getDatabaseId()
+ "/documents/"
+ key.getPath().canonicalString();
if (!bloomFilter.mightContain(documentPath)) {
diff --git a/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/BloomFilterTest.java b/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/BloomFilterTest.java
index b56538dde01..c2ba39c4d7f 100644
--- a/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/BloomFilterTest.java
+++ b/firebase-firestore/src/test/java/com/google/firebase/firestore/remote/BloomFilterTest.java
@@ -41,13 +41,13 @@ public class BloomFilterTest {
"src/test/resources/bloom_filter_golden_test_data/";
@Test
- public void instantiateEmptyBloomFilter() throws BloomFilterException {
+ public void instantiateEmptyBloomFilter() {
BloomFilter bloomFilter = new BloomFilter(new byte[0], 0, 0);
assertEquals(bloomFilter.getBitCount(), 0);
}
@Test
- public void instantiateNonEmptyBloomFilter() throws BloomFilterException {
+ public void instantiateNonEmptyBloomFilter() {
{
BloomFilter bloomFilter1 = new BloomFilter(new byte[] {1}, 0, 1);
assertEquals(bloomFilter1.getBitCount(), 8);
@@ -124,7 +124,7 @@ public void constructorShouldThrowBFEIfPaddingIsTooLarge() {
}
@Test
- public void mightContainCanProcessNonStandardCharacters() throws BloomFilterException {
+ public void mightContainCanProcessNonStandardCharacters() {
// A non-empty BloomFilter object with 1 insertion : "ÀÒ∑"
BloomFilter bloomFilter = new BloomFilter(new byte[] {(byte) 237, 5}, 5, 8);
assertTrue(bloomFilter.mightContain("ÀÒ∑"));
@@ -132,15 +132,14 @@ public void mightContainCanProcessNonStandardCharacters() throws BloomFilterExce
}
@Test
- public void mightContainOnEmptyBloomFilterShouldReturnFalse() throws BloomFilterException {
+ public void mightContainOnEmptyBloomFilterShouldReturnFalse() {
BloomFilter bloomFilter = new BloomFilter(new byte[0], 0, 0);
assertFalse(bloomFilter.mightContain(""));
assertFalse(bloomFilter.mightContain("a"));
}
@Test
- public void mightContainWithEmptyStringMightReturnFalsePositiveResult()
- throws BloomFilterException {
+ public void mightContainWithEmptyStringMightReturnFalsePositiveResult() {
{
BloomFilter bloomFilter1 = new BloomFilter(new byte[] {1}, 1, 1);
assertFalse(bloomFilter1.mightContain(""));
@@ -152,7 +151,7 @@ public void mightContainWithEmptyStringMightReturnFalsePositiveResult()
}
@Test
- public void bloomFilterToString() throws BloomFilterException {
+ public void bloomFilterToString() {
{
BloomFilter emptyBloomFilter = new BloomFilter(new byte[0], 0, 0);
assertEquals(emptyBloomFilter.toString(), "BloomFilter{hashCount=0, size=0, bitmap=\"\"}");
diff --git a/firebase-firestore/src/test/java/com/google/firebase/firestore/spec/SpecTestCase.java b/firebase-firestore/src/test/java/com/google/firebase/firestore/spec/SpecTestCase.java
index e001e9dcdac..e00f14d5466 100644
--- a/firebase-firestore/src/test/java/com/google/firebase/firestore/spec/SpecTestCase.java
+++ b/firebase-firestore/src/test/java/com/google/firebase/firestore/spec/SpecTestCase.java
@@ -143,18 +143,27 @@ public abstract class SpecTestCase implements RemoteStoreCallback {
// this tag and they'll all be run (but all others won't).
private static final String EXCLUSIVE_TAG = "exclusive";
- // The name of a Java system property ({@link System#getProperty(String)}) whose value is a filter
- // that specifies which tests to execute. The value of this property is a regular expression that
- // is matched against the name of each test. Using this property is an alternative to setting the
- // {@link #EXCLUSIVE_TAG} tag, which requires modifying the JSON file. To use this property,
- // specify -DspecTestFilter= to the Java runtime, replacing with a regular
- // expression; a test will be executed if and only if its name matches this regular expression.
- // In this context, a test's "name" is the result of appending its "itName" to its "describeName",
+ // The name of a Java system property ({@link System#getProperty(String)}) whose
+ // value is a filter
+ // that specifies which tests to execute. The value of this property is a
+ // regular expression that
+ // is matched against the name of each test. Using this property is an
+ // alternative to setting the
+ // {@link #EXCLUSIVE_TAG} tag, which requires modifying the JSON file. To use
+ // this property,
+ // specify -DspecTestFilter= to the Java runtime, replacing with
+ // a regular
+ // expression; a test will be executed if and only if its name matches this
+ // regular expression.
+ // In this context, a test's "name" is the result of appending its "itName" to
+ // its "describeName",
// separated by a space character.
private static final String TEST_FILTER_PROPERTY = "specTestFilter";
- // Tags on tests that should be excluded from execution, useful to allow the platforms to
- // temporarily diverge or for features that are designed to be platform specific (such as
+ // Tags on tests that should be excluded from execution, useful to allow the
+ // platforms to
+ // temporarily diverge or for features that are designed to be platform specific
+ // (such as
// 'multi-client').
private static final Set DISABLED_TAGS =
RUN_BENCHMARK_TESTS
@@ -233,7 +242,8 @@ public abstract class SpecTestCase implements RemoteStoreCallback {
public static void info(String line) {
if (DEBUG) {
- // Print log information out directly to cut down on logger-related cruft like the extra
+ // Print log information out directly to cut down on logger-related cruft like
+ // the extra
// line for the date and class method which are always SpecTestCase+info
System.err.println(line);
} else {
@@ -632,7 +642,8 @@ private void doWatchRemove(JSONObject watchRemoveSpec) throws Exception {
new WatchTargetChange(
WatchTargetChangeType.Removed, targetIds, WatchStream.EMPTY_RESUME_TOKEN, error);
writeWatchChange(change, SnapshotVersion.NONE);
- // Unlike web, the MockDatastore detects a watch removal with cause and will remove active
+ // Unlike web, the MockDatastore detects a watch removal with cause and will
+ // remove active
// targets
}
@@ -675,14 +686,12 @@ private void doWatchEntity(JSONObject watchEntity) throws Exception {
}
private void doWatchFilter(JSONObject watchFilter) throws Exception {
- List targets =
- watchFilter.has("targetIds")
- ? parseIntList(watchFilter.getJSONArray("targetIds"))
- : Collections.emptyList();
+ List targets = parseIntList(watchFilter.getJSONArray("targetIds"));
+
Assert.hardAssert(
targets.size() == 1, "ExistenceFilters currently support exactly one target only.");
- int keyCount = watchFilter.has("keys") ? watchFilter.getJSONArray("keys").length() : 0;
+ int keyCount = watchFilter.getJSONArray("keys").length();
BloomFilter bloomFilterProto =
watchFilter.has("bloomFilter")
? parseBloomFilter(watchFilter.getJSONObject("bloomFilter"))
@@ -701,7 +710,8 @@ private void doWatchReset(JSONArray targetIds) throws Exception {
}
private void doWatchSnapshot(JSONObject watchSnapshot) throws Exception {
- // The client will only respond to watchSnapshots if they are on a target change with an empty
+ // The client will only respond to watchSnapshots if they are on a target change
+ // with an empty
// set of target IDs.
List targets =
watchSnapshot.has("targetIds")
@@ -724,7 +734,8 @@ private void doWatchStreamClose(JSONObject spec) throws Exception {
Status status =
Status.fromCodeValue(error.getInt("code")).withDescription(error.getString("message"));
queue.runSync(() -> datastore.failWatchStream(status));
- // Unlike web, stream should re-open synchronously (if we have active listeners).
+ // Unlike web, stream should re-open synchronously (if we have active
+ // listeners).
if (!this.queryListeners.isEmpty()) {
assertTrue("Watch stream is open", datastore.isWatchStreamOpen());
}
@@ -740,7 +751,7 @@ private void doWriteAck(JSONObject writeAckSpec) throws Exception {
validateNextWriteSent(write.first);
MutationResult mutationResult =
- new MutationResult(version(version), /*transformResults=*/ Collections.emptyList());
+ new MutationResult(version(version), /* transformResults= */ Collections.emptyList());
queue.runSync(() -> datastore.ackWrite(version(version), singletonList(mutationResult)));
}
@@ -865,7 +876,8 @@ private void doStep(JSONObject step) throws Exception {
} else if (step.has("watchStreamClose")) {
doWatchStreamClose(step.getJSONObject("watchStreamClose"));
} else if (step.has("watchProto")) {
- // watchProto isn't yet used, and it's unclear how to create arbitrary protos from JSON.
+ // watchProto isn't yet used, and it's unclear how to create arbitrary protos
+ // from JSON.
throw Assert.fail("watchProto is not yet supported.");
} else if (step.has("writeAck")) {
doWriteAck(step.getJSONObject("writeAck"));
@@ -882,9 +894,12 @@ private void doStep(JSONObject step) throws Exception {
doDisableNetwork();
}
} else if (step.has("changeUser")) {
- // NOTE: JSONObject.getString("foo") where "foo" is mapped to null will return "null".
- // Explicitly testing for isNull here allows the null value to be preserved. This is important
- // because the unauthenticated user is represented as having a null uid as a value for
+ // NOTE: JSONObject.getString("foo") where "foo" is mapped to null will return
+ // "null".
+ // Explicitly testing for isNull here allows the null value to be preserved.
+ // This is important
+ // because the unauthenticated user is represented as having a null uid as a
+ // value for
// "changeUser".
String uid = step.isNull("changeUser") ? null : step.getString("changeUser");
doChangeUser(uid);
@@ -1027,8 +1042,10 @@ private void validateExpectedState(@Nullable JSONObject expectedState) throws JS
expectedActiveTargets.put(targetId, new ArrayList<>());
for (int i = 0; i < queryArrayJson.length(); i++) {
Query query = parseQuery(queryArrayJson.getJSONObject(i));
- // TODO: populate the purpose of the target once it's possible to encode that in the
- // spec tests. For now, hard-code that it's a listen despite the fact that it's not
+ // TODO: populate the purpose of the target once it's possible to encode that in
+ // the
+ // spec tests. For now, hard-code that it's a listen despite the fact that it's
+ // not
// always the right value.
TargetData targetData =
new TargetData(
@@ -1058,7 +1075,8 @@ private void validateExpectedState(@Nullable JSONObject expectedState) throws JS
// Always validate that the expected limbo docs match the actual limbo docs.
validateActiveLimboDocs();
validateEnqueuedLimboDocs();
- // Always validate that the expected active targets match the actual active targets.
+ // Always validate that the expected active targets match the actual active
+ // targets.
validateActiveTargets();
}
@@ -1097,7 +1115,8 @@ private void validateUserCallbacks(@Nullable JSONObject expected) throws JSONExc
}
private void validateActiveLimboDocs() {
- // Make a copy so it can modified while checking against the expected limbo docs.
+ // Make a copy so it can modified while checking against the expected limbo
+ // docs.
@SuppressWarnings("VisibleForTests")
Map actualLimboDocs =
new HashMap<>(syncEngine.getActiveLimboDocumentResolutions());
@@ -1174,7 +1193,8 @@ private void validateActiveTargets() {
TargetData expectedTarget = expectedQueries.get(0);
TargetData actualTarget = actualTargets.get(expected.getKey());
- // TODO: validate the purpose of the target once it's possible to encode that in the
+ // TODO: validate the purpose of the target once it's possible to encode that in
+ // the
// spec tests. For now, only validate properties that can be validated.
// assertEquals(expectedTarget, actualTarget);
assertEquals(expectedTarget.getTarget(), actualTarget.getTarget());
@@ -1233,10 +1253,14 @@ private void runSteps(JSONArray steps, JSONObject config) throws Exception {
} catch (Exception e) {
throw Assert.fail("Spec test failed with %s", e);
} finally {
- // Ensure that Persistence is torn down even if the test is failing due to a thrown exception
- // so that any open databases are closed. This is important when the LocalStore is backed by
- // SQLite because SQLite opens databases in exclusive mode. If tearDownForSpec were not called
- // after an exception then subsequent attempts to open the SQLite database will fail, making
+ // Ensure that Persistence is torn down even if the test is failing due to a
+ // thrown exception
+ // so that any open databases are closed. This is important when the LocalStore
+ // is backed by
+ // SQLite because SQLite opens databases in exclusive mode. If tearDownForSpec
+ // were not called
+ // after an exception then subsequent attempts to open the SQLite database will
+ // fail, making
// it harder to zero in on the spec tests as a culprit.
specTearDown();
}
@@ -1286,7 +1310,8 @@ public void testSpecTests() throws Exception {
String fileName = parsedSpecFile.first;
JSONObject fileJSON = parsedSpecFile.second;
- // Print the names of the files and tests regardless of whether verbose logging is enabled.
+ // Print the names of the files and tests regardless of whether verbose logging
+ // is enabled.
info("Spec test file: " + fileName);
// Iterate over the tests in the file and run them.
From f75e734bac9e863e1290a1a4c418093307b15880 Mon Sep 17 00:00:00 2001
From: milaGGL <107142260+milaGGL@users.noreply.github.com>
Date: Wed, 8 Feb 2023 10:56:46 -0800
Subject: [PATCH 26/27] remove noices introduced by wrong line wrapping on
comments
---
.../firestore/remote/BloomFilter.java | 6 +-
.../firebase/firestore/spec/SpecTestCase.java | 84 +++++++------------
2 files changed, 30 insertions(+), 60 deletions(-)
diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java
index 109b80d6e6f..080a5931c45 100644
--- a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java
+++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java
@@ -122,10 +122,8 @@ private static long getLongLittleEndian(@NonNull byte[] bytes, int offset) {
*/
private int getBitIndex(long hash1, long hash2, int hashIndex) {
// Calculate hashed value h(i) = h1 + (i * h2).
- // Even though we are interpreting hash1 and hash2 as unsigned, the addition and
- // multiplication
- // operators still perform the correct operation and give the desired overflow
- // behavior.
+ // Even though we are interpreting hash1 and hash2 as unsigned, the addition and multiplication
+ // operators still perform the correct operation and give the desired overflow behavior.
long combinedHash = hash1 + (hash2 * hashIndex);
long modulo = unsignedRemainder(combinedHash, this.bitCount);
return (int) modulo;
diff --git a/firebase-firestore/src/test/java/com/google/firebase/firestore/spec/SpecTestCase.java b/firebase-firestore/src/test/java/com/google/firebase/firestore/spec/SpecTestCase.java
index e00f14d5466..42f570711b1 100644
--- a/firebase-firestore/src/test/java/com/google/firebase/firestore/spec/SpecTestCase.java
+++ b/firebase-firestore/src/test/java/com/google/firebase/firestore/spec/SpecTestCase.java
@@ -143,27 +143,18 @@ public abstract class SpecTestCase implements RemoteStoreCallback {
// this tag and they'll all be run (but all others won't).
private static final String EXCLUSIVE_TAG = "exclusive";
- // The name of a Java system property ({@link System#getProperty(String)}) whose
- // value is a filter
- // that specifies which tests to execute. The value of this property is a
- // regular expression that
- // is matched against the name of each test. Using this property is an
- // alternative to setting the
- // {@link #EXCLUSIVE_TAG} tag, which requires modifying the JSON file. To use
- // this property,
- // specify -DspecTestFilter= to the Java runtime, replacing with
- // a regular
- // expression; a test will be executed if and only if its name matches this
- // regular expression.
- // In this context, a test's "name" is the result of appending its "itName" to
- // its "describeName",
+ // The name of a Java system property ({@link System#getProperty(String)}) whose value is a filter
+ // that specifies which tests to execute. The value of this property is a regular expression that
+ // is matched against the name of each test. Using this property is an alternative to setting the
+ // {@link #EXCLUSIVE_TAG} tag, which requires modifying the JSON file. To use this property,
+ // specify -DspecTestFilter= to the Java runtime, replacing with a regular
+ // expression; a test will be executed if and only if its name matches this regular expression.
+ // In this context, a test's "name" is the result of appending its "itName" to its "describeName",
// separated by a space character.
private static final String TEST_FILTER_PROPERTY = "specTestFilter";
- // Tags on tests that should be excluded from execution, useful to allow the
- // platforms to
- // temporarily diverge or for features that are designed to be platform specific
- // (such as
+ // Tags on tests that should be excluded from execution, useful to allow the platforms to
+ // temporarily diverge or for features that are designed to be platform specific (such as
// 'multi-client').
private static final Set DISABLED_TAGS =
RUN_BENCHMARK_TESTS
@@ -242,8 +233,7 @@ public abstract class SpecTestCase implements RemoteStoreCallback {
public static void info(String line) {
if (DEBUG) {
- // Print log information out directly to cut down on logger-related cruft like
- // the extra
+ // Print log information out directly to cut down on logger-related cruft like the extra
// line for the date and class method which are always SpecTestCase+info
System.err.println(line);
} else {
@@ -502,6 +492,7 @@ private BloomFilter parseBloomFilter(JSONObject obj) throws JSONException {
//
// Methods for doing the steps of the spec test.
//
+
private void doListen(JSONObject listenSpec) throws Exception {
int expectedId = listenSpec.getInt("targetId");
Query query = parseQuery(listenSpec.getJSONObject("query"));
@@ -642,8 +633,7 @@ private void doWatchRemove(JSONObject watchRemoveSpec) throws Exception {
new WatchTargetChange(
WatchTargetChangeType.Removed, targetIds, WatchStream.EMPTY_RESUME_TOKEN, error);
writeWatchChange(change, SnapshotVersion.NONE);
- // Unlike web, the MockDatastore detects a watch removal with cause and will
- // remove active
+ // Unlike web, the MockDatastore detects a watch removal with cause and will remove active
// targets
}
@@ -697,7 +687,6 @@ private void doWatchFilter(JSONObject watchFilter) throws Exception {
? parseBloomFilter(watchFilter.getJSONObject("bloomFilter"))
: null;
- // TODO: extend this with different existence filters over time.
ExistenceFilter filter = new ExistenceFilter(keyCount, bloomFilterProto);
ExistenceFilterWatchChange change = new ExistenceFilterWatchChange(targets.get(0), filter);
writeWatchChange(change, SnapshotVersion.NONE);
@@ -710,8 +699,7 @@ private void doWatchReset(JSONArray targetIds) throws Exception {
}
private void doWatchSnapshot(JSONObject watchSnapshot) throws Exception {
- // The client will only respond to watchSnapshots if they are on a target change
- // with an empty
+ // The client will only respond to watchSnapshots if they are on a target change with an empty
// set of target IDs.
List targets =
watchSnapshot.has("targetIds")
@@ -734,8 +722,7 @@ private void doWatchStreamClose(JSONObject spec) throws Exception {
Status status =
Status.fromCodeValue(error.getInt("code")).withDescription(error.getString("message"));
queue.runSync(() -> datastore.failWatchStream(status));
- // Unlike web, stream should re-open synchronously (if we have active
- // listeners).
+ // Unlike web, stream should re-open synchronously (if we have active listeners).
if (!this.queryListeners.isEmpty()) {
assertTrue("Watch stream is open", datastore.isWatchStreamOpen());
}
@@ -876,8 +863,7 @@ private void doStep(JSONObject step) throws Exception {
} else if (step.has("watchStreamClose")) {
doWatchStreamClose(step.getJSONObject("watchStreamClose"));
} else if (step.has("watchProto")) {
- // watchProto isn't yet used, and it's unclear how to create arbitrary protos
- // from JSON.
+ // watchProto isn't yet used, and it's unclear how to create arbitrary protos from JSON.
throw Assert.fail("watchProto is not yet supported.");
} else if (step.has("writeAck")) {
doWriteAck(step.getJSONObject("writeAck"));
@@ -894,12 +880,9 @@ private void doStep(JSONObject step) throws Exception {
doDisableNetwork();
}
} else if (step.has("changeUser")) {
- // NOTE: JSONObject.getString("foo") where "foo" is mapped to null will return
- // "null".
- // Explicitly testing for isNull here allows the null value to be preserved.
- // This is important
- // because the unauthenticated user is represented as having a null uid as a
- // value for
+ // NOTE: JSONObject.getString("foo") where "foo" is mapped to null will return "null".
+ // Explicitly testing for isNull here allows the null value to be preserved. This is important
+ // because the unauthenticated user is represented as having a null uid as a value for
// "changeUser".
String uid = step.isNull("changeUser") ? null : step.getString("changeUser");
doChangeUser(uid);
@@ -1042,10 +1025,8 @@ private void validateExpectedState(@Nullable JSONObject expectedState) throws JS
expectedActiveTargets.put(targetId, new ArrayList<>());
for (int i = 0; i < queryArrayJson.length(); i++) {
Query query = parseQuery(queryArrayJson.getJSONObject(i));
- // TODO: populate the purpose of the target once it's possible to encode that in
- // the
- // spec tests. For now, hard-code that it's a listen despite the fact that it's
- // not
+ // TODO: populate the purpose of the target once it's possible to encode that in the
+ // spec tests. For now, hard-code that it's a listen despite the fact that it's not
// always the right value.
TargetData targetData =
new TargetData(
@@ -1075,8 +1056,7 @@ private void validateExpectedState(@Nullable JSONObject expectedState) throws JS
// Always validate that the expected limbo docs match the actual limbo docs.
validateActiveLimboDocs();
validateEnqueuedLimboDocs();
- // Always validate that the expected active targets match the actual active
- // targets.
+ // Always validate that the expected active targets match the actual active targets.
validateActiveTargets();
}
@@ -1115,8 +1095,7 @@ private void validateUserCallbacks(@Nullable JSONObject expected) throws JSONExc
}
private void validateActiveLimboDocs() {
- // Make a copy so it can modified while checking against the expected limbo
- // docs.
+ // Make a copy so it can modified while checking against the expected limbo docs.
@SuppressWarnings("VisibleForTests")
Map actualLimboDocs =
new HashMap<>(syncEngine.getActiveLimboDocumentResolutions());
@@ -1193,8 +1172,7 @@ private void validateActiveTargets() {
TargetData expectedTarget = expectedQueries.get(0);
TargetData actualTarget = actualTargets.get(expected.getKey());
- // TODO: validate the purpose of the target once it's possible to encode that in
- // the
+ // TODO: validate the purpose of the target once it's possible to encode that in the
// spec tests. For now, only validate properties that can be validated.
// assertEquals(expectedTarget, actualTarget);
assertEquals(expectedTarget.getTarget(), actualTarget.getTarget());
@@ -1217,7 +1195,6 @@ private void validateActiveTargets() {
private void runSteps(JSONArray steps, JSONObject config) throws Exception {
try {
specSetUp(config);
-
for (int i = 0; i < steps.length(); ++i) {
JSONObject step = steps.getJSONObject(i);
@Nullable JSONArray expectedSnapshotEvents = step.optJSONArray("expectedSnapshotEvents");
@@ -1253,14 +1230,10 @@ private void runSteps(JSONArray steps, JSONObject config) throws Exception {
} catch (Exception e) {
throw Assert.fail("Spec test failed with %s", e);
} finally {
- // Ensure that Persistence is torn down even if the test is failing due to a
- // thrown exception
- // so that any open databases are closed. This is important when the LocalStore
- // is backed by
- // SQLite because SQLite opens databases in exclusive mode. If tearDownForSpec
- // were not called
- // after an exception then subsequent attempts to open the SQLite database will
- // fail, making
+ // Ensure that Persistence is torn down even if the test is failing due to a thrown exception
+ // so that any open databases are closed. This is important when the LocalStore is backed by
+ // SQLite because SQLite opens databases in exclusive mode. If tearDownForSpec were not called
+ // after an exception then subsequent attempts to open the SQLite database will fail, making
// it harder to zero in on the spec tests as a culprit.
specTearDown();
}
@@ -1310,8 +1283,7 @@ public void testSpecTests() throws Exception {
String fileName = parsedSpecFile.first;
JSONObject fileJSON = parsedSpecFile.second;
- // Print the names of the files and tests regardless of whether verbose logging
- // is enabled.
+ // Print the names of the files and tests regardless of whether verbose logging is enabled.
info("Spec test file: " + fileName);
// Iterate over the tests in the file and run them.
From 1f347784349d2ece1b0ce2792fa2bb8a2f8d210c Mon Sep 17 00:00:00 2001
From: milaGGL <107142260+milaGGL@users.noreply.github.com>
Date: Wed, 8 Feb 2023 19:03:53 -0800
Subject: [PATCH 27/27] resolve comments
---
.../google/firebase/firestore/remote/BloomFilter.java | 3 +--
.../firestore/remote/WatchChangeAggregator.java | 11 ++++++++---
2 files changed, 9 insertions(+), 5 deletions(-)
diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java
index 080a5931c45..e51a89906c7 100644
--- a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java
+++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/BloomFilter.java
@@ -27,8 +27,7 @@ public class BloomFilter {
private final int hashCount;
private final MessageDigest md5HashMessageDigest;
- public BloomFilter(@NonNull byte[] bitmap, int padding, int hashCount)
- throws BloomFilterException {
+ public BloomFilter(@NonNull byte[] bitmap, int padding, int hashCount) {
if (bitmap == null) {
throw new NullPointerException("Bitmap cannot be null.");
}
diff --git a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/WatchChangeAggregator.java b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/WatchChangeAggregator.java
index c2ab5bd31b1..435cbca9e24 100644
--- a/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/WatchChangeAggregator.java
+++ b/firebase-firestore/src/main/java/com/google/firebase/firestore/remote/WatchChangeAggregator.java
@@ -80,6 +80,9 @@ public interface TargetMetadataProvider {
*/
private Set pendingTargetResets = new HashSet<>();
+ /** The log tag to use for this class. */
+ private static final String LOG_TAG = "WatchChangeAggregator";
+
public WatchChangeAggregator(TargetMetadataProvider targetMetadataProvider) {
this.targetMetadataProvider = targetMetadataProvider;
}
@@ -236,9 +239,11 @@ private boolean applyBloomFilter(ExistenceFilterWatchChange watchChange, int cur
new BloomFilter(
bitmap, unchangedNames.getBits().getPadding(), unchangedNames.getHashCount());
} catch (BloomFilterException e) {
- if (e instanceof BloomFilterException) {
- Logger.warn("Firestore", "BloomFilter error: %s", e);
- }
+ Logger.warn(
+ LOG_TAG,
+ "Decoding the base64 bloom filter in existence filter failed ("
+ + e.getMessage()
+ + "); ignoring the bloom filter and falling back to full re-query.");
return false;
}