Repository: grafana/grafana-plugin-sdk-go (go)

Issue:
Improve the meta test comparision for golden files
When trying to test with a custom meta object the test fails because the object is not compared to the same type it can load from JSON:

```
               Meta: &data.FrameMeta{
        - 		Custom: map[string]interface{}{
        - 			"finishTime": float64(2222),
        - 			"queryId":    string("$queryId$"),
        - 			"startTime":  float64(1111),
        - 		},
        + 		Custom:  &models.TimestreamCustomMeta{StartTime: 1111, FinishTime: 2222, QueryID: "$queryId$"},
          		Stats:   nil,
```

Pull request:
GoldenDataChecker: frame meta comparison test
<!--

Thank you for sending a pull request! Here are some tips:

1. If this is your first time, please read our contribution guide at https://github.com/grafana/grafana-plugin-sdk-go/blob/master/CONTRIBUTING.md

2. Ensure you include and run the appropriate tests as part of your Pull Request.

3. If the Pull Request is a work in progress, make use of GitHub's "Draft PR" feature and mark it as such.

4. If you can not merge your Pull Request due to a merge conflict, Rebase it. This gets it in sync with the master branch.

-->

**What this PR does / why we need it**:

Adds frame meta comparison for Golden file testing.

**Which issue(s) this PR fixes**:

<!--

* Automatically closes linked issue when the Pull Request is merged.

Usage: "Fixes #<issue number>", or "Fixes (paste link of issue)"

-->

Fixes #213 


Patch:
diff --git a/data/frame.go b/data/frame.go
index a87069c..eae9d7b 100644
--- a/data/frame.go
+++ b/data/frame.go
@@ -10,6 +10,8 @@
 package data
 
 import (
+	"bytes"
+	"encoding/json"
 	"fmt"
 	"math"
 	"reflect"
@@ -386,8 +388,21 @@ func FrameTestCompareOptions() []cmp.Option {
 		return true
 	})
 
+	metas := cmp.Comparer(func(x, y *FrameMeta) bool {
+		// This checks that the meta attached to the frame and
+		// in the Golden file are the same. A conversion to JSON
+		// representation is needed for the Custom field within
+		// the meta where a custom struct{} cannot be directly
+		// compared for equality to a map[string]interface{}{}
+		// but a JSON byte representation of those is equivalent
+		xJSON, _ := json.Marshal(x)
+		yJSON, _ := json.Marshal(y)
+
+		return bytes.Equal(xJSON, yJSON)
+	})
+
 	unexportedField := cmp.AllowUnexported(Field{})
-	return []cmp.Option{f32s, f32Ptrs, f64s, f64Ptrs, confFloats, times, unexportedField, cmpopts.EquateEmpty()}
+	return []cmp.Option{f32s, f32Ptrs, f64s, f64Ptrs, confFloats, times, metas, unexportedField, cmpopts.EquateEmpty()}
 }
 
 const maxLengthExceededStr = "..."


Test patch:
diff --git a/experimental/golden_response_checker_test.go b/experimental/golden_response_checker_test.go
index 093260e..8016f1a 100644
--- a/experimental/golden_response_checker_test.go
+++ b/experimental/golden_response_checker_test.go
@@ -7,14 +7,19 @@ import (
 
 	"github.com/grafana/grafana-plugin-sdk-go/backend"
 	"github.com/grafana/grafana-plugin-sdk-go/data"
+	"github.com/stretchr/testify/require"
 )
 
+// some sample custom meta
+type SomeCustomMeta struct {
+	SomeValue string `json:"someValue,omitempty"`
+}
+
 var update = flag.Bool("update", false, "update.golden.data files")
 
 func TestGoldenResponseChecker(t *testing.T) {
 	dr := &backend.DataResponse{}
 
-	//	frame := data.GoldenDF() ????
 	dr.Frames = data.Frames{
 		data.NewFrame("Frame One",
 			data.NewField("Single float64", nil, []float64{
@@ -27,17 +32,49 @@ func TestGoldenResponseChecker(t *testing.T) {
 			}).SetConfig(&data.FieldConfig{DisplayName: "123"}),
 		),
 	}
-	dr.Frames[0].Meta = &data.FrameMeta{
-		ExecutedQueryString: "SELECT * FROM X",
-		Notices: []data.Notice{
-			{Severity: data.NoticeSeverityInfo, Text: "hello"},
-		},
-	}
 
-	goldenFile := filepath.Join("testdata", "sample.golden.txt")
+	t.Run("create data frames with no meta", func(t *testing.T) {
+		goldenFile := filepath.Join("testdata", "frame-no-meta.golden.txt")
+		err := CheckGoldenDataResponse(goldenFile, dr, *update)
 
-	err := CheckGoldenDataResponse(goldenFile, dr, *update)
-	if err != nil {
-		t.Error(err)
-	}
+		require.NoError(t, err)
+	})
+
+	t.Run("create data frames with some non-custom meta", func(t *testing.T) {
+		dr.Frames[0].Meta = &data.FrameMeta{
+			ExecutedQueryString: "SELECT * FROM X",
+			Notices: []data.Notice{
+				{Severity: data.NoticeSeverityInfo, Text: "hello"},
+			},
+		}
+
+		goldenFile := filepath.Join("testdata", "frame-non-custom-meta.golden.txt")
+		err := CheckGoldenDataResponse(goldenFile, dr, *update)
+
+		require.NoError(t, err)
+	})
+
+	t.Run("create data frames with some empty custom meta", func(t *testing.T) {
+		dr.Frames[0].Meta = &data.FrameMeta{
+			Custom: SomeCustomMeta{},
+		}
+
+		goldenFile := filepath.Join("testdata", "frame-empty-custom-meta.golden.txt")
+		err := CheckGoldenDataResponse(goldenFile, dr, true)
+
+		require.NoError(t, err)
+	})
+
+	t.Run("create data frames with some custom meta", func(t *testing.T) {
+		dr.Frames[0].Meta = &data.FrameMeta{
+			Custom: SomeCustomMeta{
+				SomeValue: "value",
+			},
+		}
+
+		goldenFile := filepath.Join("testdata", "frame-custom-meta.golden.txt")
+		err := CheckGoldenDataResponse(goldenFile, dr, true)
+
+		require.NoError(t, err)
+	})
 }
diff --git a/experimental/testdata/frame-custom-meta.golden.txt b/experimental/testdata/frame-custom-meta.golden.txt
new file mode 100644
index 0000000..7679870
--- /dev/null
+++ b/experimental/testdata/frame-custom-meta.golden.txt
@@ -0,0 +1,40 @@
+🌟 This was machine generated.  Do not edit. 🌟
+
+Frame[0] {
+    "custom": {
+        "someValue": "value"
+    }
+}
+Name: Frame One
+Dimensions: 1 Fields by 5 Rows
++----------------------+
+| Name: Single float64 |
+| Labels:              |
+| Type: []float64      |
++----------------------+
+| 8.26                 |
+| 8.7                  |
+| 14.82                |
+| 10.07                |
+| 8.52                 |
++----------------------+
+
+
+
+Frame[1] 
+Name: Frame Two
+Dimensions: 1 Fields by 3 Rows
++---------------------+
+| Name: single string |
+| Labels: a=b         |
+| Type: []string      |
++---------------------+
+| a                   |
+| b                   |
+| c                   |
++---------------------+
+
+
+====== TEST DATA RESPONSE (arrow base64) ======
+FRAME=QVJST1cxAAD/////mAEAABAAAAAAAAoADgAMAAsABAAKAAAAFAAAAAAAAAEDAAoADAAAAAgABAAKAAAACAAAAJwAAAADAAAAVAAAACgAAAAEAAAADP///wgAAAAMAAAAAAAAAAAAAAAFAAAAcmVmSWQAAAAs////CAAAABQAAAAJAAAARnJhbWUgT25lAAAABAAAAG5hbWUAAAAAVP///wgAAAAsAAAAIAAAAHsiY3VzdG9tIjp7InNvbWVWYWx1ZSI6InZhbHVlIn19AAAAAAQAAABtZXRhAAAAAAEAAAAYAAAAAAASABgAFAAAABMADAAAAAgABAASAAAAFAAAAIAAAACIAAAAAAAAA4gAAAACAAAAPAAAAAQAAADU////CAAAABgAAAAOAAAAU2luZ2xlIGZsb2F0NjQAAAQAAABuYW1lAAAAAAgADAAIAAQACAAAAAgAAAAcAAAAEgAAAHsidW5pdCI6IlBlcmNlbnQifQAABgAAAGNvbmZpZwAAAAAAAAAABgAIAAYABgAAAAAAAgAOAAAAU2luZ2xlIGZsb2F0NjQAAP////+IAAAAFAAAAAAAAAAMABYAFAATAAwABAAMAAAAKAAAAAAAAAAUAAAAAAAAAwMACgAYAAwACAAEAAoAAAAUAAAAOAAAAAUAAAAAAAAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAAAAAAAABAAAABQAAAAAAAAAAAAAAAAAAAIXrUbgehSBAZmZmZmZmIUCkcD0K16MtQKRwPQrXIyRACtejcD0KIUAQAAAADAAUABIADAAIAAQADAAAABAAAAAsAAAAPAAAAAAAAwABAAAAqAEAAAAAAACQAAAAAAAAACgAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAwAAAAIAAQACgAAAAgAAACcAAAAAwAAAFQAAAAoAAAABAAAAAz///8IAAAADAAAAAAAAAAAAAAABQAAAHJlZklkAAAALP///wgAAAAUAAAACQAAAEZyYW1lIE9uZQAAAAQAAABuYW1lAAAAAFT///8IAAAALAAAACAAAAB7ImN1c3RvbSI6eyJzb21lVmFsdWUiOiJ2YWx1ZSJ9fQAAAAAEAAAAbWV0YQAAAAABAAAAGAAAAAAAEgAYABQAAAATAAwAAAAIAAQAEgAAABQAAACAAAAAiAAAAAAAAAOIAAAAAgAAADwAAAAEAAAA1P///wgAAAAYAAAADgAAAFNpbmdsZSBmbG9hdDY0AAAEAAAAbmFtZQAAAAAIAAwACAAEAAgAAAAIAAAAHAAAABIAAAB7InVuaXQiOiJQZXJjZW50In0AAAYAAABjb25maWcAAAAAAAAAAAYACAAGAAYAAAAAAAIADgAAAFNpbmdsZSBmbG9hdDY0AADIAQAAQVJST1cx
+FRAME=QVJST1cxAAD/////gAEAABAAAAAAAAoADgAMAAsABAAKAAAAFAAAAAAAAAEDAAoADAAAAAgABAAKAAAACAAAAFgAAAACAAAAKAAAAAQAAAAg////CAAAAAwAAAAAAAAAAAAAAAUAAAByZWZJZAAAAED///8IAAAAFAAAAAkAAABGcmFtZSBUd28AAAAEAAAAbmFtZQAAAAABAAAAGAAAAAAAEgAYABQAAAATAAwAAAAIAAQAEgAAABQAAACwAAAAtAAAAAAAAAWwAAAAAwAAAGgAAAA0AAAABAAAAKz///8IAAAAGAAAAA0AAABzaW5nbGUgc3RyaW5nAAAABAAAAG5hbWUAAAAA2P///wgAAAAUAAAACQAAAHsiYSI6ImIifQAAAAYAAABsYWJlbHMAAAgADAAIAAQACAAAAAgAAAAgAAAAFQAAAHsiZGlzcGxheU5hbWUiOiIxMjMifQAAAAYAAABjb25maWcAAAAAAAAEAAQABAAAAA0AAABzaW5nbGUgc3RyaW5nAAAAAAAAAP////+YAAAAFAAAAAAAAAAMABYAFAATAAwABAAMAAAAGAAAAAAAAAAUAAAAAAAAAwMACgAYAAwACAAEAAoAAAAUAAAASAAAAAMAAAAAAAAAAAAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAABAAAAAAAAAACAAAAAAAAAAAAAAAAQAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAIAAAADAAAAYWJjAAAAAAAQAAAADAAUABIADAAIAAQADAAAABAAAAAsAAAAOAAAAAAAAwABAAAAkAEAAAAAAACgAAAAAAAAABgAAAAAAAAAAAAAAAAAAAAAAAoADAAAAAgABAAKAAAACAAAAFgAAAACAAAAKAAAAAQAAAAg////CAAAAAwAAAAAAAAAAAAAAAUAAAByZWZJZAAAAED///8IAAAAFAAAAAkAAABGcmFtZSBUd28AAAAEAAAAbmFtZQAAAAABAAAAGAAAAAAAEgAYABQAAAATAAwAAAAIAAQAEgAAABQAAACwAAAAtAAAAAAAAAWwAAAAAwAAAGgAAAA0AAAABAAAAKz///8IAAAAGAAAAA0AAABzaW5nbGUgc3RyaW5nAAAABAAAAG5hbWUAAAAA2P///wgAAAAUAAAACQAAAHsiYSI6ImIifQAAAAYAAABsYWJlbHMAAAgADAAIAAQACAAAAAgAAAAgAAAAFQAAAHsiZGlzcGxheU5hbWUiOiIxMjMifQAAAAYAAABjb25maWcAAAAAAAAEAAQABAAAAA0AAABzaW5nbGUgc3RyaW5nAAAAqAEAAEFSUk9XMQ==
diff --git a/experimental/testdata/frame-empty-custom-meta.golden.txt b/experimental/testdata/frame-empty-custom-meta.golden.txt
new file mode 100644
index 0000000..f68679c
--- /dev/null
+++ b/experimental/testdata/frame-empty-custom-meta.golden.txt
@@ -0,0 +1,38 @@
+🌟 This was machine generated.  Do not edit. 🌟
+
+Frame[0] {
+    "custom": {}
+}
+Name: Frame One
+Dimensions: 1 Fields by 5 Rows
++----------------------+
+| Name: Single float64 |
+| Labels:              |
+| Type: []float64      |
++----------------------+
+| 8.26                 |
+| 8.7                  |
+| 14.82                |
+| 10.07                |
+| 8.52                 |
++----------------------+
+
+
+
+Frame[1] 
+Name: Frame Two
+Dimensions: 1 Fields by 3 Rows
++---------------------+
+| Name: single string |
+| Labels: a=b         |
+| Type: []string      |
++---------------------+
+| a                   |
+| b                   |
+| c                   |
++---------------------+
+
+
+====== TEST DATA RESPONSE (arrow base64) ======
+FRAME=QVJST1cxAAD/////iAEAABAAAAAAAAoADgAMAAsABAAKAAAAFAAAAAAAAAEDAAoADAAAAAgABAAKAAAACAAAAIgAAAADAAAAVAAAACgAAAAEAAAAIP///wgAAAAMAAAAAAAAAAAAAAAFAAAAcmVmSWQAAABA////CAAAABQAAAAJAAAARnJhbWUgT25lAAAABAAAAG5hbWUAAAAAaP///wgAAAAYAAAADQAAAHsiY3VzdG9tIjp7fX0AAAAEAAAAbWV0YQAAAAABAAAAGAAAAAAAEgAYABQAAAATAAwAAAAIAAQAEgAAABQAAACAAAAAiAAAAAAAAAOIAAAAAgAAADwAAAAEAAAA1P///wgAAAAYAAAADgAAAFNpbmdsZSBmbG9hdDY0AAAEAAAAbmFtZQAAAAAIAAwACAAEAAgAAAAIAAAAHAAAABIAAAB7InVuaXQiOiJQZXJjZW50In0AAAYAAABjb25maWcAAAAAAAAAAAYACAAGAAYAAAAAAAIADgAAAFNpbmdsZSBmbG9hdDY0AAAAAAAA/////4gAAAAUAAAAAAAAAAwAFgAUABMADAAEAAwAAAAoAAAAAAAAABQAAAAAAAADAwAKABgADAAIAAQACgAAABQAAAA4AAAABQAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAAAAAAAAAAAAEAAAAFAAAAAAAAAAAAAAAAAAAAhetRuB6FIEBmZmZmZmYhQKRwPQrXoy1ApHA9CtcjJEAK16NwPQohQBAAAAAMABQAEgAMAAgABAAMAAAAEAAAACwAAAA4AAAAAAADAAEAAACYAQAAAAAAAJAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAAACgAMAAAACAAEAAoAAAAIAAAAiAAAAAMAAABUAAAAKAAAAAQAAAAg////CAAAAAwAAAAAAAAAAAAAAAUAAAByZWZJZAAAAED///8IAAAAFAAAAAkAAABGcmFtZSBPbmUAAAAEAAAAbmFtZQAAAABo////CAAAABgAAAANAAAAeyJjdXN0b20iOnt9fQAAAAQAAABtZXRhAAAAAAEAAAAYAAAAAAASABgAFAAAABMADAAAAAgABAASAAAAFAAAAIAAAACIAAAAAAAAA4gAAAACAAAAPAAAAAQAAADU////CAAAABgAAAAOAAAAU2luZ2xlIGZsb2F0NjQAAAQAAABuYW1lAAAAAAgADAAIAAQACAAAAAgAAAAcAAAAEgAAAHsidW5pdCI6IlBlcmNlbnQifQAABgAAAGNvbmZpZwAAAAAAAAAABgAIAAYABgAAAAAAAgAOAAAAU2luZ2xlIGZsb2F0NjQAALABAABBUlJPVzE=
+FRAME=QVJST1cxAAD/////gAEAABAAAAAAAAoADgAMAAsABAAKAAAAFAAAAAAAAAEDAAoADAAAAAgABAAKAAAACAAAAFgAAAACAAAAKAAAAAQAAAAg////CAAAAAwAAAAAAAAAAAAAAAUAAAByZWZJZAAAAED///8IAAAAFAAAAAkAAABGcmFtZSBUd28AAAAEAAAAbmFtZQAAAAABAAAAGAAAAAAAEgAYABQAAAATAAwAAAAIAAQAEgAAABQAAACwAAAAtAAAAAAAAAWwAAAAAwAAAGgAAAA0AAAABAAAAKz///8IAAAAGAAAAA0AAABzaW5nbGUgc3RyaW5nAAAABAAAAG5hbWUAAAAA2P///wgAAAAUAAAACQAAAHsiYSI6ImIifQAAAAYAAABsYWJlbHMAAAgADAAIAAQACAAAAAgAAAAgAAAAFQAAAHsiZGlzcGxheU5hbWUiOiIxMjMifQAAAAYAAABjb25maWcAAAAAAAAEAAQABAAAAA0AAABzaW5nbGUgc3RyaW5nAAAAAAAAAP////+YAAAAFAAAAAAAAAAMABYAFAATAAwABAAMAAAAGAAAAAAAAAAUAAAAAAAAAwMACgAYAAwACAAEAAoAAAAUAAAASAAAAAMAAAAAAAAAAAAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAABAAAAAAAAAACAAAAAAAAAAAAAAAAQAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAIAAAADAAAAYWJjAAAAAAAQAAAADAAUABIADAAIAAQADAAAABAAAAAsAAAAOAAAAAAAAwABAAAAkAEAAAAAAACgAAAAAAAAABgAAAAAAAAAAAAAAAAAAAAAAAoADAAAAAgABAAKAAAACAAAAFgAAAACAAAAKAAAAAQAAAAg////CAAAAAwAAAAAAAAAAAAAAAUAAAByZWZJZAAAAED///8IAAAAFAAAAAkAAABGcmFtZSBUd28AAAAEAAAAbmFtZQAAAAABAAAAGAAAAAAAEgAYABQAAAATAAwAAAAIAAQAEgAAABQAAACwAAAAtAAAAAAAAAWwAAAAAwAAAGgAAAA0AAAABAAAAKz///8IAAAAGAAAAA0AAABzaW5nbGUgc3RyaW5nAAAABAAAAG5hbWUAAAAA2P///wgAAAAUAAAACQAAAHsiYSI6ImIifQAAAAYAAABsYWJlbHMAAAgADAAIAAQACAAAAAgAAAAgAAAAFQAAAHsiZGlzcGxheU5hbWUiOiIxMjMifQAAAAYAAABjb25maWcAAAAAAAAEAAQABAAAAA0AAABzaW5nbGUgc3RyaW5nAAAAqAEAAEFSUk9XMQ==
diff --git a/experimental/testdata/frame-no-meta.golden.txt b/experimental/testdata/frame-no-meta.golden.txt
new file mode 100644
index 0000000..ab97cca
--- /dev/null
+++ b/experimental/testdata/frame-no-meta.golden.txt
@@ -0,0 +1,36 @@
+🌟 This was machine generated.  Do not edit. 🌟
+
+Frame[0] 
+Name: Frame One
+Dimensions: 1 Fields by 5 Rows
++----------------------+
+| Name: Single float64 |
+| Labels:              |
+| Type: []float64      |
++----------------------+
+| 8.26                 |
+| 8.7                  |
+| 14.82                |
+| 10.07                |
+| 8.52                 |
++----------------------+
+
+
+
+Frame[1] 
+Name: Frame Two
+Dimensions: 1 Fields by 3 Rows
++---------------------+
+| Name: single string |
+| Labels: a=b         |
+| Type: []string      |
++---------------------+
+| a                   |
+| b                   |
+| c                   |
++---------------------+
+
+
+====== TEST DATA RESPONSE (arrow base64) ======
+FRAME=QVJST1cxAAD/////WAEAABAAAAAAAAoADgAMAAsABAAKAAAAFAAAAAAAAAEDAAoADAAAAAgABAAKAAAACAAAAFgAAAACAAAAKAAAAAQAAABM////CAAAAAwAAAAAAAAAAAAAAAUAAAByZWZJZAAAAGz///8IAAAAFAAAAAkAAABGcmFtZSBPbmUAAAAEAAAAbmFtZQAAAAABAAAAGAAAAAAAEgAYABQAAAATAAwAAAAIAAQAEgAAABQAAACAAAAAiAAAAAAAAAOIAAAAAgAAADwAAAAEAAAA1P///wgAAAAYAAAADgAAAFNpbmdsZSBmbG9hdDY0AAAEAAAAbmFtZQAAAAAIAAwACAAEAAgAAAAIAAAAHAAAABIAAAB7InVuaXQiOiJQZXJjZW50In0AAAYAAABjb25maWcAAAAAAAAAAAYACAAGAAYAAAAAAAIADgAAAFNpbmdsZSBmbG9hdDY0AAAAAAAA/////4gAAAAUAAAAAAAAAAwAFgAUABMADAAEAAwAAAAoAAAAAAAAABQAAAAAAAADAwAKABgADAAIAAQACgAAABQAAAA4AAAABQAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAAAAAAAAAAAAEAAAAFAAAAAAAAAAAAAAAAAAAAhetRuB6FIEBmZmZmZmYhQKRwPQrXoy1ApHA9CtcjJEAK16NwPQohQBAAAAAMABQAEgAMAAgABAAMAAAAEAAAACwAAAA4AAAAAAADAAEAAABoAQAAAAAAAJAAAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAAACgAMAAAACAAEAAoAAAAIAAAAWAAAAAIAAAAoAAAABAAAAEz///8IAAAADAAAAAAAAAAAAAAABQAAAHJlZklkAAAAbP///wgAAAAUAAAACQAAAEZyYW1lIE9uZQAAAAQAAABuYW1lAAAAAAEAAAAYAAAAAAASABgAFAAAABMADAAAAAgABAASAAAAFAAAAIAAAACIAAAAAAAAA4gAAAACAAAAPAAAAAQAAADU////CAAAABgAAAAOAAAAU2luZ2xlIGZsb2F0NjQAAAQAAABuYW1lAAAAAAgADAAIAAQACAAAAAgAAAAcAAAAEgAAAHsidW5pdCI6IlBlcmNlbnQifQAABgAAAGNvbmZpZwAAAAAAAAAABgAIAAYABgAAAAAAAgAOAAAAU2luZ2xlIGZsb2F0NjQAAIABAABBUlJPVzE=
+FRAME=QVJST1cxAAD/////gAEAABAAAAAAAAoADgAMAAsABAAKAAAAFAAAAAAAAAEDAAoADAAAAAgABAAKAAAACAAAAFgAAAACAAAAKAAAAAQAAAAg////CAAAAAwAAAAAAAAAAAAAAAUAAAByZWZJZAAAAED///8IAAAAFAAAAAkAAABGcmFtZSBUd28AAAAEAAAAbmFtZQAAAAABAAAAGAAAAAAAEgAYABQAAAATAAwAAAAIAAQAEgAAABQAAACwAAAAtAAAAAAAAAWwAAAAAwAAAGgAAAA0AAAABAAAAKz///8IAAAAGAAAAA0AAABzaW5nbGUgc3RyaW5nAAAABAAAAG5hbWUAAAAA2P///wgAAAAUAAAACQAAAHsiYSI6ImIifQAAAAYAAABsYWJlbHMAAAgADAAIAAQACAAAAAgAAAAgAAAAFQAAAHsiZGlzcGxheU5hbWUiOiIxMjMifQAAAAYAAABjb25maWcAAAAAAAAEAAQABAAAAA0AAABzaW5nbGUgc3RyaW5nAAAAAAAAAP////+YAAAAFAAAAAAAAAAMABYAFAATAAwABAAMAAAAGAAAAAAAAAAUAAAAAAAAAwMACgAYAAwACAAEAAoAAAAUAAAASAAAAAMAAAAAAAAAAAAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAABAAAAAAAAAACAAAAAAAAAAAAAAAAQAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAIAAAADAAAAYWJjAAAAAAAQAAAADAAUABIADAAIAAQADAAAABAAAAAsAAAAOAAAAAAAAwABAAAAkAEAAAAAAACgAAAAAAAAABgAAAAAAAAAAAAAAAAAAAAAAAoADAAAAAgABAAKAAAACAAAAFgAAAACAAAAKAAAAAQAAAAg////CAAAAAwAAAAAAAAAAAAAAAUAAAByZWZJZAAAAED///8IAAAAFAAAAAkAAABGcmFtZSBUd28AAAAEAAAAbmFtZQAAAAABAAAAGAAAAAAAEgAYABQAAAATAAwAAAAIAAQAEgAAABQAAACwAAAAtAAAAAAAAAWwAAAAAwAAAGgAAAA0AAAABAAAAKz///8IAAAAGAAAAA0AAABzaW5nbGUgc3RyaW5nAAAABAAAAG5hbWUAAAAA2P///wgAAAAUAAAACQAAAHsiYSI6ImIifQAAAAYAAABsYWJlbHMAAAgADAAIAAQACAAAAAgAAAAgAAAAFQAAAHsiZGlzcGxheU5hbWUiOiIxMjMifQAAAAYAAABjb25maWcAAAAAAAAEAAQABAAAAA0AAABzaW5nbGUgc3RyaW5nAAAAqAEAAEFSUk9XMQ==