diff --git a/.github/ISSUE_TEMPLATE/Accessibility.md b/.github/ISSUE_TEMPLATE/Accessibility.md
index 1323e2c17e78..97fc17d28a94 100644
--- a/.github/ISSUE_TEMPLATE/Accessibility.md
+++ b/.github/ISSUE_TEMPLATE/Accessibility.md
@@ -35,12 +35,12 @@ What can we do to fix the issue?
Check off any platforms that are affected by this issue
--->
Which of our officially supported platforms is this issue occurring on? Please only tick the box if you have provided a screen-recording in the thread for each platform:
-- [ ] Android / native
-- [ ] Android / Chrome
-- [ ] iOS / native
-- [ ] iOS / Safari
-- [ ] MacOS / Chrome / Safari
-- [ ] MacOS / Desktop
+- [ ] Android: Native
+- [ ] Android: mWeb Chrome
+- [ ] iOS: Native
+- [ ] iOS: mWeb Safari
+- [ ] MacOS: Chrome / Safari
+- [ ] MacOS: Desktop
**Version Number:**
**Reproducible in staging?:**
diff --git a/.github/ISSUE_TEMPLATE/Performance.md b/.github/ISSUE_TEMPLATE/Performance.md
index 67b2e6971874..bbb729e8af31 100644
--- a/.github/ISSUE_TEMPLATE/Performance.md
+++ b/.github/ISSUE_TEMPLATE/Performance.md
@@ -28,12 +28,12 @@ Note: These should be the same as the benchmarks collected before any changes.
Check off any platforms that are affected by this issue
--->
Which of our officially supported platforms is this issue occurring on?
-- [ ] Android / native
-- [ ] Android / Chrome
-- [ ] iOS / native
-- [ ] iOS / Safari
-- [ ] MacOS / Chrome / Safari
-- [ ] MacOS / Desktop
+- [ ] Android: Native
+- [ ] Android: mWeb Chrome
+- [ ] iOS: Native
+- [ ] iOS: mWeb Safari
+- [ ] MacOS: Chrome / Safari
+- [ ] MacOS: Desktop
**Version Number:**
**Reproducible in staging?:**
diff --git a/.github/ISSUE_TEMPLATE/Standard.md b/.github/ISSUE_TEMPLATE/Standard.md
index 39d1c38fa56f..5e0e3633f3bc 100644
--- a/.github/ISSUE_TEMPLATE/Standard.md
+++ b/.github/ISSUE_TEMPLATE/Standard.md
@@ -7,6 +7,16 @@ labels: Bug, Daily
If you haven’t already, check out our [contributing guidelines](https://github.com/Expensify/ReactNativeChat/blob/main/contributingGuides/CONTRIBUTING.md) for onboarding and email contributors@expensify.com to request to join our Slack channel!
___
+**Version Number:**
+**Reproducible in staging?:**
+**Reproducible in production?:**
+**If this was caught during regression testing, add the test name, ID and link from TestRail:**
+**Email or phone of affected tester (no customers):**
+**Logs:** https://stackoverflow.com/c/expensify/questions/4856
+**Expensify/Expensify Issue URL:**
+**Issue reported by:**
+**Slack conversation:**
+
## Action Performed:
Break down in numbered steps
@@ -24,22 +34,54 @@ Can the user still use Expensify without this being fixed? Have you informed the
Check off any platforms that are affected by this issue
--->
Which of our officially supported platforms is this issue occurring on?
-- [ ] Android / native
-- [ ] Android / Chrome
-- [ ] iOS / native
-- [ ] iOS / Safari
-- [ ] MacOS / Chrome / Safari
-- [ ] MacOS / Desktop
+- [ ] Android: Native
+- [ ] Android: mWeb Chrome
+- [ ] iOS: Native
+- [ ] iOS: mWeb Safari
+- [ ] MacOS: Chrome / Safari
+- [ ] MacOS: Desktop
-**Version Number:**
-**Reproducible in staging?:**
-**Reproducible in production?:**
-**If this was caught during regression testing, add the test name, ID and link from TestRail:**
-**Email or phone of affected tester (no customers):**
-**Logs:** https://stackoverflow.com/c/expensify/questions/4856
-**Notes/Photos/Videos:** Any additional supporting documentation
-**Expensify/Expensify Issue URL:**
-**Issue reported by:**
-**Slack conversation:**
+## Screenshots/Videos
+
+Android: Native
+
+
+
+
+
+
+Android: mWeb Chrome
+
+
+
+
+
+
+iOS: Native
+
+
+
+
+
+
+iOS: mWeb Safari
+
+
+
+
+
+
+MacOS: Chrome / Safari
+
+
+
+
+
+
+MacOS: Desktop
+
+
+
+
[View all open jobs on GitHub](https://github.com/Expensify/App/issues?q=is%3Aopen+is%3Aissue+label%3A%22Help+Wanted%22)
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index 800888580518..0396a7543b50 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -70,12 +70,12 @@ This is a checklist for PR authors. Please make sure to complete all tasks and c
- [ ] I tested this PR with a [High Traffic account](https://github.com/Expensify/App/blob/main/contributingGuides/CONTRIBUTING.md#high-traffic-accounts) against the staging or production API to ensure there are no regressions (e.g. long loading states that impact usability).
- [ ] I included screenshots or videos for tests on [all platforms](https://github.com/Expensify/App/blob/main/contributingGuides/CONTRIBUTING.md#make-sure-you-can-test-on-all-platforms)
- [ ] I ran the tests on **all platforms** & verified they passed on:
- - [ ] Android / native
- - [ ] Android / Chrome
- - [ ] iOS / native
- - [ ] iOS / Safari
- - [ ] MacOS / Chrome / Safari
- - [ ] MacOS / Desktop
+ - [ ] Android: Native
+ - [ ] Android: mWeb Chrome
+ - [ ] iOS: Native
+ - [ ] iOS: mWeb Safari
+ - [ ] MacOS: Chrome / Safari
+ - [ ] MacOS: Desktop
- [ ] I verified there are no console errors (if there's a console error not related to the PR, report it or open an issue for it to be fixed)
- [ ] I followed proper code patterns (see [Reviewing the code](https://github.com/Expensify/App/blob/main/contributingGuides/PR_REVIEW_GUIDELINES.md#reviewing-the-code))
- [ ] I verified that any callback methods that were added or modified are named for what the method does and never what callback they handle (i.e. `toggleReport` and not `onIconClick`)
@@ -120,42 +120,42 @@ This is a checklist for PR authors. Please make sure to complete all tasks and c
### Screenshots/Videos
-Web
+Android: Native
-Mobile Web - Chrome
+Android: mWeb Chrome
-Mobile Web - Safari
+iOS: Native
-Desktop
+iOS: mWeb Safari
-iOS
+MacOS: Chrome / Safari
-Android
+MacOS: Desktop
diff --git a/README.md b/README.md
index 9aad797ebb51..daf9ddfae1ff 100644
--- a/README.md
+++ b/README.md
@@ -3,7 +3,7 @@
diff --git a/android/app/build.gradle b/android/app/build.gradle
index 148a46ddc00d..a28038cf0f18 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -90,8 +90,8 @@ android {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
multiDexEnabled rootProject.ext.multiDexEnabled
- versionCode 1001037903
- versionName "1.3.79-3"
+ versionCode 1001038104
+ versionName "1.3.81-4"
}
flavorDimensions "default"
diff --git a/assets/animations/Magician.json b/assets/animations/Magician.json
new file mode 100644
index 000000000000..393ad8ad3964
--- /dev/null
+++ b/assets/animations/Magician.json
@@ -0,0 +1 @@
+{"v":"5.9.6","fr":24,"ip":0,"op":69,"w":853,"h":480,"nm":"Comp 1","ddd":0,"assets":[{"id":"comp_0","nm":"Expensify-Magic-Link-120822-kjs-1","fr":24,"layers":[{"ddd":0,"ind":2,"ty":3,"nm":"sparkle 5 peg","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[1028,450.851,0],"ix":2,"l":2},"a":{"a":0,"k":[50,51.351,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,12.5]},"t":18,"s":[25,25,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,13.5]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":23,"s":[100,100,100]},{"t":28,"s":[25,25,100]}],"ix":6,"l":2}},"ao":0,"ip":18,"op":29,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"sparkle 5 Outlines","parent":2,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-12.47,143.61,0],"ix":2,"l":2},"a":{"a":0,"k":[965.53,543.11,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,23.234],[0,0],[0,-22.979],[0,0]],"o":[[0,23.49],[0,0],[0,-22.723],[0,0]],"v":[[0,-27.575],[-12,1.021],[0,27.575],[12,1.021]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.929411824544,0.560784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[1027.956,450.428],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":18,"op":29,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":4,"ty":3,"nm":"sparkle 4 peg","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[1056,396.851,0],"ix":2,"l":2},"a":{"a":0,"k":[50,51.351,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0]},"t":20,"s":[25,25,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":25,"s":[100,100,100]},{"t":30,"s":[25,25,100]}],"ix":6,"l":2}},"ao":0,"ip":20,"op":31,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"sparkle 4 Outlines","parent":4,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-40.47,197.61,0],"ix":2,"l":2},"a":{"a":0,"k":[965.53,543.11,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,38.984],[0,0],[0,-38.556],[0,0]],"o":[[0,39.413],[0,0],[0,-38.127],[0,0]],"v":[[0,-46.267],[-20.135,1.714],[0,46.267],[20.135,1.714]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.929411824544,0.560784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[1056.968,395.412],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":20,"op":31,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":6,"ty":3,"nm":"sparkle 3 peg","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[1242,355.851,0],"ix":2,"l":2},"a":{"a":0,"k":[50,51.351,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0]},"t":22,"s":[25,25,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":27,"s":[100,100,100]},{"t":32,"s":[25,25,100]}],"ix":6,"l":2}},"ao":0,"ip":22,"op":33,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"sparkle 3 Outlines","parent":6,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-226.47,238.61,0],"ix":2,"l":2},"a":{"a":0,"k":[965.53,543.11,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,23.234],[0,0],[0,-22.979],[0,0]],"o":[[0,23.49],[0,0],[0,-22.723],[0,0]],"v":[[0,-27.575],[-12,1.021],[0,27.575],[12,1.021]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.929411824544,0.560784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[1242.386,355.773],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":22,"op":33,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":8,"ty":3,"nm":"sparkle 2 peg","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[1152,138.851,0],"ix":2,"l":2},"a":{"a":0,"k":[50,51.351,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0]},"t":24,"s":[25,25,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":29,"s":[100,100,100]},{"t":34,"s":[25,25,100]}],"ix":6,"l":2}},"ao":0,"ip":24,"op":35,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"sparkle 2 Outlines","parent":8,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-136.47,455.61,0],"ix":2,"l":2},"a":{"a":0,"k":[965.53,543.11,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,15.082],[0,0],[0,-14.917],[0,0]],"o":[[0,15.248],[0,0],[0,-14.751],[0,0]],"v":[[0,-17.9],[-7.79,0.663],[0,17.9],[7.79,0.663]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.929411824544,0.560784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[1152.535,138.957],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":24,"op":35,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":10,"ty":3,"nm":"sparkle 1 peg","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[1120,116.851,0],"ix":2,"l":2},"a":{"a":0,"k":[50,51.351,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0]},"t":26,"s":[25,25,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":31,"s":[100,100,100]},{"t":36,"s":[25,25,100]}],"ix":6,"l":2}},"ao":0,"ip":26,"op":37,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":"sparkle 1 Outlines","parent":10,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-104.47,477.61,0],"ix":2,"l":2},"a":{"a":0,"k":[965.53,543.11,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,23.234],[0,0],[0,-22.979],[0,0]],"o":[[0,23.49],[0,0],[0,-22.723],[0,0]],"v":[[0,-27.575],[-12,1.021],[0,27.575],[12,1.021]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.929411824544,0.560784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[1120.952,117.61],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":26,"op":37,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":12,"ty":0,"nm":"body all comp","refId":"comp_1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[966,555.5,0],"to":[0,-2,0],"ti":[0,3,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":33,"s":[966,543.5,0],"to":[0,-3,0],"ti":[0,-0.667,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":39,"s":[966,537.5,0],"to":[0,0.667,0],"ti":[0,-1,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":47,"s":[966,547.5,0],"to":[0,1,0],"ti":[0,0.667,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.333,"y":0.333},"t":50,"s":[966,543.5,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":51,"s":[966,543.5,0],"to":[0,2,0],"ti":[0,-2,0]},{"t":68,"s":[966,555.5,0]}],"ix":2,"l":2},"a":{"a":0,"k":[966,543.5,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":1932,"h":1087,"ip":0,"op":69,"st":0,"ct":1,"bm":0}]},{"id":"comp_1","nm":"body all comp","fr":24,"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"bowtie peg","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[878,480.851,0],"ix":2,"l":2},"a":{"a":0,"k":[50,51.351,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":69,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":3,"nm":"head peg","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[23]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":33,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":39,"s":[-5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":47,"s":[2]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":50,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":51,"s":[0]},{"t":68,"s":[23]}],"ix":10},"p":{"a":0,"k":[852,470.851,0],"ix":2,"l":2},"a":{"a":0,"k":[50,51.351,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":69,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":3,"nm":"body peg","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[871,504.851,0],"ix":2,"l":2},"a":{"a":0,"k":[50,51.351,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":69,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":3,"nm":"hand 1 peg","parent":5,"sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[38]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":33,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":39,"s":[-6]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":47,"s":[7]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":50,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":51,"s":[0]},{"t":68,"s":[38]}],"ix":10},"p":{"a":0,"k":[257,-81.649,0],"ix":2,"l":2},"a":{"a":0,"k":[50,51.351,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":69,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":3,"nm":"arm 1 b peg","parent":6,"sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[10]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":33,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":39,"s":[-7]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":47,"s":[1]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":50,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":51,"s":[0]},{"t":68,"s":[10]}],"ix":10},"p":{"a":0,"k":[-43,-223.649,0],"ix":2,"l":2},"a":{"a":0,"k":[50,51.351,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":69,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":3,"nm":"arm 1 a peg","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":0,"s":[27]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":33,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":39,"s":[-1]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":47,"s":[1]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":50,"s":[0]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":51,"s":[0]},{"t":68,"s":[27]}],"ix":10},"p":{"a":0,"k":[810,557.851,0],"ix":2,"l":2},"a":{"a":0,"k":[50,51.351,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":69,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":3,"nm":"hat hand peg","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[1018,678.851,0],"to":[0,-2.333,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":33,"s":[1018,664.851,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":39,"s":[1018,651.851,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":47,"s":[1018,665.183,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.333,"y":0.333},"t":50,"s":[1018,664.851,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":51,"s":[1018,664.851,0],"to":[0,0,0],"ti":[0,-2.333,0]},{"t":68,"s":[1018,678.851,0]}],"ix":2,"l":2},"a":{"a":0,"k":[50,51.351,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":69,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":3,"nm":"arm 2 peg","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[909,524.851,0],"ix":2,"l":2},"a":{"a":0,"k":[50,51.351,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":0,"s":[100,110,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":33,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":39,"s":[101,91,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":47,"s":[102.667,101.333,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":50,"s":[100,100,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":51,"s":[100,100,100]},{"t":68,"s":[100,110,100]}],"ix":6,"l":2}},"ao":0,"ip":0,"op":69,"st":0,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"finger OL Outlines","parent":4,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[91.53,444.61,0],"ix":2,"l":2},"a":{"a":0,"k":[965.53,543.11,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-1.637,-2.817],[-2.045,4.838],[-0.469,2.45]],"o":[[-0.672,4.914],[3.649,6.282],[0.857,-2.027],[0,0]],"v":[[-6.613,-9.515],[-6.333,3.232],[5.984,0.521],[7.969,-6.263]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.980392216701,0.941176530427,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[996.38,135.455],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[3.909,2.631],[1.728,-0.883],[0.602,-1.676],[-1.618,0.846],[1.006,-4.022],[1.441,-1.398]],"o":[[7.289,-8.787],[-2.536,-1.707],[-2.314,1.145],[1.392,-3.877],[-2.968,1.516],[-0.595,2.382],[0,0]],"v":[[2.596,13.132],[5.688,-11.335],[-0.681,-12.248],[-5.282,-6.033],[-0.681,-12.248],[-6.509,-2.321],[-9.884,3.321]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.980392216701,0.941176530427,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[978.982,153.671],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":69,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":"wand Outlines","parent":4,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[91.53,444.61,0],"ix":2,"l":2},"a":{"a":0,"k":[965.53,543.11,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[14.674,-0.821],[-11.753,-8.458],[-14.673,0.765],[11.893,8.458]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.980392216701,0.941176530427,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[1085.197,172.322],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-63.345,-23.263],[-65.734,-14.123],[62.813,23.263],[65.734,14.039]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[1007.71,149.825],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":69,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":"hand 1 Outlines","parent":4,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[91.53,444.61,0],"ix":2,"l":2},"a":{"a":0,"k":[965.53,543.11,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-21.609,3.182],[5.634,3.792],[1.728,-0.882],[0.602,-1.677],[-1.618,0.847],[1.005,-4.022],[0,0],[4.242,4.772],[0,0],[-4.243,-4.773],[0,0],[-1.591,6.363],[-2.968,1.517],[-10.278,-0.664],[-4.033,-6.944],[-2.045,4.838],[2.422,8.333],[11.74,-1.97],[1.747,-3.885],[-0.997,6.54],[0.947,-0.237],[-0.055,0.183],[7.231,2.572],[2.305,-6.158],[0,0],[9.015,-15.908],[0,0],[3.29,5.556],[-0.717,0],[-0.304,0.814],[5.059,-2.024],[-0.179,-11.135],[0,0],[7.424,7.954],[5.57,-3.974],[-4.772,-9.943],[2.386,-10.34],[0,0]],"o":[[18.295,-8.352],[21.245,-3.128],[-2.536,-1.707],[-2.314,1.145],[1.392,-3.878],[-2.968,1.517],[-1.591,6.363],[0,0],[-4.243,-4.773],[0,0],[4.242,4.772],[0,0],[1.005,-4.022],[1.396,-11.442],[10.738,-0.796],[3.649,6.282],[3.428,-8.109],[-2.878,-9.899],[-0.997,6.54],[1.747,-3.885],[0.343,-0.215],[0.947,-0.237],[2.726,-17.866],[-3.944,-1.403],[3.29,5.556],[0,0],[9.015,-15.908],[0,0],[-0.005,-0.065],[0.199,0],[-2.03,-3.429],[-8.499,3.4],[0.266,16.438],[0,0],[-4.417,-4.732],[-5.966,8.749],[0,0],[-2.04,8.837],[0,0]],"v":[[-25.087,48.957],[11.645,60.722],[29.144,28.375],[22.775,27.462],[18.174,33.678],[22.775,27.462],[16.948,37.391],[8.463,46.406],[3.691,33.148],[-9.036,28.375],[3.691,33.148],[8.463,46.406],[16.948,37.391],[22.775,27.462],[29.807,-1.718],[34.522,24.729],[46.839,22.018],[48.109,-7.008],[22.305,-19.003],[18.114,-2.729],[22.305,-19.003],[22.052,-18.621],[22.305,-19.003],[17.146,-62.502],[5.497,-56.095],[8.993,-41.622],[3.16,-3.442],[8.993,-41.622],[5.497,-56.095],[5.845,-57.198],[5.497,-56.095],[-4.794,-59.651],[-5.855,-28.895],[-16.991,-5.562],[-29.452,-31.148],[-44.565,-35.125],[-35.418,-11.263],[-31.838,9.815],[-42.974,25.724]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.980392216701,0.941176530427,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[955.525,113.959],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":69,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":"arm 1 b Outlines","parent":5,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[298.53,311.61,0],"ix":2,"l":2},"a":{"a":0,"k":[965.53,543.11,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0.21,-0.14],[0.81,-0.52],[0.18,-0.11],[3.64,-4.45],[-0.57,-1.66],[0,0],[-11.24,5.42],[2.11,2.91],[9.76,-6.85],[0,0],[0,0],[0,0],[0,0],[-0.18,-0.12],[-7.39,0.98],[-5.52,3.52]],"o":[[0,0],[-0.34,0.23],[-0.16,0.11],[-5.11,3.4],[-4.25,5.21],[0.07,0.2],[0,0],[13.11,-6.37],[-3.73,-5.17],[-1.24,1.16],[0,0],[0,0],[0,0],[0,0],[1.32,0.84],[6.98,-0.92],[0,0]],"v":[[8.4,-5.74],[8.08,-5.53],[6.32,-4.38],[5.81,-4.05],[-14.14,11.49],[-15.44,26.3],[-15.33,26.61],[21.45,4.8],[27.14,-16.96],[4.65,-19.76],[2.56,-17.94],[-0.8,-15.88],[-6.25,-12.53],[-34.56,4.87],[-34.28,5.06],[-19.71,8.31],[5.81,-4.05]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[909.989,157.62],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-7.56,19.5]],"o":[[-8.34,20.87],[0,0]],"v":[[-11.015,-18.35],[19.355,-1.15]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[714.004,292.46],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[7.47,11.35],[-7.47,-11.35]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[876.449,178.18],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 3","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[-5.77,3.6],[-3.19,1.98]],"o":[[0,0],[6.47,-4.02],[3.59,-2.22],[0,0]],"v":[[-21.9,-11.83],[-6.76,11.83],[11.71,0.35],[21.9,-5.97]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[872.649,189.89],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[1.38,-0.97]],"o":[[-2.16,1.13],[0,0]],"v":[[2.725,-1.675],[-2.725,1.675]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[906.464,143.415],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 5","np":2,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[4.96,-3.12],[2.97,-5.29]],"o":[[0,0],[0,0],[-48.47,28.52],[-4.95,3.12],[0,0]],"v":[[86.36,-55.715],[79.63,-51.565],[61.4,-40.335],[-69.66,39.805],[-86.36,55.715]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[789.349,218.395],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 6","np":2,"cix":2,"bm":0,"ix":6,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[-39.18,24.37]],"o":[[2.16,-7.6],[0,0],[0,0]],"v":[[-66.265,44.795],[-33.455,17.785],[66.265,-44.795]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[799.624,246.515],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 7","np":2,"cix":2,"bm":0,"ix":7,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[-1.45,1.03],[0,0],[-0.18,-0.12]],"v":[[-14.155,8.605],[14.155,-8.795],[11.825,-7.035],[-13.875,8.795]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.980392216701,0.941176530427,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[889.584,153.885],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 8","np":2,"cix":2,"bm":0,"ix":8,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[11.13,15.12],[6.13,-3.2],[0,0],[-1.24,1.16],[-3.73,-5.17],[13.11,-6.37],[0,0],[0.07,0.2]],"o":[[0,0],[-4.16,-7.4],[0,0],[0,0],[9.76,-6.85],[2.11,2.91],[-11.24,5.42],[0,0],[15.06,-9.34]],"v":[[0.16,10.7],[8.12,-13.96],[-10.36,-15.88],[-7,-17.94],[-4.91,-19.76],[17.58,-16.96],[11.89,4.8],[-24.89,26.61],[-25,26.3]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.980392216701,0.941176530427,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[919.549,157.62],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 9","np":2,"cix":2,"bm":0,"ix":9,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-5.11,3.4],[6.98,-0.92],[1.32,0.84],[0,0],[-1.45,1.03],[0,0],[-4.16,-7.4],[0,0],[15.06,-9.34],[-4.25,5.21]],"o":[[-5.52,3.52],[-7.39,0.98],[0,0],[0,0],[0,0],[6.13,-3.2],[11.13,15.12],[0,0],[-0.57,-1.66],[3.64,-4.45]],"v":[[8.545,-6.52],[-16.975,5.84],[-31.545,2.59],[-5.845,-13.24],[-3.515,-15],[1.935,-18.35],[20.415,-16.43],[12.455,8.23],[-12.705,23.83],[-11.405,9.02]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.980392216701,0.941176530427,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[907.254,160.09],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 10","np":2,"cix":2,"bm":0,"ix":10,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-48.47,28.52],[0,0],[0,0],[2.16,-7.6],[-8.34,20.87],[-4.95,3.12]],"o":[[0,0],[-39.18,24.37],[0,0],[-7.56,19.5],[2.97,-5.29],[4.96,-3.12]],"v":[[70.48,-66.375],[85.62,-42.715],[-14.1,19.865],[-46.91,46.875],[-77.28,29.675],[-60.58,13.765]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[780.269,244.435],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 11","np":2,"cix":2,"bm":0,"ix":11,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[6.47,-4.02],[0,0],[0,0]],"o":[[0,0],[-5.77,3.6],[0,0],[0,0],[0,0]],"v":[[16.365,5.255],[16.805,5.965],[-1.665,17.445],[-16.805,-6.215],[1.425,-17.445]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0.235294132607,0.450980422076,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[867.554,184.275],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 12","np":2,"cix":2,"bm":0,"ix":12,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-5.52,3.52],[3.64,-4.45],[-0.57,-1.66],[3.59,-2.22],[0,0],[0,0],[0,0],[-7.39,0.98]],"o":[[-5.11,3.4],[-4.25,5.21],[-3.19,1.98],[0,0],[0,0],[0,0],[1.32,0.84],[6.98,-0.92]],"v":[[23.41,-18.335],[3.46,-2.795],[2.16,12.015],[-8.03,18.335],[-8.47,17.625],[-23.41,-5.075],[-16.68,-9.225],[-2.11,-5.975]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0.235294132607,0.450980422076,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[892.389,171.905],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 13","np":2,"cix":2,"bm":0,"ix":13,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":69,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":"bowtie main Outlines","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[137.53,113.61,0],"ix":2,"l":2},"a":{"a":0,"k":[965.53,543.11,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[4.242,-9.015],[-4.773,-7.955],[-4.242,6.363],[3.712,8.484]],"o":[[-4.242,9.015],[4.773,7.954],[4.242,-6.363],[-3.712,-8.485]],"v":[[-11.268,-11.401],[-11.268,12.462],[11.533,12.992],[12.329,-11.666]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.470588265213,0.019607843137,0.019607843137,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[877.95,481.052],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[25.848,11.048],[-0.8,-0.381],[-2.496,8.679],[-0.771,-0.387],[-9.893,6.974],[-19.633,-37.192]],"o":[[0,0],[-28.422,-12.148],[0,0],[2.532,-8.807],[0,0],[9.894,-6.973],[7.972,15.101]],"v":[[40.384,23.093],[-25.214,32.975],[-31.406,5.761],[-35.599,-11.037],[-19.301,-17.834],[-18.775,-37.05],[45.664,5.018]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.470588265213,0.019607843137,0.019607843137,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[827.939,470.062],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":69,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":"bowtie OL Outlines","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[137.53,113.61,0],"ix":2,"l":2},"a":{"a":0,"k":[965.53,543.11,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[-27.35,2.729],[0.859,-0.12]],"o":[[-1.783,6.781],[0,0],[30.074,-3],[0,0]],"v":[[-45.604,-20.71],[-40.93,-10.215],[17.313,17.98],[31.099,-5.426]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.470588265213,0.019607843137,0.019607843137,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[908.755,488.141],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":69,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":15,"ty":4,"nm":"body Outlines","parent":3,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[144.53,89.61,0],"ix":2,"l":2},"a":{"a":0,"k":[965.53,543.11,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-7.236],[7.029,0],[0,7.236],[-7.029,0]],"o":[[0,7.236],[-7.029,0],[0,-7.236],[7.029,0]],"v":[[12.727,0],[0,13.101],[-12.727,0],[0,-13.101]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.996078491211,0.839215746113,0.027450982262,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[846.796,649.659],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[27.575,-1.06],[39.241,-58.862],[0,0],[18.559,0.53],[0,0]],"o":[[-9.545,48.786],[61.513,-37.12],[0,0],[12.726,-11.666],[0,0]],"v":[[5.966,-70.661],[-51.57,71.72],[43.086,-28.768],[12.86,-37.253],[51.57,-47.859]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.003921568627,0.392156892664,0.749019607843,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[900.752,561.391],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[25.454,6.363],[0,0],[-13.257,-4.242],[0,0],[-27.575,-68.937]],"o":[[-23.332,9.545],[0,0],[-11.666,3.712],[0,0],[5.303,-30.757]],"v":[[8.219,-73.975],[-33.673,-43.749],[-3.447,-39.507],[-29.431,-25.719],[25.188,73.974]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.003921568627,0.392156892664,0.749019607843,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[823.729,559.402],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 3","np":3,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[-6.989,2.263]],"o":[[0,0],[0,0],[6.11,-0.264],[0,0]],"v":[[-1.027,-21.953],[-8.549,-21.608],[-9.838,21.953],[9.838,18.328]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.996078491211,0.839215746113,0.027450982262,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[885.769,488.549],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":3,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-6.637,3.928],[0,0],[0,0],[0,0]],"o":[[-19.62,-10.075],[0,0],[0,0],[6.06,-1.963]],"v":[[14.302,8.898],[-9.958,-16.158],[-14.302,-20.14],[-3.436,20.14]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.996078491211,0.839215746113,0.027450982262,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[899.044,486.737],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 5","np":3,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[-18.316,-4.7],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-1.552,-19.538],[-18.521,4.855],[10.544,20.459],[18.521,-20.459]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.996078491211,0.839215746113,0.027450982262,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[845.696,487.996],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 6","np":3,"cix":2,"bm":0,"ix":6,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[-7.262,0.313],[0,0]],"o":[[0,0],[5.831,1.496],[0,0],[0,0]],"v":[[-2.512,-21.341],[-10.49,19.577],[9.202,21.624],[10.491,-21.936]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.996078491211,0.839215746113,0.027450982262,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[866.73,488.878],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 7","np":3,"cix":2,"bm":0,"ix":7,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[4.085,4.265],[7.909,0.176],[0,0],[-7.098,3.029]],"o":[[-1.962,0.097],[0,0],[6.609,-0.956],[0.293,-13.519]],"v":[[6.836,-19.572],[-13.953,-20.192],[-6.994,20.192],[13.659,14.389]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.996078491211,0.839215746113,0.027450982262,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[893.493,508.271],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 8","np":3,"cix":2,"bm":0,"ix":8,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[5.252,0.143],[0,0],[-8.447,1.223],[0,0]],"o":[[0,0],[6.939,0.88],[0,0],[-5.282,-0.117]],"v":[[-4.076,-20.348],[-11.633,19.787],[11.633,19.639],[4.674,-20.745]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.996078491211,0.839215746113,0.027450982262,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[874.868,508.824],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 9","np":3,"cix":2,"bm":0,"ix":9,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[-16.803,-2.13],[0,0]],"o":[[0,0],[0,0],[0,0],[-9.229,-0.251]],"v":[[-2.369,-20.494],[-17.795,12.19],[10.239,20.494],[17.795,-19.641]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.996078491211,0.839215746113,0.027450982262,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[852.996,508.117],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 10","np":3,"cix":2,"bm":0,"ix":10,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[-6.989,2.263]],"o":[[0,0],[0,0],[6.11,-0.264],[0,0]],"v":[[-1.027,-21.953],[-8.549,-21.608],[-9.838,21.953],[9.838,18.328]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.996078491211,0.839215746113,0.027450982262,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[885.504,526.423],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 11","np":3,"cix":2,"bm":0,"ix":11,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-6.637,3.928],[0,0],[0,0],[0,0]],"o":[[-13.257,-4.772],[0,0],[0,0],[6.061,-1.962]],"v":[[14.965,11.812],[2.238,-20.535],[-14.965,-19.746],[-4.099,20.535]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.996078491211,0.839215746113,0.027450982262,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[899.442,524.216],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 12","np":3,"cix":2,"bm":0,"ix":12,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[-18.316,-4.7],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[-1.552,-19.538],[-18.521,4.855],[10.544,20.459],[18.521,-20.459]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.996078491211,0.839215746113,0.027450982262,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[845.431,525.87],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 13","np":3,"cix":2,"bm":0,"ix":13,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[-7.262,0.314],[0,0]],"o":[[0,0],[5.831,1.496],[0,0],[0,0]],"v":[[-2.513,-21.341],[-10.491,19.577],[9.201,21.623],[10.49,-21.937]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.996078491211,0.839215746113,0.027450982262,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[866.465,526.752],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 14","np":3,"cix":2,"bm":0,"ix":14,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[19.185,3.895],[17.567,-37.267],[0,0]],"o":[[0,0],[-2.303,18.353],[0,0],[0,0]],"v":[[32.215,-46.021],[-6.354,-53.937],[-32.214,53.407],[-31.685,53.937]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0.235294132607,0.450980422076,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[881.132,577.848],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 15","np":3,"cix":2,"bm":0,"ix":15,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0.586,-0.195],[0,0],[-2.303,18.354]],"o":[[0,0],[17.567,-37.266],[-18.496,-3.755]],"v":[[-18.697,-57.703],[-6.898,57.898],[18.698,-50.506]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0.235294132607,0.450980422076,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[856.081,574.417],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 16","np":3,"cix":2,"bm":0,"ix":16,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[8.325,-56.011],[61.242,-63.131],[0,0],[-21.136,-95.205],[0,0]],"o":[[1.233,60.226],[66.401,17.452],[0,0],[68.406,-66.816],[0,0]],"v":[[-22.688,-99.111],[-115.379,98.318],[18.147,49.079],[46.972,155.121],[102.158,-89.141]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[823.346,627.574],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 17","np":3,"cix":2,"bm":0,"ix":17,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-84.845,21.741],[0,0]],"o":[[0,0],[-9.545,-33.938],[0,0]],"v":[[-61.513,-3.712],[61.512,33.408],[29.165,-55.149]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.980392216701,0.941176530427,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[833.083,660.319],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 18","np":3,"cix":2,"bm":0,"ix":18,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-84.845,21.741],[0,0]],"o":[[0,0],[-9.545,-33.938],[0,0]],"v":[[-61.512,-3.712],[61.513,33.408],[29.166,-55.149]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.980392216701,0.941176530427,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[828.311,683.651],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 19","np":3,"cix":2,"bm":0,"ix":19,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-84.845,21.741],[0,0]],"o":[[0,0],[-9.545,-33.938],[0,0]],"v":[[-61.513,-3.712],[61.512,33.408],[29.165,-55.149]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.980392216701,0.941176530427,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[820.737,707.104],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 20","np":3,"cix":2,"bm":0,"ix":20,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":69,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":16,"ty":4,"nm":"arm 1 a Outlines","parent":6,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[205.53,36.61,0],"ix":2,"l":2},"a":{"a":0,"k":[965.53,543.11,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-0.01,0.02],[10.78,-13.79]],"o":[[0.01,-0.02],[7.37,-17.08],[0,0]],"v":[[11.315,15.68],[11.335,15.63],[-18.705,-1.89]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[722.174,275.22],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0.22,-0.36],[-3.9,-12.72],[-9.39,-15.08],[-5.62,-11.22],[10,36.66],[0,0],[8.55,23.77],[-3.54,7.32]],"o":[[-0.23,0.34],[-4.24,6.86],[0,0],[8.35,22.27],[5.63,11.22],[-6.17,-14.33],[0,0],[-5.72,-15.9],[0,0]],"v":[[-58.51,-156.02],[-59.18,-154.97],[-62.08,-125.78],[22.9,104.29],[37.96,144.8],[55.98,112.97],[41.7,77.59],[-25.08,-105.5],[-29.15,-137.4]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[762.639,428.3],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-0.33,0.53]],"o":[[0.26,-0.54],[0,0]],"v":[[-0.44,0.805],[0.44,-0.805]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[733.949,290.045],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 3","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-6.17,-14.33],[5.63,11.22],[8.35,22.27],[0,0],[-4.24,6.86],[0,0],[7.37,-17.08],[0.01,-0.02],[-5.72,-15.9],[0,0]],"o":[[10,36.66],[-5.62,-11.22],[-9.39,-15.08],[-3.9,-12.72],[0,0],[10.78,-13.79],[-0.01,0.02],[-3.54,7.32],[8.55,23.77],[0,0]],"v":[[55.98,119.34],[37.96,151.17],[22.9,110.66],[-62.08,-119.41],[-59.18,-148.6],[-59.17,-148.6],[-29.13,-131.08],[-29.15,-131.03],[-25.08,-99.13],[41.7,83.96]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[762.639,421.93],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":69,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":17,"ty":0,"nm":"head comp","parent":2,"refId":"comp_2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[164,124,0],"ix":2,"l":2},"a":{"a":0,"k":[966,543.5,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":1932,"h":1087,"ip":0,"op":69,"st":0,"bm":0},{"ddd":0,"ind":18,"ty":4,"nm":"bowtie UL Outlines","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[137.53,113.61,0],"ix":2,"l":2},"a":{"a":0,"k":[965.53,543.11,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-27.35,2.728],[0.859,-0.121],[-0.23,8.763],[0.833,-0.134],[7.17,9.331],[29.256,-28.747]],"o":[[0,0],[30.074,-3],[0,0],[0.232,-8.892],[0,0],[-7.169,-9.33],[-11.879,11.673]],"v":[[-38.419,8.467],[19.824,36.664],[33.61,13.256],[42.467,-1.084],[29.274,-12.112],[34.442,-30.062],[-38.019,-9.807]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.470588265213,0.019607843137,0.019607843137,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[906.244,469.458],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":69,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":19,"ty":0,"nm":"hat all comp","parent":7,"refId":"comp_3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-2,-70,0],"ix":2,"l":2},"a":{"a":0,"k":[966,543.5,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":1932,"h":1087,"ip":0,"op":69,"st":0,"bm":0},{"ddd":0,"ind":20,"ty":4,"nm":"arm 2 Outlines","parent":8,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[106.53,69.61,0],"ix":2,"l":2},"a":{"a":0,"k":[965.53,543.11,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[5.332,-5.359],[9.05,3.298],[9.71,10.883],[0,0],[0,0],[-17.303,-21.917],[-3.285,-1.932]],"o":[[0,0],[-2.516,1.923],[-6.912,-3.616],[-17.102,-20.681],[0,0],[0,0],[2.955,3.743],[9.98,5.868]],"v":[[63.769,66.125],[60.916,77.854],[47.27,79.31],[22.84,58.58],[-66.248,-66.301],[-47.555,-82.607],[44.316,49.035],[53.851,57.401]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[963.686,595.742],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":69,"st":0,"ct":1,"bm":0}]},{"id":"comp_2","nm":"head comp","fr":24,"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"eye1 peg","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[882,317.851,0],"ix":2,"l":2},"a":{"a":0,"k":[50,51.351,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":69,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"eye1 line Outlines","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[133.53,276.61,0],"ix":2,"l":2},"a":{"a":0,"k":[965.53,543.11,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-7.931],[12.639,0],[0,7.931],[-12.639,0]],"o":[[0,7.931],[-12.639,0],[0,-7.931],[12.639,0]],"v":[[22.885,0],[0,14.361],[-22.885,0],[0,-14.361]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[881.778,318.379],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":69,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":3,"ty":3,"nm":"lid1 peg","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[884,305.351,0],"to":[0,-1.417,0],"ti":[0,1.417,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.333,"y":0.333},"t":33,"s":[884,296.851,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":51,"s":[884,296.851,0],"to":[0,1.417,0],"ti":[0,-1.417,0]},{"t":68,"s":[884,305.351,0]}],"ix":2,"l":2},"a":{"a":0,"k":[50,51.351,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":69,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":3,"nm":"lid2 peg","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[883,330.351,0],"to":[0,1.583,0],"ti":[0,-1.583,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.333,"y":0.333},"t":33,"s":[883,339.851,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":51,"s":[883,339.851,0],"to":[0,-1.583,0],"ti":[0,1.583,0]},{"t":68,"s":[883,330.351,0]}],"ix":2,"l":2},"a":{"a":0,"k":[50,51.351,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":69,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"eye1 mask Outlines 3","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[965.53,543.11,0],"ix":2,"l":2},"a":{"a":0,"k":[965.53,543.11,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-7.931],[12.639,0],[0,7.931],[-12.639,0]],"o":[[0,7.931],[-12.639,0],[0,-7.931],[12.639,0]],"v":[[22.885,0],[0,14.361],[-22.885,0],[0,-14.361]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[881.778,318.379],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":69,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"lid1 Outlines","parent":3,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[131.53,297.61,0],"ix":2,"l":2},"a":{"a":0,"k":[965.53,543.11,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[912.249,303.77],[912.249,288.04]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.07,8.97],[0.07,-8.97]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[856.169,297.01],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[912.249,288.04],[856.239,288.04]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 3","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-14.9,-0.97]],"o":[[16.14,-2.68],[0,0]],"v":[[-28.075,1.59],[28.075,-0.62]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[884.174,304.39],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[16.14,-2.68],[0,0]],"o":[[0,0],[-14.9,-0.97],[0,0],[0,0]],"v":[[28.075,-8.97],[28.075,6.76],[-28.075,8.97],[-27.935,-8.97]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.011764706817,0.831372608858,0.486274539723,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[884.174,297.01],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 5","np":2,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":69,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"eye1 mask Outlines","parent":1,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[133.53,276.61,0],"ix":2,"l":2},"a":{"a":0,"k":[965.53,543.11,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-7.931],[12.639,0],[0,7.931],[-12.639,0]],"o":[[0,7.931],[-12.639,0],[0,-7.931],[12.639,0]],"v":[[22.885,0],[0,14.361],[-22.885,0],[0,-14.361]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[881.778,318.379],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":69,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"lid2 Outlines","parent":4,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[132.53,254.61,0],"ix":2,"l":2},"a":{"a":0,"k":[965.53,543.11,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[857.199,331.23],[857.199,345.16]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.275,-7.655],[0.275,7.655]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[910.734,337.505],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[911.009,345.16],[857.199,345.16]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 3","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-18.19,4.45]],"o":[[17.34,3.32],[0,0]],"v":[[-26.63,-0.97],[26.63,-2.35]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[883.829,332.2],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-18.19,4.45],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[17.34,3.32]],"v":[[26.355,-7.655],[26.905,7.655],[-26.905,7.655],[-26.905,-6.275]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.011764706817,0.831372608858,0.486274539723,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[884.104,337.505],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 5","np":2,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":69,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":9,"ty":3,"nm":"eyes2 peg","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[887,353.851,0],"ix":2,"l":2},"a":{"a":0,"k":[50,51.351,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":69,"st":0,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":"eyes2 line Outlines","parent":9,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[128.53,240.61,0],"ix":2,"l":2},"a":{"a":0,"k":[965.53,543.11,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,-10.564],[-15.186,0],[0.66,11.554],[11.401,0.265]],"o":[[-7.422,0],[0,7.559],[15.186,0],[0,0],[-11.401,-0.265]],"v":[[-12.699,-16.194],[-26.081,-1.303],[-0.661,16.194],[25.421,-1.963],[11.775,-14.716]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[864.717,353.521],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[7.662,5.572]],"o":[[-12.475,-5.197],[0,0]],"v":[[17.574,7.895],[-17.574,-7.895]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[907.711,359.453],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-4.62,-0.33],[-17.13,-0.5],[-6.19,1.62],[0,-15.19],[2.821,-0.517]],"o":[[0,0],[2.56,0.18],[13.82,0.41],[0,0],[0,11.821],[0,0]],"v":[[-46.715,-13.847],[-39.455,-14.837],[-2.655,-12.857],[31.195,-14.177],[46.715,0.353],[37.521,15.167]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[887.334,351.867],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 3","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0.461,-1.103],[0,0]],"v":[[-0.456,0.865],[0.456,-0.865]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[884.222,339.964],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":69,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":11,"ty":3,"nm":"lid3 peg","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[885,338.851,0],"to":[0,-1.333,0],"ti":[0,1.333,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.333,"y":0.333},"t":33,"s":[885,330.851,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":51,"s":[885,330.851,0],"to":[0,1.333,0],"ti":[0,-1.333,0]},{"t":68,"s":[885,338.851,0]}],"ix":2,"l":2},"a":{"a":0,"k":[50,51.351,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":69,"st":0,"bm":0},{"ddd":0,"ind":12,"ty":3,"nm":"lid4 peg","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":0,"s":[884,372.351,0],"to":[0,1.917,0],"ti":[0,-1.917,0]},{"i":{"x":0.667,"y":0.667},"o":{"x":0.333,"y":0.333},"t":33,"s":[884,383.851,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":51,"s":[884,383.851,0],"to":[0,-1.917,0],"ti":[0,1.917,0]},{"t":68,"s":[884,372.351,0]}],"ix":2,"l":2},"a":{"a":0,"k":[50,51.351,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":69,"st":0,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":"eyes2 mask Outlines 2","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[965.53,543.11,0],"ix":2,"l":2},"a":{"a":0,"k":[965.53,543.11,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[15.18,0],[0,7.56],[-7.42,0],[-11.4,-0.26]],"o":[[0.66,11.55],[-15.19,0],[0,-10.57],[0,0],[11.4,0.27]],"v":[[25.42,-1.965],[-0.66,16.195],[-26.08,-1.305],[-12.7,-16.195],[11.77,-14.725]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[864.719,353.525],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-15.19],[2.82,-0.51],[0,0],[7.56,5.5],[11.4,0.27],[0,0],[-13.03,-0.38],[-6.19,1.62]],"o":[[0,11.82],[0,0],[-12.38,-5.13],[0,0],[-11.4,-0.26],[6.61,0.46],[13.82,0.41],[0,0]],"v":[[41.015,0.13],[31.825,14.94],[31.775,15.06],[-2.895,-0.53],[-16.545,-13.29],[-41.015,-14.76],[-8.355,-13.08],[25.495,-14.4]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[893.034,352.09],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":69,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":"lid3 Outlines","parent":11,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[130.53,263.61,0],"ix":2,"l":2},"a":{"a":0,"k":[965.53,543.11,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.21,-7.52],[0.21,7.52]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[936.739,328.26],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.35,-6.965],[0.35,6.965]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[834.509,327.705],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[936.529,320.74],[834.159,320.74]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 3","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-12.57,3.72]],"o":[[4.61,2.63],[0,0]],"v":[[-51.045,-2.415],[51.045,-1.305]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[885.904,337.085],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[4.61,2.63],[0,0]],"o":[[0,0],[-12.57,3.72],[0,0],[0,0]],"v":[[50.975,-9.38],[51.395,5.66],[-50.695,4.55],[-51.395,-9.38]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.011764706817,0.831372608858,0.486274539723,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[885.554,330.12],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 5","np":2,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":69,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":15,"ty":4,"nm":"eyes2 mask Outlines","parent":9,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[128.53,240.61,0],"ix":2,"l":2},"a":{"a":0,"k":[965.53,543.11,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[15.18,0],[0,7.56],[-7.42,0],[-11.4,-0.26]],"o":[[0.66,11.55],[-15.19,0],[0,-10.57],[0,0],[11.4,0.27]],"v":[[25.42,-1.965],[-0.66,16.195],[-26.08,-1.305],[-12.7,-16.195],[11.77,-14.725]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[864.719,353.525],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-15.19],[2.82,-0.51],[0,0],[7.56,5.5],[11.4,0.27],[0,0],[-13.03,-0.38],[-6.19,1.62]],"o":[[0,11.82],[0,0],[-12.38,-5.13],[0,0],[-11.4,-0.26],[6.61,0.46],[13.82,0.41],[0,0]],"v":[[41.015,0.13],[31.825,14.94],[31.775,15.06],[-2.895,-0.53],[-16.545,-13.29],[-41.015,-14.76],[-8.355,-13.08],[25.495,-14.4]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[893.034,352.09],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":69,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":16,"ty":4,"nm":"lid4 Outlines","parent":12,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[131.53,210.61,0],"ix":2,"l":2},"a":{"a":0,"k":[965.53,543.11,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[935.299,371.24],[935.299,393.04]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[833.059,370],[833.059,393.04]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":2,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[25.52,2.41]],"o":[[-25.25,1.79],[0,0]],"v":[[51.12,-0.275],[-51.12,-1.515]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[884.179,371.515],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 3","np":2,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[833.059,393.04],[935.299,393.04]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-25.25,1.79],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[25.52,2.41]],"v":[[51.12,-10.28],[51.12,11.52],[-51.12,11.52],[-51.12,-11.52]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.011764706817,0.831372608858,0.486274539723,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[884.179,381.52],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 5","np":2,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":69,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":17,"ty":3,"nm":"head peg","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[852,470.851,0],"ix":2,"l":2},"a":{"a":0,"k":[50,51.351,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":69,"st":0,"bm":0},{"ddd":0,"ind":18,"ty":4,"nm":"head Outlines","parent":17,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[163.53,123.61,0],"ix":2,"l":2},"a":{"a":0,"k":[965.53,543.11,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[7.544,0],[1.453,-5.983],[0,0],[0,0],[-4.263,0],[0,7.543]],"o":[[-6.43,0],[0,0],[0,0],[2.505,3.06],[7.544,0],[0,-7.544]],"v":[[-0.2,-13.66],[-13.46,-3.228],[-2.757,1.665],[-10.773,8.646],[-0.2,13.66],[13.46,0.001]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[876.347,352.424],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[6.014,0],[1.158,-4.769],[0,0],[0,0],[-3.398,0],[0,6.013]],"o":[[-5.125,0],[0,0],[0,0],[1.997,2.439],[6.014,0],[0,-6.014]],"v":[[-0.159,-10.889],[-10.729,-2.574],[-2.198,1.327],[-8.588,6.892],[-0.159,10.889],[10.729,0.001]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[893.196,318.379],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[7.268,0],[1.4,-5.764],[0,0],[0,0],[-4.107,0],[0,7.268]],"o":[[-6.194,0],[0,0],[0,0],[2.413,2.948],[7.268,0],[0,-7.268]],"v":[[-0.193,-13.16],[-12.968,-3.11],[-2.657,1.603],[-10.379,8.329],[-0.193,13.16],[12.967,0]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[921.078,351.558],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 3","np":3,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,-10.564],[-15.186,0],[0.66,11.554],[11.401,0.265]],"o":[[-7.422,0],[0,7.559],[15.186,0],[0,0],[-11.401,-0.265]],"v":[[-12.699,-16.194],[-26.081,-1.303],[-0.661,16.194],[25.421,-1.963],[11.775,-14.716]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.980392216701,0.941176530427,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[864.717,353.521],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":3,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-24.76,10.235]],"o":[[0,0],[0,0]],"v":[[-28.232,-5.364],[28.232,-4.872]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[888.56,409.563],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 5","np":2,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[18.157,-0.661]],"o":[[0,0],[0,0]],"v":[[14.031,-8.089],[-14.031,8.089]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[804.467,355.684],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 6","np":2,"cix":2,"bm":0,"ix":6,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[25.09,-11.885]],"o":[[0,0],[0,0]],"v":[[11.555,-9.739],[-12.545,9.739]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[803.642,335.216],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 7","np":2,"cix":2,"bm":0,"ix":7,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[1.981,-3.631]],"o":[[0.33,9.904],[0,0]],"v":[[13.371,-11.39],[-13.701,11.39]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[802.486,314.417],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 8","np":2,"cix":2,"bm":0,"ix":8,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[17.497,-13.536]],"o":[[0,0],[0,0]],"v":[[22.449,4.457],[-22.449,6.768]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[801.661,277.772],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 9","np":2,"cix":2,"bm":0,"ix":9,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[16.506,-4.292]],"o":[[0,0],[0,0]],"v":[[12.875,6.107],[-12.875,-1.815]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[839.627,262.917],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 10","np":2,"cix":2,"bm":0,"ix":10,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[31.362,0.33]],"o":[[0,0],[0,0]],"v":[[22.449,11.059],[-22.449,-11.059]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[864.717,259.285],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 11","np":2,"cix":2,"bm":0,"ix":11,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[36.645,1.98]],"o":[[0,0],[0,0]],"v":[[22.119,15.351],[-22.119,-15.351]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[884.194,253.013],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 12","np":2,"cix":2,"bm":0,"ix":12,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-2.31,2.311]],"o":[[0,0],[0,0]],"v":[[-1.735,3.386],[1.735,-3.386]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[898.305,303.443],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 13","np":2,"cix":2,"bm":0,"ix":13,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0.66,1.981]],"o":[[0,0],[0,0]],"v":[[0,4.545],[-0.33,-4.545]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[885.515,299.32],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 14","np":2,"cix":2,"bm":0,"ix":14,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[3.301,1.981]],"o":[[0,0],[0,0]],"v":[[1.815,4.559],[-1.816,-4.559]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[871.485,300.324],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 15","np":2,"cix":2,"bm":0,"ix":15,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[2.971,1.32]],"o":[[0,0],[0,0]],"v":[[2.971,3.961],[-2.971,-3.961]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[861.415,304.678],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 16","np":2,"cix":2,"bm":0,"ix":16,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-7.931],[12.639,0],[0,7.931],[-12.639,0]],"o":[[0,7.931],[-12.639,0],[0,-7.931],[12.639,0]],"v":[[22.885,0],[0,14.361],[-22.885,0],[0,-14.361]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.980392216701,0.941176530427,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[881.778,318.379],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 17","np":3,"cix":2,"bm":0,"ix":17,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[-2.121,-6.363],[0,0]],"v":[[3.763,3.519],[-3.763,-3.519]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[889.433,371.079],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 18","np":2,"cix":2,"bm":0,"ix":18,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0.778,0],[0,-2.971],[-22.449,0],[0.762,0.011],[0,7.593],[14.525,10.565]],"o":[[-3.611,-0.12],[-7.593,0],[0,2.971],[36.404,0],[0,0],[0,-11.555],[0,0]],"v":[[-23.944,-3.145],[-26.081,-3.301],[-35.984,5.943],[-12.875,17.827],[22.78,18.158],[35.984,11.555],[-19.477,-19.148]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.011764706817,0.831372608858,0.486274539723,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[909.615,370.705],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 19","np":3,"cix":2,"bm":0,"ix":19,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-4.62,-0.33],[-17.13,-0.5],[-6.19,1.62],[0,-15.19],[0,0],[15.11,7.16],[0,0]],"o":[[0,0],[2.56,0.18],[13.82,0.41],[0,0],[0,15.18],[0,0],[-23.98,-11.84],[0,0]],"v":[[-46.715,-16.04],[-39.455,-17.03],[-2.655,-15.05],[31.195,-16.37],[46.715,-1.84],[36.205,13.11],[11.745,10.2],[-2.655,-14.96]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[887.334,354.06],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 20","np":2,"cix":2,"bm":0,"ix":20,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,-15.19],[0,0],[15.11,7.16],[0,0],[0,0],[-6.19,1.62]],"o":[[0,15.18],[0,0],[-23.98,-11.84],[0,0],[13.82,0.41],[0,0]],"v":[[29.475,-2.005],[18.965,12.945],[-5.495,10.035],[-19.895,-15.125],[-19.895,-15.215],[13.955,-16.535]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.980392216701,0.941176530427,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[904.574,354.225],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 21","np":2,"cix":2,"bm":0,"ix":21,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[4.952,0],[2.972,-3.961],[9.904,0.33],[2.311,-0.99],[-25.751,-0.66],[-4.952,5.282]],"o":[[-2.917,-1.856],[-4.952,0],[0,0],[-9.904,-0.33],[0,0],[13.866,0],[0,0]],"v":[[28.676,-4.312],[17.277,-12.875],[5.062,-5.282],[-8.473,-13.865],[-28.941,-4.953],[3.742,14.195],[28.941,-2.456]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.964705942191,0.552941176471,0.996078491211,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[887.852,408.341],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 22","np":3,"cix":2,"bm":0,"ix":22,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[6.086,-16.704],[0,0],[0,0],[0,0],[0,0],[-1.321,23.109],[-5.282,23.77],[-16.506,7.263],[-42.917,-7.263],[0,0],[0.66,-19.808],[5.282,-14.525],[15.846,12.876],[19.808,-25.75],[0,-17.827],[0,0]],"o":[[2.641,13.866],[-7.34,20.143],[10.738,-4.375],[-6.929,8.73],[9.904,0],[-38.296,3.961],[1.32,-23.109],[5.282,-23.769],[16.507,-7.263],[56.123,9.244],[0,0],[-0.66,19.808],[-3.962,-5.282],[-20.799,15.847],[-17.827,19.808],[0,17.827],[0,0]],"v":[[-40.936,47.041],[-29.381,95.241],[-56.607,107.033],[-42.917,91.939],[-60.745,95.241],[-49.519,78.735],[-71.308,10.066],[-85.174,-41.434],[-37.635,-70.486],[34.333,-108.121],[75.271,-55.3],[87.815,-33.512],[64.706,8.746],[59.755,-50.678],[-21.458,-36.812],[-24.43,24.592],[-49.19,48.361]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.819607902976,0.501960784314,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[853.822,328.946],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 23","np":3,"cix":2,"bm":0,"ix":23,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-9.574,0],[-2.963,1.261],[0,2.942],[0,0],[0,0],[2.121,14.848],[28.635,0.531],[4.773,-27.574],[-9.545,-22.272],[-3.182,-18.56],[-29.165,3.712],[0,0]],"o":[[3.631,6.603],[4.515,0],[12.633,-5.373],[0,0],[0,0],[0,0],[-2.121,-14.848],[-28.636,-0.53],[-4.772,27.575],[9.546,22.272],[3.182,18.559],[22.272,-7.955],[0,0]],"v":[[5.827,65.623],[29.266,74.206],[40.403,72.183],[53.036,49.446],[53.036,23.366],[54.499,-29.747],[62.839,-77.156],[18.296,-116.397],[-53.823,-75.035],[-55.414,27.84],[-31.552,98.368],[10.341,110.034],[45.87,68.937]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.011764706817,0.831372608858,0.486274539723,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[864.03,367.439],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 24","np":3,"cix":2,"bm":0,"ix":24,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":69,"st":0,"ct":1,"bm":0}]},{"id":"comp_3","nm":"hat all comp","fr":24,"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"hat peg","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[1146,639.851,0],"ix":2,"l":2},"a":{"a":0,"k":[50,51.351,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":69,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"hat Outlines","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-130.47,-45.39,0],"ix":2,"l":2},"a":{"a":0,"k":[965.53,543.11,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[-51.397,-2.254],[-35.167,1.804],[-4.208,-12.624],[11.722,6.312],[51.998,-27.952],[17.785,7.808]],"o":[[0,0],[32.912,-1.804],[35.166,-1.803],[4.207,-12.924],[-13.358,-7.193],[-37.42,19.387],[-24.646,-10.82]],"v":[[-105.498,-7.89],[-64.02,31.334],[55.906,-11.948],[111.21,12.849],[99.187,-19.612],[-2.705,-3.382],[-84.158,16.756]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[1138.248,524.199],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[22.807,1.723],[4.208,-22.242],[-22.843,4.809],[0.013,19.208]],"o":[[1.589,15.834],[32.461,3.005],[-3.388,-28.24],[-48.151,3.419]],"v":[[-54.959,-36.339],[-55.905,33.864],[55.905,32.06],[52.299,-36.868]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[1146.664,605.978],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-48.151,3.419],[0,1.308],[-1.202,2.404],[0,0],[-2.062,-20.539]],"o":[[-0.001,-1.235],[0,-43.882],[-17.733,-14.427],[0,0],[22.807,1.723]],"v":[[52.901,35.361],[52.899,31.552],[58.91,-24.353],[-58.911,12.917],[-54.358,35.891]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.470588265213,0.019607843137,0.019607843137,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[1146.063,533.75],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 3","np":3,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0.601,11.421],[0,0],[0,0],[0,0],[-15.177,1.124]],"o":[[-0.601,-11.421],[0,0],[0,0],[15.154,3.966],[24.346,-1.803]],"v":[[38.068,-4.47],[-13.629,-25.81],[-38.669,-17.148],[-38.669,18.529],[10.867,24.685]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[1212.592,530.397],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":3,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":69,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"chains mask Outlines","td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[965.53,543.11,0],"ix":2,"l":2},"a":{"a":0,"k":[965.53,543.11,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[100.29,-4.91],[-2.12,292.66]],"o":[[0,0],[-88.31,13.51],[-166.77,-119.19],[0,0]],"v":[[318.54,-308.751],[318.54,251.479],[30.15,275.149],[-316.42,-308.751]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[1019.409,275.15],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":69,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":4,"ty":0,"nm":"chains comp","tt":1,"refId":"comp_4","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[966,543.5,0],"ix":2,"l":2},"a":{"a":0,"k":[966,543.5,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":1932,"h":1087,"ip":0,"op":69,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"hat UL Outlines","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-130.47,-45.39,0],"ix":2,"l":2},"a":{"a":0,"k":[965.53,543.11,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-29.455,7.514],[-24.346,1.803],[0.601,11.422],[0,0],[0,0],[15.63,5.11],[9.294,-10.223],[-13.225,-16.831]],"o":[[11.722,5.41],[24.346,-1.803],[-0.601,-11.421],[0,0],[0,0],[-15.629,-5.109],[-9.017,9.919],[12.464,15.863]],"v":[[12.624,16.232],[83.407,29.458],[110.608,0.302],[58.911,-21.037],[11.121,-4.506],[-55.304,-26.147],[-100.99,-21.037],[-97.984,14.729]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[1140.052,525.625],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":69,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":6,"ty":3,"nm":"hat hand peg","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[1018,664.851,0],"ix":2,"l":2},"a":{"a":0,"k":[50,51.351,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":69,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"hat hand Outlines","parent":6,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-2.47,-70.39,0],"ix":2,"l":2},"a":{"a":0,"k":[965.53,543.11,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0.064,0.011],[-0.026,-0.03]],"o":[[0.026,0.03],[0.044,-0.054]],"v":[[-0.062,-0.044],[0.018,0.044]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[1169.64,657.822],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[12.461,-1.725],[2.924,-1.272],[7.556,0.795],[-12.329,2.386],[-2.371,0.328],[3.033,2.744],[0,0],[12.727,-12.726],[12.436,0.054],[1.703,0.037],[-16.675,-0.425],[-3.074,-0.072],[2.527,0.064],[1.48,-4.242],[0,0],[-7.954,4.243],[-8.484,0],[-12.328,2.254],[5.802,6.638],[0.026,0.03],[0,0],[-0.052,-0.008],[2.755,0.918],[7.556,-5.568],[-4.59,-1.53],[-2.023,-2.289],[0.044,-0.054],[-14.164,8.291]],"o":[[-2.371,0.328],[-12.329,2.386],[7.556,0.795],[2.924,-1.272],[1.443,-3.61],[-8.352,-7.557],[-42.157,0],[-8.648,8.649],[-1.542,-0.006],[1.707,4.333],[2.518,-0.187],[-3.071,0.204],[-16.871,1.248],[31.352,0.579],[0,0],[7.955,-4.242],[11.666,-0.663],[7.065,-3.042],[-0.027,-0.03],[-0.052,-0.008],[0,0],[-2.023,-2.289],[-4.59,-1.53],[7.556,-5.568],[2.755,0.918],[0.064,0.011],[13.697,0.367],[10.692,-4.678]],"v":[[68.484,-13.673],[60.522,-11.335],[24.728,-9.744],[60.522,-11.335],[68.484,-13.673],[67.681,-24.459],[2.456,-24.459],[-51.633,-1.393],[-80.266,8.505],[-85.135,8.433],[-61.322,18.948],[-52.958,18.759],[-61.322,18.948],[-84.721,30.905],[-28.566,31.485],[-12.127,27.773],[2.721,18.759],[23.932,27.773],[23.323,7.72],[23.242,7.632],[23.137,7.622],[23.242,7.632],[15.978,2.585],[-8.282,3.778],[15.978,2.585],[23.242,7.632],[23.323,7.72],[74.442,-0.995]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0.980392216701,0.941176530427,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[1146.401,650.213],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-16.87,1.248],[1.707,4.333],[4.238,0.057],[0,0],[0,0],[0,0],[-3.935,-0.073]],"o":[[-16.674,-0.425],[-3.439,-0.074],[0,0],[0,0],[0,0],[4.106,0.092],[1.48,-4.242]],"v":[[17.736,-0.6],[-6.077,-11.115],[-17.538,-11.357],[-17.737,11.112],[-17.648,10.612],[-17.737,11.112],[-5.663,11.357]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0.235294132607,0.450980422076,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[1067.299,669.856],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 3","np":3,"cix":2,"bm":0,"ix":3,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[1.789,0],[2.25,0.279],[0,0],[0,0],[0,0],[-0.954,-0.025],[-3.207,-0.072],[0,0]],"o":[[0,0],[-2.54,0],[0,0],[0,0],[0,0],[0.926,0.056],[3.271,0.085],[0,0],[0,0]],"v":[[6.242,-10.771],[1.204,-11.036],[-5.979,-11.47],[-5.955,-11.036],[-5.979,-11.47],[-6.375,11.099],[-3.568,11.236],[6.153,11.47],[6.375,-7.656]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0.235294132607,0.450980422076,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[1043.387,669.335],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":3,"cix":2,"bm":0,"ix":4,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-3.071,0.205],[2.519,-0.186]],"o":[[-3.074,-0.072],[2.527,0.065]],"v":[[4.182,-0.091],[-4.182,0.098]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[1089.195,668.996],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 5","np":2,"cix":2,"bm":0,"ix":5,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-1.929,8.298],[-3.661,-1.963],[0,0],[11.954,-9.011],[7.143,2.562]],"o":[[2.819,-6.529],[9.575,5.134],[0,0],[-6.987,-0.305],[-8.284,-2.972]],"v":[[-20.019,-4.573],[-8.329,-12.341],[10.39,-8.266],[9.994,14.303],[-10.531,11.357]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":2,"lj":2,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[1027.018,666.131],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 6","np":3,"cix":2,"bm":0,"ix":6,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":69,"st":0,"ct":1,"bm":0}]},{"id":"comp_4","nm":"chains comp","fr":24,"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"chain peg 12","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":33,"s":[-27]},{"i":{"x":[0.659],"y":[1]},"o":{"x":[0.297],"y":[0]},"t":39,"s":[-27]},{"i":{"x":[0.815],"y":[1]},"o":{"x":[0.425],"y":[0]},"t":43,"s":[-27]},{"t":45,"s":[-27]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":0.667},"o":{"x":0.333,"y":0.333},"t":33,"s":[1150,620.851,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.659,"y":0.659},"o":{"x":0.297,"y":0.297},"t":39,"s":[1150,620.851,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.425,"y":0.425},"t":43,"s":[1150,620.851,0],"to":[0,0,0],"ti":[0,0,0]},{"t":45,"s":[1150,620.851,0]}],"ix":2,"l":2},"a":{"a":0,"k":[50,51.351,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":46,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":3,"nm":"chain peg 11","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":30,"s":[-27]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":33,"s":[-27]},{"i":{"x":[0.659],"y":[1]},"o":{"x":[0.297],"y":[0]},"t":39,"s":[-58]},{"i":{"x":[0.815],"y":[1]},"o":{"x":[0.425],"y":[0]},"t":43,"s":[-58]},{"t":45,"s":[-58]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":30,"s":[1150,620.851,0],"to":[-3.5,-7.167,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":33,"s":[1129,577.851,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.659,"y":0.273},"o":{"x":0.297,"y":0},"t":39,"s":[1145,529.851,0],"to":[0,0,0],"ti":[0.198,-39.381,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.425,"y":0.258},"t":43,"s":[1144.637,602.079,0],"to":[-0.247,49.104,0],"ti":[0.092,-18.406,0]},{"t":45,"s":[1144,728.851,0]}],"ix":2,"l":2},"a":{"a":0,"k":[50,51.351,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":46,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":3,"nm":"chain peg 10","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":27,"s":[-27]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":30,"s":[-27]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":33,"s":[-26]},{"i":{"x":[0.659],"y":[0.273]},"o":{"x":[0.297],"y":[0]},"t":39,"s":[-23]},{"i":{"x":[0.815],"y":[0.903]},"o":{"x":[0.425],"y":[0.258]},"t":43,"s":[-26.992]},{"t":45,"s":[-34]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":27,"s":[1150,620.851,0],"to":[-3.5,-7.167,0],"ti":[7.5,14.167,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":30,"s":[1129,577.851,0],"to":[-7.5,-14.167,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":33,"s":[1105,535.851,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.659,"y":0.273},"o":{"x":0.297,"y":0},"t":39,"s":[1106,501.851,0],"to":[0,0,0],"ti":[0.594,-39.974,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.425,"y":0.258},"t":43,"s":[1104.911,575.168,0],"to":[-0.74,49.844,0],"ti":[0.277,-18.683,0]},{"t":45,"s":[1103,703.851,0]}],"ix":2,"l":2},"a":{"a":0,"k":[50,51.351,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":46,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":3,"nm":"chain peg 9","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":24,"s":[-27]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":27,"s":[-27]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":30,"s":[-26]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":33,"s":[-5]},{"i":{"x":[0.659],"y":[0.273]},"o":{"x":[0.297],"y":[0]},"t":39,"s":[-3]},{"i":{"x":[0.815],"y":[0.903]},"o":{"x":[0.425],"y":[0.258]},"t":43,"s":[-12.436]},{"t":45,"s":[-29]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":24,"s":[1150,620.851,0],"to":[-3.5,-7.167,0],"ti":[7.5,14.167,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":27,"s":[1129,577.851,0],"to":[-7.5,-14.167,0],"ti":[6.833,13.667,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":30,"s":[1105,535.851,0],"to":[-6.833,-13.667,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":33,"s":[1088,495.851,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.659,"y":0.273},"o":{"x":0.297,"y":0},"t":39,"s":[1093,460.851,0],"to":[0,0,0],"ti":[2.771,-40.568,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.425,"y":0.258},"t":43,"s":[1087.919,535.257,0],"to":[-3.455,50.585,0],"ti":[1.295,-18.961,0]},{"t":45,"s":[1079,665.851,0]}],"ix":2,"l":2},"a":{"a":0,"k":[50,51.351,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":46,"st":0,"bm":0},{"ddd":0,"ind":5,"ty":3,"nm":"chain peg 8","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":21,"s":[-27]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":24,"s":[-27]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":27,"s":[-26]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":30,"s":[-5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":33,"s":[22]},{"i":{"x":[0.659],"y":[0.273]},"o":{"x":[0.297],"y":[0]},"t":39,"s":[22]},{"i":{"x":[0.815],"y":[0.903]},"o":{"x":[0.425],"y":[0.258]},"t":43,"s":[19.097]},{"t":45,"s":[14]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":21,"s":[1150,620.851,0],"to":[-3.5,-7.167,0],"ti":[7.5,14.167,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":24,"s":[1129,577.851,0],"to":[-7.5,-14.167,0],"ti":[6.833,13.667,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":27,"s":[1105,535.851,0],"to":[-6.833,-13.667,0],"ti":[2.667,14,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":30,"s":[1088,495.851,0],"to":[-2.667,-14,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":33,"s":[1089,451.851,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.659,"y":0.273},"o":{"x":0.297,"y":0},"t":39,"s":[1095,416.851,0],"to":[0,0,0],"ti":[6.333,-41.36,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.425,"y":0.258},"t":43,"s":[1083.385,492.709,0],"to":[-7.896,51.572,0],"ti":[2.96,-19.331,0]},{"t":45,"s":[1063,625.851,0]}],"ix":2,"l":2},"a":{"a":0,"k":[50,51.351,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":46,"st":0,"bm":0},{"ddd":0,"ind":6,"ty":3,"nm":"chain peg 7","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":18,"s":[-27]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":21,"s":[-27]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":24,"s":[-26]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":27,"s":[-5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":30,"s":[22]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":33,"s":[49]},{"i":{"x":[0.659],"y":[0.273]},"o":{"x":[0.297],"y":[0]},"t":39,"s":[43]},{"i":{"x":[0.815],"y":[0.903]},"o":{"x":[0.425],"y":[0.258]},"t":43,"s":[48.444]},{"t":45,"s":[58]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":18,"s":[1150,620.851,0],"to":[-3.5,-7.167,0],"ti":[7.5,14.167,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":21,"s":[1129,577.851,0],"to":[-7.5,-14.167,0],"ti":[6.833,13.667,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":24,"s":[1105,535.851,0],"to":[-6.833,-13.667,0],"ti":[2.667,14,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":27,"s":[1088,495.851,0],"to":[-2.667,-14,0],"ti":[-3.333,13.833,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":30,"s":[1089,451.851,0],"to":[3.333,-13.833,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":33,"s":[1108,412.851,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.659,"y":0.273},"o":{"x":0.297,"y":0},"t":39,"s":[1114,376.851,0],"to":[0,0,0],"ti":[6.926,-41.558,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.425,"y":0.258},"t":43,"s":[1101.297,453.072,0],"to":[-8.636,51.818,0],"ti":[3.237,-19.423,0]},{"t":45,"s":[1079,586.851,0]}],"ix":2,"l":2},"a":{"a":0,"k":[50,51.351,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":46,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":3,"nm":"chain peg 6","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":15,"s":[-27]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":18,"s":[-27]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":21,"s":[-26]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":24,"s":[-5]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":27,"s":[22]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":30,"s":[49]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":33,"s":[57]},{"i":{"x":[0.659],"y":[0.273]},"o":{"x":[0.297],"y":[0]},"t":39,"s":[47]},{"i":{"x":[0.815],"y":[0.903]},"o":{"x":[0.425],"y":[0.258]},"t":43,"s":[60.792]},{"t":45,"s":[85]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":15,"s":[1150,620.851,0],"to":[-3.5,-7.167,0],"ti":[7.5,14.167,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":18,"s":[1129,577.851,0],"to":[-7.5,-14.167,0],"ti":[6.833,13.667,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":21,"s":[1105,535.851,0],"to":[-6.833,-13.667,0],"ti":[2.667,14,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":24,"s":[1088,495.851,0],"to":[-2.667,-14,0],"ti":[-3.333,13.833,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":27,"s":[1089,451.851,0],"to":[3.333,-13.833,0],"ti":[-9.333,11.5,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":30,"s":[1108,412.851,0],"to":[9.333,-11.5,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":33,"s":[1145,382.851,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.659,"y":0.273},"o":{"x":0.297,"y":0},"t":39,"s":[1148,344.851,0],"to":[0,0,0],"ti":[5.343,-43.734,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.425,"y":0.258},"t":43,"s":[1138.2,425.064,0],"to":[-6.662,54.533,0],"ti":[2.497,-20.44,0]},{"t":45,"s":[1121,565.851,0]}],"ix":2,"l":2},"a":{"a":0,"k":[50,51.351,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":46,"st":0,"bm":0},{"ddd":0,"ind":8,"ty":3,"nm":"chain peg 5","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":12,"s":[-27]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":15,"s":[-27]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":18,"s":[-26]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":21,"s":[-5]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":24,"s":[22]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":27,"s":[49]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":30,"s":[57]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":33,"s":[37]},{"i":{"x":[0.659],"y":[0.273]},"o":{"x":[0.297],"y":[0]},"t":39,"s":[28]},{"i":{"x":[0.815],"y":[0.903]},"o":{"x":[0.425],"y":[0.258]},"t":43,"s":[40.703]},{"t":45,"s":[63]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":12,"s":[1150,620.851,0],"to":[-3.5,-7.167,0],"ti":[7.5,14.167,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":15,"s":[1129,577.851,0],"to":[-7.5,-14.167,0],"ti":[6.833,13.667,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":18,"s":[1105,535.851,0],"to":[-6.833,-13.667,0],"ti":[2.667,14,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":21,"s":[1088,495.851,0],"to":[-2.667,-14,0],"ti":[-3.333,13.833,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":24,"s":[1089,451.851,0],"to":[3.333,-13.833,0],"ti":[-9.333,11.5,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":27,"s":[1108,412.851,0],"to":[9.333,-11.5,0],"ti":[-12.5,9.167,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":30,"s":[1145,382.851,0],"to":[12.5,-9.167,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":33,"s":[1183,357.851,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.659,"y":0.273},"o":{"x":0.297,"y":0},"t":39,"s":[1183,312.851,0],"to":[0,0,0],"ti":[2.968,-48.88,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.425,"y":0.258},"t":43,"s":[1177.556,402.501,0],"to":[-3.701,60.948,0],"ti":[1.387,-22.845,0]},{"t":45,"s":[1168,559.851,0]}],"ix":2,"l":2},"a":{"a":0,"k":[50,51.351,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":46,"st":0,"bm":0},{"ddd":0,"ind":9,"ty":3,"nm":"chain peg 4","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":9,"s":[-27]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":12,"s":[-27]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":15,"s":[-26]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":18,"s":[-5]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":21,"s":[22]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":24,"s":[49]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":27,"s":[57]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":30,"s":[37]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":33,"s":[7]},{"i":{"x":[0.659],"y":[0.273]},"o":{"x":[0.297],"y":[0]},"t":39,"s":[0]},{"i":{"x":[0.815],"y":[0.903]},"o":{"x":[0.425],"y":[0.258]},"t":43,"s":[5.807]},{"t":45,"s":[16]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":9,"s":[1150,620.851,0],"to":[-3.5,-7.167,0],"ti":[7.5,14.167,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":12,"s":[1129,577.851,0],"to":[-7.5,-14.167,0],"ti":[6.833,13.667,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":15,"s":[1105,535.851,0],"to":[-6.833,-13.667,0],"ti":[2.667,14,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":18,"s":[1088,495.851,0],"to":[-2.667,-14,0],"ti":[-3.333,13.833,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":21,"s":[1089,451.851,0],"to":[3.333,-13.833,0],"ti":[-9.333,11.5,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":24,"s":[1108,412.851,0],"to":[9.333,-11.5,0],"ti":[-12.5,9.167,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":27,"s":[1145,382.851,0],"to":[12.5,-9.167,0],"ti":[-10.667,10,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":30,"s":[1183,357.851,0],"to":[10.667,-10,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":33,"s":[1209,322.851,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.659,"y":0.273},"o":{"x":0.297,"y":0},"t":39,"s":[1204,274.851,0],"to":[0,0,0],"ti":[0,-52.046,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.425,"y":0.258},"t":43,"s":[1204,370.308,0],"to":[0,64.896,0],"ti":[0,-24.325,0]},{"t":45,"s":[1204,537.851,0]}],"ix":2,"l":2},"a":{"a":0,"k":[50,51.351,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":46,"st":0,"bm":0},{"ddd":0,"ind":10,"ty":3,"nm":"chain peg 3","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":6,"s":[-27]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":9,"s":[-27]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":12,"s":[-26]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":15,"s":[-5]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":18,"s":[22]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":21,"s":[49]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":24,"s":[57]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":27,"s":[37]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":30,"s":[7]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":33,"s":[-15]},{"i":{"x":[0.659],"y":[0.273]},"o":{"x":[0.297],"y":[0]},"t":39,"s":[-12]},{"i":{"x":[0.815],"y":[0.903]},"o":{"x":[0.425],"y":[0.258]},"t":43,"s":[-22.525]},{"t":45,"s":[-41]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":6,"s":[1150,620.851,0],"to":[-3.5,-7.167,0],"ti":[7.5,14.167,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":9,"s":[1129,577.851,0],"to":[-7.5,-14.167,0],"ti":[6.833,13.667,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":12,"s":[1105,535.851,0],"to":[-6.833,-13.667,0],"ti":[2.667,14,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":15,"s":[1088,495.851,0],"to":[-2.667,-14,0],"ti":[-3.333,13.833,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":18,"s":[1089,451.851,0],"to":[3.333,-13.833,0],"ti":[-9.333,11.5,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":21,"s":[1108,412.851,0],"to":[9.333,-11.5,0],"ti":[-12.5,9.167,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":24,"s":[1145,382.851,0],"to":[12.5,-9.167,0],"ti":[-10.667,10,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":27,"s":[1183,357.851,0],"to":[10.667,-10,0],"ti":[-5.167,13,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":30,"s":[1209,322.851,0],"to":[5.167,-13,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":33,"s":[1214,279.851,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.659,"y":0.273},"o":{"x":0.297,"y":0},"t":39,"s":[1205,231.851,0],"to":[0,0,0],"ti":[-0.989,-52.442,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.425,"y":0.258},"t":43,"s":[1206.815,328.034,0],"to":[1.234,65.39,0],"ti":[-0.462,-24.51,0]},{"t":45,"s":[1210,496.851,0]}],"ix":2,"l":2},"a":{"a":0,"k":[50,51.351,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":46,"st":0,"bm":0},{"ddd":0,"ind":11,"ty":3,"nm":"chain peg 2","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":3,"s":[-27]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":6,"s":[-27]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":9,"s":[-26]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":12,"s":[-5]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":15,"s":[22]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":18,"s":[49]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":21,"s":[57]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":24,"s":[37]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":27,"s":[7]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":30,"s":[-15]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":33,"s":[-43]},{"i":{"x":[0.659],"y":[0.273]},"o":{"x":[0.297],"y":[0]},"t":39,"s":[-24]},{"i":{"x":[0.815],"y":[0.903]},"o":{"x":[0.425],"y":[0.258]},"t":43,"s":[-44.687]},{"t":45,"s":[-81]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":3,"s":[1150,620.851,0],"to":[-3.5,-7.167,0],"ti":[7.5,14.167,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":6,"s":[1129,577.851,0],"to":[-7.5,-14.167,0],"ti":[6.833,13.667,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":9,"s":[1105,535.851,0],"to":[-6.833,-13.667,0],"ti":[2.667,14,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":12,"s":[1088,495.851,0],"to":[-2.667,-14,0],"ti":[-3.333,13.833,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":15,"s":[1089,451.851,0],"to":[3.333,-13.833,0],"ti":[-9.333,11.5,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":18,"s":[1108,412.851,0],"to":[9.333,-11.5,0],"ti":[-12.5,9.167,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":21,"s":[1145,382.851,0],"to":[12.5,-9.167,0],"ti":[-10.667,10,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":24,"s":[1183,357.851,0],"to":[10.667,-10,0],"ti":[-5.167,13,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":27,"s":[1209,322.851,0],"to":[5.167,-13,0],"ti":[1.167,14,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":30,"s":[1214,279.851,0],"to":[-1.167,-14,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":33,"s":[1202,238.851,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.659,"y":0.273},"o":{"x":0.297,"y":0},"t":39,"s":[1196,189.851,0],"to":[0,0,0],"ti":[2.771,-54.816,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.425,"y":0.258},"t":43,"s":[1190.919,290.39,0],"to":[-3.455,68.351,0],"ti":[1.295,-25.62,0]},{"t":45,"s":[1182,466.851,0]}],"ix":2,"l":2},"a":{"a":0,"k":[50,51.351,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":46,"st":0,"bm":0},{"ddd":0,"ind":12,"ty":3,"nm":"chain peg","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[-27]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":3,"s":[-27]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":6,"s":[-26]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":9,"s":[-5]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":12,"s":[22]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":15,"s":[49]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":18,"s":[57]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":21,"s":[37]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":24,"s":[7]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":27,"s":[-15]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0.167]},"t":30,"s":[-43]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.333],"y":[0]},"t":33,"s":[-64]},{"i":{"x":[0.659],"y":[0.273]},"o":{"x":[0.297],"y":[0]},"t":39,"s":[-38]},{"i":{"x":[0.815],"y":[0.903]},"o":{"x":[0.425],"y":[0.258]},"t":43,"s":[-64.857]},{"t":45,"s":[-112]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[1150,620.851,0],"to":[-3.5,-7.167,0],"ti":[7.5,14.167,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":3,"s":[1129,577.851,0],"to":[-7.5,-14.167,0],"ti":[6.833,13.667,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":6,"s":[1105,535.851,0],"to":[-6.833,-13.667,0],"ti":[2.667,14,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":9,"s":[1088,495.851,0],"to":[-2.667,-14,0],"ti":[-3.333,13.833,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":12,"s":[1089,451.851,0],"to":[3.333,-13.833,0],"ti":[-9.333,11.5,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":15,"s":[1108,412.851,0],"to":[9.333,-11.5,0],"ti":[-12.5,9.167,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":18,"s":[1145,382.851,0],"to":[12.5,-9.167,0],"ti":[-10.667,10,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":21,"s":[1183,357.851,0],"to":[10.667,-10,0],"ti":[-5.167,13,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":24,"s":[1209,322.851,0],"to":[5.167,-13,0],"ti":[1.167,14,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":27,"s":[1214,279.851,0],"to":[-1.167,-14,0],"ti":[7.5,11.833,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.167,"y":0.167},"t":30,"s":[1202,238.851,0],"to":[-7.5,-11.833,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":33,"s":[1169,208.851,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.659,"y":0.273},"o":{"x":0.297,"y":0},"t":39,"s":[1178,147.851,0],"to":[0,0,0],"ti":[8.312,-62.534,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.425,"y":0.258},"t":43,"s":[1162.756,262.545,0],"to":[-10.364,77.974,0],"ti":[3.885,-29.227,0]},{"t":45,"s":[1136,463.851,0]}],"ix":2,"l":2},"a":{"a":0,"k":[50,51.351,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":46,"st":0,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":"chain Outlines 12","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-99.47,283.61,0],"ix":2,"l":2},"a":{"a":0,"k":[965.53,543.11,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[12.068,0.316],[0,0],[0.234,-8.939],[0,0],[-5.422,-1.123],[-0.01,3.203],[0,0],[0,0],[-4.425,-0.116],[0.116,-4.425],[0,0],[0,0],[-6.638,-1.008],[-0.005,3.041]],"o":[[-0.014,-16.549],[0,0],[-16.091,-0.422],[0,0],[0.232,3.969],[6.389,1.4],[0.011,-3.203],[0,0],[0.116,-4.425],[4.425,0.116],[0,0],[-0.047,1.815],[0,0],[6.638,1.008],[0,0]],"v":[[22.284,-10.445],[2.561,-34.443],[2.226,-34.451],[-21.278,-12.255],[-22.284,23.59],[-15.666,33.473],[-7.575,24.328],[-7.552,17.702],[-7.162,-4.729],[1.094,-12.565],[8.929,-4.308],[8.514,18.82],[8.529,24.481],[14.805,32.677],[21.846,22.812]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.996078491211,0.839215746113,0.027450982262,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[1115.086,285.506],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":46,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":"chain Outlines 11","parent":2,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-99.47,283.61,0],"ix":2,"l":2},"a":{"a":0,"k":[965.53,543.11,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[12.068,0.316],[0,0],[0.234,-8.939],[0,0],[-5.422,-1.123],[-0.01,3.203],[0,0],[0,0],[-4.425,-0.116],[0.116,-4.425],[0,0],[0,0],[-6.638,-1.008],[-0.005,3.041]],"o":[[-0.014,-16.549],[0,0],[-16.091,-0.422],[0,0],[0.232,3.969],[6.389,1.4],[0.011,-3.203],[0,0],[0.116,-4.425],[4.425,0.116],[0,0],[-0.047,1.815],[0,0],[6.638,1.008],[0,0]],"v":[[22.284,-10.445],[2.561,-34.443],[2.226,-34.451],[-21.278,-12.255],[-22.284,23.59],[-15.666,33.473],[-7.575,24.328],[-7.552,17.702],[-7.162,-4.729],[1.094,-12.565],[8.929,-4.308],[8.514,18.82],[8.529,24.481],[14.805,32.677],[21.846,22.812]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.996078491211,0.839215746113,0.027450982262,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[1115.086,285.506],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":46,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":15,"ty":4,"nm":"chain Outlines 10","parent":3,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-99.47,283.61,0],"ix":2,"l":2},"a":{"a":0,"k":[965.53,543.11,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[12.068,0.316],[0,0],[0.234,-8.939],[0,0],[-5.422,-1.123],[-0.01,3.203],[0,0],[0,0],[-4.425,-0.116],[0.116,-4.425],[0,0],[0,0],[-6.638,-1.008],[-0.005,3.041]],"o":[[-0.014,-16.549],[0,0],[-16.091,-0.422],[0,0],[0.232,3.969],[6.389,1.4],[0.011,-3.203],[0,0],[0.116,-4.425],[4.425,0.116],[0,0],[-0.047,1.815],[0,0],[6.638,1.008],[0,0]],"v":[[22.284,-10.445],[2.561,-34.443],[2.226,-34.451],[-21.278,-12.255],[-22.284,23.59],[-15.666,33.473],[-7.575,24.328],[-7.552,17.702],[-7.162,-4.729],[1.094,-12.565],[8.929,-4.308],[8.514,18.82],[8.529,24.481],[14.805,32.677],[21.846,22.812]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.996078491211,0.839215746113,0.027450982262,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[1115.086,285.506],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":46,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":16,"ty":4,"nm":"chain Outlines 9","parent":4,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-99.47,283.61,0],"ix":2,"l":2},"a":{"a":0,"k":[965.53,543.11,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[12.068,0.316],[0,0],[0.234,-8.939],[0,0],[-5.422,-1.123],[-0.01,3.203],[0,0],[0,0],[-4.425,-0.116],[0.116,-4.425],[0,0],[0,0],[-6.638,-1.008],[-0.005,3.041]],"o":[[-0.014,-16.549],[0,0],[-16.091,-0.422],[0,0],[0.232,3.969],[6.389,1.4],[0.011,-3.203],[0,0],[0.116,-4.425],[4.425,0.116],[0,0],[-0.047,1.815],[0,0],[6.638,1.008],[0,0]],"v":[[22.284,-10.445],[2.561,-34.443],[2.226,-34.451],[-21.278,-12.255],[-22.284,23.59],[-15.666,33.473],[-7.575,24.328],[-7.552,17.702],[-7.162,-4.729],[1.094,-12.565],[8.929,-4.308],[8.514,18.82],[8.529,24.481],[14.805,32.677],[21.846,22.812]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.996078491211,0.839215746113,0.027450982262,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[1115.086,285.506],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":46,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":17,"ty":4,"nm":"chain Outlines 8","parent":5,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-99.47,283.61,0],"ix":2,"l":2},"a":{"a":0,"k":[965.53,543.11,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[12.068,0.316],[0,0],[0.234,-8.939],[0,0],[-5.422,-1.123],[-0.01,3.203],[0,0],[0,0],[-4.425,-0.116],[0.116,-4.425],[0,0],[0,0],[-6.638,-1.008],[-0.005,3.041]],"o":[[-0.014,-16.549],[0,0],[-16.091,-0.422],[0,0],[0.232,3.969],[6.389,1.4],[0.011,-3.203],[0,0],[0.116,-4.425],[4.425,0.116],[0,0],[-0.047,1.815],[0,0],[6.638,1.008],[0,0]],"v":[[22.284,-10.445],[2.561,-34.443],[2.226,-34.451],[-21.278,-12.255],[-22.284,23.59],[-15.666,33.473],[-7.575,24.328],[-7.552,17.702],[-7.162,-4.729],[1.094,-12.565],[8.929,-4.308],[8.514,18.82],[8.529,24.481],[14.805,32.677],[21.846,22.812]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.996078491211,0.839215746113,0.027450982262,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[1115.086,285.506],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":46,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":18,"ty":4,"nm":"chain Outlines 7","parent":6,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-99.47,283.61,0],"ix":2,"l":2},"a":{"a":0,"k":[965.53,543.11,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[12.068,0.316],[0,0],[0.234,-8.939],[0,0],[-5.422,-1.123],[-0.01,3.203],[0,0],[0,0],[-4.425,-0.116],[0.116,-4.425],[0,0],[0,0],[-6.638,-1.008],[-0.005,3.041]],"o":[[-0.014,-16.549],[0,0],[-16.091,-0.422],[0,0],[0.232,3.969],[6.389,1.4],[0.011,-3.203],[0,0],[0.116,-4.425],[4.425,0.116],[0,0],[-0.047,1.815],[0,0],[6.638,1.008],[0,0]],"v":[[22.284,-10.445],[2.561,-34.443],[2.226,-34.451],[-21.278,-12.255],[-22.284,23.59],[-15.666,33.473],[-7.575,24.328],[-7.552,17.702],[-7.162,-4.729],[1.094,-12.565],[8.929,-4.308],[8.514,18.82],[8.529,24.481],[14.805,32.677],[21.846,22.812]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.996078491211,0.839215746113,0.027450982262,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[1115.086,285.506],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":46,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":19,"ty":4,"nm":"chain Outlines 6","parent":7,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-99.47,283.61,0],"ix":2,"l":2},"a":{"a":0,"k":[965.53,543.11,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[12.068,0.316],[0,0],[0.234,-8.939],[0,0],[-5.422,-1.123],[-0.01,3.203],[0,0],[0,0],[-4.425,-0.116],[0.116,-4.425],[0,0],[0,0],[-6.638,-1.008],[-0.005,3.041]],"o":[[-0.014,-16.549],[0,0],[-16.091,-0.422],[0,0],[0.232,3.969],[6.389,1.4],[0.011,-3.203],[0,0],[0.116,-4.425],[4.425,0.116],[0,0],[-0.047,1.815],[0,0],[6.638,1.008],[0,0]],"v":[[22.284,-10.445],[2.561,-34.443],[2.226,-34.451],[-21.278,-12.255],[-22.284,23.59],[-15.666,33.473],[-7.575,24.328],[-7.552,17.702],[-7.162,-4.729],[1.094,-12.565],[8.929,-4.308],[8.514,18.82],[8.529,24.481],[14.805,32.677],[21.846,22.812]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.996078491211,0.839215746113,0.027450982262,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[1115.086,285.506],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":46,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":20,"ty":4,"nm":"chain Outlines 5","parent":8,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-99.47,283.61,0],"ix":2,"l":2},"a":{"a":0,"k":[965.53,543.11,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[12.068,0.316],[0,0],[0.234,-8.939],[0,0],[-5.422,-1.123],[-0.01,3.203],[0,0],[0,0],[-4.425,-0.116],[0.116,-4.425],[0,0],[0,0],[-6.638,-1.008],[-0.005,3.041]],"o":[[-0.014,-16.549],[0,0],[-16.091,-0.422],[0,0],[0.232,3.969],[6.389,1.4],[0.011,-3.203],[0,0],[0.116,-4.425],[4.425,0.116],[0,0],[-0.047,1.815],[0,0],[6.638,1.008],[0,0]],"v":[[22.284,-10.445],[2.561,-34.443],[2.226,-34.451],[-21.278,-12.255],[-22.284,23.59],[-15.666,33.473],[-7.575,24.328],[-7.552,17.702],[-7.162,-4.729],[1.094,-12.565],[8.929,-4.308],[8.514,18.82],[8.529,24.481],[14.805,32.677],[21.846,22.812]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.996078491211,0.839215746113,0.027450982262,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[1115.086,285.506],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":46,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":21,"ty":4,"nm":"chain Outlines 4","parent":9,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-99.47,283.61,0],"ix":2,"l":2},"a":{"a":0,"k":[965.53,543.11,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[12.068,0.316],[0,0],[0.234,-8.939],[0,0],[-5.422,-1.123],[-0.01,3.203],[0,0],[0,0],[-4.425,-0.116],[0.116,-4.425],[0,0],[0,0],[-6.638,-1.008],[-0.005,3.041]],"o":[[-0.014,-16.549],[0,0],[-16.091,-0.422],[0,0],[0.232,3.969],[6.389,1.4],[0.011,-3.203],[0,0],[0.116,-4.425],[4.425,0.116],[0,0],[-0.047,1.815],[0,0],[6.638,1.008],[0,0]],"v":[[22.284,-10.445],[2.561,-34.443],[2.226,-34.451],[-21.278,-12.255],[-22.284,23.59],[-15.666,33.473],[-7.575,24.328],[-7.552,17.702],[-7.162,-4.729],[1.094,-12.565],[8.929,-4.308],[8.514,18.82],[8.529,24.481],[14.805,32.677],[21.846,22.812]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.996078491211,0.839215746113,0.027450982262,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[1115.086,285.506],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":46,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":22,"ty":4,"nm":"chain Outlines 3","parent":10,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-99.47,283.61,0],"ix":2,"l":2},"a":{"a":0,"k":[965.53,543.11,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[12.068,0.316],[0,0],[0.234,-8.939],[0,0],[-5.422,-1.123],[-0.01,3.203],[0,0],[0,0],[-4.425,-0.116],[0.116,-4.425],[0,0],[0,0],[-6.638,-1.008],[-0.005,3.041]],"o":[[-0.014,-16.549],[0,0],[-16.091,-0.422],[0,0],[0.232,3.969],[6.389,1.4],[0.011,-3.203],[0,0],[0.116,-4.425],[4.425,0.116],[0,0],[-0.047,1.815],[0,0],[6.638,1.008],[0,0]],"v":[[22.284,-10.445],[2.561,-34.443],[2.226,-34.451],[-21.278,-12.255],[-22.284,23.59],[-15.666,33.473],[-7.575,24.328],[-7.552,17.702],[-7.162,-4.729],[1.094,-12.565],[8.929,-4.308],[8.514,18.82],[8.529,24.481],[14.805,32.677],[21.846,22.812]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.996078491211,0.839215746113,0.027450982262,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[1115.086,285.506],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":46,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":23,"ty":4,"nm":"chain Outlines 2","parent":11,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-99.47,283.61,0],"ix":2,"l":2},"a":{"a":0,"k":[965.53,543.11,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[12.068,0.316],[0,0],[0.234,-8.939],[0,0],[-5.422,-1.123],[-0.01,3.203],[0,0],[0,0],[-4.425,-0.116],[0.116,-4.425],[0,0],[0,0],[-6.638,-1.008],[-0.005,3.041]],"o":[[-0.014,-16.549],[0,0],[-16.091,-0.422],[0,0],[0.232,3.969],[6.389,1.4],[0.011,-3.203],[0,0],[0.116,-4.425],[4.425,0.116],[0,0],[-0.047,1.815],[0,0],[6.638,1.008],[0,0]],"v":[[22.284,-10.445],[2.561,-34.443],[2.226,-34.451],[-21.278,-12.255],[-22.284,23.59],[-15.666,33.473],[-7.575,24.328],[-7.552,17.702],[-7.162,-4.729],[1.094,-12.565],[8.929,-4.308],[8.514,18.82],[8.529,24.481],[14.805,32.677],[21.846,22.812]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.996078491211,0.839215746113,0.027450982262,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[1115.086,285.506],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":46,"st":0,"ct":1,"bm":0},{"ddd":0,"ind":24,"ty":4,"nm":"chain Outlines","parent":12,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-99.47,283.61,0],"ix":2,"l":2},"a":{"a":0,"k":[965.53,543.11,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[12.068,0.316],[0,0],[0.234,-8.939],[0,0],[-5.422,-1.123],[-0.01,3.203],[0,0],[0,0],[-4.425,-0.116],[0.116,-4.425],[0,0],[0,0],[-6.638,-1.008],[-0.005,3.041]],"o":[[-0.014,-16.549],[0,0],[-16.091,-0.422],[0,0],[0.232,3.969],[6.389,1.4],[0.011,-3.203],[0,0],[0.116,-4.425],[4.425,0.116],[0,0],[-0.047,1.815],[0,0],[6.638,1.008],[0,0]],"v":[[22.284,-10.445],[2.561,-34.443],[2.226,-34.451],[-21.278,-12.255],[-22.284,23.59],[-15.666,33.473],[-7.575,24.328],[-7.552,17.702],[-7.162,-4.729],[1.094,-12.565],[8.929,-4.308],[8.514,18.82],[8.529,24.481],[14.805,32.677],[21.846,22.812]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0,0.129411764706,0.250980392157,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.996078491211,0.839215746113,0.027450982262,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[1115.086,285.506],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":46,"st":0,"ct":1,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"Expensify-Magic-Link-120822-kjs-1","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[425.5,319,0],"ix":2,"l":2},"a":{"a":0,"k":[966,543.5,0],"ix":1,"l":2},"s":{"a":0,"k":[56,56,100],"ix":6,"l":2}},"ao":0,"w":1932,"h":1087,"ip":0,"op":69,"st":0,"ct":1,"bm":0}],"markers":[]}
\ No newline at end of file
diff --git a/assets/emojis/es.js b/assets/emojis/es.js
index c38aec7aa754..fda12f5f127c 100644
--- a/assets/emojis/es.js
+++ b/assets/emojis/es.js
@@ -6208,1044 +6208,1044 @@ const esEmojis = {
keywords: ['Bandera'],
},
'🇦🇩': {
- name: 'bandera-ad',
- keywords: ['Bandera'],
+ name: 'andorra',
+ keywords: ['bandera', 'bandera-ad'],
},
'🇦🇪': {
- name: 'bandera-ae',
- keywords: ['Bandera'],
+ name: 'emiratos_árabes_unidos',
+ keywords: ['bandera', 'bandera-ae'],
},
'🇦🇫': {
- name: 'bandera-af',
- keywords: ['Bandera'],
+ name: 'afganistán',
+ keywords: ['bandera', 'bandera-af'],
},
'🇦🇬': {
- name: 'bandera-ag',
- keywords: ['Bandera'],
+ name: 'antigua_y_barbuda',
+ keywords: ['bandera', 'bandera-ag'],
},
'🇦🇮': {
- name: 'bandera-ai',
- keywords: ['Bandera'],
+ name: 'anguila',
+ keywords: ['bandera', 'bandera-ai'],
},
'🇦🇱': {
- name: 'bandera-al',
- keywords: ['Bandera'],
+ name: 'albania',
+ keywords: ['bandera', 'bandera-al'],
},
'🇦🇲': {
- name: 'bandera-am',
- keywords: ['Bandera'],
+ name: 'armenia',
+ keywords: ['bandera', 'bandera-am'],
},
'🇦🇴': {
- name: 'bandera-ao',
- keywords: ['Bandera'],
+ name: 'angola',
+ keywords: ['bandera', 'bandera-ao'],
},
'🇦🇶': {
- name: 'bandera-aq',
- keywords: ['Bandera'],
+ name: 'antártida',
+ keywords: ['bandera', 'bandera-aq'],
},
'🇦🇷': {
- name: 'bandera-ar',
- keywords: ['Bandera'],
+ name: 'argentina',
+ keywords: ['bandera', 'bandera-ar'],
},
'🇦🇸': {
- name: 'bandera-as',
- keywords: ['Bandera'],
+ name: 'samoa_americana',
+ keywords: ['bandera', 'bandera-as'],
},
'🇦🇹': {
- name: 'bandera-at',
- keywords: ['Bandera'],
+ name: 'austria',
+ keywords: ['bandera', 'bandera-at'],
},
'🇦🇺': {
- name: 'bandera-au',
- keywords: ['Bandera'],
+ name: 'australia',
+ keywords: ['bandera', 'bandera-au'],
},
'🇦🇼': {
- name: 'bandera-aw',
- keywords: ['Bandera'],
+ name: 'aruba',
+ keywords: ['bandera', 'bandera-aw'],
},
'🇦🇽': {
- name: 'bandera-ax',
- keywords: ['Bandera'],
+ name: 'islas_de_åland',
+ keywords: ['bandera', 'bandera-ax'],
},
'🇦🇿': {
- name: 'bandera-az',
- keywords: ['Bandera'],
+ name: 'azerbaiyán',
+ keywords: ['bandera', 'bandera-az'],
},
'🇧🇦': {
- name: 'bandera-ba',
- keywords: ['Bandera'],
+ name: 'bosnia_y_herzegovina',
+ keywords: ['bandera', 'bandera-ba'],
},
'🇧🇧': {
- name: 'bandera-bb',
- keywords: ['Bandera'],
+ name: 'barbados',
+ keywords: ['bandera', 'bandera-bb'],
},
'🇧🇩': {
- name: 'bandera-bd',
- keywords: ['Bandera'],
+ name: 'bangladesh',
+ keywords: ['bandera', 'bandera-bd'],
},
'🇧🇪': {
- name: 'bandera-be',
- keywords: ['Bandera'],
+ name: 'bélgica',
+ keywords: ['bandera', 'bandera-be'],
},
'🇧🇫': {
- name: 'bandera-bf',
- keywords: ['Bandera'],
+ name: 'burkina_faso',
+ keywords: ['bandera', 'bandera-bf'],
},
'🇧🇬': {
- name: 'bandera-bg',
- keywords: ['Bandera'],
+ name: 'bulgaria',
+ keywords: ['bandera', 'bandera-bg'],
},
'🇧🇭': {
- name: 'bandera-bh',
- keywords: ['Bandera'],
+ name: 'bahrein',
+ keywords: ['bandera', 'bandera-bh'],
},
'🇧🇮': {
- name: 'bandera-bi',
- keywords: ['Bandera'],
+ name: 'burundi',
+ keywords: ['bandera', 'bandera-bi'],
},
'🇧🇯': {
- name: 'bandera-bj',
- keywords: ['Bandera'],
+ name: 'benin',
+ keywords: ['bandera', 'bandera-bj'],
},
'🇧🇱': {
- name: 'bandera-bl',
- keywords: ['Bandera'],
+ name: 'san_bartolomé',
+ keywords: ['bandera', 'bandera-bl'],
},
'🇧🇲': {
- name: 'bandera-bm',
- keywords: ['Bandera'],
+ name: 'islas_bermudas',
+ keywords: ['bandera', 'bandera-bm'],
},
'🇧🇳': {
- name: 'bandera-bn',
- keywords: ['Bandera'],
+ name: 'brunéi',
+ keywords: ['bandera', 'bandera-bn'],
},
'🇧🇴': {
- name: 'bandera-bo',
- keywords: ['Bandera'],
+ name: 'bolivia',
+ keywords: ['bandera', 'bandera-bo'],
},
'🇧🇶': {
- name: 'bandera-bq',
- keywords: ['Bandera'],
+ name: 'bonaire,_san_eustaquio_y_saba',
+ keywords: ['bandera', 'bandera-bq'],
},
'🇧🇷': {
- name: 'bandera-br',
- keywords: ['Bandera'],
+ name: 'brazil',
+ keywords: ['bandera', 'bandera-br'],
},
'🇧🇸': {
- name: 'bandera-bs',
- keywords: ['Bandera'],
+ name: 'bahamas',
+ keywords: ['bandera', 'bandera-bs'],
},
'🇧🇹': {
- name: 'bandera-bt',
- keywords: ['Bandera'],
+ name: 'bhután',
+ keywords: ['bandera', 'bandera-bt'],
},
'🇧🇻': {
name: 'bandera-bv',
- keywords: ['Bandera'],
+ keywords: ['Bandera', 'bandera-bv'],
},
'🇧🇼': {
- name: 'bandera-bw',
- keywords: ['Bandera'],
+ name: 'botsuana',
+ keywords: ['bandera', 'bandera-bw'],
},
'🇧🇾': {
- name: 'bandera-by',
- keywords: ['Bandera'],
+ name: 'bielorrusia',
+ keywords: ['bandera', 'bandera-by'],
},
'🇧🇿': {
- name: 'bandera-bz',
- keywords: ['Bandera'],
+ name: 'belice',
+ keywords: ['bandera', 'bandera-bz'],
},
'🇨🇦': {
- name: 'bandera-ca',
- keywords: ['Bandera'],
+ name: 'canadá',
+ keywords: ['bandera', 'bandera-ca'],
},
'🇨🇨': {
- name: 'bandera-cc',
- keywords: ['Bandera'],
+ name: 'islas_cocos_(keeling)',
+ keywords: ['bandera', 'bandera-cc'],
},
'🇨🇩': {
- name: 'bandera-cd',
- keywords: ['Bandera'],
+ name: 'república_democrática_del_congo',
+ keywords: ['bandera', 'bandera-cd'],
},
'🇨🇫': {
- name: 'bandera-cf',
- keywords: ['Bandera'],
+ name: 'república_centroafricana',
+ keywords: ['bandera', 'bandera-cf'],
},
'🇨🇬': {
- name: 'bandera-cg',
- keywords: ['Bandera'],
+ name: 'república_del_congo',
+ keywords: ['bandera', 'bandera-cg'],
},
'🇨🇭': {
- name: 'bandera-ch',
- keywords: ['Bandera'],
+ name: 'suiza',
+ keywords: ['bandera', 'bandera-ch'],
},
'🇨🇮': {
- name: 'bandera-ci',
- keywords: ['Bandera'],
+ name: 'costa_de_marfil',
+ keywords: ['bandera', 'bandera-ci'],
},
'🇨🇰': {
- name: 'bandera-ck',
- keywords: ['Bandera'],
+ name: 'islas_cook',
+ keywords: ['bandera', 'bandera-ck'],
},
'🇨🇱': {
- name: 'bandera-cl',
- keywords: ['Bandera'],
+ name: 'chile',
+ keywords: ['bandera', 'bandera-cl'],
},
'🇨🇲': {
- name: 'bandera-cm',
- keywords: ['Bandera'],
+ name: 'camerún',
+ keywords: ['bandera', 'bandera-cm'],
},
'🇨🇳': {
- name: 'cn',
- keywords: ['Bandera'],
+ name: 'china',
+ keywords: ['bandera', 'bandera-cn'],
},
'🇨🇴': {
- name: 'bandera-co',
- keywords: ['Bandera'],
+ name: 'colombia',
+ keywords: ['bandera', 'bandera-co'],
},
'🇨🇵': {
name: 'bandera-cp',
- keywords: ['Bandera'],
+ keywords: ['Bandera', 'bandera-cp'],
},
'🇨🇷': {
- name: 'bandera-cr',
- keywords: ['Bandera'],
+ name: 'costa_rica',
+ keywords: ['bandera', 'bandera-cr'],
},
'🇨🇺': {
- name: 'bandera-cu',
- keywords: ['Bandera'],
+ name: 'cuba',
+ keywords: ['bandera', 'bandera-cu'],
},
'🇨🇻': {
- name: 'bandera-cv',
- keywords: ['Bandera'],
+ name: 'cabo_verde',
+ keywords: ['bandera', 'bandera-cv'],
},
'🇨🇼': {
- name: 'bandera-cw',
- keywords: ['Bandera'],
+ name: 'curazao',
+ keywords: ['bandera', 'bandera-cw'],
},
'🇨🇽': {
- name: 'bandera-cx',
- keywords: ['Bandera'],
+ name: 'isla_de_navidad',
+ keywords: ['bandera', 'bandera-cx'],
},
'🇨🇾': {
- name: 'bandera-cy',
- keywords: ['Bandera'],
+ name: 'chipre',
+ keywords: ['bandera', 'bandera-cy'],
},
'🇨🇿': {
- name: 'bandera-cz',
- keywords: ['Bandera'],
+ name: 'república_checa',
+ keywords: ['bandera', 'bandera-cz'],
},
'🇩🇪': {
- name: 'de',
- keywords: ['Bandera'],
+ name: 'alemania',
+ keywords: ['bandera', 'bandera-de'],
},
'🇩🇬': {
name: 'bandera-dg',
- keywords: ['Bandera'],
+ keywords: ['Bandera', 'bandera-dg'],
},
'🇩🇯': {
- name: 'bandera-dj',
- keywords: ['Bandera'],
+ name: 'yibuti',
+ keywords: ['bandera', 'bandera-dj'],
},
'🇩🇰': {
- name: 'bandera-dk',
- keywords: ['Bandera'],
+ name: 'dinamarca',
+ keywords: ['bandera', 'bandera-dk'],
},
'🇩🇲': {
- name: 'bandera-dm',
- keywords: ['Bandera'],
+ name: 'dominica',
+ keywords: ['bandera', 'bandera-dm'],
},
'🇩🇴': {
- name: 'bandera-do',
- keywords: ['Bandera'],
+ name: 'república_dominicana',
+ keywords: ['bandera', 'bandera-do'],
},
'🇩🇿': {
- name: 'bandera-dz',
- keywords: ['Bandera'],
+ name: 'argelia',
+ keywords: ['bandera', 'bandera-dz'],
},
'🇪🇦': {
name: 'bandera-ea',
- keywords: ['Bandera'],
+ keywords: ['Bandera', 'bandera-ea'],
},
'🇪🇨': {
- name: 'bandera-ec',
- keywords: ['Bandera'],
+ name: 'ecuador',
+ keywords: ['bandera', 'bandera-ec'],
},
'🇪🇪': {
- name: 'bandera-ee',
- keywords: ['Bandera'],
+ name: 'estonia',
+ keywords: ['bandera', 'bandera-ee'],
},
'🇪🇬': {
- name: 'bandera-eg',
- keywords: ['Bandera'],
+ name: 'egipto',
+ keywords: ['bandera', 'bandera-eg'],
},
'🇪🇭': {
- name: 'bandera-eh',
- keywords: ['Bandera'],
+ name: 'sahara_occidental',
+ keywords: ['bandera', 'bandera-eh'],
},
'🇪🇷': {
- name: 'bandera-er',
- keywords: ['Bandera'],
+ name: 'eritrea',
+ keywords: ['bandera', 'bandera-er'],
},
'🇪🇸': {
- name: 'es',
- keywords: ['Bandera'],
+ name: 'españa',
+ keywords: ['bandera', 'bandera-es'],
},
'🇪🇹': {
- name: 'bandera-et',
- keywords: ['Bandera'],
+ name: 'etiopía',
+ keywords: ['bandera', 'bandera-et'],
},
'🇪🇺': {
name: 'bandera-eu',
- keywords: ['Bandera'],
+ keywords: ['Bandera', 'bandera-eu'],
},
'🇫🇮': {
- name: 'bandera-fi',
- keywords: ['Bandera'],
+ name: 'finlandia',
+ keywords: ['bandera', 'bandera-fi'],
},
'🇫🇯': {
- name: 'bandera-fj',
- keywords: ['Bandera'],
+ name: 'fiyi',
+ keywords: ['bandera', 'bandera-fj'],
},
'🇫🇰': {
- name: 'bandera-fk',
- keywords: ['Bandera'],
+ name: 'islas_malvinas',
+ keywords: ['bandera', 'bandera-fk'],
},
'🇫🇲': {
- name: 'bandera-fm',
- keywords: ['Bandera'],
+ name: 'micronesia',
+ keywords: ['bandera', 'bandera-fm'],
},
'🇫🇴': {
- name: 'bandera-fo',
- keywords: ['Bandera'],
+ name: 'islas_feroe',
+ keywords: ['bandera', 'bandera-fo'],
},
'🇫🇷': {
- name: 'fr',
- keywords: ['Bandera'],
+ name: 'francia',
+ keywords: ['bandera', 'bandera-fr'],
},
'🇬🇦': {
- name: 'bandera-ga',
- keywords: ['Bandera'],
+ name: 'gabón',
+ keywords: ['bandera', 'bandera-ga'],
},
'🇬🇧': {
- name: 'gb',
- keywords: ['Bandera'],
+ name: 'reino_unido',
+ keywords: ['bandera', 'bandera-gb'],
},
'🇬🇩': {
- name: 'bandera-gd',
- keywords: ['Bandera'],
+ name: 'granada',
+ keywords: ['bandera', 'bandera-gd'],
},
'🇬🇪': {
- name: 'bandera-ge',
- keywords: ['Bandera'],
+ name: 'georgia',
+ keywords: ['bandera', 'bandera-ge'],
},
'🇬🇫': {
- name: 'bandera-gf',
- keywords: ['Bandera'],
+ name: 'guayana_francesa',
+ keywords: ['bandera', 'bandera-gf'],
},
'🇬🇬': {
- name: 'bandera-gg',
- keywords: ['Bandera'],
+ name: 'guernsey',
+ keywords: ['bandera', 'bandera-gg'],
},
'🇬🇭': {
- name: 'bandera-gh',
- keywords: ['Bandera'],
+ name: 'ghana',
+ keywords: ['bandera', 'bandera-gh'],
},
'🇬🇮': {
- name: 'bandera-gi',
- keywords: ['Bandera'],
+ name: 'gibraltar',
+ keywords: ['bandera', 'bandera-gi'],
},
'🇬🇱': {
- name: 'bandera-gl',
- keywords: ['Bandera'],
+ name: 'groenlandia',
+ keywords: ['bandera', 'bandera-gl'],
},
'🇬🇲': {
- name: 'bandera-gm',
- keywords: ['Bandera'],
+ name: 'gambia',
+ keywords: ['bandera', 'bandera-gm'],
},
'🇬🇳': {
- name: 'bandera-gn',
- keywords: ['Bandera'],
+ name: 'guinea',
+ keywords: ['bandera', 'bandera-gn'],
},
'🇬🇵': {
- name: 'bandera-gp',
- keywords: ['Bandera'],
+ name: 'guadeloupe',
+ keywords: ['bandera', 'bandera-gp'],
},
'🇬🇶': {
- name: 'bandera-gq',
- keywords: ['Bandera'],
+ name: 'guinea_ecuatorial',
+ keywords: ['bandera', 'bandera-gq'],
},
'🇬🇷': {
- name: 'bandera-gr',
- keywords: ['Bandera'],
+ name: 'greece',
+ keywords: ['bandera', 'bandera-gr'],
},
'🇬🇸': {
- name: 'bandera-gs',
- keywords: ['Bandera'],
+ name: 'islas_georgias_del_sur_y_sandwich_del_sur',
+ keywords: ['bandera', 'bandera-gs'],
},
'🇬🇹': {
- name: 'bandera-gt',
- keywords: ['Bandera'],
+ name: 'guatemala',
+ keywords: ['bandera', 'bandera-gt'],
},
'🇬🇺': {
- name: 'bandera-gu',
- keywords: ['Bandera'],
+ name: 'guam',
+ keywords: ['bandera', 'bandera-gu'],
},
'🇬🇼': {
- name: 'bandera-gw',
- keywords: ['Bandera'],
+ name: 'guinea-bissau',
+ keywords: ['bandera', 'bandera-gw'],
},
'🇬🇾': {
- name: 'bandera-gy',
- keywords: ['Bandera'],
+ name: 'guyana',
+ keywords: ['bandera', 'bandera-gy'],
},
'🇭🇰': {
- name: 'bandera-hk',
- keywords: ['Bandera'],
+ name: 'hong_kong',
+ keywords: ['bandera', 'bandera-hk'],
},
'🇭🇲': {
name: 'bandera-hm',
- keywords: ['Bandera'],
+ keywords: ['Bandera', 'bandera-hm'],
},
'🇭🇳': {
- name: 'bandera-hn',
- keywords: ['Bandera'],
+ name: 'honduras',
+ keywords: ['bandera', 'bandera-hn'],
},
'🇭🇷': {
- name: 'bandera-hr',
- keywords: ['Bandera'],
+ name: 'croacia',
+ keywords: ['bandera', 'bandera-hr'],
},
'🇭🇹': {
- name: 'bandera-ht',
- keywords: ['Bandera'],
+ name: 'haiti',
+ keywords: ['bandera', 'bandera-ht'],
},
'🇭🇺': {
- name: 'bandera-hu',
- keywords: ['Bandera'],
+ name: 'hungría',
+ keywords: ['bandera', 'bandera-hu'],
},
'🇮🇨': {
name: 'bandera-ic',
- keywords: ['Bandera'],
+ keywords: ['Bandera', 'bandera-ic'],
},
'🇮🇩': {
- name: 'bandera-id',
- keywords: ['Bandera'],
+ name: 'indonesia',
+ keywords: ['bandera', 'bandera-id'],
},
'🇮🇪': {
- name: 'bandera-ie',
- keywords: ['Bandera'],
+ name: 'irlanda',
+ keywords: ['bandera', 'bandera-ie'],
},
'🇮🇱': {
- name: 'bandera-il',
- keywords: ['Bandera'],
+ name: 'israel',
+ keywords: ['bandera', 'bandera-il'],
},
'🇮🇲': {
- name: 'bandera-im',
- keywords: ['Bandera'],
+ name: 'isla_de_man',
+ keywords: ['bandera', 'bandera-im'],
},
'🇮🇳': {
- name: 'bandera-in',
- keywords: ['Bandera'],
+ name: 'india',
+ keywords: ['bandera', 'bandera-in'],
},
'🇮🇴': {
- name: 'bandera-io',
- keywords: ['Bandera'],
+ name: 'territorio_británico_del_océano_índico',
+ keywords: ['bandera', 'bandera-io'],
},
'🇮🇶': {
- name: 'bandera-iq',
- keywords: ['Bandera'],
+ name: 'irak',
+ keywords: ['bandera', 'bandera-iq'],
},
'🇮🇷': {
- name: 'bandera-ir',
- keywords: ['Bandera'],
+ name: 'irán',
+ keywords: ['bandera', 'bandera-ir'],
},
'🇮🇸': {
- name: 'bandera-is',
- keywords: ['Bandera'],
+ name: 'islandia',
+ keywords: ['bandera', 'bandera-is'],
},
'🇮🇹': {
- name: 'it',
- keywords: ['Bandera'],
+ name: 'italia',
+ keywords: ['bandera', 'bandera-it'],
},
'🇯🇪': {
- name: 'bandera-je',
- keywords: ['Bandera'],
+ name: 'jersey',
+ keywords: ['bandera', 'bandera-je'],
},
'🇯🇲': {
- name: 'bandera-jm',
- keywords: ['Bandera'],
+ name: 'jamaica',
+ keywords: ['bandera', 'bandera-jm'],
},
'🇯🇴': {
- name: 'bandera-jo',
- keywords: ['Bandera'],
+ name: 'jordania',
+ keywords: ['bandera', 'bandera-jo'],
},
'🇯🇵': {
- name: 'jp',
- keywords: ['Bandera'],
+ name: 'japón',
+ keywords: ['bandera', 'bandera-jp'],
},
'🇰🇪': {
- name: 'bandera-ke',
- keywords: ['Bandera'],
+ name: 'kenia',
+ keywords: ['bandera', 'bandera-ke'],
},
'🇰🇬': {
- name: 'bandera-kg',
- keywords: ['Bandera'],
+ name: 'kirguistán',
+ keywords: ['bandera', 'bandera-kg'],
},
'🇰🇭': {
- name: 'bandera-kh',
- keywords: ['Bandera'],
+ name: 'camboya',
+ keywords: ['bandera', 'bandera-kh'],
},
'🇰🇮': {
name: 'bandera-kl',
- keywords: ['Bandera'],
+ keywords: ['Bandera', 'bandera-kl'],
},
'🇰🇲': {
- name: 'bandera-km',
- keywords: ['Bandera'],
+ name: 'comoras',
+ keywords: ['bandera', 'bandera-km'],
},
'🇰🇳': {
- name: 'bandera-kn',
- keywords: ['Bandera'],
+ name: 'san_cristóbal_y_nieves',
+ keywords: ['bandera', 'bandera-kn'],
},
'🇰🇵': {
- name: 'bandera-kp',
- keywords: ['Bandera'],
+ name: 'corea_del_norte',
+ keywords: ['bandera', 'bandera-kp'],
},
'🇰🇷': {
- name: 'kr',
- keywords: ['Bandera'],
+ name: 'corea_del_sur',
+ keywords: ['bandera', 'bandera-kr'],
},
'🇰🇼': {
- name: 'bandera-kw',
- keywords: ['Bandera'],
+ name: 'kuwait',
+ keywords: ['bandera', 'bandera-kw'],
},
'🇰🇾': {
- name: 'bandera-ky',
- keywords: ['Bandera'],
+ name: 'islas_caimán',
+ keywords: ['bandera', 'bandera-ky'],
},
'🇰🇿': {
- name: 'bandera-kz',
- keywords: ['Bandera'],
+ name: 'kazajistán',
+ keywords: ['bandera', 'bandera-kz'],
},
'🇱🇦': {
- name: 'bandera-la',
- keywords: ['Bandera'],
+ name: 'laos',
+ keywords: ['bandera', 'bandera-la'],
},
'🇱🇧': {
- name: 'bandera-lb',
- keywords: ['Bandera'],
+ name: 'líbano',
+ keywords: ['bandera', 'bandera-lb'],
},
'🇱🇨': {
- name: 'bandera-lc',
- keywords: ['Bandera'],
+ name: 'santa_lucía',
+ keywords: ['bandera', 'bandera-lc'],
},
'🇱🇮': {
- name: 'bandera-li',
- keywords: ['Bandera'],
+ name: 'liechtenstein',
+ keywords: ['bandera', 'bandera-li'],
},
'🇱🇰': {
- name: 'bandera-lk',
- keywords: ['Bandera'],
+ name: 'sri_lanka',
+ keywords: ['bandera', 'bandera-lk'],
},
'🇱🇷': {
- name: 'bandera-lr',
- keywords: ['Bandera'],
+ name: 'liberia',
+ keywords: ['bandera', 'bandera-lr'],
},
'🇱🇸': {
- name: 'bandera-ls',
- keywords: ['Bandera'],
+ name: 'lesoto',
+ keywords: ['bandera', 'bandera-ls'],
},
'🇱🇹': {
- name: 'bandera-lt',
- keywords: ['Bandera'],
+ name: 'lituania',
+ keywords: ['bandera', 'bandera-lt'],
},
'🇱🇺': {
- name: 'bandera-lu',
- keywords: ['Bandera'],
+ name: 'luxemburgo',
+ keywords: ['bandera', 'bandera-lu'],
},
'🇱🇻': {
- name: 'bandera-lv',
- keywords: ['Bandera'],
+ name: 'letonia',
+ keywords: ['bandera', 'bandera-lv'],
},
'🇱🇾': {
- name: 'bandera-ly',
- keywords: ['Bandera'],
+ name: 'libia',
+ keywords: ['bandera', 'bandera-ly'],
},
'🇲🇦': {
- name: 'bandera-ma',
- keywords: ['Bandera'],
+ name: 'marruecos',
+ keywords: ['bandera', 'bandera-ma'],
},
'🇲🇨': {
- name: 'bandera-mc',
- keywords: ['Bandera'],
+ name: 'mónaco',
+ keywords: ['bandera', 'bandera-mc'],
},
'🇲🇩': {
- name: 'bandera-md',
- keywords: ['Bandera'],
+ name: 'moldavia',
+ keywords: ['bandera', 'bandera-md'],
},
'🇲🇪': {
- name: 'bandera-me',
- keywords: ['Bandera'],
+ name: 'montenegro',
+ keywords: ['bandera', 'bandera-me'],
},
'🇲🇫': {
- name: 'bandera-mf',
- keywords: ['Bandera'],
+ name: 'san_martín_(francia)',
+ keywords: ['bandera', 'bandera-mf'],
},
'🇲🇬': {
- name: 'bandera-mg',
- keywords: ['Bandera'],
+ name: 'madagascar',
+ keywords: ['bandera', 'bandera-mg'],
},
'🇲🇭': {
- name: 'bandera-mh',
- keywords: ['Bandera'],
+ name: 'islas_marshall',
+ keywords: ['bandera', 'bandera-mh'],
},
'🇲🇰': {
- name: 'bandera-mk',
- keywords: ['Bandera'],
+ name: 'macedônia',
+ keywords: ['bandera', 'bandera-mk'],
},
'🇲🇱': {
- name: 'bandera-ml',
- keywords: ['Bandera'],
+ name: 'mali',
+ keywords: ['bandera', 'bandera-ml'],
},
'🇲🇲': {
- name: 'bandera-mm',
- keywords: ['Bandera'],
+ name: 'birmania',
+ keywords: ['bandera', 'bandera-mm'],
},
'🇲🇳': {
- name: 'bandera-mn',
- keywords: ['Bandera'],
+ name: 'mongolia',
+ keywords: ['bandera', 'bandera-mn'],
},
'🇲🇴': {
- name: 'bandera-mo',
- keywords: ['Bandera'],
+ name: 'macao',
+ keywords: ['bandera', 'bandera-mo'],
},
'🇲🇵': {
- name: 'bandera-mp',
- keywords: ['Bandera'],
+ name: 'islas_marianas_del_norte',
+ keywords: ['bandera', 'bandera-mp'],
},
'🇲🇶': {
- name: 'bandera-mq',
- keywords: ['Bandera'],
+ name: 'martinica',
+ keywords: ['bandera', 'bandera-mq'],
},
'🇲🇷': {
- name: 'bandera-mr',
- keywords: ['Bandera'],
+ name: 'mauritania',
+ keywords: ['bandera', 'bandera-mr'],
},
'🇲🇸': {
- name: 'bandera-ms',
- keywords: ['Bandera'],
+ name: 'montserrat',
+ keywords: ['bandera', 'bandera-ms'],
},
'🇲🇹': {
- name: 'bandera-mt',
- keywords: ['Bandera'],
+ name: 'malta',
+ keywords: ['bandera', 'bandera-mt'],
},
'🇲🇺': {
- name: 'bandera-mu',
- keywords: ['Bandera'],
+ name: 'mauritius',
+ keywords: ['bandera', 'bandera-mu'],
},
'🇲🇻': {
- name: 'bandera-mv',
- keywords: ['Bandera'],
+ name: 'islas_maldivas',
+ keywords: ['bandera', 'bandera-mv'],
},
'🇲🇼': {
- name: 'bandera-mw',
- keywords: ['Bandera'],
+ name: 'malawi',
+ keywords: ['bandera', 'bandera-mw'],
},
'🇲🇽': {
- name: 'bandera-mx',
- keywords: ['Bandera'],
+ name: 'méxico',
+ keywords: ['bandera', 'bandera-mx'],
},
'🇲🇾': {
- name: 'bandera-my',
- keywords: ['Bandera'],
+ name: 'malasia',
+ keywords: ['bandera', 'bandera-my'],
},
'🇲🇿': {
- name: 'bandera-mz',
- keywords: ['Bandera'],
+ name: 'mozambique',
+ keywords: ['bandera', 'bandera-mz'],
},
'🇳🇦': {
- name: 'bandera-na',
- keywords: ['Bandera'],
+ name: 'namibia',
+ keywords: ['bandera', 'bandera-na'],
},
'🇳🇨': {
- name: 'bandera-nc',
- keywords: ['Bandera'],
+ name: 'nueva_caledonia',
+ keywords: ['bandera', 'bandera-nc'],
},
'🇳🇪': {
- name: 'bandera-ne',
- keywords: ['Bandera'],
+ name: 'niger',
+ keywords: ['bandera', 'bandera-ne'],
},
'🇳🇫': {
- name: 'bandera-nf',
- keywords: ['Bandera'],
+ name: 'isla_norfolk',
+ keywords: ['bandera', 'bandera-nf'],
},
'🇳🇬': {
- name: 'bandera-ng',
- keywords: ['Bandera'],
+ name: 'nigeria',
+ keywords: ['bandera', 'bandera-ng'],
},
'🇳🇮': {
- name: 'bandera-ni',
- keywords: ['Bandera'],
+ name: 'nicaragua',
+ keywords: ['bandera', 'bandera-ni'],
},
'🇳🇱': {
- name: 'bandera-nl',
- keywords: ['Bandera'],
+ name: 'países_bajos',
+ keywords: ['bandera', 'bandera-nl'],
},
'🇳🇴': {
- name: 'bandera-no',
- keywords: ['Bandera'],
+ name: 'noruega',
+ keywords: ['bandera', 'bandera-no'],
},
'🇳🇵': {
- name: 'bandera-np',
- keywords: ['Bandera'],
+ name: 'nepal',
+ keywords: ['bandera', 'bandera-np'],
},
'🇳🇷': {
- name: 'bandera-nr',
- keywords: ['Bandera'],
+ name: 'nauru',
+ keywords: ['bandera', 'bandera-nr'],
},
'🇳🇺': {
- name: 'bandera-nu',
- keywords: ['Bandera'],
+ name: 'niue',
+ keywords: ['bandera', 'bandera-nu'],
},
'🇳🇿': {
- name: 'bandera-nz',
- keywords: ['Bandera'],
+ name: 'nueva_zealand',
+ keywords: ['bandera', 'bandera-nz'],
},
'🇴🇲': {
- name: 'bandera-om',
- keywords: ['Bandera'],
+ name: 'omán',
+ keywords: ['bandera', 'bandera-om'],
},
'🇵🇦': {
- name: 'bandera-pa',
- keywords: ['Bandera'],
+ name: 'panamá',
+ keywords: ['bandera', 'bandera-pa'],
},
'🇵🇪': {
- name: 'bandera-pe',
- keywords: ['Bandera'],
+ name: 'perú',
+ keywords: ['bandera', 'bandera-pe'],
},
'🇵🇫': {
- name: 'bandera-pf',
- keywords: ['Bandera'],
+ name: 'polinesia_francesa',
+ keywords: ['bandera', 'bandera-pf'],
},
'🇵🇬': {
- name: 'bandera-pg',
- keywords: ['Bandera'],
+ name: 'papúa_nueva_guinea',
+ keywords: ['bandera', 'bandera-pg'],
},
'🇵🇭': {
- name: 'bandera-ph',
- keywords: ['Bandera'],
+ name: 'filipinas',
+ keywords: ['bandera', 'bandera-ph'],
},
'🇵🇰': {
- name: 'bandera-pk',
- keywords: ['Bandera'],
+ name: 'pakistán',
+ keywords: ['bandera', 'bandera-pk'],
},
'🇵🇱': {
- name: 'bandera-pl',
- keywords: ['Bandera'],
+ name: 'polonia',
+ keywords: ['bandera', 'bandera-pl'],
},
'🇵🇲': {
- name: 'bandera-pm',
- keywords: ['Bandera'],
+ name: 'san_pedro_y_miquelón',
+ keywords: ['bandera', 'bandera-pm'],
},
'🇵🇳': {
- name: 'bandera-pn',
- keywords: ['Bandera'],
+ name: 'islas_pitcairn',
+ keywords: ['bandera', 'bandera-pn'],
},
'🇵🇷': {
- name: 'bandera-pr',
- keywords: ['Bandera'],
+ name: 'puerto_rico',
+ keywords: ['bandera', 'bandera-pr'],
},
'🇵🇸': {
- name: 'bandera-ps',
- keywords: ['Bandera'],
+ name: 'palestina',
+ keywords: ['bandera', 'bandera-ps'],
},
'🇵🇹': {
- name: 'bandera-pt',
- keywords: ['Bandera'],
+ name: 'portugal',
+ keywords: ['bandera', 'bandera-pt'],
},
'🇵🇼': {
- name: 'bandera-pw',
- keywords: ['Bandera'],
+ name: 'palau',
+ keywords: ['bandera', 'bandera-pw'],
},
'🇵🇾': {
- name: 'bandera-py',
- keywords: ['Bandera'],
+ name: 'paraguay',
+ keywords: ['bandera', 'bandera-py'],
},
'🇶🇦': {
- name: 'bandera-qa',
- keywords: ['Bandera'],
+ name: 'qatar',
+ keywords: ['bandera', 'bandera-qa'],
},
'🇷🇪': {
- name: 'bandera-re',
- keywords: ['Bandera'],
+ name: 'reunión',
+ keywords: ['bandera', 'bandera-re'],
},
'🇷🇴': {
- name: 'bandera-ro',
- keywords: ['Bandera'],
+ name: 'rumanía',
+ keywords: ['bandera', 'bandera-ro'],
},
'🇷🇸': {
- name: 'bandera-rs',
- keywords: ['Bandera'],
+ name: 'serbia',
+ keywords: ['bandera', 'bandera-rs'],
},
'🇷🇺': {
- name: 'ru',
- keywords: ['Bandera'],
+ name: 'rusia',
+ keywords: ['bandera', 'bandera-ru'],
},
'🇷🇼': {
- name: 'bandera-rw',
- keywords: ['Bandera'],
+ name: 'ruanda',
+ keywords: ['bandera', 'bandera-rw'],
},
'🇸🇦': {
- name: 'bandera-sa',
- keywords: ['Bandera'],
+ name: 'arabia_saudita',
+ keywords: ['bandera', 'bandera-sa'],
},
'🇸🇧': {
- name: 'bandera-sb',
- keywords: ['Bandera'],
+ name: 'islas_salomón',
+ keywords: ['bandera', 'bandera-sb'],
},
'🇸🇨': {
- name: 'bandera-sc',
- keywords: ['Bandera'],
+ name: 'seychelles',
+ keywords: ['bandera', 'bandera-sc'],
},
'🇸🇩': {
- name: 'bandera-sd',
- keywords: ['Bandera'],
+ name: 'sudán',
+ keywords: ['bandera', 'bandera-sd'],
},
'🇸🇪': {
- name: 'bandera-se',
- keywords: ['Bandera'],
+ name: 'suecia',
+ keywords: ['bandera', 'bandera-se'],
},
'🇸🇬': {
- name: 'bandera-sg',
- keywords: ['Bandera'],
+ name: 'singapur',
+ keywords: ['bandera', 'bandera-sg'],
},
'🇸🇭': {
- name: 'bandera-sh',
- keywords: ['Bandera'],
+ name: 'santa_elena',
+ keywords: ['bandera', 'bandera-sh'],
},
'🇸🇮': {
- name: 'bandera-si',
- keywords: ['Bandera'],
+ name: 'eslovenia',
+ keywords: ['bandera', 'bandera-si'],
},
'🇸🇯': {
- name: 'bandera-sj',
- keywords: ['Bandera'],
+ name: 'svalbard_y_jan_mayen',
+ keywords: ['bandera', 'bandera-sj'],
},
'🇸🇰': {
- name: 'bandera-sk',
- keywords: ['Bandera'],
+ name: 'eslovaquia',
+ keywords: ['bandera', 'bandera-sk'],
},
'🇸🇱': {
- name: 'bandera-sl',
- keywords: ['Bandera'],
+ name: 'sierra_leona',
+ keywords: ['bandera', 'bandera-sl'],
},
'🇸🇲': {
- name: 'bandera-sm',
- keywords: ['Bandera'],
+ name: 'san_marino',
+ keywords: ['bandera', 'bandera-sm'],
},
'🇸🇳': {
- name: 'bandera-sn',
- keywords: ['Bandera'],
+ name: 'senegal',
+ keywords: ['bandera', 'bandera-sn'],
},
'🇸🇴': {
- name: 'bandera-so',
- keywords: ['Bandera'],
+ name: 'somalia',
+ keywords: ['bandera', 'bandera-so'],
},
'🇸🇷': {
- name: 'bandera-sr',
- keywords: ['Bandera'],
+ name: 'surinám',
+ keywords: ['bandera', 'bandera-sr'],
},
'🇸🇸': {
- name: 'bandera-ss',
- keywords: ['Bandera'],
+ name: 'república_de_sudán_del_sur',
+ keywords: ['bandera', 'bandera-ss'],
},
'🇸🇹': {
- name: 'bandera-st',
- keywords: ['Bandera'],
+ name: 'santo_tomé_y_príncipe',
+ keywords: ['bandera', 'bandera-st'],
},
'🇸🇻': {
- name: 'bandera-sv',
- keywords: ['Bandera'],
+ name: 'el_salvador',
+ keywords: ['bandera', 'bandera-sv'],
},
'🇸🇽': {
- name: 'bandera-sx',
- keywords: ['Bandera'],
+ name: 'sint_maarten',
+ keywords: ['bandera', 'bandera-sx'],
},
'🇸🇾': {
- name: 'bandera-sy',
- keywords: ['Bandera'],
+ name: 'siria',
+ keywords: ['bandera', 'bandera-sy'],
},
'🇸🇿': {
- name: 'bandera-sz',
- keywords: ['Bandera'],
+ name: 'swazilandia',
+ keywords: ['bandera', 'bandera-sz'],
},
'🇹🇦': {
- name: 'bandera-ta',
- keywords: ['Bandera'],
+ name: 'tristán_de_acuña',
+ keywords: ['bandera', 'bandera-ta'],
},
'🇹🇨': {
- name: 'bandera-tc',
- keywords: ['Bandera'],
+ name: 'islas_turcas_y_caicos',
+ keywords: ['bandera', 'bandera-tc'],
},
'🇹🇩': {
- name: 'bandera-td',
- keywords: ['Bandera'],
+ name: 'chad',
+ keywords: ['bandera', 'bandera-td'],
},
'🇹🇫': {
- name: 'bandera-tf',
- keywords: ['Bandera'],
+ name: 'territorios_australes_y_antárticas_franceses',
+ keywords: ['bandera', 'bandera-tf'],
},
'🇹🇬': {
- name: 'bandera-tg',
- keywords: ['Bandera'],
+ name: 'togo',
+ keywords: ['bandera', 'bandera-tg'],
},
'🇹🇭': {
- name: 'bandera-th',
- keywords: ['Bandera'],
+ name: 'tailandia',
+ keywords: ['bandera', 'bandera-th'],
},
'🇹🇯': {
- name: 'bandera-tj',
- keywords: ['Bandera'],
+ name: 'tayikistán',
+ keywords: ['bandera', 'bandera-tj'],
},
'🇹🇰': {
- name: 'bandera-tk',
- keywords: ['Bandera'],
+ name: 'tokelau',
+ keywords: ['bandera', 'bandera-tk'],
},
'🇹🇱': {
- name: 'bandera-tl',
- keywords: ['Bandera'],
+ name: 'timor_oriental',
+ keywords: ['bandera', 'bandera-tl'],
},
'🇹🇲': {
- name: 'bandera-tm',
- keywords: ['Bandera'],
+ name: 'turkmenistán',
+ keywords: ['bandera', 'bandera-tm'],
},
'🇹🇳': {
- name: 'bandera-tn',
- keywords: ['Bandera'],
+ name: 'tunez',
+ keywords: ['bandera', 'bandera-tn'],
},
'🇹🇴': {
- name: 'bandera-to',
- keywords: ['Bandera'],
+ name: 'tonga',
+ keywords: ['bandera', 'bandera-to'],
},
'🇹🇷': {
- name: 'bandera-tr',
- keywords: ['Bandera'],
+ name: 'turquía',
+ keywords: ['bandera', 'bandera-tr'],
},
'🇹🇹': {
- name: 'bandera-tt',
- keywords: ['Bandera'],
+ name: 'trinidad_y_tobago',
+ keywords: ['bandera', 'bandera-tt'],
},
'🇹🇻': {
- name: 'bandera-tv',
- keywords: ['Bandera'],
+ name: 'tuvalu',
+ keywords: ['bandera', 'bandera-tv'],
},
'🇹🇼': {
- name: 'bandera-tw',
- keywords: ['Bandera'],
+ name: 'taiwán',
+ keywords: ['bandera', 'bandera-tw'],
},
'🇹🇿': {
- name: 'bandera-tz',
- keywords: ['Bandera'],
+ name: 'tanzania',
+ keywords: ['bandera', 'bandera-tz'],
},
'🇺🇦': {
- name: 'bandera-ua',
- keywords: ['Bandera'],
+ name: 'ucrania',
+ keywords: ['bandera', 'bandera-ua'],
},
'🇺🇬': {
- name: 'bandera-ug',
- keywords: ['Bandera'],
+ name: 'uganda',
+ keywords: ['bandera', 'bandera-ug'],
},
'🇺🇲': {
- name: 'bandera-um',
- keywords: ['Bandera'],
+ name: 'islas_ultramarinas_menores_de_estados_unidos',
+ keywords: ['bandera', 'bandera-um'],
},
'🇺🇳': {
name: 'bandera-onu',
- keywords: ['Bandera'],
+ keywords: ['Bandera', 'bandera-onu'],
},
'🇺🇸': {
- name: 'us',
- keywords: ['Bandera'],
+ name: 'estados_unidos_de_américa',
+ keywords: ['bandera', 'bandera-us'],
},
'🇺🇾': {
- name: 'bandera-uy',
- keywords: ['Bandera'],
+ name: 'uruguay',
+ keywords: ['bandera', 'bandera-uy'],
},
'🇺🇿': {
- name: 'bandera-uz',
- keywords: ['Bandera'],
+ name: 'uzbekistan',
+ keywords: ['bandera', 'bandera-uz'],
},
'🇻🇦': {
- name: 'bandera-va',
- keywords: ['Bandera'],
+ name: 'ciudad_del_vaticano',
+ keywords: ['bandera', 'bandera-va'],
},
'🇻🇨': {
- name: 'bandera-vc',
- keywords: ['Bandera'],
+ name: 'san_vicente_y_las_granadinas',
+ keywords: ['bandera', 'bandera-vc'],
},
'🇻🇪': {
- name: 'bandera-ve',
- keywords: ['Bandera'],
+ name: 'venezuela',
+ keywords: ['bandera', 'bandera-ve'],
},
'🇻🇬': {
- name: 'bandera-vg',
- keywords: ['Bandera'],
+ name: 'islas_vírgenes_británicas',
+ keywords: ['bandera', 'bandera-vg'],
},
'🇻🇮': {
- name: 'bandera-vi',
- keywords: ['Bandera'],
+ name: 'islas_vírgenes_de_los_estados_unidos',
+ keywords: ['bandera', 'bandera-vi'],
},
'🇻🇳': {
- name: 'bandera-vn',
- keywords: ['Bandera'],
+ name: 'vietnam',
+ keywords: ['bandera', 'bandera-vn'],
},
'🇻🇺': {
- name: 'bandera-vu',
- keywords: ['Bandera'],
+ name: 'vanuatu',
+ keywords: ['bandera', 'bandera-vu'],
},
'🇼🇫': {
- name: 'bandera-wf',
- keywords: ['Bandera'],
+ name: 'wallis_y_futuna',
+ keywords: ['bandera', 'bandera-wf'],
},
'🇼🇸': {
- name: 'bandera-ws',
- keywords: ['Bandera'],
+ name: 'samoa',
+ keywords: ['bandera', 'bandera-ws'],
},
'🇽🇰': {
- name: 'bandera-xk',
- keywords: ['Bandera'],
+ name: 'kosovo',
+ keywords: ['bandera', 'bandera-xk'],
},
'🇾🇪': {
- name: 'bandera-ye',
- keywords: ['Bandera'],
+ name: 'yemen',
+ keywords: ['bandera', 'bandera-ye'],
},
'🇾🇹': {
- name: 'bandera-yt',
- keywords: ['Bandera'],
+ name: 'mayotte',
+ keywords: ['bandera', 'bandera-yt'],
},
'🇿🇦': {
- name: 'bandera-za',
- keywords: ['Bandera'],
+ name: 'sudáfrica',
+ keywords: ['bandera', 'bandera-za'],
},
'🇿🇲': {
- name: 'bandera-zm',
- keywords: ['Bandera'],
+ name: 'zambia',
+ keywords: ['bandera', 'bandera-zm'],
},
'🇿🇼': {
- name: 'bandera-zw',
- keywords: ['Bandera'],
+ name: 'zimbabue',
+ keywords: ['bandera', 'bandera-zw'],
},
'🏴': {
- name: 'bandera-inglaterra',
- keywords: ['Bandera'],
+ name: 'inglaterra',
+ keywords: ['bandera', 'bandera-inglaterra'],
},
'🏴': {
- name: 'bandera-escocia',
- keywords: ['Bandera'],
+ name: 'escocia',
+ keywords: ['bandera', 'bandera-escocia'],
},
'🏴': {
- name: 'bandera-gales',
- keywords: ['Bandera'],
+ name: 'gales',
+ keywords: ['bandera', 'bandera-gales'],
},
};
diff --git a/contributingGuides/CONTRIBUTING.md b/contributingGuides/CONTRIBUTING.md
index 900b80ba9030..5c51f16ffc4d 100644
--- a/contributingGuides/CONTRIBUTING.md
+++ b/contributingGuides/CONTRIBUTING.md
@@ -203,7 +203,6 @@ During communication with Expensify, you will come across a variety of acronyms
- **RBR:** Red Brick Road (UX Design Principle that utilizes red indicators on action items to encourage the user down the optimal path for handling and discovering errors)
- **VBA:** Verified Bank Account (Bank account that has been verified as real and belonging to the correct business/individual)
- **NAB:** Not a Blocker (An issue that doesn't block progress, but would be nice to not have)
-- **LHN:** Left Hand Navigation
- **IOU:** I owe you (used to describe payment requests between users)
- **OTP:** One-time password, or magic sign-in
- **RHP:** Right Hand Panel (on larger screens, pages are often displayed docked to the right side of the screen)
diff --git a/contributingGuides/REVIEWER_CHECKLIST.md b/contributingGuides/REVIEWER_CHECKLIST.md
index 6a5dffc8b073..d52d80a818bb 100644
--- a/contributingGuides/REVIEWER_CHECKLIST.md
+++ b/contributingGuides/REVIEWER_CHECKLIST.md
@@ -10,12 +10,12 @@
- [ ] I checked that screenshots or videos are included for tests on [all platforms](https://github.com/Expensify/App/blob/main/contributingGuides/CONTRIBUTING.md#make-sure-you-can-test-on-all-platforms)
- [ ] I included screenshots or videos for tests on [all platforms](https://github.com/Expensify/App/blob/main/contributingGuides/CONTRIBUTING.md#make-sure-you-can-test-on-all-platforms)
- [ ] I verified tests pass on **all platforms** & I tested again on:
- - [ ] Android / native
- - [ ] Android / Chrome
- - [ ] iOS / native
- - [ ] iOS / Safari
- - [ ] MacOS / Chrome / Safari
- - [ ] MacOS / Desktop
+ - [ ] Android: Native
+ - [ ] Android: mWeb Chrome
+ - [ ] iOS: Native
+ - [ ] iOS: mWeb Safari
+ - [ ] MacOS: Chrome / Safari
+ - [ ] MacOS: Desktop
- [ ] If there are any errors in the console that are unrelated to this PR, I either fixed them (preferred) or linked to where I reported them in Slack
- [ ] I verified proper code patterns were followed (see [Reviewing the code](https://github.com/Expensify/App/blob/main/contributingGuides/PR_REVIEW_GUIDELINES.md#reviewing-the-code))
- [ ] I verified that any callback methods that were added or modified are named for what the method does and never what callback they handle (i.e. `toggleReport` and not `onIconClick`).
diff --git a/docs/_config.yml b/docs/_config.yml
index dc134d0d2c19..888f0b24a91e 100644
--- a/docs/_config.yml
+++ b/docs/_config.yml
@@ -4,6 +4,7 @@ description: Got a question about receipts, expenses, corporate cards, or anythi
url: https://help.expensify.com
author: Expensify
logo: /assets/images/expensify-help.svg
+repository: Expensify/App
open_url: true
defaults:
diff --git a/docs/_sass/_search-bar.scss b/docs/_sass/_search-bar.scss
index a5cc8ae2ff20..e9c56835af50 100644
--- a/docs/_sass/_search-bar.scss
+++ b/docs/_sass/_search-bar.scss
@@ -88,11 +88,14 @@ $color-gray-label: $color-gray-label;
/* All gsc id & class are Google Search relate gcse_0 is the search bar parent & gcse_1 is the search result list parent */
#___gcse_0 {
margin-left: 20px;
+ margin-top: -8px;
}
/* This input is in #___gcse_0 search bar */
input#gsc-i-id1.gsc-input {
background-color: $color-appBG;
+ padding: 15px 0px 0px !important;
+ pointer-events: auto;
color: #E7ECE9;
font-family: "ExpensifyNeue", "Segoe UI Emoji", "Noto Color Emoji" !important;
}
@@ -102,23 +105,29 @@ input#gsc-i-id1.gsc-input {
background-color: $color-appBG;
border-bottom: $color-borders 2px solid;
border-bottom-left-radius: 0px;
-
+ pointer-events: none;
+
&:focus-within {
border-bottom: $color-accent 2px solid;
}
}
.gsc-input-box .gsib_a {
- padding: 5px 9px 4px 0px;
+ padding: 0px 0px 4px 0px;
}
.search-icon {
margin-left: auto;
}
+.gsst_b, .gsst_a {
+ padding: 0px !important;
+}
/* This is the close icon on search bar */
.gsib_b .gsst_a .gscb_a {
color: $color-icons;
+ padding: 8px 6px 0px 6px !important;
+ pointer-events: auto;
&:hover {
color: $color-text;
@@ -148,6 +157,7 @@ label.search-label {
font-family: "ExpensifyNeue", "Segoe UI Emoji", "Noto Color Emoji";
transform: translateY(-50%);
left: 20px;
+ pointer-events: none;
color: $color-gray-label;
transform-origin: left top;
user-select: none;
@@ -181,7 +191,6 @@ label.search-label {
/* Change the Google Search Button icon into Expensify icon button */
.gsc-search-button.gsc-search-button-v2 {
padding: 10px;
- margin-top: -7px;
margin-left: 15px;
margin-right: 20px;
border-radius: 25px;
diff --git a/docs/articles/expensify-classic/account-settings/Account-Details.md b/docs/articles/expensify-classic/account-settings/Account-Details.md
index 46a6c6ba0c25..8f80a35f3525 100644
--- a/docs/articles/expensify-classic/account-settings/Account-Details.md
+++ b/docs/articles/expensify-classic/account-settings/Account-Details.md
@@ -1,5 +1,61 @@
---
title: Account Details
-description: Account Details
+description: The Account Details section of your account is where you can update your profile photo, enable 2FA, and change the email address associated with your Expensify account.
---
-## Resource Coming Soon!
+
+# Overview
+The Account Details section of your account is where you can update your profile photo, enable 2FA, and change the email address associated with your account.
+
+You can have multiple email addresses tied to your account to make it easier to submit expenses or manage your account. Let’s go over how to configure the various account settings located under the Account Details section of your Expensify account.
+
+# How to add a profile photo
+To update your name or add a profile photo, navigate to **Settings** > **Account** > **Account Details.** Under “your profile” you’ll notice a profile picture thumbnail, click “edit photo” underneath to update the profile image.
+
+# How to enable Two-Factor Authentication
+Setting up Two-factor Authentication is one of the best ways to secure your account. This can be enabled individually in your account settings by following **Settings** > **Accounts** > **Account Details** > **Two Factor Authentication** and toggle the switch to **Enabled.**
+
+Save or download your **Recovery Codes.** It’s important to keep these safe! You WILL lose access to your account if you cannot use your authenticator app and do not have your recovery codes.
+
+Use your favorite authenticator app to connect to Expensify using the QR code or click the link to enter the secret key manually.
+
+Once connected, quickly enter the code generated by your app into Expensify before the timeframe runs out!
+
+# How to manage your devices
+You can access your Expensify account on multiple devices, which allows for easy access to your account data. By heading to **Settings** > **Account** > **Account Details** > **Device Management**, you can review the devices that have access to your account.
+
+From that same place in your account, you can remove any devices that should no longer have access. To do this, select the **Revoke** button next to each device you wish to remove access to your account.
+
+# How to add a Secondary Login
+A Secondary Login is helpful if you have multiple email addresses and don’t necessarily need multiple Expensify accounts. By adding additional emails to your Expensify account, you can use them to forward receipts to receipts@expensify.com and they will be uploaded to your main Expensify account. To get this added to your account, follow these steps:
+
+1. Log in to your Expensify account through a web browser at www.expensify.com. Please note that this process cannot be completed using the mobile app; it must be done from the website at expensify.com.
+2. Navigate to **Settings** > **Account** > **Account Details**. Scroll down to find the 'Secondary Logins' section, then click the 'Add Secondary Login' button.
+3. Input the email address or mobile phone number you wish to add, ensuring you include the international code if applicable.
+4. You will receive a prompt to enter the Magic Code, which will be sent to the email address you're adding as a secondary login.
+
+# How to update your email address
+Once a Secondary Login is added to your account, you can make it your primary email address. The primary address on an Expensify account is the address that will receive email notifications and updates regarding the account. Any new email addresses must be added as a secondary login before they can be made a primary address.
+
+1. Log in to your Expensify account through a web browser at www.expensify.com. Please note that this process cannot be completed using the mobile app; it must be done from the website at expensify.com.
+2. Navigate to **Settings** > **Account** > **Account Details**. Scroll down to find the 'Secondary Logins' section, then select the **"Make Primary"** button next to the email address.
+3. You can keep the old address as a secondary login or delete email addresses by selecting the **"Remove"** button.
+
+
+# Deep Dive
+## Managing emails connected to other Expensify accounts
+A secondary login can only be added if it is not linked to an existing account. If you have two email addresses with Expensify accounts linked to them, you'll need to merge them instead.
+
+Alternatively, you can remove a personal email address from a previous work/organization account to use it elsewhere.
+
+Is your Secondary Login (personal email) validated in your company account? If so, do the following:
+1. Navigate to expensify.com
+2. Log in using your validated Secondary Login
+3. Navigate to **Account** > **Settings** > **Account Details** > **Secondary Logins**
+4. Remove your personal email address from the account by clicking the **"Remove"** button next to your email
+
+Is your Secondary Login (personal email) invalidated in your company account? If so, do the following:
+1. Navigate to expensify.com
+2. Enter your invalidated secondary login email address
+3. You will be presented with a confirmation message saying Expensify sent you an email with a validation link
+4. Head to your personal email account and follow the prompts
+5. You'll receive a link in the email to click that will unlink the two accounts
diff --git a/docs/articles/expensify-classic/billing-and-subscriptions/Billing-Owner.md b/docs/articles/expensify-classic/billing-and-subscriptions/Billing-Owner.md
index acb29d91e1d8..4fd7ef71c2e7 100644
--- a/docs/articles/expensify-classic/billing-and-subscriptions/Billing-Owner.md
+++ b/docs/articles/expensify-classic/billing-and-subscriptions/Billing-Owner.md
@@ -1,5 +1,49 @@
---
title: Billing-Owner
-description: Billing-Owner
+description: The Billing Owner is the person responsible for payment for all usage on a given Workspace
---
-## Resource Coming Soon!
\ No newline at end of file
+# Overview
+In Expensify, each Workspace has a Billing Owner. The Billing Owner is the person responsible for payment for all usage on a given Workspace. The Billing Owner is also a Workspace Admin, but it’s important to note that not all Workspace Admins are Billing Owners.
+# How to set a billing owner
+If you've just created a new Group Workspace, you first need to add a payment card to your account. You can do this by going to the web app's Home page and completing the payment card task. Alternatively, you can add a payment card directly from the Payments page (**Settings > Account > Payment**).
+- If you already own a Group Workspace subscription, you can edit your payment card details or manage subscription options within the web app under **Settings > Workspaces > Group > Subscription**.
+- If you're an individual Workspace owner, you can activate a new monthly subscription in the web app by going to **Settings > Workspaces > Individual > Subscription** section.
+# How to change the Billing Owner
+A Group Workspace's Billing Owner is typically the user who initially created the Workspace. However, any Workspace Admin can take over the role of Billing Owner by choosing to "Take Over Billing."
+Any Workspace Admin can take over the billing responsibility of a Group Workspace as long as they are already a member of that Workspace. If you wish to become the Billing Owner of a Workspace you're not currently a member of, you need to contact an existing Workspace Admin and ask them to add you to the Group Workspace.
+To take over billing:
+1. Go to **Settings > Workspaces > Group**.
+1. Click on the relevant Workspace name.
+1. Click on "Take Over Billing." If you haven't added a payment card to your settings yet, you'll be prompted to do so to complete the transfer.
+
+That's it! As the new Billing Owner, you will receive a monthly email receipt for the Group Workspaces you now own.
+# How to update payment details in Expensify
+If you're a policy billing owner, you can change your payment information like your payment card and billing currency. If you are a billing owner using the Expensify Card, your monthly company policy charges will be billed to your Expensify Card.
+
+To change your payment details:
+1. Log in to your account using a web browser or Android app (not available on iOS).
+1. Go to **Settings > Account > Payments**.
+1. To change your payment card, click "Change Payment Card" in the Payment Details section.
+1. To change your billing currency, click "Change Billing Currency" and choose a new currency. You'll need to enter the CVC code of your payment card. You can pay in USD, GBP, NZD, or AUD.
+# Deep Dive
+## Taking over an existing subscription
+If the previous Billing Owner had a 12-month subscription, it will be transferred to your Expensify account. If you already have an annual subscription, the sizes of both subscriptions will be combined. For example, if you have a subscription for 10 users and take over from someone with 50 users, your subscription will now cover 60 users. To take over the Annual Subscription, you need to transfer billing ownership of all Workspaces under the previous Billing Owner's name.
+
+## Taking over Consolidated Domain Billing
+If a Domain Admin has enabled Consolidated Domain Billing (**Settings > Domains > Domain Name > Domain Admins**), all Group Workspaces owned by users with email addresses matching the domain will be billed to the Consolidated Domain Billing owner. You can take over billing for the entire domain by following these steps:
+
+To take over billing for the entire domain, you must:
+1. Ensure you have a linked card on your **Settings > Account > Billing** page.
+1. Be designated as the Primary Domain Admin.
+1. Go to **Settings > Domains > _Domain Name_ > Domain Admins** and enable Consolidated Domain Billing.
+
+Currently, Consolidated Domain Billing simply consolidates the amounts due for each Group Workspace Billing Owner (listed on the **Settings > Workspaces > Group** page). If you want to use the Annual Subscription across all Workspaces on the domain, you must also be the Billing Owner of all Group Workspaces.
+# FAQ
+## Why can't I see the option to take over billing?
+There could be two reasons:
+1. You may not have the role of Workspace Admin. If you can't click on the Workspace name (if it's not a blue hyperlink), you're not a Workspace Admin. Another Workspace Admin for that Workspace must change your role before you can proceed.
+1. Your domain might have Consolidated Domain Billing enabled. Refer to the Deep Dive section to understand how to take over Consolidated Domain Billing.
+## What if the current Billing Owner is no longer an employee?
+There are two ways to resolve this:
+1. Have your IT dept. gain access to the account so that you can make yourself an admin. Your IT department may need to recreate the ex-employee's email address. Once your IT department has access to the employee's Home page, you can request a magic link to be sent to that email address to gain access to the account.
+1. Have another admin make you a Workspace admin.
diff --git a/docs/articles/expensify-classic/getting-started/Plan-Types.md b/docs/articles/expensify-classic/getting-started/Plan-Types.md
index f0323947ee12..90c632ffa5cc 100644
--- a/docs/articles/expensify-classic/getting-started/Plan-Types.md
+++ b/docs/articles/expensify-classic/getting-started/Plan-Types.md
@@ -1,5 +1,32 @@
---
-title: Plan-Types
-description: Plan-Types
+title: Plan Types
+description: Learn which Expensify plan is the best fit for you
---
-## Resource Coming Soon!
+# Overview
+You can access comprehensive information about Expensify's plans and pricing by visiting www.expensify.com/pricing. Below, we provide an overview of each plan type to assist you in selecting the one that best suits your business or personal requirements.
+
+## Free Plan
+The Free plan is suited for small businesses, offering a dedicated workspace for efficiently handling Expensify card management, expense reimbursement, invoicing, and bill payment. This plan includes unlimited receipt scanning for all users within the company and the potential to earn up to 1% cashback on card spending exceeding $25,000 per month (across all cards).
+
+## Collect Workspace Plan
+The Collect Workspace Plan is designed with small companies in mind, providing essential features like a single layer of expense approvals, reimbursement capabilities, corporate card management, and basic integration options such as QuickBooks Online, QuickBooks Desktop, and Xero. This plan is ideal for those who require simple expense management functions.
+
+## Control Workspace Plan
+Our most popular option, the Control Workspace plan, offers a heightened level of control and Workspace customization. With a Control Workspace, you gain access to multi-level approval workflows, comprehensive corporate card management, advanced accounting integration, tax tracking capabilities, and advanced expense rules that facilitate the enforcement of your internal expense policy. This plan provides a robust set of features for effective expense management.
+
+## Individual Track Plan
+The Track plan is tailored for solo Expensify users who don't require expense submission to others. Individuals or sole proprietors can choose the Track plan to customize their Individual Workspace to align with their personal expense tracking requirements.
+
+## Individual Submit Plan
+The Submit plan is designed for individuals who need to keep track of their expenses and share them with someone else, such as their boss, accountant, or even a housemate. It's specifically tailored for single users who want to both track and submit their expenses efficiently.
+
+# FAQ
+
+## How can I change Individual plans?
+You have the flexibility to switch between a Track and Submit plan, or vice versa, at any time by navigating to **Settings > Workspaces > Individual > *Workspace Name* > Plan**. This allows you to adapt your expense management approach as needed.
+
+## How can I upgrade Group plans?
+You can easily upgrade from a Collect to a Control plan at any time by going to **Settings > Workspaces > Group > *Workspace Name* > Plan**. However, it's important to note that if you have an active Annual Subscription, downgrading from Control to Collect is not possible until your current commitment period expires.
+
+## How does pricing work if I have two types of Group Workspace plans?
+If you have a Control and Collect Workspace, you will be charged at the Control Workspace rate.
diff --git a/docs/articles/expensify-classic/integrations/accounting-integrations/QuickBooks-Desktop.md b/docs/articles/expensify-classic/integrations/accounting-integrations/QuickBooks-Desktop.md
index 3ee1c8656b4b..d8c7c145a670 100644
--- a/docs/articles/expensify-classic/integrations/accounting-integrations/QuickBooks-Desktop.md
+++ b/docs/articles/expensify-classic/integrations/accounting-integrations/QuickBooks-Desktop.md
@@ -1,5 +1,144 @@
---
-title: Coming Soon
-description: Coming Soon
+title: QuickBooks Desktop
+description: How to connect Expensify to QuickBooks Desktop and troubleshoot issues.
---
-## Resource Coming Soon!
+# Overview
+QuickBooks Desktop is an accounting package developed by Intuit. It is designed for small and medium-sized businesses to help them manage their financial and accounting tasks. You can connect Expensify to QuickBooks Desktop to make expense management seamless.
+To connect Expensify with QuickBooks Desktop, using Right Networks as your hosting platform is best. Right Networks is a cloud-based service we recommend for this integration. If you need a Right Networks account, complete [this form](https://info.rightnetworks.com/partner-expensify) and contact a Sales Consultant to start the process.
+
+# How to connect to QuickBooks Desktop
+Before you link your Expensify policy with QuickBooks Desktop, ensure you log in as an Admin in QuickBooks. Also, check that the company file you want to connect to is the only one open.
+
+## Set up submitters in QuickBooks Desktop
+For a seamless integration, here are the steps to follow:
+* Make sure all report submitters are set up as Vendors in QuickBooks Desktop and their Expensify email is in the "Main Email" field of their Vendor record. You can do this in the vendor section of QuickBooks.
+* If you want to export reports to your users' employee records instead of vendor records, select Check or Journal Entry as your reimbursable export option.
+* To set up Expensify users as employees, activate QuickBooks Desktop Payroll. This module is necessary to access the Employee Profile tab, where you can enter the submitter's email addresses.
+
+## Enable/install the Expensify Sync Manager
+Navigate to **Settings** > **Policies** > **Group** > _[Policy Name]_ > **Connections**, select the Connect to QuickBooks Desktop radio button and click Connect to QuickBooks.
+
+**Enable the Expensify Sync Manager in Right Networks (recommended)**
+*Please note: Single-user mode in QuickBooks Desktop is required.*
+If you don't yet have an account with Right Networks, you must first contact Right Networks [here](https://info.rightnetworks.com/partner-expensify). You can enable the Expensify Sync Manager yourself from your Right Networks portal's **My Account** section or contact Right Networks for assistance.
+
+**OR, install the Expensify Sync Manager on Your Third-Party Remote Desktop.**
+To download the Sync Manager to your desktop, you must contact your third-party remote desktop provider and request permission. They might have security restrictions, so it's best to communicate with them directly to avoid potential problems with the Sync Manager. Remember that the Sync Manager program file should be stored in the same location (i.e., the same drive) as your QuickBooks Desktop program.
+
+## Complete the connection
+1. Open QuickBooks and access your desired Company File using the QuickBooks Admin credentials. Admin credentials are necessary for creating the connection due to permission requirements, but you won't need to stay logged in as an admin for syncing or exporting.
+2. Navigate to your Expensify policy settings by going to **Settings** > **Policies** > **Group** > _[Policy Name]_ > **Connections**. Copy the Token by selecting the copy icon.
+3. While QuickBooks is still running, launch the Expensify Sync Manager. Paste your Token into the Sync Manager and click **Save**.
+4. Once the Sync Manager status displays **Connected**, return to Expensify and click the *Continue* button.
+
+## Allow access
+1. Return to QuickBooks, and you'll encounter an **Application Certificate** screen. On the first page of the Certificate screen, click **Yes, always; allow access even if QuickBooks is not running** and then click **Continue**.
+2. On the second page of the Certificate screen, choose the Admin user from the dropdown menu, and then click *Done* to complete this step. Note that selecting Admin here does not require you to be logged in as an admin to use this connection; it's simply selecting the appropriate permissions.
+3. Head back to Expensify and patiently wait for the sync process to finish, then move on to the configuration.
+
+# How to configure export settings for QuickBooks Desktop
+To Configure Settings, go to **Settings** > **Policies** > **Group** > _[Policy Name]_ > **Connections** and click **Configure**.
+
+## Preferred Exporter
+This person is used in QuickBooks Desktop as the export user. They will also receive notifications for errors.
+
+## Date
+Choose either the report's submitted date, the report's exported date, or the date of the last expense on the report when exporting reports to QuickBooks Desktop.
+
+## Use unique reference numbers
+Enable this to allow use of a unique reference number for each transaction. Disable this to use the same Report ID for all expenses from a certain report.
+
+## Reimbursable expenses
+* **Vendor Bill (recommended):** A single itemized vendor bill for each Expensify report. An A/P account is required to export to a vendor bill.
+* **Check:** A single itemized check for each Expensify report.
+* **Journal Entry:** A single itemized journal entry for each Expensify report.
+
+## Non-reimbursable expenses
+**Credit Card Expenses:**
+* Each expense will appear as a separate credit card transaction.
+* The posting date will match your credit card statement.
+* To display the merchant name in the payee field in QuickBooks Desktop, ensure that a matching Vendor exists in QuickBooks. Expensify searches for an exact match during export. If no match is found, the payee is mapped to a **Credit Card Misc.** Vendor created by Expensify.
+* If you're centrally managing company cards through Domain Control, you can export expenses from each card to a specific QuickBooks account (detailed instructions available).
+
+**Debit Card Expenses:**
+* Expenses export as individual itemized checks for each Expensify report.
+* The check is written to the "vendor," which is the person who created or submitted the report in Expensify.
+
+**Vendor Bill:**
+* Each Expensify report results in a single itemized vendor bill.
+* The bill is associated with the "vendor," which is the individual responsible for creating or submitting the report in Expensify.
+
+# How to configure coding for QuickBooks Desktop
+## Categories
+Expensify's integration with QuickBooks brings in your Chart of Accounts as Categories in Expensify automatically. Here's how to manage them:
+1. After connecting, go to **Settings** > **Policies** > **Group** > _[Policy Name]_ > **Categories** to view the accounts imported from QuickBooks Desktop.
+2. You can use the enable/disable button to choose which Categories your employees can access. Additionally, you can set specific rules for each Category via the blue settings cog.
+3. Expensify offers Auto-Categorization to automatically assign expenses to the appropriate expense categories.
+4. If needed, you can edit the names of the imported Categories to simplify expense coding for your employees. Keep in mind that if you make changes to these accounts in QuickBooks Desktop, the category names in Expensify will update to match them during the next sync.
+5. _**Important:**_ Each expense must have a category selected to export to QuickBooks Desktop. The selected category must be one imported from QuickBooks Desktop; you cannot manually create categories within Expensify policy settings.
+## Classes
+Classes can be imported from QuickBooks as either tags (line-item level) or report fields (header level).
+
+## Customers/Projects
+You can bring in Customers/Projects from QuickBooks into Expensify in two ways: as tags (at the line-item level) or as report fields (at the header level). If you're utilizing Billable Expenses in Expensify, here's what you need to know:
+* Customers/Projects must be enabled if you're using Billable Expenses.
+* Expenses marked as "Billable" need to be tagged with a Customer/Project to successfully export them to QuickBooks.
+
+## Items
+Items can be imported from QuickBooks as categories alongside your expense accounts.
+
+# FAQ
+## How do I sync my connection?
+1: Ensure that both the Expensify Sync Manager and QuickBooks Desktop are running.
+2: On the Expensify website, navigate to **Settings** > **Policies** > **Group** > _[Policy Name]_ > **Connections** > **QuickBooks Desktop**, and click **Sync now**.
+3: Wait for the syncing process to finish. Typically, this takes about 2-5 minutes, but it might take longer, depending on when you last synced and the size of your QuickBooks company file. The page will refresh automatically once syncing is complete.
+
+We recommend syncing at least once a week or whenever you make changes in QuickBooks Desktop that could impact how your reports export from Expensify. Changes could include adjustments to your Chart of Accounts, Vendors, Employees, Customers/Jobs, or Items. Remember, both the Sync Manager and QuickBooks Desktop need to be running for syncing or exporting to work.
+
+## Can I export negative expenses?
+Generally, you can export negative expenses to QuickBooks Desktop successfully, regardless of your option. However, please keep in mind that if you have *Check* selected as your export option, the report's total cannot be negative.
+
+## How does multi-currency work with QuickBooks Desktop?
+When using QuickBooks Desktop Multi-Currency, there are some limitations to consider based on your export options:
+1. **Vendor Bills and Checks:** The currency of the vendor and the currency of the account must match, but they do not have to be in the home currency.
+2. **Credit Card:** If an expense doesn't match an existing vendor in QuickBooks, it exports to the **Credit Card Misc.** vendor created by Expensify. When exporting a report in a currency other than your home currency, the transaction will be created under the vendor's currency with a 1:1 conversion. For example, a transaction in Expensify for $50 CAD will appear in QuickBooks as $50 USD.
+3. **Journal Entries:** Multi-currency exports will fail because the account currency must match both the vendor currency and the home currency.
+
+# Sync and export errors
+## Error: No Vendor Found For Email in QuickBooks
+To address this issue, ensure that each submitter's email is saved as the **Main Email** in their Vendor record within QuickBooks Desktop. Here's how to resolve it:
+1. Go to your Vendor section in QuickBooks.
+2. Verify that the email mentioned in the error matches the **Main Email** field in the respective vendor's record. It's important to note that this comparison is case-sensitive, so ensure that capitalization matches as well.
+3. If you prefer to export reports to your users' employee records instead of their vendor records, select either **Check** or **Journal Entry** as your reimbursable export option. If you are setting up Expensify users as employees, activate QuickBooks Desktop Payroll to access the Employee Profile tab where submitter email addresses need to be entered.
+4. Once you've added the correct email to the vendor record, save this change, and then sync your policy before attempting to export the report again.
+
+## Error: Do Not Have Permission to Access Company Data File
+To resolve this error, follow these steps:
+1. Log into QuickBooks Desktop as an Admin in single-user mode.
+2. Go to **Edit** > **Preferences** > **Integrated Applications** > **Company Preferences**.
+3. Select the Expensify Sync Manager and click on **Properties**.
+4. Ensure that **Allow this application to login automatically** is checked, and then click **OK**. Close all windows within QuickBooks.
+5. If you still encounter the error after following the above steps, go to **Edit** > **Preferences** > **Integrated Applications** > **Company Preferences**, and remove the Expensify Sync Manager from the list.
+6. Next, attempt to sync your policy again in Expensify. You'll be prompted to re-authorize the connection in QuickBooks.
+7. Click **Yes, always; allow access even if QuickBooks is not running.**
+8. From the dropdown, select the Admin user, and then click **Continue**. Note that selecting **Admin** here doesn't mean you always have to be logged in as an admin to use the connection; it's just required for setting up the connection.
+9. Click **Done** on the pop-up window and return to Expensify, where your policy should complete the syncing process.
+
+## Error: The Wrong QuickBooks Company is Open.
+This error suggests that the wrong company file is open in QuickBooks Desktop. To resolve this issue, follow these steps:
+1. First, go through the general troubleshooting steps as outlined.
+2. If you can confirm that the incorrect company file is open in QuickBooks, go to QuickBooks and select **File** > **Open or Restore Company** > _[Company Name]_ to open the correct company file. After doing this, try syncing your policy again.
+3. If the correct company file is open, but you're still encountering the error, completely close QuickBooks Desktop, reopen the desired company file and then attempt to sync again.
+4. If the error persists, log into QuickBooks as an admin in single-user mode. Then, go to **Edit** > **Preferences** > **Integrated Applications** > **Company Preferences** and remove the Expensify Sync Manager from the list.
+5. Next, try syncing your policy again in Expensify. You'll be prompted to re-authorize the connection in QuickBooks, allowing you to sync successfully.
+6. If the error continues even after trying the steps above, double-check that the token you see in the Sync Manager matches the token in your connection settings.
+
+## Error: The Expensify Sync Manager Could Not Be Reached.
+To resolve this error, follow these steps:
+*Note: You must be in single-user mode to sync.*
+
+1. Ensure that both the Sync Manager and QuickBooks Desktop are running.
+2. Confirm that the Sync Manager is installed in the correct location. It should be in the same location as your QuickBooks application. If QuickBooks is on your local desktop, the Sync Manager should be there, too. If QuickBooks is on a remote server, install the Sync Manager there.
+Verify that the Sync Manager's status is **Connected**.
+3. If the Sync Manager status is already **Connected**, click **Edit** and then *Save* to refresh the connection. Afterwards, try syncing your policy again.
+4. If the error persists, double-check that the token you see in the Sync Manager matches the token in your connection settings.
diff --git a/docs/assets/images/ExpensifyHelp_CardSettings.png b/docs/assets/images/ExpensifyHelp_CardSettings.png
new file mode 100644
index 000000000000..c10a3d1cbc39
Binary files /dev/null and b/docs/assets/images/ExpensifyHelp_CardSettings.png differ
diff --git a/docs/assets/images/ExpensifyHelp_SettlementExpanded.png b/docs/assets/images/ExpensifyHelp_SettlementExpanded.png
new file mode 100644
index 000000000000..8672c8639202
Binary files /dev/null and b/docs/assets/images/ExpensifyHelp_SettlementExpanded.png differ
diff --git a/docs/assets/images/ExpensifyHelp_SettlementExport.png b/docs/assets/images/ExpensifyHelp_SettlementExport.png
new file mode 100644
index 000000000000..b8c9a36220d4
Binary files /dev/null and b/docs/assets/images/ExpensifyHelp_SettlementExport.png differ
diff --git a/ios/NewExpensify/Info.plist b/ios/NewExpensify/Info.plist
index 9082f991bf75..9e6296400568 100644
--- a/ios/NewExpensify/Info.plist
+++ b/ios/NewExpensify/Info.plist
@@ -19,7 +19,7 @@
CFBundlePackageType
APPL
CFBundleShortVersionString
- 1.3.79
+ 1.3.81
CFBundleSignature
????
CFBundleURLTypes
@@ -40,7 +40,7 @@
CFBundleVersion
- 1.3.79.3
+ 1.3.81.4
ITSAppUsesNonExemptEncryption
LSApplicationQueriesSchemes
diff --git a/ios/NewExpensifyTests/Info.plist b/ios/NewExpensifyTests/Info.plist
index 614979cf57b7..5dc727d452d5 100644
--- a/ios/NewExpensifyTests/Info.plist
+++ b/ios/NewExpensifyTests/Info.plist
@@ -15,10 +15,10 @@
CFBundlePackageType
BNDL
CFBundleShortVersionString
- 1.3.79
+ 1.3.81
CFBundleSignature
????
CFBundleVersion
- 1.3.79.3
+ 1.3.81.4
diff --git a/ios/Podfile b/ios/Podfile
index b30510572448..6aee4b94df04 100644
--- a/ios/Podfile
+++ b/ios/Podfile
@@ -2,17 +2,29 @@
# This value is used by $RNMapboxMaps
$RNMapboxMapsImpl = 'mapbox'
-# Resolve react_native_pods.rb with node to allow for hoisting
-require Pod::Executable.execute_command('node', ['-p',
- 'require.resolve(
- "react-native/scripts/react_native_pods.rb",
- {paths: [process.argv[1]]},
- )', __dir__]).strip
+def node_require(script)
+ # Resolve script with node to allow for hoisting
+ require Pod::Executable.execute_command('node', ['-p',
+ "require.resolve(
+ '#{script}',
+ {paths: [process.argv[1]]},
+ )", __dir__]).strip
+end
+
+node_require('react-native/scripts/react_native_pods.rb')
+node_require('react-native-permissions/scripts/setup.rb')
# Our min supported iOS version is higher than the default (min_ios_version_supported) to support libraires such as Airship
platform :ios, 13
prepare_react_native_project!
+setup_permissions([
+ 'Camera',
+ 'LocationAccuracy',
+ 'LocationAlways',
+ 'LocationWhenInUse'
+])
+
# If you are using a `react-native-flipper` your iOS build will fail when `NO_FLIPPER=1` is set.
# because `react-native-flipper` depends on (FlipperKit,...) that will be excluded
#
@@ -51,8 +63,6 @@ pre_install do |installer|
end
target 'NewExpensify' do
- permissions_path = '../node_modules/react-native-permissions/ios'
-
project 'NewExpensify',
'DebugDevelopment' => :debug,
'DebugAdHoc' => :debug,
@@ -61,11 +71,6 @@ target 'NewExpensify' do
'ReleaseAdHoc' => :release,
'ReleaseProduction' => :release
- pod 'Permission-LocationAccuracy', :path => "#{permissions_path}/LocationAccuracy"
- pod 'Permission-LocationAlways', :path => "#{permissions_path}/LocationAlways"
- pod 'Permission-LocationWhenInUse', :path => "#{permissions_path}/LocationWhenInUse"
- pod 'Permission-Camera', :path => "#{permissions_path}/Camera"
-
config = use_native_modules!
# Flags change depending on the env values.
diff --git a/ios/Podfile.lock b/ios/Podfile.lock
index 6e0c44299398..1f08d51d24a8 100644
--- a/ios/Podfile.lock
+++ b/ios/Podfile.lock
@@ -256,14 +256,6 @@ PODS:
- Onfido (= 27.4.0)
- React
- OpenSSL-Universal (1.1.1100)
- - Permission-Camera (3.6.1):
- - RNPermissions
- - Permission-LocationAccuracy (3.6.1):
- - RNPermissions
- - Permission-LocationAlways (3.6.1):
- - RNPermissions
- - Permission-LocationWhenInUse (3.6.1):
- - RNPermissions
- Plaid (4.1.0)
- PromisesObjC (2.2.0)
- RCT-Folly (2021.07.22.00):
@@ -587,7 +579,7 @@ PODS:
- React
- react-native-image-picker (5.1.0):
- React-Core
- - react-native-key-command (1.0.1):
+ - react-native-key-command (1.0.6):
- React-Core
- react-native-netinfo (9.3.10):
- React-Core
@@ -781,7 +773,7 @@ PODS:
- React
- React-Core
- Turf
- - RNPermissions (3.6.1):
+ - RNPermissions (3.9.3):
- React-Core
- RNReactNativeHapticFeedback (1.14.0):
- React-Core
@@ -867,10 +859,6 @@ DEPENDENCIES:
- lottie-react-native (from `../node_modules/lottie-react-native`)
- "onfido-react-native-sdk (from `../node_modules/@onfido/react-native-sdk`)"
- OpenSSL-Universal (= 1.1.1100)
- - Permission-Camera (from `../node_modules/react-native-permissions/ios/Camera`)
- - Permission-LocationAccuracy (from `../node_modules/react-native-permissions/ios/LocationAccuracy`)
- - Permission-LocationAlways (from `../node_modules/react-native-permissions/ios/LocationAlways`)
- - Permission-LocationWhenInUse (from `../node_modules/react-native-permissions/ios/LocationWhenInUse`)
- RCT-Folly (from `../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec`)
- RCTRequired (from `../node_modules/react-native/Libraries/RCTRequired`)
- RCTTypeSafety (from `../node_modules/react-native/Libraries/TypeSafety`)
@@ -1018,14 +1006,6 @@ EXTERNAL SOURCES:
:path: "../node_modules/lottie-react-native"
onfido-react-native-sdk:
:path: "../node_modules/@onfido/react-native-sdk"
- Permission-Camera:
- :path: "../node_modules/react-native-permissions/ios/Camera"
- Permission-LocationAccuracy:
- :path: "../node_modules/react-native-permissions/ios/LocationAccuracy"
- Permission-LocationAlways:
- :path: "../node_modules/react-native-permissions/ios/LocationAlways"
- Permission-LocationWhenInUse:
- :path: "../node_modules/react-native-permissions/ios/LocationWhenInUse"
RCT-Folly:
:podspec: "../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec"
RCTRequired:
@@ -1227,10 +1207,6 @@ SPEC CHECKSUMS:
Onfido: e36f284b865adcf99d9c905590a64ac09d4a576b
onfido-react-native-sdk: 4ecde1a97435dcff9f00a878e3f8d1eb14fabbdc
OpenSSL-Universal: ebc357f1e6bc71fa463ccb2fe676756aff50e88c
- Permission-Camera: bf6791b17c7f614b6826019fcfdcc286d3a107f6
- Permission-LocationAccuracy: 76df17de5c6b8bc2eee34e61ee92cdd7a864c73d
- Permission-LocationAlways: 8d99b025c9f73c696e0cdb367e42525f2e9a26f2
- Permission-LocationWhenInUse: 3ba99e45c852763f730eabecec2870c2382b7bd4
Plaid: 7d340abeadb46c7aa1a91f896c5b22395a31fcf2
PromisesObjC: 09985d6d70fbe7878040aa746d78236e6946d2ef
RCT-Folly: 424b8c9a7a0b9ab2886ffe9c3b041ef628fd4fb1
@@ -1257,7 +1233,7 @@ SPEC CHECKSUMS:
react-native-geolocation: 0f7fe8a4c2de477e278b0365cce27d089a8c5903
react-native-image-manipulator: c48f64221cfcd46e9eec53619c4c0374f3328a56
react-native-image-picker: c33d4e79f0a14a2b66e5065e14946ae63749660b
- react-native-key-command: c2645ec01eb1fa664606c09480c05cb4220ef67b
+ react-native-key-command: 5af6ee30ff4932f78da6a2109017549042932aa5
react-native-netinfo: ccbe1085dffd16592791d550189772e13bf479e2
react-native-pager-view: 0ccb8bf60e2ebd38b1f3669fa3650ecce81db2df
react-native-pdf: 7c0e91ada997bac8bac3bb5bea5b6b81f5a3caae
@@ -1302,7 +1278,7 @@ SPEC CHECKSUMS:
RNGoogleSignin: ccaa4a81582cf713eea562c5dd9dc1961a715fd0
RNLocalize: d4b8af4e442d4bcca54e68fc687a2129b4d71a81
rnmapbox-maps: 6f638ec002aa6e906a6f766d69cd45f968d98e64
- RNPermissions: dcdb7b99796bbeda6975a6e79ad519c41b251b1c
+ RNPermissions: 9b086c8f05b2e2faa587fdc31f4c5ab4509728aa
RNReactNativeHapticFeedback: 1e3efeca9628ff9876ee7cdd9edec1b336913f8c
RNReanimated: ab2e96c6d5591c3dfbb38a464f54c8d17fb34a87
RNScreens: d037903436160a4b039d32606668350d2a808806
@@ -1315,6 +1291,6 @@ SPEC CHECKSUMS:
Yoga: 3efc43e0d48686ce2e8c60f99d4e6bd349aff981
YogaKit: f782866e155069a2cca2517aafea43200b01fd5a
-PODFILE CHECKSUM: 2daf34c870819a933f3fefe426801d54b2ff2a14
+PODFILE CHECKSUM: ff769666b7221c15936ebc5576a8c8e467dc6879
COCOAPODS: 1.12.1
diff --git a/jest.config.js b/jest.config.js
index 6cf44b6b3695..c3125284837a 100644
--- a/jest.config.js
+++ b/jest.config.js
@@ -10,6 +10,7 @@ module.exports = {
],
transform: {
'^.+\\.jsx?$': 'babel-jest',
+ '^.+\\.svg?$': 'jest-transformer-svg',
},
transformIgnorePatterns: ['/node_modules/(?!react-native)/'],
testPathIgnorePatterns: ['/node_modules'],
diff --git a/package-lock.json b/package-lock.json
index ddebbe8a3832..9a029b06ced4 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "new.expensify",
- "version": "1.3.79-3",
+ "version": "1.3.81-4",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "new.expensify",
- "version": "1.3.79-3",
+ "version": "1.3.81-4",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
@@ -51,7 +51,7 @@
"date-fns-tz": "^2.0.0",
"dom-serializer": "^0.2.2",
"domhandler": "^4.3.0",
- "expensify-common": "git+ssh://git@github.com/Expensify/expensify-common.git#f76ff4badf0934e21ac6c3f195ebc5791bb72247",
+ "expensify-common": "git+ssh://git@github.com/Expensify/expensify-common.git#009c2ab79bf7ddeab0eea7a3a4c0d9cc4277c34b",
"fbjs": "^3.0.2",
"htmlparser2": "^7.2.0",
"idb-keyval": "^6.2.1",
@@ -90,7 +90,7 @@
"react-native-image-pan-zoom": "^2.1.12",
"react-native-image-picker": "^5.1.0",
"react-native-image-size": "git+https://github.com/Expensify/react-native-image-size#8393b7e58df6ff65fd41f60aee8ece8822c91e2b",
- "react-native-key-command": "^1.0.5",
+ "react-native-key-command": "^1.0.6",
"react-native-linear-gradient": "^2.8.1",
"react-native-localize": "^2.2.6",
"react-native-modal": "^13.0.0",
@@ -98,7 +98,7 @@
"react-native-pager-view": "^6.2.0",
"react-native-pdf": "^6.7.1",
"react-native-performance": "^5.1.0",
- "react-native-permissions": "^3.0.1",
+ "react-native-permissions": "^3.9.3",
"react-native-picker-select": "git+https://github.com/Expensify/react-native-picker-select.git#eae05855286dc699954415cc1d629bfd8e8e47e2",
"react-native-plaid-link-sdk": "^10.0.0",
"react-native-qrcode-svg": "^6.2.0",
@@ -209,6 +209,7 @@
"jest-circus": "29.4.1",
"jest-cli": "29.4.1",
"jest-environment-jsdom": "^29.4.1",
+ "jest-transformer-svg": "^2.0.1",
"metro-react-native-babel-preset": "0.76.8",
"mock-fs": "^4.13.0",
"onchange": "^7.1.0",
@@ -30218,8 +30219,8 @@
},
"node_modules/expensify-common": {
"version": "1.0.0",
- "resolved": "git+ssh://git@github.com/Expensify/expensify-common.git#f76ff4badf0934e21ac6c3f195ebc5791bb72247",
- "integrity": "sha512-RCC3VBRIoW1ZF+wZktHT+0ht6EUjNfCKW4g44RR5570dRpN9SrJASGt2OnEbz6mrbohWRgAaKmB4+nfiQX5ndQ==",
+ "resolved": "git+ssh://git@github.com/Expensify/expensify-common.git#009c2ab79bf7ddeab0eea7a3a4c0d9cc4277c34b",
+ "integrity": "sha512-mD9p6Qj8FfvLdb6JLXvF0UNqLN6ymssUU67Fm37zmK18hd1Abw+vR/pQkNpHR2iv+KRs8HdcyuZ0vaOec4VrFQ==",
"license": "MIT",
"dependencies": {
"classnames": "2.3.1",
@@ -36490,6 +36491,16 @@
"node": ">=8"
}
},
+ "node_modules/jest-transformer-svg": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/jest-transformer-svg/-/jest-transformer-svg-2.0.1.tgz",
+ "integrity": "sha512-L3j70WjfQtAYXjZi/vyKW8A5pcEUnv7mR0cugSyP6Kqee+fjsMzUHs5UPbnLKH+y7lfSpOjXijMbfEcjLqCuaw==",
+ "dev": true,
+ "peerDependencies": {
+ "jest": ">= 28.1.0",
+ "react": "^17.0.0 || ^18.0.0"
+ }
+ },
"node_modules/jest-util": {
"version": "29.6.3",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.6.3.tgz",
@@ -44647,9 +44658,9 @@
"license": "MIT"
},
"node_modules/react-native-key-command": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/react-native-key-command/-/react-native-key-command-1.0.5.tgz",
- "integrity": "sha512-SJWf1e8f3yGFrFDNCmJ+aiGmnwokGgtMicfvuyukhQtXkncCQb9pBI4uhBen0Bd30uMmUDgGAA9O56OyIdf5jw==",
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/react-native-key-command/-/react-native-key-command-1.0.6.tgz",
+ "integrity": "sha512-N+/kmGMSnvTOF5DXupGg9ztkeOXjre//+Z+Mv4RU8RLYNvW7TtDgHlOxl4AngeGD1pG5gbI6hrlUukrRSCs6Ng==",
"dependencies": {
"eventemitter3": "^5.0.1",
"underscore": "^1.13.4"
@@ -44788,8 +44799,9 @@
}
},
"node_modules/react-native-permissions": {
- "version": "3.6.1",
- "license": "MIT",
+ "version": "3.9.3",
+ "resolved": "https://registry.npmjs.org/react-native-permissions/-/react-native-permissions-3.9.3.tgz",
+ "integrity": "sha512-2UqG2Em4xHxLq0E1XynXMdQ//XZltxVUjTn/i4fPIZuuZ0cQ+ydAQmLXqDPxOXvG0sICwc3oe0orJmQdqpa1sQ==",
"peerDependencies": {
"react": ">=16.13.1",
"react-native": ">=0.63.3",
@@ -74887,9 +74899,9 @@
}
},
"expensify-common": {
- "version": "git+ssh://git@github.com/Expensify/expensify-common.git#f76ff4badf0934e21ac6c3f195ebc5791bb72247",
- "integrity": "sha512-RCC3VBRIoW1ZF+wZktHT+0ht6EUjNfCKW4g44RR5570dRpN9SrJASGt2OnEbz6mrbohWRgAaKmB4+nfiQX5ndQ==",
- "from": "expensify-common@git+ssh://git@github.com/Expensify/expensify-common.git#f76ff4badf0934e21ac6c3f195ebc5791bb72247",
+ "version": "git+ssh://git@github.com/Expensify/expensify-common.git#009c2ab79bf7ddeab0eea7a3a4c0d9cc4277c34b",
+ "integrity": "sha512-mD9p6Qj8FfvLdb6JLXvF0UNqLN6ymssUU67Fm37zmK18hd1Abw+vR/pQkNpHR2iv+KRs8HdcyuZ0vaOec4VrFQ==",
+ "from": "expensify-common@git+ssh://git@github.com/Expensify/expensify-common.git#009c2ab79bf7ddeab0eea7a3a4c0d9cc4277c34b",
"requires": {
"classnames": "2.3.1",
"clipboard": "2.0.4",
@@ -79327,6 +79339,13 @@
}
}
},
+ "jest-transformer-svg": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/jest-transformer-svg/-/jest-transformer-svg-2.0.1.tgz",
+ "integrity": "sha512-L3j70WjfQtAYXjZi/vyKW8A5pcEUnv7mR0cugSyP6Kqee+fjsMzUHs5UPbnLKH+y7lfSpOjXijMbfEcjLqCuaw==",
+ "dev": true,
+ "requires": {}
+ },
"jest-util": {
"version": "29.6.3",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.6.3.tgz",
@@ -85249,9 +85268,9 @@
"from": "react-native-image-size@git+https://github.com/Expensify/react-native-image-size#8393b7e58df6ff65fd41f60aee8ece8822c91e2b"
},
"react-native-key-command": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/react-native-key-command/-/react-native-key-command-1.0.5.tgz",
- "integrity": "sha512-SJWf1e8f3yGFrFDNCmJ+aiGmnwokGgtMicfvuyukhQtXkncCQb9pBI4uhBen0Bd30uMmUDgGAA9O56OyIdf5jw==",
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/react-native-key-command/-/react-native-key-command-1.0.6.tgz",
+ "integrity": "sha512-N+/kmGMSnvTOF5DXupGg9ztkeOXjre//+Z+Mv4RU8RLYNvW7TtDgHlOxl4AngeGD1pG5gbI6hrlUukrRSCs6Ng==",
"requires": {
"eventemitter3": "^5.0.1",
"underscore": "^1.13.4"
@@ -85324,7 +85343,9 @@
"requires": {}
},
"react-native-permissions": {
- "version": "3.6.1",
+ "version": "3.9.3",
+ "resolved": "https://registry.npmjs.org/react-native-permissions/-/react-native-permissions-3.9.3.tgz",
+ "integrity": "sha512-2UqG2Em4xHxLq0E1XynXMdQ//XZltxVUjTn/i4fPIZuuZ0cQ+ydAQmLXqDPxOXvG0sICwc3oe0orJmQdqpa1sQ==",
"requires": {}
},
"react-native-picker-select": {
diff --git a/package.json b/package.json
index 9a3b9ed3af86..4533fa30d502 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "new.expensify",
- "version": "1.3.79-3",
+ "version": "1.3.81-4",
"author": "Expensify, Inc.",
"homepage": "https://new.expensify.com",
"description": "New Expensify is the next generation of Expensify: a reimagination of payments based atop a foundation of chat.",
@@ -94,7 +94,7 @@
"date-fns-tz": "^2.0.0",
"dom-serializer": "^0.2.2",
"domhandler": "^4.3.0",
- "expensify-common": "git+ssh://git@github.com/Expensify/expensify-common.git#f76ff4badf0934e21ac6c3f195ebc5791bb72247",
+ "expensify-common": "git+ssh://git@github.com/Expensify/expensify-common.git#009c2ab79bf7ddeab0eea7a3a4c0d9cc4277c34b",
"fbjs": "^3.0.2",
"htmlparser2": "^7.2.0",
"idb-keyval": "^6.2.1",
@@ -114,8 +114,8 @@
"react-collapse": "^5.1.0",
"react-content-loader": "^6.1.0",
"react-dom": "18.1.0",
- "react-map-gl": "^7.1.3",
"react-error-boundary": "^4.0.11",
+ "react-map-gl": "^7.1.3",
"react-native": "0.72.4",
"react-native-android-location-enabler": "^1.2.2",
"react-native-blob-util": "^0.17.3",
@@ -133,7 +133,7 @@
"react-native-image-pan-zoom": "^2.1.12",
"react-native-image-picker": "^5.1.0",
"react-native-image-size": "git+https://github.com/Expensify/react-native-image-size#8393b7e58df6ff65fd41f60aee8ece8822c91e2b",
- "react-native-key-command": "^1.0.5",
+ "react-native-key-command": "^1.0.6",
"react-native-linear-gradient": "^2.8.1",
"react-native-localize": "^2.2.6",
"react-native-modal": "^13.0.0",
@@ -141,7 +141,7 @@
"react-native-pager-view": "^6.2.0",
"react-native-pdf": "^6.7.1",
"react-native-performance": "^5.1.0",
- "react-native-permissions": "^3.0.1",
+ "react-native-permissions": "^3.9.3",
"react-native-picker-select": "git+https://github.com/Expensify/react-native-picker-select.git#eae05855286dc699954415cc1d629bfd8e8e47e2",
"react-native-plaid-link-sdk": "^10.0.0",
"react-native-qrcode-svg": "^6.2.0",
@@ -252,6 +252,7 @@
"jest-circus": "29.4.1",
"jest-cli": "29.4.1",
"jest-environment-jsdom": "^29.4.1",
+ "jest-transformer-svg": "^2.0.1",
"metro-react-native-babel-preset": "0.76.8",
"mock-fs": "^4.13.0",
"onchange": "^7.1.0",
diff --git a/src/CONST.ts b/src/CONST.ts
index bf330ad2795b..a192f9f69f05 100755
--- a/src/CONST.ts
+++ b/src/CONST.ts
@@ -108,6 +108,7 @@ const CONST = {
// Sizes needed for report empty state background image handling
EMPTY_STATE_BACKGROUND: {
+ ASPECT_RATIO: 3.72,
SMALL_SCREEN: {
IMAGE_HEIGHT: 300,
CONTAINER_MINHEIGHT: 200,
@@ -234,7 +235,6 @@ const CONST = {
BETA_EXPENSIFY_WALLET: 'expensifyWallet',
BETA_COMMENT_LINKING: 'commentLinking',
INTERNATIONALIZATION: 'internationalization',
- IOU_SEND: 'sendMoney',
POLICY_ROOMS: 'policyRooms',
PASSWORDLESS: 'passwordless',
TASKS: 'tasks',
@@ -478,20 +478,21 @@ const CONST = {
ACTIONS: {
LIMIT: 50,
TYPE: {
- APPROVED: 'APPROVED',
ADDCOMMENT: 'ADDCOMMENT',
+ APPROVED: 'APPROVED',
+ CHRONOSOOOLIST: 'CHRONOSOOOLIST',
CLOSED: 'CLOSED',
CREATED: 'CREATED',
- TASKEDITED: 'TASKEDITED',
- TASKCANCELLED: 'TASKCANCELLED',
IOU: 'IOU',
MODIFIEDEXPENSE: 'MODIFIEDEXPENSE',
REIMBURSEMENTQUEUED: 'REIMBURSEMENTQUEUED',
RENAMED: 'RENAMED',
- CHRONOSOOOLIST: 'CHRONOSOOOLIST',
+ REPORTPREVIEW: 'REPORTPREVIEW',
+ SUBMITTED: 'SUBMITTED',
+ TASKCANCELLED: 'TASKCANCELLED',
TASKCOMPLETED: 'TASKCOMPLETED',
+ TASKEDITED: 'TASKEDITED',
TASKREOPENED: 'TASKREOPENED',
- REPORTPREVIEW: 'REPORTPREVIEW',
POLICYCHANGELOG: {
ADD_APPROVER_RULE: 'POLICYCHANGELOG_ADD_APPROVER_RULE',
ADD_CATEGORY: 'POLICYCHANGELOG_ADD_CATEGORY',
@@ -930,6 +931,7 @@ const CONST = {
RECEIPTS: 'receipts@expensify.com',
STUDENT_AMBASSADOR: 'studentambassadors@expensify.com',
SVFG: 'svfg@expensify.com',
+ EXPENSIFY_EMAIL_DOMAIN: '@expensify.com',
},
ACCOUNT_ID: {
@@ -1170,6 +1172,14 @@ const CONST = {
AUDITOR: 'auditor',
USER: 'user',
},
+ AUTO_REPORTING_FREQUENCIES: {
+ IMMEDIATE: 'immediate',
+ WEEKLY: 'weekly',
+ SEMI_MONTHLY: 'semimonthly',
+ MONTHLY: 'monthly',
+ TRIP: 'trip',
+ MANUAL: 'manual',
+ },
ROOM_PREFIX: '#',
CUSTOM_UNIT_RATE_BASE_OFFSET: 100,
OWNER_EMAIL_FAKE: '_FAKE_',
@@ -1254,7 +1264,7 @@ const CONST = {
CARD_NUMBER: /^[0-9]{15,16}$/,
CARD_SECURITY_CODE: /^[0-9]{3,4}$/,
CARD_EXPIRATION_DATE: /^(0[1-9]|1[0-2])([^0-9])?([0-9]{4}|([0-9]{2}))$/,
- ROOM_NAME: /^#[a-z0-9à-ÿ-]{1,80}$/,
+ ROOM_NAME: /^#[\p{Ll}0-9-]{1,80}$/u,
// eslint-disable-next-line max-len, no-misleading-character-class
EMOJIS: /[\p{Extended_Pictographic}](\u200D[\p{Extended_Pictographic}]|[\u{1F3FB}-\u{1F3FF}]|[\u{E0020}-\u{E007F}]|\uFE0F|\u20E3)*|[\u{1F1E6}-\u{1F1FF}]{2}|[#*0-9]\uFE0F?\u20E3/gu,
@@ -2732,6 +2742,14 @@ const CONST = {
SPEND: 'spend',
WORKSPACES: 'workspaces',
},
+
+ MISSING_TRANSLATION: 'MISSING TRANSLATION',
+ SEARCH_MAX_LENGTH: 500,
+
+ /**
+ * The count of characters we'll allow the user to type after reaching SEARCH_MAX_LENGTH in an input.
+ */
+ ADDITIONAL_ALLOWED_CHARACTERS: 20,
} as const;
export default CONST;
diff --git a/src/ONYXKEYS.ts b/src/ONYXKEYS.ts
index 3aaaff7beda6..57bb0664ba9e 100755
--- a/src/ONYXKEYS.ts
+++ b/src/ONYXKEYS.ts
@@ -252,6 +252,7 @@ const ONYXKEYS = {
REPORT_USER_IS_LEAVING_ROOM: 'reportUserIsLeavingRoom_',
SECURITY_GROUP: 'securityGroup_',
TRANSACTION: 'transactions_',
+ PRIVATE_NOTES_DRAFT: 'privateNotesDraft_',
// Manual request tab selector
SELECTED_TAB: 'selectedTab_',
@@ -291,6 +292,7 @@ const ONYXKEYS = {
PRIVATE_NOTES_FORM: 'privateNotesForm',
I_KNOW_A_TEACHER_FORM: 'iKnowTeacherForm',
INTRO_SCHOOL_PRINCIPAL_FORM: 'introSchoolPrincipalForm',
+ REPORT_VIRTUAL_CARD_FRAUD: 'reportVirtualCardFraudForm',
},
} as const;
diff --git a/src/ROUTES.ts b/src/ROUTES.ts
index 2b64dd9c5465..2069f773075b 100644
--- a/src/ROUTES.ts
+++ b/src/ROUTES.ts
@@ -75,11 +75,19 @@ export default {
route: '/settings/wallet/card/:domain',
getRoute: (domain: string) => `/settings/wallet/card/${domain}`,
},
+ SETTINGS_REPORT_FRAUD: {
+ route: '/settings/wallet/cards/:domain/report-virtual-fraud',
+ getRoute: (domain: string) => `/settings/wallet/cards/${domain}/report-virtual-fraud`,
+ },
SETTINGS_ADD_DEBIT_CARD: 'settings/wallet/add-debit-card',
SETTINGS_ADD_BANK_ACCOUNT: 'settings/wallet/add-bank-account',
SETTINGS_ENABLE_PAYMENTS: 'settings/wallet/enable-payments',
SETTINGS_WALLET_TRANSFER_BALANCE: 'settings/wallet/transfer-balance',
SETTINGS_WALLET_CHOOSE_TRANSFER_ACCOUNT: 'settings/wallet/choose-transfer-account',
+ SETTINGS_WALLET_CARD_ACTIVATE: {
+ route: 'settings/wallet/cards/:domain/activate',
+ getRoute: (domain: string) => `settings/wallet/cards/${domain}/activate`,
+ },
SETTINGS_PERSONAL_DETAILS: 'settings/profile/personal-details',
SETTINGS_PERSONAL_DETAILS_LEGAL_NAME: 'settings/profile/personal-details/legal-name',
SETTINGS_PERSONAL_DETAILS_DATE_OF_BIRTH: 'settings/profile/personal-details/date-of-birth',
diff --git a/src/components/ArchivedReportFooter.js b/src/components/ArchivedReportFooter.js
index df49afbc3f0b..71d331b68db0 100644
--- a/src/components/ArchivedReportFooter.js
+++ b/src/components/ArchivedReportFooter.js
@@ -14,7 +14,6 @@ import reportPropTypes from '../pages/reportPropTypes';
import * as ReportActionsUtils from '../libs/ReportActionsUtils';
import styles from '../styles/styles';
import * as PersonalDetailsUtils from '../libs/PersonalDetailsUtils';
-import ArchivedReportFooterSkeletonView from './ArchivedReportFooterSkeletonView';
const propTypes = {
/** The reason this report was archived */
@@ -51,9 +50,6 @@ const defaultProps = {
};
function ArchivedReportFooter(props) {
- if (!props.reportClosedAction.reportActionID) {
- return ;
- }
const archiveReason = lodashGet(props.reportClosedAction, 'originalMessage.reason', CONST.REPORT.ARCHIVE_REASON.DEFAULT);
let displayName = PersonalDetailsUtils.getDisplayNameOrDefault(props.personalDetails, [props.report.ownerAccountID, 'displayName']);
diff --git a/src/components/ArchivedReportFooterSkeletonView.js b/src/components/ArchivedReportFooterSkeletonView.js
deleted file mode 100644
index 5fbc3c9d9e2c..000000000000
--- a/src/components/ArchivedReportFooterSkeletonView.js
+++ /dev/null
@@ -1,48 +0,0 @@
-import PropTypes from 'prop-types';
-import React from 'react';
-import SkeletonViewContentLoader from 'react-content-loader/native';
-import {View} from 'react-native';
-import {Rect} from 'react-native-svg';
-import compose from '../libs/compose';
-import styles from '../styles/styles';
-import themeColors from '../styles/themes/default';
-import withLocalize from './withLocalize';
-import withWindowDimensions from './withWindowDimensions';
-
-const propTypes = {
- /** Whether to animate the skeleton view */
- shouldAnimate: PropTypes.bool,
-};
-
-const defaultTypes = {
- shouldAnimate: true,
-};
-
-function ArchivedReportFooterSkeletonView(props) {
- return (
-
-
-
-
-
- );
-}
-
-ArchivedReportFooterSkeletonView.propTypes = propTypes;
-ArchivedReportFooterSkeletonView.defaultProps = defaultTypes;
-
-ArchivedReportFooterSkeletonView.displayName = 'ArchivedReportFooterSkeletonView';
-export default compose(withWindowDimensions, withLocalize)(ArchivedReportFooterSkeletonView);
diff --git a/src/components/BaseMiniContextMenuItem.js b/src/components/BaseMiniContextMenuItem.js
index 0e9085b54c17..3c423ffc80ea 100644
--- a/src/components/BaseMiniContextMenuItem.js
+++ b/src/components/BaseMiniContextMenuItem.js
@@ -61,12 +61,19 @@ function BaseMiniContextMenuItem(props) {
return;
}
+ // Allow text input blur on right click
+ if (!e || e.button === 2) {
+ return;
+ }
+
+ // Prevent text input blur on left click
e.preventDefault();
}}
accessibilityLabel={props.tooltipText}
style={({hovered, pressed}) => [
styles.reportActionContextMenuMiniButton,
StyleUtils.getButtonBackgroundColorStyle(getButtonState(hovered, pressed, props.isDelayButtonStateComplete)),
+ props.isDelayButtonStateComplete && styles.cursorDefault,
]}
>
{(pressableState) => (
diff --git a/src/components/CategoryPicker/index.js b/src/components/CategoryPicker/index.js
index ef8b1d71ad1d..13abf057e4b1 100644
--- a/src/components/CategoryPicker/index.js
+++ b/src/components/CategoryPicker/index.js
@@ -32,6 +32,7 @@ function CategoryPicker({selectedCategory, policyCategories, policyRecentlyUsedC
}, [selectedCategory]);
const sections = useMemo(() => {
+ const validPolicyRecentlyUsedCategories = _.filter(policyRecentlyUsedCategories, (p) => !_.isEmpty(p));
const {categoryOptions} = OptionsListUtils.getFilteredOptions(
{},
{},
@@ -43,7 +44,7 @@ function CategoryPicker({selectedCategory, policyCategories, policyRecentlyUsedC
false,
true,
policyCategories,
- policyRecentlyUsedCategories,
+ validPolicyRecentlyUsedCategories,
false,
);
diff --git a/src/components/ContextMenuItem.js b/src/components/ContextMenuItem.js
index 2314f2fcf64e..4c740caea78a 100644
--- a/src/components/ContextMenuItem.js
+++ b/src/components/ContextMenuItem.js
@@ -100,6 +100,7 @@ function ContextMenuItem({onPress, successIcon, successText, icon, text, isMini,
style={getContextMenuItemStyles(windowWidth)}
isAnonymousAction={isAnonymousAction}
focused={isFocused}
+ interactive={isThrottledButtonActive}
/>
);
}
diff --git a/src/components/EmojiPicker/EmojiPickerMenu/index.js b/src/components/EmojiPicker/EmojiPickerMenu/index.js
index e7af97145347..3dfc5f59bb38 100755
--- a/src/components/EmojiPicker/EmojiPickerMenu/index.js
+++ b/src/components/EmojiPicker/EmojiPickerMenu/index.js
@@ -195,7 +195,7 @@ class EmojiPickerMenu extends Component {
return;
}
const emoji = lodashGet(item, ['types', this.props.preferredSkinTone], item.code);
- this.addToFrequentAndSelectEmoji(emoji, item);
+ this.props.onEmojiSelected(emoji, item);
return;
}
@@ -258,16 +258,6 @@ class EmojiPickerMenu extends Component {
document.removeEventListener('mousemove', this.mouseMoveHandler);
}
- /**
- * @param {String} emoji
- * @param {Object} emojiObject
- */
- addToFrequentAndSelectEmoji(emoji, emojiObject) {
- const frequentEmojiList = EmojiUtils.getFrequentlyUsedEmojis(emojiObject);
- User.updateFrequentlyUsedEmojis(frequentEmojiList);
- this.props.onEmojiSelected(emoji, emojiObject);
- }
-
/**
* Focuses the search Input and has the text selected
*/
@@ -466,7 +456,7 @@ class EmojiPickerMenu extends Component {
return (
this.addToFrequentAndSelectEmoji(emoji, item)}
+ onPress={(emoji) => this.props.onEmojiSelected(emoji, item)}
onHoverIn={() => this.setState({highlightedIndex: index, isUsingKeyboardMovement: false})}
onHoverOut={() => {
if (this.state.arePointerEventsDisabled) {
diff --git a/src/components/EmojiPicker/EmojiPickerMenu/index.native.js b/src/components/EmojiPicker/EmojiPickerMenu/index.native.js
index dd5c18439cc1..fe8c3e275ad2 100644
--- a/src/components/EmojiPicker/EmojiPickerMenu/index.native.js
+++ b/src/components/EmojiPicker/EmojiPickerMenu/index.native.js
@@ -86,16 +86,6 @@ function EmojiPickerMenu({preferredLocale, onEmojiSelected, preferredSkinTone, t
setHeaderIndices(undefined);
}, 300);
- /**
- * @param {String} emoji
- * @param {Object} emojiObject
- */
- const addToFrequentAndSelectEmoji = (emoji, emojiObject) => {
- const frequentEmojiList = EmojiUtils.getFrequentlyUsedEmojis(emojiObject);
- User.updateFrequentlyUsedEmojis(frequentEmojiList);
- onEmojiSelected(emoji, emojiObject);
- };
-
/**
* @param {Number} skinTone
*/
@@ -152,7 +142,7 @@ function EmojiPickerMenu({preferredLocale, onEmojiSelected, preferredSkinTone, t
return (
addToFrequentAndSelectEmoji(emoji, item))}
+ onPress={singleExecution((emoji) => onEmojiSelected(emoji, item))}
emoji={emojiCode}
/>
);
diff --git a/src/components/EmojiPicker/EmojiSkinToneList.js b/src/components/EmojiPicker/EmojiSkinToneList.js
index a239f197cdd0..0c876910e746 100644
--- a/src/components/EmojiPicker/EmojiSkinToneList.js
+++ b/src/components/EmojiPicker/EmojiSkinToneList.js
@@ -46,11 +46,11 @@ function EmojiSkinToneList(props) {
{!isSkinToneListVisible && (
-
+
{currentSkinTone.code}
{props.translate('emojiPicker.skinTonePickerLabel')}
diff --git a/src/components/HTMLEngineProvider/BaseHTMLEngineProvider.js b/src/components/HTMLEngineProvider/BaseHTMLEngineProvider.js
index bba62cc4f4e0..c806bedc31c7 100755
--- a/src/components/HTMLEngineProvider/BaseHTMLEngineProvider.js
+++ b/src/components/HTMLEngineProvider/BaseHTMLEngineProvider.js
@@ -5,8 +5,8 @@ import PropTypes from 'prop-types';
import htmlRenderers from './HTMLRenderers';
import * as HTMLEngineUtils from './htmlEngineUtils';
import styles from '../../styles/styles';
-import fontFamily from '../../styles/fontFamily';
import convertToLTR from '../../libs/convertToLTR';
+import singleFontFamily from '../../styles/fontFamily/singleFontFamily';
const propTypes = {
/** Whether text elements should be selectable */
@@ -60,18 +60,13 @@ function BaseHTMLEngineProvider(props) {
// We need to memoize this prop to make it referentially stable.
const defaultTextProps = useMemo(() => ({selectable: props.textSelectable, allowFontScaling: false, textBreakStrategy: 'simple'}), [props.textSelectable]);
- // We need to pass multiple system-specific fonts for emojis but
- // we can't apply multiple fonts at once so we need to pass fallback fonts.
- const fallbackFonts = {'ExpensifyNeue-Regular': fontFamily.EXP_NEUE};
-
return (
(text.data = convertToLTR(text.data)),
diff --git a/src/components/HeaderPageLayout.js b/src/components/HeaderPageLayout.js
index 37c7eb18dad1..adfe0a8784e2 100644
--- a/src/components/HeaderPageLayout.js
+++ b/src/components/HeaderPageLayout.js
@@ -31,16 +31,26 @@ const propTypes = {
/** Style to apply to the header image container */
// eslint-disable-next-line react/forbid-prop-types
headerContainerStyles: PropTypes.arrayOf(PropTypes.object),
+
+ /** Style to apply to the ScrollView container */
+ // eslint-disable-next-line react/forbid-prop-types
+ scrollViewContainerStyles: PropTypes.arrayOf(PropTypes.object),
+
+ /** Style to apply to the children container */
+ // eslint-disable-next-line react/forbid-prop-types
+ childrenContainerStyles: PropTypes.arrayOf(PropTypes.object),
};
const defaultProps = {
backgroundColor: themeColors.appBG,
header: null,
headerContainerStyles: [],
+ scrollViewContainerStyles: [],
+ childrenContainerStyles: [],
footer: null,
};
-function HeaderPageLayout({backgroundColor, children, footer, headerContainerStyles, style, headerContent, ...propsToPassToHeader}) {
+function HeaderPageLayout({backgroundColor, children, footer, headerContainerStyles, scrollViewContainerStyles, childrenContainerStyles, style, headerContent, ...propsToPassToHeader}) {
const {windowHeight, isSmallScreenWidth} = useWindowDimensions();
const {isOffline} = useNetwork();
const appBGColor = StyleUtils.getBackgroundColorStyle(themeColors.appBG);
@@ -77,14 +87,14 @@ function HeaderPageLayout({backgroundColor, children, footer, headerContainerSty
)}
{!Browser.isSafari() && }
{headerContent}
- {children}
+ {children}
{!_.isNull(footer) && {footer} }
diff --git a/src/components/IFrame.js b/src/components/IFrame.js
index 129af4254c42..5f7f657b0c09 100644
--- a/src/components/IFrame.js
+++ b/src/components/IFrame.js
@@ -1,5 +1,8 @@
/* eslint-disable es/no-nullish-coalescing-operators */
import React, {useEffect, useState} from 'react';
+import {withOnyx} from 'react-native-onyx';
+import PropTypes from 'prop-types';
+import ONYXKEYS from '../ONYXKEYS';
function getNewDotURL(url) {
const urlObj = new URL(url);
@@ -50,6 +53,11 @@ function getOldDotURL(url) {
const pathname = urlObj.pathname;
const paths = pathname.slice(1).split('/');
+ // TODO: temporary measure until linking config is adjusted
+ if (pathname.startsWith('/r')) {
+ return 'inbox';
+ }
+
if (pathname === 'home') {
return 'inbox';
}
@@ -78,8 +86,19 @@ function getOldDotURL(url) {
return pathname;
}
-export default function ReportScreen() {
- const [oldDotURL, setOldDotURL] = useState('https://www.expensify.com.dev');
+const propTypes = {
+ // The session of the logged in person
+ session: PropTypes.shape({
+ // The email of the logged in person
+ email: PropTypes.string,
+
+ // The authToken of the logged in person
+ authToken: PropTypes.string,
+ }).isRequired,
+};
+
+function OldDotIFrame({session}) {
+ const [oldDotURL, setOldDotURL] = useState('https://staging.expensify.com');
useEffect(() => {
setOldDotURL(`https://expensify.com.dev/${getOldDotURL(window.location.href)}`);
@@ -92,6 +111,11 @@ export default function ReportScreen() {
});
}, []);
+ useEffect(() => {
+ document.cookie = `authToken=${session.authToken}; domain=expensify.com.dev; path=/;`;
+ document.cookie = `email=${session.email}; domain=expensify.com.dev; path=/;`;
+ }, [session.authToken, session.email]);
+
return (
);
}
+
+OldDotIFrame.propTypes = propTypes;
+
+export default withOnyx({
+ session: {
+ key: ONYXKEYS.SESSION,
+ },
+})(OldDotIFrame);
diff --git a/src/components/LHNOptionsList/LHNOptionsList.js b/src/components/LHNOptionsList/LHNOptionsList.js
index 7433c2798879..5e07b487c4f7 100644
--- a/src/components/LHNOptionsList/LHNOptionsList.js
+++ b/src/components/LHNOptionsList/LHNOptionsList.js
@@ -79,6 +79,7 @@ function LHNOptionsList({style, contentContainerStyles, data, onSelectRow, optio
contentContainerStyle={contentContainerStyles}
showsVerticalScrollIndicator={false}
data={data}
+ testID="lhn-options-list"
keyExtractor={(item) => item}
stickySectionHeadersEnabled={false}
renderItem={renderItem}
diff --git a/src/components/LHNOptionsList/OptionRowLHN.js b/src/components/LHNOptionsList/OptionRowLHN.js
index ac37947daa17..4e6564646cac 100644
--- a/src/components/LHNOptionsList/OptionRowLHN.js
+++ b/src/components/LHNOptionsList/OptionRowLHN.js
@@ -171,13 +171,15 @@ function OptionRowLHN(props) {
props.onSelectRow(optionItem, popoverAnchor);
}}
onMouseDown={(e) => {
- if (!e) {
+ // Allow composer blur on right click
+ if (!e || e.button === 2) {
return;
}
- // Prevent losing Composer focus
+ // Prevent composer blur on left click
e.preventDefault();
}}
+ testID={optionItem.reportID}
onSecondaryInteraction={(e) => showPopover(e)}
withoutFocusOnSecondaryInteraction
activeOpacity={0.8}
diff --git a/src/components/LottieAnimations.js b/src/components/LottieAnimations.js
index 274d60306393..167b1078c3ca 100644
--- a/src/components/LottieAnimations.js
+++ b/src/components/LottieAnimations.js
@@ -6,5 +6,6 @@ const ReviewingBankInfo = require('../../assets/animations/ReviewingBankInfo.jso
const WorkspacePlanet = require('../../assets/animations/WorkspacePlanet.json');
const SaveTheWorld = require('../../assets/animations/SaveTheWorld.json');
const Safe = require('../../assets/animations/Safe.json');
+const Magician = require('../../assets/animations/Magician.json');
-export {ExpensifyLounge, Fireworks, Hands, PreferencesDJ, ReviewingBankInfo, SaveTheWorld, WorkspacePlanet, Safe};
+export {ExpensifyLounge, Fireworks, Hands, PreferencesDJ, ReviewingBankInfo, SaveTheWorld, WorkspacePlanet, Safe, Magician};
diff --git a/src/components/MagicCodeInput.js b/src/components/MagicCodeInput.js
index 454aacc8a03b..dcaa0273f96a 100644
--- a/src/components/MagicCodeInput.js
+++ b/src/components/MagicCodeInput.js
@@ -30,7 +30,7 @@ const propTypes = {
errorText: PropTypes.string,
/** Specifies autocomplete hints for the system, so it can provide autofill */
- autoComplete: PropTypes.oneOf(['sms-otp', 'one-time-code']).isRequired,
+ autoComplete: PropTypes.oneOf(['sms-otp', 'one-time-code', 'off']).isRequired,
/* Should submit when the input is complete */
shouldSubmitOnComplete: PropTypes.bool,
@@ -48,6 +48,12 @@ const propTypes = {
/** Specifies the max length of the input */
maxLength: PropTypes.number,
+
+ /** Specifies if the keyboard should be disabled */
+ isDisableKeyboard: PropTypes.bool,
+
+ /** Last pressed digit on BigDigitPad */
+ lastPressedDigit: PropTypes.string,
};
const defaultProps = {
@@ -61,6 +67,8 @@ const defaultProps = {
onFulfill: () => {},
hasError: false,
maxLength: CONST.MAGIC_CODE_LENGTH,
+ isDisableKeyboard: false,
+ lastPressedDigit: '',
};
/**
@@ -190,9 +198,21 @@ function MagicCodeInput(props) {
* @param {Object} event
*/
const onKeyPress = ({nativeEvent: {key: keyValue}}) => {
- if (keyValue === 'Backspace') {
+ if (keyValue === 'Backspace' || keyValue === '<') {
let numbers = decomposeString(props.value, props.maxLength);
+ // If keyboard is disabled and no input is focused we need to remove
+ // the last entered digit and focus on the correct input
+ if (props.isDisableKeyboard && focusedIndex === undefined) {
+ const indexBeforeLastEditIndex = editIndex === 0 ? editIndex : editIndex - 1;
+
+ const indexToFocus = numbers[editIndex] === CONST.MAGIC_CODE_EMPTY_CHAR ? indexBeforeLastEditIndex : editIndex;
+ inputRefs.current[indexToFocus].focus();
+ props.onChangeText(props.value.substring(0, indexToFocus));
+
+ return;
+ }
+
// If the currently focused index already has a value, it will delete
// that value but maintain the focus on the same input.
if (numbers[focusedIndex] !== CONST.MAGIC_CODE_EMPTY_CHAR) {
@@ -237,13 +257,34 @@ function MagicCodeInput(props) {
}
};
+ /**
+ * If isDisableKeyboard is true we will have to call onKeyPress and onChangeText manually
+ * as the press on digit pad will not trigger native events. We take lastPressedDigit from props
+ * as it stores the last pressed digit pressed on digit pad. We take only the first character
+ * as anything after that is added to differentiate between two same digits passed in a row.
+ */
+
+ useEffect(() => {
+ if (!props.isDisableKeyboard) {
+ return;
+ }
+
+ const value = props.lastPressedDigit.charAt(0);
+ onKeyPress({nativeEvent: {key: value}});
+ onChangeText(value);
+
+ // We have not added:
+ // + the onChangeText and onKeyPress as the dependencies because we only want to run this when lastPressedDigit changes.
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [props.lastPressedDigit, props.isDisableKeyboard]);
+
return (
<>
{_.map(getInputPlaceholderSlots(props.maxLength), (index) => (
{
)}
{Boolean(props.title) && (Boolean(props.shouldRenderAsHTML) || (Boolean(props.shouldParseTitle) && Boolean(html.length))) && (
-
+
+
+
)}
{!props.shouldRenderAsHTML && !props.shouldParseTitle && Boolean(props.title) && (
-
-
- );
-}
-
-MenuItemRenderHTMLTitle.propTypes = propTypes;
-MenuItemRenderHTMLTitle.defaultProps = defaultProps;
-MenuItemRenderHTMLTitle.displayName = 'MenuItemRenderHTMLTitle';
-
-export default MenuItemRenderHTMLTitle;
diff --git a/src/components/MenuItemRenderHTMLTitle/index.native.js b/src/components/MenuItemRenderHTMLTitle/index.native.js
deleted file mode 100644
index b3dff8d77eff..000000000000
--- a/src/components/MenuItemRenderHTMLTitle/index.native.js
+++ /dev/null
@@ -1,17 +0,0 @@
-import React from 'react';
-import RenderHTML from '../RenderHTML';
-import menuItemRenderHTMLTitlePropTypes from './propTypes';
-
-const propTypes = menuItemRenderHTMLTitlePropTypes;
-
-const defaultProps = {};
-
-function MenuItemRenderHTMLTitle(props) {
- return ;
-}
-
-MenuItemRenderHTMLTitle.propTypes = propTypes;
-MenuItemRenderHTMLTitle.defaultProps = defaultProps;
-MenuItemRenderHTMLTitle.displayName = 'MenuItemRenderHTMLTitle';
-
-export default MenuItemRenderHTMLTitle;
diff --git a/src/components/MenuItemRenderHTMLTitle/propTypes.js b/src/components/MenuItemRenderHTMLTitle/propTypes.js
deleted file mode 100644
index 68e279eb28c3..000000000000
--- a/src/components/MenuItemRenderHTMLTitle/propTypes.js
+++ /dev/null
@@ -1,8 +0,0 @@
-import PropTypes from 'prop-types';
-
-const propTypes = {
- /** Processed title to display for the MenuItem */
- title: PropTypes.string.isRequired,
-};
-
-export default propTypes;
diff --git a/src/components/MoneyReportHeader.js b/src/components/MoneyReportHeader.js
index dded77d5e30f..fbd686fac692 100644
--- a/src/components/MoneyReportHeader.js
+++ b/src/components/MoneyReportHeader.js
@@ -69,16 +69,19 @@ function MoneyReportHeader({session, personalDetails, policy, chatReport, report
const isPolicyAdmin = policyType !== CONST.POLICY.TYPE.PERSONAL && lodashGet(policy, 'role') === CONST.POLICY.ROLE.ADMIN;
const isManager = ReportUtils.isMoneyRequestReport(moneyRequestReport) && lodashGet(session, 'accountID', null) === moneyRequestReport.managerID;
const isPayer = policyType === CONST.POLICY.TYPE.CORPORATE ? isPolicyAdmin && isApproved : isPolicyAdmin || (ReportUtils.isMoneyRequestReport(moneyRequestReport) && isManager);
+ const isDraft = ReportUtils.isReportDraft(moneyRequestReport);
const shouldShowSettlementButton = useMemo(
- () => isPayer && !isSettled && !moneyRequestReport.isWaitingOnBankAccount && reportTotal !== 0 && !ReportUtils.isArchivedRoom(chatReport),
- [isPayer, isSettled, moneyRequestReport, reportTotal, chatReport],
+ () => isPayer && !isDraft && !isSettled && !moneyRequestReport.isWaitingOnBankAccount && reportTotal !== 0 && !ReportUtils.isArchivedRoom(chatReport),
+ [isPayer, isDraft, isSettled, moneyRequestReport, reportTotal, chatReport],
);
const shouldShowApproveButton = useMemo(() => {
if (policyType !== CONST.POLICY.TYPE.CORPORATE) {
return false;
}
- return isManager && !isApproved && !isSettled;
- }, [policyType, isManager, isApproved, isSettled]);
+ return isManager && !isDraft && !isApproved && !isSettled;
+ }, [policyType, isManager, isDraft, isApproved, isSettled]);
+ const shouldShowSubmitButton = isDraft;
+ const shouldShowAnyButton = shouldShowSettlementButton || shouldShowApproveButton || shouldShowSubmitButton;
const bankAccountRoute = ReportUtils.getBankAccountRoute(chatReport);
const formattedAmount = CurrencyUtils.convertToDisplayString(reportTotal, moneyRequestReport.currency);
@@ -93,10 +96,10 @@ function MoneyReportHeader({session, personalDetails, policy, chatReport, report
personalDetails={personalDetails}
shouldShowBackButton={isSmallScreenWidth}
onBackButtonPress={() => Navigation.goBack(ROUTES.HOME, false, true)}
- shouldShowBorderBottom={!shouldShowSettlementButton || !isSmallScreenWidth}
+ shouldShowBorderBottom={!shouldShowAnyButton || !isSmallScreenWidth}
>
{shouldShowSettlementButton && !isSmallScreenWidth && (
-
+
)}
{shouldShowApproveButton && !isSmallScreenWidth && (
-
+
)}
+ {shouldShowSubmitButton && !isSmallScreenWidth && (
+
+ IOU.submitReport(moneyRequestReport)}
+ />
+
+ )}
{shouldShowSettlementButton && isSmallScreenWidth && (
@@ -153,6 +167,17 @@ function MoneyReportHeader({session, personalDetails, policy, chatReport, report
/>
)}
+ {shouldShowSubmitButton && isSmallScreenWidth && (
+
+ IOU.submitReport(moneyRequestReport)}
+ />
+
+ )}
);
}
diff --git a/src/components/MoneyRequestConfirmationList.js b/src/components/MoneyRequestConfirmationList.js
index b71047e3ca36..acaa83181bbf 100755
--- a/src/components/MoneyRequestConfirmationList.js
+++ b/src/components/MoneyRequestConfirmationList.js
@@ -114,8 +114,8 @@ const propTypes = {
/** File path of the receipt */
receiptPath: PropTypes.string,
- /** File source of the receipt */
- receiptSource: PropTypes.string,
+ /** File name of the receipt */
+ receiptFilename: PropTypes.string,
/** List styles for OptionsSelector */
listStyles: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.object), PropTypes.object]),
@@ -141,6 +141,12 @@ const propTypes = {
/** Whether the money request is a distance request */
isDistanceRequest: PropTypes.bool,
+ /** Whether the receipt associated with this report is being scanned */
+ isScanning: PropTypes.bool,
+
+ /** A flag for verifying that the current report is a sub-report of a workspace chat */
+ isPolicyExpenseChat: PropTypes.bool,
+
/* Onyx Props */
/** Collection of categories attached to a policy */
policyCategories: PropTypes.objectOf(categoryPropTypes),
@@ -168,7 +174,7 @@ const defaultProps = {
reportID: '',
...withCurrentUserPersonalDetailsDefaultProps,
receiptPath: '',
- receiptSource: '',
+ receiptFilename: '',
listStyles: [],
policyCategories: {},
policyTags: {},
@@ -176,6 +182,8 @@ const defaultProps = {
transaction: {},
mileageRate: {unit: CONST.CUSTOM_UNITS.DISTANCE_UNIT_MILES, rate: 0, currency: 'USD'},
isDistanceRequest: false,
+ isScanning: false,
+ isPolicyExpenseChat: false,
};
function MoneyRequestConfirmationList(props) {
@@ -184,20 +192,23 @@ function MoneyRequestConfirmationList(props) {
const {onSendMoney, onConfirm, onSelectParticipant, transaction} = props;
const {translate, toLocaleDigit} = useLocalize();
- // A flag and a toggler for showing the rest of the form fields
- const [shouldExpandFields, toggleShouldExpandFields] = useReducer((state) => !state, false);
- const shouldShowAllFields = props.isDistanceRequest || shouldExpandFields;
const isTypeRequest = props.iouType === CONST.IOU.MONEY_REQUEST_TYPE.REQUEST;
const {unit, rate, currency} = props.mileageRate;
const distance = lodashGet(transaction, 'routes.route0.distance', 0);
const shouldCalculateDistanceAmount = props.isDistanceRequest && props.iouAmount === 0;
- // A flag for verifying that the current report is a sub-report of a workspace chat
- const isPolicyExpenseChat = useMemo(() => ReportUtils.isPolicyExpenseChat(ReportUtils.getRootParentReport(ReportUtils.getReport(props.reportID))), [props.reportID]);
-
// A flag for showing the categories field
- const shouldShowCategories = isPolicyExpenseChat && Permissions.canUseCategories(props.betas) && OptionsListUtils.hasEnabledOptions(_.values(props.policyCategories));
+ const shouldShowCategories =
+ props.isPolicyExpenseChat && Permissions.canUseCategories(props.betas) && (props.iouCategory || OptionsListUtils.hasEnabledOptions(_.values(props.policyCategories)));
+
+ // A flag for showing SmartScan fields: date, merchant, and amount, only when we don't have a receiptPath (e.g. manual request)
+ // or in the split details page which is ReadOnly
+ const shouldShowSmartScanFields = (!props.receiptPath || props.isReadOnly) && !props.isScanning;
+
+ // A flag and a toggler for showing the rest of the form fields
+ const [shouldExpandFields, toggleShouldExpandFields] = useReducer((state) => !state, false);
+ const shouldShowAllFields = props.isDistanceRequest || shouldExpandFields || !shouldShowSmartScanFields;
// Fetches the first tag list of the policy
const policyTag = PolicyUtils.getTag(props.policyTags);
@@ -205,7 +216,7 @@ function MoneyRequestConfirmationList(props) {
const policyTagListName = lodashGet(policyTag, 'name', translate('common.tag'));
const canUseTags = Permissions.canUseTags(props.betas);
// A flag for showing the tags field
- const shouldShowTags = isPolicyExpenseChat && canUseTags && OptionsListUtils.hasEnabledOptions(_.values(policyTagList));
+ const shouldShowTags = props.isPolicyExpenseChat && canUseTags && OptionsListUtils.hasEnabledOptions(_.values(policyTagList));
// A flag for showing the billable field
const shouldShowBillable = canUseTags && !lodashGet(props.policy, 'disabledFields.defaultBillable', true);
@@ -243,7 +254,10 @@ function MoneyRequestConfirmationList(props) {
const getParticipantsWithAmount = useCallback(
(participantsList) => {
const iouAmount = IOUUtils.calculateAmount(participantsList.length, props.iouAmount, props.iouCurrencyCode);
- return OptionsListUtils.getIOUConfirmationOptionsFromParticipants(participantsList, CurrencyUtils.convertToDisplayString(iouAmount, props.iouCurrencyCode));
+ return OptionsListUtils.getIOUConfirmationOptionsFromParticipants(
+ participantsList,
+ props.iouAmount > 0 ? CurrencyUtils.convertToDisplayString(iouAmount, props.iouCurrencyCode) : '',
+ );
},
[props.iouAmount, props.iouCurrencyCode],
);
@@ -252,7 +266,9 @@ function MoneyRequestConfirmationList(props) {
const splitOrRequestOptions = useMemo(() => {
let text;
- if (props.receiptPath || isDistanceRequestWithoutRoute) {
+ if (props.receiptPath && props.hasMultipleParticipants && props.iouAmount === 0) {
+ text = translate('iou.split');
+ } else if (props.receiptPath || isDistanceRequestWithoutRoute) {
text = translate('iou.request');
} else {
const translationKey = props.hasMultipleParticipants ? 'iou.splitAmount' : 'iou.requestAmount';
@@ -264,7 +280,7 @@ function MoneyRequestConfirmationList(props) {
value: props.hasMultipleParticipants ? CONST.IOU.MONEY_REQUEST_TYPE.SPLIT : CONST.IOU.MONEY_REQUEST_TYPE.REQUEST,
},
];
- }, [props.hasMultipleParticipants, props.receiptPath, translate, formattedAmount, isDistanceRequestWithoutRoute]);
+ }, [props.hasMultipleParticipants, props.iouAmount, props.receiptPath, translate, formattedAmount, isDistanceRequestWithoutRoute]);
const selectedParticipants = useMemo(() => _.filter(props.selectedParticipants, (participant) => participant.selected), [props.selectedParticipants]);
const payeePersonalDetails = useMemo(() => props.payeePersonalDetails || props.currentUserPersonalDetails, [props.payeePersonalDetails, props.currentUserPersonalDetails]);
@@ -288,7 +304,7 @@ function MoneyRequestConfirmationList(props) {
const myIOUAmount = IOUUtils.calculateAmount(selectedParticipants.length, props.iouAmount, props.iouCurrencyCode, true);
const formattedPayeeOption = OptionsListUtils.getIOUConfirmationOptionsFromPayeePersonalDetail(
payeePersonalDetails,
- CurrencyUtils.convertToDisplayString(myIOUAmount, props.iouCurrencyCode),
+ props.iouAmount > 0 ? CurrencyUtils.convertToDisplayString(myIOUAmount, props.iouCurrencyCode) : '',
);
sections.push(
@@ -457,6 +473,9 @@ function MoneyRequestConfirmationList(props) {
);
}, [confirm, props.bankAccountRoute, props.iouCurrencyCode, props.iouType, props.isReadOnly, props.policyID, selectedParticipants, splitOrRequestOptions, translate, formError]);
+ const {image: receiptImage, thumbnail: receiptThumbnail} =
+ props.receiptPath && props.receiptFilename ? ReceiptUtils.getThumbnailAndImageURIs(props.receiptPath, props.receiptFilename) : {};
+
return (
)}
- {!_.isEmpty(props.receiptPath) ? (
+ {(receiptImage || receiptThumbnail) && (
- ) : (
+ )}
+ {shouldShowSmartScanFields && (
- Navigation.navigate(ROUTES.MONEY_REQUEST_DATE.getRoute(props.iouType, props.reportID))}
- disabled={didConfirm || props.isReadOnly || !isTypeRequest}
- />
- {props.isDistanceRequest ? (
+ {shouldShowSmartScanFields && (
+ Navigation.navigate(ROUTES.MONEY_REQUEST_DATE.getRoute(props.iouType, props.reportID))}
+ disabled={didConfirm || props.isReadOnly}
+ />
+ )}
+ {props.isDistanceRequest && (
Navigation.navigate(ROUTES.MONEY_REQUEST_DISTANCE.getRoute(props.iouType, props.reportID))}
disabled={didConfirm || props.isReadOnly || !isTypeRequest}
/>
- ) : (
+ )}
+ {shouldShowSmartScanFields && (
Navigation.navigate(ROUTES.MONEY_REQUEST_MERCHANT.getRoute(props.iouType, props.reportID))}
- disabled={didConfirm || props.isReadOnly || !isTypeRequest}
+ disabled={didConfirm || props.isReadOnly}
/>
)}
{shouldShowCategories && (
diff --git a/src/components/MoneyRequestHeader.js b/src/components/MoneyRequestHeader.js
index 7117f67a29b0..8a2005e64c22 100644
--- a/src/components/MoneyRequestHeader.js
+++ b/src/components/MoneyRequestHeader.js
@@ -1,4 +1,4 @@
-import React, {useState, useCallback} from 'react';
+import React, {useState, useCallback, useEffect} from 'react';
import {withOnyx} from 'react-native-onyx';
import {View} from 'react-native';
import PropTypes from 'prop-types';
@@ -81,13 +81,23 @@ function MoneyRequestHeader({session, parentReport, report, parentReportAction,
const isScanning = TransactionUtils.hasReceipt(transaction) && TransactionUtils.isReceiptBeingScanned(transaction);
+ const canModifyRequest = isActionOwner && !isSettled && !isApproved;
+
+ useEffect(() => {
+ if (canModifyRequest) {
+ return;
+ }
+
+ setIsDeleteModalVisible(false);
+ }, [canModifyRequest]);
+
return (
<>
+
{translate('iou.receiptStatusTitle')}
diff --git a/src/components/OptionRow.js b/src/components/OptionRow.js
index 70415ab03a13..85d3e83c1360 100644
--- a/src/components/OptionRow.js
+++ b/src/components/OptionRow.js
@@ -70,6 +70,9 @@ const propTypes = {
/** Whether to remove the lateral padding and align the content with the margins */
shouldDisableRowInnerPadding: PropTypes.bool,
+ /** Whether to prevent default focusing on select */
+ shouldPreventDefaultFocusOnSelectRow: PropTypes.bool,
+
/** Whether to wrap large text up to 2 lines */
isMultilineSupported: PropTypes.bool,
@@ -95,6 +98,7 @@ const defaultProps = {
style: null,
shouldHaveOptionSeparator: false,
shouldDisableRowInnerPadding: false,
+ shouldPreventDefaultFocusOnSelectRow: false,
};
class OptionRow extends Component {
@@ -213,6 +217,7 @@ class OptionRow extends Component {
hoverDimmingValue={1}
hoverStyle={this.props.hoverStyle}
needsOffscreenAlphaCompositing={lodashGet(this.props.option, 'icons.length', 0) >= 2}
+ onMouseDown={this.props.shouldPreventDefaultFocusOnSelectRow ? (e) => e.preventDefault() : undefined}
>
@@ -282,6 +287,7 @@ class OptionRow extends Component {
) : (
this.props.onSelectedStatePressed(this.props.option)}
+ disabled={this.state.isDisabled}
accessibilityRole={CONST.ACCESSIBILITY_ROLE.CHECKBOX}
accessibilityLabel={CONST.ACCESSIBILITY_ROLE.CHECKBOX}
>
diff --git a/src/components/OptionsList/BaseOptionsList.js b/src/components/OptionsList/BaseOptionsList.js
index 5a40c28a86c9..23049b65f198 100644
--- a/src/components/OptionsList/BaseOptionsList.js
+++ b/src/components/OptionsList/BaseOptionsList.js
@@ -54,6 +54,7 @@ function BaseOptionsList({
showScrollIndicator,
listContainerStyles,
shouldDisableRowInnerPadding,
+ shouldPreventDefaultFocusOnSelectRow,
disableFocusOptions,
canSelectMultipleOptions,
shouldShowMultipleOptionSelectorAsButton,
@@ -206,6 +207,7 @@ function BaseOptionsList({
isDisabled={isItemDisabled}
shouldHaveOptionSeparator={index > 0 && shouldHaveOptionSeparator}
shouldDisableRowInnerPadding={shouldDisableRowInnerPadding}
+ shouldPreventDefaultFocusOnSelectRow={shouldPreventDefaultFocusOnSelectRow}
isMultilineSupported={isRowMultilineSupported}
/>
);
diff --git a/src/components/OptionsList/optionsListPropTypes.js b/src/components/OptionsList/optionsListPropTypes.js
index a2479c878041..165cec699b80 100644
--- a/src/components/OptionsList/optionsListPropTypes.js
+++ b/src/components/OptionsList/optionsListPropTypes.js
@@ -79,6 +79,9 @@ const propTypes = {
/** Whether to disable the inner padding in rows */
shouldDisableRowInnerPadding: PropTypes.bool,
+ /** Whether to prevent default focusing when selecting a row */
+ shouldPreventDefaultFocusOnSelectRow: PropTypes.bool,
+
/** Whether to show the scroll bar */
showScrollIndicator: PropTypes.bool,
@@ -107,6 +110,7 @@ const defaultProps = {
onLayout: undefined,
shouldHaveOptionSeparator: false,
shouldDisableRowInnerPadding: false,
+ shouldPreventDefaultFocusOnSelectRow: false,
showScrollIndicator: false,
isRowMultilineSupported: false,
};
diff --git a/src/components/OptionsSelector/BaseOptionsSelector.js b/src/components/OptionsSelector/BaseOptionsSelector.js
index 1d0105394042..65f4bc64cee0 100755
--- a/src/components/OptionsSelector/BaseOptionsSelector.js
+++ b/src/components/OptionsSelector/BaseOptionsSelector.js
@@ -54,6 +54,7 @@ class BaseOptionsSelector extends Component {
this.selectRow = this.selectRow.bind(this);
this.selectFocusedOption = this.selectFocusedOption.bind(this);
this.addToSelection = this.addToSelection.bind(this);
+ this.updateSearchValue = this.updateSearchValue.bind(this);
this.relatedTarget = null;
const allOptions = this.flattenSections();
@@ -63,6 +64,7 @@ class BaseOptionsSelector extends Component {
allOptions,
focusedIndex,
shouldDisableRowSelection: false,
+ errorMessage: '',
};
}
@@ -167,6 +169,14 @@ class BaseOptionsSelector extends Component {
return defaultIndex;
}
+ updateSearchValue(value) {
+ this.setState({
+ errorMessage: value.length > this.props.maxLength ? this.props.translate('common.error.characterLimitExceedCounter', {length: value.length, limit: this.props.maxLength}) : '',
+ });
+
+ this.props.onChangeText(value);
+ }
+
subscribeToKeyboardShortcut() {
const enterConfig = CONST.KEYBOARD_SHORTCUTS.ENTER;
this.unsubscribeEnter = KeyboardShortcut.subscribe(
@@ -316,7 +326,7 @@ class BaseOptionsSelector extends Component {
*/
selectRow(option, ref) {
return new Promise((resolve) => {
- if (this.props.shouldShowTextInput && this.props.shouldFocusOnSelectRow) {
+ if (this.props.shouldShowTextInput && this.props.shouldPreventDefaultFocusOnSelectRow) {
if (this.relatedTarget && ref === this.relatedTarget) {
this.textInput.focus();
this.relatedTarget = null;
@@ -344,7 +354,7 @@ class BaseOptionsSelector extends Component {
* @param {Object} option
*/
addToSelection(option) {
- if (this.props.shouldShowTextInput && this.props.shouldFocusOnSelectRow) {
+ if (this.props.shouldShowTextInput && this.props.shouldPreventDefaultFocusOnSelectRow) {
this.textInput.focus();
if (this.textInput.isFocused()) {
setSelection(this.textInput, 0, this.props.value.length);
@@ -366,13 +376,14 @@ class BaseOptionsSelector extends Component {
label={this.props.textInputLabel}
accessibilityLabel={this.props.textInputLabel}
accessibilityRole={CONST.ACCESSIBILITY_ROLE.TEXT}
- onChangeText={this.props.onChangeText}
+ onChangeText={this.updateSearchValue}
+ errorText={this.state.errorMessage}
onSubmitEditing={this.selectFocusedOption}
placeholder={this.props.placeholderText}
- maxLength={this.props.maxLength}
+ maxLength={this.props.maxLength + CONST.ADDITIONAL_ALLOWED_CHARACTERS}
keyboardType={this.props.keyboardType}
onBlur={(e) => {
- if (!this.props.shouldFocusOnSelectRow) {
+ if (!this.props.shouldPreventDefaultFocusOnSelectRow) {
return;
}
this.relatedTarget = e.relatedTarget;
@@ -396,7 +407,7 @@ class BaseOptionsSelector extends Component {
multipleOptionSelectorButtonText={this.props.multipleOptionSelectorButtonText}
onAddToSelection={this.addToSelection}
hideSectionHeaders={this.props.hideSectionHeaders}
- headerMessage={this.props.headerMessage}
+ headerMessage={this.state.errorMessage ? '' : this.props.headerMessage}
boldStyle={this.props.boldStyle}
showTitleTooltip={this.props.showTitleTooltip}
isDisabled={this.props.isDisabled}
@@ -417,6 +428,7 @@ class BaseOptionsSelector extends Component {
isLoading={!this.props.shouldShowOptions}
showScrollIndicator={this.props.showScrollIndicator}
isRowMultilineSupported={this.props.isRowMultilineSupported}
+ shouldPreventDefaultFocusOnSelectRow={this.props.shouldPreventDefaultFocusOnSelectRow}
/>
);
return (
diff --git a/src/components/OptionsSelector/optionsSelectorPropTypes.js b/src/components/OptionsSelector/optionsSelectorPropTypes.js
index 8a7158092967..9e028510e608 100644
--- a/src/components/OptionsSelector/optionsSelectorPropTypes.js
+++ b/src/components/OptionsSelector/optionsSelectorPropTypes.js
@@ -1,6 +1,7 @@
import PropTypes from 'prop-types';
import optionPropTypes from '../optionPropTypes';
import styles from '../../styles/styles';
+import CONST from '../../CONST';
const propTypes = {
/** Callback to fire when a row is tapped */
@@ -80,8 +81,8 @@ const propTypes = {
/** Whether to show the title tooltip */
showTitleTooltip: PropTypes.bool,
- /** Whether to focus the textinput after an option is selected */
- shouldFocusOnSelectRow: PropTypes.bool,
+ /** Whether to prevent default focusing of options and focus the textinput when selecting an option */
+ shouldPreventDefaultFocusOnSelectRow: PropTypes.bool,
/** Whether to autofocus the search input on mount */
autoFocus: PropTypes.bool,
@@ -144,7 +145,7 @@ const defaultProps = {
hideSectionHeaders: false,
boldStyle: false,
showTitleTooltip: false,
- shouldFocusOnSelectRow: false,
+ shouldPreventDefaultFocusOnSelectRow: false,
autoFocus: true,
shouldShowConfirmButton: false,
confirmButtonText: undefined,
@@ -157,7 +158,7 @@ const defaultProps = {
isDisabled: false,
shouldHaveOptionSeparator: false,
initiallyFocusedOptionKey: undefined,
- maxLength: undefined,
+ maxLength: CONST.SEARCH_MAX_LENGTH,
shouldShowTextInput: true,
onChangeText: () => {},
shouldUseStyleForChildren: true,
diff --git a/src/components/PopoverWithoutOverlay/index.js b/src/components/PopoverWithoutOverlay/index.js
index 7287f36e7f2c..3b194ad4b9cf 100644
--- a/src/components/PopoverWithoutOverlay/index.js
+++ b/src/components/PopoverWithoutOverlay/index.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import React, {useRef} from 'react';
import {View} from 'react-native';
import {SafeAreaInsetsContext} from 'react-native-safe-area-context';
import {PopoverContext} from '../PopoverProvider';
@@ -11,6 +11,7 @@ import withWindowDimensions from '../withWindowDimensions';
function Popover(props) {
const {onOpen, close} = React.useContext(PopoverContext);
+ const firstRenderRef = useRef(true);
const {modalStyle, modalContainerStyle, shouldAddTopSafeAreaMargin, shouldAddBottomSafeAreaMargin, shouldAddTopSafeAreaPadding, shouldAddBottomSafeAreaPadding} = getModalStyles(
'popover',
{
@@ -37,6 +38,13 @@ function Popover(props) {
Modal.onModalDidClose();
}
Modal.willAlertModalBecomeVisible(props.isVisible);
+
+ // We prevent setting closeModal function to null when the component is invisible the first time it is rendered
+ if (!firstRenderRef.current || !props.isVisible) {
+ firstRenderRef.current = false;
+ return;
+ }
+ firstRenderRef.current = false;
Modal.setCloseModal(props.isVisible ? () => props.onClose(props.anchorRef) : null);
// We want this effect to run strictly ONLY when isVisible prop changes
diff --git a/src/components/Pressable/GenericPressable/BaseGenericPressable.js b/src/components/Pressable/GenericPressable/BaseGenericPressable.js
index 9bb221b2de1e..79ce5629c9e9 100644
--- a/src/components/Pressable/GenericPressable/BaseGenericPressable.js
+++ b/src/components/Pressable/GenericPressable/BaseGenericPressable.js
@@ -10,6 +10,7 @@ import styles from '../../../styles/styles';
import genericPressablePropTypes from './PropTypes';
import CONST from '../../../CONST';
import * as StyleUtils from '../../../styles/StyleUtils';
+import useSingleExecution from '../../../hooks/useSingleExecution';
/**
* Returns the cursor style based on the state of Pressable
@@ -44,12 +45,12 @@ const GenericPressable = forwardRef((props, ref) => {
keyboardShortcut,
shouldUseAutoHitSlop,
enableInScreenReaderStates,
- isExecuting,
onPressIn,
onPressOut,
...rest
} = props;
+ const {isExecuting, singleExecution} = useSingleExecution();
const isScreenReaderActive = Accessibility.useScreenReaderStatus();
const [hitSlop, onLayout] = Accessibility.useAutoHitSlop();
@@ -63,8 +64,8 @@ const GenericPressable = forwardRef((props, ref) => {
shouldBeDisabledByScreenReader = isScreenReaderActive;
}
- return props.disabled || shouldBeDisabledByScreenReader;
- }, [isScreenReaderActive, enableInScreenReaderStates, props.disabled]);
+ return props.disabled || shouldBeDisabledByScreenReader || isExecuting;
+ }, [isScreenReaderActive, enableInScreenReaderStates, props.disabled, isExecuting]);
const shouldUseDisabledCursor = useMemo(() => isDisabled && !isExecuting, [isDisabled, isExecuting]);
@@ -134,7 +135,7 @@ const GenericPressable = forwardRef((props, ref) => {
hitSlop={shouldUseAutoHitSlop ? hitSlop : undefined}
onLayout={shouldUseAutoHitSlop ? onLayout : undefined}
ref={ref}
- onPress={!isDisabled ? onPressHandler : undefined}
+ onPress={!isDisabled ? singleExecution(onPressHandler) : undefined}
// In order to prevent haptic feedback, pass empty callback as onLongPress props. Please refer https://github.com/necolas/react-native-web/issues/2349#issuecomment-1195564240
onLongPress={!isDisabled && onLongPress ? onLongPressHandler : defaultLongPressHandler}
onKeyPress={!isDisabled ? onKeyPressHandler : undefined}
diff --git a/src/components/Pressable/GenericPressable/PropTypes.js b/src/components/Pressable/GenericPressable/PropTypes.js
index 690e265b6552..3933b31d2d47 100644
--- a/src/components/Pressable/GenericPressable/PropTypes.js
+++ b/src/components/Pressable/GenericPressable/PropTypes.js
@@ -45,9 +45,6 @@ const pressablePropTypes = {
*/
shouldUseHapticsOnLongPress: PropTypes.bool,
- /** Whether the button is executing */
- isExecuting: PropTypes.bool,
-
/**
* style for when the component is disabled. Can be a function that receives the component's state (active, disabled, hover, focus, pressed, isScreenReaderActive)
* @default {}
@@ -128,7 +125,6 @@ const defaultProps = {
keyboardShortcut: undefined,
shouldUseHapticsOnPress: false,
shouldUseHapticsOnLongPress: false,
- isExecuting: false,
disabledStyle: {},
hoverStyle: {},
focusStyle: {},
diff --git a/src/components/Pressable/PressableWithDelayToggle.js b/src/components/Pressable/PressableWithDelayToggle.js
index 38660e390208..b55770a63196 100644
--- a/src/components/Pressable/PressableWithDelayToggle.js
+++ b/src/components/Pressable/PressableWithDelayToggle.js
@@ -114,7 +114,7 @@ function PressableWithDelayToggle(props) {
focusable={false}
accessible={false}
onPress={updatePressState}
- style={[styles.flexRow, ...props.styles]}
+ style={[styles.flexRow, ...props.styles, !isActive && styles.cursorDefault]}
>
{({hovered, pressed}) => (
<>
diff --git a/src/components/Pressable/PressableWithFeedback.js b/src/components/Pressable/PressableWithFeedback.js
index a80e2109ebd7..07601ed35789 100644
--- a/src/components/Pressable/PressableWithFeedback.js
+++ b/src/components/Pressable/PressableWithFeedback.js
@@ -5,7 +5,6 @@ import GenericPressable from './GenericPressable';
import GenericPressablePropTypes from './GenericPressable/PropTypes';
import OpacityView from '../OpacityView';
import variables from '../../styles/variables';
-import useSingleExecution from '../../hooks/useSingleExecution';
const omittedProps = ['wrapperStyle', 'needsOffscreenAlphaCompositing'];
@@ -43,14 +42,12 @@ const PressableWithFeedbackDefaultProps = {
const PressableWithFeedback = forwardRef((props, ref) => {
const propsWithoutWrapperProps = _.omit(props, omittedProps);
- const {isExecuting, singleExecution} = useSingleExecution();
const [isPressed, setIsPressed] = useState(false);
const [isHovered, setIsHovered] = useState(false);
- const isDisabled = props.disabled || isExecuting;
return (
{
ref={ref}
// eslint-disable-next-line react/jsx-props-no-spreading
{...propsWithoutWrapperProps}
- disabled={isDisabled}
- isExecuting={isExecuting}
+ disabled={props.disabled}
onHoverIn={() => {
setIsHovered(true);
if (props.onHoverIn) {
@@ -85,9 +81,6 @@ const PressableWithFeedback = forwardRef((props, ref) => {
props.onPressOut();
}
}}
- onPress={(e) => {
- singleExecution(() => props.onPress(e))();
- }}
>
{(state) => (_.isFunction(props.children) ? props.children(state) : props.children)}
diff --git a/src/components/QRShare/index.js b/src/components/QRShare/index.js
index d96024ad1046..837adcac8efe 100644
--- a/src/components/QRShare/index.js
+++ b/src/components/QRShare/index.js
@@ -76,7 +76,6 @@ class QRShare extends Component {
{!_.isEmpty(this.props.subtitle) && (
[styles.emojiReactionBubble, styles.userSelectNone, StyleUtils.getEmojiReactionBubbleStyle(hovered || pressed, false, props.isContextMenu)]}
onPress={Session.checkIfActionIsAllowed(onPress)}
- // Prevent text input blur when Add reaction is clicked
- onMouseDown={(e) => e.preventDefault()}
+ onMouseDown={(e) => {
+ // Allow text input blur when Add reaction is right clicked
+ if (!e || e.button === 2) {
+ return;
+ }
+
+ // Prevent text input blur when Add reaction is left clicked
+ e.preventDefault();
+ }}
accessibilityLabel={props.translate('emojiReactions.addReactionTooltip')}
accessibilityRole={CONST.ACCESSIBILITY_ROLE.BUTTON}
// disable dimming
diff --git a/src/components/ReportActionItem/MoneyRequestPreview.js b/src/components/ReportActionItem/MoneyRequestPreview.js
index 35215cadd15d..b4101d9b5721 100644
--- a/src/components/ReportActionItem/MoneyRequestPreview.js
+++ b/src/components/ReportActionItem/MoneyRequestPreview.js
@@ -317,7 +317,7 @@ function MoneyRequestPreview(props) {
)}
{shouldShowDescription && {description} }
- {props.isBillSplit && !_.isEmpty(participantAccountIDs) && (
+ {props.isBillSplit && !_.isEmpty(participantAccountIDs) && requestAmount > 0 && (
{props.translate('iou.amountEach', {
amount: CurrencyUtils.convertToDisplayString(
diff --git a/src/components/ReportActionItem/TaskPreview.js b/src/components/ReportActionItem/TaskPreview.js
index 51677892652e..3499aee5f682 100644
--- a/src/components/ReportActionItem/TaskPreview.js
+++ b/src/components/ReportActionItem/TaskPreview.js
@@ -77,7 +77,9 @@ function TaskPreview(props) {
const assigneeDisplayName = lodashGet(props.personalDetailsList, [taskAssigneeAccountID, 'displayName'], '');
const taskAssignee = assigneeDisplayName || LocalePhoneNumber.formatPhoneNumber(assigneeLogin);
const htmlForTaskPreview =
- taskAssignee && taskAssigneeAccountID !== 0 ? `@${taskAssignee} ${taskTitle} ` : `${taskTitle} `;
+ taskAssignee && taskAssigneeAccountID !== 0
+ ? `@${taskAssignee} ${taskTitle} `
+ : `${taskTitle} `;
const isDeletedParentAction = ReportUtils.isCanceledTaskReport(props.taskReport, props.action);
if (isDeletedParentAction) {
diff --git a/src/components/ReportWelcomeText.js b/src/components/ReportWelcomeText.js
index 071e53de1776..7c8444a5d5b9 100644
--- a/src/components/ReportWelcomeText.js
+++ b/src/components/ReportWelcomeText.js
@@ -48,9 +48,6 @@ const propTypes = {
/** All of the personal details for everyone */
personalDetails: PropTypes.objectOf(personalDetailsPropTypes),
- /** List of betas available to current user */
- betas: PropTypes.arrayOf(PropTypes.string),
-
...withLocalizePropTypes,
};
@@ -58,7 +55,6 @@ const defaultProps = {
report: {},
policy: {},
personalDetails: {},
- betas: [],
};
function ReportWelcomeText(props) {
@@ -73,7 +69,7 @@ function ReportWelcomeText(props) {
);
const isUserPolicyAdmin = PolicyUtils.isPolicyAdmin(props.policy);
const roomWelcomeMessage = ReportUtils.getRoomWelcomeMessage(props.report, isUserPolicyAdmin);
- const moneyRequestOptions = ReportUtils.getMoneyRequestOptions(props.report, participantAccountIDs, props.betas);
+ const moneyRequestOptions = ReportUtils.getMoneyRequestOptions(props.report, participantAccountIDs);
return (
<>
@@ -137,7 +133,9 @@ function ReportWelcomeText(props) {
))}
)}
- {moneyRequestOptions.includes(CONST.IOU.MONEY_REQUEST_TYPE.REQUEST) && {props.translate('reportActionsView.usePlusButton')} }
+ {(moneyRequestOptions.includes(CONST.IOU.MONEY_REQUEST_TYPE.SEND) || moneyRequestOptions.includes(CONST.IOU.MONEY_REQUEST_TYPE.REQUEST)) && (
+ {props.translate('reportActionsView.usePlusButton')}
+ )}
>
);
@@ -150,9 +148,6 @@ ReportWelcomeText.displayName = 'ReportWelcomeText';
export default compose(
withLocalize,
withOnyx({
- betas: {
- key: ONYXKEYS.BETAS,
- },
personalDetails: {
key: ONYXKEYS.PERSONAL_DETAILS_LIST,
},
diff --git a/src/components/SelectionList/BaseListItem.js b/src/components/SelectionList/BaseListItem.js
index 8a42c84ffc67..171a58ee9fa9 100644
--- a/src/components/SelectionList/BaseListItem.js
+++ b/src/components/SelectionList/BaseListItem.js
@@ -13,7 +13,16 @@ import RadioListItem from './RadioListItem';
import OfflineWithFeedback from '../OfflineWithFeedback';
import CONST from '../../CONST';
-function BaseListItem({item, isFocused = false, isDisabled = false, showTooltip, canSelectMultiple = false, onSelectRow, onDismissError = () => {}}) {
+function BaseListItem({
+ item,
+ isFocused = false,
+ isDisabled = false,
+ showTooltip,
+ shouldPreventDefaultFocusOnSelectRow = false,
+ canSelectMultiple = false,
+ onSelectRow,
+ onDismissError = () => {},
+}) {
const isUserItem = lodashGet(item, 'icons.length', 0) > 0;
const ListItem = isUserItem ? UserListItem : RadioListItem;
@@ -32,6 +41,7 @@ function BaseListItem({item, isFocused = false, isDisabled = false, showTooltip,
hoverDimmingValue={1}
hoverStyle={styles.hoveredComponentBG}
dataSet={{[CONST.SELECTION_SCRAPER_HIDDEN_ELEMENT]: true}}
+ onMouseDown={shouldPreventDefaultFocusOnSelectRow ? (e) => e.preventDefault() : undefined}
>
{
onSelectAll();
- if (shouldShowTextInput && shouldFocusOnSelectRow && textInputRef.current) {
+ if (shouldShowTextInput && shouldPreventDefaultFocusOnSelectRow && textInputRef.current) {
textInputRef.current.focus();
}
};
@@ -299,6 +299,7 @@ function BaseSelectionList({
canSelectMultiple={canSelectMultiple}
onSelectRow={() => selectRow(item, true)}
onDismissError={onDismissError}
+ shouldPreventDefaultFocusOnSelectRow={shouldPreventDefaultFocusOnSelectRow}
/>
);
};
@@ -401,6 +402,7 @@ function BaseSelectionList({
accessibilityState={{checked: flattenedSections.allSelected}}
disabled={flattenedSections.allOptions.length === flattenedSections.disabledOptionsIndexes.length}
dataSet={{[CONST.SELECTION_SCRAPER_HIDDEN_ELEMENT]: true}}
+ onMouseDown={shouldPreventDefaultFocusOnSelectRow ? (e) => e.preventDefault() : undefined}
>
(value: T): T {
+ const ref = useRef(value);
useEffect(() => {
ref.current = value;
}, [value]);
diff --git a/src/hooks/useThrottledButtonState.js b/src/hooks/useThrottledButtonState.ts
similarity index 76%
rename from src/hooks/useThrottledButtonState.js
rename to src/hooks/useThrottledButtonState.ts
index fbf5a15e916f..c6322d063724 100644
--- a/src/hooks/useThrottledButtonState.js
+++ b/src/hooks/useThrottledButtonState.ts
@@ -1,9 +1,8 @@
import {useEffect, useState} from 'react';
-/**
- * @returns {Array}
- */
-export default function useThrottledButtonState() {
+type ThrottledButtonState = [boolean, () => void];
+
+export default function useThrottledButtonState(): ThrottledButtonState {
const [isButtonActive, setIsButtonActive] = useState(true);
useEffect(() => {
diff --git a/src/languages/en.ts b/src/languages/en.ts
index 7133ed88579e..72e183fc8561 100755
--- a/src/languages/en.ts
+++ b/src/languages/en.ts
@@ -193,6 +193,7 @@ export default {
phoneNumber: `Please enter a valid phone number, with the country code (e.g. ${CONST.EXAMPLE_PHONE_NUMBER})`,
fieldRequired: 'This field is required.',
characterLimit: ({limit}: CharacterLimitParams) => `Exceeds the maximum length of ${limit} characters`,
+ characterLimitExceedCounter: ({length, limit}) => `Character limit exceeded (${length}/${limit})`,
dateInvalid: 'Please select a valid date',
invalidCharacter: 'Invalid character',
enterMerchant: 'Enter a merchant name',
@@ -441,7 +442,7 @@ export default {
chatWithAccountManager: 'Chat with your account manager here',
sayHello: 'Say hello!',
welcomeToRoom: ({roomName}: WelcomeToRoomParams) => `Welcome to ${roomName}!`,
- usePlusButton: '\n\nYou can also use the + button below to request money or assign a task!',
+ usePlusButton: '\n\nYou can also use the + button to send money, request money, or assign a task!',
},
reportAction: {
asCopilot: 'as copilot for',
@@ -833,6 +834,7 @@ export default {
availableSpend: 'Remaining spending power',
virtualCardNumber: 'Virtual card number',
physicalCardNumber: 'Physical card number',
+ reportFraud: 'Report virtual card fraud',
cardDetails: {
cardNumber: 'Virtual card number',
expiration: 'Expiration',
@@ -842,6 +844,20 @@ export default {
copyCardNumber: 'Copy card number',
},
},
+ reportFraudPage: {
+ title: 'Report virtual card fraud',
+ description: 'If your virtual card details have been stolen or compromised, we’ll permanently deactivate your existing card and provide you with a new virtual card and number.',
+ deactivateCard: 'Deactivate card',
+ reportVirtualCardFraud: 'Report virtual card fraud',
+ },
+ activateCardPage: {
+ activateCard: 'Activate card',
+ pleaseEnterLastFour: 'Please enter the last four digits of your card.',
+ activatePhysicalCard: 'Activate physical card',
+ error: {
+ thatDidntMatch: "That didn't match the last 4 digits on your card. Please try again.",
+ },
+ },
transferAmountPage: {
transfer: ({amount}: TransferParams) => `Transfer${amount ? ` ${amount}` : ''}`,
instant: 'Instant (Debit card)',
@@ -995,7 +1011,7 @@ export default {
error: {
dateShouldBeBefore: ({dateString}: DateShouldBeBeforeParams) => `Date should be before ${dateString}.`,
dateShouldBeAfter: ({dateString}: DateShouldBeAfterParams) => `Date should be after ${dateString}.`,
- hasInvalidCharacter: 'Name can only include letters.',
+ hasInvalidCharacter: 'Name can only include Latin characters.',
incorrectZipFormat: ({zipFormat}: IncorrectZipFormatParams) => `Incorrect zip code format.${zipFormat ? ` Acceptable format: ${zipFormat}` : ''}`,
},
},
@@ -1354,6 +1370,7 @@ export default {
notAuthorized: `You do not have access to this page. Are you trying to join the workspace? Please reach out to the owner of this workspace so they can add you as a member! Something else? Reach out to ${CONST.EMAIL.CONCIERGE}`,
goToRoom: ({roomName}: GoToRoomParams) => `Go to ${roomName} room`,
workspaceAvatar: 'Workspace avatar',
+ mustBeOnlineToViewMembers: 'You must be online in order to view members of this workspace.',
},
emptyWorkspace: {
title: 'Create a new workspace',
diff --git a/src/languages/es.ts b/src/languages/es.ts
index a98ddfaff7d0..eed5c75e2269 100644
--- a/src/languages/es.ts
+++ b/src/languages/es.ts
@@ -183,6 +183,7 @@ export default {
phoneNumber: `Introduce un teléfono válido, incluyendo el código del país (p. ej. ${CONST.EXAMPLE_PHONE_NUMBER})`,
fieldRequired: 'Este campo es obligatorio.',
characterLimit: ({limit}: CharacterLimitParams) => `Supera el límite de ${limit} caracteres`,
+ characterLimitExceedCounter: ({length, limit}) => `Se superó el límite de caracteres (${length}/${limit})`,
dateInvalid: 'Por favor, selecciona una fecha válida',
invalidCharacter: 'Carácter invalido',
enterMerchant: 'Introduce un comerciante',
@@ -433,7 +434,7 @@ export default {
chatWithAccountManager: 'Chatea con tu gestor de cuenta aquí',
sayHello: '¡Saluda!',
welcomeToRoom: ({roomName}: WelcomeToRoomParams) => `¡Bienvenido a ${roomName}!`,
- usePlusButton: '\n\n¡También puedes usar el botón + de abajo para pedir dinero o asignar una tarea!',
+ usePlusButton: '\n\n¡También puedes usar el botón + de abajo para enviar dinero, pedir dinero, o asignar una tarea!',
},
reportAction: {
asCopilot: 'como copiloto de',
@@ -829,6 +830,7 @@ export default {
availableSpend: 'Capacidad de gasto restante',
virtualCardNumber: 'Número de la tarjeta virtual',
physicalCardNumber: 'Número de la tarjeta física',
+ reportFraud: 'Reportar fraude con la tarjeta virtual',
cardDetails: {
cardNumber: 'Número de tarjeta virtual',
expiration: 'Expiración',
@@ -838,6 +840,21 @@ export default {
copyCardNumber: 'Copiar número de la tarjeta',
},
},
+ reportFraudPage: {
+ title: 'Reportar fraude con la tarjeta virtual',
+ description:
+ 'Si los datos de tu tarjeta virtual han sido robados o se han visto comprometidos, desactivaremos permanentemente la tarjeta actual y le proporcionaremos una tarjeta virtual y un número nuevo.',
+ deactivateCard: 'Desactivar tarjeta',
+ reportVirtualCardFraud: 'Reportar fraude con la tarjeta virtual',
+ },
+ activateCardPage: {
+ activateCard: 'Activar tarjeta',
+ pleaseEnterLastFour: 'Introduce los cuatro últimos dígitos de la tarjeta.',
+ activatePhysicalCard: 'Activar tarjeta física',
+ error: {
+ thatDidntMatch: 'Los 4 últimos dígitos de tu tarjeta no coinciden. Por favor, inténtalo de nuevo.',
+ },
+ },
transferAmountPage: {
transfer: ({amount}: TransferParams) => `Transferir${amount ? ` ${amount}` : ''}`,
instant: 'Instante',
@@ -993,7 +1010,7 @@ export default {
dateShouldBeBefore: ({dateString}: DateShouldBeBeforeParams) => `La fecha debe ser anterior a ${dateString}.`,
dateShouldBeAfter: ({dateString}: DateShouldBeAfterParams) => `La fecha debe ser posterior a ${dateString}.`,
incorrectZipFormat: ({zipFormat}: IncorrectZipFormatParams) => `Formato de código postal incorrecto.${zipFormat ? ` Formato aceptable: ${zipFormat}` : ''}`,
- hasInvalidCharacter: 'El nombre sólo puede incluir letras.',
+ hasInvalidCharacter: 'El nombre sólo puede incluir caracteres latinos.',
},
},
resendValidationForm: {
@@ -1374,6 +1391,7 @@ export default {
notAuthorized: `No tienes acceso a esta página. ¿Estás tratando de unirte al espacio de trabajo? Comunícate con el propietario de este espacio de trabajo para que pueda añadirte como miembro. ¿Necesitas algo más? Comunícate con ${CONST.EMAIL.CONCIERGE}`,
goToRoom: ({roomName}: GoToRoomParams) => `Ir a la sala ${roomName}`,
workspaceAvatar: 'Espacio de trabajo avatar',
+ mustBeOnlineToViewMembers: 'Debes estar en línea para poder ver los miembros de este espacio de trabajo.',
},
emptyWorkspace: {
title: 'Crear un nuevo espacio de trabajo',
diff --git a/src/libs/EmojiUtils.js b/src/libs/EmojiUtils.js
index 136eee5a4116..af498831f4a4 100644
--- a/src/libs/EmojiUtils.js
+++ b/src/libs/EmojiUtils.js
@@ -278,17 +278,10 @@ function extractEmojis(text) {
}
const emojis = [];
-
- // Text can contain similar emojis as well as their skin tone variants. Create a Set to remove duplicate emojis from the search.
- const foundEmojiCodes = new Set();
-
for (let i = 0; i < parsedEmojis.length; i++) {
const character = parsedEmojis[i];
const emoji = Emojis.emojiCodeTableWithSkinTones[character];
-
- // Add the parsed emoji to the final emojis if not already present.
- if (emoji && !foundEmojiCodes.has(emoji.code)) {
- foundEmojiCodes.add(emoji.code);
+ if (emoji) {
emojis.push(emoji);
}
}
@@ -296,6 +289,24 @@ function extractEmojis(text) {
return emojis;
}
+/**
+ * Take the current emojis and the former emojis and return the emojis that were added, if we add an already existing emoji, we also return it
+ * @param {Object[]} currentEmojis The array of current emojis
+ * @param {Object[]} formerEmojis The array of former emojis
+ * @returns {Object[]} The array of added emojis
+ */
+function getAddedEmojis(currentEmojis, formerEmojis) {
+ const newEmojis = [...currentEmojis];
+ // We are removing the emojis from the newEmojis array if they were already present before.
+ formerEmojis.forEach((formerEmoji) => {
+ const indexOfAlreadyPresentEmoji = _.findIndex(newEmojis, (newEmoji) => newEmoji.code === formerEmoji.code);
+ if (indexOfAlreadyPresentEmoji >= 0) {
+ newEmojis.splice(indexOfAlreadyPresentEmoji, 1);
+ }
+ });
+ return newEmojis;
+}
+
/**
* Replace any emoji name in a text with the emoji icon.
* If we're on mobile, we also add a space after the emoji granted there's no text after it.
@@ -484,4 +495,6 @@ export {
getPreferredEmojiCode,
getUniqueEmojiCodes,
replaceAndExtractEmojis,
+ extractEmojis,
+ getAddedEmojis,
};
diff --git a/src/libs/IOUUtils.ts b/src/libs/IOUUtils.ts
index 6f6024506985..2425211d16bc 100644
--- a/src/libs/IOUUtils.ts
+++ b/src/libs/IOUUtils.ts
@@ -77,7 +77,7 @@ function isIOUReportPendingCurrencyConversion(iouReport: Report): boolean {
* Checks if the iou type is one of request, send, or split.
*/
function isValidMoneyRequestType(iouType: string): boolean {
- const moneyRequestType: string[] = [CONST.IOU.MONEY_REQUEST_TYPE.REQUEST, CONST.IOU.MONEY_REQUEST_TYPE.SPLIT];
+ const moneyRequestType: string[] = [CONST.IOU.MONEY_REQUEST_TYPE.REQUEST, CONST.IOU.MONEY_REQUEST_TYPE.SPLIT, CONST.IOU.MONEY_REQUEST_TYPE.SEND];
return moneyRequestType.includes(iouType);
}
diff --git a/src/libs/Localize/index.js b/src/libs/Localize/index.js
index db371301f43f..a26c7d4ebc10 100644
--- a/src/libs/Localize/index.js
+++ b/src/libs/Localize/index.js
@@ -2,12 +2,27 @@ import _ from 'underscore';
import lodashGet from 'lodash/get';
import Str from 'expensify-common/lib/str';
import * as RNLocalize from 'react-native-localize';
+import Onyx from 'react-native-onyx';
import Log from '../Log';
import Config from '../../CONFIG';
import translations from '../../languages/translations';
import CONST from '../../CONST';
import LocaleListener from './LocaleListener';
import BaseLocaleListener from './LocaleListener/BaseLocaleListener';
+import ONYXKEYS from '../../ONYXKEYS';
+
+// Current user mail is needed for handling missing translations
+let userEmail = '';
+Onyx.connect({
+ key: ONYXKEYS.SESSION,
+ waitForCollectionCallback: true,
+ callback: (val) => {
+ if (!val) {
+ return;
+ }
+ userEmail = val.email;
+ },
+});
// Listener when an update in Onyx happens so we use the updated locale when translating/localizing items.
LocaleListener.connect();
@@ -70,11 +85,14 @@ function translate(desiredLanguage = CONST.LOCALES.DEFAULT, phraseKey, phrasePar
return Str.result(translatedPhrase, phraseParameters);
}
- // Phrase is not found in default language, on production log an alert to server
+ // Phrase is not found in default language, on production and staging log an alert to server
// on development throw an error
- if (Config.IS_IN_PRODUCTION) {
+ if (Config.IS_IN_PRODUCTION || Config.IS_IN_STAGING) {
const phraseString = _.isArray(phraseKey) ? phraseKey.join('.') : phraseKey;
Log.alert(`${phraseString} was not found in the en locale`);
+ if (userEmail.includes(CONST.EMAIL.EXPENSIFY_EMAIL_DOMAIN)) {
+ return CONST.MISSING_TRANSLATION;
+ }
return phraseString;
}
throw new Error(`${phraseKey} was not found in the default language`);
diff --git a/src/libs/Middleware/HandleUnusedOptimisticID.ts b/src/libs/Middleware/HandleUnusedOptimisticID.ts
index a96eb4d5651b..14f7d08d1fdb 100644
--- a/src/libs/Middleware/HandleUnusedOptimisticID.ts
+++ b/src/libs/Middleware/HandleUnusedOptimisticID.ts
@@ -10,11 +10,7 @@ const handleUnusedOptimisticID: Middleware = (requestResponse, request, isFromSe
const responseOnyxData = response?.onyxData ?? [];
responseOnyxData.forEach((onyxData) => {
const key = onyxData.key;
- if (!key) {
- return;
- }
-
- if (!key.startsWith(ONYXKEYS.COLLECTION.REPORT)) {
+ if (!key?.startsWith(ONYXKEYS.COLLECTION.REPORT)) {
return;
}
diff --git a/src/libs/Middleware/SaveResponseInOnyx.js b/src/libs/Middleware/SaveResponseInOnyx.js
index c866a797877e..d8c47d4c01dd 100644
--- a/src/libs/Middleware/SaveResponseInOnyx.js
+++ b/src/libs/Middleware/SaveResponseInOnyx.js
@@ -14,50 +14,46 @@ const requestsToIgnoreLastUpdateID = ['OpenApp', 'ReconnectApp', 'GetMissingOnyx
* @returns {Promise}
*/
function SaveResponseInOnyx(requestResponse, request) {
- return requestResponse
- .then((response = {}) => {
- const onyxUpdates = response.onyxData;
-
- // Sometimes we call requests that are successfull but they don't have any response or any success/failure data to set. Let's return early since
- // we don't need to store anything here.
- if (!onyxUpdates && !request.successData && !request.failureData) {
- return Promise.resolve(response);
+ return requestResponse.then((response = {}) => {
+ const onyxUpdates = response.onyxData;
+
+ // Sometimes we call requests that are successfull but they don't have any response or any success/failure data to set. Let's return early since
+ // we don't need to store anything here.
+ if (!onyxUpdates && !request.successData && !request.failureData) {
+ return Promise.resolve(response);
+ }
+
+ // If there is an OnyxUpdate for using memory only keys, enable them
+ _.find(onyxUpdates, ({key, value}) => {
+ if (key !== ONYXKEYS.IS_USING_MEMORY_ONLY_KEYS || !value) {
+ return false;
}
- // If there is an OnyxUpdate for using memory only keys, enable them
- _.find(onyxUpdates, ({key, value}) => {
- if (key !== ONYXKEYS.IS_USING_MEMORY_ONLY_KEYS || !value) {
- return false;
- }
-
- MemoryOnlyKeys.enable();
- return true;
- });
-
- const responseToApply = {
- type: CONST.ONYX_UPDATE_TYPES.HTTPS,
- lastUpdateID: Number(response.lastUpdateID || 0),
- previousUpdateID: Number(response.previousUpdateID || 0),
- request,
- response,
- };
-
- if (_.includes(requestsToIgnoreLastUpdateID, request.command) || !OnyxUpdates.doesClientNeedToBeUpdated(Number(response.previousUpdateID || 0))) {
- return OnyxUpdates.apply(responseToApply);
- }
+ MemoryOnlyKeys.enable();
+ return true;
+ });
- // Save the update IDs to Onyx so they can be used to fetch incremental updates if the client gets out of sync from the server
- OnyxUpdates.saveUpdateInformation(responseToApply);
-
- // Ensure the queue is paused while the client resolves the gap in onyx updates so that updates are guaranteed to happen in a specific order.
- return Promise.resolve({
- ...response,
- shouldPauseQueue: true,
- });
- })
- .catch((err) => {
- console.error('Got exception while saving response in Onyx', err);
+ const responseToApply = {
+ type: CONST.ONYX_UPDATE_TYPES.HTTPS,
+ lastUpdateID: Number(response.lastUpdateID || 0),
+ previousUpdateID: Number(response.previousUpdateID || 0),
+ request,
+ response,
+ };
+
+ if (_.includes(requestsToIgnoreLastUpdateID, request.command) || !OnyxUpdates.doesClientNeedToBeUpdated(Number(response.previousUpdateID || 0))) {
+ return OnyxUpdates.apply(responseToApply);
+ }
+
+ // Save the update IDs to Onyx so they can be used to fetch incremental updates if the client gets out of sync from the server
+ OnyxUpdates.saveUpdateInformation(responseToApply);
+
+ // Ensure the queue is paused while the client resolves the gap in onyx updates so that updates are guaranteed to happen in a specific order.
+ return Promise.resolve({
+ ...response,
+ shouldPauseQueue: true,
});
+ });
}
export default SaveResponseInOnyx;
diff --git a/src/libs/Navigation/AppNavigator/ModalStackNavigators.js b/src/libs/Navigation/AppNavigator/ModalStackNavigators.js
index 6636702592c0..c32120db2e45 100644
--- a/src/libs/Navigation/AppNavigator/ModalStackNavigators.js
+++ b/src/libs/Navigation/AppNavigator/ModalStackNavigators.js
@@ -142,6 +142,8 @@ const SettingsModalStackNavigator = createModalStackNavigator({
Settings_Lounge_Access: () => require('../../../pages/settings/Profile/LoungeAccessPage').default,
Settings_Wallet: () => require('../../../pages/settings/Wallet/WalletPage').default,
Settings_Wallet_DomainCards: () => require('../../../pages/settings/Wallet/ExpensifyCardPage').default,
+ Settings_Wallet_ReportVirtualCardFraud: () => require('../../../pages/settings/Wallet/ReportVirtualCardFraudPage').default,
+ Settings_Wallet_Card_Activate: () => require('../../../pages/settings/Wallet/ActivatePhysicalCardPage').default,
Settings_Wallet_Transfer_Balance: () => require('../../../pages/settings/Wallet/TransferBalancePage').default,
Settings_Wallet_Choose_Transfer_Account: () => require('../../../pages/settings/Wallet/ChooseTransferAccountPage').default,
Settings_Wallet_EnablePayments: () => require('../../../pages/EnablePayments/EnablePaymentsPage').default,
diff --git a/src/libs/Navigation/linkingConfig.js b/src/libs/Navigation/linkingConfig.js
index bf069aba314e..5616e8d63797 100644
--- a/src/libs/Navigation/linkingConfig.js
+++ b/src/libs/Navigation/linkingConfig.js
@@ -73,6 +73,10 @@ export default {
path: ROUTES.SETTINGS_WALLET_DOMAINCARDS.route,
exact: true,
},
+ Settings_Wallet_ReportVirtualCardFraud: {
+ path: ROUTES.SETTINGS_REPORT_FRAUD.route,
+ exact: true,
+ },
Settings_Wallet_EnablePayments: {
path: ROUTES.SETTINGS_ENABLE_PAYMENTS,
exact: true,
@@ -85,6 +89,10 @@ export default {
path: ROUTES.SETTINGS_WALLET_CHOOSE_TRANSFER_ACCOUNT,
exact: true,
},
+ Settings_Wallet_Card_Activate: {
+ path: ROUTES.SETTINGS_WALLET_CARD_ACTIVATE.route,
+ exact: true,
+ },
Settings_Add_Debit_Card: {
path: ROUTES.SETTINGS_ADD_DEBIT_CARD,
exact: true,
diff --git a/src/libs/NetworkConnection.js b/src/libs/NetworkConnection.ts
similarity index 90%
rename from src/libs/NetworkConnection.js
rename to src/libs/NetworkConnection.ts
index 9ca09c9154bc..663a9c1b37d5 100644
--- a/src/libs/NetworkConnection.js
+++ b/src/libs/NetworkConnection.ts
@@ -1,6 +1,6 @@
-import _ from 'underscore';
import Onyx from 'react-native-onyx';
import NetInfo from '@react-native-community/netinfo';
+import throttle from 'lodash/throttle';
import AppStateMonitor from './AppStateMonitor';
import Log from './Log';
import * as NetworkActions from './actions/Network';
@@ -13,15 +13,17 @@ let hasPendingNetworkCheck = false;
// Holds all of the callbacks that need to be triggered when the network reconnects
let callbackID = 0;
-const reconnectionCallbacks = {};
+const reconnectionCallbacks: Record Promise> = {};
/**
* Loop over all reconnection callbacks and fire each one
*/
-const triggerReconnectionCallbacks = _.throttle(
+const triggerReconnectionCallbacks = throttle(
(reason) => {
Log.info(`[NetworkConnection] Firing reconnection callbacks because ${reason}`);
- _.each(reconnectionCallbacks, (callback) => callback());
+ Object.values(reconnectionCallbacks).forEach((callback) => {
+ callback();
+ });
},
5000,
{trailing: false},
@@ -30,10 +32,8 @@ const triggerReconnectionCallbacks = _.throttle(
/**
* Called when the offline status of the app changes and if the network is "reconnecting" (going from offline to online)
* then all of the reconnection callbacks are triggered
- *
- * @param {Boolean} isCurrentlyOffline
*/
-function setOfflineStatus(isCurrentlyOffline) {
+function setOfflineStatus(isCurrentlyOffline: boolean): void {
NetworkActions.setIsOffline(isCurrentlyOffline);
// When reconnecting, ie, going from offline to online, all the reconnection callbacks
@@ -72,7 +72,7 @@ Onyx.connect({
* internet connectivity or not. This is more reliable than the Pusher
* `disconnected` event which takes about 10-15 seconds to emit.
*/
-function subscribeToNetInfo() {
+function subscribeToNetInfo(): void {
// Note: We are disabling the configuration for NetInfo when using the local web API since requests can get stuck in a 'Pending' state and are not reliable indicators for "offline".
// If you need to test the "recheck" feature then switch to the production API proxy server.
if (!CONFIG.IS_USING_LOCAL_WEB) {
@@ -101,7 +101,7 @@ function subscribeToNetInfo() {
// Subscribe to the state change event via NetInfo so we can update
// whether a user has internet connectivity or not.
NetInfo.addEventListener((state) => {
- Log.info('[NetworkConnection] NetInfo state change', false, state);
+ Log.info('[NetworkConnection] NetInfo state change', false, {...state});
if (shouldForceOffline) {
Log.info('[NetworkConnection] Not setting offline status because shouldForceOffline = true');
return;
@@ -120,11 +120,9 @@ function listenForReconnect() {
/**
* Register callback to fire when we reconnect
- *
- * @param {Function} callback - must return a Promise
- * @returns {Function} unsubscribe method
+ * @returns unsubscribe method
*/
-function onReconnect(callback) {
+function onReconnect(callback: () => Promise): () => void {
const currentID = callbackID;
callbackID++;
reconnectionCallbacks[currentID] = callback;
@@ -135,7 +133,7 @@ function onReconnect(callback) {
* Delete all queued reconnection callbacks
*/
function clearReconnectionCallbacks() {
- _.each(_.keys(reconnectionCallbacks), (key) => delete reconnectionCallbacks[key]);
+ Object.keys(reconnectionCallbacks).forEach((key) => delete reconnectionCallbacks[key]);
}
/**
diff --git a/src/libs/Notification/LocalNotification/BrowserNotifications.js b/src/libs/Notification/LocalNotification/BrowserNotifications.js
index ca2cfc73866d..3199e4c6388d 100644
--- a/src/libs/Notification/LocalNotification/BrowserNotifications.js
+++ b/src/libs/Notification/LocalNotification/BrowserNotifications.js
@@ -111,7 +111,7 @@ export default {
const plainTextMessage = (_.find(message, (f) => f.type === 'COMMENT') || {}).text;
if (isChatRoom) {
- const roomName = _.get(report, 'displayName', '');
+ const roomName = ReportUtils.getReportName(report);
title = roomName;
body = `${plainTextPerson}: ${plainTextMessage}`;
} else {
diff --git a/src/libs/Permissions.ts b/src/libs/Permissions.ts
index 05322472a407..13489c396c3c 100644
--- a/src/libs/Permissions.ts
+++ b/src/libs/Permissions.ts
@@ -17,13 +17,6 @@ function canUseDefaultRooms(betas: Beta[]): boolean {
return betas?.includes(CONST.BETAS.DEFAULT_ROOMS) || canUseAllBetas(betas);
}
-/**
- * IOU Send feature is temporarily disabled.
- */
-function canUseIOUSend(): boolean {
- return false;
-}
-
function canUseWallet(betas: Beta[]): boolean {
return betas?.includes(CONST.BETAS.BETA_EXPENSIFY_WALLET) || canUseAllBetas(betas);
}
@@ -68,7 +61,6 @@ export default {
canUseChronos,
canUsePayWithExpensify,
canUseDefaultRooms,
- canUseIOUSend,
canUseWallet,
canUseCommentLinking,
canUsePolicyRooms,
diff --git a/src/libs/ReportUtils.js b/src/libs/ReportUtils.js
index 3508d99c2ae0..79f052bd21b4 100644
--- a/src/libs/ReportUtils.js
+++ b/src/libs/ReportUtils.js
@@ -1901,15 +1901,11 @@ function getParentNavigationSubtitle(report) {
function navigateToDetailsPage(report) {
const participantAccountIDs = lodashGet(report, 'participantAccountIDs', []);
- if (isChatRoom(report) || isPolicyExpenseChat(report) || isChatThread(report) || isTaskReport(report) || isMoneyRequestReport(report)) {
- Navigation.navigate(ROUTES.REPORT_WITH_ID_DETAILS.getRoute(report.reportID));
- return;
- }
- if (participantAccountIDs.length === 1) {
+ if (isDM(report) && participantAccountIDs.length === 1) {
Navigation.navigate(ROUTES.PROFILE.getRoute(participantAccountIDs[0]));
return;
}
- Navigation.navigate(ROUTES.REPORT_PARTICIPANTS.getRoute(report.reportID));
+ Navigation.navigate(ROUTES.REPORT_WITH_ID_DETAILS.getRoute(report.reportID));
}
/**
@@ -2203,6 +2199,9 @@ function getIOUReportActionMessage(iouReportID, type, total, comment, currency,
case CONST.REPORT.ACTIONS.TYPE.APPROVED:
iouMessage = `approved ${amount}`;
break;
+ case CONST.REPORT.ACTIONS.TYPE.SUBMITTED:
+ iouMessage = `submitted ${amount}`;
+ break;
case CONST.IOU.REPORT_ACTION_TYPE.CREATE:
iouMessage = `requested ${amount}${comment && ` for ${comment}`}`;
break;
@@ -2360,6 +2359,44 @@ function buildOptimisticApprovedReportAction(amount, currency, expenseReportID)
};
}
+/**
+ * Builds an optimistic SUBMITTED report action with a randomly generated reportActionID.
+ *
+ * @param {Number} amount
+ * @param {String} currency
+ * @param {Number} expenseReportID
+ *
+ * @returns {Object}
+ */
+function buildOptimisticSubmittedReportAction(amount, currency, expenseReportID) {
+ const originalMessage = {
+ amount,
+ currency,
+ expenseReportID,
+ };
+
+ return {
+ actionName: CONST.REPORT.ACTIONS.TYPE.SUBMITTED,
+ actorAccountID: currentUserAccountID,
+ automatic: false,
+ avatar: lodashGet(currentUserPersonalDetails, 'avatar', UserUtils.getDefaultAvatar(currentUserAccountID)),
+ isAttachment: false,
+ originalMessage,
+ message: getIOUReportActionMessage(expenseReportID, CONST.REPORT.ACTIONS.TYPE.SUBMITTED, Math.abs(amount), '', currency),
+ person: [
+ {
+ style: 'strong',
+ text: lodashGet(currentUserPersonalDetails, 'displayName', currentUserEmail),
+ type: 'TEXT',
+ },
+ ],
+ reportActionID: NumberUtils.rand64(),
+ shouldShow: true,
+ created: DateUtils.getDBTime(),
+ pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD,
+ };
+}
+
/**
* Builds an optimistic report preview action with a randomly generated reportActionID.
*
@@ -3327,10 +3364,9 @@ function canRequestMoney(report, participants) {
*
* @param {Object} report
* @param {Array} reportParticipants
- * @param {Array} betas
* @returns {Array}
*/
-function getMoneyRequestOptions(report, reportParticipants, betas) {
+function getMoneyRequestOptions(report, reportParticipants) {
// In any thread or task report, we do not allow any new money requests yet
if (isChatThread(report) || isTaskReport(report)) {
return [];
@@ -3362,7 +3398,7 @@ function getMoneyRequestOptions(report, reportParticipants, betas) {
...(canRequestMoney(report, participants) ? [CONST.IOU.MONEY_REQUEST_TYPE.REQUEST] : []),
// Send money option should be visible only in DMs
- ...(Permissions.canUseIOUSend(betas) && isChatReport(report) && !isPolicyExpenseChat(report) && hasSingleParticipantInReport ? [CONST.IOU.MONEY_REQUEST_TYPE.SEND] : []),
+ ...(isChatReport(report) && !isPolicyExpenseChat(report) && hasSingleParticipantInReport ? [CONST.IOU.MONEY_REQUEST_TYPE.SEND] : []),
];
}
@@ -3540,12 +3576,13 @@ function getPolicyExpenseChatReportIDByOwner(policyOwner) {
return expenseChat.reportID;
}
-/*
- * @param {Object|null} report
- * @returns {Boolean}
+/**
+ * @param {String} policyID
+ * @param {Array} accountIDs
+ * @returns {Array}
*/
-function shouldDisableSettings(report) {
- return !isMoneyRequestReport(report) && !isPolicyExpenseChat(report) && !isChatRoom(report) && !isChatThread(report);
+function getWorkspaceChats(policyID, accountIDs) {
+ return _.filter(allReports, (report) => isPolicyExpenseChat(report) && lodashGet(report, 'policyID', '') === policyID && _.contains(accountIDs, lodashGet(report, 'ownerAccountID', '')));
}
/**
@@ -3798,7 +3835,7 @@ function useRouteChangeHandler(reportID = '', reportActionID = '', triggerFetch
* @returns {Boolean}
*/
function isReportDraft(report) {
- return lodashGet(report, 'stateNum') === CONST.REPORT.STATE_NUM.OPEN && lodashGet(report, 'statusNum') === CONST.REPORT.STATUS.OPEN;
+ return isExpenseReport(report) && lodashGet(report, 'stateNum') === CONST.REPORT.STATE_NUM.OPEN && lodashGet(report, 'statusNum') === CONST.REPORT.STATUS.OPEN;
}
export {
@@ -3861,6 +3898,7 @@ export {
buildOptimisticEditedTaskReportAction,
buildOptimisticIOUReport,
buildOptimisticApprovedReportAction,
+ buildOptimisticSubmittedReportAction,
buildOptimisticExpenseReport,
buildOptimisticIOUReportAction,
buildOptimisticReportPreview,
@@ -3927,7 +3965,7 @@ export {
isDM,
getPolicy,
getPolicyExpenseChatReportIDByOwner,
- shouldDisableSettings,
+ getWorkspaceChats,
shouldDisableRename,
hasSingleParticipant,
getReportRecipientAccountIDs,
diff --git a/src/libs/__mocks__/Permissions.ts b/src/libs/__mocks__/Permissions.ts
index 2c062590573e..66ef64bbb994 100644
--- a/src/libs/__mocks__/Permissions.ts
+++ b/src/libs/__mocks__/Permissions.ts
@@ -12,6 +12,5 @@ export default {
...jest.requireActual('../Permissions'),
canUseDefaultRooms: (betas: Beta[]) => betas.includes(CONST.BETAS.DEFAULT_ROOMS),
canUsePolicyRooms: (betas: Beta[]) => betas.includes(CONST.BETAS.POLICY_ROOMS),
- canUseIOUSend: (betas: Beta[]) => betas.includes(CONST.BETAS.IOU_SEND),
canUseCustomStatus: (betas: Beta[]) => betas.includes(CONST.BETAS.CUSTOM_STATUS),
};
diff --git a/src/libs/actions/CanvasSize.js b/src/libs/actions/CanvasSize.js
index ed83562a3e43..0c4cd88fea70 100644
--- a/src/libs/actions/CanvasSize.js
+++ b/src/libs/actions/CanvasSize.js
@@ -1,16 +1,25 @@
import Onyx from 'react-native-onyx';
import canvasSize from 'canvas-size';
import ONYXKEYS from '../../ONYXKEYS';
+import * as Browser from '../Browser';
/**
* Calculate the max area of canvas on this specific platform and save it in onyx
*/
function retrieveMaxCanvasArea() {
- canvasSize.maxArea({
- onSuccess: (width, height) => {
- Onyx.merge(ONYXKEYS.MAX_CANVAS_AREA, width * height);
- },
- });
+ // We're limiting the maximum value on mobile web to prevent a crash related to rendering large canvas elements.
+ // More information at: https://github.com/jhildenbiddle/canvas-size/issues/13
+ canvasSize
+ .maxArea({
+ max: Browser.isMobile() ? 8192 : null,
+ usePromise: true,
+ useWorker: false,
+ })
+ .then(() => ({
+ onSuccess: (width, height) => {
+ Onyx.merge(ONYXKEYS.MAX_CANVAS_AREA, width * height);
+ },
+ }));
}
/**
diff --git a/src/libs/actions/Card.js b/src/libs/actions/Card.js
new file mode 100644
index 000000000000..a060c1bc67fa
--- /dev/null
+++ b/src/libs/actions/Card.js
@@ -0,0 +1,104 @@
+import Onyx from 'react-native-onyx';
+import ONYXKEYS from '../../ONYXKEYS';
+import * as API from '../API';
+
+/**
+ * @param {Number} cardID
+ */
+function reportVirtualExpensifyCardFraud(cardID) {
+ API.write(
+ 'ReportVirtualExpensifyCardFraud',
+ {
+ cardID,
+ },
+ {
+ optimisticData: [
+ {
+ onyxMethod: Onyx.METHOD.MERGE,
+ key: ONYXKEYS.FORMS.REPORT_VIRTUAL_CARD_FRAUD,
+ value: {
+ isLoading: true,
+ },
+ },
+ ],
+ successData: [
+ {
+ onyxMethod: Onyx.METHOD.MERGE,
+ key: ONYXKEYS.FORMS.REPORT_VIRTUAL_CARD_FRAUD,
+ value: {
+ isLoading: false,
+ },
+ },
+ ],
+ failureData: [
+ {
+ onyxMethod: Onyx.METHOD.MERGE,
+ key: ONYXKEYS.FORMS.REPORT_VIRTUAL_CARD_FRAUD,
+ value: {
+ isLoading: false,
+ },
+ },
+ ],
+ },
+ );
+}
+
+/**
+ * Activates the physical Expensify card based on the last four digits of the card number
+ *
+ * @param {Number} lastFourDigits
+ * @param {Number} cardID
+ */
+function activatePhysicalExpensifyCard(lastFourDigits, cardID) {
+ API.write(
+ 'ActivatePhysicalExpensifyCard',
+ {lastFourDigits, cardID},
+ {
+ optimisticData: [
+ {
+ onyxMethod: Onyx.METHOD.MERGE,
+ key: ONYXKEYS.CARD_LIST,
+ value: {
+ [cardID]: {
+ errors: null,
+ isLoading: true,
+ },
+ },
+ },
+ ],
+ successData: [
+ {
+ onyxMethod: Onyx.METHOD.MERGE,
+ key: ONYXKEYS.CARD_LIST,
+ value: {
+ [cardID]: {
+ isLoading: false,
+ },
+ },
+ },
+ ],
+ failureData: [
+ {
+ onyxMethod: Onyx.METHOD.MERGE,
+ key: ONYXKEYS.CARD_LIST,
+ value: {
+ [cardID]: {
+ isLoading: false,
+ },
+ },
+ },
+ ],
+ },
+ );
+}
+
+/**
+ * Clears errors for a specific cardID
+ *
+ * @param {Number} cardID
+ */
+function clearCardListErrors(cardID) {
+ Onyx.merge(ONYXKEYS.CARD_LIST, {[cardID]: {errors: null, isLoading: false}});
+}
+
+export {reportVirtualExpensifyCardFraud, activatePhysicalExpensifyCard, clearCardListErrors};
diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js
index 07f61470f24d..d5676672dd33 100644
--- a/src/libs/actions/IOU.js
+++ b/src/libs/actions/IOU.js
@@ -22,6 +22,15 @@ import * as Report from './Report';
import * as NumberUtils from '../NumberUtils';
import ReceiptGeneric from '../../../assets/images/receipt-generic.png';
import * as LocalePhoneNumber from '../LocalePhoneNumber';
+import * as Policy from './Policy';
+
+let allPersonalDetails;
+Onyx.connect({
+ key: ONYXKEYS.PERSONAL_DETAILS_LIST,
+ callback: (val) => {
+ allPersonalDetails = val || {};
+ },
+});
let allReports;
Onyx.connect({
@@ -44,13 +53,6 @@ Onyx.connect({
},
});
-let allRecentlyUsedCategories = {};
-Onyx.connect({
- key: ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_CATEGORIES,
- waitForCollectionCallback: true,
- callback: (val) => (allRecentlyUsedCategories = val),
-});
-
let allRecentlyUsedTags = {};
Onyx.connect({
key: ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_TAGS,
@@ -122,7 +124,7 @@ function resetMoneyRequestInfo(id = '') {
tag: '',
created,
receiptPath: '',
- receiptSource: '',
+ receiptFilename: '',
transactionID: '',
billable: null,
});
@@ -137,7 +139,7 @@ function buildOnyxDataForMoneyRequest(
iouAction,
optimisticPersonalDetailListAction,
reportPreviewAction,
- optimisticRecentlyUsedCategories,
+ optimisticPolicyRecentlyUsedCategories,
optimisticPolicyRecentlyUsedTags,
isNewChatReport,
isNewIOUReport,
@@ -189,11 +191,11 @@ function buildOnyxDataForMoneyRequest(
},
];
- if (!_.isEmpty(optimisticRecentlyUsedCategories)) {
+ if (!_.isEmpty(optimisticPolicyRecentlyUsedCategories)) {
optimisticData.push({
onyxMethod: Onyx.METHOD.SET,
key: `${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_CATEGORIES}${iouReport.policyID}`,
- value: optimisticRecentlyUsedCategories,
+ value: optimisticPolicyRecentlyUsedCategories,
});
}
@@ -478,13 +480,10 @@ function getMoneyRequestInformation(
billable,
);
- const uniquePolicyRecentlyUsedCategories = allRecentlyUsedCategories
- ? _.filter(
- allRecentlyUsedCategories[`${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_CATEGORIES}${iouReport.policyID}`],
- (recentlyUsedPolicyCategory) => recentlyUsedPolicyCategory !== category,
- )
- : [];
- const optimisticPolicyRecentlyUsedCategories = [category, ...uniquePolicyRecentlyUsedCategories];
+ let optimisticPolicyRecentlyUsedCategories = [];
+ if (category) {
+ optimisticPolicyRecentlyUsedCategories = Policy.buildOptimisticPolicyRecentlyUsedCategories(iouReport.policyID, category);
+ }
const optimisticPolicyRecentlyUsedTags = {};
const policyTags = allPolicyTags[`${ONYXKEYS.COLLECTION.POLICY_TAGS}${iouReport.policyID}`];
@@ -882,11 +881,12 @@ function requestMoney(
* @param {Number} amount - always in the smallest unit of the currency
* @param {String} comment
* @param {String} currency
+ * @param {String} category
* @param {String} existingSplitChatReportID - the report ID where the split bill happens, could be a group chat or a workspace chat
*
* @return {Object}
*/
-function createSplitsAndOnyxData(participants, currentUserLogin, currentUserAccountID, amount, comment, currency, existingSplitChatReportID = '') {
+function createSplitsAndOnyxData(participants, currentUserLogin, currentUserAccountID, amount, comment, currency, category, existingSplitChatReportID = '') {
const currentUserEmailForIOUSplit = OptionsListUtils.addSMSDomainIfPhoneNumber(currentUserLogin);
const participantAccountIDs = _.map(participants, (participant) => Number(participant.accountID));
const existingSplitChatReport =
@@ -910,6 +910,10 @@ function createSplitsAndOnyxData(participants, currentUserLogin, currentUserAcco
'',
'',
`${Localize.translateLocal('iou.splitBill')} ${Localize.translateLocal('common.with')} ${formattedParticipants} [${DateUtils.getDBTime().slice(0, 10)}]`,
+ undefined,
+ undefined,
+ undefined,
+ category,
);
// Note: The created action must be optimistically generated before the IOU action so there's no chance that the created action appears after the IOU action in the chat
@@ -1036,9 +1040,12 @@ function createSplitsAndOnyxData(participants, currentUserLogin, currentUserAcco
const hasMultipleParticipants = participants.length > 1;
_.each(participants, (participant) => {
- // In case the participant is a worskapce, email & accountID should remain undefined and won't be used in the rest of this code
- const email = isOwnPolicyExpenseChat ? '' : OptionsListUtils.addSMSDomainIfPhoneNumber(participant.login).toLowerCase();
- const accountID = isOwnPolicyExpenseChat ? 0 : Number(participant.accountID);
+ // In a case when a participant is a workspace, even when a current user is not an owner of the workspace
+ const isPolicyExpenseChat = ReportUtils.isPolicyExpenseChat(participant);
+
+ // In case the participant is a workspace, email & accountID should remain undefined and won't be used in the rest of this code
+ const email = isOwnPolicyExpenseChat || isPolicyExpenseChat ? '' : OptionsListUtils.addSMSDomainIfPhoneNumber(participant.login).toLowerCase();
+ const accountID = isOwnPolicyExpenseChat || isPolicyExpenseChat ? 0 : Number(participant.accountID);
if (email === currentUserEmailForIOUSplit) {
return;
}
@@ -1090,6 +1097,11 @@ function createSplitsAndOnyxData(participants, currentUserLogin, currentUserAcco
'',
CONST.IOU.MONEY_REQUEST_TYPE.SPLIT,
splitTransaction.transactionID,
+ undefined,
+ undefined,
+ undefined,
+ undefined,
+ category,
);
// STEP 4: Build optimistic reportActions. We need:
@@ -1131,6 +1143,12 @@ function createSplitsAndOnyxData(participants, currentUserLogin, currentUserAcco
oneOnOneReportPreviewAction = ReportUtils.buildOptimisticReportPreview(oneOnOneChatReport, oneOnOneIOUReport);
}
+ // Add category to optimistic policy recently used categories when a participant is a workspace
+ let optimisticPolicyRecentlyUsedCategories = [];
+ if (isPolicyExpenseChat) {
+ optimisticPolicyRecentlyUsedCategories = Policy.buildOptimisticPolicyRecentlyUsedCategories(participant.policyID, category);
+ }
+
// STEP 5: Build Onyx Data
const [oneOnOneOptimisticData, oneOnOneSuccessData, oneOnOneFailureData] = buildOnyxDataForMoneyRequest(
oneOnOneChatReport,
@@ -1141,7 +1159,7 @@ function createSplitsAndOnyxData(participants, currentUserLogin, currentUserAcco
oneOnOneIOUAction,
oneOnOnePersonalDetailListAction,
oneOnOneReportPreviewAction,
- [],
+ optimisticPolicyRecentlyUsedCategories,
{},
isNewOneOnOneChatReport,
shouldCreateNewOneOnOneIOUReport,
@@ -1191,11 +1209,11 @@ function createSplitsAndOnyxData(participants, currentUserLogin, currentUserAcco
* @param {Number} amount - always in smallest currency unit
* @param {String} comment
* @param {String} currency
+ * @param {String} category
* @param {String} existingSplitChatReportID - Either a group DM or a workspace chat
*/
-function splitBill(participants, currentUserLogin, currentUserAccountID, amount, comment, currency, existingSplitChatReportID = '') {
- const {splitData, splits, onyxData} = createSplitsAndOnyxData(participants, currentUserLogin, currentUserAccountID, amount, comment, currency, existingSplitChatReportID);
-
+function splitBill(participants, currentUserLogin, currentUserAccountID, amount, comment, currency, category, existingSplitChatReportID = '') {
+ const {splitData, splits, onyxData} = createSplitsAndOnyxData(participants, currentUserLogin, currentUserAccountID, amount, comment, currency, category, existingSplitChatReportID);
API.write(
'SplitBill',
{
@@ -1204,6 +1222,7 @@ function splitBill(participants, currentUserLogin, currentUserAccountID, amount,
splits: JSON.stringify(splits),
currency,
comment,
+ category,
transactionID: splitData.transactionID,
reportActionID: splitData.reportActionID,
createdReportActionID: splitData.createdReportActionID,
@@ -1224,9 +1243,10 @@ function splitBill(participants, currentUserLogin, currentUserAccountID, amount,
* @param {Number} amount - always in smallest currency unit
* @param {String} comment
* @param {String} currency
+ * @param {String} category
*/
-function splitBillAndOpenReport(participants, currentUserLogin, currentUserAccountID, amount, comment, currency) {
- const {splitData, splits, onyxData} = createSplitsAndOnyxData(participants, currentUserLogin, currentUserAccountID, amount, comment, currency);
+function splitBillAndOpenReport(participants, currentUserLogin, currentUserAccountID, amount, comment, currency, category) {
+ const {splitData, splits, onyxData} = createSplitsAndOnyxData(participants, currentUserLogin, currentUserAccountID, amount, comment, currency, category);
API.write(
'SplitBillAndOpenReport',
@@ -1236,6 +1256,7 @@ function splitBillAndOpenReport(participants, currentUserLogin, currentUserAccou
splits: JSON.stringify(splits),
currency,
comment,
+ category,
transactionID: splitData.transactionID,
reportActionID: splitData.reportActionID,
createdReportActionID: splitData.createdReportActionID,
@@ -1249,6 +1270,225 @@ function splitBillAndOpenReport(participants, currentUserLogin, currentUserAccou
Report.notifyNewAction(splitData.chatReportID, currentUserAccountID);
}
+/** Used exclusively for starting a split bill request that contains a receipt, the split request will be completed once the receipt is scanned
+ * or user enters details manually.
+ *
+ * @param {Array} participants
+ * @param {String} currentUserLogin
+ * @param {Number} currentUserAccountID
+ * @param {String} comment
+ * @param {Object} receipt
+ * @param {String} existingSplitChatReportID - Either a group DM or a workspace chat
+ */
+function startSplitBill(participants, currentUserLogin, currentUserAccountID, comment, receipt, existingSplitChatReportID = '') {
+ const currentUserEmailForIOUSplit = OptionsListUtils.addSMSDomainIfPhoneNumber(currentUserLogin);
+ const participantAccountIDs = _.map(participants, (participant) => Number(participant.accountID));
+ const existingSplitChatReport =
+ existingSplitChatReportID || participants[0].reportID
+ ? allReports[`${ONYXKEYS.COLLECTION.REPORT}${existingSplitChatReportID || participants[0].reportID}`]
+ : ReportUtils.getChatByParticipants(participantAccountIDs);
+ const splitChatReport = existingSplitChatReport || ReportUtils.buildOptimisticChatReport(participantAccountIDs);
+ const isOwnPolicyExpenseChat = splitChatReport.isOwnPolicyExpenseChat || false;
+
+ const {name: filename, source, state = CONST.IOU.RECEIPT_STATE.SCANREADY} = receipt;
+ const receiptObject = {state, source};
+
+ // ReportID is -2 (aka "deleted") on the group transaction
+ const splitTransaction = TransactionUtils.buildOptimisticTransaction(0, CONST.CURRENCY.USD, CONST.REPORT.SPLIT_REPORTID, comment, '', '', '', '', receiptObject, filename);
+
+ // Note: The created action must be optimistically generated before the IOU action so there's no chance that the created action appears after the IOU action in the chat
+ const splitChatCreatedReportAction = ReportUtils.buildOptimisticCreatedReportAction(currentUserEmailForIOUSplit);
+ const splitIOUReportAction = ReportUtils.buildOptimisticIOUReportAction(
+ CONST.IOU.REPORT_ACTION_TYPE.SPLIT,
+ 0,
+ CONST.CURRENCY.USD,
+ comment,
+ participants,
+ splitTransaction.transactionID,
+ '',
+ '',
+ false,
+ false,
+ receiptObject,
+ isOwnPolicyExpenseChat,
+ );
+
+ splitChatReport.lastReadTime = DateUtils.getDBTime();
+ splitChatReport.lastMessageText = splitIOUReportAction.message[0].text;
+ splitChatReport.lastMessageHtml = splitIOUReportAction.message[0].html;
+
+ // If we have an existing splitChatReport (group chat or workspace) use it's pending fields, otherwise indicate that we are adding a chat
+ if (!existingSplitChatReport) {
+ splitChatReport.pendingFields = {
+ createChat: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD,
+ };
+ }
+
+ const optimisticData = [
+ {
+ // Use set for new reports because it doesn't exist yet, is faster,
+ // and we need the data to be available when we navigate to the chat page
+ onyxMethod: existingSplitChatReport ? Onyx.METHOD.MERGE : Onyx.METHOD.SET,
+ key: `${ONYXKEYS.COLLECTION.REPORT}${splitChatReport.reportID}`,
+ value: splitChatReport,
+ },
+ {
+ onyxMethod: existingSplitChatReport ? Onyx.METHOD.MERGE : Onyx.METHOD.SET,
+ key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${splitChatReport.reportID}`,
+ value: {
+ ...(existingSplitChatReport ? {} : {[splitChatCreatedReportAction.reportActionID]: splitChatCreatedReportAction}),
+ [splitIOUReportAction.reportActionID]: splitIOUReportAction,
+ },
+ },
+ {
+ onyxMethod: Onyx.METHOD.SET,
+ key: `${ONYXKEYS.COLLECTION.TRANSACTION}${splitTransaction.transactionID}`,
+ value: splitTransaction,
+ },
+ ];
+
+ const successData = [
+ {
+ onyxMethod: Onyx.METHOD.MERGE,
+ key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${splitChatReport.reportID}`,
+ value: {
+ ...(existingSplitChatReport ? {} : {[splitChatCreatedReportAction.reportActionID]: {pendingAction: null}}),
+ [splitIOUReportAction.reportActionID]: {pendingAction: null},
+ },
+ },
+ {
+ onyxMethod: Onyx.METHOD.MERGE,
+ key: `${ONYXKEYS.COLLECTION.TRANSACTION}${splitTransaction.transactionID}`,
+ value: {pendingAction: null},
+ },
+ ];
+
+ if (!existingSplitChatReport) {
+ successData.push({
+ onyxMethod: Onyx.METHOD.MERGE,
+ key: `${ONYXKEYS.COLLECTION.REPORT}${splitChatReport.reportID}`,
+ value: {pendingFields: {createChat: null}},
+ });
+ }
+
+ const failureData = [
+ {
+ onyxMethod: Onyx.METHOD.MERGE,
+ key: `${ONYXKEYS.COLLECTION.TRANSACTION}${splitTransaction.transactionID}`,
+ value: {
+ errors: ErrorUtils.getMicroSecondOnyxError('iou.error.genericCreateFailureMessage'),
+ },
+ },
+ ];
+
+ if (existingSplitChatReport) {
+ failureData.push({
+ onyxMethod: Onyx.METHOD.MERGE,
+ key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${splitChatReport.reportID}`,
+ value: {
+ [splitIOUReportAction.reportActionID]: {
+ errors: ErrorUtils.getMicroSecondOnyxError('iou.error.genericCreateFailureMessage'),
+ },
+ },
+ });
+ } else {
+ failureData.push(
+ {
+ onyxMethod: Onyx.METHOD.MERGE,
+ key: `${ONYXKEYS.COLLECTION.REPORT}${splitChatReport.reportID}`,
+ value: {
+ errorFields: {
+ createChat: ErrorUtils.getMicroSecondOnyxError('report.genericCreateReportFailureMessage'),
+ },
+ },
+ },
+ {
+ onyxMethod: Onyx.METHOD.MERGE,
+ key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${splitChatReport.reportID}`,
+ value: {
+ [splitChatCreatedReportAction.reportActionID]: {
+ errors: ErrorUtils.getMicroSecondOnyxError('report.genericCreateReportFailureMessage'),
+ },
+ [splitIOUReportAction.reportActionID]: {
+ errors: ErrorUtils.getMicroSecondOnyxError('report.genericCreateFailureMessage'),
+ },
+ },
+ },
+ );
+ }
+
+ const splits = [{email: currentUserEmailForIOUSplit, accountID: currentUserAccountID}];
+
+ _.each(participants, (participant) => {
+ const email = participant.isOwnPolicyExpenseChat ? '' : OptionsListUtils.addSMSDomainIfPhoneNumber(participant.login || participant.text).toLowerCase();
+ const accountID = participant.isOwnPolicyExpenseChat ? 0 : Number(participant.accountID);
+ if (email === currentUserEmailForIOUSplit) {
+ return;
+ }
+
+ // When splitting with a workspace chat, we only need to supply the policyID and the workspace reportID as it's needed so we can update the report preview
+ if (participant.isOwnPolicyExpenseChat) {
+ splits.push({
+ policyID: participant.policyID,
+ chatReportID: splitChatReport.reportID,
+ });
+ return;
+ }
+
+ const participantPersonalDetails = allPersonalDetails[participant.accountID];
+ if (!participantPersonalDetails) {
+ optimisticData.push({
+ onyxMethod: Onyx.METHOD.MERGE,
+ key: ONYXKEYS.PERSONAL_DETAILS_LIST,
+ value: {
+ [accountID]: {
+ accountID,
+ avatar: UserUtils.getDefaultAvatarURL(accountID),
+ displayName: LocalePhoneNumber.formatPhoneNumber(participant.displayName || email),
+ login: participant.login || participant.text,
+ isOptimisticPersonalDetail: true,
+ },
+ },
+ });
+ }
+
+ splits.push({
+ email,
+ accountID,
+ });
+ });
+
+ // Save the new splits array into the transaction's comment in case the user calls CompleteSplitBill while offline
+ optimisticData.push({
+ onyxMethod: Onyx.METHOD.MERGE,
+ key: `${ONYXKEYS.COLLECTION.TRANSACTION}${splitTransaction.transactionID}`,
+ value: {
+ comment: {
+ splits,
+ },
+ },
+ });
+
+ API.write(
+ 'StartSplitBill',
+ {
+ chatReportID: splitChatReport.reportID,
+ reportActionID: splitIOUReportAction.reportActionID,
+ transactionID: splitTransaction.transactionID,
+ splits: JSON.stringify(splits),
+ receipt,
+ comment,
+ isFromGroupDM: !existingSplitChatReport,
+ ...(existingSplitChatReport ? {} : {createdReportActionID: splitChatCreatedReportAction.reportActionID}),
+ },
+ {optimisticData, successData, failureData},
+ );
+
+ resetMoneyRequestInfo();
+ Navigation.dismissModal(splitChatReport.reportID);
+ Report.notifyNewAction(splitChatReport.chatReportID, currentUserAccountID);
+}
+
/**
* @param {String} transactionID
* @param {Number} transactionThreadReportID
@@ -2096,6 +2336,80 @@ function approveMoneyRequest(expenseReport) {
API.write('ApproveMoneyRequest', {reportID: expenseReport.reportID, approvedReportActionID: optimisticApprovedReportAction.reportActionID}, {optimisticData, successData, failureData});
}
+/**
+ * @param {Object} expenseReport
+ */
+function submitReport(expenseReport) {
+ const optimisticSubmittedReportAction = ReportUtils.buildOptimisticSubmittedReportAction(expenseReport.total, expenseReport.currency, expenseReport.reportID);
+
+ const optimisticReportActionsData = {
+ onyxMethod: Onyx.METHOD.MERGE,
+ key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${expenseReport.reportID}`,
+ value: {
+ [optimisticSubmittedReportAction.reportActionID]: {
+ ...optimisticSubmittedReportAction,
+ pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.ADD,
+ },
+ },
+ };
+ const optimisticIOUReportData = {
+ onyxMethod: Onyx.METHOD.MERGE,
+ key: `${ONYXKEYS.COLLECTION.REPORT}${expenseReport.reportID}`,
+ value: {
+ ...expenseReport,
+ lastMessageText: optimisticSubmittedReportAction.message[0].text,
+ lastMessageHtml: optimisticSubmittedReportAction.message[0].html,
+ state: CONST.REPORT.STATE.SUBMITTED,
+ stateNum: CONST.REPORT.STATE_NUM.PROCESSING,
+ statusNum: CONST.REPORT.STATUS.SUBMITTED,
+ },
+ };
+ const optimisticData = [optimisticIOUReportData, optimisticReportActionsData];
+
+ const successData = [
+ {
+ onyxMethod: Onyx.METHOD.MERGE,
+ key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${expenseReport.reportID}`,
+ value: {
+ [optimisticSubmittedReportAction.reportActionID]: {
+ pendingAction: null,
+ },
+ },
+ },
+ ];
+
+ const failureData = [
+ {
+ onyxMethod: Onyx.METHOD.MERGE,
+ key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${expenseReport.reportID}`,
+ value: {
+ [expenseReport.reportActionID]: {
+ errors: ErrorUtils.getMicroSecondOnyxError('iou.error.other'),
+ },
+ },
+ },
+ {
+ onyxMethod: Onyx.METHOD.MERGE,
+ key: `${ONYXKEYS.COLLECTION.REPORT}${expenseReport.reportID}`,
+ value: {
+ state: CONST.REPORT.STATE.OPEN,
+ stateNum: CONST.REPORT.STATE_NUM.OPEN,
+ },
+ },
+ ];
+
+ API.write(
+ 'SubmitReport',
+ {
+ reportID: expenseReport.reportID,
+ managerEmail: expenseReport.managerEmail,
+ managerAccountID: expenseReport.managerID,
+ reportActionID: optimisticSubmittedReportAction.reportActionID,
+ },
+ {optimisticData, successData, failureData},
+ );
+}
+
/**
* @param {String} paymentType
* @param {Object} chatReport
@@ -2244,10 +2558,10 @@ function setMoneyRequestParticipants(participants) {
/**
* @param {String} receiptPath
- * @param {String} receiptSource
+ * @param {String} receiptFilename
*/
-function setMoneyRequestReceipt(receiptPath, receiptSource) {
- Onyx.merge(ONYXKEYS.IOU, {receiptPath, receiptSource, merchant: ''});
+function setMoneyRequestReceipt(receiptPath, receiptFilename) {
+ Onyx.merge(ONYXKEYS.IOU, {receiptPath, receiptFilename, merchant: ''});
}
function createEmptyTransaction() {
@@ -2302,8 +2616,19 @@ function navigateToNextPage(iou, iouType, report, path = '') {
Navigation.navigate(ROUTES.MONEY_REQUEST_PARTICIPANTS.getRoute(iouType));
}
-function submitReport() {
- // Will be implemented in https://github.com/Expensify/App/issues/28763
+/**
+ * When the money request or split bill creation flow is initialized via FAB, the reportID is not passed as a navigation
+ * parameter.
+ * Gets a report id from the first participant of the IOU object stored in Onyx.
+ * @param {Object} iou
+ * @param {Array} iou.participants
+ * @param {Object} route
+ * @param {Object} route.params
+ * @param {String} [route.params.reportID]
+ * @returns {String}
+ */
+function getIOUReportID(iou, route) {
+ return lodashGet(route, 'params.reportID') || lodashGet(iou, 'participants.0.reportID', '');
}
export {
@@ -2312,9 +2637,11 @@ export {
deleteMoneyRequest,
splitBill,
splitBillAndOpenReport,
+ startSplitBill,
requestMoney,
sendMoneyElsewhere,
approveMoneyRequest,
+ submitReport,
payMoneyRequest,
sendMoneyWithWallet,
startMoneyRequest,
@@ -2336,5 +2663,5 @@ export {
navigateToNextPage,
updateDistanceRequest,
replaceReceipt,
- submitReport,
+ getIOUReportID,
};
diff --git a/src/libs/actions/Policy.js b/src/libs/actions/Policy.js
index 577048b1b716..61f9c49e3fdd 100644
--- a/src/libs/actions/Policy.js
+++ b/src/libs/actions/Policy.js
@@ -1,6 +1,7 @@
import _ from 'underscore';
import Onyx from 'react-native-onyx';
import lodashGet from 'lodash/get';
+import lodashUnion from 'lodash/union';
import {PUBLIC_DOMAINS} from 'expensify-common/lib/CONST';
import Str from 'expensify-common/lib/str';
import {escapeRegExp} from 'lodash';
@@ -65,6 +66,13 @@ Onyx.connect({
callback: (val) => (allPersonalDetails = val),
});
+let allRecentlyUsedCategories = {};
+Onyx.connect({
+ key: ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_CATEGORIES,
+ waitForCollectionCallback: true,
+ callback: (val) => (allRecentlyUsedCategories = val),
+});
+
/**
* Stores in Onyx the policy ID of the last workspace that was accessed by the user
* @param {String|null} policyID
@@ -196,14 +204,37 @@ function removeMembers(accountIDs, policyID) {
if (accountIDs.length === 0) {
return;
}
+
const membersListKey = `${ONYXKEYS.COLLECTION.POLICY_MEMBERS}${policyID}`;
+ const policy = ReportUtils.getPolicy(policyID);
+ const workspaceChats = ReportUtils.getWorkspaceChats(policyID, accountIDs);
+ const optimisticClosedReportActions = _.map(workspaceChats, () =>
+ ReportUtils.buildOptimisticClosedReportAction(sessionEmail, policy.name, CONST.REPORT.ARCHIVE_REASON.REMOVED_FROM_POLICY),
+ );
+
const optimisticData = [
{
onyxMethod: Onyx.METHOD.MERGE,
key: membersListKey,
value: _.object(accountIDs, Array(accountIDs.length).fill({pendingAction: CONST.RED_BRICK_ROAD_PENDING_ACTION.DELETE})),
},
+ ..._.map(workspaceChats, (report) => ({
+ onyxMethod: Onyx.METHOD.MERGE,
+ key: `${ONYXKEYS.COLLECTION.REPORT}${report.reportID}`,
+ value: {
+ statusNum: CONST.REPORT.STATUS.CLOSED,
+ stateNum: CONST.REPORT.STATE_NUM.SUBMITTED,
+ oldPolicyName: policy.name,
+ hasDraft: false,
+ },
+ })),
+ ..._.map(optimisticClosedReportActions, (reportAction, index) => ({
+ onyxMethod: Onyx.METHOD.MERGE,
+ key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${workspaceChats[index].reportID}`,
+ value: {[reportAction.reportActionID]: reportAction},
+ })),
];
+
const successData = [
{
onyxMethod: Onyx.METHOD.MERGE,
@@ -217,6 +248,21 @@ function removeMembers(accountIDs, policyID) {
key: membersListKey,
value: _.object(accountIDs, Array(accountIDs.length).fill({errors: ErrorUtils.getMicroSecondOnyxError('workspace.people.error.genericRemove')})),
},
+ ..._.map(workspaceChats, ({reportID, stateNum, statusNum, hasDraft, oldPolicyName = null}) => ({
+ onyxMethod: Onyx.METHOD.MERGE,
+ key: `${ONYXKEYS.COLLECTION.REPORT}${reportID}`,
+ value: {
+ stateNum,
+ statusNum,
+ hasDraft,
+ oldPolicyName,
+ },
+ })),
+ ..._.map(optimisticClosedReportActions, (reportAction, index) => ({
+ onyxMethod: Onyx.METHOD.MERGE,
+ key: `${ONYXKEYS.COLLECTION.REPORT_ACTIONS}${workspaceChats[index].reportID}`,
+ value: {[reportAction.reportActionID]: null},
+ })),
];
API.write(
'DeleteMembersFromWorkspace',
@@ -1168,6 +1214,21 @@ function clearErrors(policyID) {
hideWorkspaceAlertMessage(policyID);
}
+/**
+ * @param {String} policyID
+ * @param {String} category
+ * @returns {Object}
+ */
+function buildOptimisticPolicyRecentlyUsedCategories(policyID, category) {
+ if (!policyID || !category) {
+ return [];
+ }
+
+ const policyRecentlyUsedCategories = lodashGet(allRecentlyUsedCategories, `${ONYXKEYS.COLLECTION.POLICY_RECENTLY_USED_CATEGORIES}${policyID}`, []);
+
+ return lodashUnion([category], policyRecentlyUsedCategories);
+}
+
export {
removeMembers,
addMembersToWorkspace,
@@ -1197,4 +1258,5 @@ export {
setWorkspaceInviteMembersDraft,
clearErrors,
openDraftWorkspaceRequest,
+ buildOptimisticPolicyRecentlyUsedCategories,
};
diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js
index 36f37ac5db7d..7418f579e442 100644
--- a/src/libs/actions/Report.js
+++ b/src/libs/actions/Report.js
@@ -87,6 +87,19 @@ Onyx.connect({
},
});
+const draftNoteMap = {};
+Onyx.connect({
+ key: ONYXKEYS.COLLECTION.PRIVATE_NOTES_DRAFT,
+ callback: (value, key) => {
+ if (!key) {
+ return;
+ }
+
+ const reportID = key.replace(ONYXKEYS.COLLECTION.PRIVATE_NOTES_DRAFT, '');
+ draftNoteMap[reportID] = value;
+ },
+});
+
const allReports = {};
let conciergeChatReportID;
const typingWatchTimers = {};
@@ -2233,6 +2246,21 @@ function clearPrivateNotesError(reportID, accountID) {
Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${reportID}`, {privateNotes: {[accountID]: {errors: null}}});
}
+function getDraftPrivateNote(reportID) {
+ return draftNoteMap[reportID];
+}
+
+/**
+ * Saves the private notes left by the user as they are typing. By saving this data the user can switch between chats, close
+ * tab, refresh etc without worrying about loosing what they typed out.
+ *
+ * @param {String} reportID
+ * @param {String} note
+ */
+function savePrivateNotesDraft(reportID, note) {
+ Onyx.merge(`${ONYXKEYS.COLLECTION.PRIVATE_NOTES_DRAFT}${reportID}`, note);
+}
+
export {
addComment,
addAttachment,
@@ -2288,4 +2316,6 @@ export {
hasErrorInPrivateNotes,
getOlderActions,
getNewerActions,
+ savePrivateNotesDraft,
+ getDraftPrivateNote,
};
diff --git a/src/libs/migrateOnyx.js b/src/libs/migrateOnyx.js
index d96a37d95457..aaa706e71fb2 100644
--- a/src/libs/migrateOnyx.js
+++ b/src/libs/migrateOnyx.js
@@ -1,6 +1,5 @@
import _ from 'underscore';
import Log from './Log';
-import RenamePriorityModeKey from './migrations/RenamePriorityModeKey';
import PersonalDetailsByAccountID from './migrations/PersonalDetailsByAccountID';
import RenameReceiptFilename from './migrations/RenameReceiptFilename';
@@ -10,7 +9,7 @@ export default function () {
return new Promise((resolve) => {
// Add all migrations to an array so they are executed in order
- const migrationPromises = [RenamePriorityModeKey, PersonalDetailsByAccountID, RenameReceiptFilename];
+ const migrationPromises = [PersonalDetailsByAccountID, RenameReceiptFilename];
// Reduce all promises down to a single promise. All promises run in a linear fashion, waiting for the
// previous promise to finish before moving onto the next one.
diff --git a/src/libs/migrations/RenamePriorityModeKey.js b/src/libs/migrations/RenamePriorityModeKey.js
deleted file mode 100644
index a2be26880b52..000000000000
--- a/src/libs/migrations/RenamePriorityModeKey.js
+++ /dev/null
@@ -1,33 +0,0 @@
-import Onyx from 'react-native-onyx';
-import _ from 'underscore';
-import ONYXKEYS from '../../ONYXKEYS';
-import Log from '../Log';
-
-// This migration changes the name of the Onyx key NVP_PRIORITY_MODE from priorityMode to nvp_priorityMode
-export default function () {
- return new Promise((resolve) => {
- // Connect to the old key in Onyx to get the old value of priorityMode
- // then set the new key nvp_priorityMode to hold the old data
- // finally remove the old key by setting the value to null
- const connectionID = Onyx.connect({
- key: 'priorityMode',
- callback: (oldPriorityMode) => {
- Onyx.disconnect(connectionID);
-
- // Fail early here because there is nothing to migrate
- if (_.isEmpty(oldPriorityMode)) {
- Log.info('[Migrate Onyx] Skipped migration RenamePriorityModeKey');
- return resolve();
- }
-
- Onyx.multiSet({
- priorityMode: null,
- [ONYXKEYS.NVP_PRIORITY_MODE]: oldPriorityMode,
- }).then(() => {
- Log.info('[Migrate Onyx] Ran migration RenamePriorityModeKey');
- resolve();
- });
- },
- });
- });
-}
diff --git a/src/pages/EditRequestDistancePage.js b/src/pages/EditRequestDistancePage.js
index 3a606aeb8f07..f5beba5fdcfd 100644
--- a/src/pages/EditRequestDistancePage.js
+++ b/src/pages/EditRequestDistancePage.js
@@ -39,13 +39,17 @@ const propTypes = {
/* Onyx props */
/** The original transaction that is being edited */
transaction: transactionPropTypes,
+
+ /** backup version of the original transaction */
+ transactionBackup: transactionPropTypes,
};
const defaultProps = {
transaction: {},
+ transactionBackup: {},
};
-function EditRequestDistancePage({report, route, transaction}) {
+function EditRequestDistancePage({report, route, transaction, transactionBackup}) {
const {isOffline} = useNetwork();
const {translate} = useLocalize();
const transactionWasSaved = useRef(false);
@@ -87,6 +91,16 @@ function EditRequestDistancePage({report, route, transaction}) {
* @param {Object} waypoints
*/
const saveTransaction = (waypoints) => {
+ // If nothing was changed, simply go to transaction thread
+ // We compare only addresses because numbers are rounded while backup
+ const oldWaypoints = lodashGet(transactionBackup, 'comment.waypoints', {});
+ const oldAddresses = _.mapObject(oldWaypoints, (waypoint) => _.pick(waypoint, 'address'));
+ const addresses = _.mapObject(waypoints, (waypoint) => _.pick(waypoint, 'address'));
+ if (_.isEqual(oldAddresses, addresses)) {
+ Navigation.dismissModal(report.reportID);
+ return;
+ }
+
transactionWasSaved.current = true;
IOU.updateDistanceRequest(transaction.transactionID, report.reportID, {waypoints});
@@ -125,4 +139,7 @@ export default withOnyx({
transaction: {
key: (props) => `${ONYXKEYS.COLLECTION.TRANSACTION}${props.transactionID}`,
},
+ transactionBackup: {
+ key: (props) => `${ONYXKEYS.COLLECTION.TRANSACTION}${props.transactionID}-backup`,
+ },
})(EditRequestDistancePage);
diff --git a/src/pages/NewChatPage.js b/src/pages/NewChatPage.js
index c3b66910face..565f36d69e54 100755
--- a/src/pages/NewChatPage.js
+++ b/src/pages/NewChatPage.js
@@ -198,7 +198,7 @@ function NewChatPage({betas, isGroupChat, personalDetails, reports, translate})
onChangeText={setSearchTerm}
headerMessage={headerMessage}
boldStyle
- shouldFocusOnSelectRow={!Browser.isMobile()}
+ shouldPreventDefaultFocusOnSelectRow={!Browser.isMobile()}
shouldShowOptions={isOptionsDataReady}
shouldShowConfirmButton
confirmButtonText={selectedOptions.length > 1 ? translate('newChatPage.createGroup') : translate('newChatPage.createChat')}
diff --git a/src/pages/PrivateNotes/PrivateNotesEditPage.js b/src/pages/PrivateNotes/PrivateNotesEditPage.js
index 183bd6d16233..1bf99a6f5681 100644
--- a/src/pages/PrivateNotes/PrivateNotesEditPage.js
+++ b/src/pages/PrivateNotes/PrivateNotesEditPage.js
@@ -1,4 +1,4 @@
-import React, {useState, useRef, useCallback} from 'react';
+import React, {useState, useRef, useCallback, useMemo} from 'react';
import PropTypes from 'prop-types';
import {Keyboard} from 'react-native';
import {withOnyx} from 'react-native-onyx';
@@ -63,7 +63,23 @@ function PrivateNotesEditPage({route, personalDetailsList, session, report}) {
// We need to edit the note in markdown format, but display it in HTML format
const parser = new ExpensiMark();
- const [privateNote, setPrivateNote] = useState(parser.htmlToMarkdown(lodashGet(report, ['privateNotes', route.params.accountID, 'note'], '')).trim());
+ const [privateNote, setPrivateNote] = useState(
+ Report.getDraftPrivateNote(report.reportID) || parser.htmlToMarkdown(lodashGet(report, ['privateNotes', route.params.accountID, 'note'], '')).trim(),
+ );
+
+ /**
+ * Save the draft of the private note. This debounced so that we're not ceaselessly saving your edit. Saving the draft
+ * allows one to navigate somewhere else and come back to the private note and still have it in edit mode.
+ * @param {String} newDraft
+ */
+ const debouncedSavePrivateNote = useMemo(
+ () =>
+ _.debounce((text) => {
+ Report.savePrivateNotesDraft(report.reportID, text);
+ }, 1000),
+ [report.reportID],
+ );
+
const isCurrentUserNote = Number(session.accountID) === Number(route.params.accountID);
// To focus on the input field when the page loads
@@ -153,7 +169,10 @@ function PrivateNotesEditPage({route, personalDetailsList, session, report}) {
containerStyles={[styles.autoGrowHeightMultilineInput]}
defaultValue={privateNote}
value={privateNote}
- onChangeText={(text) => setPrivateNote(text)}
+ onChangeText={(text) => {
+ debouncedSavePrivateNote(text);
+ setPrivateNote(text);
+ }}
ref={(el) => {
if (!el) {
return;
diff --git a/src/pages/ProfilePage.js b/src/pages/ProfilePage.js
index 6bacc8ed3bb4..3df72deccefd 100755
--- a/src/pages/ProfilePage.js
+++ b/src/pages/ProfilePage.js
@@ -37,6 +37,7 @@ import variables from '../styles/variables';
import * as ValidationUtils from '../libs/ValidationUtils';
import Permissions from '../libs/Permissions';
import ROUTES from '../ROUTES';
+import MenuItemWithTopDescription from '../components/MenuItemWithTopDescription';
const matchType = PropTypes.shape({
params: PropTypes.shape({
@@ -122,7 +123,7 @@ function ProfilePage(props) {
const phoneOrEmail = isSMSLogin ? getPhoneNumber(details) : login;
const isCurrentUser = _.keys(props.loginList).includes(login);
- const hasMinimumDetails = !_.isEmpty(details.avatar) && !_.isUndefined(details.displayName);
+ const hasMinimumDetails = !_.isEmpty(details.avatar);
const isLoading = lodashGet(details, 'isLoading', false) || _.isEmpty(details) || props.isLoadingReportData;
// If the API returns an error for some reason there won't be any details and isLoading will get set to false, so we want to show a blocking screen
@@ -135,7 +136,7 @@ function ProfilePage(props) {
const navigateBackTo = lodashGet(props.route, 'params.backTo', ROUTES.HOME);
- const chatReportWithCurrentUser = !isCurrentUser && !Session.isAnonymousUser() ? ReportUtils.getChatByParticipants([accountID]) : 0;
+ const notificationPreference = !_.isEmpty(props.report) ? props.translate(`notificationPreferencesPage.notificationPreferences.${props.report.notificationPreference}`) : '';
// eslint-disable-next-line rulesdir/prefer-early-return
useEffect(() => {
@@ -231,6 +232,15 @@ function ProfilePage(props) {
) : null}
{shouldShowLocalTime && }
+ {!_.isEmpty(props.report) && notificationPreference !== CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN && (
+ Navigation.navigate(ROUTES.REPORT_SETTINGS_NOTIFICATION_PREFERENCES.getRoute(props.report.reportID))}
+ wrapperStyle={[styles.mtn6, styles.mb5]}
+ />
+ )}
{!isCurrentUser && !Session.isAnonymousUser() && (
)}
- {!_.isEmpty(chatReportWithCurrentUser) && (
+ {!_.isEmpty(props.report) && (
Navigation.navigate(ROUTES.PRIVATE_NOTES_LIST.getRoute(chatReportWithCurrentUser.reportID))}
+ onPress={() => Navigation.navigate(ROUTES.PRIVATE_NOTES_LIST.getRoute(props.report.reportID))}
wrapperStyle={styles.breakAll}
shouldShowRightIcon
- brickRoadIndicator={Report.hasErrorInPrivateNotes(chatReportWithCurrentUser) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : ''}
+ brickRoadIndicator={Report.hasErrorInPrivateNotes(props.report) ? CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR : ''}
/>
)}
@@ -289,5 +299,21 @@ export default compose(
betas: {
key: ONYXKEYS.BETAS,
},
+ session: {
+ key: ONYXKEYS.SESSION,
+ },
+ }),
+ // eslint-disable-next-line rulesdir/no-multiple-onyx-in-file
+ withOnyx({
+ report: {
+ key: ({route, session}) => {
+ const accountID = Number(lodashGet(route.params, 'accountID', 0));
+ const reportID = lodashGet(ReportUtils.getChatByParticipants([accountID]), 'reportID', '');
+ if (Number(session.accountID) === accountID || Session.isAnonymousUser() || !reportID) {
+ return null;
+ }
+ return `${ONYXKEYS.COLLECTION.REPORT}${reportID}`;
+ },
+ },
}),
)(ProfilePage);
diff --git a/src/pages/ReportDetailsPage.js b/src/pages/ReportDetailsPage.js
index e4ce09fc7e1a..42a535844c72 100644
--- a/src/pages/ReportDetailsPage.js
+++ b/src/pages/ReportDetailsPage.js
@@ -61,8 +61,7 @@ const defaultProps = {
function ReportDetailsPage(props) {
const policy = useMemo(() => props.policies[`${ONYXKEYS.COLLECTION.POLICY}${props.report.policyID}`], [props.policies, props.report.policyID]);
const isPolicyAdmin = useMemo(() => PolicyUtils.isPolicyAdmin(policy), [policy]);
- const shouldDisableSettings = useMemo(() => ReportUtils.shouldDisableSettings(props.report), [props.report]);
- const shouldUseFullTitle = !shouldDisableSettings || ReportUtils.isTaskReport(props.report);
+ const shouldUseFullTitle = ReportUtils.isTaskReport(props.report);
const isChatRoom = useMemo(() => ReportUtils.isChatRoom(props.report), [props.report]);
const isThread = useMemo(() => ReportUtils.isChatThread(props.report), [props.report]);
const isUserCreatedPolicyRoom = useMemo(() => ReportUtils.isUserCreatedPolicyRoom(props.report), [props.report]);
@@ -75,16 +74,20 @@ function ReportDetailsPage(props) {
const canLeaveRoom = useMemo(() => ReportUtils.canLeaveRoom(props.report, !_.isEmpty(policy)), [policy, props.report]);
const participants = useMemo(() => ReportUtils.getParticipantsIDs(props.report), [props.report]);
+ const isGroupDMChat = useMemo(() => ReportUtils.isDM(props.report) && participants.length > 1, [props.report, participants.length]);
+
const menuItems = useMemo(() => {
- const items = [
- {
+ const items = [];
+
+ if (!isGroupDMChat) {
+ items.push({
key: CONST.REPORT_DETAILS_MENU_ITEM.SHARE_CODE,
translationKey: 'common.shareCode',
icon: Expensicons.QrCode,
isAnonymousAction: true,
action: () => Navigation.navigate(ROUTES.REPORT_WITH_ID_DETAILS_SHARE_CODE.getRoute(props.report.reportID)),
- },
- ];
+ });
+ }
if (isArchivedRoom) {
return items;
@@ -103,17 +106,15 @@ function ReportDetailsPage(props) {
});
}
- if (!shouldDisableSettings) {
- items.push({
- key: CONST.REPORT_DETAILS_MENU_ITEM.SETTINGS,
- translationKey: 'common.settings',
- icon: Expensicons.Gear,
- isAnonymousAction: false,
- action: () => {
- Navigation.navigate(ROUTES.REPORT_SETTINGS.getRoute(props.report.reportID));
- },
- });
- }
+ items.push({
+ key: CONST.REPORT_DETAILS_MENU_ITEM.SETTINGS,
+ translationKey: 'common.settings',
+ icon: Expensicons.Gear,
+ isAnonymousAction: false,
+ action: () => {
+ Navigation.navigate(ROUTES.REPORT_SETTINGS.getRoute(props.report.reportID));
+ },
+ });
// Prevent displaying private notes option for threads and task reports
if (!isThread && !isMoneyRequestReport && !ReportUtils.isTaskReport(props.report)) {
@@ -138,7 +139,7 @@ function ReportDetailsPage(props) {
}
return items;
- }, [isArchivedRoom, participants.length, shouldDisableSettings, isThread, isMoneyRequestReport, props.report, isUserCreatedPolicyRoom, canLeaveRoom]);
+ }, [isArchivedRoom, participants.length, isThread, isMoneyRequestReport, props.report, isUserCreatedPolicyRoom, canLeaveRoom, isGroupDMChat]);
const displayNamesWithTooltips = useMemo(() => {
const hasMultipleParticipants = participants.length > 1;
diff --git a/src/pages/home/ReportScreen.js b/src/pages/home/ReportScreen.js
index 4a29a05421fc..7d99e84cb7f6 100644
--- a/src/pages/home/ReportScreen.js
+++ b/src/pages/home/ReportScreen.js
@@ -262,12 +262,12 @@ function ReportScreen({
// It possible that we may not have the report object yet in Onyx yet e.g. we navigated to a URL for an accessible report that
// is not stored locally yet. If report.reportID exists, then the report has been stored locally and nothing more needs to be done.
// If it doesn't exist, then we fetch the report from the API.
- if (report.reportID && report.reportID === getReportID(route) && !reportMetadata.isLoadingInitialReportActions) {
+ if (report.reportID && report.reportID === getReportID(route) && !isFirstlyLoadingReportActions) {
return;
}
fetchReport();
- }, [report.reportID, route, reportMetadata.isLoadingInitialReportActions, fetchReport]);
+ }, [report.reportID, route, isFirstlyLoadingReportActions, fetchReport]);
const dismissBanner = useCallback(() => {
setIsBannerVisible(false);
diff --git a/src/pages/home/report/AnimatedEmptyStateBackground.js b/src/pages/home/report/AnimatedEmptyStateBackground.js
index ecc37a2b785f..67d9a9584b39 100644
--- a/src/pages/home/report/AnimatedEmptyStateBackground.js
+++ b/src/pages/home/report/AnimatedEmptyStateBackground.js
@@ -4,6 +4,8 @@ import useWindowDimensions from '../../../hooks/useWindowDimensions';
import * as NumberUtils from '../../../libs/NumberUtils';
import EmptyStateBackgroundImage from '../../../../assets/images/empty-state_background-fade.png';
import * as StyleUtils from '../../../styles/StyleUtils';
+import variables from '../../../styles/variables';
+import CONST from '../../../CONST';
const IMAGE_OFFSET_Y = 75;
@@ -11,6 +13,9 @@ function AnimatedEmptyStateBackground() {
const {windowWidth, isSmallScreenWidth} = useWindowDimensions();
const IMAGE_OFFSET_X = windowWidth / 2;
+ // If window width is greater than the max background width, repeat the background image
+ const maxBackgroundWidth = variables.sideBarWidth + CONST.EMPTY_STATE_BACKGROUND.ASPECT_RATIO * CONST.EMPTY_STATE_BACKGROUND.WIDE_SCREEN.IMAGE_HEIGHT;
+
// Get data from phone rotation sensor and prep other variables for animation
const animatedSensor = useAnimatedSensor(SensorType.GYROSCOPE);
const xOffset = useSharedValue(0);
@@ -32,13 +37,14 @@ function AnimatedEmptyStateBackground() {
return {
transform: [{translateX: withSpring(-IMAGE_OFFSET_X - xOffset.value)}, {translateY: withSpring(yOffset.value)}],
};
- });
+ }, []);
return (
maxBackgroundWidth ? 'repeat' : 'cover'}
/>
);
}
diff --git a/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.js b/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.js
index 58017705c5f1..e987eff4c7e8 100644
--- a/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.js
+++ b/src/pages/home/report/ContextMenu/PopoverReportActionContextMenu.js
@@ -316,7 +316,7 @@ function PopoverReportActionContextMenu(_props, ref) {
/>
({
+ return _.map(ReportUtils.getMoneyRequestOptions(report, reportParticipantIDs), (option) => ({
...options[option],
onSelected: () => IOU.startMoneyRequest(option, report.reportID),
}));
- }, [betas, report, reportParticipantIDs, translate]);
+ }, [report, reportParticipantIDs, translate]);
/**
* Determines if we can show the task option
diff --git a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js
index a4777556dda7..faa710d2cd6b 100644
--- a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js
+++ b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js
@@ -102,8 +102,14 @@ function ComposerWithSuggestions({
const {preferredLocale} = useLocalize();
const isFocused = useIsFocused();
const navigation = useNavigation();
-
- const [value, setValue] = useState(() => getDraftComment(reportID) || '');
+ const emojisPresentBefore = useRef([]);
+ const [value, setValue] = useState(() => {
+ const draft = getDraftComment(reportID) || '';
+ if (draft) {
+ emojisPresentBefore.current = EmojiUtils.extractEmojis(draft);
+ }
+ return draft;
+ });
const commentRef = useRef(value);
const {isSmallScreenWidth} = useWindowDimensions();
@@ -154,14 +160,6 @@ function ComposerWithSuggestions({
debouncedLowerIsScrollLikelyLayoutTriggered();
}, [debouncedLowerIsScrollLikelyLayoutTriggered]);
- const onInsertedEmoji = useCallback(
- (emojiObject) => {
- insertedEmojisRef.current = [...insertedEmojisRef.current, emojiObject];
- debouncedUpdateFrequentlyUsedEmojis(emojiObject);
- },
- [debouncedUpdateFrequentlyUsedEmojis],
- );
-
/**
* Set the TextInput Ref
*
@@ -206,10 +204,13 @@ function ComposerWithSuggestions({
const {text: newComment, emojis} = EmojiUtils.replaceAndExtractEmojis(commentValue, preferredSkinTone, preferredLocale);
if (!_.isEmpty(emojis)) {
- insertedEmojisRef.current = [...insertedEmojisRef.current, ...emojis];
- debouncedUpdateFrequentlyUsedEmojis();
+ const newEmojis = EmojiUtils.getAddedEmojis(emojis, emojisPresentBefore.current);
+ if (!_.isEmpty(newEmojis)) {
+ insertedEmojisRef.current = [...insertedEmojisRef.current, ...newEmojis];
+ debouncedUpdateFrequentlyUsedEmojis();
+ }
}
-
+ emojisPresentBefore.current = emojis;
setIsCommentEmpty(!!newComment.match(/^(\s)*$/));
setValue(newComment);
if (commentValue !== newComment) {
@@ -550,7 +551,6 @@ function ComposerWithSuggestions({
isComposerFullSize={isComposerFullSize}
updateComment={updateComment}
composerHeight={composerHeight}
- onInsertedEmoji={onInsertedEmoji}
measureParentContainer={measureParentContainer}
// Input
value={value}
diff --git a/src/pages/home/report/ReportActionCompose/SuggestionEmoji.js b/src/pages/home/report/ReportActionCompose/SuggestionEmoji.js
index 910a338c83b6..8ffed01f1068 100644
--- a/src/pages/home/report/ReportActionCompose/SuggestionEmoji.js
+++ b/src/pages/home/report/ReportActionCompose/SuggestionEmoji.js
@@ -39,9 +39,6 @@ const propTypes = {
/** Function to clear the input */
resetKeyboardInput: PropTypes.func.isRequired,
- /** Callback when a emoji was inserted */
- onInsertedEmoji: PropTypes.func.isRequired,
-
...SuggestionProps.baseProps,
};
@@ -61,7 +58,6 @@ function SuggestionEmoji({
isAutoSuggestionPickerLarge,
forwardedRef,
resetKeyboardInput,
- onInsertedEmoji,
measureParentContainer,
}) {
const [suggestionValues, setSuggestionValues] = useState(defaultSuggestionsValues);
@@ -102,10 +98,8 @@ function SuggestionEmoji({
end: suggestionValues.colonIndex + emojiCode.length + CONST.SPACE_LENGTH,
});
setSuggestionValues((prevState) => ({...prevState, suggestedEmojis: []}));
-
- onInsertedEmoji(emojiObject);
},
- [onInsertedEmoji, preferredSkinTone, resetKeyboardInput, selection.end, setSelection, suggestionValues.colonIndex, suggestionValues.suggestedEmojis, updateComment, value],
+ [preferredSkinTone, resetKeyboardInput, selection.end, setSelection, suggestionValues.colonIndex, suggestionValues.suggestedEmojis, updateComment, value],
);
/**
diff --git a/src/pages/home/report/ReportActionCompose/Suggestions.js b/src/pages/home/report/ReportActionCompose/Suggestions.js
index a00bd342b17d..0e98e69d31d1 100644
--- a/src/pages/home/report/ReportActionCompose/Suggestions.js
+++ b/src/pages/home/report/ReportActionCompose/Suggestions.js
@@ -9,9 +9,6 @@ const propTypes = {
/** A ref to this component */
forwardedRef: PropTypes.shape({current: PropTypes.shape({})}),
- /** Callback when a emoji was inserted */
- onInsertedEmoji: PropTypes.func.isRequired,
-
/** Function to clear the input */
resetKeyboardInput: PropTypes.func.isRequired,
@@ -28,19 +25,7 @@ const defaultProps = {
*
* @returns {React.Component}
*/
-function Suggestions({
- isComposerFullSize,
- value,
- setValue,
- selection,
- setSelection,
- updateComment,
- composerHeight,
- forwardedRef,
- onInsertedEmoji,
- resetKeyboardInput,
- measureParentContainer,
-}) {
+function Suggestions({isComposerFullSize, value, setValue, selection, setSelection, updateComment, composerHeight, forwardedRef, resetKeyboardInput, measureParentContainer}) {
const suggestionEmojiRef = useRef(null);
const suggestionMentionRef = useRef(null);
@@ -114,7 +99,6 @@ function Suggestions({
ref={suggestionEmojiRef}
// eslint-disable-next-line react/jsx-props-no-spreading
{...baseProps}
- onInsertedEmoji={onInsertedEmoji}
resetKeyboardInput={resetKeyboardInput}
/>
getInitialDraft());
+ const emojisPresentBefore = useRef([]);
+ const [draft, setDraft] = useState(() => {
+ const initialDraft = getInitialDraft();
+ if (initialDraft) {
+ emojisPresentBefore.current = EmojiUtils.extractEmojis(initialDraft);
+ }
+ return initialDraft;
+ });
const [selection, setSelection] = useState(getInitialSelection());
const [isFocused, setIsFocused] = useState(false);
const [hasExceededMaxCommentLength, setHasExceededMaxCommentLength] = useState(false);
@@ -200,9 +204,13 @@ function ReportActionItemMessageEdit(props) {
const {text: newDraft, emojis} = EmojiUtils.replaceAndExtractEmojis(newDraftInput, props.preferredSkinTone, preferredLocale);
if (!_.isEmpty(emojis)) {
- insertedEmojis.current = [...insertedEmojis.current, ...emojis];
- debouncedUpdateFrequentlyUsedEmojis();
+ const newEmojis = EmojiUtils.getAddedEmojis(emojis, emojisPresentBefore.current);
+ if (!_.isEmpty(newEmojis)) {
+ insertedEmojis.current = [...insertedEmojis.current, ...newEmojis];
+ debouncedUpdateFrequentlyUsedEmojis();
+ }
}
+ emojisPresentBefore.current = emojis;
setDraft((prevDraft) => {
if (newDraftInput !== newDraft) {
const remainder = ComposerUtils.getCommonSuffixLength(prevDraft, newDraft);
@@ -313,30 +321,6 @@ function ReportActionItemMessageEdit(props) {
return (
<>
-
-
- e.preventDefault()}
- >
- {({hovered, pressed}) => (
-
- )}
-
-
-
-
+
+
+ e.preventDefault()}
+ >
+
+
+
+
+
{
diff --git a/src/pages/home/report/ReportActionItemParentAction.js b/src/pages/home/report/ReportActionItemParentAction.js
index 8e1fb6aafdd4..b67707031372 100644
--- a/src/pages/home/report/ReportActionItemParentAction.js
+++ b/src/pages/home/report/ReportActionItemParentAction.js
@@ -1,5 +1,5 @@
import React from 'react';
-import {View, Image} from 'react-native';
+import {View} from 'react-native';
import lodashGet from 'lodash/get';
import {withOnyx} from 'react-native-onyx';
import PropTypes from 'prop-types';
@@ -15,7 +15,7 @@ import withLocalize from '../../../components/withLocalize';
import ReportActionItem from './ReportActionItem';
import reportActionPropTypes from './reportActionPropTypes';
import * as ReportActionsUtils from '../../../libs/ReportActionsUtils';
-import EmptyStateBackgroundImage from '../../../../assets/images/empty-state_background-fade.png';
+import AnimatedEmptyStateBackground from './AnimatedEmptyStateBackground';
const propTypes = {
/** Flag to show, hide the thread divider line */
@@ -61,11 +61,7 @@ function ReportActionItemParentAction(props) {
onClose={() => Report.navigateToConciergeChatAndDeleteReport(props.report.reportID)}
>
-
+
{parentReportAction && (
{
- let shouldDisplay = false;
+ const renderItem = useCallback(
+ ({item: reportAction, index}) => {
+ let shouldDisplayNewMarker = false;
if (!currentUnreadMarker) {
const nextMessage = sortedReportActions[index + 1];
const isCurrentMessageUnread = isMessageUnread(reportAction, report.lastReadTime);
- shouldDisplay = isCurrentMessageUnread && !isMessageUnread(nextMessage, report.lastReadTime);
+ shouldDisplayNewMarker = isCurrentMessageUnread && !isMessageUnread(nextMessage, report.lastReadTime);
+
if (!messageManuallyMarkedUnread) {
- shouldDisplay = shouldDisplay && reportAction.actorAccountID !== Report.getCurrentUserAccountID();
+ shouldDisplayNewMarker = shouldDisplayNewMarker && reportAction.actorAccountID !== Report.getCurrentUserAccountID();
+ }
+ const canDisplayMarker = scrollingVerticalOffset.current < MSG_VISIBLE_THRESHOLD ? reportAction.created < userActiveSince.current : true;
+
+ if (!currentUnreadMarker && shouldDisplayNewMarker && canDisplayMarker) {
+ setCurrentUnreadMarker(reportAction.reportActionID);
}
} else {
- shouldDisplay = reportAction.reportActionID === currentUnreadMarker;
+ shouldDisplayNewMarker = reportAction.reportActionID === currentUnreadMarker;
}
- return shouldDisplay;
+ return (
+
+ );
},
- [currentUnreadMarker, sortedReportActions, report.lastReadTime, messageManuallyMarkedUnread],
- );
-
- useEffect(() => {
- // Iterate through the report actions and set appropriate unread marker.
- // This is to avoid a warning of:
- // Cannot update a component (ReportActionsList) while rendering a different component (CellRenderer).
- _.each(sortedReportActions, (reportAction, index) => {
- if (!shouldDisplayNewMarker(reportAction, index)) {
- return;
- }
- setCurrentUnreadMarker(reportAction.reportActionID);
- });
- }, [sortedReportActions, report.lastReadTime, messageManuallyMarkedUnread, shouldDisplayNewMarker]);
-
- const renderItem = useCallback(
- ({item: reportAction, index}) => (
-
- ),
- [report, linkedReportActionID, hasOutstandingIOU, sortedReportActions, mostRecentIOUReportActionID, shouldHideThreadDividerLine, shouldDisplayNewMarker],
+ [report, linkedReportActionID, hasOutstandingIOU, sortedReportActions, mostRecentIOUReportActionID, messageManuallyMarkedUnread, shouldHideThreadDividerLine, currentUnreadMarker],
);
// Native mobile does not render updates flatlist the changes even though component did update called.
diff --git a/src/pages/home/report/ReportActionsView.js b/src/pages/home/report/ReportActionsView.js
index 38174a867b80..06e0b4d865fc 100755
--- a/src/pages/home/report/ReportActionsView.js
+++ b/src/pages/home/report/ReportActionsView.js
@@ -84,10 +84,15 @@ function ReportActionsView({reportActions: allReportActions, fetchReport, ...pro
const {reportActionID} = getReportActionID(route);
const didLayout = useRef(false);
const didSubscribeToReportTypingEvents = useRef(false);
+
const [isLinkingToCattedMessage, setLinkingToCattedMessage] = useState(false);
const [isLinkingToExtendedMessage, setLinkingToExtendedMessage] = useState(false);
const isLoadingLinkedMessage = !!reportActionID && props.isLoadingInitialReportActions;
+ const isFirstRender = useRef(true); //TODO:
+ // const hasCachedActions = useRef(_.size(props.reportActions) > 0); //TODO:
+
+
useEffect(() => {
let timeoutIdCatted;
let timeoutIdExtended;
@@ -264,7 +269,12 @@ function ReportActionsView({reportActions: allReportActions, fetchReport, ...pro
//
// Additionally, we use throttling on the 'onStartReached' callback to further reduce the frequency of its invocation.
// This should be removed once the issue of frequent re-renders is resolved.
- if (!isLinkingToExtendedMessage || distanceFromStart <= CONST.CHAT_HEADER_LOADER_HEIGHT) {
+
+ // if (!isLinkingToExtendedMessage || distanceFromStart <= CONST.CHAT_HEADER_LOADER_HEIGHT) { // TODO:
+ //
+ // onStartReached is triggered during the first render. Since we use OpenReport on the first render and are confident about the message ordering, we can safely skip this call
+ if (isFirstRender.current || distanceFromStart <= CONST.CHAT_HEADER_LOADER_HEIGHT) {
+ isFirstRender.current = false;
return;
}
diff --git a/src/pages/home/sidebar/SidebarLinksData.js b/src/pages/home/sidebar/SidebarLinksData.js
index 0aa7423afacd..9dbdde14c50d 100644
--- a/src/pages/home/sidebar/SidebarLinksData.js
+++ b/src/pages/home/sidebar/SidebarLinksData.js
@@ -60,7 +60,7 @@ const defaultProps = {
isLoadingReportData: true,
priorityMode: CONST.PRIORITY_MODE.DEFAULT,
betas: [],
- policies: [],
+ policies: {},
};
function SidebarLinksData({isFocused, allReportActions, betas, chatReports, currentReportID, insets, isLoadingReportData, onLinkClick, policies, priorityMode}) {
diff --git a/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js b/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js
index e9ede2c9a89a..80fd1d39239d 100644
--- a/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js
+++ b/src/pages/home/sidebar/SidebarScreen/FloatingActionButtonAndPopover.js
@@ -154,7 +154,7 @@ function FloatingActionButtonAndPopover(props) {
}
Welcome.show({routes, showCreateMenu});
// eslint-disable-next-line react-hooks/exhaustive-deps
- }, []);
+ }, [props.isLoading]);
useEffect(() => {
if (!didScreenBecomeInactive()) {
@@ -185,20 +185,16 @@ function FloatingActionButtonAndPopover(props) {
text: props.translate('sidebarScreen.fabNewChat'),
onSelected: () => interceptAnonymousUser(() => Navigation.navigate(ROUTES.NEW)),
},
- ...(Permissions.canUseIOUSend(props.betas)
- ? [
- {
- icon: Expensicons.Send,
- text: props.translate('iou.sendMoney'),
- onSelected: () => interceptAnonymousUser(() => IOU.startMoneyRequest(CONST.IOU.MONEY_REQUEST_TYPE.SEND)),
- },
- ]
- : []),
{
icon: Expensicons.MoneyCircle,
text: props.translate('iou.requestMoney'),
onSelected: () => interceptAnonymousUser(() => IOU.startMoneyRequest(CONST.IOU.MONEY_REQUEST_TYPE.REQUEST)),
},
+ {
+ icon: Expensicons.Send,
+ text: props.translate('iou.sendMoney'),
+ onSelected: () => interceptAnonymousUser(() => IOU.startMoneyRequest(CONST.IOU.MONEY_REQUEST_TYPE.SEND)),
+ },
...(Permissions.canUseTasks(props.betas)
? [
{
@@ -208,6 +204,11 @@ function FloatingActionButtonAndPopover(props) {
},
]
: []),
+ {
+ icon: Expensicons.Heart,
+ text: props.translate('sidebarScreen.saveTheWorld'),
+ onSelected: () => interceptAnonymousUser(() => Navigation.navigate(ROUTES.TEACHERS_UNITE)),
+ },
...(!props.isLoading && !Policy.hasActiveFreePolicy(props.allPolicies)
? [
{
diff --git a/src/pages/iou/MoneyRequestCategoryPage.js b/src/pages/iou/MoneyRequestCategoryPage.js
index 5284b785304f..5055c9f90f8a 100644
--- a/src/pages/iou/MoneyRequestCategoryPage.js
+++ b/src/pages/iou/MoneyRequestCategoryPage.js
@@ -2,6 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import lodashGet from 'lodash/get';
import {withOnyx} from 'react-native-onyx';
+import compose from '../../libs/compose';
import ROUTES from '../../ROUTES';
import Navigation from '../../libs/Navigation/Navigation';
import useLocalize from '../../hooks/useLocalize';
@@ -83,11 +84,20 @@ MoneyRequestCategoryPage.displayName = 'MoneyRequestCategoryPage';
MoneyRequestCategoryPage.propTypes = propTypes;
MoneyRequestCategoryPage.defaultProps = defaultProps;
-export default withOnyx({
- report: {
- key: ({route}) => `${ONYXKEYS.COLLECTION.REPORT}${lodashGet(route, 'params.reportID', '')}`,
- },
- iou: {
- key: ONYXKEYS.IOU,
- },
-})(MoneyRequestCategoryPage);
+export default compose(
+ withOnyx({
+ iou: {
+ key: ONYXKEYS.IOU,
+ },
+ }),
+ // eslint-disable-next-line rulesdir/no-multiple-onyx-in-file
+ withOnyx({
+ report: {
+ key: ({route, iou}) => {
+ const reportID = IOU.getIOUReportID(iou, route);
+
+ return `${ONYXKEYS.COLLECTION.REPORT}${reportID}`;
+ },
+ },
+ }),
+)(MoneyRequestCategoryPage);
diff --git a/src/pages/iou/MoneyRequestSelectorPage.js b/src/pages/iou/MoneyRequestSelectorPage.js
index c8e3aebaa0b3..d006e3480a4e 100644
--- a/src/pages/iou/MoneyRequestSelectorPage.js
+++ b/src/pages/iou/MoneyRequestSelectorPage.js
@@ -99,7 +99,7 @@ function MoneyRequestSelectorPage(props) {
title={title[iouType]}
onBackButtonPress={Navigation.dismissModal}
/>
- {iouType === CONST.IOU.MONEY_REQUEST_TYPE.REQUEST ? (
+ {iouType === CONST.IOU.MONEY_REQUEST_TYPE.REQUEST || iouType === CONST.IOU.MONEY_REQUEST_TYPE.SPLIT ? (
`${ONYXKEYS.COLLECTION.REPORT}${lodashGet(route, 'params.reportID')}`,
- },
iou: {
key: ONYXKEYS.IOU,
},
}),
// eslint-disable-next-line rulesdir/no-multiple-onyx-in-file
+ withOnyx({
+ report: {
+ key: ({route, iou}) => {
+ const reportID = IOU.getIOUReportID(iou, route);
+
+ return `${ONYXKEYS.COLLECTION.REPORT}${reportID}`;
+ },
+ },
+ }),
+ // eslint-disable-next-line rulesdir/no-multiple-onyx-in-file
withOnyx({
policyTags: {
key: ({report}) => `${ONYXKEYS.COLLECTION.POLICY_TAGS}${report ? report.policyID : '0'}`,
diff --git a/src/pages/iou/ReceiptSelector/index.native.js b/src/pages/iou/ReceiptSelector/index.native.js
index 4887d0816c81..d509fbce176d 100644
--- a/src/pages/iou/ReceiptSelector/index.native.js
+++ b/src/pages/iou/ReceiptSelector/index.native.js
@@ -94,9 +94,7 @@ function ReceiptSelector({route, report, iou, transactionID, isInTabNavigator})
const camera = useRef(null);
const [flash, setFlash] = useState(false);
- const [permissions, setPermissions] = useState('granted');
- const isAndroidBlockedPermissionRef = useRef(false);
- const appState = useRef(AppState.currentState);
+ const [cameraPermissionStatus, setCameraPermissionStatus] = useState(undefined);
const iouType = lodashGet(route, 'params.iouType', '');
const pageIndex = lodashGet(route, 'params.pageIndex', 1);
@@ -105,16 +103,23 @@ function ReceiptSelector({route, report, iou, transactionID, isInTabNavigator})
const CameraComponent = isInTabNavigator ? TabNavigationAwareCamera : NavigationAwareCamera;
- // We want to listen to if the app has come back from background and refresh the permissions status to show camera when permissions were granted
useEffect(() => {
- const subscription = AppState.addEventListener('change', (nextAppState) => {
- if (appState.current.match(/inactive|background/) && nextAppState === 'active') {
- CameraPermission.getCameraPermissionStatus().then((permissionStatus) => {
- setPermissions(permissionStatus);
- });
+ const refreshCameraPermissionStatus = () => {
+ CameraPermission.getCameraPermissionStatus()
+ .then(setCameraPermissionStatus)
+ .catch(() => setCameraPermissionStatus(RESULTS.UNAVAILABLE));
+ };
+
+ // Check initial camera permission status
+ refreshCameraPermissionStatus();
+
+ // Refresh permission status when app gain focus
+ const subscription = AppState.addEventListener('change', (appState) => {
+ if (appState !== 'active') {
+ return;
}
- appState.current = nextAppState;
+ refreshCameraPermissionStatus();
});
return () => {
@@ -154,14 +159,17 @@ function ReceiptSelector({route, report, iou, transactionID, isInTabNavigator})
const askForPermissions = () => {
// There's no way we can check for the BLOCKED status without requesting the permission first
// https://github.com/zoontek/react-native-permissions/blob/a836e114ce3a180b2b23916292c79841a267d828/README.md?plain=1#L670
- if (permissions === RESULTS.BLOCKED || isAndroidBlockedPermissionRef.current) {
- Linking.openSettings();
- } else if (permissions === RESULTS.DENIED) {
- CameraPermission.requestCameraPermission().then((permissionStatus) => {
- setPermissions(permissionStatus);
- isAndroidBlockedPermissionRef.current = permissionStatus === RESULTS.BLOCKED;
+ CameraPermission.requestCameraPermission()
+ .then((status) => {
+ setCameraPermissionStatus(status);
+
+ if (status === RESULTS.BLOCKED) {
+ showPermissionsAlert();
+ }
+ })
+ .catch(() => {
+ setCameraPermissionStatus(RESULTS.UNAVAILABLE);
});
- }
};
/**
@@ -230,13 +238,14 @@ function ReceiptSelector({route, report, iou, transactionID, isInTabNavigator})
});
}, [flash, iouType, iou, report, translate, transactionID, route.path]);
- CameraPermission.getCameraPermissionStatus().then((permissionStatus) => {
- setPermissions(permissionStatus);
- });
+ // Wait for camera permission status to render
+ if (cameraPermissionStatus == null) {
+ return null;
+ }
return (
- {permissions !== RESULTS.GRANTED && (
+ {cameraPermissionStatus !== RESULTS.GRANTED && (
)}
- {permissions === RESULTS.GRANTED && device == null && (
+ {cameraPermissionStatus === RESULTS.GRANTED && device == null && (
)}
- {permissions === RESULTS.GRANTED && device != null && (
+ {cameraPermissionStatus === RESULTS.GRANTED && device != null && (
setFlash((prevFlash) => !prevFlash)}
>
participant.accountID !== reportAction.actorAccountID);
- const {amount: splitAmount, currency: splitCurrency, comment: splitComment} = ReportUtils.getTransactionDetails(transaction);
+ const {
+ amount: splitAmount,
+ currency: splitCurrency,
+ merchant: splitMerchant,
+ created: splitCreated,
+ comment: splitComment,
+ category: splitCategory,
+ } = ReportUtils.getTransactionDetails(transaction);
+ const isScanning = TransactionUtils.hasReceipt(transaction) && TransactionUtils.isReceiptBeingScanned(transaction);
return (
@@ -79,17 +89,25 @@ function SplitBillDetailsPage(props) {
pointerEvents="box-none"
style={[styles.containerWithSpaceBetween]}
>
+ {isScanning && }
{Boolean(participants.length) && (
)}
diff --git a/src/pages/iou/steps/MoneyRequestConfirmPage.js b/src/pages/iou/steps/MoneyRequestConfirmPage.js
index 3881221d5c52..d007e168de79 100644
--- a/src/pages/iou/steps/MoneyRequestConfirmPage.js
+++ b/src/pages/iou/steps/MoneyRequestConfirmPage.js
@@ -75,8 +75,14 @@ function MoneyRequestConfirmPage(props) {
}),
[props.iou.participants, props.personalDetails],
);
+ const isPolicyExpenseChat = useMemo(() => ReportUtils.isPolicyExpenseChat(ReportUtils.getRootParentReport(props.report)), [props.report]);
const isManualRequestDM = props.selectedTab === CONST.TAB.MANUAL && iouType.current === CONST.IOU.MONEY_REQUEST_TYPE.REQUEST;
+ useEffect(() => {
+ IOU.resetMoneyRequestCategory();
+ IOU.resetMoneyRequestTag();
+ }, []);
+
useEffect(() => {
const policyExpenseChat = _.find(participants, (participant) => participant.isPolicyExpenseChat);
if (policyExpenseChat) {
@@ -188,6 +194,22 @@ function MoneyRequestConfirmPage(props) {
(selectedParticipants) => {
const trimmedComment = props.iou.comment.trim();
+ // If we have a receipt let's start the split bill by creating only the action, the transaction, and the group DM if needed
+ if (iouType.current === CONST.IOU.MONEY_REQUEST_TYPE.SPLIT && props.iou.receiptPath) {
+ const existingSplitChatReportID = CONST.REGEX.NUMBER.test(reportID.current) ? reportID.current : '';
+ FileUtils.readFileAsync(props.iou.receiptPath, props.iou.receiptFilename).then((receipt) => {
+ IOU.startSplitBill(
+ selectedParticipants,
+ props.currentUserPersonalDetails.login,
+ props.currentUserPersonalDetails.accountID,
+ trimmedComment,
+ receipt,
+ existingSplitChatReportID,
+ );
+ });
+ return;
+ }
+
// IOUs created from a group report will have a reportID param in the route.
// Since the user is already viewing the report, we don't need to navigate them to the report
if (iouType.current === CONST.IOU.MONEY_REQUEST_TYPE.SPLIT && CONST.REGEX.NUMBER.test(reportID.current)) {
@@ -198,6 +220,7 @@ function MoneyRequestConfirmPage(props) {
props.iou.amount,
trimmedComment,
props.iou.currency,
+ props.iou.category,
reportID.current,
);
return;
@@ -212,12 +235,13 @@ function MoneyRequestConfirmPage(props) {
props.iou.amount,
trimmedComment,
props.iou.currency,
+ props.iou.category,
);
return;
}
- if (props.iou.receiptPath && props.iou.receiptSource) {
- FileUtils.readFileAsync(props.iou.receiptPath, props.iou.receiptSource).then((file) => {
+ if (props.iou.receiptPath && props.iou.receiptFilename) {
+ FileUtils.readFileAsync(props.iou.receiptPath, props.iou.receiptFilename).then((file) => {
const receipt = file;
receipt.state = file && isManualRequestDM ? CONST.IOU.RECEIPT_STATE.OPEN : CONST.IOU.RECEIPT_STATE.SCANREADY;
requestMoney(selectedParticipants, trimmedComment, receipt);
@@ -238,8 +262,9 @@ function MoneyRequestConfirmPage(props) {
props.currentUserPersonalDetails.login,
props.currentUserPersonalDetails.accountID,
props.iou.currency,
+ props.iou.category,
props.iou.receiptPath,
- props.iou.receiptSource,
+ props.iou.receiptFilename,
isDistanceRequest,
requestMoney,
createDistanceRequest,
@@ -335,9 +360,10 @@ function MoneyRequestConfirmPage(props) {
IOU.setMoneyRequestParticipants(newParticipants);
}}
receiptPath={props.iou.receiptPath}
- receiptSource={props.iou.receiptSource}
+ receiptFilename={props.iou.receiptFilename}
iouType={iouType.current}
reportID={reportID.current}
+ isPolicyExpenseChat={isPolicyExpenseChat}
// The participants can only be modified when the action is initiated from directly within a group chat and not the floating-action-button.
// This is because when there is a group of people, say they are on a trip, and you have some shared expenses with some of the people,
// but not all of them (maybe someone skipped out on dinner). Then it's nice to be able to select/deselect people from the group chat bill
@@ -375,12 +401,8 @@ export default compose(
withOnyx({
report: {
key: ({route, iou}) => {
- let reportID = lodashGet(route, 'params.reportID', '');
- if (!reportID) {
- // When the money request creation flow is initialized on Global Create, the reportID is not passed as a navigation parameter.
- // Get the report id from the participants list on the IOU object stored in Onyx.
- reportID = lodashGet(iou, 'participants.0.reportID', '');
- }
+ const reportID = IOU.getIOUReportID(iou, route);
+
return `${ONYXKEYS.COLLECTION.REPORT}${reportID}`;
},
},
diff --git a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage.js b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage.js
index 8d745903eb40..bd3ea8a50402 100644
--- a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage.js
+++ b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsPage.js
@@ -35,17 +35,17 @@ const propTypes = {
iou: iouPropTypes,
/** The current tab we have navigated to in the request modal. String that corresponds to the request type. */
- selectedTab: PropTypes.oneOf([CONST.TAB.DISTANCE, CONST.TAB.MANUAL, CONST.TAB.SCAN]).isRequired,
+ selectedTab: PropTypes.oneOf([CONST.TAB.DISTANCE, CONST.TAB.MANUAL, CONST.TAB.SCAN]),
};
const defaultProps = {
iou: iouDefaultProps,
+ selectedTab: undefined,
};
function MoneyRequestParticipantsPage({iou, selectedTab, route}) {
const {translate} = useLocalize();
const prevMoneyRequestId = useRef(iou.id);
- const isNewReportIDSelectedLocally = useRef(false);
const optionsSelectorRef = useRef();
const iouType = useRef(lodashGet(route, 'params.iouType', ''));
const reportID = useRef(lodashGet(route, 'params.reportID', ''));
@@ -63,19 +63,7 @@ function MoneyRequestParticipantsPage({iou, selectedTab, route}) {
setHeaderTitle(_.isEmpty(iou.participants) ? translate('tabSelector.manual') : translate('iou.split'));
}, [iou.participants, isDistanceRequest, translate]);
- const navigateToRequestStep = (moneyRequestType, option) => {
- if (option.reportID) {
- isNewReportIDSelectedLocally.current = true;
- IOU.setMoneyRequestId(`${moneyRequestType}${option.reportID}`);
- Navigation.navigate(ROUTES.MONEY_REQUEST_CONFIRMATION.getRoute(moneyRequestType, option.reportID));
- return;
- }
-
- IOU.setMoneyRequestId(moneyRequestType);
- Navigation.navigate(ROUTES.MONEY_REQUEST_CONFIRMATION.getRoute(moneyRequestType, reportID.current));
- };
-
- const navigateToSplitStep = (moneyRequestType) => {
+ const navigateToConfirmationStep = (moneyRequestType) => {
IOU.setMoneyRequestId(moneyRequestType);
Navigation.navigate(ROUTES.MONEY_REQUEST_CONFIRMATION.getRoute(moneyRequestType, reportID.current));
};
@@ -88,7 +76,7 @@ function MoneyRequestParticipantsPage({iou, selectedTab, route}) {
// ID in Onyx could change by initiating a new request in a separate browser tab or completing a request
if (prevMoneyRequestId.current !== iou.id) {
// The ID is cleared on completing a request. In that case, we will do nothing
- if (iou.id && !isDistanceRequest && !isSplitRequest && !isNewReportIDSelectedLocally.current) {
+ if (iou.id && !isDistanceRequest && !isSplitRequest) {
navigateBack(true);
}
return;
@@ -96,7 +84,7 @@ function MoneyRequestParticipantsPage({iou, selectedTab, route}) {
// Reset the money request Onyx if the ID in Onyx does not match the ID from params
const moneyRequestId = `${iouType.current}${reportID.current}`;
- const shouldReset = iou.id !== moneyRequestId && !isNewReportIDSelectedLocally.current;
+ const shouldReset = iou.id !== moneyRequestId;
if (shouldReset) {
IOU.resetMoneyRequestInfo(moneyRequestId);
}
@@ -126,8 +114,8 @@ function MoneyRequestParticipantsPage({iou, selectedTab, route}) {
ref={(el) => (optionsSelectorRef.current = el)}
participants={iou.participants}
onAddParticipants={IOU.setMoneyRequestParticipants}
- navigateToRequest={(option) => navigateToRequestStep(CONST.IOU.MONEY_REQUEST_TYPE.REQUEST, option)}
- navigateToSplit={() => navigateToSplitStep(CONST.IOU.MONEY_REQUEST_TYPE.SPLIT)}
+ navigateToRequest={() => navigateToConfirmationStep(iouType.current)}
+ navigateToSplit={() => navigateToConfirmationStep(CONST.IOU.MONEY_REQUEST_TYPE.SPLIT)}
safeAreaPaddingBottomStyle={safeAreaPaddingBottomStyle}
iouType={iouType.current}
isDistanceRequest={isDistanceRequest}
@@ -139,7 +127,7 @@ function MoneyRequestParticipantsPage({iou, selectedTab, route}) {
);
}
-MoneyRequestParticipantsPage.displayName = 'IOUParticipantsPage';
+MoneyRequestParticipantsPage.displayName = 'MoneyRequestParticipantsPage';
MoneyRequestParticipantsPage.propTypes = propTypes;
MoneyRequestParticipantsPage.defaultProps = defaultProps;
diff --git a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSelector.js b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSelector.js
index 05b206ce4147..bedca1a10c35 100755
--- a/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSelector.js
+++ b/src/pages/iou/steps/MoneyRequstParticipantsPage/MoneyRequestParticipantsSelector.js
@@ -59,9 +59,6 @@ const propTypes = {
/** Whether the money request is a distance request or not */
isDistanceRequest: PropTypes.bool,
- /** Whether the money request is a scan request or not */
- isScanRequest: PropTypes.bool,
-
...withLocalizePropTypes,
};
@@ -73,7 +70,6 @@ const defaultProps = {
reports: {},
betas: [],
isDistanceRequest: false,
- isScanRequest: false,
};
function MoneyRequestParticipantsSelector({
@@ -89,7 +85,6 @@ function MoneyRequestParticipantsSelector({
safeAreaPaddingBottomStyle,
iouType,
isDistanceRequest,
- isScanRequest,
}) {
const [searchTerm, setSearchTerm] = useState('');
const [newChatOptions, setNewChatOptions] = useState({
@@ -164,7 +159,7 @@ function MoneyRequestParticipantsSelector({
onAddParticipants([
{accountID: option.accountID, login: option.login, isPolicyExpenseChat: option.isPolicyExpenseChat, reportID: option.reportID, selected: true, searchText: option.searchText},
]);
- navigateToRequest(option);
+ navigateToRequest();
};
/**
@@ -245,7 +240,7 @@ function MoneyRequestParticipantsSelector({
// the app from crashing on native when you try to do this, we'll going to hide the button if you have a workspace and other participants
const hasPolicyExpenseChatParticipant = _.some(participants, (participant) => participant.isPolicyExpenseChat);
const shouldShowConfirmButton = !(participants.length > 1 && hasPolicyExpenseChatParticipant);
- const isAllowedToSplit = !isDistanceRequest && !isScanRequest;
+ const isAllowedToSplit = !isDistanceRequest;
return (
0 ? safeAreaPaddingBottomStyle : {}]}>
@@ -268,7 +263,7 @@ function MoneyRequestParticipantsSelector({
textInputLabel={translate('optionsSelector.nameEmailOrPhoneNumber')}
safeAreaPaddingBottomStyle={safeAreaPaddingBottomStyle}
shouldShowOptions={isOptionsDataReady}
- shouldFocusOnSelectRow={!Browser.isMobile()}
+ shouldPreventDefaultFocusOnSelectRow={!Browser.isMobile()}
shouldDelayFocus
/>
diff --git a/src/pages/settings/Profile/Contacts/ValidateCodeForm/BaseValidateCodeForm.js b/src/pages/settings/Profile/Contacts/ValidateCodeForm/BaseValidateCodeForm.js
index af36650d6812..73231cd315ad 100644
--- a/src/pages/settings/Profile/Contacts/ValidateCodeForm/BaseValidateCodeForm.js
+++ b/src/pages/settings/Profile/Contacts/ValidateCodeForm/BaseValidateCodeForm.js
@@ -4,6 +4,7 @@ import PropTypes from 'prop-types';
import _ from 'underscore';
import {withOnyx} from 'react-native-onyx';
import lodashGet from 'lodash/get';
+import {useFocusEffect} from '@react-navigation/native';
import MagicCodeInput from '../../../../../components/MagicCodeInput';
import * as ErrorUtils from '../../../../../libs/ErrorUtils';
import withLocalize, {withLocalizePropTypes} from '../../../../../components/withLocalize';
@@ -77,6 +78,7 @@ function BaseValidateCodeForm(props) {
const inputValidateCodeRef = useRef();
const validateLoginError = ErrorUtils.getEarliestErrorField(loginData, 'validateLogin');
const shouldDisableResendValidateCode = props.network.isOffline || props.account.isLoading;
+ const focusTimeoutRef = useRef(null);
useImperativeHandle(props.innerRef, () => ({
focus() {
@@ -87,6 +89,21 @@ function BaseValidateCodeForm(props) {
},
}));
+ useFocusEffect(
+ useCallback(() => {
+ if (!inputValidateCodeRef.current) {
+ return;
+ }
+ focusTimeoutRef.current = setTimeout(inputValidateCodeRef.current.focus, CONST.ANIMATED_TRANSITION);
+ return () => {
+ if (!focusTimeoutRef.current) {
+ return;
+ }
+ clearTimeout(focusTimeoutRef.current);
+ };
+ }, []),
+ );
+
useEffect(() => {
Session.clearAccountMessages();
if (!validateLoginError) {
diff --git a/src/pages/settings/Report/NotificationPreferencePage.js b/src/pages/settings/Report/NotificationPreferencePage.js
index a69b227470d6..7dc9ff7773de 100644
--- a/src/pages/settings/Report/NotificationPreferencePage.js
+++ b/src/pages/settings/Report/NotificationPreferencePage.js
@@ -26,7 +26,7 @@ const propTypes = {
const greenCheckmark = {src: Expensicons.Checkmark, color: themeColors.success};
function NotificationPreferencePage(props) {
- const shouldDisableNotificationPreferences = ReportUtils.shouldDisableSettings(props.report) || ReportUtils.isArchivedRoom(props.report);
+ const shouldDisableNotificationPreferences = ReportUtils.isArchivedRoom(props.report);
const notificationPreferenceOptions = _.map(
_.filter(_.values(CONST.REPORT.NOTIFICATION_PREFERENCE), (pref) => pref !== CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN),
(preference) => ({
diff --git a/src/pages/settings/Report/ReportSettingsPage.js b/src/pages/settings/Report/ReportSettingsPage.js
index 9f4f4d048354..5612096207bb 100644
--- a/src/pages/settings/Report/ReportSettingsPage.js
+++ b/src/pages/settings/Report/ReportSettingsPage.js
@@ -64,7 +64,7 @@ function ReportSettingsPage(props) {
const shouldDisableWelcomeMessage =
isMoneyRequestReport || ReportUtils.isArchivedRoom(report) || !ReportUtils.isChatRoom(report) || _.isEmpty(linkedWorkspace) || linkedWorkspace.role !== CONST.POLICY.ROLE.ADMIN;
- const shouldDisableSettings = _.isEmpty(report) || ReportUtils.shouldDisableSettings(report) || ReportUtils.isArchivedRoom(report);
+ const shouldDisableSettings = _.isEmpty(report) || ReportUtils.isArchivedRoom(report);
const shouldShowRoomName = !ReportUtils.isPolicyExpenseChat(report) && !ReportUtils.isChatThread(report);
const notificationPreference =
report.notificationPreference !== CONST.REPORT.NOTIFICATION_PREFERENCE.HIDDEN
diff --git a/src/pages/settings/Wallet/ActivatePhysicalCardPage.js b/src/pages/settings/Wallet/ActivatePhysicalCardPage.js
new file mode 100644
index 000000000000..e7198c009a44
--- /dev/null
+++ b/src/pages/settings/Wallet/ActivatePhysicalCardPage.js
@@ -0,0 +1,180 @@
+import React, {useRef, useCallback, useState, useEffect} from 'react';
+import {View} from 'react-native';
+import PropTypes from 'prop-types';
+import {withOnyx} from 'react-native-onyx';
+import lodashGet from 'lodash/get';
+import _ from 'underscore';
+import Text from '../../../components/Text';
+import Navigation from '../../../libs/Navigation/Navigation';
+import styles from '../../../styles/styles';
+import MagicCodeInput from '../../../components/MagicCodeInput';
+import * as DeviceCapabilities from '../../../libs/DeviceCapabilities';
+import * as ErrorUtils from '../../../libs/ErrorUtils';
+import * as CardSettings from '../../../libs/actions/Card';
+import BigNumberPad from '../../../components/BigNumberPad';
+import Button from '../../../components/Button';
+import IllustratedHeaderPageLayout from '../../../components/IllustratedHeaderPageLayout';
+import themeColors from '../../../styles/themes/default';
+import SCREENS from '../../../SCREENS';
+import * as LottieAnimations from '../../../components/LottieAnimations';
+import useWindowDimensions from '../../../hooks/useWindowDimensions';
+import ONYXKEYS from '../../../ONYXKEYS';
+import useLocalize from '../../../hooks/useLocalize';
+import ROUTES from '../../../ROUTES';
+import CONST from '../../../CONST';
+import assignedCardPropTypes from './assignedCardPropTypes';
+import * as CardUtils from '../../../libs/CardUtils';
+import useNetwork from '../../../hooks/useNetwork';
+import NotFoundPage from '../../ErrorPage/NotFoundPage';
+
+const propTypes = {
+ /* Onyx Props */
+
+ /** The details about the Expensify cards */
+ cardList: PropTypes.objectOf(assignedCardPropTypes),
+
+ /** Navigation route context info provided by react navigation */
+ route: PropTypes.shape({
+ params: PropTypes.shape({
+ /** domain passed via route /settings/wallet/card/:domain */
+ domain: PropTypes.string,
+ }),
+ }).isRequired,
+};
+
+const defaultProps = {
+ cardList: {},
+};
+
+const LAST_FOUR_DIGITS_LENGTH = 4;
+const MAGIC_INPUT_MIN_HEIGHT = 86;
+
+function ActivatePhysicalCardPage({
+ cardList,
+ route: {
+ params: {domain},
+ },
+}) {
+ const {isExtraSmallScreenHeight} = useWindowDimensions();
+ const {translate} = useLocalize();
+ const {isOffline} = useNetwork();
+
+ const [formError, setFormError] = useState('');
+ const [lastFourDigits, setLastFourDigits] = useState('');
+ const [lastPressedDigit, setLastPressedDigit] = useState('');
+
+ const domainCards = CardUtils.getDomainCards(cardList)[domain];
+ const physicalCard = _.find(domainCards, (card) => !card.isVirtual) || {};
+ const cardID = lodashGet(physicalCard, 'cardID', 0);
+ const cardError = ErrorUtils.getLatestErrorMessage(physicalCard);
+
+ const activateCardCodeInputRef = useRef(null);
+
+ /**
+ * If state of the card is CONST.EXPENSIFY_CARD.STATE.OPEN, navigate to card details screen.
+ */
+ useEffect(() => {
+ if (physicalCard.isLoading || lodashGet(cardList, `${cardID}.state`, 0) !== CONST.EXPENSIFY_CARD.STATE.OPEN) {
+ return;
+ }
+
+ Navigation.navigate(ROUTES.SETTINGS_WALLET_DOMAINCARDS.getRoute(domain));
+ }, [cardID, cardList, domain, physicalCard.isLoading]);
+
+ useEffect(
+ () => () => {
+ CardSettings.clearCardListErrors(cardID);
+ },
+ [cardID],
+ );
+
+ /**
+ * Update lastPressedDigit with value that was pressed on BigNumberPad.
+ *
+ * NOTE: If the same digit is pressed twice in a row, append it to the end of the string
+ * so that useEffect inside MagicCodeInput will be triggered by artificial change of the value.
+ *
+ * @param {String} key
+ */
+ const updateLastPressedDigit = useCallback((key) => setLastPressedDigit(lastPressedDigit === key ? lastPressedDigit + key : key), [lastPressedDigit]);
+
+ /**
+ * Handle card activation code input
+ *
+ * @param {String} text
+ */
+ const onCodeInput = (text) => {
+ setFormError('');
+
+ if (cardError) {
+ CardSettings.clearCardListErrors(cardID);
+ }
+
+ setLastFourDigits(text);
+ };
+
+ const submitAndNavigateToNextPage = useCallback(() => {
+ activateCardCodeInputRef.current.blur();
+
+ if (lastFourDigits.replace(CONST.MAGIC_CODE_EMPTY_CHAR, '').length !== LAST_FOUR_DIGITS_LENGTH) {
+ setFormError(translate('activateCardPage.error.thatDidntMatch'));
+ return;
+ }
+
+ CardSettings.activatePhysicalExpensifyCard(Number(lastFourDigits), cardID);
+ }, [lastFourDigits, cardID, translate]);
+
+ if (_.isEmpty(physicalCard)) {
+ return ;
+ }
+
+ return (
+ Navigation.navigate(ROUTES.SETTINGS_WALLET_DOMAINCARDS.getRoute(domain))}
+ backgroundColor={themeColors.PAGE_BACKGROUND_COLORS[SCREENS.SETTINGS.PREFERENCES]}
+ illustration={LottieAnimations.Magician}
+ scrollViewContainerStyles={[styles.mnh100]}
+ childrenContainerStyles={[styles.flex1]}
+ >
+ {translate('activateCardPage.pleaseEnterLastFour')}
+
+
+
+
+ {DeviceCapabilities.canUseTouchScreen() && }
+
+
+
+ );
+}
+
+ActivatePhysicalCardPage.propTypes = propTypes;
+ActivatePhysicalCardPage.defaultProps = defaultProps;
+ActivatePhysicalCardPage.displayName = 'ActivatePhysicalCardPage';
+
+export default withOnyx({
+ cardList: {
+ key: ONYXKEYS.CARD_LIST,
+ },
+})(ActivatePhysicalCardPage);
diff --git a/src/pages/settings/Wallet/ExpensifyCardPage.js b/src/pages/settings/Wallet/ExpensifyCardPage.js
index 026e8147d79f..cfbd26133ced 100644
--- a/src/pages/settings/Wallet/ExpensifyCardPage.js
+++ b/src/pages/settings/Wallet/ExpensifyCardPage.js
@@ -10,17 +10,20 @@ import CardPreview from '../../../components/CardPreview';
import HeaderWithBackButton from '../../../components/HeaderWithBackButton';
import MenuItemWithTopDescription from '../../../components/MenuItemWithTopDescription';
import ScreenWrapper from '../../../components/ScreenWrapper';
-import assignedCardPropTypes from './assignedCardPropTypes';
import useLocalize from '../../../hooks/useLocalize';
import * as CurrencyUtils from '../../../libs/CurrencyUtils';
import Navigation from '../../../libs/Navigation/Navigation';
import styles from '../../../styles/styles';
+import * as Expensicons from '../../../components/Icon/Expensicons';
import * as CardUtils from '../../../libs/CardUtils';
import Button from '../../../components/Button';
import CardDetails from './WalletPage/CardDetails';
+import CONST from '../../../CONST';
+import assignedCardPropTypes from './assignedCardPropTypes';
const propTypes = {
/* Onyx Props */
+ /** The details about the Expensify cards */
cardList: PropTypes.objectOf(assignedCardPropTypes),
/** Navigation route context info provided by react navigation */
@@ -106,6 +109,13 @@ function ExpensifyCardPage({
}
/>
)}
+ Navigation.navigate(ROUTES.SETTINGS_REPORT_FRAUD.getRoute(domain))}
+ />
>
)}
{!_.isEmpty(physicalCard) && (
@@ -113,10 +123,18 @@ function ExpensifyCardPage({
description={translate('cardPage.physicalCardNumber')}
title={CardUtils.maskCard(physicalCard.lastFourPAN)}
interactive={false}
- titleStyle={styles.walletCardNumber}
+ titleStyle={styles.walletCardMenuItem}
/>
)}
+ {physicalCard.state === CONST.EXPENSIFY_CARD.STATE.NOT_ACTIVATED && (
+ Navigation.navigate(ROUTES.SETTINGS_WALLET_CARD_ACTIVATE.getRoute(domain))}
+ text={translate('activateCardPage.activatePhysicalCard')}
+ />
+ )}
>
)}
diff --git a/src/pages/settings/Wallet/ReportVirtualCardFraudPage.js b/src/pages/settings/Wallet/ReportVirtualCardFraudPage.js
new file mode 100644
index 000000000000..2652494aa1c7
--- /dev/null
+++ b/src/pages/settings/Wallet/ReportVirtualCardFraudPage.js
@@ -0,0 +1,104 @@
+import React, {useEffect} from 'react';
+import _ from 'underscore';
+import {View} from 'react-native';
+import PropTypes from 'prop-types';
+import {withOnyx} from 'react-native-onyx';
+import ROUTES from '../../../ROUTES';
+import HeaderWithBackButton from '../../../components/HeaderWithBackButton';
+import ScreenWrapper from '../../../components/ScreenWrapper';
+import Navigation from '../../../libs/Navigation/Navigation';
+import styles from '../../../styles/styles';
+import Text from '../../../components/Text';
+import useLocalize from '../../../hooks/useLocalize';
+import * as Card from '../../../libs/actions/Card';
+import assignedCardPropTypes from './assignedCardPropTypes';
+import * as CardUtils from '../../../libs/CardUtils';
+import ONYXKEYS from '../../../ONYXKEYS';
+import NotFoundPage from '../../ErrorPage/NotFoundPage';
+import usePrevious from '../../../hooks/usePrevious';
+import FormAlertWithSubmitButton from '../../../components/FormAlertWithSubmitButton';
+import * as ErrorUtils from '../../../libs/ErrorUtils';
+
+const propTypes = {
+ /* Onyx Props */
+ formData: PropTypes.shape({
+ isLoading: PropTypes.bool,
+ }),
+ cardList: PropTypes.objectOf(assignedCardPropTypes),
+ /** The parameters needed to authenticate with a short-lived token are in the URL */
+ route: PropTypes.shape({
+ /** Each parameter passed via the URL */
+ params: PropTypes.shape({
+ /** Domain string */
+ domain: PropTypes.string,
+ }),
+ }).isRequired,
+};
+
+const defaultProps = {
+ cardList: {},
+ formData: {},
+};
+
+function ReportVirtualCardFraudPage({
+ route: {
+ params: {domain},
+ },
+ cardList,
+ formData,
+}) {
+ const {translate} = useLocalize();
+
+ const domainCards = CardUtils.getDomainCards(cardList)[domain];
+ const virtualCard = _.find(domainCards, (card) => card.isVirtual) || {};
+ const virtualCardError = ErrorUtils.getLatestErrorMessage(virtualCard) || '';
+
+ const prevIsLoading = usePrevious(formData.isLoading);
+
+ useEffect(() => {
+ if (!prevIsLoading || formData.isLoading) {
+ return;
+ }
+ if (!_.isEmpty(virtualCard.errors)) {
+ return;
+ }
+
+ Navigation.navigate(ROUTES.SETTINGS_WALLET_DOMAINCARDS.getRoute(domain));
+ }, [domain, formData.isLoading, prevIsLoading, virtualCard.errors]);
+
+ if (_.isEmpty(virtualCard)) {
+ return ;
+ }
+
+ return (
+
+ Navigation.goBack(ROUTES.SETTINGS_WALLET_DOMAINCARDS.getRoute(domain))}
+ />
+
+ {translate('reportFraudPage.description')}
+ Card.reportVirtualExpensifyCardFraud(virtualCard.cardID)}
+ message={virtualCardError}
+ isLoading={formData.isLoading}
+ buttonText={translate('reportFraudPage.deactivateCard')}
+ />
+
+
+ );
+}
+
+ReportVirtualCardFraudPage.propTypes = propTypes;
+ReportVirtualCardFraudPage.defaultProps = defaultProps;
+ReportVirtualCardFraudPage.displayName = 'ReportVirtualCardFraudPage';
+
+export default withOnyx({
+ cardList: {
+ key: ONYXKEYS.CARD_LIST,
+ },
+ formData: {
+ key: ONYXKEYS.FORMS.REPORT_VIRTUAL_CARD_FRAUD,
+ },
+})(ReportVirtualCardFraudPage);
diff --git a/src/pages/settings/Wallet/assignedCardPropTypes.js b/src/pages/settings/Wallet/assignedCardPropTypes.js
index 2f0eb1ad4ec9..06779e473579 100644
--- a/src/pages/settings/Wallet/assignedCardPropTypes.js
+++ b/src/pages/settings/Wallet/assignedCardPropTypes.js
@@ -15,6 +15,7 @@ const assignedCardPropTypes = PropTypes.shape({
cardholderFirstName: PropTypes.string,
cardholderLastName: PropTypes.string,
errors: PropTypes.objectOf(PropTypes.string),
+ isLoading: PropTypes.bool,
});
export default assignedCardPropTypes;
diff --git a/src/pages/workspace/WorkspaceInvitePage.js b/src/pages/workspace/WorkspaceInvitePage.js
index 39495911b8dc..e7bbd9657e8b 100644
--- a/src/pages/workspace/WorkspaceInvitePage.js
+++ b/src/pages/workspace/WorkspaceInvitePage.js
@@ -18,6 +18,7 @@ import withPolicy, {policyDefaultProps, policyPropTypes} from './withPolicy';
import FullPageNotFoundView from '../../components/BlockingViews/FullPageNotFoundView';
import ROUTES from '../../ROUTES';
import * as PolicyUtils from '../../libs/PolicyUtils';
+import * as Browser from '../../libs/Browser';
import useNetwork from '../../hooks/useNetwork';
import useLocalize from '../../hooks/useLocalize';
import SelectionList from '../../components/SelectionList';
@@ -231,6 +232,7 @@ function WorkspaceInvitePage(props) {
onConfirm={inviteUser}
showScrollIndicator
showLoadingPlaceholder={!didScreenTransitionEnd || !OptionsListUtils.isPersonalDetailsReady(props.personalDetails)}
+ shouldPreventDefaultFocusOnSelectRow={!Browser.isMobile()}
/>
_.keys(props.policyMembers), [props.policyMembers]);
const prevAccountIDs = usePrevious(accountIDs);
const textInputRef = useRef(null);
-
+ const isOfflineAndNoMemberDataAvailable = _.isEmpty(props.policyMembers) && props.network.isOffline;
/**
* Get members for the current workspace
*/
@@ -344,9 +344,14 @@ function WorkspaceMembersPage(props) {
return result;
};
-
const data = getMemberOptions();
- const headerMessage = searchValue.trim() && !data.length ? props.translate('workspace.common.memberNotFound') : '';
+
+ const getHeaderMessage = () => {
+ if (isOfflineAndNoMemberDataAvailable) {
+ return props.translate('workspace.common.mustBeOnlineToViewMembers');
+ }
+ return searchValue.trim() && !data.length ? props.translate('workspace.common.memberNotFound') : '';
+ };
return (
toggleUser(item.keyForList)}
onSelectAll={() => toggleAllUsers(data)}
onDismissError={dismissError}
- showLoadingPlaceholder={!OptionsListUtils.isPersonalDetailsReady(props.personalDetails) || _.isEmpty(props.policyMembers)}
+ showLoadingPlaceholder={!isOfflineAndNoMemberDataAvailable && (!OptionsListUtils.isPersonalDetailsReady(props.personalDetails) || _.isEmpty(props.policyMembers))}
showScrollIndicator
- shouldFocusOnSelectRow={!Browser.isMobile()}
+ shouldPreventDefaultFocusOnSelectRow={!Browser.isMobile()}
inputRef={textInputRef}
/>
diff --git a/src/styles/fontFamily/bold/index.android.js b/src/styles/fontFamily/bold/index.android.js
index 7473e4d7533c..73ba56dc4262 100644
--- a/src/styles/fontFamily/bold/index.android.js
+++ b/src/styles/fontFamily/bold/index.android.js
@@ -1,3 +1,4 @@
-const bold = 'ExpensifyNeue-Bold';
+const singleBold = 'ExpensifyNeue-Bold';
+const multiBold = 'ExpensifyNeue-Bold';
-export default bold;
+export {singleBold, multiBold};
diff --git a/src/styles/fontFamily/bold/index.ios.js b/src/styles/fontFamily/bold/index.ios.js
index 3ba35f200d3d..a0523831a058 100644
--- a/src/styles/fontFamily/bold/index.ios.js
+++ b/src/styles/fontFamily/bold/index.ios.js
@@ -1,3 +1,4 @@
-const bold = 'ExpensifyNeue-Regular';
+const singleBold = 'ExpensifyNeue-Regular';
+const multiBold = 'ExpensifyNeue-Regular';
-export default bold;
+export {singleBold, multiBold};
diff --git a/src/styles/fontFamily/bold/index.js b/src/styles/fontFamily/bold/index.js
index 66d3c64f3565..401a808d29d6 100644
--- a/src/styles/fontFamily/bold/index.js
+++ b/src/styles/fontFamily/bold/index.js
@@ -1,3 +1,4 @@
-const bold = 'ExpensifyNeue-Regular, Segoe UI Emoji, Noto Color Emoji';
+const singleBold = 'ExpensifyNeue-Regular';
+const multiBold = 'ExpensifyNeue-Regular, Segoe UI Emoji, Noto Color Emoji';
-export default bold;
+export {singleBold, multiBold};
diff --git a/src/styles/fontFamily/index.native.ts b/src/styles/fontFamily/index.native.ts
index 0d6c253eb3a6..53f421a58535 100644
--- a/src/styles/fontFamily/index.native.ts
+++ b/src/styles/fontFamily/index.native.ts
@@ -1,17 +1,3 @@
-import bold from './bold';
-import FontFamilyStyles from './types';
+import singleFontFamily from './singleFontFamily';
-const fontFamily: FontFamilyStyles = {
- EXP_NEUE_ITALIC: 'ExpensifyNeue-Italic',
- EXP_NEUE_BOLD: bold,
- EXP_NEUE: 'ExpensifyNeue-Regular',
- EXP_NEW_KANSAS_MEDIUM: 'ExpensifyNewKansas-Medium',
- EXP_NEW_KANSAS_MEDIUM_ITALIC: 'ExpensifyNewKansas-MediumItalic',
- SYSTEM: 'System',
- MONOSPACE: 'ExpensifyMono-Regular',
- MONOSPACE_ITALIC: 'ExpensifyMono-Regular',
- MONOSPACE_BOLD: 'ExpensifyMono-Bold',
- MONOSPACE_BOLD_ITALIC: 'ExpensifyMono-Bold',
-};
-
-export default fontFamily;
+export default singleFontFamily;
diff --git a/src/styles/fontFamily/index.ts b/src/styles/fontFamily/index.ts
index 57d08ce28771..7a8267eba1a5 100644
--- a/src/styles/fontFamily/index.ts
+++ b/src/styles/fontFamily/index.ts
@@ -1,19 +1,3 @@
-import bold from './bold';
-import FontFamilyStyles from './types';
+import multiFontFamily from './multiFontFamily';
-// In windows and ubuntu, we need some extra system fonts for emojis to work properly
-// otherwise few of them will appear as black and white
-const fontFamily: FontFamilyStyles = {
- EXP_NEUE_ITALIC: 'ExpensifyNeue-Italic, Segoe UI Emoji, Noto Color Emoji',
- EXP_NEUE_BOLD: bold,
- EXP_NEUE: 'ExpensifyNeue-Regular, Segoe UI Emoji, Noto Color Emoji',
- EXP_NEW_KANSAS_MEDIUM: 'ExpensifyNewKansas-Medium, Segoe UI Emoji, Noto Color Emoji',
- EXP_NEW_KANSAS_MEDIUM_ITALIC: 'ExpensifyNewKansas-MediumItalic, Segoe UI Emoji, Noto Color Emoji',
- SYSTEM: 'System',
- MONOSPACE: 'ExpensifyMono-Regular, Segoe UI Emoji, Noto Color Emoji',
- MONOSPACE_ITALIC: 'ExpensifyMono-Regular, Segoe UI Emoji, Noto Color Emoji',
- MONOSPACE_BOLD: 'ExpensifyMono-Bold, Segoe UI Emoji, Noto Color Emoji',
- MONOSPACE_BOLD_ITALIC: 'ExpensifyMono-Bold, Segoe UI Emoji, Noto Color Emoji',
-};
-
-export default fontFamily;
+export default multiFontFamily;
diff --git a/src/styles/fontFamily/multiFontFamily.ts b/src/styles/fontFamily/multiFontFamily.ts
new file mode 100644
index 000000000000..2edd17548354
--- /dev/null
+++ b/src/styles/fontFamily/multiFontFamily.ts
@@ -0,0 +1,19 @@
+import {multiBold} from './bold';
+import FontFamilyStyles from './types';
+
+// In windows and ubuntu, we need some extra system fonts for emojis to work properly
+// otherwise few of them will appear as black and white
+const fontFamily: FontFamilyStyles = {
+ EXP_NEUE_ITALIC: 'ExpensifyNeue-Italic, Segoe UI Emoji, Noto Color Emoji',
+ EXP_NEUE_BOLD: multiBold,
+ EXP_NEUE: 'ExpensifyNeue-Regular, Segoe UI Emoji, Noto Color Emoji',
+ EXP_NEW_KANSAS_MEDIUM: 'ExpensifyNewKansas-Medium, Segoe UI Emoji, Noto Color Emoji',
+ EXP_NEW_KANSAS_MEDIUM_ITALIC: 'ExpensifyNewKansas-MediumItalic, Segoe UI Emoji, Noto Color Emoji',
+ SYSTEM: 'System',
+ MONOSPACE: 'ExpensifyMono-Regular, Segoe UI Emoji, Noto Color Emoji',
+ MONOSPACE_ITALIC: 'ExpensifyMono-Regular, Segoe UI Emoji, Noto Color Emoji',
+ MONOSPACE_BOLD: 'ExpensifyMono-Bold, Segoe UI Emoji, Noto Color Emoji',
+ MONOSPACE_BOLD_ITALIC: 'ExpensifyMono-Bold, Segoe UI Emoji, Noto Color Emoji',
+};
+
+export default fontFamily;
diff --git a/src/styles/fontFamily/singleFontFamily.ts b/src/styles/fontFamily/singleFontFamily.ts
new file mode 100644
index 000000000000..6d5b05a5b0aa
--- /dev/null
+++ b/src/styles/fontFamily/singleFontFamily.ts
@@ -0,0 +1,17 @@
+import {singleBold} from './bold';
+import FontFamilyStyles from './types';
+
+const fontFamily: FontFamilyStyles = {
+ EXP_NEUE_ITALIC: 'ExpensifyNeue-Italic',
+ EXP_NEUE_BOLD: singleBold,
+ EXP_NEUE: 'ExpensifyNeue-Regular',
+ EXP_NEW_KANSAS_MEDIUM: 'ExpensifyNewKansas-Medium',
+ EXP_NEW_KANSAS_MEDIUM_ITALIC: 'ExpensifyNewKansas-MediumItalic',
+ SYSTEM: 'System',
+ MONOSPACE: 'ExpensifyMono-Regular',
+ MONOSPACE_ITALIC: 'ExpensifyMono-Regular',
+ MONOSPACE_BOLD: 'ExpensifyMono-Bold',
+ MONOSPACE_BOLD_ITALIC: 'ExpensifyMono-Bold',
+};
+
+export default fontFamily;
diff --git a/src/styles/getTooltipStyles.ts b/src/styles/getTooltipStyles.ts
index 97402467ab4c..be76002bd216 100644
--- a/src/styles/getTooltipStyles.ts
+++ b/src/styles/getTooltipStyles.ts
@@ -257,6 +257,7 @@ export default function getTooltipStyles(
fontSize: variables.fontSizeSmall,
overflow: 'hidden',
lineHeight: variables.lineHeightSmall,
+ textAlign: 'center',
},
pointerWrapperStyle: {
position: 'fixed',
diff --git a/src/styles/styles.js b/src/styles/styles.js
index 12f8c3052557..7340350114ed 100644
--- a/src/styles/styles.js
+++ b/src/styles/styles.js
@@ -1782,7 +1782,6 @@ const styles = (theme) => ({
},
emojiSkinToneTitle: {
- width: '100%',
...spacing.pv1,
fontFamily: fontFamily.EXP_NEUE_BOLD,
fontWeight: fontWeightBold,
@@ -2533,6 +2532,7 @@ const styles = (theme) => ({
// However, it is not possible to override the background-color directly as explained in this resource: https://developer.mozilla.org/en-US/docs/Web/CSS/:autofill
// Therefore, the transition effect needs to be delayed.
transitionDelay: '99999s',
+ transitionProperty: 'background-color',
}
: {}),
},
@@ -3784,7 +3784,7 @@ const styles = (theme) => ({
overflow: 'hidden',
},
- walletCardNumber: {
+ walletCardMenuItem: {
color: theme.text,
fontSize: variables.fontSizeNormal,
},
diff --git a/src/styles/utilities/spacing.ts b/src/styles/utilities/spacing.ts
index b635b7cc39a6..f0fbe4b4591a 100644
--- a/src/styles/utilities/spacing.ts
+++ b/src/styles/utilities/spacing.ts
@@ -207,6 +207,10 @@ export default {
marginTop: 'auto',
},
+ mtn6: {
+ marginTop: -24,
+ },
+
mb0: {
marginBottom: 0,
},
diff --git a/src/types/onyx/Card.ts b/src/types/onyx/Card.ts
index e7bf417fccc0..be9c31845acd 100644
--- a/src/types/onyx/Card.ts
+++ b/src/types/onyx/Card.ts
@@ -18,6 +18,7 @@ type Card = {
cardholderFirstName: string;
cardholderLastName: string;
errors?: OnyxCommon.Errors;
+ isLoading?: boolean;
};
export default Card;
diff --git a/src/types/onyx/IOU.ts b/src/types/onyx/IOU.ts
index 7151bb84d1f1..a89b0d4530ef 100644
--- a/src/types/onyx/IOU.ts
+++ b/src/types/onyx/IOU.ts
@@ -16,7 +16,7 @@ type IOU = {
merchant?: string;
created?: string;
receiptPath?: string;
- receiptSource?: string;
+ receiptFilename?: string;
transactionID?: string;
participants?: Participant[];
tag?: string;
diff --git a/src/types/onyx/OriginalMessage.ts b/src/types/onyx/OriginalMessage.ts
index 143b70127de5..e03775ee114e 100644
--- a/src/types/onyx/OriginalMessage.ts
+++ b/src/types/onyx/OriginalMessage.ts
@@ -53,6 +53,10 @@ type OriginalMessageAddComment = {
reactions?: Reaction[];
};
};
+type OriginalMessageSubmitted = {
+ actionName: typeof CONST.REPORT.ACTIONS.TYPE.SUBMITTED;
+ originalMessage: unknown;
+};
type OriginalMessageClosed = {
actionName: typeof CONST.REPORT.ACTIONS.TYPE.CLOSED;
@@ -127,6 +131,7 @@ type OriginalMessagePolicyTask = {
type OriginalMessage =
| OriginalMessageIOU
| OriginalMessageAddComment
+ | OriginalMessageSubmitted
| OriginalMessageClosed
| OriginalMessageCreated
| OriginalMessageRenamed
diff --git a/src/types/onyx/Policy.ts b/src/types/onyx/Policy.ts
index df4a1364a894..12b4cb92024e 100644
--- a/src/types/onyx/Policy.ts
+++ b/src/types/onyx/Policy.ts
@@ -47,6 +47,12 @@ type Policy = {
/** Whether policy expense chats can be created and used on this policy. Enabled manually by CQ/JS snippet. Always true for free policies. */
isPolicyExpenseChatEnabled: boolean;
+
+ /** Whether the scheduled submit is enabled */
+ autoReporting: boolean;
+
+ /** The scheduled submit frequency set up on the this policy */
+ autoReportingFrequency: ValueOf;
};
export default Policy;
diff --git a/tests/perf-test/SidebarLinks.perf-test.js b/tests/perf-test/SidebarLinks.perf-test.js
index 87d2648f78dd..1772c20fbf72 100644
--- a/tests/perf-test/SidebarLinks.perf-test.js
+++ b/tests/perf-test/SidebarLinks.perf-test.js
@@ -1,57 +1,122 @@
import {measurePerformance} from 'reassure';
import Onyx from 'react-native-onyx';
+import {fireEvent, screen} from '@testing-library/react-native';
import _ from 'underscore';
import * as LHNTestUtils from '../utils/LHNTestUtils';
import CONST from '../../src/CONST';
+import ONYXKEYS from '../../src/ONYXKEYS';
import waitForBatchedUpdates from '../utils/waitForBatchedUpdates';
+import wrapOnyxWithWaitForBatchedUpdates from '../utils/wrapOnyxWithWaitForBatchedUpdates';
+import variables from '../../src/styles/variables';
+
+jest.setTimeout(10000);
jest.mock('../../src/libs/Permissions');
+jest.mock('../../src/libs/Navigation/Navigation');
jest.mock('../../src/components/Icon/Expensicons');
-const ONYXKEYS = {
- PERSONAL_DETAILS: 'personalDetails',
- NVP_PRIORITY_MODE: 'nvp_priorityMode',
- SESSION: 'session',
- BETAS: 'betas',
- COLLECTION: {
- REPORT: 'report_',
- REPORT_ACTIONS: 'reportActions_',
- },
- NETWORK: 'network',
-};
+jest.mock('@react-navigation/native');
beforeAll(() =>
Onyx.init({
keys: ONYXKEYS,
+ safeEvictionKeys: [ONYXKEYS.COLLECTION.REPORT_ACTIONS],
registerStorageEventListener: () => {},
}),
);
// Initialize the network key for OfflineWithFeedback
-beforeEach(() => Onyx.merge(ONYXKEYS.NETWORK, {isOffline: false}));
+beforeEach(() => {
+ wrapOnyxWithWaitForBatchedUpdates(Onyx);
+ return Onyx.merge(ONYXKEYS.NETWORK, {isOffline: false});
+});
// Clear out Onyx after each test so that each test starts with a clean slate
afterEach(() => {
Onyx.clear();
});
-test('simple Sidebar render with hundred of reports', () => {
- const mockReports = Array.from({length: 100}, (__, i) => {
+const getMockedReportsMap = (length = 100) => {
+ const mockReports = Array.from({length}, (__, i) => {
const reportID = i + 1;
- const emails = [`email${reportID}@test.com`];
+ const participants = [1, 2];
const reportKey = `${ONYXKEYS.COLLECTION.REPORT}${reportID}`;
- const report = LHNTestUtils.getFakeReport(emails, 1, false);
+ const report = LHNTestUtils.getFakeReport(participants, 1, true);
+
return {[reportKey]: report};
});
- const mockOnyxReports = _.assign({}, ...mockReports);
+
+ return _.assign({}, ...mockReports);
+};
+
+const mockedResponseMap = getMockedReportsMap(500);
+
+test('should render Sidebar with 500 reports stored', () => {
+ const scenario = async () => {
+ // Query for the sidebar
+ await screen.findByTestId('lhn-options-list');
+ /**
+ * Query for display names of participants [1, 2].
+ * This will ensure that the sidebar renders a list of items.
+ */
+ await screen.findAllByText('One, Two');
+ };
+
+ return waitForBatchedUpdates()
+ .then(() =>
+ Onyx.multiSet({
+ [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.DEFAULT,
+ [ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails,
+ [ONYXKEYS.BETAS]: [CONST.BETAS.DEFAULT_ROOMS, CONST.BETAS.POLICY_ROOMS],
+ [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.GSD,
+ [ONYXKEYS.IS_LOADING_REPORT_DATA]: false,
+ ...mockedResponseMap,
+ }),
+ )
+ .then(() => measurePerformance( , {scenario}));
+});
+
+test('should scroll and click some of the items', () => {
+ const scenario = async () => {
+ const eventData = {
+ nativeEvent: {
+ contentOffset: {
+ y: variables.optionRowHeight * 5,
+ },
+ contentSize: {
+ // Dimensions of the scrollable content
+ height: variables.optionRowHeight * 10,
+ width: 100,
+ },
+ layoutMeasurement: {
+ // Dimensions of the device
+ height: variables.optionRowHeight * 5,
+ width: 100,
+ },
+ },
+ };
+
+ const lhnOptionsList = await screen.findByTestId('lhn-options-list');
+ expect(lhnOptionsList).toBeDefined();
+
+ fireEvent.scroll(lhnOptionsList, eventData);
+
+ const button1 = await screen.findByTestId('1');
+ const button2 = await screen.findByTestId('2');
+ fireEvent.press(button1);
+ fireEvent.press(button2);
+ };
return waitForBatchedUpdates()
.then(() =>
Onyx.multiSet({
[ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.DEFAULT,
[ONYXKEYS.PERSONAL_DETAILS_LIST]: LHNTestUtils.fakePersonalDetails,
- ...mockOnyxReports,
+ [ONYXKEYS.BETAS]: [CONST.BETAS.DEFAULT_ROOMS, CONST.BETAS.POLICY_ROOMS],
+ [ONYXKEYS.NVP_PRIORITY_MODE]: CONST.PRIORITY_MODE.GSD,
+ [ONYXKEYS.IS_LOADING_REPORT_DATA]: false,
+ ...mockedResponseMap,
}),
)
- .then(() => measurePerformance( ));
+ .then(() => measurePerformance( , {scenario}));
});
diff --git a/tests/unit/IOUUtilsTest.js b/tests/unit/IOUUtilsTest.js
index 9ea30638af87..9785acf68317 100644
--- a/tests/unit/IOUUtilsTest.js
+++ b/tests/unit/IOUUtilsTest.js
@@ -118,10 +118,10 @@ describe('isValidMoneyRequestType', () => {
test('Return true for valid iou type', () => {
expect(IOUUtils.isValidMoneyRequestType('request')).toBe(true);
expect(IOUUtils.isValidMoneyRequestType('split')).toBe(true);
+ expect(IOUUtils.isValidMoneyRequestType('send')).toBe(true);
});
test('Return false for invalid iou type', () => {
- expect(IOUUtils.isValidMoneyRequestType('send')).toBe(false);
expect(IOUUtils.isValidMoneyRequestType('money')).toBe(false);
});
});
diff --git a/tests/unit/ReportUtilsTest.js b/tests/unit/ReportUtilsTest.js
index 4704994bd1d2..c6afde7d9161 100644
--- a/tests/unit/ReportUtilsTest.js
+++ b/tests/unit/ReportUtilsTest.js
@@ -64,150 +64,40 @@ describe('ReportUtils', () => {
describe('getIconsForParticipants', () => {
it('returns sorted avatar source by name, then accountID', () => {
- expect(ReportUtils.getIconsForParticipants([1, 2, 3, 4, 5], participantsPersonalDetails)).toEqual([
- {
- id: 4,
- name: '(833) 240-3627',
- source: {
- testUri: '../../../assets/images/avatars/user/default-avatar_5.svg',
- },
- type: 'avatar',
- },
- {
- id: 2,
- name: 'floki@vikings.net',
- source: {
- testUri: '../../../assets/images/avatars/user/default-avatar_3.svg',
- },
- type: 'avatar',
- },
- {
- id: 3,
- name: 'Lagertha Lothbrok',
- source: {
- testUri: '../../../assets/images/avatars/user/default-avatar_4.svg',
- },
- type: 'avatar',
- },
- {
- id: 5,
- name: 'Lagertha Lothbrok',
- source: {
- testUri: '../../../assets/images/avatars/user/default-avatar_6.svg',
- },
- type: 'avatar',
- },
- {
- id: 1,
- name: 'Ragnar Lothbrok',
- source: {
- testUri: '../../../assets/images/avatars/user/default-avatar_2.svg',
- },
- type: 'avatar',
- },
- ]);
+ const participants = ReportUtils.getIconsForParticipants([1, 2, 3, 4, 5], participantsPersonalDetails);
+ expect(participants).toHaveLength(5);
+
+ expect(participants[0].source).toBeInstanceOf(Function);
+ expect(participants[0].name).toBe('(833) 240-3627');
+ expect(participants[0].id).toBe(4);
+ expect(participants[0].type).toBe('avatar');
+
+ expect(participants[1].source).toBeInstanceOf(Function);
+ expect(participants[1].name).toBe('floki@vikings.net');
+ expect(participants[1].id).toBe(2);
+ expect(participants[1].type).toBe('avatar');
});
});
describe('getDisplayNamesWithTooltips', () => {
test('withSingleParticipantReport', () => {
- expect(ReportUtils.getDisplayNamesWithTooltips(participantsPersonalDetails, false)).toStrictEqual([
- {
- displayName: 'Ragnar Lothbrok',
- login: 'ragnar@vikings.net',
- avatar: {
- testUri: '../../../assets/images/avatars/user/default-avatar_2.svg',
- },
- accountID: 1,
- pronouns: undefined,
- },
- {
- displayName: 'floki@vikings.net',
- avatar: {
- testUri: '../../../assets/images/avatars/user/default-avatar_3.svg',
- },
- login: 'floki@vikings.net',
- accountID: 2,
- pronouns: undefined,
- },
- {
- displayName: 'Lagertha Lothbrok',
- avatar: {
- testUri: '../../../assets/images/avatars/user/default-avatar_4.svg',
- },
- login: 'lagertha@vikings.net',
- accountID: 3,
- pronouns: 'She/her',
- },
- {
- displayName: '(833) 240-3627',
- avatar: {
- testUri: '../../../assets/images/avatars/user/default-avatar_5.svg',
- },
- login: '+18332403627@expensify.sms',
- accountID: 4,
- pronouns: undefined,
- },
- {
- displayName: 'Lagertha Lothbrok',
- avatar: {
- testUri: '../../../assets/images/avatars/user/default-avatar_6.svg',
- },
- login: 'lagertha2@vikings.net',
- accountID: 5,
- pronouns: 'She/her',
- },
- ]);
- });
-
- test('withMultiParticipantReport', () => {
- expect(ReportUtils.getDisplayNamesWithTooltips(participantsPersonalDetails, true)).toStrictEqual([
- {
- displayName: 'Ragnar',
- login: 'ragnar@vikings.net',
- avatar: {
- testUri: '../../../assets/images/avatars/user/default-avatar_2.svg',
- },
- accountID: 1,
- pronouns: undefined,
- },
- {
- displayName: 'floki@vikings.net',
- avatar: {
- testUri: '../../../assets/images/avatars/user/default-avatar_3.svg',
- },
- login: 'floki@vikings.net',
- accountID: 2,
- pronouns: undefined,
- },
- {
- displayName: 'Lagertha',
- avatar: {
- testUri: '../../../assets/images/avatars/user/default-avatar_4.svg',
- },
- login: 'lagertha@vikings.net',
- accountID: 3,
- pronouns: 'She/her',
- },
- {
- displayName: '(833) 240-3627',
- avatar: {
- testUri: '../../../assets/images/avatars/user/default-avatar_5.svg',
- },
- login: '+18332403627@expensify.sms',
- accountID: 4,
- pronouns: undefined,
- },
- {
- displayName: 'Lagertha',
- avatar: {
- testUri: '../../../assets/images/avatars/user/default-avatar_6.svg',
- },
- login: 'lagertha2@vikings.net',
- accountID: 5,
- pronouns: 'She/her',
- },
- ]);
+ const participants = ReportUtils.getDisplayNamesWithTooltips(participantsPersonalDetails, false);
+ expect(participants).toHaveLength(5);
+
+ expect(participants[0].avatar).toBeInstanceOf(Function);
+ expect(participants[0].displayName).toBe('Ragnar Lothbrok');
+ expect(participants[0].login).toBe('ragnar@vikings.net');
+ expect(participants[0].accountID).toBe(1);
+ expect(participants[0].pronouns).toBeUndefined();
+
+ expect(participants[2].avatar).toBeInstanceOf(Function);
+ expect(participants[2].displayName).toBe('Lagertha Lothbrok');
+ expect(participants[2].login).toBe('lagertha@vikings.net');
+ expect(participants[2].accountID).toBe(3);
+ expect(participants[2].pronouns).toBe('She/her');
+
+ expect(participants[3].displayName).toBe('(833) 240-3627');
+ expect(participants[3].login).toBe('+18332403627@expensify.sms');
});
});
diff --git a/tests/unit/ValidationUtilsTest.js b/tests/unit/ValidationUtilsTest.js
index 003e0ab75afe..a9e0b1b61128 100644
--- a/tests/unit/ValidationUtilsTest.js
+++ b/tests/unit/ValidationUtilsTest.js
@@ -253,6 +253,14 @@ describe('ValidationUtils', () => {
test('room name with spanish Accented letters and dashes', () => {
expect(ValidationUtils.isValidRoomName('#sala-de-opinión')).toBe(true);
});
+
+ test('room name with division sign (÷)', () => {
+ expect(ValidationUtils.isValidRoomName('#room-name-with-÷-sign')).toBe(false);
+ });
+
+ test('room name with Greek alphabets and Cyrillic alphabets', () => {
+ expect(ValidationUtils.isValidRoomName('#σοβαρός-серьезный')).toBe(true);
+ });
});
describe('isValidWebsite', () => {
diff --git a/tests/utils/LHNTestUtils.js b/tests/utils/LHNTestUtils.js
index 8689c7b65602..ce4edc75b444 100644
--- a/tests/utils/LHNTestUtils.js
+++ b/tests/utils/LHNTestUtils.js
@@ -6,6 +6,7 @@ import OnyxProvider from '../../src/components/OnyxProvider';
import {LocaleContextProvider} from '../../src/components/LocaleContextProvider';
import SidebarLinksData from '../../src/pages/home/sidebar/SidebarLinksData';
import {EnvironmentProvider} from '../../src/components/withEnvironment';
+import {CurrentReportIDContextProvider} from '../../src/components/withCurrentReportID';
import CONST from '../../src/CONST';
import DateUtils from '../../src/libs/DateUtils';
@@ -193,7 +194,7 @@ function getDefaultRenderedSidebarLinks(currentReportID = '') {
*/
function MockedSidebarLinks({currentReportID}) {
return (
-
+
{}}
/>
);