Repository: microsoft/qsharp
Pull request #1079 (2024-01-27 00:04:57)

Reverse Endianness
Based on feedback, we are reversing the endianness of ket displays from the QDK along with associated code. This includes reversing the display for state dumps from within Q#, in the debugger, and in Jupyter output. Included in this change is the revert of updates to kata content that tried to accomodate the different ordering between exercise text and the state display. The change also includes update to the new `dump_operation` in Python so that it is consistent with the endianness and outputs matrices that match the same conventions.

minestarks: @swernli Shouldn't we reverse the order of the formatted tables as well so they still go from 00001 => 11111? 
ScottCarda-MS: > @swernli Shouldn't we reverse the order of the formatted tables as well so they still go from 00001 => 11111?

![image](https://github.com/microsoft/qsharp/assets/55811729/1ec714db-0609-4e16-b066-c14b6768b6b7)
Yes I think that is what I'm seeing here as well.
swernli: > @swernli Shouldn't we reverse the order of the formatted tables as well so they still go from 00001 => 11111?

No, because that is the correct order for what those entries are. `|10⟩` is the first entry in the state vector, `|01⟩` is the second entry, etc.

If there were 4 qubits in equal superposition, it would go:
```|0000⟩
|1000⟩
|0100⟩
|1100⟩
|0010⟩
|1010⟩
|0110⟩
|1110⟩
|0001⟩
|1001⟩
|0101⟩
|1101⟩
|0011⟩
|1011⟩
|0111⟩
|1111⟩
```
github-actions[bot]: ## Benchmark for 9daf12d
  <details>
    <summary>Click to view benchmark</summary>

| Test | Base         | PR               | % |
|------|--------------|------------------|---|
| Array append evaluation | 878.1±14.74µs | 868.1±31.81µs | -1.14% |
| Array update evaluation | 953.9±4.27µs | **932.7±4.37µs** | **-2.22%** |
| Deutsch-Jozsa evaluation | 31.3±0.23ms | 31.5±1.62ms | +0.64% |
| Large file parity evaluation | 36.0±0.23ms | 35.9±0.11ms | -0.28% |
| Large input file | 38.8±2.21ms | **38.0±0.55ms** | **-2.06%** |
| Standard library | 21.3±0.59ms | **20.8±0.20ms** | **-2.35%** |
| Teleport evaluation | **103.9±1.98µs** | 106.1±1.97µs | **+2.12%** |

  </details>
  
tcNickolas: The order of the printed entries is the second part of our discussion today, do we interpret bit strings as integers using little endian (least significant bit first) or big endian (most significant bit first)? For the CNOT matrix to have the right ("textbook") shape, we need to use big endian, so it makes sense to have the same for ordering the entries. (|0000⟩ then |0001⟩ then |0010⟩ etc.)
ScottCarda-MS: > > @swernli Shouldn't we reverse the order of the formatted tables as well so they still go from 00001 => 11111?
> 
> No, because that is the correct order for what those entries are. `|10⟩` is the first entry in the state vector, `|01⟩` is the second entry, etc.
> 
> If there were 4 qubits in equal superposition, it would go:
> 
> ```
> |0000⟩
> |1000⟩
> |0100⟩
> |1100⟩
> |0010⟩
> |1010⟩
> |0110⟩
> |1110⟩
> |0001⟩
> |1001⟩
> |0101⟩
> |1101⟩
> |0011⟩
> |1011⟩
> |0111⟩
> |1111⟩
> ```

Is there something imposing a particular order other than what we want to display? Displaying the kets in that order seems confusing.
github-actions[bot]: ## Benchmark for 5b3dab7
  <details>
    <summary>Click to view benchmark</summary>

| Test | Base         | PR               | % |
|------|--------------|------------------|---|
| Array append evaluation | **859.5±7.82µs** | 878.6±24.81µs | **+2.22%** |
| Array update evaluation | **935.2±8.90µs** | 952.4±9.75µs | **+1.84%** |
| Deutsch-Jozsa evaluation | 31.3±0.26ms | 31.2±0.17ms | -0.32% |
| Large file parity evaluation | 35.9±0.10ms | 36.0±0.18ms | +0.28% |
| Large input file | 39.9±1.05ms | 39.3±0.86ms | -1.50% |
| Standard library | 21.6±0.44ms | 21.4±0.40ms | -0.93% |
| Teleport evaluation | **102.2±1.56µs** | 105.5±2.51µs | **+3.23%** |

  </details>
  
swernli: Given the feedback and sticking with the theme of trying to make things less confusing, I'll make sure the state display is sorted according to the display format rather than the original state vector ordering.
billti: > No, because that is the correct order for what those entries are. |10⟩ is the first entry in the state vector, |01⟩ is the second entry, etc.

Is this correct? If |01> is the tensor product of |0> and |1>, then it is [1, 0]T x [0, 1]T which is [0, 1, 0, 0]T. In other words, the kets should be ordered from |00>, |01>, |10>, |11> to map to the way state vectors are typically laid out horizontally, i.e. mapping to top-to-bottm entries of [1, 0, 0, 0]T, [0, 1, 0, 0]T, [0, 0, 1, 0]T, and [0, 0, 0, 1]T.

Patch:
diff --git a/compiler/qsc_eval/src/backend.rs b/compiler/qsc_eval/src/backend.rs
index 5deb5507..950021ec 100644
--- a/compiler/qsc_eval/src/backend.rs
+++ b/compiler/qsc_eval/src/backend.rs
@@ -189,7 +189,23 @@ impl Backend for SparseSim {
     }
 
     fn capture_quantum_state(&mut self) -> (Vec<(BigUint, Complex<f64>)>, usize) {
-        self.sim.get_state()
+        let (state, count) = self.sim.get_state();
+        // Because the simulator returns the state indices with opposite endianness from the
+        // expected one, we need to reverse the bit order of the indices.
+        let mut new_state = state
+            .into_iter()
+            .map(|(idx, val)| {
+                let mut new_idx = BigUint::default();
+                for i in 0..(count as u64) {
+                    if idx.bit((count as u64) - 1 - i) {
+                        new_idx.set_bit(i, true);
+                    }
+                }
+                (new_idx, val)
+            })
+            .collect::<Vec<_>>();
+        new_state.sort_unstable_by(|a, b| a.0.cmp(&b.0));
+        (new_state, count)
     }
 
     fn qubit_is_zero(&mut self, q: usize) -> bool {
diff --git a/katas/content/multi_qubit_systems/prepare_superposition/index.md b/katas/content/multi_qubit_systems/prepare_superposition/index.md
index a5d20b42..ac3f71b5 100644
--- a/katas/content/multi_qubit_systems/prepare_superposition/index.md
+++ b/katas/content/multi_qubit_systems/prepare_superposition/index.md
@@ -1,10 +1,8 @@
 **Input:** A two-qubit system in the basis state $|00\rangle = \begin{bmatrix} 1 \\ 0 \\ 0 \\ 0 \end{bmatrix}$.
 
-**Goal:** Transform the system into the state $\frac{1}{\sqrt2}\big(|00\rangle - |10\rangle\big) = \frac{1}{\sqrt2}\begin{bmatrix} 1 \\\ 0 \\\ -1 \\\ 0 \end{bmatrix}$.
-
-> Note that the quantum states are represented in little-endian format For a state $|qs_1 qs_0\rangle$, the "first" qubit (`qs[0]` in a Q# qubit register) refers to the least-significant qubit $qs_0$, while the "second" qubit (`qs[1]` in a Q# register) refers to the most-significant qubit $qs_1$.
+**Goal:** Transform the system into the state $\frac{1}{\sqrt2}\big(|00\rangle - |01\rangle\big) = \frac{1}{\sqrt2}\begin{bmatrix} 1 \\\ -1 \\\ 0 \\\ 0 \end{bmatrix}$.
 
 <details>
     <summary><b>Need a hint?</b></summary>
-    Represent the target state as a tensor product $\frac{1}{\sqrt2}\big(|0\rangle - |1\rangle\big) \otimes |0\rangle = \frac{1}{\sqrt2}\begin{bmatrix} 1 \\\ -1 \end{bmatrix} \otimes \begin{bmatrix} 1 \\\ 0 \end{bmatrix}$.
+    Represent the target state as a tensor product $|0\rangle \otimes \frac{1}{\sqrt2}\big(|0\rangle - |1\rangle\big) = \begin{bmatrix} 1 \\\ 0 \end{bmatrix} \otimes \frac{1}{\sqrt2}\begin{bmatrix} 1 \\\ -1 \end{bmatrix}$.
 </details>
diff --git a/katas/content/multi_qubit_systems/prepare_superposition/solution.md b/katas/content/multi_qubit_systems/prepare_superposition/solution.md
index 044ccfda..5179aaad 100644
--- a/katas/content/multi_qubit_systems/prepare_superposition/solution.md
+++ b/katas/content/multi_qubit_systems/prepare_superposition/solution.md
@@ -2,7 +2,7 @@
 $$ \begin{bmatrix} 1 \\\ 0 \\\ 0 \\\ 0 \end{bmatrix} = \begin{bmatrix} 1 \\\ 0 \end{bmatrix} \otimes \begin{bmatrix} 1 \\\ 0 \end{bmatrix} = |0\rangle \otimes |0\rangle$$
 
 The goal state can be separated as follows:
-$$ \frac{1}{\sqrt2} \begin{bmatrix} 1 \\\ 0 \\\ -1 \\\ 0 \end{bmatrix} = \frac{1}{\sqrt2}\begin{bmatrix} 1 \\\ -1 \end{bmatrix} \otimes \begin{bmatrix} 1 \\\ 0 \end{bmatrix} = \frac{1}{\sqrt2}\big(|0\rangle - |1\rangle\big) \otimes |0\rangle$$
+$$ \frac{1}{\sqrt2} \begin{bmatrix} 1 \\\ -1 \\\ 0 \\\ 0 \end{bmatrix} = \begin{bmatrix} 1 \\\ 0 \end{bmatrix} \otimes \frac{1}{\sqrt2}\begin{bmatrix} 1 \\\ -1 \end{bmatrix} = |0\rangle \otimes \frac{1}{\sqrt2}\big(|0\rangle - |1\rangle\big)$$
 
 This means that the first qubit is already in the state we want it to be, but the second qubit needs to be transformed from the $ \begin{bmatrix} 1 \\\ 0 \end{bmatrix} $ into $ \frac{1}{\sqrt{2}}\begin{bmatrix} 1 \\\ -1\end{bmatrix}$ state.
 
diff --git a/katas/content/multi_qubit_systems/prepare_with_complex/index.md b/katas/content/multi_qubit_systems/prepare_with_complex/index.md
index 25d268d7..ff5a0641 100644
--- a/katas/content/multi_qubit_systems/prepare_with_complex/index.md
+++ b/katas/content/multi_qubit_systems/prepare_with_complex/index.md
@@ -1,11 +1,9 @@
 
 **Input:** A two-qubit system in the basis state $|00\rangle = \begin{bmatrix} 1 \\ 0 \\ 0 \\ 0 \end{bmatrix}$.
 
-**Goal:** Transform the system into the state $\frac{1}{2}\big(|00\rangle + e^{i\pi/2}|01\rangle + e^{i\pi/4}|10\rangle + e^{3i\pi/4}|11\rangle\big) = \frac{1}{2}\begin{bmatrix} 1 \\ e^{i\pi/2} \\ e^{i\pi/4} \\ e^{3i\pi/4} \end{bmatrix}$.
-
-> Note that the quantum states are represented in little-endian format For a state $|qs_1 qs_0\rangle$, the "first" qubit (`qs[0]` in a Q# qubit register) refers to the least-significant qubit $qs_0$, while the "second" qubit (`qs[1]` in a Q# register) refers to the most-significant qubit $qs_1$.
+**Goal:** Transform the system into the state $\frac{1}{2}\big(|00\rangle + e^{i\pi/4}|01\rangle + e^{i\pi/2}|10\rangle + e^{3i\pi/4}|11\rangle\big) = \frac{1}{2}\begin{bmatrix} 1 \\ e^{i\pi/4} \\ e^{i\pi/2} \\ e^{3i\pi/4} \end{bmatrix}$.
 
 <details>
     <summary><b>Need a hint?</b></summary>
-    Represent the target state as a tensor product $\frac{1}{\sqrt2}\big(|0\rangle + e^{i\pi/4}|1\rangle\big) \otimes \frac{1}{\sqrt2}\big(|0\rangle + e^{i\pi/2}|1\rangle\big) = \frac{1}{\sqrt2}\begin{bmatrix} 1 \\\ e^{i\pi/4} \end{bmatrix} \otimes \frac{1}{\sqrt2} \begin{bmatrix} 1 \\\ e^{i\pi/2} \end{bmatrix}$.
+    Represent the target state as a tensor product $\frac{1}{\sqrt2}\big(|0\rangle + e^{i\pi/2}|1\rangle\big) \otimes \frac{1}{\sqrt2}\big(|0\rangle + e^{i\pi/4}|1\rangle\big) = \frac{1}{\sqrt2} \begin{bmatrix} 1 \\\ e^{i\pi/2} \end{bmatrix} \otimes \frac{1}{\sqrt2}\begin{bmatrix} 1 \\\ e^{i\pi/4} \end{bmatrix}$.
 </details>
diff --git a/katas/content/multi_qubit_systems/prepare_with_complex/solution.md b/katas/content/multi_qubit_systems/prepare_with_complex/solution.md
index 61383822..df9e0a33 100644
--- a/katas/content/multi_qubit_systems/prepare_with_complex/solution.md
+++ b/katas/content/multi_qubit_systems/prepare_with_complex/solution.md
@@ -4,9 +4,9 @@ $$ \begin{bmatrix} 1 \\\ 0 \\\ 0 \\\ 0 \end{bmatrix} = \begin{bmatrix} 1 \\\ 0 \
 The goal state, factored as a tensor product, looks like this (remember that $e^{3i\pi/4} = e^{i\pi/4} e^{i\pi/2}$):
 
 $$
-\frac{1}{2}\begin{bmatrix} 1 \\\ e^{i\pi/2} \\\ e^{i\pi/4} \\\ e^{3i\pi/4} \end{bmatrix} =
-\frac{1}{\sqrt2} \begin{bmatrix} 1 \\\ e^{i\pi/4} \end{bmatrix} \otimes \frac{1}{\sqrt2}\begin{bmatrix} 1 \\\ e^{i\pi/2} \end{bmatrix} =
-\frac{1}{\sqrt2}\big(|0\rangle + e^{i\pi/4}|1\rangle\big) \otimes \frac{1}{\sqrt2}\big(|0\rangle + e^{i\pi/2}|1\rangle\big) $$
+\frac{1}{2}\begin{bmatrix} 1 \\\ e^{i\pi/4} \\\ e^{i\pi/2} \\\ e^{3i\pi/4} \end{bmatrix} =
+\frac{1}{\sqrt2} \begin{bmatrix} 1 \\\ e^{i\pi/2} \end{bmatrix} \otimes \frac{1}{\sqrt2}\begin{bmatrix} 1 \\\ e^{i\pi/4} \end{bmatrix} =
+\frac{1}{\sqrt2}\big(|0\rangle + e^{i\pi/2}|1\rangle\big) \otimes \frac{1}{\sqrt2}\big(|0\rangle + e^{i\pi/4}|1\rangle\big) $$
 
 We will again need to adjust the states of both qubits independently.
 
diff --git a/katas/content/multi_qubit_systems/prepare_with_real/index.md b/katas/content/multi_qubit_systems/prepare_with_real/index.md
index d14bee4f..46f834f5 100644
--- a/katas/content/multi_qubit_systems/prepare_with_real/index.md
+++ b/katas/content/multi_qubit_systems/prepare_with_real/index.md
@@ -1,11 +1,9 @@
 
 **Input:** A two-qubit system in the basis state $|00\rangle = \begin{bmatrix} 1 \\\ 0 \\\ 0 \\\ 0 \end{bmatrix}$.
 
-**Goal:** Transform the system into the state $\frac{1}{2}\big(|00\rangle + |01\rangle - |10\rangle - |11\rangle\big) = \frac{1}{2}\begin{bmatrix} 1 \\\ 1 \\\ -1 \\\ -1 \end{bmatrix}$.
-
-> Note that the quantum states are represented in little-endian format For a state $|qs_1 qs_0\rangle$, the "first" qubit (`qs[0]` in a Q# qubit register) refers to the least-significant qubit $qs_0$, while the "second" qubit (`qs[1]` in a Q# register) refers to the most-significant qubit $qs_1$.
+**Goal:** Transform the system into the state $\frac{1}{2}\big(|00\rangle - |01\rangle + |10\rangle - |11\rangle\big) = \frac{1}{2}\begin{bmatrix} 1 \\\ -1 \\\ 1 \\\ -1 \end{bmatrix}$.
 
 <details>
     <summary><b>Need a hint?</b></summary>
-    Represent the target state as a tensor product $\frac{1}{\sqrt2}\big(|0\rangle - |1\rangle\big) \otimes \frac{1}{\sqrt2}\big(|0\rangle + |1\rangle\big) = \frac{1}{\sqrt2} \begin{bmatrix} 1 \\\ -1 \end{bmatrix} \otimes \frac{1}{\sqrt2}\begin{bmatrix} 1 \\\ 1 \end{bmatrix}$.
+    Represent the target state as a tensor product $\frac{1}{\sqrt2}\big(|0\rangle + |1\rangle\big) \otimes \frac{1}{\sqrt2}\big(|0\rangle - |1\rangle\big) = \frac{1}{\sqrt2} \begin{bmatrix} 1 \\\ 1 \end{bmatrix} \otimes \frac{1}{\sqrt2}\begin{bmatrix} 1 \\\ -1 \end{bmatrix}$.
 </details>
diff --git a/katas/content/multi_qubit_systems/prepare_with_real/solution.md b/katas/content/multi_qubit_systems/prepare_with_real/solution.md
index 9bf5b750..195c251c 100644
--- a/katas/content/multi_qubit_systems/prepare_with_real/solution.md
+++ b/katas/content/multi_qubit_systems/prepare_with_real/solution.md
@@ -1,6 +1,6 @@
 ﻿Again, to start we will represent the goal state as a tensor product of single-qubit states; this gives us the following representation:
 
-$$ \frac{1}{2}\big(|00\rangle + |01\rangle - |10\rangle - |11\rangle\big) = \frac{1}{2}\begin{bmatrix} 1 \\\ 1 \\\ -1 \\\ -1 \end{bmatrix} = \frac{1}{\sqrt2} \begin{bmatrix} 1 \\\ -1 \end{bmatrix} \otimes \frac{1}{\sqrt2}\begin{bmatrix} 1 \\\ 1 \end{bmatrix} = \frac{1}{\sqrt2}\big(|0\rangle - |1\rangle\big) \otimes \frac{1}{\sqrt2}\big(|0\rangle + |1\rangle\big)$$
+$$ \frac{1}{2}\big(|00\rangle - |01\rangle + |10\rangle - |11\rangle\big) = \frac{1}{2}\begin{bmatrix} 1 \\\ -1 \\\ 1 \\\ -1 \end{bmatrix} = \frac{1}{\sqrt2} \begin{bmatrix} 1 \\\ 1 \end{bmatrix} \otimes \frac{1}{\sqrt2}\begin{bmatrix} 1 \\\ -1 \end{bmatrix} = \frac{1}{\sqrt2}\big(|0\rangle + |1\rangle\big) \otimes \frac{1}{\sqrt2}\big(|0\rangle - |1\rangle\big)  $$
 
 This time we need to transform both the first and the second qubits. Let's start with the first qubit. Applying the **H** gate transforms its state as follows:
 
diff --git a/katas/content/qubit/index.md b/katas/content/qubit/index.md
index dc3ed917..a3d85e39 100644
--- a/katas/content/qubit/index.md
+++ b/katas/content/qubit/index.md
@@ -38,8 +38,6 @@ The state of a qubit is represented by a complex vector of size 2:
 $$\begin{bmatrix} \alpha \\\ \beta \end{bmatrix}$$
 
 Here $\alpha$ and $\beta$ are complex numbers. $\alpha$ represents how "close" the qubit is to state $0$, and $\beta$ represents how "close" the qubit is to state $1$. This vector is normalized: $|\alpha|^2 + |\beta|^2 = 1$.
-α and β are known as the probability amplitudes of states 0 and 1, respectively.
-
 $\alpha$ and $\beta$ are known as the probability amplitudes of states $0$ and $1$, respectively.
 
 ## Basis States
@@ -195,7 +193,7 @@ Note that each row has the following format:
 <table>
     <thead>
         <tr>
-            <th>Basis State<br>(|𝜓ₙ…𝜓₁⟩)</th>
+            <th>Basis State<br>(|𝜓₁…𝜓ₙ⟩)</th>
             <th>Amplitude</th>
             <th>Measurement Probability</th>
             <th>Phase</th>
diff --git a/npm/ux/estimatesOverview.tsx b/npm/ux/estimatesOverview.tsx
index 9938f724..5ef066bd 100644
--- a/npm/ux/estimatesOverview.tsx
+++ b/npm/ux/estimatesOverview.tsx
@@ -39,7 +39,7 @@ const columnNames = [
   "Physical qubits",
 ];
 
-const initialColumns = [0, 2, 3, 10, 11, 12];
+const initialColumns = [0, 10, 13, 11, 12];
 
 const xAxis: Axis = {
   isTime: true,
@@ -117,6 +117,58 @@ function reDataToRowScatter(data: ReData, color: string): ScatterSeries {
   };
 }
 
+function createRunNames(estimatesData: ReData[]): string[] {
+  const fields: string[][] = [];
+
+  estimatesData.forEach(() => {
+    fields.push([]);
+  });
+
+  // Could be multiple runs, e.g. against different algorithms.
+  addIfDifferent(fields, estimatesData, (data) => data.jobParams.sharedRunName);
+
+  addIfDifferent(
+    fields,
+    estimatesData,
+    (data) => data.jobParams.qubitParams.name,
+  );
+
+  addIfDifferent(
+    fields,
+    estimatesData,
+    (data) => data.jobParams.qecScheme.name,
+  );
+
+  addIfDifferent(fields, estimatesData, (data) =>
+    String(data.jobParams.errorBudget),
+  );
+
+  const proposedRunNames = fields.map((field) => field.join(", "));
+  if (new Set(proposedRunNames).size != proposedRunNames.length) {
+    // If there are duplicates, add the run index to the name.
+    return proposedRunNames.map(
+      (runName, index) => runName + " (" + index + ")",
+    );
+  }
+
+  return proposedRunNames;
+}
+
+function addIfDifferent(
+  fields: string[][],
+  estimatesData: ReData[],
+  fieldMethod: (data: ReData) => string,
+): void {
+  const arr = estimatesData.map(fieldMethod);
+
+  const set = new Set(arr);
+  if (set.size > 1) {
+    arr.forEach((field, index) => {
+      fields[index].push(field);
+    });
+  }
+}
+
 export function EstimatesOverview(props: {
   estimatesData: ReData[];
   colors: string[] | null;
@@ -127,18 +179,22 @@ export function EstimatesOverview(props: {
 }) {
   const [selectedRow, setSelectedRow] = useState<string | null>(null);
 
+  const runNameRenderingError =
+    props.runNames != null &&
+    props.runNames.length > 0 &&
+    props.runNames.length != props.estimatesData.length
+      ? "Warning: The number of runNames does not match the number of estimates. Ignoring provided runNames."
+      : "";
+
+  const runNames =
+    props.runNames != null &&
+    props.runNames.length == props.estimatesData.length
+      ? props.runNames
+      : createRunNames(props.estimatesData);
+
   props.estimatesData.forEach((item, idx) => {
-    if (
-      props.runNames != null &&
-      props.runNames.length == props.estimatesData.length
-    ) {
-      item.jobParams.runName = props.runNames[idx];
-    } else {
-      if (item.jobParams.runName == null) {
-        // Start indexing with 0 to match with the original object indexing.
-        item.jobParams.runName = `(${idx})`;
-      }
-    }
+    // Start indexing with 0 to match with the original object indexing.
+    item.jobParams.runName = runNames[idx];
   });
 
   function onPointSelected(seriesIndex: number, pointIndex: number): void {
@@ -148,12 +204,16 @@ export function EstimatesOverview(props: {
     setSelectedRow(rowId);
   }
 
-  function onRowSelected(rowId: string) {
+  function onRowSelected(rowId: string, ev?: Event) {
     setSelectedRow(rowId);
     // On any selection, clear the "new" flag on all rows. This ensures that
     // new rows do not steal focus from the user selected row.
     props.estimatesData.forEach((data) => (data.new = false));
-    HideTooltip();
+
+    const root = findRoot(ev);
+    if (root) {
+      HideTooltip(root);
+    }
     if (!rowId) {
       props.setEstimate(null);
     } else {
@@ -166,11 +226,28 @@ export function EstimatesOverview(props: {
       } else {
         const estimateFound = props.estimatesData[index];
         props.setEstimate(CreateSingleEstimateResult(estimateFound, 0));
-        SelectPoint(index, 0);
+        if (root) {
+          SelectPoint(index, 0, root);
+        }
       }
     }
   }
 
+  function findRoot(ev?: Event): Element | undefined {
+    return (
+      (ev?.currentTarget as Element | undefined)?.closest(
+        ".qs-estimatesOverview",
+      ) ?? undefined
+    );
+  }
+
+  const colorRenderingError =
+    props.colors != null &&
+    props.colors.length > 0 &&
+    props.colors.length != props.estimatesData.length
+      ? "Warning: The number of colors does not match the number of estimates. Ignoring provided colors."
+      : "";
+
   const colormap =
     props.colors != null && props.colors.length == props.estimatesData.length
       ? props.colors
@@ -178,17 +255,24 @@ export function EstimatesOverview(props: {
 
   if (props.isSimplifiedView) {
     return (
-      <>
+      <div className="qs-estimatesOverview">
+        {runNameRenderingError != "" && (
+          <div class="qs-estimatesOverview-error">{runNameRenderingError}</div>
+        )}
+        {colorRenderingError != "" && (
+          <div class="qs-estimatesOverview-error">{colorRenderingError}</div>
+        )}
         <ResultsTable
           columnNames={columnNames}
           rows={props.estimatesData.map((dataItem, index) =>
             reDataToRow(dataItem, colormap[index]),
           )}
           initialColumns={initialColumns}
-          ensureSelected={true}
+          // should be able to deselect rows for making screenshots
+          ensureSelected={false}
           onRowDeleted={props.onRowDeleted}
           selectedRow={selectedRow}
-          setSelectedRow={onRowSelected}
+          onRowSelected={onRowSelected}
         />
         <ScatterChart
           xAxis={xAxis}
@@ -198,12 +282,18 @@ export function EstimatesOverview(props: {
           )}
           onPointSelected={onPointSelected}
         />
-      </>
+      </div>
     );
   }
 
   return (
-    <>
+    <div className="qs-estimatesOverview">
+      {runNameRenderingError != "" && (
+        <div class="qs-estimatesOverview-error">{runNameRenderingError}</div>
+      )}
+      {colorRenderingError != "" && (
+        <div class="qs-estimatesOverview-error">{colorRenderingError}</div>
+      )}
       <details open>
         <summary style="font-size: 1.5em; font-weight: bold; margin: 24px 8px;">
           Results
@@ -215,8 +305,9 @@ export function EstimatesOverview(props: {
           )}
           initialColumns={initialColumns}
           selectedRow={selectedRow}
-          setSelectedRow={onRowSelected}
-          ensureSelected={true}
+          onRowSelected={onRowSelected}
+          // should be able to deselect rows for making screenshots
+          ensureSelected={false}
           onRowDeleted={props.onRowDeleted}
         />
       </details>
@@ -233,6 +324,6 @@ export function EstimatesOverview(props: {
           onPointSelected={onPointSelected}
         />
       </details>
-    </>
+    </div>
   );
 }
diff --git a/vscode/src/webview/rePage.tsx b/npm/ux/estimatesPanel.tsx
similarity index 89%
rename from vscode/src/webview/rePage.tsx
rename to npm/ux/estimatesPanel.tsx
index eeb65878..5ac0b98a 100644
--- a/vscode/src/webview/rePage.tsx
+++ b/npm/ux/estimatesPanel.tsx
@@ -2,16 +2,15 @@
 // Licensed under the MIT License.
 
 import { useState } from "preact/hooks";
-import {
-  SpaceChart,
-  ReTable,
-  type ReData,
-  EstimatesOverview,
-} from "qsharp-lang/ux";
-import { SingleEstimateResult } from "qsharp-lang/ux/data";
+import { type ReData, SingleEstimateResult } from "./data.js";
+import { EstimatesOverview } from "./estimatesOverview.js";
+import { ReTable } from "./reTable.js";
+import { SpaceChart } from "./spaceChart.js";
 
-export function RePage(props: {
+export function EstimatesPanel(props: {
   estimatesData: ReData[];
+  colors: string[];
+  runNames: string[];
   calculating: boolean;
   renderer: (input: string) => string;
   onRowDeleted: (rowId: string) => void;
@@ -71,8 +70,8 @@ export function RePage(props: {
         isSimplifiedView={false}
         onRowDeleted={props.onRowDeleted}
         setEstimate={setEstimate}
-        runNames={null}
-        colors={null}
+        runNames={props.runNames}
+        colors={props.colors}
       ></EstimatesOverview>
       {!estimate ? null : (
         <>
diff --git a/npm/ux/histogram.tsx b/npm/ux/histogram.tsx
index 29e0d201..f132d306 100644
--- a/npm/ux/histogram.tsx
+++ b/npm/ux/histogram.tsx
@@ -35,7 +35,6 @@ function resultToKet(result: string): string {
     // The result is a simple array of Zero and One
     // The below will return an array of "Zero" or "One" in the order found
     const matches = result.match(/(One|Zero)/g);
-    matches?.reverse();
     let ket = "|";
     matches?.forEach((digit) => (ket += digit == "One" ? "1" : "0"));
     ket += "⟩";
diff --git a/npm/ux/index.ts b/npm/ux/index.ts
index 6506ea2f..bfe96711 100644
--- a/npm/ux/index.ts
+++ b/npm/ux/index.ts
@@ -11,3 +11,4 @@ export { ReTable } from "./reTable.js";
 export { SpaceChart } from "./spaceChart.js";
 export { ScatterChart } from "./scatterChart.js";
 export { EstimatesOverview } from "./estimatesOverview.js";
+export { EstimatesPanel } from "./estimatesPanel.js";
diff --git a/npm/ux/qsharp-ux.css b/npm/ux/qsharp-ux.css
index 8ea7fd22..c54a144b 100644
--- a/npm/ux/qsharp-ux.css
+++ b/npm/ux/qsharp-ux.css
@@ -632,23 +632,56 @@ html {
   transform: rotate(180deg);
 }
 
-.qs-scatterChart-line {
-  stroke: var(--border-color);
-}
-
 .qs-scatterChart-point {
   r: 2px;
   stroke-width: 4px;
 }
 
-.qs-scatterChart-point-selected,
-.qs-scatterChart-point:hover {
+.qs-scatterChart-point-selected {
   r: 6px;
   stroke-width: 3px;
   fill: white;
 }
 
+.qs-scatterChart-point:hover {
+  r: 4px;
+  stroke-width: 4px;
+  fill: white;
+}
+
 .qs-scatterChart-watermark {
   font-size: 16px;
   fill: var(--main-color);
 }
+
+.qs-scatterChart-tooltip-text {
+  text-anchor: left;
+  fill: black;
+}
+
+.qs-scatterChart-tooltip-rect {
+  fill: white;
+  stroke: black;
+  stroke-width: 1px;
+  height: 22px;
+}
+
+.qs-scatterChart-line,
+.qs-scatterChart-axis,
+.qs-scatterChart-tick-line {
+  stroke: var(--border-color);
+}
+
+.qs-scatterChart-x-tick-text {
+  text-anchor: middle;
+  fill: var(--main-color);
+}
+
+.qs-scatterChart-y-tick-text {
+  text-anchor: end;
+  fill: var(--main-color);
+}
+
+.qs-estimatesOverview-error {
+  color: red;
+}
diff --git a/npm/ux/resultsTable.tsx b/npm/ux/resultsTable.tsx
index bab3d5f8..e42aab6f 100644
--- a/npm/ux/resultsTable.tsx
+++ b/npm/ux/resultsTable.tsx
@@ -17,7 +17,7 @@ export function ResultsTable(props: {
   ensureSelected: boolean;
   onRowDeleted(rowId: string): void;
   selectedRow: string | null; // type selected to confirm with the useState pattern on the parent component
-  setSelectedRow(rowId: string): void;
+  onRowSelected(rowId: string, ev?: Event): void;
 }) {
   const [showColumns, setShowColumns] = useState(props.initialColumns);
   const [sortColumn, setSortColumn] = useState<{
@@ -36,14 +36,14 @@ export function ResultsTable(props: {
   // Select the first of the newest rows, otherwise preserve the existing selection
   if (newest && props.ensureSelected) {
     const rowId = newest.cells[0].toString();
-    setSelectedRow(rowId);
+    onRowSelected(rowId, undefined);
   } else if (
     !props.selectedRow &&
     props.ensureSelected &&
     props.rows.length > 0
   ) {
     const rowId = props.rows[0].cells[0].toString();
-    setSelectedRow(rowId);
+    onRowSelected(rowId, undefined);
   }
 
   // Use to track the column being dragged
@@ -83,8 +83,8 @@ export function ResultsTable(props: {
     }
   }
 
-  function setSelectedRow(rowId: string) {
-    props.setSelectedRow(rowId);
+  function onRowSelected(rowId: string, ev?: Event) {
+    props.onRowSelected(rowId, ev);
   }
 
   function onDragOver(ev: DragEvent) {
@@ -200,11 +200,11 @@ export function ResultsTable(props: {
     }
   }
 
-  function rowClicked(rowId: string) {
+  function onRowClicked(rowId: string, ev: Event) {
     if (props.selectedRow === rowId && props.ensureSelected) return;
 
     const newSelectedRow = props.selectedRow === rowId ? "" : rowId;
-    setSelectedRow(newSelectedRow);
+    onRowSelected(newSelectedRow, ev);
   }
 
   function onClickRowMenu(ev: MouseEvent, rowid: string) {
@@ -254,7 +254,7 @@ export function ResultsTable(props: {
     // Clear out any menus or selections for the row if needed
     setShowRowMenu("");
     if (props.selectedRow === rowId) {
-      setSelectedRow("");
+      onRowSelected("", e);
     }
     props.onRowDeleted(rowId);
   }
@@ -354,7 +354,7 @@ export function ResultsTable(props: {
           const rowId = row.cells[0].toString();
           return (
             <tr
-              onClick={() => rowClicked(rowId)}
+              onClick={(e) => onRowClicked(rowId, e)}
               data-rowid={rowId}
               class={
                 rowId === props.selectedRow
diff --git a/npm/ux/scatterChart.tsx b/npm/ux/scatterChart.tsx
index 9de383e7..c576a4a3 100644
--- a/npm/ux/scatterChart.tsx
+++ b/npm/ux/scatterChart.tsx
@@ -2,6 +2,7 @@
 // Licensed under the MIT License.
 
 import { CreateIntegerTicks, CreateTimeTicks, Tick } from "../src/ux/ticks.js";
+import { useEffect, useRef } from "preact/hooks";
 
 export type ScatterSeries = {
   color: string;
@@ -24,14 +25,21 @@ type Range = {
   max: number;
 };
 
-export function HideTooltip() {
-  const tooltip = document.getElementById("tooltip");
-  if (tooltip) {
-    tooltip.setAttribute("visibility", "hidden");
-  }
+export function HideTooltip(root: Element) {
+  // could be called extenally with a root out of the chart.
+  const chart =
+    root.id == "scatterChart" ? root : root.querySelector("#scatterChart");
+
+  chart
+    ?.querySelector("#tooltip-selected")
+    ?.setAttribute("visibility", "hidden");
 }
 
-function drawTooltip(target: SVGCircleElement, clicked: boolean = false) {
+function drawTooltip(
+  target: SVGCircleElement,
+  root: Element,
+  clicked: boolean = false,
+) {
   const xAttr = target.getAttribute("cx");
   const x = xAttr ? parseInt(xAttr) : 0;
   const yAttr = target.getAttribute("cy");
@@ -40,10 +48,11 @@ function drawTooltip(target: SVGCircleElement, clicked: boolean = false) {
   const tooltipTextLeftPadding = 5;
   const tooltipRectanglePaddingHeight = 10;
   const tooltipTextPaddingHeight = 25;
-  const tooltip = document.getElementById("tooltip");
-  const tooltipRect = document.getElementById("tooltipRect");
-  const tooltipText = document.getElementById(
-    "tooltipText",
+  const tooltipId = clicked ? "#tooltip-selected" : "#tooltip-hover";
+  const tooltip = root.querySelector(tooltipId);
+  const tooltipRect = tooltip?.querySelector("#tooltipRect");
+  const tooltipText = tooltip?.querySelector(
+    "#tooltipText",
   ) as unknown as SVGTextElement;
 
   if (tooltipText) {
@@ -70,37 +79,34 @@ function drawTooltip(target: SVGCircleElement, clicked: boolean = false) {
   }
 }
 
-function hideTooltipIfNotClicked() {
-  const tooltip = document.getElementById("tooltip");
-  if (tooltip) {
-    if (tooltip.getAttribute("clicked") === "false") {
-      tooltip.setAttribute("visibility", "hidden");
+function deselectPoint(root: Element) {
+  if (root.getAttribute("selectedPoint")) {
+    const point = root.querySelector(
+      ("#" + root.getAttribute("selectedPoint")) as string,
+    );
+    if (point) {
+      point.classList.remove("qs-scatterChart-point-selected");
     }
   }
 }
 
-function deselectPoint() {
-  const chart = document.getElementById(`scatterChart`);
-  if (chart) {
-    if (chart.getAttribute("selectedPoint")) {
-      const point = document.getElementById(
-        chart.getAttribute("selectedPoint") as string,
-      );
-      if (point) {
-        point.classList.remove("qs-scatterChart-point-selected");
-      }
-    }
+export function SelectPoint(
+  seriesIndex: number,
+  pointIndex: number,
+  root: Element,
+) {
+  // could be called extenally with a root out of the chart.
+  const chart =
+    root.id == "scatterChart" ? root : root.querySelector("#scatterChart");
+  if (chart == null) {
+    return;
   }
-}
-
-export function SelectPoint(seriesIndex: number, pointIndex: number) {
-  deselectPoint();
-  const point = document.getElementById(`point-${seriesIndex}-${pointIndex}`);
-  const chart = document.getElementById(`scatterChart`);
-  if (point && chart) {
+  deselectPoint(chart);
+  const point = chart.querySelector(`#point-${seriesIndex}-${pointIndex}`);
+  if (point) {
     point.classList.add("qs-scatterChart-point-selected");
     chart.setAttribute("selectedPoint", point.id);
-    drawTooltip(point as unknown as SVGCircleElement, true);
+    drawTooltip(point as unknown as SVGCircleElement, root, true);
   }
 }
 
@@ -202,46 +208,91 @@ export function ScatterChart(props: {
   }`;
 
   const yAxisTextPaddingFromTicks = 5;
-  const yAxisTextYPadding = 6;
+  const yAxisTextYPadding = 4;
+
+  function trySetAttribute(element: Element, attribute: string, value: string) {
+    if (element.getAttribute(attribute) !== value) {
+      element.setAttribute(attribute, value);
+    }
+  }
+
+  function hideHoverTooltip() {
+    const tooltip = chart?.querySelector("#tooltip-hover");
+
+    if (tooltip) {
+      if (tooltip.getAttribute("clicked") === "false") {
+        tooltip.setAttribute("visibility", "hidden");
+      }
+    }
+  }
+
+  const scatterChartContainerRef = useRef<SVGSVGElement | null>(null);
+  let chart: Element | null = null;
+
+  function updateCoordinates() {
+    if (!chart) {
+      return;
+    }
+
+    chart.querySelectorAll("[x-data-value]").forEach((element) => {
+      const value = Number(element.getAttribute("x-data-value"));
+      const x = coordinateToSvgLogarithmic(value, rangeX, plotAreaWidth);
+      const padding = element.getAttribute("x-data-padding");
+      const value_with_padding = (x + Number(padding)).toString();
+      trySetAttribute(element, "x", value_with_padding);
+      trySetAttribute(element, "x1", value_with_padding);
+      trySetAttribute(element, "x2", value_with_padding);
+      trySetAttribute(element, "cx", value_with_padding);
+    });
+
+    chart.querySelectorAll("[y-data-value]").forEach((element) => {
+      const value = Number(element.getAttribute("y-data-value"));
+      const y = -coordinateToSvgLogarithmic(value, rangeY, plotAreaHeight);
+      const padding = element.getAttribute("y-data-padding");
+      const value_with_padding = (y + Number(padding)).toString();
+      trySetAttribute(element, "y", value_with_padding);
+      trySetAttribute(element, "y1", value_with_padding);
+      trySetAttribute(element, "y2", value_with_padding);
+      trySetAttribute(element, "cy", value_with_padding);
+    });
+  }
+
+  useEffect(() => {
+    chart = scatterChartContainerRef.current as Element | null;
+    updateCoordinates();
+  });
 
   return (
     <div style="display: flex; flex-wrap: wrap; margin-top: 8px;">
       <div class="chart-container">
         <svg
+          id="scatterChart"
+          ref={scatterChartContainerRef}
+          viewBox={viewBox}
           width={svgWidth}
           height={svgHeight}
-          viewBox={viewBox}
-          id="scatterChart"
         >
           <line
-            id="xAxis"
+            class="qs-scatterChart-axis"
             x1="0"
             y1="0"
             x2={plotAreaWidth}
             y2="0"
-            stroke="var(--border-color)"
           />
 
           {xTicks.map((tick) => {
-            const x = coordinateToSvgLogarithmic(
-              tick.value,
-              rangeX,
-              plotAreaWidth,
-            );
             return (
               <g>
                 <line
-                  x1={x}
                   y1="1"
-                  x2={x}
                   y2={axisTickLength}
-                  stroke="var(--border-color)"
+                  x-data-value={tick.value}
+                  class="qs-scatterChart-tick-line"
                 />
                 <text
-                  x={x}
                   y={axisTickLength + xAxisTickCaptionMaxHeight}
-                  text-anchor="middle"
-                  fill="var(--main-color)"
+                  x-data-value={tick.value}
+                  class="qs-scatterChart-x-tick-text"
                 >
                   {tick.label}
                 </text>
@@ -250,7 +301,7 @@ export function ScatterChart(props: {
           })}
 
           <line
-            id="yAxis"
+            class="qs-scatterChart-axis"
             x1="0"
             y1="0"
             x2="0"
@@ -259,25 +310,19 @@ export function ScatterChart(props: {
           />
 
           {yTicks.map((tick) => {
-            const y = -coordinateToSvgLogarithmic(
-              tick.value,
-              rangeY,
-              plotAreaHeight,
-            );
             return (
               <g>
                 <line
                   x1="0"
-                  y1={y}
                   x2={-axisTickLength}
-                  y2={y}
-                  stroke="var(--border-color)"
+                  y-data-value={tick.value}
+                  class="qs-scatterChart-tick-line"
                 />
                 <text
                   x={-axisTickLength - yAxisTextPaddingFromTicks}
-                  y={y + yAxisTextYPadding}
-                  text-anchor="end"
-                  fill="var(--main-color)"
+                  y-data-value={tick.value}
+                  class="qs-scatterChart-y-tick-text"
+                  y-data-padding={yAxisTextYPadding}
                 >
                   {tick.label}
                 </text>
@@ -308,59 +353,44 @@ export function ScatterChart(props: {
           >
             Created with Azure Quantum Resource Estimator
           </text>
-
-          {data.map((data, seriesIndex) => {
-            return data.items.map((item, pointIndex) => {
-              const x = coordinateToSvgLogarithmic(
-                item.x,
-                rangeX,
-                plotAreaWidth,
-              );
-
-              const y = -coordinateToSvgLogarithmic(
-                item.y,
-                rangeY,
-                plotAreaHeight,
-              );
-              return (
-                <circle
-                  id={`point-${seriesIndex}-${pointIndex}`}
-                  cx={x}
-                  cy={y}
-                  data-label={item.label}
-                  class="qs-scatterChart-point"
-                  stroke={data.color}
-                  onMouseOver={(e) => {
-                    drawTooltip(e.currentTarget, false);
-                    deselectPoint();
-                  }}
-                  onClick={() => {
-                    SelectPoint(seriesIndex, pointIndex);
-                    props.onPointSelected(seriesIndex, pointIndex);
-                  }}
-                  onMouseOut={() => hideTooltipIfNotClicked()}
-                />
-              );
-            });
-          })}
-          <g id="tooltip" visibility="hidden">
-            <rect
-              id="tooltipRect"
-              x="100"
-              y="-100"
-              width="200"
-              height="22"
-              fill="white"
-              stroke="black"
-              stroke-width="1"
-            />
-            <text
-              id="tooltipText"
-              x="105"
-              y="115"
-              text-anchor="left"
-              fill="black"
-            ></text>
+          <g>
+            {data.map((data, seriesIndex) => {
+              return data.items.map((item, pointIndex) => {
+                return (
+                  <circle
+                    id={`point-${seriesIndex}-${pointIndex}`}
+                    data-label={item.label}
+                    class="qs-scatterChart-point"
+                    x-data-value={item.x}
+                    y-data-value={item.y}
+                    stroke={data.color}
+                    onMouseOver={(e) => {
+                      const circle = e.currentTarget;
+
+                      if (chart) {
+                        drawTooltip(circle, chart, false);
+                      }
+                      circle?.parentNode?.appendChild(circle); // move the hovered cicrle up on the rendering stack
+                    }}
+                    onClick={() => {
+                      if (chart) {
+                        SelectPoint(seriesIndex, pointIndex, chart);
+                      }
+                      props.onPointSelected(seriesIndex, pointIndex);
+                    }}
+                    onMouseOut={() => hideHoverTooltip()}
+                  />
+                );
+              });
+            })}
+          </g>
+          <g id="tooltip-selected" visibility="hidden">
+            <rect id="tooltipRect" class="qs-scatterChart-tooltip-rect" />
+            <text id="tooltipText" class="qs-scatterChart-tooltip-text" />
+          </g>
+          <g id="tooltip-hover" visibility="hidden">
+            <rect id="tooltipRect" class="qs-scatterChart-tooltip-rect" />
+            <text id="tooltipText" class="qs-scatterChart-tooltip-text" />
           </g>
         </svg>
       </div>
diff --git a/pip/samples/project.ipynb b/pip/samples/project.ipynb
index aeca3e96..3890968c 100644
--- a/pip/samples/project.ipynb
+++ b/pip/samples/project.ipynb
@@ -15,7 +15,7 @@
       "outputs": [
         {
           "data": {
-            "application/javascript": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\n// This file provides CodeMirror syntax highlighting for Q# magic cells\n// in classic Jupyter Notebooks. It does nothing in other (Jupyter Notebook 7,\n// VS Code, Azure Notebooks, etc.) environments.\n\n// Detect the prerequisites and do nothing if they don't exist.\nif (window.require && window.CodeMirror && window.Jupyter) {\n  // The simple mode plugin for CodeMirror is not loaded by default, so require it.\n  window.require([\"codemirror/addon/mode/simple\"], function defineMode() {\n    let rules = [\n      {\n        token: \"comment\",\n        regex: /(\\/\\/).*/,\n        beginWord: false,\n      },\n      {\n        token: \"string\",\n        regex: String.raw`^\\\"(?:[^\\\"\\\\]|\\\\[\\s\\S])*(?:\\\"|$)`,\n        beginWord: false,\n      },\n      {\n        token: \"keyword\",\n        regex: String.raw`(namespace|open|as|operation|function|body|adjoint|newtype|controlled|internal)\\b`,\n        beginWord: true,\n      },\n      {\n        token: \"keyword\",\n        regex: String.raw`(if|elif|else|repeat|until|fixup|for|in|return|fail|within|apply)\\b`,\n        beginWord: true,\n      },\n      {\n        token: \"keyword\",\n        regex: String.raw`(Adjoint|Controlled|Adj|Ctl|is|self|auto|distribute|invert|intrinsic)\\b`,\n        beginWord: true,\n      },\n      {\n        token: \"keyword\",\n        regex: String.raw`(let|set|use|borrow|mutable)\\b`,\n        beginWord: true,\n      },\n      {\n        token: \"operatorKeyword\",\n        regex: String.raw`(not|and|or)\\b|(w/)`,\n        beginWord: true,\n      },\n      {\n        token: \"operatorKeyword\",\n        regex: String.raw`(=)|(!)|(<)|(>)|(\\\\+)|(-)|(\\\\*)|(\\\\/)|(\\\\^)|(%)|(\\\\|)|(\\\\&\\\\&\\\\&)|(\\\\~\\\\~\\\\~)|(\\\\.\\\\.\\\\.)|(\\\\.\\\\.)|(\\\\?)`,\n        beginWord: false,\n      },\n      {\n        token: \"meta\",\n        regex: String.raw`(Int|BigInt|Double|Bool|Qubit|Pauli|Result|Range|String|Unit)\\b`,\n        beginWord: true,\n      },\n      {\n        token: \"atom\",\n        regex: String.raw`(true|false|Pauli(I|X|Y|Z)|One|Zero)\\b`,\n        beginWord: true,\n      },\n    ];\n    let simpleRules = [];\n    for (let rule of rules) {\n      simpleRules.push({\n        token: rule.token,\n        regex: new RegExp(rule.regex, \"g\"),\n        sol: rule.beginWord,\n      });\n      if (rule.beginWord) {\n        // Need an additional rule due to the fact that CodeMirror simple mode doesn't work with ^ token\n        simpleRules.push({\n          token: rule.token,\n          regex: new RegExp(String.raw`\\W` + rule.regex, \"g\"),\n          sol: false,\n        });\n      }\n    }\n\n    // Register the mode defined above with CodeMirror\n    window.CodeMirror.defineSimpleMode(\"qsharp\", { start: simpleRules });\n    window.CodeMirror.defineMIME(\"text/x-qsharp\", \"qsharp\");\n\n    // Tell Jupyter to associate %%qsharp magic cells with the qsharp mode\n    window.Jupyter.CodeCell.options_default.highlight_modes[\"qsharp\"] = {\n      reg: [/^%%qsharp/],\n    };\n\n    // Force re-highlighting of all cells the first time this code runs\n    for (const cell of window.Jupyter.notebook.get_cells()) {\n      cell.auto_highlight();\n    }\n  });\n}\n",
+            "application/javascript": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\n// This file provides CodeMirror syntax highlighting for Q# magic cells\n// in classic Jupyter Notebooks. It does nothing in other (Jupyter Notebook 7,\n// VS Code, Azure Notebooks, etc.) environments.\n\n// Detect the prerequisites and do nothing if they don't exist.\nif (window.require && window.CodeMirror && window.Jupyter) {\n  // The simple mode plugin for CodeMirror is not loaded by default, so require it.\n  window.require([\"codemirror/addon/mode/simple\"], function defineMode() {\n    let rules = [\n      {\n        token: \"comment\",\n        regex: /(\\/\\/).*/,\n        beginWord: false,\n      },\n      {\n        token: \"string\",\n        regex: String.raw`^\\\"(?:[^\\\"\\\\]|\\\\[\\s\\S])*(?:\\\"|$)`,\n        beginWord: false,\n      },\n      {\n        token: \"keyword\",\n        regex: String.raw`(namespace|open|as|operation|function|body|adjoint|newtype|controlled|internal)\\b`,\n        beginWord: true,\n      },\n      {\n        token: \"keyword\",\n        regex: String.raw`(if|elif|else|repeat|until|fixup|for|in|return|fail|within|apply)\\b`,\n        beginWord: true,\n      },\n      {\n        token: \"keyword\",\n        regex: String.raw`(Adjoint|Controlled|Adj|Ctl|is|self|auto|distribute|invert|intrinsic)\\b`,\n        beginWord: true,\n      },\n      {\n        token: \"keyword\",\n        regex: String.raw`(let|set|use|borrow|mutable)\\b`,\n        beginWord: true,\n      },\n      {\n        token: \"operatorKeyword\",\n        regex: String.raw`(not|and|or)\\b|(w/)`,\n        beginWord: true,\n      },\n      {\n        token: \"operatorKeyword\",\n        regex: String.raw`(=)|(!)|(<)|(>)|(\\+)|(-)|(\\*)|(/)|(\\^)|(%)|(\\|)|(&&&)|(~~~)|(\\.\\.\\.)|(\\.\\.)|(\\?)`,\n        beginWord: false,\n      },\n      {\n        token: \"meta\",\n        regex: String.raw`(Int|BigInt|Double|Bool|Qubit|Pauli|Result|Range|String|Unit)\\b`,\n        beginWord: true,\n      },\n      {\n        token: \"atom\",\n        regex: String.raw`(true|false|Pauli(I|X|Y|Z)|One|Zero)\\b`,\n        beginWord: true,\n      },\n    ];\n    let simpleRules = [];\n    for (let rule of rules) {\n      simpleRules.push({\n        token: rule.token,\n        regex: new RegExp(rule.regex, \"g\"),\n        sol: rule.beginWord,\n      });\n      if (rule.beginWord) {\n        // Need an additional rule due to the fact that CodeMirror simple mode doesn't work with ^ token\n        simpleRules.push({\n          token: rule.token,\n          regex: new RegExp(String.raw`\\W` + rule.regex, \"g\"),\n          sol: false,\n        });\n      }\n    }\n\n    // Register the mode defined above with CodeMirror\n    window.CodeMirror.defineSimpleMode(\"qsharp\", { start: simpleRules });\n    window.CodeMirror.defineMIME(\"text/x-qsharp\", \"qsharp\");\n\n    // Tell Jupyter to associate %%qsharp magic cells with the qsharp mode\n    window.Jupyter.CodeCell.options_default.highlight_modes[\"qsharp\"] = {\n      reg: [/^%%qsharp/],\n    };\n\n    // Force re-highlighting of all cells the first time this code runs\n    for (const cell of window.Jupyter.notebook.get_cells()) {\n      cell.auto_highlight();\n    }\n  });\n}\n",
             "text/plain": []
           },
           "metadata": {},
@@ -62,7 +62,7 @@
               "<table>\n",
               "  <thead>\n",
               "    <tr>\n",
-              "      <th style=\"text-align: left\">Basis State<br />(|𝜓ₙ…𝜓₁⟩)</th>\n",
+              "      <th style=\"text-align: left\">Basis State<br />(|𝜓₁…𝜓ₙ⟩)</th>\n",
               "      <th style=\"text-align: left\">Amplitude</th>\n",
               "      <th style=\"text-align: left\">Measurement Probability</th>\n",
               "      <th style=\"text-align: left\" colspan=\"2\">Phase</th>\n",
@@ -143,7 +143,7 @@
       "name": "python",
       "nbconvert_exporter": "python",
       "pygments_lexer": "ipython3",
-      "version": "3.11.7"
+      "version": "3.11.6"
     }
   },
   "nbformat": 4,
diff --git a/pip/samples/sample.ipynb b/pip/samples/sample.ipynb
index b50152ac..afe2336e 100644
--- a/pip/samples/sample.ipynb
+++ b/pip/samples/sample.ipynb
@@ -10,6 +10,12 @@
         "This enables the `%%qsharp` magic and initializes a Q# interpreter singleton."
       ]
     },
+    {
+      "cell_type": "markdown",
+      "id": "ed1b75bf",
+      "metadata": {},
+      "source": []
+    },
     {
       "cell_type": "code",
       "execution_count": 1,
@@ -55,7 +61,7 @@
               "<table>\n",
               "  <thead>\n",
               "    <tr>\n",
-              "      <th style=\"text-align: left\">Basis State<br />(|𝜓ₙ…𝜓₁⟩)</th>\n",
+              "      <th style=\"text-align: left\">Basis State<br />(|𝜓₁…𝜓ₙ⟩)</th>\n",
               "      <th style=\"text-align: left\">Amplitude</th>\n",
               "      <th style=\"text-align: left\">Measurement Probability</th>\n",
               "      <th style=\"text-align: left\" colspan=\"2\">Phase</th>\n",
@@ -347,7 +353,7 @@
             "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
             "\u001b[0;31mQSharpError\u001b[0m                               Traceback (most recent call last)",
             "Cell \u001b[0;32mIn[7], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mqsharp\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43meval\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43moperation Foo() : Unit \u001b[39;49m\u001b[38;5;124;43m{\u001b[39;49m\u001b[38;5;124;43m use q = Qubit(); X(q) } Foo()\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\n",
-            "File \u001b[0;32m/workspaces/qsharp/pip/qsharp/_qsharp.py:120\u001b[0m, in \u001b[0;36meval\u001b[0;34m(source)\u001b[0m\n\u001b[1;32m    117\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mcallback\u001b[39m(output: Output) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[1;32m    118\u001b[0m     \u001b[38;5;28mprint\u001b[39m(output)\n\u001b[0;32m--> 120\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mget_interpreter\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43minterpret\u001b[49m\u001b[43m(\u001b[49m\u001b[43msource\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcallback\u001b[49m\u001b[43m)\u001b[49m\n",
+            "File \u001b[0;32m~/Programming/qsharp/pip/qsharp/_qsharp.py:120\u001b[0m, in \u001b[0;36meval\u001b[0;34m(source)\u001b[0m\n\u001b[1;32m    117\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mcallback\u001b[39m(output: Output) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[1;32m    118\u001b[0m     \u001b[38;5;28mprint\u001b[39m(output)\n\u001b[0;32m--> 120\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mget_interpreter\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43minterpret\u001b[49m\u001b[43m(\u001b[49m\u001b[43msource\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcallback\u001b[49m\u001b[43m)\u001b[49m\n",
             "\u001b[0;31mQSharpError\u001b[0m: Error: Qubit1 released while not in |0⟩ state\nCall stack:\n    at QIR.Runtime.__quantum__rt__qubit_release in core/qir.qs\n    at Foo in line_5\n\u001b[31mQsc.Eval.ReleasedQubitNotZero\u001b[0m\n\n  \u001b[31m×\u001b[0m runtime error\n\u001b[31m  ╰─▶ \u001b[0mQubit1 released while not in |0⟩ state\n   ╭─[\u001b[36;1;4mline_5\u001b[0m:1:1]\n \u001b[2m1\u001b[0m │ operation Foo() : Unit { use q = Qubit(); X(q) } Foo()\n   · \u001b[35;1m                         ────────┬───────\u001b[0m\n   ·                                  \u001b[35;1m╰── \u001b[35;1mQubit1\u001b[0m\u001b[0m\n   ╰────\n\u001b[36m  help: \u001b[0mqubits should be returned to the |0⟩ state before being released to\n        satisfy the assumption that allocated qubits start in the |0⟩ state\n"
           ]
         }
@@ -381,7 +387,7 @@
               "<table>\n",
               "  <thead>\n",
               "    <tr>\n",
-              "      <th style=\"text-align: left\">Basis State<br />(|𝜓ₙ…𝜓₁⟩)</th>\n",
+              "      <th style=\"text-align: left\">Basis State<br />(|𝜓₁…𝜓ₙ⟩)</th>\n",
               "      <th style=\"text-align: left\">Amplitude</th>\n",
               "      <th style=\"text-align: left\">Measurement Probability</th>\n",
               "      <th style=\"text-align: left\" colspan=\"2\">Phase</th>\n",
@@ -390,7 +396,7 @@
               "  <tbody>\n",
               "    <tr>\n",
               "  <td style=\"text-align: left\">\n",
-              "    <span style=\"display: inline-block\">|011⟩</span>\n",
+              "    <span style=\"display: inline-block\">|110⟩</span>\n",
               "  </td>\n",
               "  <td style=\"text-align: left\">\n",
               "    <span style=\"display: inline-block\">1.0000+0.0000𝑖</span>\n",
@@ -410,7 +416,7 @@
             ],
             "text/plain": [
               "STATE:\n",
-              "|011⟩: 1.0000+0.0000𝑖"
+              "|110⟩: 1.0000+0.0000𝑖"
             ]
           },
           "metadata": {},
@@ -489,7 +495,7 @@
               "<table>\n",
               "  <thead>\n",
               "    <tr>\n",
-              "      <th style=\"text-align: left\">Basis State<br />(|𝜓ₙ…𝜓₁⟩)</th>\n",
+              "      <th style=\"text-align: left\">Basis State<br />(|𝜓₁…𝜓ₙ⟩)</th>\n",
               "      <th style=\"text-align: left\">Amplitude</th>\n",
               "      <th style=\"text-align: left\">Measurement Probability</th>\n",
               "      <th style=\"text-align: left\" colspan=\"2\">Phase</th>\n",
@@ -542,7 +548,7 @@
               "<table>\n",
               "  <thead>\n",
               "    <tr>\n",
-              "      <th style=\"text-align: left\">Basis State<br />(|𝜓ₙ…𝜓₁⟩)</th>\n",
+              "      <th style=\"text-align: left\">Basis State<br />(|𝜓₁…𝜓ₙ⟩)</th>\n",
               "      <th style=\"text-align: left\">Amplitude</th>\n",
               "      <th style=\"text-align: left\">Measurement Probability</th>\n",
               "      <th style=\"text-align: left\" colspan=\"2\">Phase</th>\n",
@@ -595,7 +601,7 @@
               "<table>\n",
               "  <thead>\n",
               "    <tr>\n",
-              "      <th style=\"text-align: left\">Basis State<br />(|𝜓ₙ…𝜓₁⟩)</th>\n",
+              "      <th style=\"text-align: left\">Basis State<br />(|𝜓₁…𝜓ₙ⟩)</th>\n",
               "      <th style=\"text-align: left\">Amplitude</th>\n",
               "      <th style=\"text-align: left\">Measurement Probability</th>\n",
               "      <th style=\"text-align: left\" colspan=\"2\">Phase</th>\n",
@@ -648,7 +654,7 @@
               "<table>\n",
               "  <thead>\n",
               "    <tr>\n",
-              "      <th style=\"text-align: left\">Basis State<br />(|𝜓ₙ…𝜓₁⟩)</th>\n",
+              "      <th style=\"text-align: left\">Basis State<br />(|𝜓₁…𝜓ₙ⟩)</th>\n",
               "      <th style=\"text-align: left\">Amplitude</th>\n",
               "      <th style=\"text-align: left\">Measurement Probability</th>\n",
               "      <th style=\"text-align: left\" colspan=\"2\">Phase</th>\n",
@@ -701,7 +707,7 @@
               "<table>\n",
               "  <thead>\n",
               "    <tr>\n",
-              "      <th style=\"text-align: left\">Basis State<br />(|𝜓ₙ…𝜓₁⟩)</th>\n",
+              "      <th style=\"text-align: left\">Basis State<br />(|𝜓₁…𝜓ₙ⟩)</th>\n",
               "      <th style=\"text-align: left\">Amplitude</th>\n",
               "      <th style=\"text-align: left\">Measurement Probability</th>\n",
               "      <th style=\"text-align: left\" colspan=\"2\">Phase</th>\n",
@@ -810,7 +816,7 @@
         {
           "data": {
             "text/plain": [
-              "[One, One, Zero, One, Zero, One, One, Zero, One, Zero]"
+              "[One, Zero, Zero, Zero, Zero, Zero, Zero, One, Zero, Zero]"
             ]
           },
           "execution_count": 11,
@@ -837,7 +843,26 @@
       "execution_count": null,
       "id": "7bd77379",
       "metadata": {},
-      "outputs": [],
+      "outputs": [
+        {
+          "name": "stdout",
+          "output_type": "stream",
+          "text": [
+            "Requirement already satisfied: matplotlib in /opt/homebrew/lib/python3.11/site-packages (3.8.2)\n",
+            "Requirement already satisfied: contourpy>=1.0.1 in /opt/homebrew/lib/python3.11/site-packages (from matplotlib) (1.2.0)\n",
+            "Requirement already satisfied: cycler>=0.10 in /opt/homebrew/lib/python3.11/site-packages (from matplotlib) (0.12.1)\n",
+            "Requirement already satisfied: fonttools>=4.22.0 in /opt/homebrew/lib/python3.11/site-packages (from matplotlib) (4.46.0)\n",
+            "Requirement already satisfied: kiwisolver>=1.3.1 in /opt/homebrew/lib/python3.11/site-packages (from matplotlib) (1.4.5)\n",
+            "Requirement already satisfied: numpy<2,>=1.21 in /opt/homebrew/lib/python3.11/site-packages (from matplotlib) (1.23.5)\n",
+            "Requirement already satisfied: packaging>=20.0 in /Users/swernli/Library/Python/3.11/lib/python/site-packages (from matplotlib) (23.2)\n",
+            "Requirement already satisfied: pillow>=8 in /opt/homebrew/lib/python3.11/site-packages (from matplotlib) (10.1.0)\n",
+            "Requirement already satisfied: pyparsing>=2.3.1 in /opt/homebrew/lib/python3.11/site-packages (from matplotlib) (3.1.1)\n",
+            "Requirement already satisfied: python-dateutil>=2.7 in /Users/swernli/Library/Python/3.11/lib/python/site-packages (from matplotlib) (2.8.2)\n",
+            "Requirement already satisfied: six>=1.5 in /opt/homebrew/lib/python3.11/site-packages (from python-dateutil>=2.7->matplotlib) (1.16.0)\n",
+            "Note: you may need to restart the kernel to use updated packages.\n"
+          ]
+        }
+      ],
       "source": [
         "%pip install matplotlib\n"
       ]
@@ -850,7 +875,7 @@
       "outputs": [
         {
           "data": {
-            "image/png": "iVBORw0KGgoAAAANSUhEUgAAAhYAAAGdCAYAAABO2DpVAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8g+/7EAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAWKElEQVR4nO3de4xUhdn48Wd1uyPK7iIIArKA1htesApoKG0Fq1KqBm2ijcFKkLRR1gsSkwptao3VxaSvsU3teomtTaNCGkNtqkLVFDAIFbAabZUKal0vgIruAm8cLTu/P5ru790iyMAzwODnk5yEOXPOnGcSZvebM2dnakqlUikAABLst6cHAAD2HcICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEhTu7sP2NnZGW+//XbU19dHTU3N7j48ALATSqVSbNy4MQYOHBj77bft8xK7PSzefvvtaGpq2t2HBQAStLW1xaBBg7Z5/24Pi/r6+oj492ANDQ27+/AAwE7o6OiIpqamrt/j27Lbw+I/b380NDQICwCoMp91GYOLNwGANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEhTdli89dZbcckll0SfPn2iR48eceKJJ8aKFSsqMRsAUGXK+q6QDz74IMaMGRPjxo2Lxx57LPr27RuvvPJKHHzwwZWaDwCoImWFxa233hpNTU3x61//umvd4Ycfnj4UAFCdynor5A9/+EOMHDkyLrzwwujXr1+cfPLJcc8992x3n2KxGB0dHd0WAGDfVNYZi1dffTVaW1tjxowZMWvWrFi+fHlcffXVUVdXF5MnT/7UfVpaWuLGG29MGRYgImLo9Y/s6RFgr/X67HP26PFrSqVSaUc3rquri5EjR8bTTz/dte7qq6+O5cuXx9KlSz91n2KxGMViset2R0dHNDU1RXt7ezQ0NOzC6MDnlbCAbatUWHR0dERjY+Nn/v4u662QAQMGxHHHHddt3bBhw+KNN97Y5j6FQiEaGhq6LQDAvqmssBgzZkysWrWq27p//OMfMWTIkNShAIDqVFZYXHvttbFs2bK45ZZbYvXq1fHAAw/E3XffHc3NzZWaDwCoImWFxahRo2LevHnx4IMPxgknnBA33XRT3H777TFp0qRKzQcAVJGy/iokIuLcc8+Nc889txKzAABVzneFAABphAUAkEZYAABphAUAkEZYAABphAUAkEZYAABphAUAkEZYAABphAUAkEZYAABphAUAkEZYAABphAUAkEZYAABphAUAkEZYAABphAUAkEZYAABphAUAkEZYAABphAUAkEZYAABphAUAkEZYAABphAUAkEZYAABphAUAkEZYAABphAUAkEZYAABphAUAkEZYAABphAUAkEZYAABphAUAkEZYAABphAUAkEZYAABphAUAkEZYAABphAUAkEZYAABphAUAkEZYAABphAUAkEZYAABphAUAkKassPjxj38cNTU13ZZjjz22UrMBAFWmttwdjj/++HjiiSf+/wPUlv0QAMA+quwqqK2tjf79+1diFgCgypV9jcUrr7wSAwcOjCOOOCImTZoUb7zxxna3LxaL0dHR0W0BAPZNZYXFaaedFvfdd1/Mnz8/Wltb47XXXouvfvWrsXHjxm3u09LSEo2NjV1LU1PTLg8NAOydakqlUmlnd/7www9jyJAhcdttt8XUqVM/dZtisRjFYrHrdkdHRzQ1NUV7e3s0NDTs7KGBz7Gh1z+yp0eAvdbrs8+pyON2dHREY2PjZ/7+3qUrL3v16hVHH310rF69epvbFAqFKBQKu3IYAKBK7NLnWGzatCnWrFkTAwYMyJoHAKhiZYXFddddF4sWLYrXX389nn766bjgggti//33j4svvrhS8wEAVaSst0LefPPNuPjii+P999+Pvn37xle+8pVYtmxZ9O3bt1LzAQBVpKywmDNnTqXmAAD2Ab4rBABIIywAgDTCAgBIIywAgDTCAgBIIywAgDTCAgBIIywAgDTCAgBIIywAgDTCAgBIIywAgDTCAgBIIywAgDTCAgBIIywAgDTCAgBIIywAgDTCAgBIIywAgDTCAgBIIywAgDTCAgBIIywAgDTCAgBIIywAgDTCAgBIIywAgDTCAgBIIywAgDTCAgBIIywAgDTCAgBIIywAgDTCAgBIIywAgDTCAgBIIywAgDTCAgBIIywAgDTCAgBIIywAgDTCAgBIIywAgDTCAgBIIywAgDTCAgBIs0thMXv27KipqYnp06cnjQMAVLOdDovly5fHXXfdFcOHD8+cBwCoYjsVFps2bYpJkybFPffcEwcffHD2TABAldqpsGhubo5zzjknzjzzzOx5AIAqVlvuDnPmzIlnn302li9fvkPbF4vFKBaLXbc7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yvkcCwAgjbAAANIICwAgjbAAANIICwAgjbAAANIICwAgjbAAANIICwAgjbAAANIICwAgjbAAANIICwAgjbAAANIICwAgjbAAANIICwAgjbAAANIICwAgjbAAANIICwAgjbAAANIICwAgjbAAANIICwAgjbAAANIICwAgjbAAANIICwAgjbAAANIICwAgjbAAANIICwAgjbAAANIICwAgjbAAANIICwAgjbAAANIICwAgjbAAANIICwAgjbAAANIICwAgjbAAANIICwAgjbAAANIICwAgjbAAANLsVFjccccdMXTo0DjggAPitNNOi2eeeSZ7LgCgCpUdFnPnzo0ZM2bEDTfcEM8++2ycdNJJMX78+Fi/fn0l5gMAqkjZYXHbbbfFd7/73ZgyZUocd9xxceedd8aBBx4Yv/rVryoxHwBQRWrL2fjjjz+OlStXxsyZM7vW7bfffnHmmWfG0qVLP3WfYrEYxWKx63Z7e3tERHR0dOzMvNvVWfzf9MeEfUklXnd7gtc6bFulXuf/edxSqbTd7coKi/feey+2bNkShx56aLf1hx56aLz88sufuk9LS0vceOONW61vamoq59BAgsbb9/QEQKVV+nW+cePGaGxs3Ob9ZYXFzpg5c2bMmDGj63ZnZ2ds2LAh+vTpEzU1NZU+PHtIR0dHNDU1RVtbWzQ0NOzpcYAK8Vr//CiVSrFx48YYOHDgdrcrKywOOeSQ2H///WPdunXd1q9bty769+//qfsUCoUoFArd1vXq1aucw1LFGhoa/LCBzwGv9c+H7Z2p+I+yLt6sq6uLESNGxJNPPtm1rrOzM5588skYPXp0+RMCAPuUst8KmTFjRkyePDlGjhwZp556atx+++2xefPmmDJlSiXmAwCqSNlh8e1vfzvefffd+NGPfhRr166NL33pSzF//vytLujk861QKMQNN9yw1dtgwL7Fa53/VlP6rL8bAQDYQb4rBABIIywAgDTCAgBIIywAgDTCgu1auHBh1NTUbHMZN27cnh4RqIC2tra47LLLYuDAgVFXVxdDhgyJa665Jt5///09PRp7OWHBdn35y1+Od955Z6vlrrvuipqampg2bdpOPe7HH3+cPCmQ5dVXX42RI0fGK6+8Eg8++GCsXr067rzzzq4PQ9ywYcOeHpG9mLBgu+rq6qJ///7dlg8++CCuu+66mDVrVlx44YUREfHiiy/GhAkTomfPnnHooYfGd77znXjvvfe6Hmfs2LFx5ZVXxvTp0+OQQw6J8ePHR0TEokWL4tRTT41CoRADBgyI66+/Pv71r3/tkecK/Ftzc3PU1dXFn/70pzj99NNj8ODBMWHChHjiiSfirbfeih/84AcRETF06NC45ZZb4rLLLov6+voYPHhw3H333d0eq62tLS666KLo1atX9O7dOyZOnBivv/76HnhW7C7CgrJ8+OGHMXHixBg7dmzcdNNNXevOOOOMOPnkk2PFihUxf/78WLduXVx00UXd9v3Nb34TdXV1sWTJkrjzzjvjrbfeim9+85sxatSoeP7556O1tTXuvffe+MlPfrInnhoQERs2bIgFCxbEtGnTokePHt3u69+/f0yaNCnmzp3b9dXZ//M//xMjR46Mv/71rzFt2rS44oorYtWqVRER8cknn8T48eOjvr4+nnrqqViyZEn07NkzvvGNbzhruS8rwQ7asmVLacKECaVhw4aVOjo6utbfdNNNpbPPPrvbtm1tbaWIKK1atapUKpVKp59+eunkk0/uts2sWbNKxxxzTKmzs7Nr3R133FHq2bNnacuWLRV8JsC2LFu2rBQRpXnz5n3q/bfddlspIkrr1q0rDRkypHTJJZd03dfZ2Vnq169fqbW1tVQqlUq//e1vt3qNF4vFUo8ePUoLFiyo6PNgz6n416az75g1a1YsXbo0nnnmmaivr+9a//zzz8ef//zn6Nmz51b7rFmzJo4++uiIiBgxYkS3+1566aUYPXp01NTUdK0bM2ZMbNq0Kd58880YPHhwhZ4J8FlKO/ihzMOHD+/6d01NTfTv3z/Wr18fEf/+2bB69epuPy8iIj766KNYs2ZN3rDsVYQFO2TOnDnx05/+NB555JE46qijut23adOmOO+88+LWW2/dar8BAwZ0/fuggw6q+JzArjnyyCOjpqYmXnrppbjgggu2uv+ll16Kgw8+OPr27RsREV/4whe63V9TUxOdnZ0R8e+fDSNGjIj7779/q8f5z/7se4QFn+m5556LqVOnxuzZs7suuvy/TjnllHjooYdi6NChUVu74/+lhg0bFg899FCUSqWusxZLliyJ+vr6GDRoUNr8wI7r06dPnHXWWfHLX/4yrr322m7XWaxduzbuv//+uPTSS7udadyWU045JebOnRv9+vWLhoaGSo7NXsTFm2zXe++9F+eff36MHTs2Lrnkkli7dm235d13343m5ubYsGFDXHzxxbF8+fJYs2ZNLFiwIKZMmRJbtmzZ5mNPmzYt2tra4qqrroqXX345Hn744bjhhhtixowZsd9+/mvCnvKLX/wiisVijB8/PhYvXhxtbW0xf/78OOuss+Kwww6Lm2++eYceZ9KkSXHIIYfExIkT46mnnorXXnstFi5cGFdffXW8+eabFX4W7Cl+erNdjzzySPzzn/+MRx99NAYMGLDVMmrUqBg4cGAsWbIktmzZEmeffXaceOKJMX369OjVq9d2A+Gwww6LRx99NJ555pk46aST4vLLL4+pU6fGD3/4w934DIH/dtRRR8WKFSviiCOOiIsuuii++MUvxve+970YN25cLF26NHr37r1Dj3PggQfG4sWLY/DgwfGtb30rhg0bFlOnTo2PPvrIGYx9mK9NBwDSOGMBAKQRFgBAGmEBAKQRFgBAGmEBAKQRFgBAGmEBAKQRFgBAGmEBAKQRFgBAGmEBAKQRFgBAmv8HvX2m8Y1VbDQAAAAASUVORK5CYII=",
+            "image/png": "iVBORw0KGgoAAAANSUhEUgAAAhYAAAGdCAYAAABO2DpVAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8g+/7EAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAYm0lEQVR4nO3de4xU9fn48WeFMqLsLoIgrCzgXUSxCmiQ9itYgW6RoE20NVgpkLYKikhsytqqJZQuJpbQVIuXWCUtCG0s2lSFFlPEIpSLl2irKHhbL4CK7gCNo92d3x9N99ctgszyGWHw9UpOwjlzzpxnEmZ558xhpyyfz+cDACCBQ/b3AADAwUNYAADJCAsAIBlhAQAkIywAgGSEBQCQjLAAAJIRFgBAMm0/6xM2NTXFW2+9FeXl5VFWVvZZnx4AaIV8Ph/bt2+PqqqqOOSQ3V+X+MzD4q233orq6urP+rQAQAL19fXRo0eP3T7+mYdFeXl5RPx7sIqKis/69ABAK2Sz2aiurm7+d3x3PvOw+M/HHxUVFcICAErMp93G4OZNACAZYQEAJCMsAIBkhAUAkIywAACSERYAQDLCAgBIRlgAAMkICwAgGWEBACRTUFg0NjbGDTfcEMccc0y0b98+jjvuuJgxY0bk8/lizQcAlJCCvivk5ptvjrlz58a8efOib9++sW7duhg3blxUVlbG5MmTizUjAFAiCgqLJ554IkaPHh0jR46MiIjevXvHfffdF2vWrCnKcABAaSnoo5BzzjknHn300XjxxRcjIuKZZ56Jv/71r1FTU7PbY3K5XGSz2RYLAHBwKuiKxbRp0yKbzcbJJ58cbdq0icbGxpg5c2aMGTNmt8fU1dXF9OnT93nQvdF72kOfyXmgVL06a+T+HgE4yBV0xeK3v/1tzJ8/PxYsWBBPPvlkzJs3L2655ZaYN2/ebo+pra2NhoaG5qW+vn6fhwYADkwFXbH4/ve/H9OmTYtvfvObERFx2mmnxWuvvRZ1dXUxduzYTzwmk8lEJpPZ90kBgANeQVcs/vnPf8Yhh7Q8pE2bNtHU1JR0KACgNBV0xWLUqFExc+bM6NmzZ/Tt2zeeeuqpmD17dowfP75Y8wEAJaSgsPjFL34RN9xwQ0ycODG2bt0aVVVV8b3vfS9uvPHGYs0HAJSQgsKivLw85syZE3PmzCnSOABAKfNdIQBAMsICAEhGWAAAyQgLACAZYQEAJCMsAIBkhAUAkIywAACSERYAQDLCAgBIRlgAAMkICwAgGWEBACQjLACAZIQFAJCMsAAAkhEWAEAywgIASEZYAADJCAsAIBlhAQAkIywAgGSEBQCQjLAAAJIRFgBAMsICAEhGWAAAyQgLACAZYQEAJCMsAIBkhAUAkIywAACSERYAQDIFhUXv3r2jrKxsl2XSpEnFmg8AKCFtC9l57dq10djY2Lz+3HPPxbBhw+Liiy9OPhgAUHoKCosuXbq0WJ81a1Ycd9xxce655yYdCgAoTQWFxX/76KOP4je/+U1MnTo1ysrKdrtfLpeLXC7XvJ7NZlt7SgDgANfqmzcfeOCB+OCDD+Lb3/72Hverq6uLysrK5qW6urq1pwQADnCtDou77747ampqoqqqao/71dbWRkNDQ/NSX1/f2lMCAAe4Vn0U8tprr8WyZcvi97///afum8lkIpPJtOY0AECJadUVi3vuuSe6du0aI0eOTD0PAFDCCg6LpqamuOeee2Ls2LHRtm2r7/0EAA5CBYfFsmXL4vXXX4/x48cXYx4AoIQVfMlh+PDhkc/nizELAFDifFcIAJCMsAAAkhEWAEAywgIASEZYAADJCAsAIBlhAQAkIywAgGSEBQCQjLAAAJIRFgBAMsICAEhGWAAAyQgLACAZYQEAJCMsAIBkhAUAkIywAACSERYAQDLCAgBIRlgAAMkICwAgGWEBACQjLACAZIQFAJCMsAAAkhEWAEAywgIASEZYAADJCAsAIBlhAQAkIywAgGSEBQCQTMFh8eabb8Zll10WnTt3jvbt28dpp50W69atK8ZsAECJaVvIzu+//34MHjw4hg4dGo888kh06dIlXnrppTjiiCOKNR8AUEIKCoubb745qqur45577mnedswxxyQfCgAoTQV9FPKHP/whBgwYEBdffHF07do1zjjjjLjrrrv2eEwul4tsNttiAQAOTgWFxcsvvxxz586NE044IZYuXRpXXnllTJ48OebNm7fbY+rq6qKysrJ5qa6u3uehAYADU1k+n8/v7c7t2rWLAQMGxBNPPNG8bfLkybF27dpYtWrVJx6Ty+Uil8s1r2ez2aiuro6GhoaoqKjYh9F31XvaQ0mfDw42r84aub9HAEpUNpuNysrKT/33u6ArFt27d49TTjmlxbY+ffrE66+/vttjMplMVFRUtFgAgINTQWExePDg2LBhQ4ttL774YvTq1SvpUABAaSooLK699tpYvXp1/PSnP42NGzfGggUL4s4774xJkyYVaz4AoIQUFBYDBw6MxYsXx3333RennnpqzJgxI+bMmRNjxowp1nwAQAkp6PdYRERccMEFccEFFxRjFgCgxPmuEAAgGWEBACQjLACAZIQFAJCMsAAAkhEWAEAywgIASEZYAADJCAsAIBlhAQAkIywAgGSEBQCQjLAAAJIRFgBAMsICAEhGWAAAyQgLACAZYQEAJCMsAIBkhAUAkIywAACSERYAQDLCAgBIRlgAAMkICwAgGWEBACQjLACAZIQFAJCMsAAAkhEWAEAywgIASEZYAADJCAsAIJmCwuLHP/5xlJWVtVhOPvnkYs0GAJSYtoUe0Ldv31i2bNn/f4K2BT8FAHCQKrgK2rZtG926dSvGLABAiSv4HouXXnopqqqq4thjj40xY8bE66+/vsf9c7lcZLPZFgsAcHAqKCzOPvvsuPfee2PJkiUxd+7ceOWVV+LLX/5ybN++fbfH1NXVRWVlZfNSXV29z0MDAAemsnw+n2/twR988EH06tUrZs+eHRMmTPjEfXK5XORyueb1bDYb1dXV0dDQEBUVFa099SfqPe2hpM8HB5tXZ43c3yMAJSqbzUZlZeWn/vu9T3deduzYMU488cTYuHHjbvfJZDKRyWT25TQAQInYp99jsWPHjti0aVN079491TwAQAkrKCyuu+66eOyxx+LVV1+NJ554Ii666KJo06ZNXHrppcWaDwAoIQV9FPLGG2/EpZdeGu+991506dIlvvSlL8Xq1aujS5cuxZoPACghBYXFwoULizUHAHAQ8F0hAEAywgIASEZYAADJCAsAIBlhAQAkIywAgGSEBQCQjLAAAJIRFgBAMsICAEhGWAAAyQgLACAZYQEAJCMsAIBkhAUAkIywAACSERYAQDLCAgBIRlgAAMkICwAgGWEBACQjLACAZIQFAJCMsAAAkhEWAEAywgIASEZYAADJCAsAIBlhAQAkIywAgGSEBQCQjLAAAJIRFgBAMvsUFrNmzYqysrKYMmVKonEAgFLW6rBYu3Zt3HHHHdGvX7+U8wAAJaxVYbFjx44YM2ZM3HXXXXHEEUekngkAKFGtCotJkybFyJEj4/zzz//UfXO5XGSz2RYLAHBwalvoAQsXLownn3wy1q5du1f719XVxfTp0wseDAAoPQVdsaivr49rrrkm5s+fH4ceeuheHVNbWxsNDQ3NS319fasGBQAOfAVdsVi/fn1s3bo1zjzzzOZtjY2NsWLFirj11lsjl8tFmzZtWhyTyWQik8mkmRYAOKAVFBZf+cpX4tlnn22xbdy4cXHyySfHD37wg12iAgD4fCkoLMrLy+PUU09tse3www+Pzp0777IdAPj88Zs3AYBkCv5fIf9r+fLlCcYAAA4GrlgAAMkICwAgGWEBACQjLACAZIQFAJCMsAAAkhEWAEAywgIASEZYAADJCAsAIBlhAQAkIywAgGSEBQCQjLAAAJIRFgBAMsICAEhGWAAAyQgLACAZYQEAJCMsAIBkhAUAkIywAACSERYAQDLCAgBIRlgAAMkICwAgGWEBACQjLACAZIQFAJCMsAAAkhEWAEAywgIASEZYAADJFBQWc+fOjX79+kVFRUVUVFTEoEGD4pFHHinWbABAiSkoLHr06BGzZs2K9evXx7p16+K8886L0aNHx9///vdizQcAlJC2hew8atSoFuszZ86MuXPnxurVq6Nv375JBwMASk9BYfHfGhsb43e/+13s3LkzBg0atNv9crlc5HK55vVsNtvaUwIAB7iCb9589tlno0OHDpHJZOKKK66IxYsXxymnnLLb/evq6qKysrJ5qa6u3qeBAYADV8FhcdJJJ8XTTz8df/vb3+LKK6+MsWPHxj/+8Y/d7l9bWxsNDQ3NS319/T4NDAAcuAr+KKRdu3Zx/PHHR0RE//79Y+3atfHzn/887rjjjk/cP5PJRCaT2bcpAYCSsM+/x6KpqanFPRQAwOdXQVcsamtro6amJnr27Bnbt2+PBQsWxPLly2Pp0qXFmg8AKCEFhcXWrVvj8ssvj7fffjsqKyujX79+sXTp0hg2bFix5gMASkhBYXH33XcXaw4A4CDgu0IAgGSEBQCQjLAAAJIRFgBAMsICAEhGWAAAyQgLACAZYQEAJCMsAIBkhAUAkIywAACSERYAQDLCAgBIRlgAAMkICwAgGWEBACQjLACAZIQFAJCMsAAAkhEWAEAywgIASEZYAADJCAsAIBlhAQAkIywAgGSEBQCQjLAAAJIRFgBAMsICAEhGWAAAyQgLACAZYQEAJCMsAIBkCgqLurq6GDhwYJSXl0fXrl3jwgsvjA0bNhRrNgCgxBQUFo899lhMmjQpVq9eHX/+85/j448/juHDh8fOnTuLNR8AUELaFrLzkiVLWqzfe++90bVr11i/fn383//9X9LBAIDSU1BY/K+GhoaIiOjUqdNu98nlcpHL5ZrXs9nsvpwSADiAtTosmpqaYsqUKTF48OA49dRTd7tfXV1dTJ8+vbWnAdhF72kP7e8R4ID16qyR+/X8rf5fIZMmTYrnnnsuFi5cuMf9amtro6GhoXmpr69v7SkBgANcq65YXHXVVfHHP/4xVqxYET169NjjvplMJjKZTKuGAwBKS0Fhkc/n4+qrr47FixfH8uXL45hjjinWXABACSooLCZNmhQLFiyIBx98MMrLy2Pz5s0REVFZWRnt27cvyoAAQOko6B6LuXPnRkNDQwwZMiS6d+/evCxatKhY8wEAJaTgj0IAAHbHd4UAAMkICwAgGWEBACQjLACAZIQFAJCMsAAAkhEWAEAywgIASEZYAADJCAsAIBlhAQAkIywAgGSEBQCQjLAAAJIRFgBAMsICAEhGWAAAyQgLACAZYQEAJCMsAIBkhAUAkIywAACSERYAQDLCAgBIRlgAAMkICwAgGWEBACQjLACAZIQFAJCMsAAAkhEWAEAywgIASEZYAADJFBwWK1asiFGjRkVVVVWUlZXFAw88UISxAIBSVHBY7Ny5M04//fS47bbbijEPAFDC2hZ6QE1NTdTU1BRjFgCgxBUcFoXK5XKRy+Wa17PZbLFPCQDsJ0W/ebOuri4qKyubl+rq6mKfEgDYT4oeFrW1tdHQ0NC81NfXF/uUAMB+UvSPQjKZTGQymWKfBgA4APg9FgBAMgVfsdixY0ds3Lixef2VV16Jp59+Ojp16hQ9e/ZMOhwAUFoKDot169bF0KFDm9enTp0aERFjx46Ne++9N9lgAEDpKTgshgwZEvl8vhizAAAlzj0WAEAywgIASEZYAADJCAsAIBlhAQAkIywAgGSEBQCQjLAAAJIRFgBAMsICAEhGWAAAyQgLACAZYQEAJCMsAIBkhAUAkIywAACSERYAQDLCAgBIRlgAAMkICwAgGWEBACQjLACAZIQFAJCMsAAAkhEWAEAywgIASEZYAADJCAsAIBlhAQAkIywAgGSEBQCQjLAAAJIRFgBAMq0Ki9tuuy169+4dhx56aJx99tmxZs2a1HMBACWo4LBYtGhRTJ06NW666aZ48skn4/TTT48RI0bE1q1bizEfAFBCCg6L2bNnx3e+850YN25cnHLKKXH77bfHYYcdFr/61a+KMR8AUELaFrLzRx99FOvXr4/a2trmbYccckicf/75sWrVqk88JpfLRS6Xa15vaGiIiIhsNtuaefeoKffP5M8JB5NivO/2B+912L1ivc//87z5fH6P+xUUFu+++240NjbGUUcd1WL7UUcdFS+88MInHlNXVxfTp0/fZXt1dXUhpwYSqJyzvycAiq3Y7/Pt27dHZWXlbh8vKCxao7a2NqZOndq83tTUFNu2bYvOnTtHWVlZsU/PfpLNZqO6ujrq6+ujoqJif48DFIn3+udHPp+P7du3R1VV1R73KygsjjzyyGjTpk1s2bKlxfYtW7ZEt27dPvGYTCYTmUymxbaOHTsWclpKWEVFhR828Dngvf75sKcrFf9R0M2b7dq1i/79+8ejjz7avK2pqSkeffTRGDRoUOETAgAHlYI/Cpk6dWqMHTs2BgwYEGeddVbMmTMndu7cGePGjSvGfABACSk4LL7xjW/EO++8EzfeeGNs3rw5vvjFL8aSJUt2uaGTz7dMJhM33XTTLh+DAQcX73X+V1n+0/7fCADAXvJdIQBAMsICAEhGWAAAyQgLACAZYcEeLV++PMrKyna7DB06dH+PCBRBfX19jB8/PqqqqqJdu3bRq1evuOaaa+K9997b36NxgBMW7NE555wTb7/99i7LHXfcEWVlZTFx4sRWPe9HH32UeFIglZdffjkGDBgQL730Utx3332xcePGuP3225t/GeK2bdv294gcwIQFe9SuXbvo1q1bi+X999+P6667Lq6//vq4+OKLIyLiueeei5qamujQoUMcddRR8a1vfSvefffd5ucZMmRIXHXVVTFlypQ48sgjY8SIERER8dhjj8VZZ50VmUwmunfvHtOmTYt//etf++W1Av82adKkaNeuXfzpT3+Kc889N3r27Bk1NTWxbNmyePPNN+OHP/xhRET07t07fvrTn8b48eOjvLw8evbsGXfeeWeL56qvr49LLrkkOnbsGJ06dYrRo0fHq6++uh9eFZ8VYUFBPvjggxg9enQMGTIkZsyY0bztvPPOizPOOCPWrVsXS5YsiS1btsQll1zS4th58+ZFu3btYuXKlXH77bfHm2++GV/72tdi4MCB8cwzz8TcuXPj7rvvjp/85Cf746UBEbFt27ZYunRpTJw4Mdq3b9/isW7dusWYMWNi0aJFzV+d/bOf/SwGDBgQTz31VEycODGuvPLK2LBhQ0REfPzxxzFixIgoLy+Pxx9/PFauXBkdOnSIr371q65aHszysJcaGxvzNTU1+T59+uSz2Wzz9hkzZuSHDx/eYt/6+vp8ROQ3bNiQz+fz+XPPPTd/xhlntNjn+uuvz5900kn5pqam5m233XZbvkOHDvnGxsYivhJgd1avXp2PiPzixYs/8fHZs2fnIyK/ZcuWfK9evfKXXXZZ82NNTU35rl275ufOnZvP5/P5X//617u8x3O5XL59+/b5pUuXFvV1sP8U/WvTOXhcf/31sWrVqlizZk2Ul5c3b3/mmWfiL3/5S3To0GGXYzZt2hQnnnhiRET079+/xWPPP/98DBo0KMrKypq3DR48OHbs2BFvvPFG9OzZs0ivBPg0+b38pcz9+vVr/nNZWVl069Yttm7dGhH//tmwcePGFj8vIiI+/PDD2LRpU7phOaAIC/bKwoUL45ZbbomHHnooTjjhhBaP7dixI0aNGhU333zzLsd17969+c+HH3540ecE9s3xxx8fZWVl8fzzz8dFF120y+PPP/98HHHEEdGlS5eIiPjCF77Q4vGysrJoamqKiH//bOjfv3/Mnz9/l+f5z/EcfIQFn+rpp5+OCRMmxKxZs5pvuvxvZ555Ztx///3Ru3fvaNt27/9K9enTJ+6///7I5/PNVy1WrlwZ5eXl0aNHj2TzA3uvc+fOMWzYsPjlL38Z1157bYv7LDZv3hzz58+Pyy+/vMWVxt0588wzY9GiRdG1a9eoqKgo5tgcQNy8yR69++67ceGFF8aQIUPisssui82bN7dY3nnnnZg0aVJs27YtLr300li7dm1s2rQpli5dGuPGjYvGxsbdPvfEiROjvr4+rr766njhhRfiwQcfjJtuuimmTp0ahxzirybsL7feemvkcrkYMWJErFixIurr62PJkiUxbNiwOProo2PmzJl79TxjxoyJI488MkaPHh2PP/54vPLKK7F8+fKYPHlyvPHGG0V+FewvfnqzRw899FC89tpr8fDDD0f37t13WQYOHBhVVVWxcuXKaGxsjOHDh8dpp50WU6ZMiY4dO+4xEI4++uh4+OGHY82aNXH66afHFVdcERMmTIgf/ehHn+ErBP7XCSecEOvWrYtjjz02LrnkkjjuuOPiu9/9bgwdOjRWrVoVnTp12qvnOeyww2LFihXRs2fP+PrXvx59+vSJCRMmxIcffugKxkHM16YDAMm4YgEAJCMsAIBkhAUAkIywAACSERYAQDLCAgBIRlgAAMkICwAgGWEBACQjLACAZIQFAJCMsAAAkvl/ckGCHgMKFIgAAAAASUVORK5CYII=",
             "text/plain": [
               "<Figure size 640x480 with 1 Axes>"
             ]
@@ -881,7 +906,21 @@
       "execution_count": null,
       "id": "eaf766f4",
       "metadata": {},
-      "outputs": [],
+      "outputs": [
+        {
+          "name": "stdout",
+          "output_type": "stream",
+          "text": [
+            "Requirement already satisfied: pandas in /opt/homebrew/lib/python3.11/site-packages (2.1.3)\n",
+            "Requirement already satisfied: numpy<2,>=1.23.2 in /opt/homebrew/lib/python3.11/site-packages (from pandas) (1.23.5)\n",
+            "Requirement already satisfied: python-dateutil>=2.8.2 in /Users/swernli/Library/Python/3.11/lib/python/site-packages (from pandas) (2.8.2)\n",
+            "Requirement already satisfied: pytz>=2020.1 in /opt/homebrew/lib/python3.11/site-packages (from pandas) (2023.3.post1)\n",
+            "Requirement already satisfied: tzdata>=2022.1 in /opt/homebrew/lib/python3.11/site-packages (from pandas) (2023.3)\n",
+            "Requirement already satisfied: six>=1.5 in /opt/homebrew/lib/python3.11/site-packages (from python-dateutil>=2.8.2->pandas) (1.16.0)\n",
+            "Note: you may need to restart the kernel to use updated packages.\n"
+          ]
+        }
+      ],
       "source": [
         "%pip install pandas\n"
       ]
@@ -892,20 +931,6 @@
       "id": "8095640a",
       "metadata": {},
       "outputs": [
-        {
-          "name": "stderr",
-          "output_type": "stream",
-          "text": [
-            "/tmp/ipykernel_3468/2211578213.py:1: DeprecationWarning: \n",
-            "Pyarrow will become a required dependency of pandas in the next major release of pandas (pandas 3.0),\n",
-            "(to allow more performant data types, such as the Arrow string type, and better interoperability with other libraries)\n",
-            "but was not found to be installed on your system.\n",
-            "If this would cause problems for you,\n",
-            "please provide us feedback at https://github.com/pandas-dev/pandas/issues/54466\n",
-            "        \n",
-            "  import pandas\n"
-          ]
-        },
         {
           "data": {
             "text/plain": [
@@ -918,7 +943,7 @@
         },
         {
           "data": {
-            "image/png": "iVBORw0KGgoAAAANSUhEUgAAAhYAAAGvCAYAAAAHapzzAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8g+/7EAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAXaklEQVR4nO3da4wVhfn48ecgckS7uyIIQlhRihVRwQpqCNWoqHi3NqmX0JRYa6KsV2JiqVG0xi6+qKUNFqmxJU1jMW1ibWrFCyLGAhYw3qsFBV2kiIruAo1HZff3onH//y1ge5Zn9+yBzyeZFzNnxnlMXPebmTk7hba2trYAAEjQq9IDAAC7D2EBAKQRFgBAGmEBAKQRFgBAGmEBAKQRFgBAGmEBAKTp3d0nbG1tjfXr10dNTU0UCoXuPj0A0AltbW2xefPmGDJkSPTqtfPrEt0eFuvXr4/6+vruPi0AkKCpqSmGDh2608+7PSxqamoi4t+D1dbWdvfpAYBOaGlpifr6+vbf4zvT7WHxxe2P2tpaYQEAVea/Pcbg4U0AII2wAADSCAsAII2wAADSCAsAII2wAADSCAsAII2wAADSCAsAII2wAADSlB0W7777bnznO9+J/v37R9++fePoo4+OFStWdMVsAECVKetdIR999FFMmDAhTjnllHj00UfjwAMPjFWrVkW/fv26aj4AoIqUFRZ33XVX1NfXx69//ev2bYceemj6UABAdSrrVsif/vSnGDduXHz729+OgQMHxte//vW47777vvSYUqkULS0tHRYAYPdU1hWLt956K+bMmRPTpk2LH/7wh7F8+fK49tpro0+fPjFlypQdHtPY2Bi33357yrAAPdUhP3ik0iPQjdbOPKfSI/RYhba2trb/dec+ffrEuHHjYsmSJe3brr322li+fHksXbp0h8eUSqUolUrt6y0tLVFfXx/Nzc1RW1u7C6MD9BzCYs+yJ4ZFS0tL1NXV/dff32XdChk8eHCMGjWqw7Yjjjgi3nnnnZ0eUywWo7a2tsMCAOyeygqLCRMmxBtvvNFh2z/+8Y8YNmxY6lAAQHUqKyxuuOGGWLZsWfz4xz+O1atXxwMPPBC//OUvo6GhoavmAwCqSFlhcdxxx8VDDz0Uv/vd7+Koo46KO+64I2bNmhWTJ0/uqvkAgCpS1rdCIiLOPffcOPfcc7tiFgCgynlXCACQRlgAAGmEBQCQRlgAAGmEBQCQRlgAAGmEBQCQRlgAAGmEBQCQRlgAAGmEBQCQRlgAAGmEBQCQRlgAAGmEBQCQRlgAAGmEBQCQRlgAAGmEBQCQRlgAAGmEBQCQRlgAAGmEBQCQRlgAAGmEBQCQRlgAAGmEBQCQRlgAAGmEBQCQRlgAAGmEBQCQRlgAAGmEBQCQRlgAAGmEBQCQRlgAAGmEBQCQRlgAAGmEBQCQRlgAAGmEBQCQRlgAAGmEBQCQRlgAAGmEBQCQRlgAAGmEBQCQRlgAAGnKCovbbrstCoVCh2XkyJFdNRsAUGV6l3vAkUceGU8++eT/+wf0LvsfAQDspsqugt69e8dBBx3UFbMAAFWu7GcsVq1aFUOGDInhw4fH5MmT45133vnS/UulUrS0tHRYAIDdU1lhccIJJ8S8efNiwYIFMWfOnFizZk2ceOKJsXnz5p0e09jYGHV1de1LfX39Lg8NAPRMhba2trbOHvzxxx/HsGHD4u67747LL798h/uUSqUolUrt6y0tLVFfXx/Nzc1RW1vb2VMD9CiH/OCRSo9AN1o785xKj9DtWlpaoq6u7r/+/t6lJy/333//+NrXvharV6/e6T7FYjGKxeKunAYAqBK79HcstmzZEm+++WYMHjw4ax4AoIqVFRY33nhjLF68ONauXRtLliyJCy+8MPbaa6+49NJLu2o+AKCKlHUrZN26dXHppZfGhx9+GAceeGB84xvfiGXLlsWBBx7YVfMBAFWkrLCYP39+V80BAOwGvCsEAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEizS2Exc+bMKBQKcf311yeNAwBUs06HxfLly2Pu3LkxevTozHkAgCrWqbDYsmVLTJ48Oe67777o169f9kwAQJXqVFg0NDTEOeecE6eddlr2PABAFetd7gHz58+P559/PpYvX/4/7V8qlaJUKrWvt7S0lHtKAKBKlBUWTU1Ncd1118UTTzwR++yzz/90TGNjY9x+++2dGm53c8gPHqn0CHSjtTPPqfQIAN2urFshK1eujI0bN8axxx4bvXv3jt69e8fixYvj5z//efTu3Tu2bdu23THTp0+P5ubm9qWpqSlteACgZynrisXEiRPj5Zdf7rDtsssui5EjR8ZNN90Ue+2113bHFIvFKBaLuzYlAFAVygqLmpqaOOqoozps22+//aJ///7bbQcA9jz+8iYAkKbsb4X8p6effjphDABgd+CKBQCQRlgAAGmEBQCQRlgAAGmEBQCQRlgAAGmEBQCQRlgAAGmEBQCQRlgAAGmEBQCQRlgAAGmEBQCQRlgAAGmEBQCQRlgAAGmEBQCQRlgAAGmEBQCQRlgAAGmEBQCQRlgAAGmEBQCQRlgAAGmEBQCQRlgAAGmEBQCQRlgAAGmEBQCQRlgAAGmEBQCQRlgAAGmEBQCQRlgAAGmEBQCQRlgAAGmEBQCQRlgAAGmEBQCQRlgAAGmEBQCQRlgAAGmEBQCQRlgAAGmEBQCQRlgAAGmEBQCQRlgAAGnKCos5c+bE6NGjo7a2Nmpra2P8+PHx6KOPdtVsAECVKSsshg4dGjNnzoyVK1fGihUr4tRTT40LLrggXn311a6aDwCoIr3L2fm8887rsH7nnXfGnDlzYtmyZXHkkUemDgYAVJ+ywuL/t23btvj9738fW7dujfHjx+90v1KpFKVSqX29paWls6cEAHq4sh/efPnll+MrX/lKFIvFuPLKK+Ohhx6KUaNG7XT/xsbGqKura1/q6+t3aWAAoOcqOywOP/zweOGFF+K5556Lq666KqZMmRKvvfbaTvefPn16NDc3ty9NTU27NDAA0HOVfSukT58+MWLEiIiIGDt2bCxfvjx+9rOfxdy5c3e4f7FYjGKxuGtTAgBVYZf/jkVra2uHZygAgD1XWVcspk+fHmeddVYcfPDBsXnz5njggQfi6aefjscee6yr5gMAqkhZYbFx48b47ne/G//85z+jrq4uRo8eHY899licfvrpXTUfAFBFygqL+++/v6vmAAB2A94VAgCkERYAQBphAQCkERYAQBphAQCkERYAQBphAQCkERYAQBphAQCkERYAQBphAQCkERYAQBphAQCkERYAQBphAQCkERYAQBphAQCkERYAQBphAQCkERYAQBphAQCkERYAQBphAQCkERYAQBphAQCkERYAQBphAQCkERYAQBphAQCkERYAQBphAQCkERYAQBphAQCkERYAQBphAQCkERYAQBphAQCkERYAQBphAQCkERYAQBphAQCkERYAQBphAQCkERYAQBphAQCkERYAQBphAQCkERYAQJqywqKxsTGOO+64qKmpiYEDB8Y3v/nNeOONN7pqNgCgypQVFosXL46GhoZYtmxZPPHEE/HZZ5/FGWecEVu3bu2q+QCAKtK7nJ0XLFjQYX3evHkxcODAWLlyZZx00kmpgwEA1aessPhPzc3NERFxwAEH7HSfUqkUpVKpfb2lpWVXTgkA9GCdfniztbU1rr/++pgwYUIcddRRO92vsbEx6urq2pf6+vrOnhIA6OE6HRYNDQ3xyiuvxPz58790v+nTp0dzc3P70tTU1NlTAgA9XKduhVx99dXx5z//OZ555pkYOnTol+5bLBajWCx2ajgAoLqUFRZtbW1xzTXXxEMPPRRPP/10HHrooV01FwBQhcoKi4aGhnjggQfi4YcfjpqamtiwYUNERNTV1UXfvn27ZEAAoHqU9YzFnDlzorm5OU4++eQYPHhw+/Lggw921XwAQBUp+1YIAMDOeFcIAJBGWAAAaYQFAJBGWAAAaYQFAJBGWAAAaYQFAJBGWAAAaYQFAJBGWAAAaYQFAJBGWAAAaYQFAJBGWAAAaYQFAJBGWAAAaYQFAJBGWAAAaYQFAJBGWAAAaYQFAJBGWAAAaYQFAJBGWAAAaYQFAJBGWAAAaYQFAJBGWAAAaYQFAJBGWAAAaYQFAJBGWAAAaYQFAJBGWAAAaYQFAJBGWAAAaYQFAJBGWAAAaYQFAJBGWAAAaYQFAJBGWAAAaYQFAJBGWAAAaYQFAJBGWAAAaYQFAJCm7LB45pln4rzzzoshQ4ZEoVCIP/7xj10wFgBQjcoOi61bt8aYMWPinnvu6Yp5AIAq1rvcA84666w466yzumIWAKDKecYCAEhT9hWLcpVKpSiVSu3rLS0tXX1KAKBCuvyKRWNjY9TV1bUv9fX1XX1KAKBCujwspk+fHs3Nze1LU1NTV58SAKiQLr8VUiwWo1gsdvVpAIAeoOyw2LJlS6xevbp9fc2aNfHCCy/EAQccEAcffHDqcABAdSk7LFasWBGnnHJK+/q0adMiImLKlCkxb968tMEAgOpTdlicfPLJ0dbW1hWzAABVzt+xAADSCAsAII2wAADSCAsAII2wAADSCAsAII2wAADSCAsAII2wAADSCAsAII2wAADSCAsAII2wAADSCAsAII2wAADSCAsAII2wAADSCAsAII2wAADSCAsAII2wAADSCAsAII2wAADSCAsAII2wAADSCAsAII2wAADSCAsAII2wAADSCAsAII2wAADSCAsAII2wAADSCAsAII2wAADSCAsAII2wAADSCAsAII2wAADSCAsAII2wAADSCAsAII2wAADSCAsAII2wAADSCAsAII2wAADSCAsAIE2nwuKee+6JQw45JPbZZ5844YQT4m9/+1v2XABAFSo7LB588MGYNm1azJgxI55//vkYM2ZMTJo0KTZu3NgV8wEAVaTssLj77rvjiiuuiMsuuyxGjRoV9957b+y7777xq1/9qivmAwCqSO9ydv70009j5cqVMX369PZtvXr1itNOOy2WLl26w2NKpVKUSqX29ebm5oiIaGlp6cy8Va219K9Kj0A32hP/G9+T+fnes+yJP99f/Du3tbV96X5lhcUHH3wQ27Zti0GDBnXYPmjQoHj99dd3eExjY2Pcfvvt222vr68v59RQdepmVXoCoKvsyT/fmzdvjrq6up1+XlZYdMb06dNj2rRp7eutra2xadOm6N+/fxQKha4+PRXW0tIS9fX10dTUFLW1tZUeB0jk53vP0tbWFps3b44hQ4Z86X5lhcWAAQNir732ivfee6/D9vfeey8OOuigHR5TLBajWCx22Lb//vuXc1p2A7W1tf7HA7spP997ji+7UvGFsh7e7NOnT4wdOzYWLlzYvq21tTUWLlwY48ePL39CAGC3UvatkGnTpsWUKVNi3Lhxcfzxx8esWbNi69atcdlll3XFfABAFSk7LC6++OJ4//3349Zbb40NGzbEMcccEwsWLNjugU6I+PetsBkzZmx3Owyofn6+2ZFC23/73ggAwP/Iu0IAgDTCAgBIIywAgDTCAgBIIywAgDTCgi6zbt26WLduXaXHABJ9/vnn8eSTT8bcuXNj8+bNERGxfv362LJlS4Uno6cQFqRqbW2NH/3oR1FXVxfDhg2LYcOGxf777x933HFHtLa2Vno8YBe8/fbbcfTRR8cFF1wQDQ0N8f7770dExF133RU33nhjhaejp+jyl5CxZ7n55pvj/vvvj5kzZ8aECRMiIuLZZ5+N2267LT755JO48847Kzwh0FnXXXddjBs3Ll588cXo379/+/YLL7wwrrjiigpORk/iD2SRasiQIXHvvffG+eef32H7ww8/HFOnTo133323QpMBu6p///6xZMmSOPzww6OmpiZefPHFGD58eKxduzZGjRoV//rXvyo9Ij2AWyGk2rRpU4wcOXK77SNHjoxNmzZVYCIgS2tra2zbtm277evWrYuampoKTERPJCxINWbMmJg9e/Z222fPnh1jxoypwERAljPOOCNmzZrVvl4oFGLLli0xY8aMOPvssys3GD2KWyGkWrx4cZxzzjlx8MEHx/jx4yMiYunSpdHU1BR/+ctf4sQTT6zwhEBnrVu3LiZNmhRtbW2xatWqGDduXKxatSoGDBgQzzzzTAwcOLDSI9IDCAvSrV+/Pu655554/fXXIyLiiCOOiKlTp8aQIUMqPBmwqz7//POYP39+vPTSS7Fly5Y49thjY/LkydG3b99Kj0YPISxI89lnn8WZZ54Z9957bxx22GGVHgeACvB1U9Lsvffe8dJLL1V6DKALrVq1KhYtWhQbN27c7m/T3HrrrRWaip7EFQtS3XDDDVEsFmPmzJmVHgVIdt9998VVV10VAwYMiIMOOigKhUL7Z4VCIZ5//vkKTkdPISxIdc0118RvfvObOOyww2Ls2LGx3377dfj87rvvrtBkwK4aNmxYTJ06NW666aZKj0IPJixIdcopp+z0s0KhEE899VQ3TgNkqq2tjRdeeCGGDx9e6VHowYQFAP+Tyy+/PI477ri48sorKz0KPZiHN+kSq1evjjfffDNOOumk6Nu3b7S1tXW4HwtUnxEjRsQtt9wSS5cujdGjR8fee+/d4fNrr722QpPRk7hiQaoPP/wwLrrooli0aFEUCoVYtWpVDB8+PL73ve9Fv3794ic/+UmlRwQ66dBDD93pZ4VCId56661unIaeyhULUt1www2x9957xzvvvBNHHHFE+/aLL744pk2bJiygiq1ZsyYiIj744IOIiBgwYEAlx6GH8q4QUj3++ONx1113xdChQztsP+yww+Ltt9+u0FTArvr444+joaEhBgwYEIMGDYpBgwbFgAED4uqrr47m5uZKj0cP4ooFqbZu3Rr77rvvdts3bdoUxWKxAhMBu2rTpk0xfvz4ePfdd2Py5MntVyNfe+21mDdvXixcuDCWLFkS/fr1q/Ck9ASesSDV2WefHWPHjo077rgjampq4qWXXophw4bFJZdcEq2trfGHP/yh0iMCZbr++utj4cKF8eSTT8agQYM6fLZhw4Y444wzYuLEifHTn/60QhPSkwgLUr3yyisxceLEOPbYY+Opp56K888/P1599dXYtGlT/PWvf42vfvWrlR4RKNMhhxwSc+fOjUmTJu3w8wULFsSVV14Za9eu7d7B6JGEBemam5tj9uzZ8eKLL7a//bChoSEGDx5c6dGATigWi/Hmm29u9+zUF9atWxcjRoyITz75pJsnoyfyjAUpJk6cGA0NDfGtb30r6urq4uabb+7w+QcffBDDhw/3dTSoQgMGDIi1a9fuNCzWrFkTBxxwQDdPRU/lWyGkWLRoUVx00UUxY8aMHX6+bds23wqBKjVp0qS4+eab49NPP93us1KpFLfcckuceeaZFZiMnsitEFL06tUr5s6dGzfeeGOceuqp8dvf/rbDC8jee++9GDJkSGzbtq2CUwKdsW7duhg3blwUi8VoaGiIkSNHRltbW/z973+PX/ziF1EqlWLFihVRX19f6VHpAYQFKXr16hUbNmyIDz/8MC644IIoFovx8MMPt7+sSFhAdVuzZk1MnTo1Hn/88fji10ahUIjTTz89Zs+eHSNGjKjwhPQUwoIUX4TFwIEDo7m5OS699NJ47rnn4sEHH4zTTjtNWMBu4qOPPopVq1ZFxL/fHeLZCv6TZyxIV1dXF4888khcccUVcfbZZ/tuO+xG+vXrF8cff3wcf/zxooId8q0QUvznm0sLhULMnDkzjjnmmPj+978fTz31VIUmA6A7uWJBip3dUbvkkkvi2WefjZdffrmbJwKgElyxIMWiRYt2eln0mGOOiZUrV8YjjzzSzVMB0N08vAkApHErBABIIywAgDTCAgBIIywAgDTCAgBIIywAgDTCAgBIIywAgDT/BzRqNf3Uih03AAAAAElFTkSuQmCC",
+            "image/png": "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CjUbAFBi8gqLJ554Iqqrq2PFihXx97//PT755JMYM2ZM7Nixo1DzAQAlpFM+Oz/00EOt1ufPnx89evSI1atXxwknnJB0MACg9OQVFv+tvr4+IiIOOuigXe6Ty+Uil8u1rDc0NOzOKQGAdqzNYdHU1BRXXXVVjBo1Ko444ohd7ldbWxvTp09v62kASkK/6x4o9gjsQetnji/2CO1Wm78VUl1dHS+88EIsWrToC/erqamJ+vr6lqWurq6tpwQA2rk2XbG4/PLL469//WssXbo0evfu/YX7ZrPZyGazbRoOACgteYVFc3NzXHHFFXHvvffG448/Hv379y/UXABACcorLKqrq2PhwoVx//33R1lZWWzevDkiIioqKqJz584FGRAAKB15PWMxd+7cqK+vj+985zvRq1evluWee+4p1HwAQAnJ+1YIAMCueFcIAJCMsAAAkhEWAEAywgIASEZYAADJCAsAIBlhAQAkIywAgGSEBQCQjLAAAJIRFgBAMsICAEhGWAAAyQgLACAZYQEAJCMsAIBkhAUAkIywAACSERYAQDLCAgBIRlgAAMkICwAgGWEBACQjLACAZIQFAJCMsAAAkhEWAEAywgIASEZYAADJCAsAIBlhAQAkIywAgGSEBQCQTN5hsXTp0jjjjDOisrIyMplM3HfffQUYCwAoRXmHxY4dO2LYsGFxyy23FGIeAKCEdcr3gHHjxsW4ceMKMQsAUOLyDot85XK5yOVyLesNDQ2FPiUAUCQFf3iztrY2KioqWpaqqqpCnxIAKJKCh0VNTU3U19e3LHV1dYU+JQBQJAW/FZLNZiObzRb6NABAO+DvWAAAyeR9xWL79u3x2muvtayvW7cunn322TjooIOiT58+SYcDAEpL3mGxatWqOPHEE1vWp0yZEhEREydOjPnz5ycbDAAoPXmHxXe+851obm4uxCwAQInzjAUAkIywAACSERYAQDLCAgBIRlgAAMkICwAgGWEBACQjLACAZIQFAJCMsAAAkhEWAEAywgIASEZYAADJCAsAIBlhAQAkIywAgGSEBQCQjLAAAJIRFgBAMsICAEhGWAAAyQgLACAZYQEAJCMsAIBkhAUAkIywAACSERYAQDLCAgBIRlgAAMkICwAgGWEBACQjLACAZIQFAJBMm8LilltuiX79+sV+++0Xxx13XDz99NOp5wIASlDeYXHPPffElClTYtq0afHMM8/EsGHDYuzYsbFly5ZCzAcAlJC8w2LWrFlxySWXxIUXXhhDhgyJW2+9Nfbff//43e9+V4j5AIAS0imfnT/++ONYvXp11NTUtGzr0KFDnHzyybF8+fLPPSaXy0Uul2tZr6+vj4iIhoaGtsxb0ppyHxZ7BPagr+J/419lfr6/Wr6KP9+f/Ts3Nzd/4X55hcW7774bjY2N0bNnz1bbe/bsGS+//PLnHlNbWxvTp0/faXtVVVU+p4aSUzG72BMAhfJV/vnetm1bVFRU7PLzvMKiLWpqamLKlCkt601NTbF169bo2rVrZDKZQp+eImtoaIiqqqqoq6uL8vLyYo8DJOTn+6ulubk5tm3bFpWVlV+4X15h0a1bt+jYsWO8/fbbrba//fbbcfDBB3/uMdlsNrLZbKttBx54YD6nZS9QXl7ufzywl/Lz/dXxRVcqPpPXw5v77rtvDB8+PJYsWdKyrampKZYsWRIjR47Mf0IAYK+S962QKVOmxMSJE2PEiBFx7LHHxuzZs2PHjh1x4YUXFmI+AKCE5B0W5513Xrzzzjtxww03xObNm+Ooo46Khx56aKcHOiHiP7fCpk2bttPtMKD0+fnm82Sav+x7IwAA/yPvCgEAkhEWAEAywgIASEZYAADJCAsAIBlhQcFs3LgxNm7cWOwxgIQ+/fTTWLx4ccybNy+2bdsWERGbNm2K7du3F3ky2gthQVJNTU3x05/+NCoqKqJv377Rt2/fOPDAA+Omm26KpqamYo8H7IYNGzbEkUceGWeddVZUV1fHO++8ExERN998c1xzzTVFno72ouAvIeOr5frrr4/bb789Zs6cGaNGjYqIiCeffDJuvPHG+Oijj2LGjBlFnhBoqyuvvDJGjBgRa9asia5du7ZsP/vss+OSSy4p4mS0J/5AFklVVlbGrbfeGmeeeWar7ffff39MmjQp3nrrrSJNBuyurl27xrJly+LQQw+NsrKyWLNmTQwYMCDWr18fQ4YMiQ8//LDYI9IOuBVCUlu3bo3BgwfvtH3w4MGxdevWIkwEpNLU1BSNjY07bd+4cWOUlZUVYSLaI2FBUsOGDYs5c+bstH3OnDkxbNiwIkwEpDJmzJiYPXt2y3omk4nt27fHtGnT4rTTTiveYLQrboWQ1BNPPBHjx4+PPn36xMiRIyMiYvny5VFXVxd/+9vf4vjjjy/yhEBbbdy4McaOHRvNzc2xdu3aGDFiRKxduza6desWS5cujR49ehR7RNoBYUFymzZtiltuuSVefvnliIg47LDDYtKkSVFZWVnkyYDd9emnn8aiRYviueeei+3bt8fRRx8dEyZMiM6dOxd7NNoJYUEyn3zySZx66qlx6623xqBBg4o9DgBF4OumJLPPPvvEc889V+wxgAJau3ZtPPbYY7Fly5ad/jbNDTfcUKSpaE9csSCpq6++OrLZbMycObPYowCJ3XbbbXHZZZdFt27d4uCDD45MJtPyWSaTiWeeeaaI09FeCAuSuuKKK+L3v/99DBo0KIYPHx4HHHBAq89nzZpVpMmA3dW3b9+YNGlSXHvttcUehXZMWJDUiSeeuMvPMplMPProo3twGiCl8vLyePbZZ2PAgAHFHoV2TFgA8D+5+OKL45hjjolLL7202KPQjnl4k4J47bXX4vXXX48TTjghOnfuHM3Nza3uxwKlZ+DAgTF16tRYvnx5DB06NPbZZ59Wn0+ePLlIk9GeuGJBUu+9916ce+658dhjj0Umk4m1a9fGgAED4qKLLoouXbrEL37xi2KPCLRR//79d/lZJpOJN954Yw9OQ3vligVJXX311bHPPvvEm2++GYcddljL9vPOOy+mTJkiLKCErVu3LiIi3n333YiI6NatWzHHoZ3yrhCSeuSRR+Lmm2+O3r17t9o+aNCg2LBhQ5GmAnbXBx98ENXV1dGtW7fo2bNn9OzZM7p16xaXX3551NfXF3s82hFXLEhqx44dsf/++++0fevWrZHNZoswEbC7tm7dGiNHjoy33norJkyY0HI18qWXXor58+fHkiVLYtmyZdGlS5ciT0p74BkLkjrttNNi+PDhcdNNN0VZWVk899xz0bdv3zj//POjqakp/vSnPxV7RCBPV111VSxZsiQWL14cPXv2bPXZ5s2bY8yYMTF69Oj45S9/WaQJaU+EBUm98MILMXr06Dj66KPj0UcfjTPPPDNefPHF2Lp1a/zjH/+IQw45pNgjAnnq169fzJs3L8aOHfu5nz/00ENx6aWXxvr16/fsYLRLwoLk6uvrY86cObFmzZqWtx9WV1dHr169ij0a0AbZbDZef/31nZ6d+szGjRtj4MCB8dFHH+3hyWiPPGNBEqNHj47q6ur43ve+FxUVFXH99de3+vzdd9+NAQMG+DoalKBu3brF+vXrdxkW69ati4MOOmgPT0V75VshJPHYY4/FueeeG9OmTfvczxsbG30rBErU2LFj4/rrr4+PP/54p89yuVxMnTo1Tj311CJMRnvkVghJdOjQIebNmxfXXHNNnHTSSXHnnXe2egHZ22+/HZWVldHY2FjEKYG22LhxY4wYMSKy2WxUV1fH4MGDo7m5Of71r3/Fb37zm8jlcrFq1aqoqqoq9qi0A8KCJDp06BCbN2+O9957L84666zIZrNx//33t7ysSFhAaVu3bl1MmjQpHnnkkfjs10Ymk4lTTjkl5syZEwMHDizyhLQXwoIkPguLHj16RH19fVxwwQXx1FNPxT333BMnn3yysIC9xPvvvx9r166NiP+8O8SzFfw3z1iQXEVFRTzwwANxySWXxGmnnea77bAX6dKlSxx77LFx7LHHigo+l2+FkMR/v7k0k8nEzJkz46ijjoof/ehH8eijjxZpMgD2JFcsSGJXd9TOP//8ePLJJ+P555/fwxMBUAyuWJDEY489tsvLokcddVSsXr06HnjggT08FQB7moc3AYBk3AoBAJIRFgBAMsICAEhGWAAAyQgLACAZYQEAJCMsAIBkhAUAkMz/A0oPESovBdCBAAAAAElFTkSuQmCC",
             "text/plain": [
               "<Figure size 640x480 with 1 Axes>"
             ]
@@ -958,7 +983,7 @@
             "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
             "\u001b[0;31mQSharpError\u001b[0m                               Traceback (most recent call last)",
             "Cell \u001b[0;32mIn[14], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mqsharp\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrun\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m\"\"\"\u001b[39;49m\u001b[38;5;124;43mRandomBit(\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43ma\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43m)\u001b[39;49m\u001b[38;5;124;43m\"\"\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m10\u001b[39;49m\u001b[43m)\u001b[49m\n",
-            "File \u001b[0;32m/workspaces/qsharp/pip/qsharp/_qsharp.py:165\u001b[0m, in \u001b[0;36mrun\u001b[0;34m(entry_expr, shots, on_result, save_events)\u001b[0m\n\u001b[1;32m    163\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m _ \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mrange\u001b[39m(shots):\n\u001b[1;32m    164\u001b[0m     results\u001b[38;5;241m.\u001b[39mappend({\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mresult\u001b[39m\u001b[38;5;124m\"\u001b[39m: \u001b[38;5;28;01mNone\u001b[39;00m, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mevents\u001b[39m\u001b[38;5;124m\"\u001b[39m: []})\n\u001b[0;32m--> 165\u001b[0m     run_results \u001b[38;5;241m=\u001b[39m \u001b[43mget_interpreter\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrun\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m    166\u001b[0m \u001b[43m        \u001b[49m\u001b[43mentry_expr\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mon_save_events\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43;01mif\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43msave_events\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43;01melse\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43mprint_output\u001b[49m\n\u001b[1;32m    167\u001b[0m \u001b[43m    \u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m    168\u001b[0m     results[\u001b[38;5;241m-\u001b[39m\u001b[38;5;241m1\u001b[39m][\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mresult\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m=\u001b[39m run_results\n\u001b[1;32m    169\u001b[0m     \u001b[38;5;28;01mif\u001b[39;00m on_result:\n",
+            "File \u001b[0;32m~/Programming/qsharp/pip/qsharp/_qsharp.py:165\u001b[0m, in \u001b[0;36mrun\u001b[0;34m(entry_expr, shots, on_result, save_events)\u001b[0m\n\u001b[1;32m    163\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m _ \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mrange\u001b[39m(shots):\n\u001b[1;32m    164\u001b[0m     results\u001b[38;5;241m.\u001b[39mappend({\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mresult\u001b[39m\u001b[38;5;124m\"\u001b[39m: \u001b[38;5;28;01mNone\u001b[39;00m, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mevents\u001b[39m\u001b[38;5;124m\"\u001b[39m: []})\n\u001b[0;32m--> 165\u001b[0m     run_results \u001b[38;5;241m=\u001b[39m \u001b[43mget_interpreter\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrun\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m    166\u001b[0m \u001b[43m        \u001b[49m\u001b[43mentry_expr\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mon_save_events\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43;01mif\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43msave_events\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43;01melse\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43mprint_output\u001b[49m\n\u001b[1;32m    167\u001b[0m \u001b[43m    \u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m    168\u001b[0m     results[\u001b[38;5;241m-\u001b[39m\u001b[38;5;241m1\u001b[39m][\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mresult\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m=\u001b[39m run_results\n\u001b[1;32m    169\u001b[0m     \u001b[38;5;28;01mif\u001b[39;00m on_result:\n",
             "\u001b[0;31mQSharpError\u001b[0m: \u001b[31mQsc.TypeCk.TyMismatch\u001b[0m\n\n  \u001b[31m×\u001b[0m type error\n\u001b[31m  ╰─▶ \u001b[0mexpected Unit, found String\n   ╭─[\u001b[36;1;4m<entry>\u001b[0m:1:1]\n \u001b[2m1\u001b[0m │ RandomBit(\"a\")\n   · \u001b[35;1m──────────────\u001b[0m\n   ╰────\n"
           ]
         }
@@ -1014,7 +1039,7 @@
             "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
             "\u001b[0;31mQSharpError\u001b[0m                               Traceback (most recent call last)",
             "Cell \u001b[0;32mIn[16], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mqsharp\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrun\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mBad()\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m10\u001b[39;49m\u001b[43m)\u001b[49m\n",
-            "File \u001b[0;32m/workspaces/qsharp/pip/qsharp/_qsharp.py:165\u001b[0m, in \u001b[0;36mrun\u001b[0;34m(entry_expr, shots, on_result, save_events)\u001b[0m\n\u001b[1;32m    163\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m _ \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mrange\u001b[39m(shots):\n\u001b[1;32m    164\u001b[0m     results\u001b[38;5;241m.\u001b[39mappend({\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mresult\u001b[39m\u001b[38;5;124m\"\u001b[39m: \u001b[38;5;28;01mNone\u001b[39;00m, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mevents\u001b[39m\u001b[38;5;124m\"\u001b[39m: []})\n\u001b[0;32m--> 165\u001b[0m     run_results \u001b[38;5;241m=\u001b[39m \u001b[43mget_interpreter\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrun\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m    166\u001b[0m \u001b[43m        \u001b[49m\u001b[43mentry_expr\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mon_save_events\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43;01mif\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43msave_events\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43;01melse\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43mprint_output\u001b[49m\n\u001b[1;32m    167\u001b[0m \u001b[43m    \u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m    168\u001b[0m     results[\u001b[38;5;241m-\u001b[39m\u001b[38;5;241m1\u001b[39m][\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mresult\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m=\u001b[39m run_results\n\u001b[1;32m    169\u001b[0m     \u001b[38;5;28;01mif\u001b[39;00m on_result:\n",
+            "File \u001b[0;32m~/Programming/qsharp/pip/qsharp/_qsharp.py:165\u001b[0m, in \u001b[0;36mrun\u001b[0;34m(entry_expr, shots, on_result, save_events)\u001b[0m\n\u001b[1;32m    163\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m _ \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mrange\u001b[39m(shots):\n\u001b[1;32m    164\u001b[0m     results\u001b[38;5;241m.\u001b[39mappend({\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mresult\u001b[39m\u001b[38;5;124m\"\u001b[39m: \u001b[38;5;28;01mNone\u001b[39;00m, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mevents\u001b[39m\u001b[38;5;124m\"\u001b[39m: []})\n\u001b[0;32m--> 165\u001b[0m     run_results \u001b[38;5;241m=\u001b[39m \u001b[43mget_interpreter\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrun\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m    166\u001b[0m \u001b[43m        \u001b[49m\u001b[43mentry_expr\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mon_save_events\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43;01mif\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43msave_events\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43;01melse\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43mprint_output\u001b[49m\n\u001b[1;32m    167\u001b[0m \u001b[43m    \u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m    168\u001b[0m     results[\u001b[38;5;241m-\u001b[39m\u001b[38;5;241m1\u001b[39m][\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mresult\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m=\u001b[39m run_results\n\u001b[1;32m    169\u001b[0m     \u001b[38;5;28;01mif\u001b[39;00m on_result:\n",
             "\u001b[0;31mQSharpError\u001b[0m: Error: Qubit1 released while not in |0⟩ state\nCall stack:\n    at QIR.Runtime.__quantum__rt__qubit_release in core/qir.qs\n    at Bad in line_9\n\u001b[31mQsc.Eval.ReleasedQubitNotZero\u001b[0m\n\n  \u001b[31m×\u001b[0m runtime error\n\u001b[31m  ╰─▶ \u001b[0mQubit1 released while not in |0⟩ state\n   ╭─[\u001b[36;1;4mline_9\u001b[0m:7:1]\n \u001b[2m7\u001b[0m │         // Do something bad, sometimes\n \u001b[2m8\u001b[0m │         use q2 = Qubit();\n   · \u001b[35;1m        ────────┬────────\u001b[0m\n   ·                 \u001b[35;1m╰── \u001b[35;1mQubit1\u001b[0m\u001b[0m\n \u001b[2m9\u001b[0m │         X(q2);\n   ╰────\n\u001b[36m  help: \u001b[0mqubits should be returned to the |0⟩ state before being released to\n        satisfy the assumption that allocated qubits start in the |0⟩ state\n"
           ]
         }
@@ -1040,7 +1065,7 @@
       "name": "python",
       "nbconvert_exporter": "python",
       "pygments_lexer": "ipython3",
-      "version": "3.12.1"
+      "version": "3.11.6"
     }
   },
   "nbformat": 4,
diff --git a/pip/src/state_header_template.html b/pip/src/state_header_template.html
index 44d301a9..2093cde6 100644
--- a/pip/src/state_header_template.html
+++ b/pip/src/state_header_template.html
@@ -1,7 +1,7 @@
 <table>
   <thead>
     <tr>
-      <th style="text-align: left">Basis State<br />(|𝜓ₙ…𝜓₁⟩)</th>
+      <th style="text-align: left">Basis State<br />(|𝜓₁…𝜓ₙ⟩)</th>
       <th style="text-align: left">Amplitude</th>
       <th style="text-align: left">Measurement Probability</th>
       <th style="text-align: left" colspan="2">Phase</th>
diff --git a/playground/src/state.tsx b/playground/src/state.tsx
index 5d613944..99830021 100644
--- a/playground/src/state.tsx
+++ b/playground/src/state.tsx
@@ -24,7 +24,7 @@ export function StateTable(props: { dump: Dump }) {
           <th>
             Basis State
             <br />
-            (|𝜓ₙ…𝜓₁⟩)
+            (|𝜓₁…𝜓ₙ⟩)
           </th>
           <th>Amplitude</th>
           <th>Measurement Probability</th>
diff --git a/samples/estimation/estimation-frontier-widgets.ipynb b/samples/estimation/estimation-frontier-widgets.ipynb
index f2eafe41..6cda95f1 100644
--- a/samples/estimation/estimation-frontier-widgets.ipynb
+++ b/samples/estimation/estimation-frontier-widgets.ipynb
@@ -2,12 +2,22 @@
  "cells": [
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 1,
    "metadata": {},
-   "outputs": [],
+   "outputs": [
+    {
+     "data": {
+      "application/javascript": "// Copyright (c) Microsoft Corporation.\n// Licensed under the MIT License.\n\n// This file provides CodeMirror syntax highlighting for Q# magic cells\n// in classic Jupyter Notebooks. It does nothing in other (Jupyter Notebook 7,\n// VS Code, Azure Notebooks, etc.) environments.\n\n// Detect the prerequisites and do nothing if they don't exist.\nif (window.require && window.CodeMirror && window.Jupyter) {\n  // The simple mode plugin for CodeMirror is not loaded by default, so require it.\n  window.require([\"codemirror/addon/mode/simple\"], function defineMode() {\n    let rules = [\n      {\n        token: \"comment\",\n        regex: /(\\/\\/).*/,\n        beginWord: false,\n      },\n      {\n        token: \"string\",\n        regex: String.raw`^\\\"(?:[^\\\"\\\\]|\\\\[\\s\\S])*(?:\\\"|$)`,\n        beginWord: false,\n      },\n      {\n        token: \"keyword\",\n        regex: String.raw`(namespace|open|as|operation|function|body|adjoint|newtype|controlled|internal)\\b`,\n        beginWord: true,\n      },\n      {\n        token: \"keyword\",\n        regex: String.raw`(if|elif|else|repeat|until|fixup|for|in|return|fail|within|apply)\\b`,\n        beginWord: true,\n      },\n      {\n        token: \"keyword\",\n        regex: String.raw`(Adjoint|Controlled|Adj|Ctl|is|self|auto|distribute|invert|intrinsic)\\b`,\n        beginWord: true,\n      },\n      {\n        token: \"keyword\",\n        regex: String.raw`(let|set|use|borrow|mutable)\\b`,\n        beginWord: true,\n      },\n      {\n        token: \"operatorKeyword\",\n        regex: String.raw`(not|and|or)\\b|(w/)`,\n        beginWord: true,\n      },\n      {\n        token: \"operatorKeyword\",\n        regex: String.raw`(=)|(!)|(<)|(>)|(\\+)|(-)|(\\*)|(/)|(\\^)|(%)|(\\|)|(&&&)|(~~~)|(\\.\\.\\.)|(\\.\\.)|(\\?)`,\n        beginWord: false,\n      },\n      {\n        token: \"meta\",\n        regex: String.raw`(Int|BigInt|Double|Bool|Qubit|Pauli|Result|Range|String|Unit)\\b`,\n        beginWord: true,\n      },\n      {\n        token: \"atom\",\n        regex: String.raw`(true|false|Pauli(I|X|Y|Z)|One|Zero)\\b`,\n        beginWord: true,\n      },\n    ];\n    let simpleRules = [];\n    for (let rule of rules) {\n      simpleRules.push({\n        token: rule.token,\n        regex: new RegExp(rule.regex, \"g\"),\n        sol: rule.beginWord,\n      });\n      if (rule.beginWord) {\n        // Need an additional rule due to the fact that CodeMirror simple mode doesn't work with ^ token\n        simpleRules.push({\n          token: rule.token,\n          regex: new RegExp(String.raw`\\W` + rule.regex, \"g\"),\n          sol: false,\n        });\n      }\n    }\n\n    // Register the mode defined above with CodeMirror\n    window.CodeMirror.defineSimpleMode(\"qsharp\", { start: simpleRules });\n    window.CodeMirror.defineMIME(\"text/x-qsharp\", \"qsharp\");\n\n    // Tell Jupyter to associate %%qsharp magic cells with the qsharp mode\n    window.Jupyter.CodeCell.options_default.highlight_modes[\"qsharp\"] = {\n      reg: [/^%%qsharp/],\n    };\n\n    // Force re-highlighting of all cells the first time this code runs\n    for (const cell of window.Jupyter.notebook.get_cells()) {\n      cell.auto_highlight();\n    }\n  });\n}\n",
+      "text/plain": []
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    }
+   ],
    "source": [
     "import qsharp\n",
-    "from qsharp_widgets import SpaceChart, EstimateDetails, EstimatesOverview\n",
+    "from qsharp_widgets import SpaceChart, EstimateDetails, EstimatesOverview, EstimatesPanel\n",
+    "\n",
     "with open(\"Dynamics.qs\", \"r\") as f:\n",
     "    contents = f.read()\n",
     "qsharp.eval(contents)"
@@ -15,7 +25,7 @@
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 34,
    "metadata": {},
    "outputs": [],
    "source": [
@@ -23,8 +33,24 @@
     "    \"QuantumDynamics.Main()\",\n",
     "    [\n",
     "        {\n",
+    "        \"qubitParams\": { \"name\": \"qubit_gate_ns_e3\" },\n",
+    "        \"estimateType\": \"frontier\",\n",
+    "        },\n",
+    "        {\n",
+    "        \"qubitParams\": { \"name\": \"qubit_gate_ns_e4\" },\n",
+    "        \"estimateType\": \"frontier\",\n",
+    "        },\n",
+    "        {\n",
+    "        \"qubitParams\": { \"name\": \"qubit_gate_us_e3\" },\n",
+    "        \"estimateType\": \"frontier\",\n",
+    "        },\n",
+    "        {\n",
+    "        \"qubitParams\": { \"name\": \"qubit_gate_us_e4\" },\n",
+    "        \"estimateType\": \"frontier\",\n",
+    "        },\n",
+    "        {\n",
     "        \"qubitParams\": { \"name\": \"qubit_maj_ns_e4\" },\n",
-    "        \"qecScheme\": { \"name\": \"surface_code\" },\n",
+    "        \"qecScheme\": { \"name\": \"floquet_code\" },\n",
     "        \"estimateType\": \"frontier\",\n",
     "        },\n",
     "        {\n",
@@ -33,30 +59,112 @@
     "        \"estimateType\": \"frontier\",\n",
     "        },\n",
     "    ]\n",
-    ")\n",
-    "\n",
-    "EstimatesOverview(result, colors=[\"#1f77b4\", \"#ff7f0e\"], runNames=[\"e4 Surface Code\", \"e6 Floquet Code\"])"
+    ")"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 40,
    "metadata": {},
-   "outputs": [],
+   "outputs": [
+    {
+     "data": {
+      "application/vnd.jupyter.widget-view+json": {
+       "model_id": "ad98b6f2e9dc4b748f0845751f903e1d",
+       "version_major": 2,
+       "version_minor": 0
+      },
+      "text/plain": [
+       "EstimatesPanel(estimates={0: {'status': 'success', 'jobParams': {'qecScheme': {'name': 'surface_code', 'errorC…"
+      ]
+     },
+     "execution_count": 40,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "# The full experience with the summary table, the space-time diagrams, the space diagrams, and the estimate details\n",
+    "EstimatesPanel(result)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 39,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "application/vnd.jupyter.widget-view+json": {
+       "model_id": "7b082ec4006b4134afe54c7e7068acb3",
+       "version_major": 2,
+       "version_minor": 0
+      },
+      "text/plain": [
+       "SpaceChart(estimates={'status': 'success', 'jobParams': {'qecScheme': {'name': 'surface_code', 'errorCorrectio…"
+      ]
+     },
+     "execution_count": 39,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
    "source": [
     "# Qubit usage diagram for the first (estimate index=0) run and the third (point index=2) shortest runtime\n",
-    "SpaceChart(result[0], 2)"
+    "SpaceChart(result[0],8)"
    ]
   },
   {
    "cell_type": "code",
-   "execution_count": null,
+   "execution_count": 37,
    "metadata": {},
-   "outputs": [],
+   "outputs": [
+    {
+     "data": {
+      "application/vnd.jupyter.widget-view+json": {
+       "model_id": "d3c556b135f84bf19770a6fe2c17b297",
+       "version_major": 2,
+       "version_minor": 0
+      },
+      "text/plain": [
+       "EstimateDetails(estimates={'status': 'success', 'jobParams': {'qecScheme': {'name': 'surface_code', 'errorCorr…"
+      ]
+     },
+     "execution_count": 37,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
    "source": [
     "# Estimate details usage for the second (estimate index=0) run and the fourth (point index=3) shortest runtime\n",
     "EstimateDetails(result[1], 4)"
    ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 36,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "application/vnd.jupyter.widget-view+json": {
+       "model_id": "88d4400236ed4f8ea65b32f803a19971",
+       "version_major": 2,
+       "version_minor": 0
+      },
+      "text/plain": [
+       "EstimatesOverview(colors=['#1f77b4', '#ff7f0e', 'blue', 'red', 'green', 'yellow'], estimates={0: {'status': 's…"
+      ]
+     },
+     "execution_count": 36,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "# Estimate overview with the summary table and the space-time diagram\n",
+    "EstimatesOverview(result, colors=[\"#1f77b4\", \"#ff7f0e\", \"blue\", \"red\", \"green\", \"yellow\"], runNames=[\"Gate ns e3, surface\", \"Gate ns e4, surface\", \"Gate us e3, surface\", \"Gate us e4, surface\", \"Majorana ns e4, floquet\", \"Majorana ns e6, floquet\"])"
+   ]
   }
  ],
  "metadata": {
diff --git a/vscode/src/webview/webview.tsx b/vscode/src/webview/webview.tsx
index 6468eb58..394af61b 100644
--- a/vscode/src/webview/webview.tsx
+++ b/vscode/src/webview/webview.tsx
@@ -6,9 +6,8 @@
 const vscodeApi = acquireVsCodeApi();
 
 import { render } from "preact";
-import { Histogram, type ReData } from "qsharp-lang/ux";
+import { EstimatesPanel, Histogram, type ReData } from "qsharp-lang/ux";
 import { HelpPage } from "./help";
-import { RePage } from "./rePage";
 
 // eslint-disable-next-line @typescript-eslint/ban-ts-comment
 // @ts-ignore - there are no types for this
@@ -154,11 +153,13 @@ function App({ state }: { state: State }) {
       );
     case "estimates":
       return (
-        <RePage
+        <EstimatesPanel
           calculating={state.estimatesData.calculating}
           estimatesData={state.estimatesData.estimates}
           renderer={markdownRenderer}
           onRowDeleted={onRowDeleted}
+          colors={[]}
+          runNames={[]}
         />
       );
     case "help":
diff --git a/vscode/src/webviewPanel.ts b/vscode/src/webviewPanel.ts
index 3e46f205..c9a2176b 100644
--- a/vscode/src/webviewPanel.ts
+++ b/vscode/src/webviewPanel.ts
@@ -234,10 +234,7 @@ export function registerWebViewCommands(context: ExtensionContext) {
         }
 
         (estimates as Array<any>).forEach(
-          (item, idx) =>
-            (item.jobParams.runName = `${runName} (${String.fromCharCode(
-              0x61 + idx,
-            )})`),
+          (item) => (item.jobParams.sharedRunName = runName),
         );
 
         clearTimeout(compilerTimeout);
diff --git a/widgets/js/index.tsx b/widgets/js/index.tsx
index a7c3d90b..f6a2b997 100644
--- a/widgets/js/index.tsx
+++ b/widgets/js/index.tsx
@@ -8,6 +8,8 @@ import {
   Histogram,
   CreateSingleEstimateResult,
   EstimatesOverview,
+  EstimatesPanel,
+  ReData,
 } from "qsharp-lang/ux";
 import markdownIt from "markdown-it";
 
@@ -48,6 +50,9 @@ export function render({ model, el }: RenderArgs) {
     case "Histogram":
       renderHistogram({ model, el });
       break;
+    case "EstimatesPanel":
+      renderEstimatesPanel({ model, el });
+      break;
     default:
       throw new Error(`Unknown component type ${componentType}`);
   }
@@ -91,7 +96,7 @@ function renderEstimatesOverview({ model, el }: RenderArgs) {
     const colors = model.get("colors");
     const runNames = model.get("runNames");
 
-    const estimates = [];
+    let estimates = [];
     if (results[0] == null) {
       estimates.push(results);
     } else {
@@ -100,13 +105,18 @@ function renderEstimatesOverview({ model, el }: RenderArgs) {
       }
     }
 
+    const onRowDeleted = createOnRowDeleted(estimates, (newEstimates) => {
+      estimates = newEstimates;
+      model.set("estimates", estimates);
+    });
+
     prender(
       <EstimatesOverview
         estimatesData={estimates}
         runNames={runNames}
         colors={colors}
         isSimplifiedView={true}
-        onRowDeleted={() => undefined}
+        onRowDeleted={onRowDeleted}
         setEstimate={() => undefined}
       ></EstimatesOverview>,
       el,
@@ -116,6 +126,66 @@ function renderEstimatesOverview({ model, el }: RenderArgs) {
   onChange();
   model.on("change:estimates", onChange);
   model.on("change:colors", onChange);
+  model.on("change:runNames", onChange);
+}
+
+function renderEstimatesPanel({ model, el }: RenderArgs) {
+  const onChange = () => {
+    const results = model.get("estimates");
+    const colors = model.get("colors");
+    const runNames = model.get("runNames");
+
+    let estimates: ReData[] = [];
+    if (results[0] == null) {
+      estimates.push(results);
+    } else {
+      for (const estimate of Object.values(results)) {
+        estimates.push(estimate as ReData);
+      }
+    }
+
+    const onRowDeleted = createOnRowDeleted(estimates, (newEstimates) => {
+      estimates = newEstimates;
+      model.set("estimates", estimates);
+    });
+
+    prender(
+      <EstimatesPanel
+        estimatesData={estimates}
+        runNames={runNames}
+        colors={colors}
+        renderer={mdRenderer}
+        calculating={false}
+        onRowDeleted={onRowDeleted}
+      ></EstimatesPanel>,
+      el,
+    );
+  };
+
+  onChange();
+  model.on("change:estimates", onChange);
+  model.on("change:colors", onChange);
+  model.on("change:runNames", onChange);
+}
+
+function createOnRowDeleted(
+  estimates: ReData[],
+  setEstimates: (estimates: ReData[]) => void,
+) {
+  return (rowId: string) => {
+    // Clone estimates into a new object
+    const newEstimates = JSON.parse(JSON.stringify(estimates)) as ReData[];
+
+    // Splice out the estimate that was deleted
+    const index = newEstimates.findIndex(
+      (estimate) => estimate.jobParams.runName === rowId,
+    );
+    if (index >= 0) {
+      newEstimates.splice(index, 1);
+    }
+
+    setEstimates(newEstimates);
+  };
 }
 
 function renderHistogram({ model, el }: RenderArgs) {
diff --git a/widgets/src/qsharp_widgets/__init__.py b/widgets/src/qsharp_widgets/__init__.py
index 09fceb23..bbc07462 100644
--- a/widgets/src/qsharp_widgets/__init__.py
+++ b/widgets/src/qsharp_widgets/__init__.py
@@ -62,6 +62,33 @@ class EstimatesOverview(anywidget.AnyWidget):
         self.runNames = [] if runNames is None else runNames
 
 
+class EstimatesPanel(anywidget.AnyWidget):
+    _esm = pathlib.Path(__file__).parent / "static" / "index.js"
+    _css = pathlib.Path(__file__).parent / "static" / "index.css"
+
+    comp = traitlets.Unicode("EstimatesPanel").tag(sync=True)
+    estimates = traitlets.Dict().tag(sync=True)
+    colors = traitlets.List().tag(sync=True)
+    runNames = traitlets.List().tag(sync=True)
+
+    def __init__(self, estimates, colors=None, runNames=None):
+        """
+        This function generates the whole estimates panel with the summary results table, ther space-time chart, the space chart and the details report.
+
+        Parameters:
+        - estimates: data for all the tables and diagrams.
+        - colors (optional): the list of colors which could be provided in the hex form or by name. If the length of the list does not match the number of the estimates, the colors parameter will be ignored and replaced with defaults.
+        - runNames (optional): the list of the run names. If the length of the list does not match the number of the estimates, the runNames parameter will be ignored and replaced with defaults.
+
+        Returns:
+        None
+        """
+        super().__init__()
+        self.estimates = estimates
+        self.colors = [] if colors is None else colors
+        self.runNames = [] if runNames is None else runNames
+
+
 class EstimateDetails(anywidget.AnyWidget):
     _esm = pathlib.Path(__file__).parent / "static" / "index.js"
     _css = pathlib.Path(__file__).parent / "static" / "index.css"


Test patch:
diff --git a/compiler/qsc/src/interpret/tests.rs b/compiler/qsc/src/interpret/tests.rs
index 1d9121df..693f1247 100644
--- a/compiler/qsc/src/interpret/tests.rs
+++ b/compiler/qsc/src/interpret/tests.rs
@@ -330,7 +330,7 @@ mod given_interpreter {
             let (result, output) = line(&mut interpreter, "X(q0); X(qs[1]);");
             is_only_value(&result, &output, &Value::unit());
             let (result, output) = line(&mut interpreter, "DumpMachine()");
-            is_unit_with_output(&result, &output, "STATE:\n|0101⟩: 1+0i");
+            is_unit_with_output(&result, &output, "STATE:\n|1010⟩: 1+0i");
         }
 
         #[test]
diff --git a/compiler/qsc_eval/src/intrinsic/tests.rs b/compiler/qsc_eval/src/intrinsic/tests.rs
index 4c05191d..502debc4 100644
--- a/compiler/qsc_eval/src/intrinsic/tests.rs
+++ b/compiler/qsc_eval/src/intrinsic/tests.rs
@@ -281,7 +281,7 @@ fn dump_machine_endianness() {
         }"},
         &expect![[r#"
             STATE:
-            |0010⟩: 1+0i
+            |0100⟩: 1+0i
         "#]],
     );
 }
@@ -1045,7 +1045,7 @@ fn qubit_nested_bind_not_released() {
         }"},
         &expect![[r#"
             STATE:
-            |10⟩: 1+0i
+            |01⟩: 1+0i
         "#]],
     );
 }
diff --git a/pip/tests/test_interpreter.py b/pip/tests/test_interpreter.py
index 9adbad8c..43c91276 100644
--- a/pip/tests/test_interpreter.py
+++ b/pip/tests/test_interpreter.py
@@ -34,7 +34,7 @@ def test_dump_output() -> None:
     def callback(output):
         nonlocal called
         called = True
-        assert output.__repr__() == "STATE:\n|01⟩: 1.0000+0.0000𝑖"
+        assert output.__repr__() == "STATE:\n|10⟩: 1.0000+0.0000𝑖"
 
     called = False
     value = e.interpret(
@@ -72,7 +72,7 @@ def test_dump_machine() -> None:
     e = Interpreter(TargetProfile.Unrestricted)
 
     def callback(output):
-        assert output.__repr__() == "STATE:\n|01⟩: 1.0000+0.0000𝑖"
+        assert output.__repr__() == "STATE:\n|10⟩: 1.0000+0.0000𝑖"
 
     value = e.interpret(
         """
@@ -86,11 +86,11 @@ def test_dump_machine() -> None:
     state_dump = e.dump_machine()
     assert state_dump.qubit_count == 2
     assert len(state_dump) == 1
-    assert state_dump[1][0] == 1.0
-    assert state_dump[1][1] == 0.0
+    assert state_dump[2][0] == 1.0
+    assert state_dump[2][1] == 0.0
     state_dict = state_dump.get_dict()
-    assert state_dict[1][0] == 1.0
-    assert state_dict[1][1] == 0.0
+    assert state_dict[2][0] == 1.0
+    assert state_dict[2][1] == 0.0
 
 
 def test_error() -> None:
diff --git a/pip/tests/test_qsharp.py b/pip/tests/test_qsharp.py
index e20848bc..574603c4 100644
--- a/pip/tests/test_qsharp.py
+++ b/pip/tests/test_qsharp.py
@@ -72,7 +72,7 @@ def test_dump_machine() -> None:
     state_dump = qsharp.dump_machine()
     assert state_dump.qubit_count == 2
     assert len(state_dump) == 1
-    assert state_dump[1] == (1.0, 0.0)
+    assert state_dump[2] == (1.0, 0.0)
     qsharp.eval("X(q2);")
     state_dump = qsharp.dump_machine()
     assert state_dump.qubit_count == 2
@@ -87,12 +87,33 @@ def test_dump_operation() -> None:
     res = qsharp.utils.dump_operation("qs => H(qs[0])", 1)
     assert res == [[complex(0.707107, 0.0), complex(0.707107, 0.0)],
                    [complex(0.707107, 0.0), complex(-0.707107, 0.0)]]
+    res = qsharp.utils.dump_operation("qs => CNOT(qs[0], qs[1])", 2)
+    assert res == [[complex(1.0, 0.0), complex(0.0, 0.0), complex(0.0, 0.0), complex(0.0, 0.0)],
+                   [complex(0.0, 0.0), complex(1.0, 0.0), complex(0.0, 0.0), complex(0.0, 0.0)],
+                   [complex(0.0, 0.0), complex(0.0, 0.0), complex(0.0, 0.0), complex(1.0, 0.0)],
+                   [complex(0.0, 0.0), complex(0.0, 0.0), complex(1.0, 0.0), complex(0.0, 0.0)]]
+    res = qsharp.utils.dump_operation("qs => CCNOT(qs[0], qs[1], qs[2])", 3)
+    assert res == [[complex(1.0, 0.0), complex(0.0, 0.0), complex(0.0, 0.0), complex(0.0, 0.0), complex(0.0, 0.0), complex(0.0, 0.0), complex(0.0, 0.0), complex(0.0, 0.0)],
+                   [complex(0.0, 0.0), complex(1.0, 0.0), complex(0.0, 0.0), complex(0.0, 0.0), complex(0.0, 0.0), complex(0.0, 0.0), complex(0.0, 0.0), complex(0.0, 0.0)],
+                   [complex(0.0, 0.0), complex(0.0, 0.0), complex(1.0, 0.0), complex(0.0, 0.0), complex(0.0, 0.0), complex(0.0, 0.0), complex(0.0, 0.0), complex(0.0, 0.0)],
+                   [complex(0.0, 0.0), complex(0.0, 0.0), complex(0.0, 0.0), complex(1.0, 0.0), complex(0.0, 0.0), complex(0.0, 0.0), complex(0.0, 0.0), complex(0.0, 0.0)],
+                   [complex(0.0, 0.0), complex(0.0, 0.0), complex(0.0, 0.0), complex(0.0, 0.0), complex(1.0, 0.0), complex(0.0, 0.0), complex(0.0, 0.0), complex(0.0, 0.0)],
+                   [complex(0.0, 0.0), complex(0.0, 0.0), complex(0.0, 0.0), complex(0.0, 0.0), complex(0.0, 0.0), complex(1.0, 0.0), complex(0.0, 0.0), complex(0.0, 0.0)],
+                   [complex(0.0, 0.0), complex(0.0, 0.0), complex(0.0, 0.0), complex(0.0, 0.0), complex(0.0, 0.0), complex(0.0, 0.0), complex(0.0, 0.0), complex(1.0, 0.0)],
+                   [complex(0.0, 0.0), complex(0.0, 0.0), complex(0.0, 0.0), complex(0.0, 0.0), complex(0.0, 0.0), complex(0.0, 0.0), complex(1.0, 0.0), complex(0.0, 0.0)]]
     qsharp.eval("operation ApplySWAP(qs : Qubit[]) : Unit { SWAP(qs[0], qs[1]); }")
     res = qsharp.utils.dump_operation("ApplySWAP", 2)
     assert res == [[complex(1.0, 0.0), complex(0.0, 0.0), complex(0.0, 0.0), complex(0.0, 0.0)],
                    [complex(0.0, 0.0), complex(0.0, 0.0), complex(1.0, 0.0), complex(0.0, 0.0)],
                    [complex(0.0, 0.0), complex(1.0, 0.0), complex(0.0, 0.0), complex(0.0, 0.0)],
                    [complex(0.0, 0.0), complex(0.0, 0.0), complex(0.0, 0.0), complex(1.0, 0.0)]]
+    res = qsharp.utils.dump_operation("qs => ()", 8)
+    for i in range(8):
+        for j in range(8):
+            if i == j:
+                assert res[i][j] == complex(1.0, 0.0)
+            else:
+                assert res[i][j] == complex(0.0, 0.0)
 
 
 def test_compile_qir_input_data() -> None: