diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index e0f15db2..00000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "java.configuration.updateBuildConfiguration": "automatic" -} \ No newline at end of file diff --git a/apps/client/assets/images/DefaultPicture.jpg b/apps/client/assets/images/DefaultPicture.jpg deleted file mode 100644 index ef039c30..00000000 Binary files a/apps/client/assets/images/DefaultPicture.jpg and /dev/null differ diff --git a/apps/client/assets/images/agents/assistant.png b/apps/client/assets/images/agents/assistant.png deleted file mode 100644 index 43a73a46..00000000 Binary files a/apps/client/assets/images/agents/assistant.png and /dev/null differ diff --git a/apps/client/assets/images/agents/doctor.png b/apps/client/assets/images/agents/doctor.png deleted file mode 100644 index e4b67e84..00000000 Binary files a/apps/client/assets/images/agents/doctor.png and /dev/null differ diff --git a/apps/client/assets/images/agents/girlfriend.png b/apps/client/assets/images/agents/girlfriend.png deleted file mode 100644 index 3940a9ea..00000000 Binary files a/apps/client/assets/images/agents/girlfriend.png and /dev/null differ diff --git a/apps/client/assets/images/agents/interpreter.png b/apps/client/assets/images/agents/interpreter.png deleted file mode 100644 index fef1600b..00000000 Binary files a/apps/client/assets/images/agents/interpreter.png and /dev/null differ diff --git a/apps/client/assets/images/agents/lily.png b/apps/client/assets/images/agents/lily.png deleted file mode 100644 index c7492ff9..00000000 Binary files a/apps/client/assets/images/agents/lily.png and /dev/null differ diff --git a/apps/client/assets/images/agents/love_guru.png b/apps/client/assets/images/agents/love_guru.png deleted file mode 100644 index 0cb7caec..00000000 Binary files a/apps/client/assets/images/agents/love_guru.png and /dev/null differ diff --git a/apps/client/assets/images/agents/mei_hua.png b/apps/client/assets/images/agents/mei_hua.png deleted file mode 100644 index a51a542a..00000000 Binary files a/apps/client/assets/images/agents/mei_hua.png and /dev/null differ diff --git a/apps/client/assets/images/agents/shopping.png b/apps/client/assets/images/agents/shopping.png deleted file mode 100644 index 056bf31f..00000000 Binary files a/apps/client/assets/images/agents/shopping.png and /dev/null differ diff --git a/apps/client/assets/images/agents/socrates.png b/apps/client/assets/images/agents/socrates.png deleted file mode 100644 index 3a64b44e..00000000 Binary files a/apps/client/assets/images/agents/socrates.png and /dev/null differ diff --git a/apps/client/assets/images/agents/speaking_coach.png b/apps/client/assets/images/agents/speaking_coach.png deleted file mode 100644 index 8771f423..00000000 Binary files a/apps/client/assets/images/agents/speaking_coach.png and /dev/null differ diff --git a/apps/client/assets/images/agents/storyteller.png b/apps/client/assets/images/agents/storyteller.png deleted file mode 100644 index 47ef268a..00000000 Binary files a/apps/client/assets/images/agents/storyteller.png and /dev/null differ diff --git a/apps/client/assets/images/agents/tarot.png b/apps/client/assets/images/agents/tarot.png deleted file mode 100644 index ad503060..00000000 Binary files a/apps/client/assets/images/agents/tarot.png and /dev/null differ diff --git a/apps/client/assets/images/defaultPicture.png b/apps/client/assets/images/defaultPicture.png deleted file mode 100644 index 57953cc0..00000000 Binary files a/apps/client/assets/images/defaultPicture.png and /dev/null differ diff --git a/apps/client/assets/images/explore.png b/apps/client/assets/images/explore.png deleted file mode 100644 index b2673961..00000000 Binary files a/apps/client/assets/images/explore.png and /dev/null differ diff --git a/apps/client/assets/images/explore1.png b/apps/client/assets/images/explore1.png deleted file mode 100644 index 9a81a96c..00000000 Binary files a/apps/client/assets/images/explore1.png and /dev/null differ diff --git a/apps/client/assets/images/explore2.jpg b/apps/client/assets/images/explore2.jpg deleted file mode 100644 index 8b23189b..00000000 Binary files a/apps/client/assets/images/explore2.jpg and /dev/null differ diff --git a/apps/client/assets/images/glasses_light.png b/apps/client/assets/images/glasses_light.png deleted file mode 100644 index 13d66464..00000000 Binary files a/apps/client/assets/images/glasses_light.png and /dev/null differ diff --git a/apps/client/assets/images/music.png b/apps/client/assets/images/music.png deleted file mode 100644 index cc29d697..00000000 Binary files a/apps/client/assets/images/music.png and /dev/null differ diff --git a/apps/client/assets/images/qqmusic.png b/apps/client/assets/images/qqmusic.png deleted file mode 100644 index c90f96c1..00000000 Binary files a/apps/client/assets/images/qqmusic.png and /dev/null differ diff --git a/apps/client/assets/images/robot_light.png b/apps/client/assets/images/robot_light.png deleted file mode 100644 index 40bf9a9c..00000000 Binary files a/apps/client/assets/images/robot_light.png and /dev/null differ diff --git a/apps/client/assets/listening.mp3 b/apps/client/assets/listening.mp3 deleted file mode 100644 index cff159b4..00000000 Binary files a/apps/client/assets/listening.mp3 and /dev/null differ diff --git a/apps/client/assets/lottie/audio_wave.json b/apps/client/assets/lottie/audio_wave.json deleted file mode 100644 index 160c3fdd..00000000 --- a/apps/client/assets/lottie/audio_wave.json +++ /dev/null @@ -1 +0,0 @@ -{"v":"4.8.0","meta":{"g":"LottieFiles AE ","a":"","k":"","d":"","tc":""},"fr":60,"ip":0,"op":90,"w":512,"h":512,"nm":"sound wave","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 32","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[218.413,256,0],"ix":2},"a":{"a":0,"k":[23.382,5.347,0],"ix":1},"s":{"a":0,"k":[75,32,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-9,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-4,"s":[8,237]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":1,"s":[8,264.333]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":6,"s":[8,247.667]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":11,"s":[8,197]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":16,"s":[8,29]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":21,"s":[8,26]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":26,"s":[8,158.5]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":31,"s":[8,217]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":36,"s":[8,250]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":41,"s":[8,125]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":46,"s":[8,163.5]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":51,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":56,"s":[8,37]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":61,"s":[8,52]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":66,"s":[8,92]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":71,"s":[8,50]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":76,"s":[8,154]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":81,"s":[8,115]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":86,"s":[8,157]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":91,"s":[8,98]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":96,"s":[8,168]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":101,"s":[8,39]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":106,"s":[8,73]},{"t":110,"s":[8,27]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":4,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0.7490196078431373,0.6470588235294118,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":[23.382,5.347],"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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-9,"op":591,"st":-9,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"Shape Layer 31","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[203.678,256,0],"ix":2},"a":{"a":0,"k":[23.382,5.347,0],"ix":1},"s":{"a":0,"k":[75,46,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-14,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-9,"s":[8,237]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-4,"s":[8,264.333]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":1,"s":[8,247.667]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":6,"s":[8,197]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":11,"s":[8,29]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":16,"s":[8,26]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":21,"s":[8,158.5]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":26,"s":[8,217]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":31,"s":[8,250]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":36,"s":[8,125]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":41,"s":[8,163.5]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":46,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":51,"s":[8,37]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":56,"s":[8,52]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":61,"s":[8,92]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":66,"s":[8,50]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":71,"s":[8,154]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":76,"s":[8,115]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":81,"s":[8,157]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":86,"s":[8,98]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":91,"s":[8,168]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":96,"s":[8,39]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":101,"s":[8,73]},{"t":105,"s":[8,27]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":4,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0.7490196078431373,0.6470588235294118,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":[23.382,5.347],"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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-14,"op":586,"st":-14,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":"Shape Layer 34","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[26.86,256,0],"ix":2},"a":{"a":0,"k":[23.382,5.347,0],"ix":1},"s":{"a":0,"k":[75,18,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-32,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-27,"s":[8,237]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-22,"s":[8,264.333]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-17,"s":[8,247.667]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-12,"s":[8,197]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-7,"s":[8,29]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-2,"s":[8,26]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":3,"s":[8,158.5]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":8,"s":[8,217]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":13,"s":[8,250]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":18,"s":[8,125]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":23,"s":[8,163.5]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":28,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":33,"s":[8,37]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":38,"s":[8,52]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":43,"s":[8,92]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":48,"s":[8,50]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":53,"s":[8,154]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":58,"s":[8,115]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":63,"s":[8,157]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":68,"s":[8,98]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":73,"s":[8,168]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":78,"s":[8,39]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":83,"s":[8,73]},{"t":87,"s":[8,27]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":4,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0.7490196078431373,0.6470588235294118,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":[23.382,5.347],"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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-32,"op":568,"st":-32,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"Shape Layer 30","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[188.943,256,0],"ix":2},"a":{"a":0,"k":[23.382,5.347,0],"ix":1},"s":{"a":0,"k":[75,18,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-32,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-27,"s":[8,237]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-22,"s":[8,264.333]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-17,"s":[8,247.667]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-12,"s":[8,197]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-7,"s":[8,29]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-2,"s":[8,26]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":3,"s":[8,158.5]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":8,"s":[8,217]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":13,"s":[8,250]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":18,"s":[8,125]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":23,"s":[8,163.5]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":28,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":33,"s":[8,37]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":38,"s":[8,52]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":43,"s":[8,92]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":48,"s":[8,50]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":53,"s":[8,154]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":58,"s":[8,115]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":63,"s":[8,157]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":68,"s":[8,98]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":73,"s":[8,168]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":78,"s":[8,39]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":83,"s":[8,73]},{"t":87,"s":[8,27]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":4,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0.7490196078431373,0.6470588235294118,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":[23.382,5.347],"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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-32,"op":568,"st":-32,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Shape Layer 29","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[174.208,256,0],"ix":2},"a":{"a":0,"k":[23.382,5.347,0],"ix":1},"s":{"a":0,"k":[75,57,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-23,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-18,"s":[8,237]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-13,"s":[8,264.333]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-8,"s":[8,247.667]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-3,"s":[8,197]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":2,"s":[8,29]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":7,"s":[8,26]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":12,"s":[8,158.5]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":17,"s":[8,217]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":22,"s":[8,250]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":27,"s":[8,125]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":32,"s":[8,163.5]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":37,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":42,"s":[8,37]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":47,"s":[8,52]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":52,"s":[8,92]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":57,"s":[8,50]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":62,"s":[8,154]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":67,"s":[8,115]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":72,"s":[8,157]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":77,"s":[8,98]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":82,"s":[8,168]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":87,"s":[8,39]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":92,"s":[8,73]},{"t":96,"s":[8,27]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":4,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0.7490196078431373,0.6470588235294118,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":[23.382,5.347],"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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-23,"op":577,"st":-23,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"Shape Layer 28","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[159.473,256,0],"ix":2},"a":{"a":0,"k":[23.382,5.347,0],"ix":1},"s":{"a":0,"k":[75,57,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-29,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-24,"s":[8,237]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-19,"s":[8,264.333]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-14,"s":[8,247.667]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-9,"s":[8,197]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-4,"s":[8,29]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":1,"s":[8,26]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":6,"s":[8,158.5]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":11,"s":[8,217]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":16,"s":[8,250]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":21,"s":[8,125]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":26,"s":[8,163.5]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":31,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":36,"s":[8,37]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":41,"s":[8,52]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":46,"s":[8,92]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":51,"s":[8,50]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":56,"s":[8,154]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":61,"s":[8,115]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":66,"s":[8,157]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":71,"s":[8,98]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":76,"s":[8,168]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":81,"s":[8,39]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":86,"s":[8,73]},{"t":90,"s":[8,27]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":4,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0.7490196078431373,0.6470588235294118,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":[23.382,5.347],"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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-29,"op":571,"st":-29,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":"Shape Layer 35","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[12.125,256,0],"ix":2},"a":{"a":0,"k":[23.382,5.347,0],"ix":1},"s":{"a":0,"k":[75,76,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-32,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-27,"s":[8,237]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-22,"s":[8,264.333]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-17,"s":[8,247.667]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-12,"s":[8,197]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-7,"s":[8,29]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-2,"s":[8,26]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":3,"s":[8,158.5]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":8,"s":[8,217]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":13,"s":[8,250]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":18,"s":[8,125]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":23,"s":[8,163.5]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":28,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":33,"s":[8,37]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":38,"s":[8,52]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":43,"s":[8,92]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":48,"s":[8,50]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":53,"s":[8,154]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":58,"s":[8,115]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":63,"s":[8,157]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":68,"s":[8,98]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":73,"s":[8,168]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":78,"s":[8,39]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":83,"s":[8,73]},{"t":87,"s":[8,27]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":4,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0.7490196078431373,0.6470588235294118,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":[23.382,5.347],"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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-32,"op":568,"st":-32,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"Shape Layer 27","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[130.004,256,0],"ix":2},"a":{"a":0,"k":[23.382,5.347,0],"ix":1},"s":{"a":0,"k":[75,76,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-32,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-27,"s":[8,237]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-22,"s":[8,264.333]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-17,"s":[8,247.667]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-12,"s":[8,197]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-7,"s":[8,29]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-2,"s":[8,26]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":3,"s":[8,158.5]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":8,"s":[8,217]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":13,"s":[8,250]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":18,"s":[8,125]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":23,"s":[8,163.5]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":28,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":33,"s":[8,37]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":38,"s":[8,52]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":43,"s":[8,92]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":48,"s":[8,50]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":53,"s":[8,154]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":58,"s":[8,115]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":63,"s":[8,157]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":68,"s":[8,98]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":73,"s":[8,168]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":78,"s":[8,39]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":83,"s":[8,73]},{"t":87,"s":[8,27]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":4,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0.7490196078431373,0.6470588235294118,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":[23.382,5.347],"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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-32,"op":568,"st":-32,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"Shape Layer 26","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[144.739,256,0],"ix":2},"a":{"a":0,"k":[23.382,5.347,0],"ix":1},"s":{"a":0,"k":[75,30,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-40,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-35,"s":[8,237]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-30,"s":[8,264.333]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-25,"s":[8,247.667]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-20,"s":[8,197]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-15,"s":[8,29]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-10,"s":[8,26]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-5,"s":[8,158.5]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":0,"s":[8,217]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":5,"s":[8,250]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":10,"s":[8,125]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":15,"s":[8,163.5]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":20,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":25,"s":[8,37]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":30,"s":[8,52]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":35,"s":[8,92]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":40,"s":[8,50]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":45,"s":[8,154]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":50,"s":[8,115]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":55,"s":[8,157]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":60,"s":[8,98]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":65,"s":[8,168]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":70,"s":[8,39]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":75,"s":[8,73]},{"t":79,"s":[8,27]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":4,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0.7490196078431373,0.6470588235294118,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":[23.382,5.347],"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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-40,"op":560,"st":-40,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":"Shape Layer 25","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[115.269,256,0],"ix":2},"a":{"a":0,"k":[23.382,5.347,0],"ix":1},"s":{"a":0,"k":[75,47,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-46,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-41,"s":[8,237]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-36,"s":[8,264.333]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-31,"s":[8,247.667]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-26,"s":[8,197]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-21,"s":[8,29]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-16,"s":[8,26]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-11,"s":[8,158.5]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-6,"s":[8,217]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-1,"s":[8,250]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":4,"s":[8,125]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":9,"s":[8,163.5]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":14,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":19,"s":[8,37]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":24,"s":[8,52]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":29,"s":[8,92]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":34,"s":[8,50]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":39,"s":[8,154]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":44,"s":[8,115]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":49,"s":[8,157]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":54,"s":[8,98]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":59,"s":[8,168]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":64,"s":[8,39]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":69,"s":[8,73]},{"t":73,"s":[8,27]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":4,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0.7490196078431373,0.6470588235294118,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":[23.382,5.347],"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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-46,"op":554,"st":-46,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":"Shape Layer 24","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[100.534,256,0],"ix":2},"a":{"a":0,"k":[23.382,5.347,0],"ix":1},"s":{"a":0,"k":[75,27,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-30,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-25,"s":[8,237]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-20,"s":[8,264.333]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-15,"s":[8,247.667]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-10,"s":[8,197]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-5,"s":[8,29]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":0,"s":[8,26]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":5,"s":[8,158.5]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":10,"s":[8,217]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":15,"s":[8,250]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":20,"s":[8,125]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":25,"s":[8,163.5]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":30,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":35,"s":[8,37]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":40,"s":[8,52]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":45,"s":[8,92]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":50,"s":[8,50]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":55,"s":[8,154]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":60,"s":[8,115]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":65,"s":[8,157]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":70,"s":[8,98]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":75,"s":[8,168]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":80,"s":[8,39]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":85,"s":[8,73]},{"t":89,"s":[8,27]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":4,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0.7490196078431373,0.6470588235294118,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":[23.382,5.347],"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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-30,"op":570,"st":-30,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":"Shape Layer 23","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[85.799,256,0],"ix":2},"a":{"a":0,"k":[23.382,5.347,0],"ix":1},"s":{"a":0,"k":[75,18,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-35,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-30,"s":[8,237]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-25,"s":[8,264.333]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-20,"s":[8,247.667]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-15,"s":[8,197]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-10,"s":[8,29]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-5,"s":[8,26]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":0,"s":[8,158.5]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":5,"s":[8,217]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":10,"s":[8,250]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":15,"s":[8,125]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":20,"s":[8,163.5]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":25,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":30,"s":[8,37]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":35,"s":[8,52]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":40,"s":[8,92]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":45,"s":[8,50]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":50,"s":[8,154]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":55,"s":[8,115]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":60,"s":[8,157]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":65,"s":[8,98]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":70,"s":[8,168]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":75,"s":[8,39]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":80,"s":[8,73]},{"t":84,"s":[8,27]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":4,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0.7490196078431373,0.6470588235294118,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":[23.382,5.347],"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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-35,"op":565,"st":-35,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":"Shape Layer 22","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[71.064,256,0],"ix":2},"a":{"a":0,"k":[23.382,5.347,0],"ix":1},"s":{"a":0,"k":[75,28,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-21,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-16,"s":[8,237]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-11,"s":[8,264.333]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-6,"s":[8,247.667]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-1,"s":[8,197]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":4,"s":[8,29]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":9,"s":[8,26]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":14,"s":[8,158.5]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":19,"s":[8,217]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":24,"s":[8,250]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":29,"s":[8,125]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":34,"s":[8,163.5]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":39,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":44,"s":[8,37]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":49,"s":[8,52]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":54,"s":[8,92]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":59,"s":[8,50]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":64,"s":[8,154]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":69,"s":[8,115]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":74,"s":[8,157]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":79,"s":[8,98]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":84,"s":[8,168]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":89,"s":[8,39]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":94,"s":[8,73]},{"t":98,"s":[8,27]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":4,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0.7490196078431373,0.6470588235294118,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":[23.382,5.347],"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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-21,"op":579,"st":-21,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":"Shape Layer 21","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[56.33,256,0],"ix":2},"a":{"a":0,"k":[23.382,5.347,0],"ix":1},"s":{"a":0,"k":[75,37,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-19,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-14,"s":[8,237]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-9,"s":[8,264.333]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-4,"s":[8,247.667]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":1,"s":[8,197]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":6,"s":[8,29]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":11,"s":[8,26]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":16,"s":[8,158.5]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":21,"s":[8,217]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":26,"s":[8,250]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":31,"s":[8,125]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":36,"s":[8,163.5]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":41,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":46,"s":[8,37]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":51,"s":[8,52]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":56,"s":[8,92]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":61,"s":[8,50]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":66,"s":[8,154]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":71,"s":[8,115]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":76,"s":[8,157]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":81,"s":[8,98]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":86,"s":[8,168]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":91,"s":[8,39]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":96,"s":[8,73]},{"t":100,"s":[8,27]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":4,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0.7490196078431373,0.6470588235294118,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":[23.382,5.347],"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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-19,"op":581,"st":-19,"bm":0},{"ddd":0,"ind":15,"ty":4,"nm":"Shape Layer 20","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[498.375,256,0],"ix":2},"a":{"a":0,"k":[23.382,5.347,0],"ix":1},"s":{"a":0,"k":[75,32,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-9,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-4,"s":[8,237]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":1,"s":[8,264.333]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":6,"s":[8,247.667]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":11,"s":[8,197]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":16,"s":[8,29]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":21,"s":[8,26]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":26,"s":[8,158.5]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":31,"s":[8,217]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":36,"s":[8,250]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":41,"s":[8,125]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":46,"s":[8,163.5]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":51,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":56,"s":[8,37]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":61,"s":[8,52]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":66,"s":[8,92]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":71,"s":[8,50]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":76,"s":[8,154]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":81,"s":[8,115]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":86,"s":[8,157]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":91,"s":[8,98]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":96,"s":[8,168]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":101,"s":[8,39]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":106,"s":[8,73]},{"t":110,"s":[8,27]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":4,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0.7490196078431373,0.6470588235294118,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":[23.382,5.347],"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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-9,"op":591,"st":-9,"bm":0},{"ddd":0,"ind":16,"ty":4,"nm":"Shape Layer 19","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[483.64,256,0],"ix":2},"a":{"a":0,"k":[23.382,5.347,0],"ix":1},"s":{"a":0,"k":[75,46,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-14,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-9,"s":[8,237]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-4,"s":[8,264.333]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":1,"s":[8,247.667]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":6,"s":[8,197]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":11,"s":[8,29]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":16,"s":[8,26]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":21,"s":[8,158.5]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":26,"s":[8,217]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":31,"s":[8,250]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":36,"s":[8,125]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":41,"s":[8,163.5]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":46,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":51,"s":[8,37]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":56,"s":[8,52]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":61,"s":[8,92]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":66,"s":[8,50]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":71,"s":[8,154]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":76,"s":[8,115]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":81,"s":[8,157]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":86,"s":[8,98]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":91,"s":[8,168]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":96,"s":[8,39]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":101,"s":[8,73]},{"t":105,"s":[8,27]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":4,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0.7490196078431373,0.6470588235294118,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":[23.382,5.347],"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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-14,"op":586,"st":-14,"bm":0},{"ddd":0,"ind":17,"ty":4,"nm":"Shape Layer 18","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[468.905,256,0],"ix":2},"a":{"a":0,"k":[23.382,5.347,0],"ix":1},"s":{"a":0,"k":[75,18,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-32,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-27,"s":[8,237]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-22,"s":[8,264.333]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-17,"s":[8,247.667]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-12,"s":[8,197]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-7,"s":[8,29]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-2,"s":[8,26]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":3,"s":[8,158.5]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":8,"s":[8,217]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":13,"s":[8,250]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":18,"s":[8,125]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":23,"s":[8,163.5]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":28,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":33,"s":[8,37]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":38,"s":[8,52]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":43,"s":[8,92]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":48,"s":[8,50]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":53,"s":[8,154]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":58,"s":[8,115]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":63,"s":[8,157]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":68,"s":[8,98]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":73,"s":[8,168]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":78,"s":[8,39]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":83,"s":[8,73]},{"t":87,"s":[8,27]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":4,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0.7490196078431373,0.6470588235294118,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":[23.382,5.347],"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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-32,"op":568,"st":-32,"bm":0},{"ddd":0,"ind":18,"ty":4,"nm":"Shape Layer 17","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[454.17,256,0],"ix":2},"a":{"a":0,"k":[23.382,5.347,0],"ix":1},"s":{"a":0,"k":[75,57,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-23,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-18,"s":[8,237]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-13,"s":[8,264.333]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-8,"s":[8,247.667]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-3,"s":[8,197]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":2,"s":[8,29]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":7,"s":[8,26]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":12,"s":[8,158.5]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":17,"s":[8,217]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":22,"s":[8,250]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":27,"s":[8,125]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":32,"s":[8,163.5]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":37,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":42,"s":[8,37]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":47,"s":[8,52]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":52,"s":[8,92]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":57,"s":[8,50]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":62,"s":[8,154]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":67,"s":[8,115]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":72,"s":[8,157]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":77,"s":[8,98]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":82,"s":[8,168]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":87,"s":[8,39]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":92,"s":[8,73]},{"t":96,"s":[8,27]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":4,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0.7490196078431373,0.6470588235294118,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":[23.382,5.347],"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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-23,"op":577,"st":-23,"bm":0},{"ddd":0,"ind":19,"ty":4,"nm":"Shape Layer 16","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[439.436,256,0],"ix":2},"a":{"a":0,"k":[23.382,5.347,0],"ix":1},"s":{"a":0,"k":[75,57,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-29,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-24,"s":[8,237]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-19,"s":[8,264.333]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-14,"s":[8,247.667]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-9,"s":[8,197]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-4,"s":[8,29]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":1,"s":[8,26]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":6,"s":[8,158.5]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":11,"s":[8,217]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":16,"s":[8,250]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":21,"s":[8,125]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":26,"s":[8,163.5]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":31,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":36,"s":[8,37]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":41,"s":[8,52]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":46,"s":[8,92]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":51,"s":[8,50]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":56,"s":[8,154]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":61,"s":[8,115]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":66,"s":[8,157]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":71,"s":[8,98]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":76,"s":[8,168]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":81,"s":[8,39]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":86,"s":[8,73]},{"t":90,"s":[8,27]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":4,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0.7490196078431373,0.6470588235294118,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":[23.382,5.347],"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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-29,"op":571,"st":-29,"bm":0},{"ddd":0,"ind":20,"ty":4,"nm":"Shape Layer 15","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[409.966,256,0],"ix":2},"a":{"a":0,"k":[23.382,5.347,0],"ix":1},"s":{"a":0,"k":[75,76,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-32,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-27,"s":[8,237]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-22,"s":[8,264.333]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-17,"s":[8,247.667]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-12,"s":[8,197]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-7,"s":[8,29]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-2,"s":[8,26]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":3,"s":[8,158.5]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":8,"s":[8,217]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":13,"s":[8,250]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":18,"s":[8,125]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":23,"s":[8,163.5]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":28,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":33,"s":[8,37]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":38,"s":[8,52]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":43,"s":[8,92]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":48,"s":[8,50]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":53,"s":[8,154]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":58,"s":[8,115]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":63,"s":[8,157]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":68,"s":[8,98]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":73,"s":[8,168]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":78,"s":[8,39]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":83,"s":[8,73]},{"t":87,"s":[8,27]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":4,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0.7490196078431373,0.6470588235294118,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":[23.382,5.347],"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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-32,"op":568,"st":-32,"bm":0},{"ddd":0,"ind":21,"ty":4,"nm":"Shape Layer 14","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[424.701,256,0],"ix":2},"a":{"a":0,"k":[23.382,5.347,0],"ix":1},"s":{"a":0,"k":[75,30,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-40,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-35,"s":[8,237]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-30,"s":[8,264.333]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-25,"s":[8,247.667]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-20,"s":[8,197]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-15,"s":[8,29]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-10,"s":[8,26]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-5,"s":[8,158.5]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":0,"s":[8,217]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":5,"s":[8,250]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":10,"s":[8,125]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":15,"s":[8,163.5]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":20,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":25,"s":[8,37]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":30,"s":[8,52]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":35,"s":[8,92]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":40,"s":[8,50]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":45,"s":[8,154]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":50,"s":[8,115]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":55,"s":[8,157]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":60,"s":[8,98]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":65,"s":[8,168]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":70,"s":[8,39]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":75,"s":[8,73]},{"t":79,"s":[8,27]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":4,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0.7490196078431373,0.6470588235294118,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":[23.382,5.347],"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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-40,"op":560,"st":-40,"bm":0},{"ddd":0,"ind":22,"ty":4,"nm":"Shape Layer 13","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[395.231,256,0],"ix":2},"a":{"a":0,"k":[23.382,5.347,0],"ix":1},"s":{"a":0,"k":[75,47,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-46,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-41,"s":[8,237]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-36,"s":[8,264.333]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-31,"s":[8,247.667]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-26,"s":[8,197]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-21,"s":[8,29]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-16,"s":[8,26]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-11,"s":[8,158.5]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-6,"s":[8,217]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-1,"s":[8,250]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":4,"s":[8,125]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":9,"s":[8,163.5]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":14,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":19,"s":[8,37]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":24,"s":[8,52]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":29,"s":[8,92]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":34,"s":[8,50]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":39,"s":[8,154]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":44,"s":[8,115]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":49,"s":[8,157]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":54,"s":[8,98]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":59,"s":[8,168]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":64,"s":[8,39]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":69,"s":[8,73]},{"t":73,"s":[8,27]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":4,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0.7490196078431373,0.6470588235294118,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":[23.382,5.347],"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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-46,"op":554,"st":-46,"bm":0},{"ddd":0,"ind":23,"ty":4,"nm":"Shape Layer 12","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[380.496,256,0],"ix":2},"a":{"a":0,"k":[23.382,5.347,0],"ix":1},"s":{"a":0,"k":[75,27,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-30,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-25,"s":[8,237]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-20,"s":[8,264.333]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-15,"s":[8,247.667]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-10,"s":[8,197]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-5,"s":[8,29]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":0,"s":[8,26]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":5,"s":[8,158.5]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":10,"s":[8,217]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":15,"s":[8,250]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":20,"s":[8,125]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":25,"s":[8,163.5]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":30,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":35,"s":[8,37]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":40,"s":[8,52]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":45,"s":[8,92]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":50,"s":[8,50]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":55,"s":[8,154]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":60,"s":[8,115]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":65,"s":[8,157]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":70,"s":[8,98]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":75,"s":[8,168]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":80,"s":[8,39]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":85,"s":[8,73]},{"t":89,"s":[8,27]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":4,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0.7490196078431373,0.6470588235294118,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":[23.382,5.347],"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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-30,"op":570,"st":-30,"bm":0},{"ddd":0,"ind":24,"ty":4,"nm":"Shape Layer 11","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[365.761,256,0],"ix":2},"a":{"a":0,"k":[23.382,5.347,0],"ix":1},"s":{"a":0,"k":[75,18,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-35,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-30,"s":[8,237]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-25,"s":[8,264.333]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-20,"s":[8,247.667]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-15,"s":[8,197]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-10,"s":[8,29]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-5,"s":[8,26]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":0,"s":[8,158.5]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":5,"s":[8,217]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":10,"s":[8,250]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":15,"s":[8,125]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":20,"s":[8,163.5]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":25,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":30,"s":[8,37]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":35,"s":[8,52]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":40,"s":[8,92]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":45,"s":[8,50]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":50,"s":[8,154]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":55,"s":[8,115]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":60,"s":[8,157]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":65,"s":[8,98]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":70,"s":[8,168]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":75,"s":[8,39]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":80,"s":[8,73]},{"t":84,"s":[8,27]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":4,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0.7490196078431373,0.6470588235294118,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":[23.382,5.347],"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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-35,"op":565,"st":-35,"bm":0},{"ddd":0,"ind":25,"ty":4,"nm":"Shape Layer 10","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[351.027,256,0],"ix":2},"a":{"a":0,"k":[23.382,5.347,0],"ix":1},"s":{"a":0,"k":[75,28,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-21,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-16,"s":[8,237]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-11,"s":[8,264.333]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-6,"s":[8,247.667]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-1,"s":[8,197]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":4,"s":[8,29]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":9,"s":[8,26]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":14,"s":[8,158.5]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":19,"s":[8,217]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":24,"s":[8,250]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":29,"s":[8,125]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":34,"s":[8,163.5]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":39,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":44,"s":[8,37]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":49,"s":[8,52]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":54,"s":[8,92]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":59,"s":[8,50]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":64,"s":[8,154]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":69,"s":[8,115]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":74,"s":[8,157]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":79,"s":[8,98]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":84,"s":[8,168]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":89,"s":[8,39]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":94,"s":[8,73]},{"t":98,"s":[8,27]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":4,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0.7490196078431373,0.6470588235294118,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":[23.382,5.347],"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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-21,"op":579,"st":-21,"bm":0},{"ddd":0,"ind":26,"ty":4,"nm":"Shape Layer 9","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[336.292,256,0],"ix":2},"a":{"a":0,"k":[23.382,5.347,0],"ix":1},"s":{"a":0,"k":[75,37,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-19,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-14,"s":[8,237]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-9,"s":[8,264.333]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-4,"s":[8,247.667]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":1,"s":[8,197]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":6,"s":[8,29]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":11,"s":[8,26]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":16,"s":[8,158.5]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":21,"s":[8,217]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":26,"s":[8,250]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":31,"s":[8,125]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":36,"s":[8,163.5]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":41,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":46,"s":[8,37]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":51,"s":[8,52]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":56,"s":[8,92]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":61,"s":[8,50]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":66,"s":[8,154]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":71,"s":[8,115]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":76,"s":[8,157]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":81,"s":[8,98]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":86,"s":[8,168]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":91,"s":[8,39]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":96,"s":[8,73]},{"t":100,"s":[8,27]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":4,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0.7490196078431373,0.6470588235294118,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":[23.382,5.347],"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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-19,"op":581,"st":-19,"bm":0},{"ddd":0,"ind":27,"ty":4,"nm":"Shape Layer 8","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[321.557,256,0],"ix":2},"a":{"a":0,"k":[23.382,5.347,0],"ix":1},"s":{"a":0,"k":[75,78,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-5,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":0,"s":[8,237]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":5,"s":[8,264.333]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":10,"s":[8,247.667]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":15,"s":[8,197]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":20,"s":[8,29]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":25,"s":[8,26]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":30,"s":[8,158.5]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":35,"s":[8,217]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":40,"s":[8,250]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":45,"s":[8,125]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":50,"s":[8,163.5]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":55,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":60,"s":[8,37]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":65,"s":[8,52]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":70,"s":[8,92]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":75,"s":[8,50]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":80,"s":[8,154]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":85,"s":[8,115]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":90,"s":[8,157]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":95,"s":[8,98]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":100,"s":[8,168]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":105,"s":[8,39]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":110,"s":[8,73]},{"t":114,"s":[8,27]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":4,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0.7490196078431373,0.6470588235294118,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":[23.382,5.347],"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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-5,"op":595,"st":-5,"bm":0},{"ddd":0,"ind":28,"ty":4,"nm":"Shape Layer 33","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[41.595,256,0],"ix":2},"a":{"a":0,"k":[23.382,5.347,0],"ix":1},"s":{"a":0,"k":[75,55,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-23,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-18,"s":[8,237]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-13,"s":[8,264.333]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-8,"s":[8,247.667]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-3,"s":[8,197]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":2,"s":[8,29]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":7,"s":[8,26]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":12,"s":[8,158.5]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":17,"s":[8,217]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":22,"s":[8,250]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":27,"s":[8,125]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":32,"s":[8,163.5]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":37,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":42,"s":[8,37]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":47,"s":[8,52]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":52,"s":[8,92]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":57,"s":[8,50]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":62,"s":[8,154]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":67,"s":[8,115]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":72,"s":[8,157]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":77,"s":[8,98]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":82,"s":[8,168]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":87,"s":[8,39]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":92,"s":[8,73]},{"t":96,"s":[8,27]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":4,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0.7490196078431373,0.6470588235294118,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":[23.382,5.347],"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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-23,"op":577,"st":-23,"bm":0},{"ddd":0,"ind":29,"ty":4,"nm":"Shape Layer 7","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[306.822,256,0],"ix":2},"a":{"a":0,"k":[23.382,5.347,0],"ix":1},"s":{"a":0,"k":[75,55,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-23,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-18,"s":[8,237]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-13,"s":[8,264.333]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-8,"s":[8,247.667]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-3,"s":[8,197]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":2,"s":[8,29]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":7,"s":[8,26]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":12,"s":[8,158.5]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":17,"s":[8,217]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":22,"s":[8,250]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":27,"s":[8,125]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":32,"s":[8,163.5]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":37,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":42,"s":[8,37]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":47,"s":[8,52]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":52,"s":[8,92]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":57,"s":[8,50]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":62,"s":[8,154]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":67,"s":[8,115]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":72,"s":[8,157]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":77,"s":[8,98]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":82,"s":[8,168]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":87,"s":[8,39]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":92,"s":[8,73]},{"t":96,"s":[8,27]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":4,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0.7490196078431373,0.6470588235294118,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":[23.382,5.347],"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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-23,"op":577,"st":-23,"bm":0},{"ddd":0,"ind":30,"ty":4,"nm":"Shape Layer 6","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[292.087,256,0],"ix":2},"a":{"a":0,"k":[23.382,5.347,0],"ix":1},"s":{"a":0,"k":[75,45,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-6,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-1,"s":[8,237]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":4,"s":[8,264.333]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":9,"s":[8,247.667]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":14,"s":[8,197]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":19,"s":[8,29]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":24,"s":[8,26]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":29,"s":[8,158.5]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":34,"s":[8,217]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":39,"s":[8,250]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":44,"s":[8,125]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":49,"s":[8,163.5]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":54,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":59,"s":[8,37]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":64,"s":[8,52]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":69,"s":[8,92]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":74,"s":[8,50]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":79,"s":[8,154]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":84,"s":[8,115]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":89,"s":[8,157]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":94,"s":[8,98]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":99,"s":[8,168]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":104,"s":[8,39]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":109,"s":[8,73]},{"t":113,"s":[8,27]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":4,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0.7490196078431373,0.6470588235294118,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":[23.382,5.347],"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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-6,"op":594,"st":-6,"bm":0},{"ddd":0,"ind":31,"ty":4,"nm":"Shape Layer 5","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[233.148,256,0],"ix":2},"a":{"a":0,"k":[23.382,5.347,0],"ix":1},"s":{"a":0,"k":[75,45,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-13,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-8,"s":[8,237]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-3,"s":[8,264.333]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":2,"s":[8,247.667]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":7,"s":[8,197]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":12,"s":[8,29]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":17,"s":[8,26]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":22,"s":[8,158.5]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":27,"s":[8,217]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":32,"s":[8,250]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":37,"s":[8,125]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":42,"s":[8,163.5]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":47,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":52,"s":[8,37]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":57,"s":[8,52]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":62,"s":[8,92]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":67,"s":[8,50]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":72,"s":[8,154]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":77,"s":[8,115]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":82,"s":[8,157]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":87,"s":[8,98]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":92,"s":[8,168]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":97,"s":[8,39]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":102,"s":[8,73]},{"t":106,"s":[8,27]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":4,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0.7490196078431373,0.6470588235294118,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":[23.382,5.347],"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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-13,"op":587,"st":-13,"bm":0},{"ddd":0,"ind":32,"ty":4,"nm":"Shape Layer 4","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[247.883,256,0],"ix":2},"a":{"a":0,"k":[23.382,5.347,0],"ix":1},"s":{"a":0,"k":[75,75,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-5,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":0,"s":[8,237]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":5,"s":[8,264.333]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":10,"s":[8,247.667]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":15,"s":[8,197]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":20,"s":[8,29]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":25,"s":[8,26]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":30,"s":[8,158.5]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":35,"s":[8,217]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":40,"s":[8,250]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":45,"s":[8,125]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":50,"s":[8,163.5]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":55,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":60,"s":[8,37]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":65,"s":[8,52]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":70,"s":[8,92]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":75,"s":[8,50]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":80,"s":[8,154]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":85,"s":[8,115]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":90,"s":[8,157]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":95,"s":[8,98]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":100,"s":[8,168]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":105,"s":[8,39]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":110,"s":[8,73]},{"t":114,"s":[8,27]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":4,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0.7490196078431373,0.6470588235294118,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":[23.382,5.347],"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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-5,"op":595,"st":-5,"bm":0},{"ddd":0,"ind":33,"ty":4,"nm":"Shape Layer 3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[277.352,256,0],"ix":2},"a":{"a":0,"k":[23.382,5.347,0],"ix":1},"s":{"a":0,"k":[75,44,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":-3,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":2,"s":[8,237]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":7,"s":[8,264.333]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":12,"s":[8,247.667]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":17,"s":[8,197]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":22,"s":[8,29]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":27,"s":[8,26]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":32,"s":[8,158.5]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":37,"s":[8,217]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":42,"s":[8,250]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":47,"s":[8,125]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":52,"s":[8,163.5]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":57,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":62,"s":[8,37]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":67,"s":[8,52]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":72,"s":[8,92]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":77,"s":[8,50]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":82,"s":[8,154]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":87,"s":[8,115]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":92,"s":[8,157]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":97,"s":[8,98]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":102,"s":[8,168]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":107,"s":[8,39]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":112,"s":[8,73]},{"t":116,"s":[8,27]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":4,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0.7490196078431373,0.6470588235294118,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":[23.382,5.347],"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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-3,"op":597,"st":-3,"bm":0},{"ddd":0,"ind":34,"ty":4,"nm":"Shape Layer 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[262.617,256,0],"ix":2},"a":{"a":0,"k":[23.382,5.347,0],"ix":1},"s":{"a":0,"k":[75,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":0,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":5,"s":[8,237]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":10,"s":[8,264.333]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":15,"s":[8,247.667]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":20,"s":[8,197]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":25,"s":[8,29]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":30,"s":[8,26]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":35,"s":[8,158.5]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":40,"s":[8,217]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":45,"s":[8,250]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":50,"s":[8,125]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":55,"s":[8,163.5]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":60,"s":[8,100]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":65,"s":[8,37]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":70,"s":[8,52]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":75,"s":[8,92]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":80,"s":[8,50]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":85,"s":[8,154]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":90,"s":[8,115]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":95,"s":[8,157]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":100,"s":[8,98]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":105,"s":[8,168]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":110,"s":[8,39]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":115,"s":[8,73]},{"t":119,"s":[8,27]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":4,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0.7490196078431373,0.6470588235294118,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":[23.382,5.347],"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":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}],"markers":[]} \ No newline at end of file diff --git a/apps/client/assets/lottie/intro_foriday.json b/apps/client/assets/lottie/intro_foriday.json deleted file mode 100644 index e030941b..00000000 --- a/apps/client/assets/lottie/intro_foriday.json +++ /dev/null @@ -1 +0,0 @@ -{"nm":"Comp 1","ddd":0,"h":700,"w":700,"meta":{"g":"@lottiefiles/toolkit-js 0.22.1"},"layers":[{"ty":0,"nm":"Pre-comp 3","sr":1,"st":141.000005743048,"op":231.000009408823,"ip":141.000005743048,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[350,350,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[350,350,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"w":700,"h":700,"refId":"comp_0","ind":1},{"ty":0,"nm":"Pre-comp 3","sr":1,"st":71.0000028918893,"op":161.000006557664,"ip":71.0000028918893,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[350,350,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[350,350,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"w":700,"h":700,"refId":"comp_0","ind":2},{"ty":0,"nm":"Pre-comp 3","sr":1,"st":0,"op":90.0000036657751,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[350,350,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[350,350,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"w":700,"h":700,"refId":"comp_0","ind":3},{"ty":0,"nm":"bubble","sr":1,"st":0,"op":600.000024438501,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[350,350,0],"ix":1},"s":{"a":0,"k":[91,91,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[350,350,0],"ix":2},"r":{"a":0,"k":43,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":70,"ix":11}},"ef":[{"ty":0,"mn":"ADBE Gaussian Blur 2","nm":"Gaussian Blur","ix":1,"en":1,"ef":[{"ty":0,"mn":"ADBE Gaussian Blur 2-0001","nm":"Blurriness","ix":1,"v":{"a":0,"k":40.5,"ix":1}},{"ty":7,"mn":"ADBE Gaussian Blur 2-0002","nm":"Blur Dimensions","ix":2,"v":{"a":0,"k":1,"ix":2}},{"ty":7,"mn":"ADBE Gaussian Blur 2-0003","nm":"Repeat Edge Pixels","ix":3,"v":{"a":0,"k":0,"ix":3}}]}],"w":700,"h":700,"refId":"comp_4","ind":4},{"ty":0,"nm":"bubble","sr":1,"st":0,"op":600.000024438501,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[350,350,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[350,350,0],"ix":2},"r":{"a":0,"k":226,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":48,"ix":11}},"ef":[{"ty":0,"mn":"ADBE Tint","nm":"Tint","ix":1,"en":1,"ef":[{"ty":2,"mn":"ADBE Tint-0001","nm":"Map Black To","ix":1,"v":{"a":0,"k":[0,0,0,0],"ix":1}},{"ty":2,"mn":"ADBE Tint-0002","nm":"Map White To","ix":2,"v":{"a":0,"k":[1,0,0.7765],"ix":2}},{"ty":0,"mn":"ADBE Tint-0003","nm":"Amount to Tint","ix":3,"v":{"a":0,"k":100,"ix":3}},{"ty":6,"mn":"ADBE Tint-0004","nm":"","ix":4,"v":0}]}],"w":700,"h":700,"refId":"comp_4","ind":5},{"ty":0,"nm":"bubble","sr":1,"st":0,"op":600.000024438501,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[350,350,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[350,350,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"w":700,"h":700,"refId":"comp_4","ind":6}],"v":"5.5.5","fr":29.9700012207031,"op":231.000009408823,"ip":0,"assets":[{"nm":"","id":"comp_0","layers":[{"ty":0,"nm":"Pre-comp 2","sr":1,"st":13.0000005295009,"op":90.0000036657751,"ip":13.0000005295009,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[350,350,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[350,350,0],"ix":2},"r":{"a":0,"k":42,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":55,"ix":11}},"ef":[],"w":700,"h":700,"refId":"comp_1","ind":1},{"ty":0,"nm":"Pre-comp 2","sr":1,"st":0,"op":77.0000031362743,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[350,350,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[350,350,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"w":700,"h":700,"refId":"comp_1","ind":2}]},{"nm":"","id":"comp_1","layers":[{"ty":0,"nm":"Pre-comp 1","sr":1,"st":9.00000036657752,"op":77.0000031362743,"ip":9.00000036657752,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[350,350,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[350,350,0],"ix":2},"r":{"a":0,"k":69,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[{"ty":0,"mn":"ADBE Tint","nm":"Tint","ix":1,"en":1,"ef":[{"ty":2,"mn":"ADBE Tint-0001","nm":"Map Black To","ix":1,"v":{"a":0,"k":[0,0,0,0],"ix":1}},{"ty":2,"mn":"ADBE Tint-0002","nm":"Map White To","ix":2,"v":{"a":0,"k":[1,0.4078,0.6588],"ix":2}},{"ty":0,"mn":"ADBE Tint-0003","nm":"Amount to Tint","ix":3,"v":{"a":0,"k":100,"ix":3}},{"ty":6,"mn":"ADBE Tint-0004","nm":"","ix":4,"v":0}]}],"w":700,"h":700,"refId":"comp_2","ind":1},{"ty":0,"nm":"Pre-comp 1","sr":1,"st":0,"op":68.0000027696968,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[350,350,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[350,350,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"w":700,"h":700,"refId":"comp_2","ind":2}]},{"nm":"","id":"comp_2","layers":[{"ty":0,"nm":"Shape Layer 1 Comp 1","sr":1,"st":0,"op":47.0000019143492,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[350,350,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[350,350,0],"ix":2},"r":{"a":0,"k":275,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"w":700,"h":700,"refId":"comp_3","ind":1},{"ty":0,"nm":"Shape Layer 1 Comp 1","sr":1,"st":12.00000048877,"op":59.0000024031193,"ip":12.00000048877,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[350,350,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[350,350,0],"ix":2},"r":{"a":0,"k":227,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"w":700,"h":700,"refId":"comp_3","ind":2},{"ty":0,"nm":"Shape Layer 1 Comp 1","sr":1,"st":5.00000020365417,"op":52.0000021180034,"ip":5.00000020365417,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[350,350,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[350,350,0],"ix":2},"r":{"a":0,"k":140,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"w":700,"h":700,"refId":"comp_3","ind":3},{"ty":0,"nm":"Shape Layer 1 Comp 1","sr":1,"st":21.0000008553475,"op":68.0000027696968,"ip":21.0000008553475,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[350,350,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[350,350,0],"ix":2},"r":{"a":0,"k":48,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"w":700,"h":700,"refId":"comp_3","ind":4},{"ty":0,"nm":"Shape Layer 1 Comp 1","sr":1,"st":14.0000005702317,"op":61.0000024845809,"ip":14.0000005702317,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[350,350,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[350,350,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"w":700,"h":700,"refId":"comp_3","ind":5}]},{"nm":"","id":"comp_3","layers":[{"ty":4,"nm":"Shape Layer 1","sr":1,"st":0,"op":47.0000019143492,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[-261,141,0],"ix":1},"s":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0,0,100],"t":0},{"s":[100,100,100],"t":48.0000019550801}],"ix":6},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[349,350,0],"t":0,"ti":[19.167,-15.333,0],"to":[-19.167,15.333,0]},{"s":[234,442,0],"t":48.0000019550801}],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100],"t":26},{"s":[0],"t":46.0000018736184}],"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Ellipse 1","ix":1,"cix":2,"np":3,"it":[{"ty":"el","bm":0,"hd":false,"mn":"ADBE Vector Shape - Ellipse","nm":"Ellipse Path 1","d":1,"p":{"a":0,"k":[0,0],"ix":3},"s":{"a":0,"k":[12,12],"ix":2}},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":1,"lj":1,"ml":4,"o":{"a":0,"k":0,"ix":4},"w":{"a":0,"k":3,"ix":5},"c":{"a":0,"k":[0.9529,0.9608,0.9686],"ix":3}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[1,0.9529,0.9725],"ix":4},"r":1,"o":{"a":0,"k":100,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[-261,141],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":1}]},{"nm":"","id":"comp_4","layers":[{"ty":4,"nm":"Shape Layer 1","sr":1,"st":0,"op":600.000024438501,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[350,350,0],"ix":2},"r":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":0},{"s":[720],"t":231.000009408823}],"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Ellipse 1","ix":1,"cix":2,"np":3,"it":[{"ty":"el","bm":0,"hd":false,"mn":"ADBE Vector Shape - Ellipse","nm":"Ellipse Path 1","d":1,"p":{"a":0,"k":[0,0],"ix":3},"s":{"a":0,"k":[400,400],"ix":2}},{"ty":"gs","bm":0,"hd":false,"mn":"ADBE Vector Graphic - G-Stroke","nm":"Gradient Stroke 1","e":{"a":0,"k":[-761.875,495.96],"ix":5},"g":{"p":3,"k":{"a":0,"k":[0,1,1,1,0.496,0.9882352941176471,0.39215686274509803,0.17647058823529413,0.993,1,0.35294117647058826,0.37254901960784315,0,0,0.496,1,0.993,1],"ix":8}},"t":2,"a":{"a":0,"k":0,"ix":7},"h":{"a":0,"k":0,"ix":6},"s":{"a":0,"k":[154.435,-126.834],"ix":4},"lc":1,"lj":1,"ml":4,"o":{"a":0,"k":100,"ix":9},"w":{"a":0,"k":1,"ix":10}},{"ty":"fl","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Fill","nm":"Fill 1","c":{"a":0,"k":[1,0.9529,0.9725],"ix":4},"r":1,"o":{"a":0,"k":0,"ix":5}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[1,-1],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":1},{"ty":4,"nm":"Shape Layer 10","sr":1,"st":0,"op":600.000024438501,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[59.113,-37.893,0],"ix":1},"s":{"a":0,"k":[131.951,131.951,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[351,351,0],"ix":2},"r":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[382],"t":0},{"s":[742],"t":231.000009408823}],"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Shape 1","ix":1,"cix":2,"np":3,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[0,75.084],[-2.326,11.481],[8.484,-20.679],[0,-18.258],[-75.111,0],[-2.638,0.152]],"o":[[0,-12.43],[4.439,-21.907],[-6.526,15.906],[0,75.111],[2.677,0],[-56.982,-4.209]],"v":[[-30.208,-36.759],[-26.642,-72.724],[-61.861,-83.451],[-71.985,-31.87],[64.015,104.13],[71.985,103.892]]},"ix":2}},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":1,"lj":1,"ml":4,"o":{"a":0,"k":0,"ix":4},"w":{"a":0,"k":3,"ix":5},"c":{"a":0,"k":[0.9529,0.9608,0.9686],"ix":3}},{"ty":"gf","bm":0,"hd":false,"mn":"ADBE Vector Graphic - G-Fill","nm":"Gradient Fill 1","e":{"a":0,"k":[100,0],"ix":6},"g":{"p":3,"k":{"a":0,"k":[0,1,0.9529411764705882,0.9725490196078431,0.487,1,0.9529411764705882,0.9725490196078431,0.998,0.5176470588235295,0,1,0,1,0.487,1,0.998,0],"ix":9}},"t":2,"a":{"a":0,"k":0,"ix":8},"h":{"a":0,"k":0,"ix":7},"s":{"a":0,"k":[0,0],"ix":5},"r":1,"o":{"a":0,"k":100,"ix":10}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[0,0],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":2},{"ty":4,"nm":"Shape Layer 4","sr":1,"st":0,"op":600.000024438501,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[-128,0,0],"ix":1},"s":{"a":0,"k":[65.625,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[222,350,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":54,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Ellipse 1","ix":1,"cix":2,"np":3,"it":[{"ty":"el","bm":0,"hd":false,"mn":"ADBE Vector Shape - Ellipse","nm":"Ellipse Path 1","d":1,"p":{"a":0,"k":[0,0],"ix":3},"s":{"a":0,"k":[16,16],"ix":2}},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":1,"lj":1,"ml":4,"o":{"a":0,"k":0,"ix":4},"w":{"a":0,"k":3,"ix":5},"c":{"a":0,"k":[0.9529,0.9608,0.9686],"ix":3}},{"ty":"gf","bm":0,"hd":false,"mn":"ADBE Vector Graphic - G-Fill","nm":"Gradient Fill 1","e":{"a":0,"k":[100,0],"ix":6},"g":{"p":3,"k":{"a":0,"k":[0.002,1,1,1,0.488,1,1,1,0.998,1,1,1,0.002,1,0.488,0.5,0.998,0],"ix":9}},"t":2,"a":{"a":0,"k":0,"ix":8},"h":{"a":0,"k":0,"ix":7},"s":{"a":0,"k":[0,0],"ix":5},"r":1,"o":{"a":0,"k":100,"ix":10}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[-128,0],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":3},{"ty":4,"nm":"Shape Layer 8","sr":1,"st":0,"op":600.000024438501,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"td":1,"ao":0,"ks":{"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[350,350,0],"ix":2},"r":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[0],"t":0},{"s":[360],"t":59.0000024031193}],"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Ellipse 1","ix":1,"cix":2,"np":3,"it":[{"ty":"el","bm":0,"hd":false,"mn":"ADBE Vector Shape - Ellipse","nm":"Ellipse Path 1","d":1,"p":{"a":0,"k":[0,0],"ix":3},"s":{"a":0,"k":[400,400],"ix":2}},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":1,"lj":1,"ml":4,"o":{"a":0,"k":0,"ix":4},"w":{"a":0,"k":3,"ix":5},"c":{"a":0,"k":[0.9529,0.9608,0.9686],"ix":3}},{"ty":"gf","bm":0,"hd":false,"mn":"ADBE Vector Graphic - G-Fill","nm":"Gradient Fill 1","e":{"a":0,"k":[202.396,-0.369],"ix":6},"g":{"p":3,"k":{"a":0,"k":[0,1,1,1,0.487,1,1,1,0.998,1,1,1,0,0.44,0.487,0.22,0.998,0],"ix":9}},"t":2,"a":{"a":0,"k":0,"ix":8},"h":{"a":0,"k":0,"ix":7},"s":{"a":0,"k":[0,0],"ix":5},"r":1,"o":{"a":0,"k":100,"ix":10}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[1,-1],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":4},{"ty":4,"nm":"Shape Layer 7","sr":1,"st":0,"op":600.000024438501,"ip":0,"hd":false,"ddd":0,"bm":0,"tt":1,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[-118,46,0],"ix":1},"s":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[33.333,100,100],"t":0},{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[100,100,100],"t":29},{"s":[33.333,100,100],"t":59.0000024031193}],"ix":6},"sk":{"a":0,"k":0},"p":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[106,342,0],"t":0,"ti":[-81.667,0,0],"to":[81.667,0,0]},{"s":[596,342,0],"t":59.0000024031193}],"ix":2},"r":{"a":0,"k":38,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":39,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Rectangle 1","ix":1,"cix":2,"np":3,"it":[{"ty":"rc","bm":0,"hd":false,"mn":"ADBE Vector Shape - Rect","nm":"Rectangle Path 1","d":1,"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"s":{"a":0,"k":[72,596],"ix":2}},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":1,"lj":1,"ml":4,"o":{"a":0,"k":0,"ix":4},"w":{"a":0,"k":3,"ix":5},"c":{"a":0,"k":[0.9529,0.9608,0.9686],"ix":3}},{"ty":"gf","bm":0,"hd":false,"mn":"ADBE Vector Graphic - G-Fill","nm":"Gradient Fill 1","e":{"a":0,"k":[-2.662,190],"ix":6},"g":{"p":3,"k":{"a":0,"k":[0,1,1,1,0.487,1,1,1,0.998,1,1,1,0,0.44,0.487,0.22,0.998,0],"ix":9}},"t":2,"a":{"a":0,"k":0,"ix":8},"h":{"a":0,"k":0,"ix":7},"s":{"a":0,"k":[1.369,-19],"ix":5},"r":1,"o":{"a":0,"k":100,"ix":10}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[-118,46],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":5},{"ty":4,"nm":"Shape Layer 6","sr":1,"st":0,"op":600.000024438501,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[146.132,146.132,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[350,350,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Ellipse 1","ix":1,"cix":2,"np":3,"it":[{"ty":"el","bm":0,"hd":false,"mn":"ADBE Vector Shape - Ellipse","nm":"Ellipse Path 1","d":1,"p":{"a":0,"k":[0,0],"ix":3},"s":{"a":0,"k":[142,142],"ix":2}},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":1,"lj":1,"ml":4,"o":{"a":0,"k":0,"ix":4},"w":{"a":0,"k":3,"ix":5},"c":{"a":0,"k":[0.9529,0.9608,0.9686],"ix":3}},{"ty":"gf","bm":0,"hd":false,"mn":"ADBE Vector Graphic - G-Fill","nm":"Gradient Fill 1","e":{"a":0,"k":[60.839,0],"ix":6},"g":{"p":3,"k":{"a":0,"k":[0,0.8549019607843137,0.8549019607843137,0.8549019607843137,0.487,0.9254901960784314,0.9254901960784314,0.9254901960784314,0.998,1,1,1,0,0.44,0.487,0.22,0.998,0],"ix":9}},"t":2,"a":{"a":0,"k":0,"ix":8},"h":{"a":0,"k":0,"ix":7},"s":{"a":0,"k":[0,0],"ix":5},"r":1,"o":{"a":0,"k":100,"ix":10}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[181.304,181.304],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[0,-3],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":6},{"ty":4,"nm":"Shape Layer 5","sr":1,"st":0,"op":600.000024438501,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[124.841,124.841,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[350,458,0],"ix":2},"r":{"a":0,"k":180,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":10,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Shape 2","ix":1,"cix":2,"np":3,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[0,0],[-36.43,1.19],[0,0],[24.53,-18.36]],"o":[[25.85,-22.17],[0,0],[-32.74,1.05],[0,0]],"v":[[-100.64,-30.635],[-5.11,-67.775],[-5.11,37.125],[-92.55,67.775]]},"ix":2}},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":1,"lj":1,"ml":4,"o":{"a":0,"k":0,"ix":4},"w":{"a":0,"k":3,"ix":5},"c":{"a":0,"k":[0.9529,0.9608,0.9686],"ix":3}},{"ty":"gf","bm":0,"hd":false,"mn":"ADBE Vector Graphic - G-Fill","nm":"Gradient Fill 1","e":{"a":0,"k":[0,105.643],"ix":6},"g":{"p":3,"k":{"a":0,"k":[0,1,1,1,0.487,1,1,1,0.998,1,1,1,0,1,0.487,0.5,0.998,0],"ix":9}},"t":1,"a":{"a":0,"k":0},"h":{"a":0,"k":0},"s":{"a":0,"k":[-1,-118.622],"ix":5},"r":1,"o":{"a":0,"k":100,"ix":10}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[0,0],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]},{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Shape 1","ix":2,"cix":2,"np":3,"it":[{"ty":"sh","bm":0,"hd":false,"mn":"ADBE Vector Shape - Group","nm":"Path 1","ix":1,"d":1,"ks":{"a":0,"k":{"c":true,"i":[[-25.85,-22.17],[0,0],[32.74,1.05],[0,0]],"o":[[0,0],[-24.53,-18.36],[0,0],[36.43,1.19]],"v":[[100.64,-30.635],[92.55,67.775],[5.11,37.125],[5.11,-67.775]]},"ix":2}},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":1,"lj":1,"ml":4,"o":{"a":0,"k":0,"ix":4},"w":{"a":0,"k":3,"ix":5},"c":{"a":0,"k":[0.9529,0.9608,0.9686],"ix":3}},{"ty":"gf","bm":0,"hd":false,"mn":"ADBE Vector Graphic - G-Fill","nm":"Gradient Fill 1","e":{"a":0,"k":[0,105.643],"ix":6},"g":{"p":3,"k":{"a":0,"k":[0,1,1,1,0.487,1,1,1,0.998,1,1,1,0,1,0.487,0.5,0.998,0],"ix":9}},"t":1,"a":{"a":0,"k":0},"h":{"a":0,"k":0},"s":{"a":0,"k":[-1,-118.622],"ix":5},"r":1,"o":{"a":0,"k":100,"ix":10}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[0,0],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":7},{"ty":4,"nm":"Shape Layer 3","sr":1,"st":0,"op":600.000024438501,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[343,317,0],"ix":2},"r":{"a":0,"k":0,"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Ellipse 1","ix":1,"cix":2,"np":3,"it":[{"ty":"el","bm":0,"hd":false,"mn":"ADBE Vector Shape - Ellipse","nm":"Ellipse Path 1","d":1,"p":{"a":0,"k":[0,0],"ix":3},"s":{"a":0,"k":[177,116],"ix":2}},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":1,"lj":1,"ml":4,"o":{"a":0,"k":0,"ix":4},"w":{"a":0,"k":3,"ix":5},"c":{"a":0,"k":[0.9529,0.9608,0.9686],"ix":3}},{"ty":"gf","bm":0,"hd":false,"mn":"ADBE Vector Graphic - G-Fill","nm":"Gradient Fill 1","e":{"a":0,"k":[100,0],"ix":6},"g":{"p":3,"k":{"a":0,"k":[0.002,0.9529411764705882,0.9529411764705882,0.9529411764705882,0.488,0.9764705882352941,0.9764705882352941,0.9764705882352941,0.998,1,1,1,0.002,1,0.488,0.5,0.998,0],"ix":9}},"t":2,"a":{"a":0,"k":0,"ix":8},"h":{"a":0,"k":0,"ix":7},"s":{"a":0,"k":[-10,-146],"ix":5},"r":1,"o":{"a":0,"k":100,"ix":10}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[7.5,-104],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":8},{"ty":4,"nm":"Shape Layer 9","sr":1,"st":0,"op":600.000024438501,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[350,350,0],"ix":2},"r":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[190],"t":0},{"s":[550],"t":230.000009368092}],"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Ellipse 1","ix":1,"cix":2,"np":3,"it":[{"ty":"el","bm":0,"hd":false,"mn":"ADBE Vector Shape - Ellipse","nm":"Ellipse Path 1","d":1,"p":{"a":0,"k":[0,0],"ix":3},"s":{"a":0,"k":[400,400],"ix":2}},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":1,"lj":1,"ml":4,"o":{"a":0,"k":0,"ix":4},"w":{"a":0,"k":3,"ix":5},"c":{"a":0,"k":[0.9529,0.9608,0.9686],"ix":3}},{"ty":"gf","bm":0,"hd":false,"mn":"ADBE Vector Graphic - G-Fill","nm":"Gradient Fill 1","e":{"a":0,"k":[29.602,-44.441],"ix":6},"g":{"p":3,"k":{"a":0,"k":[0.002,0.5450980392156862,0.9882352941176471,0.9725490196078431,0.488,0.5686274509803921,0.7294117647058823,0.7176470588235294,0.998,1,0,0,0.002,1,0.488,0.5,0.998,0],"ix":9}},"t":2,"a":{"a":0,"k":0,"ix":8},"h":{"a":0,"k":0,"ix":7},"s":{"a":0,"k":[-131.837,65.407],"ix":5},"r":1,"o":{"a":0,"k":100,"ix":10}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[1,-1],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":9},{"ty":4,"nm":"Shape Layer 2","sr":1,"st":0,"op":600.000024438501,"ip":0,"hd":false,"ddd":0,"bm":0,"hasMask":false,"ao":0,"ks":{"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6},"sk":{"a":0,"k":0},"p":{"a":0,"k":[350,350,0],"ix":2},"r":{"a":1,"k":[{"o":{"x":0.167,"y":0.167},"i":{"x":0.833,"y":0.833},"s":[190],"t":0},{"s":[1270],"t":230.000009368092}],"ix":10},"sa":{"a":0,"k":0},"o":{"a":0,"k":100,"ix":11}},"ef":[],"shapes":[{"ty":"gr","bm":0,"hd":false,"mn":"ADBE Vector Group","nm":"Ellipse 1","ix":1,"cix":2,"np":3,"it":[{"ty":"el","bm":0,"hd":false,"mn":"ADBE Vector Shape - Ellipse","nm":"Ellipse Path 1","d":1,"p":{"a":0,"k":[0,0],"ix":3},"s":{"a":0,"k":[400,400],"ix":2}},{"ty":"st","bm":0,"hd":false,"mn":"ADBE Vector Graphic - Stroke","nm":"Stroke 1","lc":1,"lj":1,"ml":4,"o":{"a":0,"k":0,"ix":4},"w":{"a":0,"k":3,"ix":5},"c":{"a":0,"k":[0.9529,0.9608,0.9686],"ix":3}},{"ty":"gf","bm":0,"hd":false,"mn":"ADBE Vector Graphic - G-Fill","nm":"Gradient Fill 1","e":{"a":0,"k":[-48.365,-83.495],"ix":6},"g":{"p":3,"k":{"a":0,"k":[0.002,0.9882352941176471,0.7333333333333333,0.984313725490196,0.488,0.5254901960784314,0.9686274509803922,0.9294117647058824,0.998,1,0,0.8470588235294118,0.002,1,0.488,1,0.998,0],"ix":9}},"t":1,"a":{"a":0,"k":0},"h":{"a":0,"k":0},"s":{"a":0,"k":[-134.449,-317.964],"ix":5},"r":1,"o":{"a":0,"k":100,"ix":10}},{"ty":"tr","a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"sk":{"a":0,"k":0,"ix":4},"p":{"a":0,"k":[1,-1],"ix":2},"r":{"a":0,"k":0,"ix":6},"sa":{"a":0,"k":0,"ix":5},"o":{"a":0,"k":100,"ix":7}}]}],"ind":10}]}]} \ No newline at end of file diff --git a/apps/client/assets/weather/100-fill.svg b/apps/client/assets/weather/100-fill.svg deleted file mode 100644 index 8eb998ab..00000000 --- a/apps/client/assets/weather/100-fill.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/100.svg b/apps/client/assets/weather/100.svg deleted file mode 100644 index c09c8059..00000000 --- a/apps/client/assets/weather/100.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1001.svg b/apps/client/assets/weather/1001.svg deleted file mode 100644 index 94a63dc8..00000000 --- a/apps/client/assets/weather/1001.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1002.svg b/apps/client/assets/weather/1002.svg deleted file mode 100644 index 40812fa2..00000000 --- a/apps/client/assets/weather/1002.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1003.svg b/apps/client/assets/weather/1003.svg deleted file mode 100644 index 62f27976..00000000 --- a/apps/client/assets/weather/1003.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1004.svg b/apps/client/assets/weather/1004.svg deleted file mode 100644 index 436bba64..00000000 --- a/apps/client/assets/weather/1004.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1005.svg b/apps/client/assets/weather/1005.svg deleted file mode 100644 index e20a99b4..00000000 --- a/apps/client/assets/weather/1005.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1006.svg b/apps/client/assets/weather/1006.svg deleted file mode 100644 index 4c7c42c1..00000000 --- a/apps/client/assets/weather/1006.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1007.svg b/apps/client/assets/weather/1007.svg deleted file mode 100644 index 4e0cca2d..00000000 --- a/apps/client/assets/weather/1007.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1008.svg b/apps/client/assets/weather/1008.svg deleted file mode 100644 index 329f6c70..00000000 --- a/apps/client/assets/weather/1008.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1009.svg b/apps/client/assets/weather/1009.svg deleted file mode 100644 index e066c196..00000000 --- a/apps/client/assets/weather/1009.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/101-fill.svg b/apps/client/assets/weather/101-fill.svg deleted file mode 100644 index dae24c35..00000000 --- a/apps/client/assets/weather/101-fill.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/101.svg b/apps/client/assets/weather/101.svg deleted file mode 100644 index 690c9237..00000000 --- a/apps/client/assets/weather/101.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1010.svg b/apps/client/assets/weather/1010.svg deleted file mode 100644 index ce17e9b1..00000000 --- a/apps/client/assets/weather/1010.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1011.svg b/apps/client/assets/weather/1011.svg deleted file mode 100644 index 791c2a96..00000000 --- a/apps/client/assets/weather/1011.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1012.svg b/apps/client/assets/weather/1012.svg deleted file mode 100644 index 0ca6ee60..00000000 --- a/apps/client/assets/weather/1012.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1013.svg b/apps/client/assets/weather/1013.svg deleted file mode 100644 index b1f0cdf1..00000000 --- a/apps/client/assets/weather/1013.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1014.svg b/apps/client/assets/weather/1014.svg deleted file mode 100644 index 48009329..00000000 --- a/apps/client/assets/weather/1014.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1015.svg b/apps/client/assets/weather/1015.svg deleted file mode 100644 index 9876330b..00000000 --- a/apps/client/assets/weather/1015.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1016.svg b/apps/client/assets/weather/1016.svg deleted file mode 100644 index 903efef2..00000000 --- a/apps/client/assets/weather/1016.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1017.svg b/apps/client/assets/weather/1017.svg deleted file mode 100644 index d8ef224c..00000000 --- a/apps/client/assets/weather/1017.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1018.svg b/apps/client/assets/weather/1018.svg deleted file mode 100644 index 4a060632..00000000 --- a/apps/client/assets/weather/1018.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1019.svg b/apps/client/assets/weather/1019.svg deleted file mode 100644 index 7d81f72d..00000000 --- a/apps/client/assets/weather/1019.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/102-fill.svg b/apps/client/assets/weather/102-fill.svg deleted file mode 100644 index 2add9787..00000000 --- a/apps/client/assets/weather/102-fill.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/102.svg b/apps/client/assets/weather/102.svg deleted file mode 100644 index a37a5036..00000000 --- a/apps/client/assets/weather/102.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1020.svg b/apps/client/assets/weather/1020.svg deleted file mode 100644 index adcca8e0..00000000 --- a/apps/client/assets/weather/1020.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1021.svg b/apps/client/assets/weather/1021.svg deleted file mode 100644 index 24eb564a..00000000 --- a/apps/client/assets/weather/1021.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1022.svg b/apps/client/assets/weather/1022.svg deleted file mode 100644 index af2a3af9..00000000 --- a/apps/client/assets/weather/1022.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1023.svg b/apps/client/assets/weather/1023.svg deleted file mode 100644 index 8d07633c..00000000 --- a/apps/client/assets/weather/1023.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1024.svg b/apps/client/assets/weather/1024.svg deleted file mode 100644 index 0dd41ac0..00000000 --- a/apps/client/assets/weather/1024.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1025.svg b/apps/client/assets/weather/1025.svg deleted file mode 100644 index 469aede6..00000000 --- a/apps/client/assets/weather/1025.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1026.svg b/apps/client/assets/weather/1026.svg deleted file mode 100644 index 5ebad73b..00000000 --- a/apps/client/assets/weather/1026.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1027.svg b/apps/client/assets/weather/1027.svg deleted file mode 100644 index 434aa1ed..00000000 --- a/apps/client/assets/weather/1027.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1028.svg b/apps/client/assets/weather/1028.svg deleted file mode 100644 index 6369a487..00000000 --- a/apps/client/assets/weather/1028.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1029.svg b/apps/client/assets/weather/1029.svg deleted file mode 100644 index 178c3d08..00000000 --- a/apps/client/assets/weather/1029.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/103-fill.svg b/apps/client/assets/weather/103-fill.svg deleted file mode 100644 index d629442a..00000000 --- a/apps/client/assets/weather/103-fill.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/103.svg b/apps/client/assets/weather/103.svg deleted file mode 100644 index bbc124f1..00000000 --- a/apps/client/assets/weather/103.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1030.svg b/apps/client/assets/weather/1030.svg deleted file mode 100644 index e9b85010..00000000 --- a/apps/client/assets/weather/1030.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1031.svg b/apps/client/assets/weather/1031.svg deleted file mode 100644 index 43f8d448..00000000 --- a/apps/client/assets/weather/1031.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1032.svg b/apps/client/assets/weather/1032.svg deleted file mode 100644 index da53958d..00000000 --- a/apps/client/assets/weather/1032.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1033.svg b/apps/client/assets/weather/1033.svg deleted file mode 100644 index bb7787ba..00000000 --- a/apps/client/assets/weather/1033.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1034.svg b/apps/client/assets/weather/1034.svg deleted file mode 100644 index c2774607..00000000 --- a/apps/client/assets/weather/1034.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1035.svg b/apps/client/assets/weather/1035.svg deleted file mode 100644 index a168b4c7..00000000 --- a/apps/client/assets/weather/1035.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1036.svg b/apps/client/assets/weather/1036.svg deleted file mode 100644 index 6437f278..00000000 --- a/apps/client/assets/weather/1036.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1037.svg b/apps/client/assets/weather/1037.svg deleted file mode 100644 index db7dcefe..00000000 --- a/apps/client/assets/weather/1037.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1038.svg b/apps/client/assets/weather/1038.svg deleted file mode 100644 index 5bc07b12..00000000 --- a/apps/client/assets/weather/1038.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1039.svg b/apps/client/assets/weather/1039.svg deleted file mode 100644 index 3822b501..00000000 --- a/apps/client/assets/weather/1039.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/104-fill.svg b/apps/client/assets/weather/104-fill.svg deleted file mode 100644 index 02d8ee11..00000000 --- a/apps/client/assets/weather/104-fill.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/104.svg b/apps/client/assets/weather/104.svg deleted file mode 100644 index 4c6fec88..00000000 --- a/apps/client/assets/weather/104.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1040.svg b/apps/client/assets/weather/1040.svg deleted file mode 100644 index e4c91188..00000000 --- a/apps/client/assets/weather/1040.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1041.svg b/apps/client/assets/weather/1041.svg deleted file mode 100644 index 4746bee3..00000000 --- a/apps/client/assets/weather/1041.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1042.svg b/apps/client/assets/weather/1042.svg deleted file mode 100644 index 54015f71..00000000 --- a/apps/client/assets/weather/1042.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1043.svg b/apps/client/assets/weather/1043.svg deleted file mode 100644 index 4f04d544..00000000 --- a/apps/client/assets/weather/1043.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1044.svg b/apps/client/assets/weather/1044.svg deleted file mode 100644 index 0dad4967..00000000 --- a/apps/client/assets/weather/1044.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1045.svg b/apps/client/assets/weather/1045.svg deleted file mode 100644 index e3c7f50f..00000000 --- a/apps/client/assets/weather/1045.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1046.svg b/apps/client/assets/weather/1046.svg deleted file mode 100644 index 53a56aa6..00000000 --- a/apps/client/assets/weather/1046.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1047.svg b/apps/client/assets/weather/1047.svg deleted file mode 100644 index 34cbaf0e..00000000 --- a/apps/client/assets/weather/1047.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1048.svg b/apps/client/assets/weather/1048.svg deleted file mode 100644 index a58beb97..00000000 --- a/apps/client/assets/weather/1048.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1049.svg b/apps/client/assets/weather/1049.svg deleted file mode 100644 index 5ffaa6a2..00000000 --- a/apps/client/assets/weather/1049.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1050.svg b/apps/client/assets/weather/1050.svg deleted file mode 100644 index 037e5254..00000000 --- a/apps/client/assets/weather/1050.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1051.svg b/apps/client/assets/weather/1051.svg deleted file mode 100644 index f0fd308c..00000000 --- a/apps/client/assets/weather/1051.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1052.svg b/apps/client/assets/weather/1052.svg deleted file mode 100644 index 39d4662e..00000000 --- a/apps/client/assets/weather/1052.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1053.svg b/apps/client/assets/weather/1053.svg deleted file mode 100644 index d79c9f61..00000000 --- a/apps/client/assets/weather/1053.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1054.svg b/apps/client/assets/weather/1054.svg deleted file mode 100644 index 464c0442..00000000 --- a/apps/client/assets/weather/1054.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1055.svg b/apps/client/assets/weather/1055.svg deleted file mode 100644 index 9d8315c2..00000000 --- a/apps/client/assets/weather/1055.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1056.svg b/apps/client/assets/weather/1056.svg deleted file mode 100644 index b106fede..00000000 --- a/apps/client/assets/weather/1056.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1057.svg b/apps/client/assets/weather/1057.svg deleted file mode 100644 index b0a541e7..00000000 --- a/apps/client/assets/weather/1057.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1058.svg b/apps/client/assets/weather/1058.svg deleted file mode 100644 index aea2b8ff..00000000 --- a/apps/client/assets/weather/1058.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1059.svg b/apps/client/assets/weather/1059.svg deleted file mode 100644 index d17130e4..00000000 --- a/apps/client/assets/weather/1059.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1060.svg b/apps/client/assets/weather/1060.svg deleted file mode 100644 index 1133fd33..00000000 --- a/apps/client/assets/weather/1060.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1061.svg b/apps/client/assets/weather/1061.svg deleted file mode 100644 index 4c4adf2c..00000000 --- a/apps/client/assets/weather/1061.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1062.svg b/apps/client/assets/weather/1062.svg deleted file mode 100644 index 34161dac..00000000 --- a/apps/client/assets/weather/1062.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1063.svg b/apps/client/assets/weather/1063.svg deleted file mode 100644 index ec0e1b6e..00000000 --- a/apps/client/assets/weather/1063.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1064.svg b/apps/client/assets/weather/1064.svg deleted file mode 100644 index ae669d95..00000000 --- a/apps/client/assets/weather/1064.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1065.svg b/apps/client/assets/weather/1065.svg deleted file mode 100644 index 98f95e5c..00000000 --- a/apps/client/assets/weather/1065.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1066.svg b/apps/client/assets/weather/1066.svg deleted file mode 100644 index 1883b60b..00000000 --- a/apps/client/assets/weather/1066.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1067.svg b/apps/client/assets/weather/1067.svg deleted file mode 100644 index d2fde3ea..00000000 --- a/apps/client/assets/weather/1067.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1068.svg b/apps/client/assets/weather/1068.svg deleted file mode 100644 index 3feab39c..00000000 --- a/apps/client/assets/weather/1068.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1069.svg b/apps/client/assets/weather/1069.svg deleted file mode 100644 index a4680fad..00000000 --- a/apps/client/assets/weather/1069.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1071.svg b/apps/client/assets/weather/1071.svg deleted file mode 100644 index c27ced5f..00000000 --- a/apps/client/assets/weather/1071.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1072.svg b/apps/client/assets/weather/1072.svg deleted file mode 100644 index 5a382fec..00000000 --- a/apps/client/assets/weather/1072.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1073.svg b/apps/client/assets/weather/1073.svg deleted file mode 100644 index 415717de..00000000 --- a/apps/client/assets/weather/1073.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1074.svg b/apps/client/assets/weather/1074.svg deleted file mode 100644 index daa16940..00000000 --- a/apps/client/assets/weather/1074.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1075.svg b/apps/client/assets/weather/1075.svg deleted file mode 100644 index 423056bd..00000000 --- a/apps/client/assets/weather/1075.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1076.svg b/apps/client/assets/weather/1076.svg deleted file mode 100644 index 3cfd9ba7..00000000 --- a/apps/client/assets/weather/1076.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1077.svg b/apps/client/assets/weather/1077.svg deleted file mode 100644 index 0c69bd82..00000000 --- a/apps/client/assets/weather/1077.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1078.svg b/apps/client/assets/weather/1078.svg deleted file mode 100644 index 0f1a9e02..00000000 --- a/apps/client/assets/weather/1078.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1079.svg b/apps/client/assets/weather/1079.svg deleted file mode 100644 index 55b72f86..00000000 --- a/apps/client/assets/weather/1079.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1080.svg b/apps/client/assets/weather/1080.svg deleted file mode 100644 index 72f82334..00000000 --- a/apps/client/assets/weather/1080.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1081.svg b/apps/client/assets/weather/1081.svg deleted file mode 100644 index a9a9a8fb..00000000 --- a/apps/client/assets/weather/1081.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1082.svg b/apps/client/assets/weather/1082.svg deleted file mode 100644 index ad1de1a0..00000000 --- a/apps/client/assets/weather/1082.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1084.svg b/apps/client/assets/weather/1084.svg deleted file mode 100644 index 33359191..00000000 --- a/apps/client/assets/weather/1084.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1085.svg b/apps/client/assets/weather/1085.svg deleted file mode 100644 index 70e0797f..00000000 --- a/apps/client/assets/weather/1085.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1086.svg b/apps/client/assets/weather/1086.svg deleted file mode 100644 index 7848e85a..00000000 --- a/apps/client/assets/weather/1086.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1087.svg b/apps/client/assets/weather/1087.svg deleted file mode 100644 index f54d9f80..00000000 --- a/apps/client/assets/weather/1087.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1088.svg b/apps/client/assets/weather/1088.svg deleted file mode 100644 index dcdb94f9..00000000 --- a/apps/client/assets/weather/1088.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1089.svg b/apps/client/assets/weather/1089.svg deleted file mode 100644 index 073fcc64..00000000 --- a/apps/client/assets/weather/1089.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1201.svg b/apps/client/assets/weather/1201.svg deleted file mode 100644 index a3548378..00000000 --- a/apps/client/assets/weather/1201.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1202.svg b/apps/client/assets/weather/1202.svg deleted file mode 100644 index eccdcefb..00000000 --- a/apps/client/assets/weather/1202.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1203.svg b/apps/client/assets/weather/1203.svg deleted file mode 100644 index 39db56e0..00000000 --- a/apps/client/assets/weather/1203.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1204.svg b/apps/client/assets/weather/1204.svg deleted file mode 100644 index d895006a..00000000 --- a/apps/client/assets/weather/1204.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1205.svg b/apps/client/assets/weather/1205.svg deleted file mode 100644 index 77c8f228..00000000 --- a/apps/client/assets/weather/1205.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1206.svg b/apps/client/assets/weather/1206.svg deleted file mode 100644 index 890a97f3..00000000 --- a/apps/client/assets/weather/1206.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1207.svg b/apps/client/assets/weather/1207.svg deleted file mode 100644 index 51a2e300..00000000 --- a/apps/client/assets/weather/1207.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1208.svg b/apps/client/assets/weather/1208.svg deleted file mode 100644 index a8c10e05..00000000 --- a/apps/client/assets/weather/1208.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1209.svg b/apps/client/assets/weather/1209.svg deleted file mode 100644 index 095caf59..00000000 --- a/apps/client/assets/weather/1209.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1210.svg b/apps/client/assets/weather/1210.svg deleted file mode 100644 index 2d9ceea0..00000000 --- a/apps/client/assets/weather/1210.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1211.svg b/apps/client/assets/weather/1211.svg deleted file mode 100644 index 2a1b965e..00000000 --- a/apps/client/assets/weather/1211.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1212.svg b/apps/client/assets/weather/1212.svg deleted file mode 100644 index 781c77e0..00000000 --- a/apps/client/assets/weather/1212.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1213.svg b/apps/client/assets/weather/1213.svg deleted file mode 100644 index 943fdbe3..00000000 --- a/apps/client/assets/weather/1213.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1214.svg b/apps/client/assets/weather/1214.svg deleted file mode 100644 index 6193798c..00000000 --- a/apps/client/assets/weather/1214.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1215.svg b/apps/client/assets/weather/1215.svg deleted file mode 100644 index 9cc09643..00000000 --- a/apps/client/assets/weather/1215.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1216.svg b/apps/client/assets/weather/1216.svg deleted file mode 100644 index 7d92e74e..00000000 --- a/apps/client/assets/weather/1216.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1217.svg b/apps/client/assets/weather/1217.svg deleted file mode 100644 index 275a382a..00000000 --- a/apps/client/assets/weather/1217.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1218.svg b/apps/client/assets/weather/1218.svg deleted file mode 100644 index 3b5fb1e5..00000000 --- a/apps/client/assets/weather/1218.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1219.svg b/apps/client/assets/weather/1219.svg deleted file mode 100644 index 6467fd9d..00000000 --- a/apps/client/assets/weather/1219.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1221.svg b/apps/client/assets/weather/1221.svg deleted file mode 100644 index a4532adf..00000000 --- a/apps/client/assets/weather/1221.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1241.svg b/apps/client/assets/weather/1241.svg deleted file mode 100644 index 354ff652..00000000 --- a/apps/client/assets/weather/1241.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1242.svg b/apps/client/assets/weather/1242.svg deleted file mode 100644 index d9d61bda..00000000 --- a/apps/client/assets/weather/1242.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1243.svg b/apps/client/assets/weather/1243.svg deleted file mode 100644 index 19c10b5e..00000000 --- a/apps/client/assets/weather/1243.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1244.svg b/apps/client/assets/weather/1244.svg deleted file mode 100644 index cd74ff56..00000000 --- a/apps/client/assets/weather/1244.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1245.svg b/apps/client/assets/weather/1245.svg deleted file mode 100644 index e39e90b2..00000000 --- a/apps/client/assets/weather/1245.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1246.svg b/apps/client/assets/weather/1246.svg deleted file mode 100644 index a56c0051..00000000 --- a/apps/client/assets/weather/1246.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1247.svg b/apps/client/assets/weather/1247.svg deleted file mode 100644 index a0648645..00000000 --- a/apps/client/assets/weather/1247.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1248.svg b/apps/client/assets/weather/1248.svg deleted file mode 100644 index e89ad75d..00000000 --- a/apps/client/assets/weather/1248.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1249.svg b/apps/client/assets/weather/1249.svg deleted file mode 100644 index 506e4bd2..00000000 --- a/apps/client/assets/weather/1249.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1250.svg b/apps/client/assets/weather/1250.svg deleted file mode 100644 index 886d7a65..00000000 --- a/apps/client/assets/weather/1250.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1251.svg b/apps/client/assets/weather/1251.svg deleted file mode 100644 index 46acf7d2..00000000 --- a/apps/client/assets/weather/1251.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1271.svg b/apps/client/assets/weather/1271.svg deleted file mode 100644 index 91e62d98..00000000 --- a/apps/client/assets/weather/1271.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1272.svg b/apps/client/assets/weather/1272.svg deleted file mode 100644 index 2a7bca4b..00000000 --- a/apps/client/assets/weather/1272.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1273.svg b/apps/client/assets/weather/1273.svg deleted file mode 100644 index aff1cc84..00000000 --- a/apps/client/assets/weather/1273.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1274.svg b/apps/client/assets/weather/1274.svg deleted file mode 100644 index cf9db926..00000000 --- a/apps/client/assets/weather/1274.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/150-fill.svg b/apps/client/assets/weather/150-fill.svg deleted file mode 100644 index 18b4fc04..00000000 --- a/apps/client/assets/weather/150-fill.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/150.svg b/apps/client/assets/weather/150.svg deleted file mode 100644 index 3b78903d..00000000 --- a/apps/client/assets/weather/150.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/151-fill.svg b/apps/client/assets/weather/151-fill.svg deleted file mode 100644 index f0ac1382..00000000 --- a/apps/client/assets/weather/151-fill.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/151.svg b/apps/client/assets/weather/151.svg deleted file mode 100644 index 48b4502d..00000000 --- a/apps/client/assets/weather/151.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/152-fill.svg b/apps/client/assets/weather/152-fill.svg deleted file mode 100644 index d26dadac..00000000 --- a/apps/client/assets/weather/152-fill.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/152.svg b/apps/client/assets/weather/152.svg deleted file mode 100644 index 091390da..00000000 --- a/apps/client/assets/weather/152.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/153-fill.svg b/apps/client/assets/weather/153-fill.svg deleted file mode 100644 index daa1a1ef..00000000 --- a/apps/client/assets/weather/153-fill.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/153.svg b/apps/client/assets/weather/153.svg deleted file mode 100644 index 052f33f7..00000000 --- a/apps/client/assets/weather/153.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1601.svg b/apps/client/assets/weather/1601.svg deleted file mode 100644 index 7fe3c0eb..00000000 --- a/apps/client/assets/weather/1601.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1602.svg b/apps/client/assets/weather/1602.svg deleted file mode 100644 index 2761af84..00000000 --- a/apps/client/assets/weather/1602.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1603.svg b/apps/client/assets/weather/1603.svg deleted file mode 100644 index 890ed8f0..00000000 --- a/apps/client/assets/weather/1603.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1604.svg b/apps/client/assets/weather/1604.svg deleted file mode 100644 index 18d5ecbc..00000000 --- a/apps/client/assets/weather/1604.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1605.svg b/apps/client/assets/weather/1605.svg deleted file mode 100644 index a1158fd9..00000000 --- a/apps/client/assets/weather/1605.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1606.svg b/apps/client/assets/weather/1606.svg deleted file mode 100644 index 84417356..00000000 --- a/apps/client/assets/weather/1606.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1607.svg b/apps/client/assets/weather/1607.svg deleted file mode 100644 index 45662d8f..00000000 --- a/apps/client/assets/weather/1607.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1608.svg b/apps/client/assets/weather/1608.svg deleted file mode 100644 index ca87c168..00000000 --- a/apps/client/assets/weather/1608.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1609.svg b/apps/client/assets/weather/1609.svg deleted file mode 100644 index 235ab403..00000000 --- a/apps/client/assets/weather/1609.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1610.svg b/apps/client/assets/weather/1610.svg deleted file mode 100644 index cd61c4a5..00000000 --- a/apps/client/assets/weather/1610.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1701.svg b/apps/client/assets/weather/1701.svg deleted file mode 100644 index db7b60f0..00000000 --- a/apps/client/assets/weather/1701.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1702.svg b/apps/client/assets/weather/1702.svg deleted file mode 100644 index b2ad0668..00000000 --- a/apps/client/assets/weather/1702.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1703.svg b/apps/client/assets/weather/1703.svg deleted file mode 100644 index aeaa7b54..00000000 --- a/apps/client/assets/weather/1703.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1704.svg b/apps/client/assets/weather/1704.svg deleted file mode 100644 index bfe01062..00000000 --- a/apps/client/assets/weather/1704.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1705.svg b/apps/client/assets/weather/1705.svg deleted file mode 100644 index ab6c0c2a..00000000 --- a/apps/client/assets/weather/1705.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1706.svg b/apps/client/assets/weather/1706.svg deleted file mode 100644 index f292a63c..00000000 --- a/apps/client/assets/weather/1706.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1707.svg b/apps/client/assets/weather/1707.svg deleted file mode 100644 index aeb9c519..00000000 --- a/apps/client/assets/weather/1707.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1708.svg b/apps/client/assets/weather/1708.svg deleted file mode 100644 index 20eff2d6..00000000 --- a/apps/client/assets/weather/1708.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1709.svg b/apps/client/assets/weather/1709.svg deleted file mode 100644 index e9d26602..00000000 --- a/apps/client/assets/weather/1709.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1710.svg b/apps/client/assets/weather/1710.svg deleted file mode 100644 index 7d65071d..00000000 --- a/apps/client/assets/weather/1710.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1801.svg b/apps/client/assets/weather/1801.svg deleted file mode 100644 index 16d1e6cb..00000000 --- a/apps/client/assets/weather/1801.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1802.svg b/apps/client/assets/weather/1802.svg deleted file mode 100644 index 55c91855..00000000 --- a/apps/client/assets/weather/1802.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1803.svg b/apps/client/assets/weather/1803.svg deleted file mode 100644 index f3634018..00000000 --- a/apps/client/assets/weather/1803.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1804.svg b/apps/client/assets/weather/1804.svg deleted file mode 100644 index 392f65c8..00000000 --- a/apps/client/assets/weather/1804.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/1805.svg b/apps/client/assets/weather/1805.svg deleted file mode 100644 index 8452bed4..00000000 --- a/apps/client/assets/weather/1805.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2001.svg b/apps/client/assets/weather/2001.svg deleted file mode 100644 index 1c074ca6..00000000 --- a/apps/client/assets/weather/2001.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2002.svg b/apps/client/assets/weather/2002.svg deleted file mode 100644 index fa41f55f..00000000 --- a/apps/client/assets/weather/2002.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2003.svg b/apps/client/assets/weather/2003.svg deleted file mode 100644 index 0db57c91..00000000 --- a/apps/client/assets/weather/2003.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2004.svg b/apps/client/assets/weather/2004.svg deleted file mode 100644 index 6ec30d63..00000000 --- a/apps/client/assets/weather/2004.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2005.svg b/apps/client/assets/weather/2005.svg deleted file mode 100644 index 234edda6..00000000 --- a/apps/client/assets/weather/2005.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2006.svg b/apps/client/assets/weather/2006.svg deleted file mode 100644 index aa7ad0a2..00000000 --- a/apps/client/assets/weather/2006.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2007.svg b/apps/client/assets/weather/2007.svg deleted file mode 100644 index 449a3c47..00000000 --- a/apps/client/assets/weather/2007.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2029.svg b/apps/client/assets/weather/2029.svg deleted file mode 100644 index 7e0c67ca..00000000 --- a/apps/client/assets/weather/2029.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2030.svg b/apps/client/assets/weather/2030.svg deleted file mode 100644 index 59d6e5a2..00000000 --- a/apps/client/assets/weather/2030.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2031.svg b/apps/client/assets/weather/2031.svg deleted file mode 100644 index a517e94c..00000000 --- a/apps/client/assets/weather/2031.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2032.svg b/apps/client/assets/weather/2032.svg deleted file mode 100644 index 05848d81..00000000 --- a/apps/client/assets/weather/2032.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2033.svg b/apps/client/assets/weather/2033.svg deleted file mode 100644 index 815c98c6..00000000 --- a/apps/client/assets/weather/2033.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2050.svg b/apps/client/assets/weather/2050.svg deleted file mode 100644 index 393e8b2b..00000000 --- a/apps/client/assets/weather/2050.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2051.svg b/apps/client/assets/weather/2051.svg deleted file mode 100644 index b8e61331..00000000 --- a/apps/client/assets/weather/2051.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2052.svg b/apps/client/assets/weather/2052.svg deleted file mode 100644 index 6a68373e..00000000 --- a/apps/client/assets/weather/2052.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2053.svg b/apps/client/assets/weather/2053.svg deleted file mode 100644 index 85417c26..00000000 --- a/apps/client/assets/weather/2053.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2054.svg b/apps/client/assets/weather/2054.svg deleted file mode 100644 index 040dbc36..00000000 --- a/apps/client/assets/weather/2054.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2070.svg b/apps/client/assets/weather/2070.svg deleted file mode 100644 index 8ff29605..00000000 --- a/apps/client/assets/weather/2070.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2071.svg b/apps/client/assets/weather/2071.svg deleted file mode 100644 index 090b0aa2..00000000 --- a/apps/client/assets/weather/2071.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2072.svg b/apps/client/assets/weather/2072.svg deleted file mode 100644 index 8fd9e7c4..00000000 --- a/apps/client/assets/weather/2072.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2073.svg b/apps/client/assets/weather/2073.svg deleted file mode 100644 index 0f1cc40b..00000000 --- a/apps/client/assets/weather/2073.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2074.svg b/apps/client/assets/weather/2074.svg deleted file mode 100644 index 87ffaa33..00000000 --- a/apps/client/assets/weather/2074.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2075.svg b/apps/client/assets/weather/2075.svg deleted file mode 100644 index 243f0e1b..00000000 --- a/apps/client/assets/weather/2075.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2076.svg b/apps/client/assets/weather/2076.svg deleted file mode 100644 index 2cde19fc..00000000 --- a/apps/client/assets/weather/2076.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2077.svg b/apps/client/assets/weather/2077.svg deleted file mode 100644 index 7587cf9f..00000000 --- a/apps/client/assets/weather/2077.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2078.svg b/apps/client/assets/weather/2078.svg deleted file mode 100644 index 993893d7..00000000 --- a/apps/client/assets/weather/2078.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2079.svg b/apps/client/assets/weather/2079.svg deleted file mode 100644 index 9f600564..00000000 --- a/apps/client/assets/weather/2079.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2080.svg b/apps/client/assets/weather/2080.svg deleted file mode 100644 index 19d181d9..00000000 --- a/apps/client/assets/weather/2080.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2081.svg b/apps/client/assets/weather/2081.svg deleted file mode 100644 index dc016b34..00000000 --- a/apps/client/assets/weather/2081.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2082.svg b/apps/client/assets/weather/2082.svg deleted file mode 100644 index b46b2514..00000000 --- a/apps/client/assets/weather/2082.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2083.svg b/apps/client/assets/weather/2083.svg deleted file mode 100644 index dd730aac..00000000 --- a/apps/client/assets/weather/2083.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2084.svg b/apps/client/assets/weather/2084.svg deleted file mode 100644 index fe9aaf45..00000000 --- a/apps/client/assets/weather/2084.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2085.svg b/apps/client/assets/weather/2085.svg deleted file mode 100644 index 5ad4117d..00000000 --- a/apps/client/assets/weather/2085.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2100.svg b/apps/client/assets/weather/2100.svg deleted file mode 100644 index 06a33798..00000000 --- a/apps/client/assets/weather/2100.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2101.svg b/apps/client/assets/weather/2101.svg deleted file mode 100644 index dc1e4f7d..00000000 --- a/apps/client/assets/weather/2101.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2102.svg b/apps/client/assets/weather/2102.svg deleted file mode 100644 index c6692389..00000000 --- a/apps/client/assets/weather/2102.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2103.svg b/apps/client/assets/weather/2103.svg deleted file mode 100644 index 69142bbd..00000000 --- a/apps/client/assets/weather/2103.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2104.svg b/apps/client/assets/weather/2104.svg deleted file mode 100644 index c17aaf34..00000000 --- a/apps/client/assets/weather/2104.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2105.svg b/apps/client/assets/weather/2105.svg deleted file mode 100644 index 4bd7f83f..00000000 --- a/apps/client/assets/weather/2105.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2106.svg b/apps/client/assets/weather/2106.svg deleted file mode 100644 index 6d2b09fe..00000000 --- a/apps/client/assets/weather/2106.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2107.svg b/apps/client/assets/weather/2107.svg deleted file mode 100644 index ee9602bb..00000000 --- a/apps/client/assets/weather/2107.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2108.svg b/apps/client/assets/weather/2108.svg deleted file mode 100644 index 1bc2bd64..00000000 --- a/apps/client/assets/weather/2108.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2109.svg b/apps/client/assets/weather/2109.svg deleted file mode 100644 index 0fc99a2e..00000000 --- a/apps/client/assets/weather/2109.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2111.svg b/apps/client/assets/weather/2111.svg deleted file mode 100644 index 73e82ae9..00000000 --- a/apps/client/assets/weather/2111.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2120.svg b/apps/client/assets/weather/2120.svg deleted file mode 100644 index d3b8b5dc..00000000 --- a/apps/client/assets/weather/2120.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2121.svg b/apps/client/assets/weather/2121.svg deleted file mode 100644 index d282d3da..00000000 --- a/apps/client/assets/weather/2121.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2122.svg b/apps/client/assets/weather/2122.svg deleted file mode 100644 index 80c4740a..00000000 --- a/apps/client/assets/weather/2122.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2123.svg b/apps/client/assets/weather/2123.svg deleted file mode 100644 index 39b692ef..00000000 --- a/apps/client/assets/weather/2123.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2124.svg b/apps/client/assets/weather/2124.svg deleted file mode 100644 index edba0a24..00000000 --- a/apps/client/assets/weather/2124.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2125.svg b/apps/client/assets/weather/2125.svg deleted file mode 100644 index 8eece542..00000000 --- a/apps/client/assets/weather/2125.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2126.svg b/apps/client/assets/weather/2126.svg deleted file mode 100644 index abbf223e..00000000 --- a/apps/client/assets/weather/2126.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2127.svg b/apps/client/assets/weather/2127.svg deleted file mode 100644 index 298108f8..00000000 --- a/apps/client/assets/weather/2127.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2128.svg b/apps/client/assets/weather/2128.svg deleted file mode 100644 index 843a5eb8..00000000 --- a/apps/client/assets/weather/2128.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2129.svg b/apps/client/assets/weather/2129.svg deleted file mode 100644 index addaf565..00000000 --- a/apps/client/assets/weather/2129.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2130.svg b/apps/client/assets/weather/2130.svg deleted file mode 100644 index df294f1f..00000000 --- a/apps/client/assets/weather/2130.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2131.svg b/apps/client/assets/weather/2131.svg deleted file mode 100644 index 265c5f6f..00000000 --- a/apps/client/assets/weather/2131.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2132.svg b/apps/client/assets/weather/2132.svg deleted file mode 100644 index f0e53441..00000000 --- a/apps/client/assets/weather/2132.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2133.svg b/apps/client/assets/weather/2133.svg deleted file mode 100644 index dd1aec04..00000000 --- a/apps/client/assets/weather/2133.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2134.svg b/apps/client/assets/weather/2134.svg deleted file mode 100644 index a64d0b28..00000000 --- a/apps/client/assets/weather/2134.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2135.svg b/apps/client/assets/weather/2135.svg deleted file mode 100644 index 9bd2ae53..00000000 --- a/apps/client/assets/weather/2135.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2150.svg b/apps/client/assets/weather/2150.svg deleted file mode 100644 index 0f29ad58..00000000 --- a/apps/client/assets/weather/2150.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2151.svg b/apps/client/assets/weather/2151.svg deleted file mode 100644 index 78a04a9c..00000000 --- a/apps/client/assets/weather/2151.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2152.svg b/apps/client/assets/weather/2152.svg deleted file mode 100644 index be19f658..00000000 --- a/apps/client/assets/weather/2152.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2153.svg b/apps/client/assets/weather/2153.svg deleted file mode 100644 index c2a0f298..00000000 --- a/apps/client/assets/weather/2153.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2154.svg b/apps/client/assets/weather/2154.svg deleted file mode 100644 index 5dd08ee4..00000000 --- a/apps/client/assets/weather/2154.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2155.svg b/apps/client/assets/weather/2155.svg deleted file mode 100644 index ea4bf548..00000000 --- a/apps/client/assets/weather/2155.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2156.svg b/apps/client/assets/weather/2156.svg deleted file mode 100644 index 7e8a21f4..00000000 --- a/apps/client/assets/weather/2156.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2157.svg b/apps/client/assets/weather/2157.svg deleted file mode 100644 index e1b358a4..00000000 --- a/apps/client/assets/weather/2157.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2158.svg b/apps/client/assets/weather/2158.svg deleted file mode 100644 index 78649a9f..00000000 --- a/apps/client/assets/weather/2158.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2159.svg b/apps/client/assets/weather/2159.svg deleted file mode 100644 index cdc4d820..00000000 --- a/apps/client/assets/weather/2159.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2160.svg b/apps/client/assets/weather/2160.svg deleted file mode 100644 index 50af78ca..00000000 --- a/apps/client/assets/weather/2160.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2161.svg b/apps/client/assets/weather/2161.svg deleted file mode 100644 index 10d94a65..00000000 --- a/apps/client/assets/weather/2161.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2162.svg b/apps/client/assets/weather/2162.svg deleted file mode 100644 index bee69779..00000000 --- a/apps/client/assets/weather/2162.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2163.svg b/apps/client/assets/weather/2163.svg deleted file mode 100644 index 39176211..00000000 --- a/apps/client/assets/weather/2163.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2164.svg b/apps/client/assets/weather/2164.svg deleted file mode 100644 index 37cab870..00000000 --- a/apps/client/assets/weather/2164.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2165.svg b/apps/client/assets/weather/2165.svg deleted file mode 100644 index c9d3df80..00000000 --- a/apps/client/assets/weather/2165.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2166.svg b/apps/client/assets/weather/2166.svg deleted file mode 100644 index da8ad78c..00000000 --- a/apps/client/assets/weather/2166.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2167.svg b/apps/client/assets/weather/2167.svg deleted file mode 100644 index 9cf296cd..00000000 --- a/apps/client/assets/weather/2167.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2190.svg b/apps/client/assets/weather/2190.svg deleted file mode 100644 index 80584de4..00000000 --- a/apps/client/assets/weather/2190.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2191.svg b/apps/client/assets/weather/2191.svg deleted file mode 100644 index eea74886..00000000 --- a/apps/client/assets/weather/2191.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2192.svg b/apps/client/assets/weather/2192.svg deleted file mode 100644 index 6b435075..00000000 --- a/apps/client/assets/weather/2192.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2193.svg b/apps/client/assets/weather/2193.svg deleted file mode 100644 index 5c4a9d03..00000000 --- a/apps/client/assets/weather/2193.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2200.svg b/apps/client/assets/weather/2200.svg deleted file mode 100644 index 46704338..00000000 --- a/apps/client/assets/weather/2200.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2201.svg b/apps/client/assets/weather/2201.svg deleted file mode 100644 index 6efab12f..00000000 --- a/apps/client/assets/weather/2201.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2202.svg b/apps/client/assets/weather/2202.svg deleted file mode 100644 index e58a0236..00000000 --- a/apps/client/assets/weather/2202.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2203.svg b/apps/client/assets/weather/2203.svg deleted file mode 100644 index ef22be71..00000000 --- a/apps/client/assets/weather/2203.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2204.svg b/apps/client/assets/weather/2204.svg deleted file mode 100644 index 633600dc..00000000 --- a/apps/client/assets/weather/2204.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2205.svg b/apps/client/assets/weather/2205.svg deleted file mode 100644 index 487da31a..00000000 --- a/apps/client/assets/weather/2205.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2207.svg b/apps/client/assets/weather/2207.svg deleted file mode 100644 index e633e5ba..00000000 --- a/apps/client/assets/weather/2207.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2208.svg b/apps/client/assets/weather/2208.svg deleted file mode 100644 index 03da20d1..00000000 --- a/apps/client/assets/weather/2208.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2209.svg b/apps/client/assets/weather/2209.svg deleted file mode 100644 index 1b77a501..00000000 --- a/apps/client/assets/weather/2209.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2210.svg b/apps/client/assets/weather/2210.svg deleted file mode 100644 index 23aec9b2..00000000 --- a/apps/client/assets/weather/2210.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2211.svg b/apps/client/assets/weather/2211.svg deleted file mode 100644 index 2c057242..00000000 --- a/apps/client/assets/weather/2211.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2212.svg b/apps/client/assets/weather/2212.svg deleted file mode 100644 index 0bc1621c..00000000 --- a/apps/client/assets/weather/2212.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2213.svg b/apps/client/assets/weather/2213.svg deleted file mode 100644 index d4ff0e39..00000000 --- a/apps/client/assets/weather/2213.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2214.svg b/apps/client/assets/weather/2214.svg deleted file mode 100644 index ce6daa62..00000000 --- a/apps/client/assets/weather/2214.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2215.svg b/apps/client/assets/weather/2215.svg deleted file mode 100644 index 3b006390..00000000 --- a/apps/client/assets/weather/2215.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2216.svg b/apps/client/assets/weather/2216.svg deleted file mode 100644 index 88c40d72..00000000 --- a/apps/client/assets/weather/2216.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2217.svg b/apps/client/assets/weather/2217.svg deleted file mode 100644 index 98dc35b5..00000000 --- a/apps/client/assets/weather/2217.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2218.svg b/apps/client/assets/weather/2218.svg deleted file mode 100644 index 833ab49b..00000000 --- a/apps/client/assets/weather/2218.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2300.svg b/apps/client/assets/weather/2300.svg deleted file mode 100644 index dbf3becb..00000000 --- a/apps/client/assets/weather/2300.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2301.svg b/apps/client/assets/weather/2301.svg deleted file mode 100644 index 1bd72fa1..00000000 --- a/apps/client/assets/weather/2301.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2302.svg b/apps/client/assets/weather/2302.svg deleted file mode 100644 index 87df1b43..00000000 --- a/apps/client/assets/weather/2302.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2303.svg b/apps/client/assets/weather/2303.svg deleted file mode 100644 index a0a5dabe..00000000 --- a/apps/client/assets/weather/2303.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2304.svg b/apps/client/assets/weather/2304.svg deleted file mode 100644 index 4a3f01ea..00000000 --- a/apps/client/assets/weather/2304.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2305.svg b/apps/client/assets/weather/2305.svg deleted file mode 100644 index 73a797f6..00000000 --- a/apps/client/assets/weather/2305.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2306.svg b/apps/client/assets/weather/2306.svg deleted file mode 100644 index 31631aaf..00000000 --- a/apps/client/assets/weather/2306.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2307.svg b/apps/client/assets/weather/2307.svg deleted file mode 100644 index 1ec69e7c..00000000 --- a/apps/client/assets/weather/2307.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2308.svg b/apps/client/assets/weather/2308.svg deleted file mode 100644 index 32d9db1f..00000000 --- a/apps/client/assets/weather/2308.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2309.svg b/apps/client/assets/weather/2309.svg deleted file mode 100644 index 21640bbd..00000000 --- a/apps/client/assets/weather/2309.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2311.svg b/apps/client/assets/weather/2311.svg deleted file mode 100644 index ae172f52..00000000 --- a/apps/client/assets/weather/2311.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2312.svg b/apps/client/assets/weather/2312.svg deleted file mode 100644 index c5e53206..00000000 --- a/apps/client/assets/weather/2312.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2313.svg b/apps/client/assets/weather/2313.svg deleted file mode 100644 index ac90056f..00000000 --- a/apps/client/assets/weather/2313.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2314.svg b/apps/client/assets/weather/2314.svg deleted file mode 100644 index 10e7fb6c..00000000 --- a/apps/client/assets/weather/2314.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2315.svg b/apps/client/assets/weather/2315.svg deleted file mode 100644 index 32f99f62..00000000 --- a/apps/client/assets/weather/2315.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2316.svg b/apps/client/assets/weather/2316.svg deleted file mode 100644 index 4841bdd1..00000000 --- a/apps/client/assets/weather/2316.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2317.svg b/apps/client/assets/weather/2317.svg deleted file mode 100644 index 903299a1..00000000 --- a/apps/client/assets/weather/2317.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2318.svg b/apps/client/assets/weather/2318.svg deleted file mode 100644 index eb3667ac..00000000 --- a/apps/client/assets/weather/2318.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2319.svg b/apps/client/assets/weather/2319.svg deleted file mode 100644 index c3e387e1..00000000 --- a/apps/client/assets/weather/2319.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2320.svg b/apps/client/assets/weather/2320.svg deleted file mode 100644 index 685bebf2..00000000 --- a/apps/client/assets/weather/2320.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2321.svg b/apps/client/assets/weather/2321.svg deleted file mode 100644 index 91ee16c6..00000000 --- a/apps/client/assets/weather/2321.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2322.svg b/apps/client/assets/weather/2322.svg deleted file mode 100644 index bee58cdf..00000000 --- a/apps/client/assets/weather/2322.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2323.svg b/apps/client/assets/weather/2323.svg deleted file mode 100644 index 0480365e..00000000 --- a/apps/client/assets/weather/2323.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2324.svg b/apps/client/assets/weather/2324.svg deleted file mode 100644 index 7d9db6d0..00000000 --- a/apps/client/assets/weather/2324.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2325.svg b/apps/client/assets/weather/2325.svg deleted file mode 100644 index 57c80844..00000000 --- a/apps/client/assets/weather/2325.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2326.svg b/apps/client/assets/weather/2326.svg deleted file mode 100644 index 9d99f04d..00000000 --- a/apps/client/assets/weather/2326.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2327.svg b/apps/client/assets/weather/2327.svg deleted file mode 100644 index 8e681197..00000000 --- a/apps/client/assets/weather/2327.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2328.svg b/apps/client/assets/weather/2328.svg deleted file mode 100644 index 252677e9..00000000 --- a/apps/client/assets/weather/2328.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2330.svg b/apps/client/assets/weather/2330.svg deleted file mode 100644 index 474c74da..00000000 --- a/apps/client/assets/weather/2330.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2331.svg b/apps/client/assets/weather/2331.svg deleted file mode 100644 index f00559b4..00000000 --- a/apps/client/assets/weather/2331.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2332.svg b/apps/client/assets/weather/2332.svg deleted file mode 100644 index 5d95372f..00000000 --- a/apps/client/assets/weather/2332.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2333.svg b/apps/client/assets/weather/2333.svg deleted file mode 100644 index 58ed7da6..00000000 --- a/apps/client/assets/weather/2333.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2341.svg b/apps/client/assets/weather/2341.svg deleted file mode 100644 index 185eef0e..00000000 --- a/apps/client/assets/weather/2341.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2343.svg b/apps/client/assets/weather/2343.svg deleted file mode 100644 index d44a28ae..00000000 --- a/apps/client/assets/weather/2343.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2345.svg b/apps/client/assets/weather/2345.svg deleted file mode 100644 index 8d3ada27..00000000 --- a/apps/client/assets/weather/2345.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2346.svg b/apps/client/assets/weather/2346.svg deleted file mode 100644 index 4607eb16..00000000 --- a/apps/client/assets/weather/2346.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2348.svg b/apps/client/assets/weather/2348.svg deleted file mode 100644 index 1b6944ee..00000000 --- a/apps/client/assets/weather/2348.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2349.svg b/apps/client/assets/weather/2349.svg deleted file mode 100644 index 386a3e8f..00000000 --- a/apps/client/assets/weather/2349.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2350.svg b/apps/client/assets/weather/2350.svg deleted file mode 100644 index 7c05490e..00000000 --- a/apps/client/assets/weather/2350.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2351.svg b/apps/client/assets/weather/2351.svg deleted file mode 100644 index 74b5eb80..00000000 --- a/apps/client/assets/weather/2351.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2352.svg b/apps/client/assets/weather/2352.svg deleted file mode 100644 index 9924426f..00000000 --- a/apps/client/assets/weather/2352.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2353.svg b/apps/client/assets/weather/2353.svg deleted file mode 100644 index fb480b41..00000000 --- a/apps/client/assets/weather/2353.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2354.svg b/apps/client/assets/weather/2354.svg deleted file mode 100644 index 1c92250f..00000000 --- a/apps/client/assets/weather/2354.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2355.svg b/apps/client/assets/weather/2355.svg deleted file mode 100644 index 92b85408..00000000 --- a/apps/client/assets/weather/2355.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2356.svg b/apps/client/assets/weather/2356.svg deleted file mode 100644 index 3a2ffb06..00000000 --- a/apps/client/assets/weather/2356.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2357.svg b/apps/client/assets/weather/2357.svg deleted file mode 100644 index 57cb5d78..00000000 --- a/apps/client/assets/weather/2357.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2358.svg b/apps/client/assets/weather/2358.svg deleted file mode 100644 index 55c509b1..00000000 --- a/apps/client/assets/weather/2358.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2359.svg b/apps/client/assets/weather/2359.svg deleted file mode 100644 index b8ce8d4e..00000000 --- a/apps/client/assets/weather/2359.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2360.svg b/apps/client/assets/weather/2360.svg deleted file mode 100644 index 91e4e3e5..00000000 --- a/apps/client/assets/weather/2360.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2361.svg b/apps/client/assets/weather/2361.svg deleted file mode 100644 index f731066a..00000000 --- a/apps/client/assets/weather/2361.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2362.svg b/apps/client/assets/weather/2362.svg deleted file mode 100644 index e141b7fa..00000000 --- a/apps/client/assets/weather/2362.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2363.svg b/apps/client/assets/weather/2363.svg deleted file mode 100644 index f69a1473..00000000 --- a/apps/client/assets/weather/2363.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2364.svg b/apps/client/assets/weather/2364.svg deleted file mode 100644 index dba246d4..00000000 --- a/apps/client/assets/weather/2364.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2365.svg b/apps/client/assets/weather/2365.svg deleted file mode 100644 index b22301e6..00000000 --- a/apps/client/assets/weather/2365.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2366.svg b/apps/client/assets/weather/2366.svg deleted file mode 100644 index 07e3d4ab..00000000 --- a/apps/client/assets/weather/2366.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2367.svg b/apps/client/assets/weather/2367.svg deleted file mode 100644 index 79bbbff5..00000000 --- a/apps/client/assets/weather/2367.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2368.svg b/apps/client/assets/weather/2368.svg deleted file mode 100644 index 09a53455..00000000 --- a/apps/client/assets/weather/2368.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2369.svg b/apps/client/assets/weather/2369.svg deleted file mode 100644 index fb5e7b5f..00000000 --- a/apps/client/assets/weather/2369.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2370.svg b/apps/client/assets/weather/2370.svg deleted file mode 100644 index 6a6c3086..00000000 --- a/apps/client/assets/weather/2370.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2371.svg b/apps/client/assets/weather/2371.svg deleted file mode 100644 index b548764b..00000000 --- a/apps/client/assets/weather/2371.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2372.svg b/apps/client/assets/weather/2372.svg deleted file mode 100644 index 1f2084ff..00000000 --- a/apps/client/assets/weather/2372.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2373.svg b/apps/client/assets/weather/2373.svg deleted file mode 100644 index ca1c0b6f..00000000 --- a/apps/client/assets/weather/2373.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2374.svg b/apps/client/assets/weather/2374.svg deleted file mode 100644 index 341d9237..00000000 --- a/apps/client/assets/weather/2374.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2375.svg b/apps/client/assets/weather/2375.svg deleted file mode 100644 index 16e6d509..00000000 --- a/apps/client/assets/weather/2375.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2376.svg b/apps/client/assets/weather/2376.svg deleted file mode 100644 index 8b27291f..00000000 --- a/apps/client/assets/weather/2376.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2377.svg b/apps/client/assets/weather/2377.svg deleted file mode 100644 index fe09b42c..00000000 --- a/apps/client/assets/weather/2377.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2378.svg b/apps/client/assets/weather/2378.svg deleted file mode 100644 index db5587b8..00000000 --- a/apps/client/assets/weather/2378.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2379.svg b/apps/client/assets/weather/2379.svg deleted file mode 100644 index ea7cfbe2..00000000 --- a/apps/client/assets/weather/2379.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2380.svg b/apps/client/assets/weather/2380.svg deleted file mode 100644 index 2638ba55..00000000 --- a/apps/client/assets/weather/2380.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2381.svg b/apps/client/assets/weather/2381.svg deleted file mode 100644 index 4043048d..00000000 --- a/apps/client/assets/weather/2381.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2382.svg b/apps/client/assets/weather/2382.svg deleted file mode 100644 index 768764ad..00000000 --- a/apps/client/assets/weather/2382.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2383.svg b/apps/client/assets/weather/2383.svg deleted file mode 100644 index b54aec8a..00000000 --- a/apps/client/assets/weather/2383.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2384.svg b/apps/client/assets/weather/2384.svg deleted file mode 100644 index 0fe5430f..00000000 --- a/apps/client/assets/weather/2384.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2385.svg b/apps/client/assets/weather/2385.svg deleted file mode 100644 index 845881c9..00000000 --- a/apps/client/assets/weather/2385.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2386.svg b/apps/client/assets/weather/2386.svg deleted file mode 100644 index 21583a6b..00000000 --- a/apps/client/assets/weather/2386.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2387.svg b/apps/client/assets/weather/2387.svg deleted file mode 100644 index 0e1055a2..00000000 --- a/apps/client/assets/weather/2387.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2388.svg b/apps/client/assets/weather/2388.svg deleted file mode 100644 index 7424b524..00000000 --- a/apps/client/assets/weather/2388.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2389.svg b/apps/client/assets/weather/2389.svg deleted file mode 100644 index ecf82d37..00000000 --- a/apps/client/assets/weather/2389.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2390.svg b/apps/client/assets/weather/2390.svg deleted file mode 100644 index 85194ed4..00000000 --- a/apps/client/assets/weather/2390.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2391.svg b/apps/client/assets/weather/2391.svg deleted file mode 100644 index 75cb7112..00000000 --- a/apps/client/assets/weather/2391.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2392.svg b/apps/client/assets/weather/2392.svg deleted file mode 100644 index b0f2e104..00000000 --- a/apps/client/assets/weather/2392.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2393.svg b/apps/client/assets/weather/2393.svg deleted file mode 100644 index c5f81604..00000000 --- a/apps/client/assets/weather/2393.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2394.svg b/apps/client/assets/weather/2394.svg deleted file mode 100644 index 70b2078d..00000000 --- a/apps/client/assets/weather/2394.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2395.svg b/apps/client/assets/weather/2395.svg deleted file mode 100644 index 4b0e634a..00000000 --- a/apps/client/assets/weather/2395.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2396.svg b/apps/client/assets/weather/2396.svg deleted file mode 100644 index 246cfe99..00000000 --- a/apps/client/assets/weather/2396.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2397.svg b/apps/client/assets/weather/2397.svg deleted file mode 100644 index 5d11876f..00000000 --- a/apps/client/assets/weather/2397.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2398.svg b/apps/client/assets/weather/2398.svg deleted file mode 100644 index 7b9888ff..00000000 --- a/apps/client/assets/weather/2398.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2399.svg b/apps/client/assets/weather/2399.svg deleted file mode 100644 index 3eb42463..00000000 --- a/apps/client/assets/weather/2399.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2400.svg b/apps/client/assets/weather/2400.svg deleted file mode 100644 index 5d989037..00000000 --- a/apps/client/assets/weather/2400.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2409.svg b/apps/client/assets/weather/2409.svg deleted file mode 100644 index d4de8880..00000000 --- a/apps/client/assets/weather/2409.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2411.svg b/apps/client/assets/weather/2411.svg deleted file mode 100644 index c73b9bed..00000000 --- a/apps/client/assets/weather/2411.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2412.svg b/apps/client/assets/weather/2412.svg deleted file mode 100644 index 40405d9c..00000000 --- a/apps/client/assets/weather/2412.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2413.svg b/apps/client/assets/weather/2413.svg deleted file mode 100644 index 55f8e73e..00000000 --- a/apps/client/assets/weather/2413.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2414.svg b/apps/client/assets/weather/2414.svg deleted file mode 100644 index dda86d67..00000000 --- a/apps/client/assets/weather/2414.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2415.svg b/apps/client/assets/weather/2415.svg deleted file mode 100644 index ba163d72..00000000 --- a/apps/client/assets/weather/2415.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2416.svg b/apps/client/assets/weather/2416.svg deleted file mode 100644 index 7a34c89a..00000000 --- a/apps/client/assets/weather/2416.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2417.svg b/apps/client/assets/weather/2417.svg deleted file mode 100644 index 22f8f226..00000000 --- a/apps/client/assets/weather/2417.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2418.svg b/apps/client/assets/weather/2418.svg deleted file mode 100644 index f0b2ea16..00000000 --- a/apps/client/assets/weather/2418.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2419.svg b/apps/client/assets/weather/2419.svg deleted file mode 100644 index 64f7f3e0..00000000 --- a/apps/client/assets/weather/2419.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2420.svg b/apps/client/assets/weather/2420.svg deleted file mode 100644 index 9928b683..00000000 --- a/apps/client/assets/weather/2420.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2421.svg b/apps/client/assets/weather/2421.svg deleted file mode 100644 index c36b000b..00000000 --- a/apps/client/assets/weather/2421.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2422.svg b/apps/client/assets/weather/2422.svg deleted file mode 100644 index a688a1f4..00000000 --- a/apps/client/assets/weather/2422.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2423.svg b/apps/client/assets/weather/2423.svg deleted file mode 100644 index 8fdd9509..00000000 --- a/apps/client/assets/weather/2423.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2424.svg b/apps/client/assets/weather/2424.svg deleted file mode 100644 index d618b99a..00000000 --- a/apps/client/assets/weather/2424.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2425.svg b/apps/client/assets/weather/2425.svg deleted file mode 100644 index b970315e..00000000 --- a/apps/client/assets/weather/2425.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2426.svg b/apps/client/assets/weather/2426.svg deleted file mode 100644 index 1ea07134..00000000 --- a/apps/client/assets/weather/2426.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2501.svg b/apps/client/assets/weather/2501.svg deleted file mode 100644 index edef801e..00000000 --- a/apps/client/assets/weather/2501.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2502.svg b/apps/client/assets/weather/2502.svg deleted file mode 100644 index 166cbff2..00000000 --- a/apps/client/assets/weather/2502.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2521.svg b/apps/client/assets/weather/2521.svg deleted file mode 100644 index 6654758c..00000000 --- a/apps/client/assets/weather/2521.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2522.svg b/apps/client/assets/weather/2522.svg deleted file mode 100644 index 5263d492..00000000 --- a/apps/client/assets/weather/2522.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2523.svg b/apps/client/assets/weather/2523.svg deleted file mode 100644 index 2b82ccc7..00000000 --- a/apps/client/assets/weather/2523.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2524.svg b/apps/client/assets/weather/2524.svg deleted file mode 100644 index a02594d3..00000000 --- a/apps/client/assets/weather/2524.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2525.svg b/apps/client/assets/weather/2525.svg deleted file mode 100644 index dac5f63f..00000000 --- a/apps/client/assets/weather/2525.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2526.svg b/apps/client/assets/weather/2526.svg deleted file mode 100644 index 5608b4e3..00000000 --- a/apps/client/assets/weather/2526.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2527.svg b/apps/client/assets/weather/2527.svg deleted file mode 100644 index 244e04f2..00000000 --- a/apps/client/assets/weather/2527.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2528.svg b/apps/client/assets/weather/2528.svg deleted file mode 100644 index 3ba2067e..00000000 --- a/apps/client/assets/weather/2528.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2529.svg b/apps/client/assets/weather/2529.svg deleted file mode 100644 index c76a339e..00000000 --- a/apps/client/assets/weather/2529.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2530.svg b/apps/client/assets/weather/2530.svg deleted file mode 100644 index 8e76e769..00000000 --- a/apps/client/assets/weather/2530.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2531.svg b/apps/client/assets/weather/2531.svg deleted file mode 100644 index f2aa91a8..00000000 --- a/apps/client/assets/weather/2531.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2532.svg b/apps/client/assets/weather/2532.svg deleted file mode 100644 index 1039ed1b..00000000 --- a/apps/client/assets/weather/2532.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2550.svg b/apps/client/assets/weather/2550.svg deleted file mode 100644 index 23c3a03f..00000000 --- a/apps/client/assets/weather/2550.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2551.svg b/apps/client/assets/weather/2551.svg deleted file mode 100644 index bf180c07..00000000 --- a/apps/client/assets/weather/2551.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2552.svg b/apps/client/assets/weather/2552.svg deleted file mode 100644 index deba5914..00000000 --- a/apps/client/assets/weather/2552.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2553.svg b/apps/client/assets/weather/2553.svg deleted file mode 100644 index d483ed4a..00000000 --- a/apps/client/assets/weather/2553.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/2554.svg b/apps/client/assets/weather/2554.svg deleted file mode 100644 index 47da238c..00000000 --- a/apps/client/assets/weather/2554.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/300-fill.svg b/apps/client/assets/weather/300-fill.svg deleted file mode 100644 index 1ee4a8bb..00000000 --- a/apps/client/assets/weather/300-fill.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/300.svg b/apps/client/assets/weather/300.svg deleted file mode 100644 index 4a70d965..00000000 --- a/apps/client/assets/weather/300.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/301-fill.svg b/apps/client/assets/weather/301-fill.svg deleted file mode 100644 index b0b043f9..00000000 --- a/apps/client/assets/weather/301-fill.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/301.svg b/apps/client/assets/weather/301.svg deleted file mode 100644 index 50c116fc..00000000 --- a/apps/client/assets/weather/301.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/302-fill.svg b/apps/client/assets/weather/302-fill.svg deleted file mode 100644 index 2a2f2e57..00000000 --- a/apps/client/assets/weather/302-fill.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/302.svg b/apps/client/assets/weather/302.svg deleted file mode 100644 index 51c65369..00000000 --- a/apps/client/assets/weather/302.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/303-fill.svg b/apps/client/assets/weather/303-fill.svg deleted file mode 100644 index d92a7015..00000000 --- a/apps/client/assets/weather/303-fill.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/303.svg b/apps/client/assets/weather/303.svg deleted file mode 100644 index 64b5cf92..00000000 --- a/apps/client/assets/weather/303.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/304-fill.svg b/apps/client/assets/weather/304-fill.svg deleted file mode 100644 index bb4a8b42..00000000 --- a/apps/client/assets/weather/304-fill.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/304.svg b/apps/client/assets/weather/304.svg deleted file mode 100644 index 167ed4f9..00000000 --- a/apps/client/assets/weather/304.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/305-fill.svg b/apps/client/assets/weather/305-fill.svg deleted file mode 100644 index 788d5952..00000000 --- a/apps/client/assets/weather/305-fill.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/305.svg b/apps/client/assets/weather/305.svg deleted file mode 100644 index 5190dcd2..00000000 --- a/apps/client/assets/weather/305.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/306-fill.svg b/apps/client/assets/weather/306-fill.svg deleted file mode 100644 index 9eb78acc..00000000 --- a/apps/client/assets/weather/306-fill.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/306.svg b/apps/client/assets/weather/306.svg deleted file mode 100644 index e2fedd5e..00000000 --- a/apps/client/assets/weather/306.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/307-fill.svg b/apps/client/assets/weather/307-fill.svg deleted file mode 100644 index a672532d..00000000 --- a/apps/client/assets/weather/307-fill.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/307.svg b/apps/client/assets/weather/307.svg deleted file mode 100644 index 73e3025b..00000000 --- a/apps/client/assets/weather/307.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/308-fill.svg b/apps/client/assets/weather/308-fill.svg deleted file mode 100644 index 22aba0fd..00000000 --- a/apps/client/assets/weather/308-fill.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/308.svg b/apps/client/assets/weather/308.svg deleted file mode 100644 index 950f6e4e..00000000 --- a/apps/client/assets/weather/308.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/309-fill.svg b/apps/client/assets/weather/309-fill.svg deleted file mode 100644 index dd03e77b..00000000 --- a/apps/client/assets/weather/309-fill.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/309.svg b/apps/client/assets/weather/309.svg deleted file mode 100644 index 5268dd17..00000000 --- a/apps/client/assets/weather/309.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/310-fill.svg b/apps/client/assets/weather/310-fill.svg deleted file mode 100644 index 6d438c11..00000000 --- a/apps/client/assets/weather/310-fill.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/310.svg b/apps/client/assets/weather/310.svg deleted file mode 100644 index b1a16f4c..00000000 --- a/apps/client/assets/weather/310.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/311-fill.svg b/apps/client/assets/weather/311-fill.svg deleted file mode 100644 index c1f4cd2a..00000000 --- a/apps/client/assets/weather/311-fill.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/311.svg b/apps/client/assets/weather/311.svg deleted file mode 100644 index 211cf254..00000000 --- a/apps/client/assets/weather/311.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/312-fill.svg b/apps/client/assets/weather/312-fill.svg deleted file mode 100644 index 8f122125..00000000 --- a/apps/client/assets/weather/312-fill.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/312.svg b/apps/client/assets/weather/312.svg deleted file mode 100644 index d98270a0..00000000 --- a/apps/client/assets/weather/312.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/313-fill.svg b/apps/client/assets/weather/313-fill.svg deleted file mode 100644 index b2a58300..00000000 --- a/apps/client/assets/weather/313-fill.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/313.svg b/apps/client/assets/weather/313.svg deleted file mode 100644 index c32f9538..00000000 --- a/apps/client/assets/weather/313.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/314-fill.svg b/apps/client/assets/weather/314-fill.svg deleted file mode 100644 index 2c2ea768..00000000 --- a/apps/client/assets/weather/314-fill.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/314.svg b/apps/client/assets/weather/314.svg deleted file mode 100644 index a384deef..00000000 --- a/apps/client/assets/weather/314.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/315-fill.svg b/apps/client/assets/weather/315-fill.svg deleted file mode 100644 index e4bc831a..00000000 --- a/apps/client/assets/weather/315-fill.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/315.svg b/apps/client/assets/weather/315.svg deleted file mode 100644 index 68fba7da..00000000 --- a/apps/client/assets/weather/315.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/316-fill.svg b/apps/client/assets/weather/316-fill.svg deleted file mode 100644 index 74a63b76..00000000 --- a/apps/client/assets/weather/316-fill.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/316.svg b/apps/client/assets/weather/316.svg deleted file mode 100644 index 32119ec6..00000000 --- a/apps/client/assets/weather/316.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/317-fill.svg b/apps/client/assets/weather/317-fill.svg deleted file mode 100644 index a7db999b..00000000 --- a/apps/client/assets/weather/317-fill.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/317.svg b/apps/client/assets/weather/317.svg deleted file mode 100644 index c1b1d9eb..00000000 --- a/apps/client/assets/weather/317.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/318-fill.svg b/apps/client/assets/weather/318-fill.svg deleted file mode 100644 index 1198ceb2..00000000 --- a/apps/client/assets/weather/318-fill.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/318.svg b/apps/client/assets/weather/318.svg deleted file mode 100644 index 8349d004..00000000 --- a/apps/client/assets/weather/318.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/350-fill.svg b/apps/client/assets/weather/350-fill.svg deleted file mode 100644 index bc33bc1c..00000000 --- a/apps/client/assets/weather/350-fill.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/350.svg b/apps/client/assets/weather/350.svg deleted file mode 100644 index 3639e455..00000000 --- a/apps/client/assets/weather/350.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/351-fill.svg b/apps/client/assets/weather/351-fill.svg deleted file mode 100644 index f497a286..00000000 --- a/apps/client/assets/weather/351-fill.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/351.svg b/apps/client/assets/weather/351.svg deleted file mode 100644 index 35811ebd..00000000 --- a/apps/client/assets/weather/351.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/399-fill.svg b/apps/client/assets/weather/399-fill.svg deleted file mode 100644 index 6165118f..00000000 --- a/apps/client/assets/weather/399-fill.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/399.svg b/apps/client/assets/weather/399.svg deleted file mode 100644 index 01946d3d..00000000 --- a/apps/client/assets/weather/399.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/400-fill.svg b/apps/client/assets/weather/400-fill.svg deleted file mode 100644 index 8b2855e4..00000000 --- a/apps/client/assets/weather/400-fill.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/400.svg b/apps/client/assets/weather/400.svg deleted file mode 100644 index 7e726e59..00000000 --- a/apps/client/assets/weather/400.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/401-fill.svg b/apps/client/assets/weather/401-fill.svg deleted file mode 100644 index 9fccde01..00000000 --- a/apps/client/assets/weather/401-fill.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/401.svg b/apps/client/assets/weather/401.svg deleted file mode 100644 index 8fe40271..00000000 --- a/apps/client/assets/weather/401.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/402-fill.svg b/apps/client/assets/weather/402-fill.svg deleted file mode 100644 index c3446d70..00000000 --- a/apps/client/assets/weather/402-fill.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/402.svg b/apps/client/assets/weather/402.svg deleted file mode 100644 index 9ae768ed..00000000 --- a/apps/client/assets/weather/402.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/403-fill.svg b/apps/client/assets/weather/403-fill.svg deleted file mode 100644 index e801c0ba..00000000 --- a/apps/client/assets/weather/403-fill.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/403.svg b/apps/client/assets/weather/403.svg deleted file mode 100644 index 4707249c..00000000 --- a/apps/client/assets/weather/403.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/404-fill.svg b/apps/client/assets/weather/404-fill.svg deleted file mode 100644 index fd743592..00000000 --- a/apps/client/assets/weather/404-fill.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/404.svg b/apps/client/assets/weather/404.svg deleted file mode 100644 index 38e6570d..00000000 --- a/apps/client/assets/weather/404.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/405-fill.svg b/apps/client/assets/weather/405-fill.svg deleted file mode 100644 index e9a5ef11..00000000 --- a/apps/client/assets/weather/405-fill.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/405.svg b/apps/client/assets/weather/405.svg deleted file mode 100644 index 5b9f849c..00000000 --- a/apps/client/assets/weather/405.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/406-fill.svg b/apps/client/assets/weather/406-fill.svg deleted file mode 100644 index d995ccb4..00000000 --- a/apps/client/assets/weather/406-fill.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/406.svg b/apps/client/assets/weather/406.svg deleted file mode 100644 index 4b83f04a..00000000 --- a/apps/client/assets/weather/406.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/407-fill.svg b/apps/client/assets/weather/407-fill.svg deleted file mode 100644 index 7e839fbe..00000000 --- a/apps/client/assets/weather/407-fill.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/407.svg b/apps/client/assets/weather/407.svg deleted file mode 100644 index 8a85a5f7..00000000 --- a/apps/client/assets/weather/407.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/408-fill.svg b/apps/client/assets/weather/408-fill.svg deleted file mode 100644 index ef300738..00000000 --- a/apps/client/assets/weather/408-fill.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/408.svg b/apps/client/assets/weather/408.svg deleted file mode 100644 index e40c7280..00000000 --- a/apps/client/assets/weather/408.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/409-fill.svg b/apps/client/assets/weather/409-fill.svg deleted file mode 100644 index 7810ae4e..00000000 --- a/apps/client/assets/weather/409-fill.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/409.svg b/apps/client/assets/weather/409.svg deleted file mode 100644 index f03f7208..00000000 --- a/apps/client/assets/weather/409.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/410-fill.svg b/apps/client/assets/weather/410-fill.svg deleted file mode 100644 index 408854ea..00000000 --- a/apps/client/assets/weather/410-fill.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/410.svg b/apps/client/assets/weather/410.svg deleted file mode 100644 index a0d3f108..00000000 --- a/apps/client/assets/weather/410.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/456-fill.svg b/apps/client/assets/weather/456-fill.svg deleted file mode 100644 index edd6df40..00000000 --- a/apps/client/assets/weather/456-fill.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/456.svg b/apps/client/assets/weather/456.svg deleted file mode 100644 index c85ae194..00000000 --- a/apps/client/assets/weather/456.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/457-fill.svg b/apps/client/assets/weather/457-fill.svg deleted file mode 100644 index 946990e5..00000000 --- a/apps/client/assets/weather/457-fill.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/457.svg b/apps/client/assets/weather/457.svg deleted file mode 100644 index b5fdf64b..00000000 --- a/apps/client/assets/weather/457.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/499-fill.svg b/apps/client/assets/weather/499-fill.svg deleted file mode 100644 index 412acfe1..00000000 --- a/apps/client/assets/weather/499-fill.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/499.svg b/apps/client/assets/weather/499.svg deleted file mode 100644 index c6c1111d..00000000 --- a/apps/client/assets/weather/499.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/500-fill.svg b/apps/client/assets/weather/500-fill.svg deleted file mode 100644 index 7f23e700..00000000 --- a/apps/client/assets/weather/500-fill.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/500.svg b/apps/client/assets/weather/500.svg deleted file mode 100644 index 0fed18cf..00000000 --- a/apps/client/assets/weather/500.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/501-fill.svg b/apps/client/assets/weather/501-fill.svg deleted file mode 100644 index 4293cb48..00000000 --- a/apps/client/assets/weather/501-fill.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/501.svg b/apps/client/assets/weather/501.svg deleted file mode 100644 index 4ff02b67..00000000 --- a/apps/client/assets/weather/501.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/502-fill.svg b/apps/client/assets/weather/502-fill.svg deleted file mode 100644 index c77fc0aa..00000000 --- a/apps/client/assets/weather/502-fill.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/502.svg b/apps/client/assets/weather/502.svg deleted file mode 100644 index f0f0afb8..00000000 --- a/apps/client/assets/weather/502.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/503-fill.svg b/apps/client/assets/weather/503-fill.svg deleted file mode 100644 index 46775e3c..00000000 --- a/apps/client/assets/weather/503-fill.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/503.svg b/apps/client/assets/weather/503.svg deleted file mode 100644 index c8668762..00000000 --- a/apps/client/assets/weather/503.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/504-fill.svg b/apps/client/assets/weather/504-fill.svg deleted file mode 100644 index 51b1f727..00000000 --- a/apps/client/assets/weather/504-fill.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/504.svg b/apps/client/assets/weather/504.svg deleted file mode 100644 index d65b6942..00000000 --- a/apps/client/assets/weather/504.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/507-fill.svg b/apps/client/assets/weather/507-fill.svg deleted file mode 100644 index 56d21bf8..00000000 --- a/apps/client/assets/weather/507-fill.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/507.svg b/apps/client/assets/weather/507.svg deleted file mode 100644 index 5c566dbc..00000000 --- a/apps/client/assets/weather/507.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/508-fill.svg b/apps/client/assets/weather/508-fill.svg deleted file mode 100644 index 40e1d122..00000000 --- a/apps/client/assets/weather/508-fill.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/508.svg b/apps/client/assets/weather/508.svg deleted file mode 100644 index 97948442..00000000 --- a/apps/client/assets/weather/508.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/509-fill.svg b/apps/client/assets/weather/509-fill.svg deleted file mode 100644 index f23ab925..00000000 --- a/apps/client/assets/weather/509-fill.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/509.svg b/apps/client/assets/weather/509.svg deleted file mode 100644 index 15c45523..00000000 --- a/apps/client/assets/weather/509.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/510-fill.svg b/apps/client/assets/weather/510-fill.svg deleted file mode 100644 index 98f8fe40..00000000 --- a/apps/client/assets/weather/510-fill.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/510.svg b/apps/client/assets/weather/510.svg deleted file mode 100644 index 3eb2d139..00000000 --- a/apps/client/assets/weather/510.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/511-fill.svg b/apps/client/assets/weather/511-fill.svg deleted file mode 100644 index ada9420b..00000000 --- a/apps/client/assets/weather/511-fill.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/511.svg b/apps/client/assets/weather/511.svg deleted file mode 100644 index 44c91b33..00000000 --- a/apps/client/assets/weather/511.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/512-fill.svg b/apps/client/assets/weather/512-fill.svg deleted file mode 100644 index aaa72157..00000000 --- a/apps/client/assets/weather/512-fill.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/512.svg b/apps/client/assets/weather/512.svg deleted file mode 100644 index af484013..00000000 --- a/apps/client/assets/weather/512.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/513-fill.svg b/apps/client/assets/weather/513-fill.svg deleted file mode 100644 index 95646d8b..00000000 --- a/apps/client/assets/weather/513-fill.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/513.svg b/apps/client/assets/weather/513.svg deleted file mode 100644 index 30e9382e..00000000 --- a/apps/client/assets/weather/513.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/514-fill.svg b/apps/client/assets/weather/514-fill.svg deleted file mode 100644 index 47af727b..00000000 --- a/apps/client/assets/weather/514-fill.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/514.svg b/apps/client/assets/weather/514.svg deleted file mode 100644 index 9167a40f..00000000 --- a/apps/client/assets/weather/514.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/515-fill.svg b/apps/client/assets/weather/515-fill.svg deleted file mode 100644 index 6ff6c6a0..00000000 --- a/apps/client/assets/weather/515-fill.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/515.svg b/apps/client/assets/weather/515.svg deleted file mode 100644 index 36f0cc3e..00000000 --- a/apps/client/assets/weather/515.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/800.svg b/apps/client/assets/weather/800.svg deleted file mode 100644 index 7a5f34d1..00000000 --- a/apps/client/assets/weather/800.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/801.svg b/apps/client/assets/weather/801.svg deleted file mode 100644 index 87ad4b6c..00000000 --- a/apps/client/assets/weather/801.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/802.svg b/apps/client/assets/weather/802.svg deleted file mode 100644 index 2f024241..00000000 --- a/apps/client/assets/weather/802.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/803.svg b/apps/client/assets/weather/803.svg deleted file mode 100644 index c713455f..00000000 --- a/apps/client/assets/weather/803.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/804.svg b/apps/client/assets/weather/804.svg deleted file mode 100644 index baab6b4e..00000000 --- a/apps/client/assets/weather/804.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/805.svg b/apps/client/assets/weather/805.svg deleted file mode 100644 index 7601207d..00000000 --- a/apps/client/assets/weather/805.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/806.svg b/apps/client/assets/weather/806.svg deleted file mode 100644 index a0b70b6f..00000000 --- a/apps/client/assets/weather/806.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/807.svg b/apps/client/assets/weather/807.svg deleted file mode 100644 index 38534023..00000000 --- a/apps/client/assets/weather/807.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/900-fill.svg b/apps/client/assets/weather/900-fill.svg deleted file mode 100644 index 193c0b80..00000000 --- a/apps/client/assets/weather/900-fill.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/900.svg b/apps/client/assets/weather/900.svg deleted file mode 100644 index 4991e017..00000000 --- a/apps/client/assets/weather/900.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/901-fill.svg b/apps/client/assets/weather/901-fill.svg deleted file mode 100644 index be28bd8a..00000000 --- a/apps/client/assets/weather/901-fill.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/901.svg b/apps/client/assets/weather/901.svg deleted file mode 100644 index 7f1fe148..00000000 --- a/apps/client/assets/weather/901.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/999-fill.svg b/apps/client/assets/weather/999-fill.svg deleted file mode 100644 index 91d9d4f3..00000000 --- a/apps/client/assets/weather/999-fill.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/999.svg b/apps/client/assets/weather/999.svg deleted file mode 100644 index 865cc87c..00000000 --- a/apps/client/assets/weather/999.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/9999.svg b/apps/client/assets/weather/9999.svg deleted file mode 100644 index 51a7425c..00000000 --- a/apps/client/assets/weather/9999.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/assets/weather/qweather-fill.svg b/apps/client/assets/weather/qweather-fill.svg deleted file mode 100644 index 819aa6ad..00000000 --- a/apps/client/assets/weather/qweather-fill.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/apps/client/assets/weather/qweather.svg b/apps/client/assets/weather/qweather.svg deleted file mode 100644 index 6a7cd023..00000000 --- a/apps/client/assets/weather/qweather.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/apps/client/ios/Podfile.lock b/apps/client/ios/Podfile.lock index 99ae5440..a7b6b0fb 100644 --- a/apps/client/ios/Podfile.lock +++ b/apps/client/ios/Podfile.lock @@ -18,8 +18,6 @@ PODS: - Flutter - flutter_timezone (0.0.1): - Flutter - - flutter_tts (0.0.1): - - Flutter - fluwx (0.0.1): - Flutter - fluwx/pay (= 0.0.1) @@ -30,20 +28,8 @@ PODS: - Flutter - image_gallery_saver_plus (0.0.1): - Flutter - - QCloudCore (6.5.3): - - QCloudCore/Default (= 6.5.3) - - QCloudCore/Default (6.5.3): - - QCloudTrack/Beacon (= 6.5.3) - - QCloudCOSXML (6.5.3): - - QCloudCOSXML/Default (= 6.5.3) - - QCloudCOSXML/Default (6.5.3): - - QCloudCore (= 6.5.3) - - QCloudTrack/Beacon (6.5.3) - sign_in_with_apple (0.0.1): - Flutter - - tencentcloud_cos_sdk_plugin (1.2.8): - - Flutter - - QCloudCOSXML (= 6.5.3) - tobias (0.0.1): - Flutter - tobias/normal (= 0.0.1) @@ -62,12 +48,10 @@ DEPENDENCIES: - Flutter (from `Flutter`) - flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`) - flutter_timezone (from `.symlinks/plugins/flutter_timezone/ios`) - - flutter_tts (from `.symlinks/plugins/flutter_tts/ios`) - fluwx (from `.symlinks/plugins/fluwx/ios`) - haptic_feedback (from `.symlinks/plugins/haptic_feedback/ios`) - image_gallery_saver_plus (from `.symlinks/plugins/image_gallery_saver_plus/ios`) - sign_in_with_apple (from `.symlinks/plugins/sign_in_with_apple/ios`) - - tencentcloud_cos_sdk_plugin (from `.symlinks/plugins/tencentcloud_cos_sdk_plugin/ios`) - tobias (from `.symlinks/plugins/tobias/ios`) - wifi_iot (from `.symlinks/plugins/wifi_iot/ios`) @@ -75,9 +59,6 @@ SPEC REPOS: trunk: - AMapFoundation - AMapNavi - - QCloudCore - - QCloudCOSXML - - QCloudTrack - WechatOpenSDK-XCFramework EXTERNAL SOURCES: @@ -97,8 +78,6 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/flutter_local_notifications/ios" flutter_timezone: :path: ".symlinks/plugins/flutter_timezone/ios" - flutter_tts: - :path: ".symlinks/plugins/flutter_tts/ios" fluwx: :path: ".symlinks/plugins/fluwx/ios" haptic_feedback: @@ -107,8 +86,6 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/image_gallery_saver_plus/ios" sign_in_with_apple: :path: ".symlinks/plugins/sign_in_with_apple/ios" - tencentcloud_cos_sdk_plugin: - :path: ".symlinks/plugins/tencentcloud_cos_sdk_plugin/ios" tobias: :path: ".symlinks/plugins/tobias/ios" wifi_iot: @@ -125,15 +102,10 @@ SPEC CHECKSUMS: Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467 flutter_local_notifications: df98d66e515e1ca797af436137b4459b160ad8c9 flutter_timezone: ffb07bdad3c6276af8dada0f11978d8a1f8a20bb - flutter_tts: 91ad1884033cd95ef6e9338754adad54f01f090f fluwx: 95a2274c23418c1098940bd00dcfe7c975bb0550 haptic_feedback: 8cb3ee0cb6b797946c2b0df9c99ebc8f7ed79c71 image_gallery_saver_plus: 782ade975fe6a4600b53e7c1983e3a2979d1e9e5 - QCloudCore: 463b8c0c99fdc48a1c9cc637ee5466a1e5cf0c6e - QCloudCOSXML: b092a768b1f290235ca99205123d12e5e8f389b4 - QCloudTrack: 4bafb980038f59b78270acb260bf5b093a6d23db sign_in_with_apple: f3bf75217ea4c2c8b91823f225d70230119b8440 - tencentcloud_cos_sdk_plugin: d380c573277dba3d511fb7c4588e651f71fa3a71 tobias: 444de28ea3441b5bdbe2f85321544dd62c0dabe4 WechatOpenSDK-XCFramework: 5df9b250e9839dcc306ad8b00f46822eead1ed47 wifi_iot: b5aafd6f9b52f8a357383a1deabab45f31cd602d diff --git a/apps/client/ios/Runner.xcodeproj/project.pbxproj b/apps/client/ios/Runner.xcodeproj/project.pbxproj index 25aa42e4..df80aa2b 100644 --- a/apps/client/ios/Runner.xcodeproj/project.pbxproj +++ b/apps/client/ios/Runner.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 60; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ @@ -338,7 +338,7 @@ ); mainGroup = 97C146E51CF9000F007C117D; packageReferences = ( - 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */, + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */, ); productRefGroup = 97C146EF1CF9000F007C117D /* Products */; projectDirPath = ""; @@ -389,14 +389,10 @@ inputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist", ); - inputPaths = ( - ); name = "[CP] Copy Pods Resources"; outputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist", ); - outputPaths = ( - ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; @@ -441,14 +437,10 @@ inputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); - inputPaths = ( - ); name = "[CP] Embed Pods Frameworks"; outputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); - outputPaths = ( - ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; @@ -996,7 +988,7 @@ /* End XCConfigurationList section */ /* Begin XCLocalSwiftPackageReference section */ - 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */ = { + 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */ = { isa = XCLocalSwiftPackageReference; relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; }; @@ -1005,7 +997,7 @@ /* Begin XCSwiftPackageProductDependency section */ 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */ = { isa = XCSwiftPackageProductDependency; - package = 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */; + package = 781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */; productName = FlutterGeneratedPluginSwiftPackage; }; /* End XCSwiftPackageProductDependency section */ diff --git a/apps/client/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/apps/client/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 27d1df0a..87c332df 100644 --- a/apps/client/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/apps/client/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -122,8 +122,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/google/GoogleUtilities.git", "state" : { - "revision" : "60da361632d0de02786f709bdc0c4df340f7613e", - "version" : "8.1.0" + "revision" : "92c8f6dc3ac375d6febdfcb3db68bc3d10633db3", + "version" : "8.1.3" } }, { diff --git a/apps/client/lib/core/bindings/initial_binding.dart b/apps/client/lib/core/bindings/initial_binding.dart index 2e0f27fc..05296a95 100644 --- a/apps/client/lib/core/bindings/initial_binding.dart +++ b/apps/client/lib/core/bindings/initial_binding.dart @@ -4,9 +4,7 @@ import '/data/services/qq_music.dart'; import '../../../data/services/user_portrait.dart'; -import '../../../data/services/location_manager.dart'; import '../../../data/services/music_manager.dart'; -import '../../../data/services/navigation_manager.dart'; import '../../../data/services/ast_service.dart'; import '../../../data/services/speech_impl/azure_ast_service.dart'; import 'package:get/get.dart'; @@ -18,7 +16,6 @@ import '../../data/services/assistant_directive_service.dart'; import '../../data/services/bailian_multimodal_service.dart'; import '../../data/services/emai_chat_store.dart'; import '../../data/services/id_verify_service.dart'; -import '../../data/services/microsoft_translation_service.dart'; import '../../data/services/server_translation_service.dart'; import '../../data/services/language_manager.dart'; import '../../core/utils/logger.dart'; @@ -67,11 +64,6 @@ class InitialBinding extends Bindings { // 注册 AST 服务 Get.lazyPut(() => AzureAstService(), fenix: true); - // 微软翻译服务:通话/同声/面对面/多媒体的三段式翻译,以及文本翻译 - Get.lazyPut( - () => MicrosoftTranslationService(), - fenix: true); - // 火山引擎翻译服务:TranslationController / PictureTranslationController // 文本翻译改走服务端(用后台第三方服务配置里的 MT 服务,当前是阿里云)。 // 火山那个仍保留:图片翻译还在用它的 translateImage。 Get.lazyPut(() => ServerTranslationService(), @@ -123,9 +115,6 @@ class InitialBinding extends Bindings { // MusicManager Get.lazyPut(() => MusicManager(), fenix: true); - // 导航模块 - Get.lazyPut(() => NavigationManager(), fenix: true); - Get.lazyPut(() => LocationManager(), fenix: true); // 账号管理服务 Get.lazyPut(() => AccountService(), fenix: true); diff --git a/apps/client/lib/core/theme/text_styles.dart b/apps/client/lib/core/theme/text_styles.dart deleted file mode 100644 index 4d4fb263..00000000 --- a/apps/client/lib/core/theme/text_styles.dart +++ /dev/null @@ -1,80 +0,0 @@ -import 'package:flutter/material.dart'; -import 'app_colors.dart'; - -class TextStyles { - // Headings - static const TextStyle heading1 = TextStyle( - fontSize: 28, - fontWeight: FontWeight.bold, - color: AppColors.textPrimary, - height: 1.2, - ); - - static const TextStyle heading2 = TextStyle( - fontSize: 24, - fontWeight: FontWeight.bold, - color: AppColors.textPrimary, - height: 1.2, - ); - - static const TextStyle heading3 = TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - color: AppColors.textPrimary, - height: 1.2, - ); - - // Title and subtitle - static const TextStyle title = TextStyle( - fontSize: 18, - fontWeight: FontWeight.w600, - color: AppColors.textPrimary, - height: 1.3, - ); - - static const TextStyle subtitle = TextStyle( - fontSize: 16, - fontWeight: FontWeight.w500, - color: AppColors.textPrimary, - height: 1.3, - ); - - // Body text - static const TextStyle body = TextStyle( - fontSize: 16, - fontWeight: FontWeight.normal, - color: AppColors.textPrimary, - height: 1.5, - ); - - static const TextStyle bodySmall = TextStyle( - fontSize: 14, - fontWeight: FontWeight.normal, - color: AppColors.textPrimary, - height: 1.5, - ); - - // Button text - static const TextStyle button = TextStyle( - fontSize: 16, - fontWeight: FontWeight.w500, - color: AppColors.textPrimary, - letterSpacing: 0.5, - ); - - // Caption and overline - static const TextStyle caption = TextStyle( - fontSize: 12, - fontWeight: FontWeight.normal, - color: AppColors.textSecondary, - height: 1.4, - ); - - static const TextStyle overline = TextStyle( - fontSize: 10, - fontWeight: FontWeight.w500, - color: AppColors.textSecondary, - letterSpacing: 1.5, - height: 1.4, - ); -} \ No newline at end of file diff --git a/apps/client/lib/core/theme/theme_service.dart b/apps/client/lib/core/theme/theme_service.dart index d8161250..8d85167a 100644 --- a/apps/client/lib/core/theme/theme_service.dart +++ b/apps/client/lib/core/theme/theme_service.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:get/get.dart'; import 'package:get_storage/get_storage.dart'; import '../utils/logger.dart'; diff --git a/apps/client/lib/core/utils/audio_player_utils.dart b/apps/client/lib/core/utils/audio_player_utils.dart deleted file mode 100644 index 3027bf47..00000000 --- a/apps/client/lib/core/utils/audio_player_utils.dart +++ /dev/null @@ -1,70 +0,0 @@ -import 'package:just_audio/just_audio.dart'; -import 'logger.dart'; - -/// 音频播放工具类 -/// 提供播放assets及本地音频文件的功能 -class AudioPlayerUtils { - // 单例模式 - static final AudioPlayerUtils instance = AudioPlayerUtils._internal(); - - // 音频播放器 - final AudioPlayer _audioPlayer = AudioPlayer(); - - // 构造函数 - AudioPlayerUtils._internal() { - _setupAudioPlayer(); - } - - /// 设置音频播放器 - void _setupAudioPlayer() { - // 可以根据需要添加播放状态监听等 - } - - /// 播放assets中的音频文件 - /// [assetPath] assets资源路径,例如 'assets/listening.mp3' - Future playAssetAudio(String assetPath) async { - try { - // 停止当前播放 - await stopPlayback(); - - // 设置音频源并播放 - await _audioPlayer.setAsset(assetPath); - await _audioPlayer.play(); - - Logger.info('播放assets音频: $assetPath'); - } catch (e) { - Logger.error('播放assets音频失败', e); - } - } - - /// 播放本地文件路径的音频 - /// [filePath] 本地文件路径 - Future playLocalAudio(String filePath) async { - try { - // 停止当前播放 - await stopPlayback(); - - // 设置音频源并播放 - await _audioPlayer.setFilePath(filePath); - await _audioPlayer.play(); - - Logger.info('播放本地音频文件: $filePath'); - } catch (e) { - Logger.error('播放本地音频文件失败', e); - } - } - - /// 停止播放 - Future stopPlayback() async { - try { - await _audioPlayer.stop(); - } catch (e) { - Logger.error('停止播放失败', e); - } - } - - /// 释放资源 - void dispose() { - _audioPlayer.dispose(); - } -} \ No newline at end of file diff --git a/apps/client/lib/core/widgets/global_ai_orb.dart b/apps/client/lib/core/widgets/global_ai_orb.dart deleted file mode 100644 index e713f87a..00000000 --- a/apps/client/lib/core/widgets/global_ai_orb.dart +++ /dev/null @@ -1,27 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; - -import '../utils/ai_navigation.dart'; -import '../../modules/home/views/widgets/siri_orb_view.dart'; - -/// AI 球:点击进入 AI 助手,系统返回键回到点击前的页面。 -/// -/// 改版前它是挂在 main.dart 最外层、可拖到屏幕任意位置的全局悬浮球,结果 -/// 经常压住底部 tab 栏或页面标题。现在改为只由 AI tab 自己渲染并固定在底部 -/// 导航栏正上方居中(见 ai_tab.dart),所以这里只保留按钮本体,不再有 -/// Positioned / 拖拽 / 位置持久化。 -class AiOrbButton extends StatelessWidget { - const AiOrbButton({super.key}); - - /// 比原来嵌在首页里的版本(76.w)小一圈 - static const double ballSize = 56; - - @override - Widget build(BuildContext context) { - return GestureDetector( - behavior: HitTestBehavior.opaque, - onTap: navigateToAIAssistant, - child: SiriOrbView(size: ballSize.w), - ); - } -} diff --git a/apps/client/lib/core/widgets/intro_overlay_builder.dart b/apps/client/lib/core/widgets/intro_overlay_builder.dart deleted file mode 100644 index abbcb547..00000000 --- a/apps/client/lib/core/widgets/intro_overlay_builder.dart +++ /dev/null @@ -1,402 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_intro/flutter_intro.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:get/get.dart'; -import 'package:lottie/lottie.dart'; - -class IntroOverlayBuilder { - static OverlayPosition overlayPosition({ - required Offset offset, - required Size screenSize, - required Size size, - }) { - return OverlayPosition( - top: 0, - width: screenSize.width, - crossAxisAlignment: CrossAxisAlignment.center, - ); - } - - static Widget homeBuilder( - StepWidgetParams params, - bool isWakeup, { - String title = 'sayLilyHint', - Function? onNext, - }) { - return Column( - children: [ - Container( - padding: EdgeInsetsGeometry.all(12.w), - margin: EdgeInsets.only(top: ScreenUtil().statusBarHeight), - alignment: Alignment.centerRight, - child: _button( - 'skip'.tr, - () { - params.onFinish(); - }, - isSkip: true, - ), - ), - 100.verticalSpace, - isWakeup - ? _AnimatedLottieWidget() - : SizedBox( - width: 200.w, - height: 200.w, - child: Lottie.asset('assets/lottie/intro_foriday.json'), - ), - Padding( - padding: EdgeInsets.only(bottom: 10.w), - child: Text( - isWakeup ? 'imHere'.tr : title.tr, - style: TextStyle( - fontSize: 15.sp, - color: Colors.white, - fontWeight: FontWeight.bold, - ), - ), - ), - if (onNext != null) - _button( - 'next'.tr, - () { - params.onNext!(); - onNext(); - }, - ), - ], - ); - } - - static Widget aiBuilder( - StepWidgetParams params, - String text, { - String buttonText = 'next', - bool alignment = true, - Function? onNext, - Function? onFinish, - Function? onTap, - }) { - double dy = params.offset?.dy ?? 0; - double width = params.size.width; - double height = params.size.height; - double totalHeight = dy + height + 3; - double left = params.offset?.dx ?? 0; - double right = 1.sw - left - width; - return SizedBox( - height: totalHeight, - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Container( - padding: EdgeInsetsGeometry.all(12.w), - margin: EdgeInsets.only(top: ScreenUtil().statusBarHeight), - alignment: Alignment.centerRight, - child: _button( - 'skip'.tr, - () { - params.onFinish(); - }, - isSkip: true, - ), - ), - Padding( - padding: EdgeInsets.only( - left: alignment ? left - 3 : 12.w - 3, - right: alignment ? 12.w - 3 : right - 3, - ), - child: Column( - crossAxisAlignment: - alignment ? CrossAxisAlignment.start : CrossAxisAlignment.end, - children: [ - Padding( - padding: const EdgeInsets.symmetric(horizontal: 3), - child: Text( - text, - style: TextStyle( - fontSize: 15.sp, - color: Colors.white, - fontWeight: FontWeight.bold, - ), - ), - ), - Row( - children: [ - if (onNext != null) - Padding( - padding: EdgeInsets.only(top: 10.w, left: 3, right: 3), - child: _button( - buttonText.tr, - () { - params.onNext!(); - onNext(); - }, - ), - ), - if (onFinish != null) - Padding( - padding: EdgeInsets.only(top: 10.w, left: 3, right: 3), - child: _button( - buttonText.tr, - () { - params.onFinish(); - onFinish(); - }, - ), - ), - ], - ), - SizedBox(height: 20.w), - onTap != null - ? _AnimatedBorderButton( - onTap: () { - onTap(); - }, - isButton: false, - child: Padding( - padding: const EdgeInsetsGeometry.all(3), - child: SizedBox( - width: width, - height: height, - ), - ), - ) - : Padding( - padding: const EdgeInsetsGeometry.all(3), - child: SizedBox( - width: width, - height: height, - ), - ), - ], - ), - ), - ], - ), - ); - } - - static Widget _button(String text, Function() onTap, {bool isSkip = false}) { - return isSkip - ? GestureDetector( - onTap: onTap, - child: Container( - padding: EdgeInsets.symmetric(horizontal: 15.w, vertical: 5.w), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(20.r), - border: Border.all(color: Colors.white), - ), - child: Text( - text, - style: TextStyle( - fontSize: 14.sp, - color: Colors.white, - ), - ), - ), - ) - : _AnimatedBorderButton( - onTap: onTap, - child: Container( - padding: EdgeInsets.symmetric(horizontal: 15.w, vertical: 5.w), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(20.r), - border: Border.all(color: Colors.transparent), - ), - child: Text( - text, - style: TextStyle( - fontSize: 14.sp, - color: Colors.white, - ), - ), - ), - ); - } -} - -// 新增的动画Widget -class _AnimatedLottieWidget extends StatefulWidget { - @override - _AnimatedLottieWidgetState createState() => _AnimatedLottieWidgetState(); -} - -class _AnimatedLottieWidgetState extends State<_AnimatedLottieWidget> - with SingleTickerProviderStateMixin { - late AnimationController _animationController; - late Animation _scaleAnimation; - - @override - void initState() { - super.initState(); - - // 创建动画控制器,持续时间1.5秒 - _animationController = AnimationController( - duration: const Duration(milliseconds: 1000), - vsync: this, - ); - - // 创建缩放动画,从0.8到1.2再回到1.0 - _scaleAnimation = Tween( - begin: 0.8, - end: 1.2, - ).animate(CurvedAnimation( - parent: _animationController, - curve: Curves.elasticInOut, - )); - - // 启动动画并设置为循环 - _animationController.repeat(reverse: true); - } - - @override - void dispose() { - _animationController.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return AnimatedBuilder( - animation: _scaleAnimation, - builder: (context, child) { - return Transform.scale( - scale: _scaleAnimation.value, - child: SizedBox( - width: 200.w, - height: 200.w, - child: Lottie.asset('assets/lottie/intro_foriday.json'), - ), - ); - }, - ); - } -} - -// 新增的带边框流动动画的按钮组件 -class _AnimatedBorderButton extends StatefulWidget { - final Widget child; - final bool isButton; - final Function() onTap; - - const _AnimatedBorderButton({ - required this.child, - required this.onTap, - this.isButton = true, - }); - - @override - _AnimatedBorderButtonState createState() => _AnimatedBorderButtonState(); -} - -class _AnimatedBorderButtonState extends State<_AnimatedBorderButton> - with SingleTickerProviderStateMixin { - late AnimationController _animationController; - late Animation _animation; - - @override - void initState() { - super.initState(); - _animationController = AnimationController( - duration: const Duration(seconds: 2), - vsync: this, - ); - _animation = Tween( - begin: 0.0, - end: 1.0, - ).animate(_animationController); - - _animationController.repeat(); - } - - @override - void dispose() { - _animationController.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return GestureDetector( - onTap: widget.onTap, - child: AnimatedBuilder( - animation: _animation, - builder: (context, child) { - return CustomPaint( - painter: _FlowingBorderPainter( - progress: _animation.value, - borderRadius: widget.isButton ? 20.r : 0.r, - ), - child: widget.child, - ); - }, - ), - ); - } -} - -// 自定义绘制器,用于绘制流动的边框 -class _FlowingBorderPainter extends CustomPainter { - final double progress; - final double borderRadius; - - _FlowingBorderPainter({ - required this.progress, - required this.borderRadius, - }); - - @override - void paint(Canvas canvas, Size size) { - final rect = Rect.fromLTWH(0, 0, size.width, size.height); - final rrect = RRect.fromRectAndRadius(rect, Radius.circular(borderRadius)); - - // 计算路径总长度 - final path = Path()..addRRect(rrect); - final pathMetrics = path.computeMetrics().first; - final totalLength = pathMetrics.length; - - // 流动效果:创建一个渐变的虚线效果 - final dashLength = totalLength * 0.3; // 虚线长度 - final startOffset = (progress * totalLength) % totalLength; - - // 绘制流动的边框段 - for (int i = 0; i < 3; i++) { - final offset = (startOffset + i * totalLength / 3) % totalLength; - final endOffset = (offset + dashLength) % totalLength; - - Path extractedPath; - if (endOffset > offset) { - extractedPath = pathMetrics.extractPath(offset, endOffset); - } else { - // 处理跨越路径起点的情况 - final path1 = pathMetrics.extractPath(offset, totalLength); - final path2 = pathMetrics.extractPath(0, endOffset); - extractedPath = Path() - ..addPath(path1, Offset.zero) - ..addPath(path2, Offset.zero); - } - - // 创建渐变效果 - const gradient = LinearGradient( - colors: [ - Colors.green, - Colors.yellow, - Colors.red, - ], - stops: [0.0, 0.5, 1.0], - ); - - final gradientPaint = Paint() - ..shader = gradient.createShader(rect) - ..style = PaintingStyle.stroke - ..strokeWidth = 1.5; - - canvas.drawPath(extractedPath, gradientPaint); - } - } - - @override - bool shouldRepaint(covariant CustomPainter oldDelegate) { - return true; - } -} diff --git a/apps/client/lib/data/models/agent.dart b/apps/client/lib/data/models/agent.dart deleted file mode 100644 index 0bdbd278..00000000 --- a/apps/client/lib/data/models/agent.dart +++ /dev/null @@ -1,83 +0,0 @@ - -class Agent { - final String id; - final String name; - final String avatarUrl; - final String description; - final String tag; - final bool isOnline; - final String voice; - final String welcomeMessage; - final String? voiceWelcomeMessage; - final String systemPrompt; - - const Agent({ - required this.id, - required this.name, - required this.avatarUrl, - required this.description, - required this.tag, - required this.isOnline, - required this.voice, - required this.welcomeMessage, - this.voiceWelcomeMessage, - required this.systemPrompt, - }); - - // 添加一个fromJson构造函数 - factory Agent.fromJson(Map json) { - return Agent( - id: json['id'] as String, - name: json['name'] as String, - avatarUrl: json['avatarUrl'] as String, - description: json['description'] as String, - tag: json['tag'] as String, - isOnline: json['isOnline'] as bool, - voice: json['voice'] as String, - welcomeMessage: json['welcomeMessage'] as String, - systemPrompt: json['systemPrompt'] as String, - ); - } - - // 添加一个toJson方法 - Map toJson() { - return { - 'id': id, - 'name': name, - 'avatarUrl': avatarUrl, - 'description': description, - 'tag': tag, - 'isOnline': isOnline, - 'voice': voice, - 'welcomeMessage': welcomeMessage, - 'systemPrompt': systemPrompt, - 'voiceWelcomeMessage': voiceWelcomeMessage, - }; - } - - // 添加一个copyWith方法 - Agent copyWith({ - String? id, - String? name, - String? avatarUrl, - String? description, - String? tag, - bool? isOnline, - String? voice, - String? welcomeMessage, - String? systemPrompt, - }) { - return Agent( - id: id ?? this.id, - name: name ?? this.name, - avatarUrl: avatarUrl ?? this.avatarUrl, - description: description ?? this.description, - tag: tag ?? this.tag, - isOnline: isOnline ?? this.isOnline, - voice: voice ?? this.voice, - welcomeMessage: welcomeMessage ?? this.welcomeMessage, - systemPrompt: systemPrompt ?? this.systemPrompt, - voiceWelcomeMessage: voiceWelcomeMessage ?? this.voiceWelcomeMessage, - ); - } -} \ No newline at end of file diff --git a/apps/client/lib/data/models/events/voice_interaction_event.dart b/apps/client/lib/data/models/events/voice_interaction_event.dart deleted file mode 100644 index 81860de2..00000000 --- a/apps/client/lib/data/models/events/voice_interaction_event.dart +++ /dev/null @@ -1,42 +0,0 @@ -import 'package:meta/meta.dart'; - -/// 语音交互事件基类 -abstract class VoiceInteractionEvent { - final int timestamp; - - VoiceInteractionEvent({required this.timestamp}); -} - -/// 聊天历史事件 -class ChatHistoryEvent extends VoiceInteractionEvent { - final String agentId; - final String userMessage; - final String assistantMessage; - - ChatHistoryEvent({ - required this.agentId, - required this.userMessage, - required this.assistantMessage, - required int timestamp, - }) : super(timestamp: timestamp); -} - -/// 语音识别开始事件 -class RecognitionStartedEvent extends VoiceInteractionEvent { - RecognitionStartedEvent({ - required int timestamp, - }) : super(timestamp: timestamp); -} - -/// 通用语音交互事件 -/// 用于处理其他类型的事件 -class GenericVoiceInteractionEvent extends VoiceInteractionEvent { - final String type; - final Map? data; - - GenericVoiceInteractionEvent({ - required this.type, - this.data, - required int timestamp, - }) : super(timestamp: timestamp); -} \ No newline at end of file diff --git a/apps/client/lib/data/models/message_model.dart b/apps/client/lib/data/models/message_model.dart deleted file mode 100644 index c19fe9f8..00000000 --- a/apps/client/lib/data/models/message_model.dart +++ /dev/null @@ -1,105 +0,0 @@ -import 'dart:io'; - -import 'package:path_provider/path_provider.dart'; - -class Message { - final String sessionid; // 会话ID - final bool isUser; //标识信息是否来自用户还是AI - final String text; //信息文本内容 - final DateTime timestamp; // 消息时间戳 - final bool isRecognizing; // 是否为语音识别中的临时消息 - final bool hasImage; // 是否包含图片 - final String? imagePath; // 图片路径 - final Map? meta; //卡片数据 - final Map>? functionCalls; // 函数调用 - bool isToolCallsExpanded; // 工具调用是否展开 - - Message({ - // 构造函数 - required this.sessionid, // 会话ID - required this.isUser, - required this.text, - DateTime? timestamp, - this.isRecognizing = false, - this.hasImage = false, - this.imagePath, - this.meta, - this.functionCalls, - this.isToolCallsExpanded = false, // 默认不展开 - }) : this.timestamp = timestamp ?? DateTime.now(); - - // 从JSON构造函数 - factory Message.fromJson(Map json) { - return Message( - sessionid: json['sessionid'] as String, // 会话ID - isUser: json['isUser'] as bool, - text: json['text'] as String, - timestamp: DateTime.parse(json['timestamp'] as String).toLocal(), - isRecognizing: json['isRecognizing'] as bool? ?? false, - hasImage: json['hasImage'] as bool? ?? false, - imagePath: json['imagePath'] as String?, - meta: json['meta'] as Map?, - functionCalls: - json['functionCalls'] as Map>?, - isToolCallsExpanded: json['isToolCallsExpanded'] as bool? ?? false, - ); - } - - // 转换为JSON - Map toJson() { - return { - 'isUser': isUser, - 'text': text, - 'timestamp': timestamp.toIso8601String(), - 'isRecognizing': isRecognizing, - 'hasImage': hasImage, - 'imagePath': imagePath, - 'meta': meta, - 'functionCalls': functionCalls, - 'isToolCallsExpanded': isToolCallsExpanded, - }; - } - - // 创建一个加载中的消息 - factory Message.loading() { - return Message( - sessionid: '', // 会话ID - isUser: false, - text: '', - timestamp: DateTime.now(), - isRecognizing: true, - ); - } - - // 复制并修改 - Message copyWith({ - required String sessionid, // 会话ID - bool? isUser, - String? text, - DateTime? timestamp, - bool? isRecognizing, - bool? hasImage, - String? imagePath, - Map? meta, - Map>? functionCalls, - bool? isToolCallsExpanded, - }) { - return Message( - sessionid: sessionid, // 会话ID - isUser: isUser ?? this.isUser, - text: text ?? this.text, - timestamp: timestamp ?? this.timestamp, - isRecognizing: isRecognizing ?? this.isRecognizing, - hasImage: hasImage ?? this.hasImage, - imagePath: imagePath ?? this.imagePath, - meta: meta ?? this.meta, - functionCalls: functionCalls ?? this.functionCalls, - isToolCallsExpanded: isToolCallsExpanded ?? this.isToolCallsExpanded, - ); - } - - // 切换工具调用展开状态 - void toggleToolCallsExpanded() { - isToolCallsExpanded = !isToolCallsExpanded; - } -} diff --git a/apps/client/lib/data/services/audio_service.dart b/apps/client/lib/data/services/audio_service.dart deleted file mode 100644 index 6dbdd781..00000000 --- a/apps/client/lib/data/services/audio_service.dart +++ /dev/null @@ -1,29 +0,0 @@ -import 'dart:async'; -import 'dart:typed_data'; - -/// 语音识别服务接口 -abstract class AudioService { - /// 开始录音 - Future enableRecord(String filePath); - - /// 暂停录音 - Future pauseRecord(); - - /// 继续录音 - Future resumeRecord(); - - /// 设置音频配置 - Future setAudioConfig({ - int sampleRate = 16000, - int channels = 1, - }); - - // /// 移动文件到新路径 - Future moveFile(String sourcePath, String destPath); - - // /// 重命名指定路径的音频文件 - Future renameFile(String filePath, String newName); - - /// 结束录音 - Future stopRecord(bool isSave); -} diff --git a/apps/client/lib/data/services/location_manager.dart b/apps/client/lib/data/services/location_manager.dart deleted file mode 100644 index ccad59a9..00000000 --- a/apps/client/lib/data/services/location_manager.dart +++ /dev/null @@ -1,57 +0,0 @@ -import '/core/utils/logger.dart'; -import 'package:get/get.dart'; -import 'package:location_service/location_service.dart'; -import 'package:permission_handler/permission_handler.dart'; -import '/core/utils/permission_util.dart'; - -/// 定位管理 -class LocationManager extends GetxService { - static LocationManager get to => Get.find(); - - final LocationService _locationService = LocationService(); - - /// 初始化 - /// - /// 合规(场景 1/2):这里**不能**申请定位权限。 - /// 这个 Service 是 lazyPut 出来的,任何页面 find 一下就会触发 onInit, - /// 原来在这里申请 locationAlways(后台定位),等于用户没点任何跟定位有关的 - /// 功能、甚至刚进首页就被弹后台定位框,属于「申请与当前服务场景无关的权限」。 - /// 现在改成用到定位时由 [ensureLocationPermission] 按场景申请。 - @override - void onInit() { - super.onInit(); - } - - /// 当前是否已有定位权限(只查不申请,供 UI 置灰判断) - Future get hasLocationPermission => - PermissionUtil.instance.hasPermission(Permission.locationWhenInUse); - - /// 用户拒绝过、还在 48h 冷却里 —— UI 应把定位相关入口置灰 - bool get isPermissionCoolingDown => - PermissionUtil.instance.isDenialCoolingDown(Permission.locationWhenInUse); - - /// 在真正需要定位的场景下申请权限。 - /// - /// 申请的是 locationWhenInUse(使用期间),不是 locationAlways—— - /// 本 App 没有后台持续定位的场景,申请后台定位过不了合规审核。 - /// - /// 返回 false 表示拿不到权限(用户拒绝或处于冷却期),调用方应把功能置灰 - /// 或退出,**不要**再补弹窗。 - Future ensureLocationPermission() async { - final granted = await PermissionUtil.instance.requestPermission( - permissionType: Permission.locationWhenInUse, - permissionName: 'locationPermission'.tr, - explanationText: 'locationPermissionExplanation'.tr, - permanentDenialText: 'locationPermissionPermanentDenial'.tr, - ); - if (!granted) { - Logger.warning('定位权限未授予,定位功能不可用'); - } - return granted; - } - - //定位 - Future> location() async { - return await _locationService.location(); - } -} diff --git a/apps/client/lib/data/services/microsoft_translation_service.dart b/apps/client/lib/data/services/microsoft_translation_service.dart deleted file mode 100644 index 9aee7c3c..00000000 --- a/apps/client/lib/data/services/microsoft_translation_service.dart +++ /dev/null @@ -1,247 +0,0 @@ -import 'dart:convert'; - -import 'package:get/get.dart'; -import 'package:http/http.dart' as http; - -import '../../core/utils/logger.dart'; -import '../../data/models/appconfig.dart'; -import 'language_configs/azure_language_config.dart'; -import 'language_manager.dart'; - -/// 微软 Azure Translator REST 翻译服务 -/// 端点:https://api.cognitive.microsofttranslator.com -/// 文档:https://learn.microsoft.com/azure/ai-services/translator/reference/v3-0-translate -class MicrosoftTranslationService extends GetxService { - static const String _defaultEndpoint = - 'https://api.cognitive.microsofttranslator.com'; - static const String _apiPath = '/translate'; - static const String _apiVersion = '3.0'; - - late final String _subscriptionKey; - late final String _region; - late final String _endpoint; - - bool _isInitialized = false; - bool get isInitialized => _isInitialized; - - final LanguageManager _languageManager = Get.find(); - - /// shortCode -> 微软 translationCode 缓存(由 getAzureTranslationLanguageSpecs 构建) - final Map _shortCodeToTranslationCode = {}; - - @override - Future onInit() async { - await initialize(); - super.onInit(); - } - - Future initialize() async { - if (_isInitialized) return true; - try { - _subscriptionKey = AppConfig.cred('mt_azure', 'subscription_key', 'AZURE_TRANSLATION_KEY') ?? ''; - _region = AppConfig.cred('mt_azure', 'region', 'AZURE_TRANSLATION_REGION') ?? ''; - _endpoint = - AppConfig.cred('mt_azure', 'endpoint', 'AZURE_TRANSLATION_ENDPOINT') ?? _defaultEndpoint; - - if (_subscriptionKey.isEmpty) { - print( - '🟢[MS-TRANS-DBG] AZURE_TRANSLATION_KEY 未配置,服务无法初始化'); - Logger.error('微软翻译服务初始化失败:AZURE_TRANSLATION_KEY 为空'); - return false; - } - - for (final spec in getAzureTranslationLanguageSpecs()) { - final short = spec['shortCode']; - final code = spec['translationCode']; - if (short != null && code != null) { - _shortCodeToTranslationCode[short] = code; - } - } - - _isInitialized = true; - print( - '🟢[MS-TRANS-DBG] 微软翻译服务初始化成功: endpoint=$_endpoint, region=$_region, keyLen=${_subscriptionKey.length}, specCount=${_shortCodeToTranslationCode.length}'); - Logger.info('微软翻译服务初始化成功 region=$_region'); - return true; - } catch (e) { - print('🟢[MS-TRANS-DBG] 微软翻译服务初始化异常: $e'); - Logger.error('微软翻译服务初始化异常: $e'); - return false; - } - } - - /// 把 ASR 代码(如 `zh-CN`)映射为微软 Translator 语言码(如 `zh-Hans`) - /// 找不到返回 null - String? _toTranslationCode(String asrCode) { - if (asrCode.isEmpty) return null; - final short = _languageManager.getShortCodeByAsrCode(asrCode); - if (short == null) return null; - return _shortCodeToTranslationCode[short]; - } - - /// 文本翻译 - /// [text] 待翻译文本 - /// [sourceLanguageCode] 源语言 ASR 码(传空串则让微软自动检测) - /// [targetLanguageCode] 目标语言 ASR 码 - Future translateText({ - required String text, - required String sourceLanguageCode, - required String targetLanguageCode, - }) async { - if (!_isInitialized) { - print('🟢[MS-TRANS-DBG] 未初始化,返回 null'); - Logger.error('微软翻译服务未初始化'); - return null; - } - if (text.isEmpty) return null; - - try { - final String? targetCode = _toTranslationCode(targetLanguageCode); - if (targetCode == null) { - print( - '🟢[MS-TRANS-DBG] 目标语言码映射失败: targetAsr=$targetLanguageCode,返回 null'); - Logger.error('微软翻译失败:目标语言 $targetLanguageCode 不在映射表'); - return null; - } - final String? sourceCode = _toTranslationCode(sourceLanguageCode); - - final queryParams = { - 'api-version': _apiVersion, - 'to': targetCode, - }; - if (sourceCode != null && sourceCode.isNotEmpty) { - queryParams['from'] = sourceCode; - } - - final uri = Uri.parse('$_endpoint$_apiPath') - .replace(queryParameters: queryParams); - final body = json.encode([ - {'text': text} - ]); - final headers = { - 'Content-Type': 'application/json', - 'Ocp-Apim-Subscription-Key': _subscriptionKey, - 'Ocp-Apim-Subscription-Region': _region, - 'X-ClientTraceId': _newTraceId(), - }; - - print( - '🟢[MS-TRANS-DBG] 发起翻译请求: uri=$uri, from=$sourceCode, to=$targetCode, text=$text'); - final response = - await http.post(uri, headers: headers, body: body).timeout( - const Duration(seconds: 10), - onTimeout: () => http.Response('{"error":"timeout"}', 408), - ); - print( - '🟢[MS-TRANS-DBG] 翻译响应: status=${response.statusCode}, bodyLen=${response.body.length}, body=${response.body.length > 500 ? response.body.substring(0, 500) : response.body}'); - - if (response.statusCode != 200) { - Logger.error( - '微软翻译 HTTP 错误: status=${response.statusCode}, body=${response.body}'); - return null; - } - - final decoded = json.decode(response.body); - if (decoded is! List || decoded.isEmpty) { - print('🟢[MS-TRANS-DBG] 响应非 List 或为空,解析失败'); - return null; - } - final first = decoded.first; - if (first is! Map) return null; - final translations = first['translations']; - if (translations is! List || translations.isEmpty) return null; - final translated = translations.first; - if (translated is! Map) return null; - final result = translated['text']; - if (result is! String) return null; - print('🟢[MS-TRANS-DBG] 翻译成功: $result'); - return result; - } catch (e, st) { - print('🟢[MS-TRANS-DBG] 翻译请求异常: $e\n$st'); - Logger.error('微软翻译请求异常: $e'); - return null; - } - } - - // ===== 语种检测(Azure Translator /detect)===== - // 与原火山实现保持同一契约:返回 **ASR 代码**(如 zh-CN), - // 带同文本缓存与最小请求间隔,避免自动检测场景下频繁打接口。 - DateTime? _lastDetectTime; - String? _lastDetectTextKey; - final Map _detectCache = {}; - static const Duration _detectMinInterval = Duration(milliseconds: 800); - - Future detectTextLanguage({required String text}) async { - if (!_isInitialized) { - Logger.error('语种检测服务未初始化'); - return null; - } - final normalized = text.trim(); - if (normalized.isEmpty) return null; - final textKey = - normalized.length > 256 ? normalized.substring(0, 256) : normalized; - - // 命中缓存直接返回 - final cachedShort = _detectCache[textKey]; - if (cachedShort != null && cachedShort.isNotEmpty) { - final cachedAsr = _languageManager.getAsrCodeByShortCode(cachedShort); - if (cachedAsr != null && cachedAsr.isNotEmpty) return cachedAsr; - } - - // 频率控制:同一文本在最小间隔内不重复请求 - final now = DateTime.now(); - if (_lastDetectTime != null && _lastDetectTextKey == textKey) { - if (now.difference(_lastDetectTime!) < _detectMinInterval) { - Logger.info('语种检测过于频繁,已短路本次请求'); - return null; - } - } - _lastDetectTime = now; - _lastDetectTextKey = textKey; - - try { - final uri = Uri.parse('$_endpoint/detect') - .replace(queryParameters: {'api-version': _apiVersion}); - final response = await http - .post(uri, - headers: { - 'Content-Type': 'application/json', - 'Ocp-Apim-Subscription-Key': _subscriptionKey, - 'Ocp-Apim-Subscription-Region': _region, - 'X-ClientTraceId': _newTraceId(), - }, - body: json.encode([ - {'text': textKey} - ])) - .timeout(const Duration(seconds: 10), - onTimeout: () => http.Response('{"error":"timeout"}', 408)); - - if (response.statusCode != 200) { - Logger.error( - '微软语种检测 HTTP 错误: status=${response.statusCode}, body=${response.body}'); - return null; - } - final decoded = json.decode(response.body); - if (decoded is! List || decoded.isEmpty) return null; - final first = decoded.first; - if (first is! Map) return null; - final short = first['language']; - if (short is! String || short.isEmpty) return null; - - // Azure 返回的是短代码(en / zh-Hans / ja …),统一收敛到项目的 shortCode - final normalizedShort = short.split('-').first.toLowerCase(); - _detectCache[textKey] = normalizedShort; - final asr = _languageManager.getAsrCodeByShortCode(normalizedShort); - Logger.info('微软语种检测: $short -> short=$normalizedShort, asr=$asr'); - return asr; - } catch (e) { - Logger.error('微软语种检测异常: $e'); - return null; - } - } - - String _newTraceId() { - final now = DateTime.now().microsecondsSinceEpoch; - return 'ms-trans-$now'; - } -} diff --git a/apps/client/lib/data/services/music_manager.dart b/apps/client/lib/data/services/music_manager.dart index da3ac828..6d782607 100644 --- a/apps/client/lib/data/services/music_manager.dart +++ b/apps/client/lib/data/services/music_manager.dart @@ -3,7 +3,6 @@ import 'package:get/get.dart'; import 'package:music_service/music_service.dart'; import 'package:permission_handler/permission_handler.dart'; import '../../core/utils/permission_util.dart'; -import 'package:flutter/material.dart'; //音乐播放管理 class MusicManager extends GetxService { diff --git a/apps/client/lib/data/services/navigation_manager.dart b/apps/client/lib/data/services/navigation_manager.dart deleted file mode 100644 index e1334e5a..00000000 --- a/apps/client/lib/data/services/navigation_manager.dart +++ /dev/null @@ -1,41 +0,0 @@ -import 'package:amap_service/amap_service.dart'; -import '../../core/utils/logger.dart'; -import 'package:get/get.dart'; - -//导航管理 -class NavigationManager extends GetxService { - static NavigationManager get to => Get.find(); - - // 导航服务实例 - final AmapService _amapervice = AmapService(); - - /// 初始化 - @override - void onInit() { - super.onInit(); - Logger.info('导航服务初始化'); - } - - /// 释放资源 - @override - void onClose() { - super.onClose(); - } - - Stream events() { - return _amapervice.events; - } - - //导航 - Future start(String org, String dis) async { - // await _amapervice.navigation(org, dis); - } - //导航 - Future open( - String start, - String end, - String ntype, - ) async { - await _amapervice.open(start, end, ntype); - } -} diff --git a/apps/client/lib/data/services/network/api.dart b/apps/client/lib/data/services/network/api.dart index 85bdcd72..70a31309 100644 --- a/apps/client/lib/data/services/network/api.dart +++ b/apps/client/lib/data/services/network/api.dart @@ -191,15 +191,6 @@ class Api { ); } - // 获取阿里token - static getAliToken([params]) { - return DioManager().request( - NWMethod.post, - '/api/home/auth_alitoken', - params: params, - ); - } - //更新用户设置 static updateUserSetting([dynamic params]) { return DioManager().request( @@ -253,15 +244,6 @@ class Api { ); } - //app获取设备信息 - static getproducts([params]) { - return DioManager().request( - NWMethod.post, - '/api/home/user_getproducts', - params: params, - ); - } - //举报AI内容 static reportAiContent([params]) { return DioManager().request( @@ -271,15 +253,6 @@ class Api { ); } - //获取音乐连接 - static getMusicUrl([params]) { - return DioManager().request( - NWMethod.post, - '/api/home/music_getmusicurl', - params: params, - ); - } - // 获取会议助手数据 static getOperationAllRecord([params]) { diff --git a/apps/client/lib/data/services/pay_service.dart b/apps/client/lib/data/services/pay_service.dart index ded2dda7..4d4f8be2 100644 --- a/apps/client/lib/data/services/pay_service.dart +++ b/apps/client/lib/data/services/pay_service.dart @@ -261,7 +261,6 @@ class PayService extends GetxService { _iapOnResult?.call(false, details.error?.message ?? '支付错误'); break; case PurchaseStatus.purchased: - final txId = details.purchaseID ?? ''; final ok = await _verifyIapWithServer(details); if (!ok) { print( @@ -281,7 +280,6 @@ class PayService extends GetxService { break; case PurchaseStatus.restored: - final txId = details.purchaseID ?? ''; final ok = await _verifyIapWithServer(details); if (!ok) { print( diff --git a/apps/client/lib/data/services/qq_music.dart b/apps/client/lib/data/services/qq_music.dart index 2ea18a91..0f37e16e 100644 --- a/apps/client/lib/data/services/qq_music.dart +++ b/apps/client/lib/data/services/qq_music.dart @@ -1,5 +1,4 @@ import 'dart:async'; -import 'dart:ffi'; import 'package:get/get.dart'; import 'package:qq_music/qq_music.dart'; import '../models/song_model.dart'; @@ -151,12 +150,6 @@ class QqMusicService extends GetxService { } } - // 后台执行的同步方法 - static Future> _performSync(dynamic _) async { - final qqMusic = QqMusic(); - return await qqMusic.syncCurrentPlayInfo(); - } - /// 格式化时间 String formatDuration(int milliseconds) { final duration = Duration(milliseconds: milliseconds); diff --git a/apps/client/lib/data/services/speech_impl/azure_asr_service.dart b/apps/client/lib/data/services/speech_impl/azure_asr_service.dart index 6148c65e..b3f4bf03 100644 --- a/apps/client/lib/data/services/speech_impl/azure_asr_service.dart +++ b/apps/client/lib/data/services/speech_impl/azure_asr_service.dart @@ -3,7 +3,6 @@ import 'dart:io'; import 'dart:typed_data'; import '../../../data/models/appconfig.dart'; import 'package:flutter/services.dart'; -import 'package:get_storage/get_storage.dart'; import '../../../core/utils/logger.dart'; import 'package:get/get.dart'; import '../asr_service.dart'; @@ -58,7 +57,6 @@ class AzureAsrService extends GetxService implements AsrService { // 防抖时间戳与间隔(实例级) DateTime? _lastStartAt; - DateTime? _lastStopAt; static const Duration _debounce = Duration(milliseconds: 600); AzureAsrService() { @@ -253,7 +251,6 @@ class AzureAsrService extends GetxService implements AsrService { Future stopContinuousRecognition() async { // 移除防抖判断,确保停止操作总是被执行 // 这与 AgentService 的逻辑保持一致,防止“松开还在录”的问题 - _lastStopAt = DateTime.now(); if (!_isInitialized || !_isContinuousRecognitionActive) { return true; @@ -695,7 +692,7 @@ class AzureAsrService extends GetxService implements AsrService { Future disableBluetoothAudio() async { // TODO: implement disableBluetoothAudio try { - final bool result = await _channel.invokeMethod('disableBluetoothAudio'); + await _channel.invokeMethod('disableBluetoothAudio'); return; } catch (e) { Logger.error('开始录音: ${e.toString()}'); @@ -707,8 +704,7 @@ class AzureAsrService extends GetxService implements AsrService { Future restoreOriginalAudioState() async { // TODO: implement restoreOriginalAudioState try { - final bool result = - await _channel.invokeMethod('restoreOriginalAudioState'); + await _channel.invokeMethod('restoreOriginalAudioState'); return; } catch (e) { Logger.error('开始录音: ${e.toString()}'); diff --git a/apps/client/lib/data/services/speech_impl/azure_ast_service.dart b/apps/client/lib/data/services/speech_impl/azure_ast_service.dart index 7c32f16e..6317a2cc 100644 --- a/apps/client/lib/data/services/speech_impl/azure_ast_service.dart +++ b/apps/client/lib/data/services/speech_impl/azure_ast_service.dart @@ -73,7 +73,6 @@ class AzureAstService extends GetxService implements AstService { List get supportedLanguages => _defaultSupportedLanguages; //连续识别相关 - bool _isContinuousRecognitionActive = false; StreamController? _eventStreamController; StreamSubscription? _eventSubscription; @@ -200,14 +199,12 @@ class AzureAstService extends GetxService implements AstService { case 'sessionStopped': Logger.info('[STS] 会话停止'); - _isContinuousRecognitionActive = false; _eventStreamController?.add(ASTEvent( type: ASTEventType.sessionStopped, )); break; case 'canceled': - _isContinuousRecognitionActive = false; final String reason = eventMap['reason'] as String? ?? ''; final String errorDetails = eventMap['errorDetails'] as String? ?? ''; Logger.error('[STS] 识别取消: $reason - $errorDetails'); @@ -265,7 +262,6 @@ class AzureAstService extends GetxService implements AstService { void _cleanupEventStream() { _eventStreamController?.close(); _eventStreamController = null; - _isContinuousRecognitionActive = false; } /// 从环境变量加载配置 diff --git a/apps/client/lib/data/services/speech_impl/azure_tts_service.dart b/apps/client/lib/data/services/speech_impl/azure_tts_service.dart index 19af3c0b..5b75c10c 100644 --- a/apps/client/lib/data/services/speech_impl/azure_tts_service.dart +++ b/apps/client/lib/data/services/speech_impl/azure_tts_service.dart @@ -1,9 +1,7 @@ import 'dart:async'; -import 'dart:io'; import '../../../data/models/appconfig.dart'; import 'package:flutter/services.dart'; import 'package:get/get.dart'; -import 'package:get_storage/get_storage.dart'; import '../../../core/utils/logger.dart'; import '../tts_service.dart'; diff --git a/apps/client/lib/data/services/speech_impl/voice_clone_tts_service.dart b/apps/client/lib/data/services/speech_impl/voice_clone_tts_service.dart deleted file mode 100644 index 97542c02..00000000 --- a/apps/client/lib/data/services/speech_impl/voice_clone_tts_service.dart +++ /dev/null @@ -1,433 +0,0 @@ -import 'dart:async'; -import 'dart:convert'; -import 'dart:io'; -import 'dart:typed_data'; - -import 'package:crypto/crypto.dart'; -import 'package:get/get.dart'; -import 'package:get_storage/get_storage.dart'; -import 'package:just_audio/just_audio.dart'; -import 'package:web_socket_channel/web_socket_channel.dart'; -import '../../../core/utils/logger.dart'; -import '../tts_service.dart'; -import 'volcano_tts_api_service.dart'; - -/// 声音复刻服务,负责基本的文本转语音功能 -/// -/// 使用讯飞声音复刻实现TtsService接口 -class VoiceCloneTtsService extends GetxService implements TtsService { - final String hostUrl = "wss://cn-huabei-1.xf-yun.com/v1/private/voice_clone"; - - final String appId = '43d87d22'; - final String apiKey = '2bd01ce06ac35957fc0c082f9b6284ec'; - final String apiSecret = 'ODU3OTUyYjhjMjY5NDhkMmMxYWY2Zjlm'; - - WebSocketChannel? _channel; - final AudioPlayer _player = AudioPlayer(); - late ConcatenatingAudioSource _playlist; - - // 当前语音 - String _currsessionid = ''; - final RxString _currentVoice = ''.obs; - - @override - String get currentVoice => _currentVoice.value; - - // 播放状态 - final RxBool _isSpeaking = false.obs; - - @override - bool get isSpeaking => _isSpeaking.value; - - // 事件流控制器 - final StreamController _eventController = - StreamController.broadcast(); - - @override - Stream get onEvent => _eventController.stream; - - bool _isInitialized = false; - String _resId = ''; - - // 语音合成队列 - final List _textQueue = []; - bool _isProcessingQueue = false; - - BytesBuilder _audioBytes = BytesBuilder(); - - Completer _completer = Completer(); - - final isEnabled = true.obs; - - // 流式文本缓冲区 - String _streamBuffer = ''; - - @override - Future initialize({ - List? supportedLanguages, - }) async { - if (_isInitialized) return true; - try { - final GetStorage storage = GetStorage(); - String timbre = storage.read('timbre'); - _resId = timbre; - _playlist = ConcatenatingAudioSource( - useLazyPreparation: true, - children: [], - ); - return true; - } catch (e) { - Logger.error('TTS初始化失败: ${e.toString()}'); - return false; - } - } - - @override - Future setVoice(String voiceName) async { - if (!_isInitialized) await initialize(); - try { - Logger.info('设置TTS语音: $voiceName'); - return true; - } catch (e) { - Logger.error('设置TTS语音失败: ${e.toString()}'); - return false; - } - } - - @override - Future setTtsMode(String mod) async { - if (!_isInitialized) await initialize(); - try { - Logger.info('设置TTS模式: $mod'); - return true; - } catch (e) { - Logger.error('设置TTS模式失败: ${e.toString()}'); - return false; - } - } - - @override - Future setVoiceFlocking(String speakerProfileId) async { - return true; - } - - // 语音合成 - Future _speechSynthesis(String text) async { - await _tryConnecting(); - _channel?.sink.add( - json.encode({ - "header": {"app_id": appId, "status": 2, "res_id": _resId}, - "parameter": { - "tts": { - "vcn": "x5_clone", - "audio": {"encoding": "lame", "sample_rate": 16000} - } - }, - "payload": { - "text": { - "status": 2, - "seq": 0, - "text": base64Encode(utf8.encode(text)) - } - }, - }), - ); - } - - Future _tryConnecting() async { - try { - final url = _geturl(); - _channel = WebSocketChannel.connect(Uri.parse(url)); - _channel?.stream.timeout(const Duration(seconds: 10)); //设置超时时间 - await _channel?.ready; - _channel?.stream.listen( - (message) { - _handle(message); - }, - onError: (error) { - Logger.error('连接失败: ${error.toString()}'); - }, - onDone: () { - Logger.error('WebSocket 连接已关闭!'); - }, - cancelOnError: true, - ); - } catch (e) { - Logger.error('初始化异常: ${e.toString()}'); - } - } - - String _geturl() { - // 解析 URL - final uri = Uri.parse(hostUrl); - - // 获取当前时间并格式化为 RFC1123 格式 - final date = HttpDate.format(DateTime.now().toUtc()); - - // 参与签名的字段 - final signString = [ - "host: ${uri.host}", - "date: $date", - "GET ${uri.path} HTTP/1.1", - ]; - - // 拼接签名字符串 - final sgin = signString.join("\n"); - - // 使用 HMAC-SHA256 签名 - final key = utf8.encode(apiSecret); - final bytes = utf8.encode(sgin); - final hmacSha256 = Hmac(sha256, key); - final digest = hmacSha256.convert(bytes); - final sha = base64Encode(digest.bytes); - - // 构建请求参数 - final authUrl = - 'api_key="$apiKey", algorithm="hmac-sha256", headers="host date request-line", signature="$sha"'; - - // 将请求参数使用 base64 编码 - final authorization = base64Encode(utf8.encode(authUrl)); - - // 构建查询参数 - final queryParams = { - "host": uri.host, - "date": date, - "authorization": authorization, - }; - - // 将查询参数编码并拼接到 URL 后面 - final callurl = - Uri.parse(hostUrl).replace(queryParameters: queryParams).toString(); - - return callurl; - } - - void _handle(data) async { - final result = jsonDecode(data); - - int code = result['header']['code']; - if (code == 0) { - int status = result['header']['status']; - if (status == 1 || status == 2) { - Uint8List audio = base64Decode(result['payload']['audio']['audio']); - _audioBytes.add(audio); - } - if (status == 2) { - final newSource = BytesAudioSource(_audioBytes.toBytes()); - await _playlist.add(newSource); - if (!_isSpeaking.value) { - _audioPlay(); - } - _completer.complete(); - _completer = Completer(); - } - } - } - - void _audioPlay() async { - _isSpeaking.value = true; - // 发送开始事件 - _eventController.add(TtsEvent(type: TtsEventType.started)); - await _player.setAudioSource(_playlist); - await _player.play(); - } - - @override - Future startspeak(String sessionid) async { - if (!_isInitialized) await initialize(); - if (!isEnabled.value) return false; - - try { - _currsessionid = sessionid; - return true; - } catch (e) { - Logger.error('语音合成失败: ${e.toString()}'); - return false; - } - } - - @override - Future speakOnce(String sessionid, String text) async { - if (!isEnabled.value || text.isEmpty) return false; - - try { - _audioBytes.clear(); - await _speechSynthesis(text); - await _completer.future; - - return true; - } catch (e) { - _isSpeaking.value = false; - Logger.error('语音合成失败: ${e.toString()}'); - - // 发送错误事件 - _eventController.add(TtsEvent.error('语音合成失败: $e')); - - return false; - } - } - - @override - Future speakStream(String sessionid, String text) async { - if (!isEnabled.value || text.isEmpty) return false; - - try { - // 添加文本到缓冲区 - _streamBuffer += text; - - // 如果缓冲区为空,直接返回 - if (_streamBuffer.isEmpty) return true; - - // 使用正则表达式匹配句子,包括结束符号 - // 匹配任意字符,直到遇到句子结束符号 - final sentenceRegex = RegExp( - r'([^。.!!??;;:\n\r]+[。.!!??;;::\n\r]|[^。.!!??;;:\n\r]+(?:\.{3,}|…)|[^。.!!??;;:\n\r]+["」』])'); - - bool hasProcessed = false; - - // 查找所有完整句子 - final matches = sentenceRegex.allMatches(_streamBuffer); - final List sentences = []; - int lastMatchEnd = 0; - - for (final match in matches) { - // 提取完整句子(包含结束符号) - final sentence = match.group(1)?.trim(); - if (sentence != null && sentence.isNotEmpty) { - sentences.add(sentence); - lastMatchEnd = match.end; - } - } - - // 处理找到的句子 - for (final sentence in sentences) { - _textQueue.add(sentence); - hasProcessed = true; - } - - // 更新缓冲区,只保留未完成的部分 - if (lastMatchEnd > 0) { - _streamBuffer = _streamBuffer.substring(lastMatchEnd); - } - - // 如果处理了文本并且队列未在处理中,开始处理队列 - if (hasProcessed && !_isProcessingQueue) { - _processQueue(); - } - - return true; - } catch (e) { - Logger.error('处理流式文本失败: ${e.toString()}'); - - // 发送错误事件 - _eventController.add(TtsEvent.error('处理流式文本失败: $e')); - - return false; - } - } - - @override - Future flushStream( - String sessionid, - ) async { - if (_textQueue.isEmpty && _streamBuffer.isEmpty) return true; - - try { - // 处理缓冲区中可能的完整句子 - await speakStream(sessionid, ''); - - // 如果缓冲区仍有剩余文本,将其添加到播放队列 - if (_streamBuffer.isNotEmpty && _streamBuffer.trim().isNotEmpty) { - _textQueue.add(_streamBuffer); - - // 清空缓冲区 - _streamBuffer = ''; - - // 如果队列未在处理中,开始处理队列 - if (!_isProcessingQueue) { - _processQueue(); - } - } - - Logger.info('等待TTS队列播放完成,剩余${_textQueue.length}条'); - - return true; - } catch (e) { - Logger.error('刷新TTS流失败: ${e.toString()}'); - - // 发送错误事件 - _eventController.add(TtsEvent.error('刷新TTS流失败: $e')); - - return false; - } - } - - /// 处理语音合成队列 - Future _processQueue() async { - if (_textQueue.isEmpty || _isProcessingQueue) return; - - _isProcessingQueue = true; - - try { - while (_textQueue.isNotEmpty) { - if (!isEnabled.value) { - _textQueue.clear(); - break; - } - - final item = _textQueue.removeAt(0); - - // 使用speakOnce播放当前项 - await speakOnce(_currsessionid, item); - } - } catch (e) { - Logger.error('处理语音队列出错: ${e.toString()}'); - - // 发送错误事件 - _eventController.add(TtsEvent.error('处理语音队列出错: $e')); - } finally { - _isProcessingQueue = false; - } - } - - @override - Future stop() async { - try { - _textQueue.clear(); - await _player.stop(); - _playlist.clear(); - _audioBytes = BytesBuilder(); - if (_isSpeaking.value) { - _isSpeaking.value = false; - // 发送取消事件 - _eventController.add(TtsEvent(type: TtsEventType.canceled)); - } - return true; - } catch (e) { - Logger.error('停止语音合成出错: ${e.toString()}'); - // 发送错误事件 - _eventController.add(TtsEvent.error('停止语音合成出错: $e')); - return false; - } - } - - @override - Future dispose() async { - if (!_isInitialized) return; - try { - await stop(); - _player.dispose(); - // 关闭事件流控制器 - await _eventController.close(); - _isInitialized = false; - } catch (e) { - Logger.error('释放资源失败: ${e.toString()}'); - } - } - - @override - Future setAudioOutputDevice(int type) { - // TODO: implement setAudioOutputDevice - throw UnimplementedError(); - } -} diff --git a/apps/client/lib/data/services/speech_impl/volcano_asr_api_service.dart b/apps/client/lib/data/services/speech_impl/volcano_asr_api_service.dart deleted file mode 100644 index e586fa44..00000000 --- a/apps/client/lib/data/services/speech_impl/volcano_asr_api_service.dart +++ /dev/null @@ -1,904 +0,0 @@ -import 'dart:async'; -import 'dart:convert'; -import 'dart:io'; -import 'dart:math'; -import 'dart:typed_data'; -import 'package:crypto/crypto.dart'; -import 'package:flutter/foundation.dart' show kIsWeb; -import 'package:flutter_dotenv/flutter_dotenv.dart'; -import 'package:get/get.dart'; -import 'package:uuid/uuid.dart'; -import 'package:web_socket_channel/io.dart'; -import 'package:web_socket_channel/web_socket_channel.dart'; -import '../../../core/utils/logger.dart'; -import 'package:record/record.dart'; -import '../asr_service.dart'; - -/// Volcano语音识别服务 -/// -/// 负责与火山引擎实时语音识别服务的通信 -class VolcanoAsrApiService implements AsrService { - static final VolcanoAsrApiService to = Get.find(); - - // API配置 - late final String _appKey; - late final String _secretKey; - late final String _serviceId; - late final String _hostUrl; - final String _path = '/ws/v1/asr'; - - // 请求相关参数 - final String _algorithm = 'hmac-sha1'; - final Uuid _uuid = const Uuid(); - - // 录音配置 - final int _sampleRate = 16000; - final int _bitsPerSample = 16; - final int _channels = 1; - final String _encoding = 'pcm'; - // 音频输入源 - bool _audioSourceType = false; - // 连接相关 - WebSocketChannel? _channel; - Completer? _connectionCompleter; - StreamSubscription? _connectionSubscription; - Timer? _heartbeatTimer; - - // 语音录音 - final Record? _recorder = null; // TODO: 实现正确的Record实例化 - Timer? _audioTimer; - bool _isRecording = false; - - // 状态控制 - bool _isInitialized = false; - bool _isConnecting = false; - bool _isContinuousRecognitionActive = false; - - // 识别结果控制 - bool _isRecognitionEndRequested = false; - String _currentSessionId = ''; - final List _supportedLanguages = ['zh-CN', 'en-US']; - String _selectedLanguage = 'zh-CN'; - - // 结果流 - StreamController? _recognitionController; - - // 事件计数器(用于调试) - int _sendPacketCount = 0; - int _receivePacketCount = 0; - - // AsrService接口实现 - @override - List get supportedLanguages => _supportedLanguages; - - @override - Future initialize({ - List? supportedLanguages, - }) async { - try { - // 如果已经初始化过,先释放资源 - if (_isInitialized) { - await dispose(); - } - - _isInitialized = false; - - // 从环境变量加载配置 - _loadConfig(); - - // 设置支持的语言 - if (supportedLanguages != null && supportedLanguages.isNotEmpty) { - _supportedLanguages.clear(); - _supportedLanguages.addAll(supportedLanguages); - } - - // 初始化录音机 - await _initRecorder(); - - _isInitialized = true; - Logger.info('火山语音API已初始化'); - return true; - } catch (e) { - Logger.error('初始化火山语音API失败: ${e.toString()}'); - return false; - } - } - - @override - Future recognizeOnce() async { - try { - if (!_isInitialized) { - await initialize(); - } - - final resultCompleter = Completer(); - - // // 开始连续识别流程 - // final stream = await startContinuousRecognition(_audioSourceType); - - // // 监听结果 - // StreamSubscription? subscription; - // subscription = stream.listen((event) { - // if (event.type == RecognitionEventType.finalResult) { - // // 收到最终结果,完成单次识别 - // subscription?.cancel(); - // resultCompleter.complete(event); - // stopContinuousRecognition(); - // } else if (event.type == RecognitionEventType.error) { - // // 发生错误,返回错误 - // subscription?.cancel(); - // resultCompleter.completeError(event.error); - // stopContinuousRecognition(); - // } - // }, onError: (e) { - // subscription?.cancel(); - // resultCompleter.completeError(e.toString()); - // stopContinuousRecognition(); - // }, onDone: () { - // if (!resultCompleter.isCompleted) { - // resultCompleter.complete(RecognitionEvent.error('未收到识别结果')); - // } - // }); - - // // 设置超时 - // Timer(const Duration(seconds: 30), () { - // if (!resultCompleter.isCompleted) { - // subscription?.cancel(); - // resultCompleter.complete(RecognitionEvent.error('识别超时')); - // stopContinuousRecognition(); - // } - // }); - - return resultCompleter.future; - } catch (e) { - Logger.error('单次语音识别失败: ${e.toString()}'); - return RecognitionEvent.error(e.toString()); - } - } - - @override - // Future> startContinuousRecognition( - // bool audioSourceType) async { - // if (!_isInitialized) { - // await initialize(); - // } - - // if (_isContinuousRecognitionActive) { - // await stopContinuousRecognition(); - // } - - // try { - // // 创建结果控制器 - // _recognitionController = StreamController.broadcast(); - - // // 连接WebSocket - // await _connectWebSocket(); - - // // 开始录音 - // await _startRecording(); - - // _isContinuousRecognitionActive = true; - // _isRecognitionEndRequested = false; - - // Logger.info('连续语音识别已开始'); - - // return _recognitionController!.stream; - // } catch (e) { - // Logger.error('开始连续语音识别失败: ${e.toString()}'); - // await _cleanupResources(); - - // // 返回一个包含错误的流 - // final errorController = StreamController.broadcast(); - // errorController.add(RecognitionEvent.error(e.toString())); - // errorController.close(); - - // return errorController.stream; - // } - // } - - @override - Future stopContinuousRecognition() async { - if (!_isContinuousRecognitionActive) { - return true; - } - - try { - _isRecognitionEndRequested = true; - - // 先停止录音,以确保不会再发送新的音频数据 - await _stopRecording(); - - // 发送结束指令 - await _sendEndSignal(); - - // 等待服务器处理完所有已发送的数据 - await Future.delayed(const Duration(milliseconds: 500)); - - // 清理资源 - await _cleanupResources(); - - _isContinuousRecognitionActive = false; - Logger.info('连续语音识别已停止'); - - return true; - } catch (e) { - Logger.error('停止连续语音识别失败: ${e.toString()}'); - - // 确保资源被清理 - await _cleanupResources(); - _isContinuousRecognitionActive = false; - - return false; - } - } - - @override - bool isContinuousRecognitionActive() { - return _isContinuousRecognitionActive; - } - - @override - Future dispose() async { - try { - if (_isContinuousRecognitionActive) { - await stopContinuousRecognition(); - } - - // 确保资源被清理 - await _cleanupResources(); - - _isInitialized = false; - Logger.info('火山语音API资源已释放'); - } catch (e) { - Logger.error('释放火山语音API资源失败: ${e.toString()}'); - _isContinuousRecognitionActive = false; - _isInitialized = false; - } - } - - /// 从环境变量加载配置 - void _loadConfig() { - _appKey = dotenv.env['VOLCANO_APP_KEY'] ?? ''; - _secretKey = dotenv.env['VOLCANO_SECRET_KEY'] ?? ''; - _serviceId = dotenv.env['VOLCANO_SERVICE_ID'] ?? ''; - _hostUrl = dotenv.env['VOLCANO_HOST_URL'] ?? 'ws-api-asr.volces.com'; - - if (_appKey.isEmpty || _secretKey.isEmpty || _serviceId.isEmpty) { - throw Exception( - '未找到火山语音API配置,请在.env文件中设置VOLCANO_APP_KEY, VOLCANO_SECRET_KEY和VOLCANO_SERVICE_ID'); - } - } - - /// 初始化录音机 - Future _initRecorder() async { - try { - // TODO: 正确实现录音机初始化 - // _recorder = Record(); - - // 检查和请求权限 - // final hasPermission = await _recorder!.hasPermission(); - // if (!hasPermission) { - // throw Exception('没有录音权限'); - // } - - Logger.info('录音机初始化成功'); - } catch (e) { - // _recorder = null; - Logger.error('初始化录音机失败: ${e.toString()}'); - rethrow; - } - } - - /// 连接WebSocket - Future _connectWebSocket() async { - if (_isConnecting) { - // 已经有一个连接进程在进行中 - if (_connectionCompleter != null && !_connectionCompleter!.isCompleted) { - return _connectionCompleter!.future; - } - } - - _connectionCompleter = Completer(); - _isConnecting = true; - - try { - // 关闭现有连接 - await _closeWebSocket(); - - // 生成新的会话ID - _currentSessionId = _uuid.v4(); - - // 构建URL和请求头 - final (url, headers) = _buildConnectionParams(); - - // 创建WebSocket连接 - if (kIsWeb) { - _channel = WebSocketChannel.connect(Uri.parse(url)); - } else { - _channel = IOWebSocketChannel.connect( - Uri.parse(url), - headers: headers, - ); - } - - // 处理WebSocket消息 - _connectionSubscription = _channel!.stream.listen( - _handleWebSocketMessage, - onError: _handleWebSocketError, - onDone: _handleWebSocketDone, - ); - - // 开始心跳 - _startHeartbeat(); - - // 发送开始识别指令 - await _sendStartCommand(); - - _isConnecting = false; - _connectionCompleter!.complete(); - - Logger.info('WebSocket连接成功'); - } catch (e) { - _isConnecting = false; - if (_connectionCompleter != null && !_connectionCompleter!.isCompleted) { - _connectionCompleter!.completeError(e); - } - - Logger.error('连接WebSocket失败: ${e.toString()}'); - rethrow; - } - - return _connectionCompleter!.future; - } - - /// 构建连接参数 - (String, Map?) _buildConnectionParams() { - final timestamp = (DateTime.now().millisecondsSinceEpoch / 1000).floor(); - final nonce = _generateNonce(); - - // 构建表单(用于签名和查询参数) - final form = { - 'algorithm': _algorithm, - 'app_key': _appKey, - 'nonce': nonce, - 'service_id': _serviceId, - 'session_id': _currentSessionId, - 'timestamp': timestamp.toString(), - }; - - // 计算签名 - final signature = _calculateSignature(form); - - // 添加签名到表单 - form['signature'] = signature; - - // 构建URL查询参数 - final queryString = form.entries - .map((e) => '${e.key}=${Uri.encodeComponent(e.value)}') - .join('&'); - - // 构建完整URL - final url = 'wss://$_hostUrl$_path?$queryString'; - - // 构建请求头 - final headers = { - 'User-Agent': 'DeepSound App/1.0.0', - }; - - return (url, kIsWeb ? null : headers); - } - - /// 生成随机数 - String _generateNonce() { - final random = Random(); - final randoms = List.generate(16, (_) => random.nextInt(256)); - return base64Url.encode(randoms).substring(0, 16); - } - - /// 计算签名 - String _calculateSignature(Map form) { - // 按键排序 - final sortedKeys = form.keys.toList()..sort(); - - // 构建待签名字符串 - final signString = sortedKeys.map((key) => '$key=${form[key]}').join(''); - - // 使用HMAC-SHA1进行签名 - final key = utf8.encode(_secretKey); - final bytes = utf8.encode(signString); - final hmacSha1 = Hmac(sha1, key); - final digest = hmacSha1.convert(bytes); - - // 返回Base64编码的签名 - return base64.encode(digest.bytes); - } - - /// 开始心跳定时 - void _startHeartbeat() { - _heartbeatTimer?.cancel(); - _heartbeatTimer = Timer.periodic(const Duration(seconds: 15), (_) { - _sendHeartbeat(); - }); - } - - /// 发送心跳包 - void _sendHeartbeat() { - if (_channel != null && _isContinuousRecognitionActive) { - try { - final heartbeatMsg = { - 'type': 'heartbeat', - 'sequence': _sendPacketCount++, - }; - - _channel!.sink.add(jsonEncode(heartbeatMsg)); - } catch (e) { - Logger.error('发送心跳包失败: ${e.toString()}'); - } - } - } - - /// 发送开始识别指令 - Future _sendStartCommand() async { - if (_channel == null) return; - - try { - final startCommand = { - 'type': 'start', - 'sequence': _sendPacketCount++, - 'asr_params': { - 'sample_rate': _sampleRate, - 'bits_per_sample': _bitsPerSample, - 'channel': _channels, - 'encoding': _encoding, - 'audio_format': 'raw', - 'lang': _selectedLanguage, - 'vad_enable': true, - 'vad_pause_time': 500, - 'max_seconds': 60, - }, - }; - - _channel!.sink.add(jsonEncode(startCommand)); - Logger.info('已发送开始识别指令'); - } catch (e) { - Logger.error('发送开始识别指令失败: ${e.toString()}'); - rethrow; - } - } - - /// 开始录音 - Future _startRecording() async { - // TODO: 实现正确的录音开始逻辑 - /* - if (_recorder == null) { - await _initRecorder(); - } - - if (_isRecording) { - await _stopRecording(); - } - - try { - // 开始录音 - await _recorder!.start( - encoder: AudioEncoder.pcm16bits, - samplingRate: _sampleRate, - numChannels: _channels, - ); - - _isRecording = true; - - // 设置定时器定期获取音频数据 - _audioTimer = Timer.periodic(const Duration(milliseconds: 200), (_) async { - await _captureAndSendAudio(); - }); - - Logger.info('录音已开始'); - } catch (e) { - _isRecording = false; - Logger.error('开始录音失败: ${e.toString()}'); - rethrow; - } - */ - - // 临时实现,防止错误 - _isRecording = true; - Logger.info('录音已开始(模拟)'); - } - - /// 捕获并发送音频数据 - Future _captureAndSendAudio() async { - // TODO: 实现正确的音频捕获逻辑 - /* - if (!_isRecording || _recorder == null || _channel == null) { - return; - } - - try { - Uint8List? audioData; - - if (Platform.isIOS) { - // iOS 使用文件缓冲区 - final path = await _recorder!.stop(); - if (path == null) return; - - // 读取文件内容 - final file = File(path); - if (await file.exists()) { - audioData = await file.readAsBytes(); - - // 重新开始录音 - await _recorder!.start( - encoder: AudioEncoder.pcm16bits, - samplingRate: _sampleRate, - numChannels: _channels, - ); - } - } else { - // Android 使用stream获取PCM数据 - // 还未实现 - } - - // 如果有音频数据,发送给服务器 - if (audioData != null && audioData.isNotEmpty) { - await _sendAudioData(audioData); - } - } catch (e) { - Logger.error('捕获和发送音频失败: ${e.toString()}'); - } - */ - } - - /// 发送音频数据 - Future _sendAudioData(Uint8List data) async { - if (_channel == null || data.isEmpty) return; - - try { - final audioMessage = { - 'type': 'audio', - 'sequence': _sendPacketCount++, - 'audio': base64.encode(data), - }; - - _channel!.sink.add(jsonEncode(audioMessage)); - } catch (e) { - Logger.error('发送音频数据失败: ${e.toString()}'); - } - } - - /// 发送结束信号 - Future _sendEndSignal() async { - if (_channel == null) return; - - try { - final endCommand = { - 'type': 'end', - 'sequence': _sendPacketCount++, - }; - - _channel!.sink.add(jsonEncode(endCommand)); - Logger.info('已发送结束指令'); - } catch (e) { - Logger.error('发送结束指令失败: ${e.toString()}'); - } - } - - /// 停止录音 - Future _stopRecording() async { - _audioTimer?.cancel(); - _audioTimer = null; - - // TODO: 实现正确的录音停止逻辑 - /* - if (_isRecording && _recorder != null) { - try { - await _recorder!.stop(); - _isRecording = false; - Logger.info('录音已停止'); - } catch (e) { - Logger.error('停止录音失败: ${e.toString()}'); - } - } - */ - - // 临时实现,防止错误 - _isRecording = false; - Logger.info('录音已停止(模拟)'); - } - - /// 处理WebSocket消息 - void _handleWebSocketMessage(dynamic message) { - try { - _receivePacketCount++; - - if (message is String) { - final Map data = jsonDecode(message); - final String type = data['type'] as String? ?? ''; - - switch (type) { - case 'result': - _handleResultMessage(data); - break; - - case 'start_result': - _handleStartResultMessage(data); - break; - - case 'end_result': - _handleEndResultMessage(data); - break; - - case 'error': - _handleErrorMessage(data); - break; - - case 'heartbeat_result': - // 心跳响应,不需要特殊处理 - break; - - default: - Logger.info('收到未知类型的消息: $type'); - } - } - } catch (e) { - Logger.error('处理WebSocket消息失败: ${e.toString()}'); - - if (_recognitionController != null && !_recognitionController!.isClosed) { - _recognitionController!.addError('处理消息失败: $e'); - } - } - } - - /// 处理结果消息 - void _handleResultMessage(Map data) { - try { - final Map? result = - data['result'] as Map?; - if (result == null) return; - - final bool isEnd = result['is_end'] as bool? ?? false; - final String text = result['text'] as String? ?? ''; - - if (_recognitionController != null && !_recognitionController!.isClosed) { - if (isEnd) { - // 最终结果 - _recognitionController!.add(RecognitionEvent( - type: RecognitionEventType.finalResult, - text: text, - )); - } else { - // 中间结果 - _recognitionController!.add(RecognitionEvent( - type: RecognitionEventType.intermediateResult, - text: text, - )); - } - } - } catch (e) { - Logger.error('处理结果消息失败: ${e.toString()}'); - } - } - - /// 处理开始结果消息 - void _handleStartResultMessage(Map data) { - final int code = data['code'] as int? ?? -1; - - if (code == 0) { - // 开始成功 - if (_recognitionController != null && !_recognitionController!.isClosed) { - _recognitionController!.add(RecognitionEvent( - type: RecognitionEventType.sessionStarted, - )); - } - } else { - // 开始失败 - final String message = data['message'] as String? ?? '未知错误'; - - Logger.error('语音识别开始失败: [$code] $message'); - - if (_recognitionController != null && !_recognitionController!.isClosed) { - _recognitionController! - .add(RecognitionEvent.error('开始失败: [$code] $message')); - } - } - } - - /// 处理结束结果消息 - void _handleEndResultMessage(Map data) { - final int code = data['code'] as int? ?? -1; - - if (code == 0) { - // 结束成功 - Logger.info('语音识别成功结束'); - } else { - // 结束失败 - final String message = data['message'] as String? ?? '未知错误'; - Logger.error('语音识别结束失败: [$code] $message'); - } - - // 无论成功还是失败,通知会话已结束 - if (_recognitionController != null && !_recognitionController!.isClosed) { - _recognitionController!.add(RecognitionEvent( - type: RecognitionEventType.sessionStopped, - )); - } - - // 清理资源 - _cleanupResources(); - } - - /// 处理错误消息 - void _handleErrorMessage(Map data) { - final int code = data['code'] as int? ?? -1; - final String message = data['message'] as String? ?? '未知错误'; - - Logger.error('收到错误消息: [$code] $message'); - - if (_recognitionController != null && !_recognitionController!.isClosed) { - _recognitionController!.add(RecognitionEvent.error('[$code] $message')); - } - } - - /// 处理WebSocket错误 - void _handleWebSocketError(dynamic error) { - Logger.error('WebSocket错误: ${e.toString()}rror'); - - if (_connectionCompleter != null && !_connectionCompleter!.isCompleted) { - _connectionCompleter!.completeError(error); - } - - if (_recognitionController != null && !_recognitionController!.isClosed) { - _recognitionController!.addError(error); - } - - // 清理资源 - _cleanupResources(); - } - - /// 处理WebSocket连接关闭 - void _handleWebSocketDone() { - Logger.info('WebSocket连接已关闭'); - - if (_connectionCompleter != null && !_connectionCompleter!.isCompleted) { - _connectionCompleter!.completeError('WebSocket连接已关闭'); - } - - // 通知会话已结束 - if (_recognitionController != null && - !_recognitionController!.isClosed && - !_isRecognitionEndRequested) { - _recognitionController!.add(RecognitionEvent( - type: RecognitionEventType.sessionStopped, - )); - } - - // 清理资源 - _cleanupResources(); - } - - /// 关闭WebSocket连接 - Future _closeWebSocket() async { - _connectionSubscription?.cancel(); - _connectionSubscription = null; - - _heartbeatTimer?.cancel(); - _heartbeatTimer = null; - - if (_channel != null) { - try { - _channel!.sink.close(); - _channel = null; - } catch (e) { - Logger.error('关闭WebSocket连接失败: ${e.toString()}'); - } - } - } - - /// 清理所有资源 - Future _cleanupResources() async { - // 停止录音 - await _stopRecording(); - - // 关闭WebSocket - await _closeWebSocket(); - - // 关闭结果控制器 - if (_recognitionController != null && !_recognitionController!.isClosed) { - await _recognitionController!.close(); - _recognitionController = null; - } - - _isContinuousRecognitionActive = false; - _isRecognitionEndRequested = false; - } - - @override - Future enableRecord( - AudioSourceType audioSourceType, - String filePath, - bool acceptAudioData, - ) { - // TODO: implement enableRecord - throw UnimplementedError(); - } - - @override - Future stopRecord(bool isSave) { - // TODO: implement stopRecord - throw UnimplementedError(); - } - - @override - Future pauseRecord() { - // TODO: implement pauseRecord - throw UnimplementedError(); - } - - @override - Future moveFile(String sourcePath, String destPath) { - // TODO: implement moveFile - throw UnimplementedError(); - } - - @override - Future renameFile(String filePath, String newName) { - // TODO: implement renameFile - throw UnimplementedError(); - } - - @override - Future disableBluetoothAudio() { - // TODO: implement disableBluetoothAudio - throw UnimplementedError(); - } - - @override - Future restoreOriginalAudioState() { - // TODO: implement restoreOriginalAudioState - throw UnimplementedError(); - } - - @override - Future> recognizeCallback() { - // TODO: implement recognizeCallback - throw UnimplementedError(); - } - - @override - Future startContinuousRecognition( - bool audioSourceType, { - bool isRemoveFirstPunctuation = true, - String mode = "normal", - bool skipAsrForCallMode = false, - }) { - // TODO: implement startContinuousRecognition - throw UnimplementedError(); - } - - @override - Future setAudioConfig({int sampleRate = 16000, int channels = 1}) { - // TODO: implement setAudioConfig - throw UnimplementedError(); - } - - @override - Future resumeRecord() { - // TODO: implement resumeRecord - throw UnimplementedError(); - } - - @override - Stream? getAudioDataStream() { - // TODO: implement getAudioDataStream - throw UnimplementedError(); - } - - @override - Future requestScreenCapture() async => false; - - @override - Future stopScreenCapture() async => true; - - @override - Future isScreenCapturing() async => false; -} diff --git a/apps/client/lib/data/services/speech_impl/volcano_asr_service.dart b/apps/client/lib/data/services/speech_impl/volcano_asr_service.dart deleted file mode 100644 index 207702f4..00000000 --- a/apps/client/lib/data/services/speech_impl/volcano_asr_service.dart +++ /dev/null @@ -1,439 +0,0 @@ -import 'dart:async'; - -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; -import 'package:get/get.dart'; -import 'package:flutter_dotenv/flutter_dotenv.dart'; - -import '../asr_service.dart'; - -/// 火山语音识别服务实现 -class VolcanoAsrService extends GetxService implements AsrService { - /// 方法通道 - static const MethodChannel _channel = MethodChannel('volcano_speech/asr'); - - /// 事件通道 - static const EventChannel _eventChannel = - EventChannel('volcano_speech/asr_events'); - - /// 事件流控制器 - final StreamController _eventStreamController = - StreamController.broadcast(); - - /// 事件订阅 - StreamSubscription? _eventSubscription; - - /// 是否初始化完成 - bool _isInitialized = false; - - /// 是否正在连续识别 - bool _isContinuousRecognitionActive = false; - - /// 当前语言 - String _currentLanguage = 'zh-CN'; - - /// 支持的语言列表 - final List _supportedLanguages = ['zh-CN', 'en-US']; - - @override - List get supportedLanguages => _supportedLanguages; - - /// 构造函数 - VolcanoAsrService() { - _setupEventListener(); - } - - /// 初始化语音识别服务 - @override - Future initialize({ - List? supportedLanguages, - }) async { - if (_isInitialized) return true; - - try { - // 如果提供了支持的语言列表,则替换默认列表 - if (supportedLanguages != null && supportedLanguages.isNotEmpty) { - _supportedLanguages.clear(); - _supportedLanguages.addAll(supportedLanguages); - } - - // 从.env文件读取配置 - final appId = dotenv.env['VOLCANO_SPEECH_APP_ID'] ?? ''; - final appToken = dotenv.env['VOLCANO_SPEECH_APP_TOKEN'] ?? ''; - final resourceId = - dotenv.env['VOLCANO_ASR_RESOURCE_ID'] ?? 'volc.bigasr.sauc.duration'; - - if (appId.isEmpty || appToken.isEmpty) { - debugPrint( - '火山语音初始化失败:缺少VOLCANO_SPEECH_APP_ID或VOLCANO_SPEECH_APP_TOKEN环境变量'); - return false; - } - - // 初始化火山语音ASR - final initResult = await _channel.invokeMethod('initialize', { - 'appId': appId, - 'appToken': appToken, - 'resourceId': resourceId, - }) ?? - false; - - if (!initResult) { - debugPrint('火山语音ASR初始化失败'); - return false; - } - - // 设置默认语言、VAD参数和启用音量返回 - await _configureAsr(); - - _isInitialized = true; - return true; - } catch (e) { - debugPrint('火山语音ASR初始化异常:$e'); - return false; - } - } - - /// 配置ASR参数 - Future _configureAsr() async { - // 设置默认语言 - await _channel.invokeMethod('setLanguage', { - 'language': _currentLanguage, - }); - } - - /// 设置事件监听 - void _setupEventListener() { - _eventSubscription = _eventChannel.receiveBroadcastStream().listen( - (dynamic event) { - if (event is! Map) return; - _handleAsrEvent(Map.from(event as Map)); - }, - onError: (Object error) { - debugPrint('ASR事件流错误: $error'); - _eventStreamController.add(RecognitionEvent( - type: RecognitionEventType.error, - error: '事件流错误: $error', - )); - }, - ); - } - - /// 处理ASR事件 - void _handleAsrEvent(Map event) { - final eventType = event['type'] as String?; - - switch (eventType) { - case 'sessionStarted': - _eventStreamController.add(RecognitionEvent( - type: RecognitionEventType.sessionStarted, - )); - break; - - case 'sessionStopped': - _eventStreamController.add(RecognitionEvent( - type: RecognitionEventType.sessionStopped, - )); - _isContinuousRecognitionActive = false; - break; - - case 'recognizing': - final text = event['text'] as String?; - final language = event['language'] as String?; - - if (text != null) { - debugPrint('接收到中间识别结果: $text'); - _eventStreamController.add(RecognitionEvent( - type: RecognitionEventType.intermediateResult, - text: text, - detectedLanguage: language ?? _currentLanguage, - )); - } - break; - - case 'result': - final text = event['text'] as String?; - final language = event['language'] as String?; - - if (text != null) { - debugPrint('接收到最终识别结果: $text'); - _eventStreamController.add(RecognitionEvent( - type: RecognitionEventType.finalResult, - text: text, - detectedLanguage: language ?? _currentLanguage, - )); - } - break; - - case 'error': - final errorMessage = event['message'] as String?; - - debugPrint('接收到识别错误: ${errorMessage ?? "未知错误"}'); - _eventStreamController.add(RecognitionEvent( - type: RecognitionEventType.error, - error: errorMessage ?? '未知错误', - )); - _isContinuousRecognitionActive = false; - break; - - case 'volumeChanged': - // 音量变化事件仅在日志中输出,不发送到事件流 - final volume = event['volume'] as int?; - if (volume != null && volume > 5) { - // 仅记录有意义的音量变化 - debugPrint('音量变化: $volume'); - } - break; - } - } - - /// 检查初始化状态 - Future _ensureInitialized() async { - if (!_isInitialized) { - return await initialize(); - } - return true; - } - - /// 执行一次性语音识别 - @override - Future recognizeOnce() async { - if (!await _ensureInitialized()) { - return RecognitionEvent( - type: RecognitionEventType.error, - error: '语音识别服务未初始化', - ); - } - - try { - // 创建一个Completer用于等待最终结果 - final completer = Completer(); - - // 创建一次性事件监听 - StreamSubscription? subscription; - subscription = _eventStreamController.stream.listen((event) { - // 仅处理finalResult和error事件 - if (event.type == RecognitionEventType.finalResult) { - // 识别成功,返回结果 - completer.complete(event); - subscription?.cancel(); - } else if (event.type == RecognitionEventType.error) { - // 识别失败,返回错误 - completer.complete(event); - subscription?.cancel(); - } - }); - - // 启动一次性识别 - final started = - await _channel.invokeMethod('recognizeOnce') ?? false; - - if (!started) { - subscription.cancel(); - return RecognitionEvent( - type: RecognitionEventType.error, - error: '启动一次性识别失败', - ); - } - - // 设置超时,防止永久等待 - Future.delayed(const Duration(seconds: 30), () { - if (!completer.isCompleted) { - completer.complete(RecognitionEvent( - type: RecognitionEventType.error, - error: '识别超时', - )); - subscription?.cancel(); - // 停止识别 - _channel.invokeMethod('stopRecognize'); - } - }); - - // 等待结果 - return await completer.future; - } catch (e) { - // 确保停止识别 - try { - await _channel.invokeMethod('stopRecognize'); - } catch (_) {} - - return RecognitionEvent( - type: RecognitionEventType.error, - error: e.toString(), - ); - } - } - - /// 开始连续语音识别 - @override - // Future> startContinuousRecognition( - // bool audioSourceType) async { - // if (!await _ensureInitialized()) { - // _eventStreamController.add(RecognitionEvent( - // type: RecognitionEventType.error, - // error: '语音识别服务未初始化', - // )); - // return _eventStreamController.stream; - // } - - // try { - // final success = await _channel.invokeMethod('audioSourceType', { - // 'audioSourceType': audioSourceType, - // }) ?? - // false; - - // if (success) { - // _isContinuousRecognitionActive = true; - // } else { - // _eventStreamController.add(RecognitionEvent( - // type: RecognitionEventType.error, - // error: '启动连续识别失败', - // )); - // } - // } catch (e) { - // _eventStreamController.add(RecognitionEvent( - // type: RecognitionEventType.error, - // error: '启动连续识别异常:$e', - // )); - // } - - // return _eventStreamController.stream; - // } - - /// 停止连续语音识别 - @override - Future stopContinuousRecognition() async { - if (!_isInitialized || !_isContinuousRecognitionActive) { - return false; - } - - try { - final success = - await _channel.invokeMethod('stopContinuousRecognition') ?? - false; - - if (success) { - _isContinuousRecognitionActive = false; - } - return success; - } catch (e) { - debugPrint('停止连续识别异常:$e'); - return false; - } - } - - /// 检查连续识别是否活跃 - @override - bool isContinuousRecognitionActive() { - return _isContinuousRecognitionActive; - } - - /// 释放资源 - @override - Future dispose() async { - if (_isContinuousRecognitionActive) { - await stopContinuousRecognition(); - } - - await _eventSubscription?.cancel(); - _eventSubscription = null; - - if (!_eventStreamController.isClosed) { - await _eventStreamController.close(); - } - - if (_isInitialized) { - await _channel.invokeMethod('release'); - _isInitialized = false; - } - } - - @override - Future enableRecord( - AudioSourceType audioSourceType, - String filePath, - bool acceptAudioData, - ) { - // TODO: implement enableRecord - throw UnimplementedError(); - } - - @override - Future stopRecord(bool isSave) { - // TODO: implement stopRecord - throw UnimplementedError(); - } - - @override - Future pauseRecord() { - // TODO: implement pauseRecord - throw UnimplementedError(); - } - - @override - Future moveFile(String sourcePath, String destPath) { - // TODO: implement moveFile - throw UnimplementedError(); - } - - @override - Future renameFile(String filePath, String newName) { - // TODO: implement renameFile - throw UnimplementedError(); - } - - @override - Future disableBluetoothAudio() { - // TODO: implement disableBluetoothAudio - throw UnimplementedError(); - } - - @override - Future restoreOriginalAudioState() { - // TODO: implement restoreOriginalAudioState - throw UnimplementedError(); - } - - @override - Future> recognizeCallback() { - // TODO: implement recognizeCallback - throw UnimplementedError(); - } - - @override - Future startContinuousRecognition( - bool audioSourceType, { - bool isRemoveFirstPunctuation = true, - String mode = "normal", - bool skipAsrForCallMode = false, - }) { - // TODO: implement startContinuousRecognition - throw UnimplementedError(); - } - - @override - Future setAudioConfig({int sampleRate = 16000, int channels = 1}) { - // TODO: implement setAudioConfig - throw UnimplementedError(); - } - - @override - Future resumeRecord() { - // TODO: implement resumeRecord - throw UnimplementedError(); - } - - @override - Stream? getAudioDataStream() { - // TODO: implement getAudioDataStream - throw UnimplementedError(); - } - - @override - Future requestScreenCapture() async => false; - - @override - Future stopScreenCapture() async => true; - - @override - Future isScreenCapturing() async => false; -} diff --git a/apps/client/lib/data/services/speech_impl/volcano_tts_api_service.dart b/apps/client/lib/data/services/speech_impl/volcano_tts_api_service.dart deleted file mode 100644 index 8a3196c0..00000000 --- a/apps/client/lib/data/services/speech_impl/volcano_tts_api_service.dart +++ /dev/null @@ -1,1517 +0,0 @@ -import 'dart:async'; -import 'dart:convert'; -import 'dart:typed_data'; -import 'dart:io' as io; -import 'dart:math' as math; -import 'package:flutter/foundation.dart'; -import 'package:get/get.dart'; -import 'package:flutter_dotenv/flutter_dotenv.dart'; -import 'package:web_socket_channel/web_socket_channel.dart'; -import 'package:web_socket_channel/io.dart'; -import 'package:uuid/uuid.dart'; -import 'package:just_audio/just_audio.dart'; -import 'package:path_provider/path_provider.dart'; -import '../../../core/utils/logger.dart'; - -/// 火山语音合成双向流式API服务 -/// -/// 提供与火山语音TTS服务的WebSocket交互功能 -/// 用户需要自行管理会话状态,确保在使用完毕后调用 endSession -/// -/// 基本使用流程: -/// 1. 调用 startSession 开始会话 -/// 2. 调用 synthesize 合成文本 -/// 3. 调用 endSession 结束会话 -/// -/// 或者使用 speakOnce 一次性完成上述流程 -class VolcanoTtsApiService extends GetxController { - // 单例实例 - static VolcanoTtsApiService? _instance; - - // 单例工厂方法 - factory VolcanoTtsApiService() { - _instance ??= VolcanoTtsApiService._internal(); - return _instance!; - } - - // 会话状态管理 - 只保留基本状态标志 - bool _isSessionActive = false; - - // 私有构造函数 - VolcanoTtsApiService._internal() : - _appId = dotenv.env['VOLCANO_TTS_APP_ID'] ?? '', - _token = dotenv.env['VOLCANO_TTS_APP_TOKEN'] ?? '', - _resourceId = dotenv.env['VOLCANO_TTS_RESOURCE_ID'] ?? '' { - if (_appId.isEmpty || _token.isEmpty) { - throw Exception('火山语音配置信息不完整,请检查环境变量 VOLCANO_TTS_APP_ID 和 VOLCANO_TTS_APP_TOKEN'); - } - } - - // 协议常量 - static const int _protocolVersion = 0x0001; - static const int _defaultHeaderSize = 0x0001; - - // 消息类型 - static const int _fullClientRequest = 0x0001; - static const int _audioOnlyResponse = 0x000B; - static const int _fullServerResponse = 0x0009; - static const int _errorInformation = 0x000F; - - // 消息类型特定标志 - static const int _msgTypeFlagNoSeq = 0x0000; - static const int _msgTypeFlagPositiveSeq = 0x0001; - static const int _msgTypeFlagLastNoSeq = 0x0002; - static const int _msgTypeFlagNegativeSeq = 0x0003; - static const int _msgTypeFlagWithEvent = 0x0004; - - // 消息序列化 - static const int _noSerialization = 0x0000; - static const int _jsonSerialization = 0x0001; - - // 消息压缩 - static const int _compressionNo = 0x0000; - static const int _compressionGzip = 0x0001; - - // 事件类型 - static const int eventNone = 0; - static const int eventStartConnection = 1; - static const int eventFinishConnection = 2; - static const int eventConnectionStarted = 50; - static const int eventConnectionFailed = 51; - static const int eventConnectionFinished = 52; - static const int eventStartSession = 100; - static const int eventFinishSession = 102; - static const int eventSessionStarted = 150; - static const int eventSessionFinished = 152; - static const int eventSessionFailed = 153; - static const int eventTaskRequest = 200; - static const int eventTtsSentenceStart = 350; - static const int eventTtsSentenceEnd = 351; - static const int eventTtsResponse = 352; - - // 服务URL - static const String _serviceUrl = 'wss://openspeech.bytedance.com/api/v3/tts/bidirection'; - - // 配置参数 - final String _appId; - final String _token; - final String _resourceId; - - // WebSocket连接 - WebSocketChannel? _channel; - - // 会话ID - String? _sessionId; - String? _connectionId; - - // 状态控制 - bool _isConnected = false; - - // 音频数据控制器 - final _audioDataController = StreamController.broadcast(); - Stream get audioStream => _audioDataController.stream; - - // 事件控制器 - final _eventController = StreamController>.broadcast(); - Stream> get eventStream => _eventController.stream; - - // 当前状态 - final isConnecting = false.obs; - final isConnected = false.obs; - final isSynthesizing = false.obs; - - // 音频播放器 - final AudioPlayer _audioPlayer = AudioPlayer(); - - // 播放列表 - 用于连续播放 - final ConcatenatingAudioSource _playlist = ConcatenatingAudioSource(children: []); - bool _playlistInitialized = false; - - // 音频数据控制器 - 用于流式播放 - final StreamController> _audioStreamController = StreamController>(); - - // 是否正在播放 - final RxBool _isPlaying = false.obs; - bool get isPlaying => _isPlaying.value; - - // 默认发音人 - 使用预定义的值 - final String defaultSpeaker = 'zh_female_yuanqinvyou_moon_bigtts'; - - // 音频缓冲区 - final List _audioBuffer = []; - - // 检查是否需要准备下一个音频项目 - DateTime? _lastCheckTime; - int? _lastCheckedIndex; - - @override - void onInit() { - super.onInit(); - // 初始化时不自动连接,等待需要时再连接 - - // 设置音频播放器状态监听 - _setupAudioPlayerListeners(); - - // 初始化播放列表 - _initializePlaylist(); - } - - /// 初始化播放列表 - Future _initializePlaylist() async { - try { - if (!_playlistInitialized) { - // 设置音频属性,启用无缝播放 - await _audioPlayer.setLoopMode(LoopMode.off); - await _audioPlayer.setShuffleModeEnabled(false); - - // 设置自动连续播放 - await _audioPlayer.setAutomaticallyWaitsToMinimizeStalling(false); - - // 设置音频源 - await _audioPlayer.setAudioSource(_playlist, initialIndex: 0, initialPosition: Duration.zero); - - _playlistInitialized = true; - if (kDebugMode) { - print('播放列表初始化成功'); - } - } - } catch (e) { - if (kDebugMode) { - print('初始化播放列表失败: $e'); - } - // 不抛出异常,避免中断整个流程 - } - } - - /// 设置音频播放器状态监听 - void _setupAudioPlayerListeners() { - _audioPlayer.playerStateStream.listen((state) { - final processingState = state.processingState; - final playing = state.playing; - - if (processingState == ProcessingState.ready && playing) { - _isPlaying.value = true; - } else { - _isPlaying.value = false; - } - }); - - _audioPlayer.processingStateStream.listen((state) { - if (state == ProcessingState.completed) { - // 播放完成后检查播放列表是否为空 - if (_playlist.length > 0) { - final currentIndex = _audioPlayer.currentIndex; - - // 自动播放下一个项目 - _advanceToNextItem(); - } else { - // 播放列表为空,标记为未播放状态 - _isPlaying.value = false; - } - } - }); - - // 监听序列状态变化 - _audioPlayer.sequenceStateStream.listen((sequenceState) { - if (sequenceState == null) return; - - // 如果当前是最后一个项目且播放已完成,标记播放完成 - if (sequenceState.currentIndex == sequenceState.sequence.length - 1 && - _audioPlayer.processingState == ProcessingState.completed) { - _isPlaying.value = false; - } - }); - - // 监听位置变化,但减少检查频率 - DateTime _lastPositionCheck = DateTime.now(); - _audioPlayer.positionStream.listen((position) { - // 限制检查频率,每500毫秒检查一次 - final now = DateTime.now(); - if (now.difference(_lastPositionCheck).inMilliseconds >= 500) { - _lastPositionCheck = now; - _checkForNextItem(position); - } - }); - } - - /// 检查是否需要准备下一个音频项目 - Future _checkForNextItem(Duration position) async { - // 只有在播放中且有下一个项目时才检查 - if (!_isPlaying.value || _audioPlayer.currentIndex == null) return; - - final currentIndex = _audioPlayer.currentIndex!; - final sequenceState = _audioPlayer.sequenceState; - - // 如果没有序列状态,则不需要准备 - if (sequenceState == null) return; - - // 防抖动:如果在短时间内(200毫秒)对同一个索引进行了检查,则跳过 - final now = DateTime.now(); - if (_lastCheckTime != null && - _lastCheckedIndex == currentIndex && - now.difference(_lastCheckTime!) < const Duration(milliseconds: 200)) { - return; - } - - // 更新最后检查时间和索引 - _lastCheckTime = now; - _lastCheckedIndex = currentIndex; - - // 获取当前项目的总时长 - final duration = _audioPlayer.duration; - if (duration == null) return; - - // 如果是最后一个项目,不需要预加载 - final isLastItem = currentIndex >= sequenceState.sequence.length - 1; - - // 如果接近结束(剩余时间小于200毫秒),准备下一个项目或完成播放 - if (duration - position <= const Duration(milliseconds: 200) && !isLastItem) { - // 让播放器自然过渡到下一个项目 - } - } - - /// 前进到播放列表中的下一个项目 - Future _advanceToNextItem() async { - try { - if (_playlist.length == 0) return; - - // 获取当前索引和序列状态 - final currentIndex = _audioPlayer.currentIndex; - final sequenceState = _audioPlayer.sequenceState; - - if (sequenceState == null) { - // 如果没有序列状态,直接开始播放 - await _audioPlayer.seek(Duration.zero, index: 0); - await _audioPlayer.play(); - return; - } - - // 如果当前索引无效,从头开始播放 - if (currentIndex == null || currentIndex < 0) { - await _audioPlayer.seek(Duration.zero, index: 0); - await _audioPlayer.play(); - return; - } - - // 计算下一个索引 - final nextIndex = currentIndex + 1; - - // 检查是否还有下一个项目 - if (nextIndex < sequenceState.sequence.length) { - // 跳转到下一个项目并开始播放 - await _audioPlayer.seek(Duration.zero, index: nextIndex); - await _audioPlayer.play(); - } else { - // 已经是最后一个项目 - - // 确保最后一个项目播放完成 - if (_audioPlayer.position < _audioPlayer.duration!) { - await _audioPlayer.seek(_audioPlayer.duration!); - } - } - } catch (e) { - // 简单记录错误,不做复杂处理 - } - } - - /// 连接到火山语音服务 - Future connect() async { - if (_isConnected) { - Logger.info('TTS已连接,跳过连接'); - return true; // 已经连接 - } - - isConnecting.value = true; - - try { - Logger.info('开始TTS连接'); - - // 生成连接ID - _connectionId = const Uuid().v4(); - - // 创建WebSocket连接 - final uri = Uri.parse(_serviceUrl); - - if (!kIsWeb && (io.Platform.isAndroid || io.Platform.isIOS || io.Platform.isMacOS || io.Platform.isLinux || io.Platform.isWindows)) { - // 移动平台和桌面平台 - 使用IOWebSocketChannel - - _channel = IOWebSocketChannel.connect( - uri, - headers: { - 'X-Api-App-Key': _appId, - 'X-Api-Access-Key': _token, - 'X-Api-Resource-Id': _resourceId, - 'X-Api-Connect-Id': _connectionId!, - }, - ); - } else { - // Web平台 - 使用WebSocketChannel - // 注意:在Web平台上,我们无法直接设置WebSocket头部 - // 这可能会导致认证失败,需要与服务提供商确认Web平台的认证方式 - - _channel = WebSocketChannel.connect(uri); - } - - // 监听消息 - _channel!.stream.listen( - _handleMessage, - onError: (error) { - // 直接处理错误,不尝试重连 - Logger.error('WebSocket错误: ${error.toString()}'); - if (!_eventController.isClosed) { - _eventController.add({ - 'eventType': 'error', - 'error': error.toString() - }); - } - }, - onDone: _handleDone, - cancelOnError: false, - ); - - // 发送开始连接事件 - await _startConnection(); - - // 等待连接成功 - final completer = Completer(); - - // 设置超时 - Timer? timeout; - timeout = Timer(const Duration(seconds: 10), () { - if (!completer.isCompleted) { - Logger.error('火山TTS连接超时'); - completer.complete(false); - - // 使用 try-catch 包裹错误处理,避免在计时器回调中出现未捕获的异常 - try { - if (!_eventController.isClosed) { - _eventController.add({ - 'eventType': 'connectionFailed', - 'error': '连接超时' - }); - } - } catch (e) { - Logger.error('处理TTS连接超时事件失败: ${e.toString()}'); - } - } - timeout = null; - }); - - // 监听连接事件 - final subscription = eventStream.listen((event) { - if (event['eventType'] == 'connectionStarted') { - if (!completer.isCompleted) { - completer.complete(true); - timeout?.cancel(); - timeout = null; - } - } else if (event['eventType'] == 'connectionFailed') { - if (!completer.isCompleted) { - Logger.error('火山TTS连接失败: ${event['error']}'); - completer.complete(false); - timeout?.cancel(); - timeout = null; - } - } - }); - - // 等待连接结果 - final result = await completer.future; - subscription.cancel(); - - if (result) { - _isConnected = true; - isConnected.value = true; - } - - return result; - } catch (e) { - // 只记录错误,不尝试重连 - Logger.error('连接过程中发生异常: ${e.toString()}'); - return false; - } finally { - isConnecting.value = false; - } - } - - /// 开始TTS会话 - /// - /// 用户需要自行管理会话状态,确保在使用完毕后调用 endSession - /// - /// [speaker] 发音人ID - /// - /// 返回会话是否成功开始 - Future startSession(String speaker) async { - // 如果会话已经活跃,直接返回成功 - if (_isSessionActive && _sessionId != null) { - Logger.info('TTS会话已存在,跳过创建'); - return true; - } - - try { - if (!_isConnected) { - final connected = await connect(); - if (!connected) return false; - } - - // 生成会话ID - _sessionId = const Uuid().v4().replaceAll('-', ''); - - Logger.info('开始TTS会话: ${_sessionId!}'); - - // 发送开始会话事件 - await _startTtsSession(speaker); - - // 等待会话开始 - final completer = Completer(); - - // 设置超时 - Timer? timeout; - timeout = Timer(const Duration(seconds: 10), () { - if (!completer.isCompleted) { - Logger.error('火山TTS会话开始超时'); - completer.complete(false); - - // 使用 try-catch 包裹错误处理,避免在计时器回调中出现未捕获的异常 - try { - _eventController.add({ - 'eventType': 'sessionFailed', - 'error': '会话开始超时' - }); - } catch (e) { - Logger.error('处理TTS会话超时事件失败: ${e.toString()}'); - } - } - timeout = null; - }); - - // 监听会话事件 - final subscription = eventStream.listen((event) { - if (event['eventType'] == 'sessionStarted') { - if (!completer.isCompleted) { - completer.complete(true); - timeout?.cancel(); - timeout = null; - } - } else if (event['eventType'] == 'sessionFailed') { - if (!completer.isCompleted) { - Logger.error('火山TTS会话开始失败: ${event['error']}'); - completer.complete(false); - timeout?.cancel(); - timeout = null; - } - } - }); - - // 等待会话结果 - final result = await completer.future; - subscription.cancel(); - - if (result) { - // 更新会话状态 - _isSessionActive = true; - } - - return result; - } catch (e) { - // 只记录错误,不尝试恢复 - Logger.error('开始TTS会话失败: ${e.toString()}'); - return false; - } - } - - /// 合成文本 - Future synthesize(String text, String speaker) async { - if (text.isEmpty) { - Logger.warning('合成文本为空,跳过合成'); - return false; - } - - try { - // 确保已连接 - if (!_isConnected) { - Logger.error('TTS未连接,无法合成文本'); - return false; - } - - // 确保会话已开始 - if (!_isSessionActive || _sessionId == null) { - // 需要创建新会话 - final sessionStarted = await startSession(speaker); - if (!sessionStarted) { - Logger.error('TTS会话开始失败,无法合成文本'); - return false; - } - } - - // 设置合成状态 - isSynthesizing.value = true; - - // 发送合成请求 - await _sendTtsMessage(speaker, text); - - return true; - } catch (e) { - _handleError(e); - return false; - } - } - - /// 结束会话 - /// - /// 结束当前TTS会话,释放相关资源 - /// 用户应在使用完毕后调用此方法 - /// - /// 返回会话是否成功结束 - Future endSession() async { - if (!_isSessionActive || _sessionId == null) { - return true; // 没有活跃会话 - } - - Logger.info('TTS结束会话: ${_sessionId!}'); - - try { - // 发送结束会话事件 - await _finishSession(); - - // 等待会话结束 - final completer = Completer(); - - // 设置超时 - final timeout = Timer(const Duration(seconds: 5), () { - if (!completer.isCompleted) { - completer.complete(true); // 超时也认为成功 - } - }); - isSynthesizing.value = false; - _sessionId = null; - - // 监听会话事件 - final subscription = eventStream.listen((event) { - if (event['eventType'] == 'sessionFinished') { - if (!completer.isCompleted) { - completer.complete(true); - timeout.cancel(); - } - } - }); - - // 等待会话结果 - final result = await completer.future; - subscription.cancel(); - - // 重置会话状态 - _isSessionActive = false; - - return result; - } catch (e) { - _handleError(e); - // 即使出错,也重置会话状态 - _isSessionActive = false; - return false; - } - } - - /// 断开连接 - Future disconnect() async { - if (!_isConnected) { - return true; // 已经断开 - } - print('断开TTS连接'); - - try { - // 如果有活跃会话,先结束会话 - if (_isSessionActive) { - await endSession(); - } - - // 发送结束连接事件 - await _finishConnection(); - - // 等待连接结束 - final completer = Completer(); - - // 设置超时 - final timeout = Timer(const Duration(seconds: 5), () { - if (!completer.isCompleted) { - completer.complete(true); // 超时也认为成功 - } - }); - - // 监听连接事件 - final subscription = eventStream.listen((event) { - if (event['eventType'] == 'connectionFinished') { - if (!completer.isCompleted) { - completer.complete(true); - timeout.cancel(); - } - } - }); - - // 等待连接结果 - final result = await completer.future; - subscription.cancel(); - - // 关闭WebSocket连接 - await _channel?.sink.close(); - _channel = null; - - _isConnected = false; - _sessionId = null; - isConnected.value = false; - isSynthesizing.value = false; - _isSessionActive = false; - - return result; - } catch (e) { - _handleError(e); - return false; - } - } - - /// 处理接收到的消息 - void _handleMessage(dynamic message) { - try { - if (message is! List) { - _handleError(Exception('收到非二进制消息: $message')); - return; - } - - // 检查控制器是否已关闭 - if (_eventController.isClosed || _audioDataController.isClosed) { - Logger.warning('TTS服务控制器已关闭,无法处理消息'); - return; - } - - // 转换为Uint8List以提高处理效率 - final messageData = Uint8List.fromList(message); - - final response = _parseResponse(messageData); - if (response == null) { - _handleError(Exception('解析响应失败')); - return; - } - - // 处理事件 - final event = response['event'] as int?; - if (event != null && !_eventController.isClosed) { - switch (event) { - case eventConnectionStarted: - _eventController.add({'eventType': 'connectionStarted'}); - break; - case eventConnectionFailed: - _eventController.add({ - 'eventType': 'connectionFailed', - 'error': response['errorDetails'] ?? '连接失败' - }); - break; - case eventSessionStarted: - _eventController.add({'eventType': 'sessionStarted'}); - break; - case eventSessionFailed: - _eventController.add({ - 'eventType': 'sessionFailed', - 'error': response['errorDetails'] ?? '会话失败' - }); - break; - case eventTtsSentenceStart: - _eventController.add({'eventType': 'ttsSentenceStart'}); - _prepareAudioStream(); - break; - case eventTtsSentenceEnd: - _eventController.add({'eventType': 'ttsSentenceEnd'}); - // 结束音频流 - _finishAudioStream(); - break; - case eventTtsResponse: - // 处理音频数据 - final payload = response['payload'] as Uint8List?; - if (payload != null && payload.isNotEmpty) { - try { - _eventController.add({'eventType': 'ttsResponse'}); - - if (!_audioDataController.isClosed) { - _audioDataController.add(payload); - } - - // 将音频数据添加到流中 - _addAudioData(payload); - } catch (audioError) { - // 继续处理,不中断整个流程 - } - } - break; - case eventSessionFinished: - _eventController.add({'eventType': 'sessionFinished'}); - break; - case eventConnectionFinished: - _eventController.add({'eventType': 'connectionFinished'}); - break; - default: - _eventController.add({'eventType': 'unknown', 'eventCode': event}); - break; - } - } - } catch (e) { - _handleError(e); - } - } - - /// 准备音频流 - void _prepareAudioStream() { - try { - // 清空音频缓冲区 - _audioBuffer.clear(); - - } catch (e) { - if (kDebugMode) { - print('准备音频流时发生错误: $e'); - } - } - } - - /// 添加音频数据到流 - void _addAudioData(Uint8List data) { - try { - // 将音频数据添加到缓冲区 - if (data.isNotEmpty) { - _audioBuffer.add(data); - - } - } catch (e) { - if (kDebugMode) { - print('添加音频数据到流时发生错误: $e'); - } - // 不抛出异常,继续处理 - } - } - - /// 结束音频流 - void _finishAudioStream() { - try { - if (_audioBuffer.isNotEmpty) { - - - // 合并所有音频数据 - final totalSize = _audioBuffer.fold(0, (sum, data) => sum + data.length); - final mergedData = Uint8List(totalSize); - - int offset = 0; - for (final data in _audioBuffer) { - mergedData.setRange(offset, offset + data.length, data); - offset += data.length; - } - - // 清空缓冲区 - _audioBuffer.clear(); - - // 将合并后的数据添加到播放列表 - _addToPlaylist(mergedData); - } else { - - } - } catch (e) { - if (kDebugMode) { - print('结束音频流时发生错误: $e'); - } - // 不抛出异常,避免中断整个流程 - } - } - - /// 将音频数据添加到播放列表 - Future _addToPlaylist(Uint8List audioData) async { - try { - if (audioData.isEmpty) return; - - // 确保播放列表已初始化 - if (!_playlistInitialized) { - await _initializePlaylist(); - } - - // 创建音频源 - final audioSource = BytesAudioSource(audioData); - - // 添加到播放列表 - await _playlist.add(audioSource); - - // 如果当前没有播放,开始播放 - if (!_isPlaying.value) { - await _startPlayback(); - } else if (_audioPlayer.processingState == ProcessingState.completed) { - // 如果播放已完成但状态还没更新,手动前进到下一个 - await _advanceToNextItem(); - } - } catch (e) { - // 直接报告错误,不尝试恢复 - if (!_eventController.isClosed) { - _eventController.add({ - 'eventType': 'playbackError', - 'error': '添加音频到播放列表失败: $e' - }); - } - } - } - - /// 开始播放收集到的音频数据 - Future _startPlayback() async { - try { - if (!_playlistInitialized || _playlist.length == 0) { - return; - } - - // 检查当前播放状态 - final processingState = _audioPlayer.processingState; - - // 如果已经播放完成,需要重新设置位置到第一个未播放的项目 - if (processingState == ProcessingState.completed) { - // 找到第一个未播放的项目 - int nextIndex = 0; - if (_audioPlayer.currentIndex != null) { - nextIndex = math.min(_audioPlayer.currentIndex! + 1, _playlist.length - 1); - } - - // 跳转到下一个项目 - await _audioPlayer.seek(Duration.zero, index: nextIndex); - } - - // 开始播放 - await _audioPlayer.play(); - } catch (e) { - // 直接报告错误,不尝试恢复 - if (!_eventController.isClosed) { - _eventController.add({ - 'eventType': 'playbackError', - 'error': '开始播放失败: $e' - }); - } - } - } - - /// 处理错误 - void _handleError(dynamic error) { - try { - // 检查控制器是否已关闭 - if (_eventController.isClosed) { - Logger.warning('TTS事件控制器已关闭,无法发送错误事件'); - return; - } - - // 只记录错误,不尝试恢复 - _eventController.add({ - 'eventType': 'error', - 'error': error.toString() - }); - - Logger.error('火山语音TTS错误: ${error.toString()}'); - } catch (e) { - // 如果在处理错误时发生异常,记录到日志但不再抛出异常 - Logger.error('处理TTS错误时发生异常: ${e.toString()},原始错误: ${error.toString()}'); - } - } - - /// 处理连接关闭 - void _handleDone() { - Logger.info('TTS WebSocket连接已关闭'); - - // 重置所有状态 - _isConnected = false; - _sessionId = null; - isConnected.value = false; - isSynthesizing.value = false; - _isSessionActive = false; - - // 通知监听者连接已断开 - if (!_eventController.isClosed) { - _eventController.add({'eventType': 'disconnected'}); - } - } - - /// 解析响应 - Map? _parseResponse(Uint8List data) { - try { - if (data.length < 4) { - return null; - } - - // 解析头部 - final header = { - 'protocol_version': (data[0] >> 4) & 0x0F, - 'header_size': data[0] & 0x0F, - 'message_type': (data[1] >> 4) & 0x0F, - 'message_type_specific_flags': data[1] & 0x0F, - 'serialization_method': (data[2] >> 4) & 0x0F, - 'message_compression': data[2] & 0x0F, - 'reserved': data[3], - }; - - final result = { - 'header': header, - }; - - int offset = 4; - - // 解析事件 - if (header['message_type_specific_flags'] == _msgTypeFlagWithEvent) { - if (data.length < offset + 4) { - return result; - } - - final event = _bytesToInt(data.sublist(offset, offset + 4)); - result['event'] = event; - offset += 4; - } - - // 根据消息类型和事件类型解析剩余数据 - final messageType = header['message_type']; - final event = result['event'] as int?; - - if (messageType == _fullServerResponse || messageType == _audioOnlyResponse) { - if (event != null) { - switch (event) { - case eventConnectionStarted: - if (data.length < offset + 4) break; - - final connectionIdSize = _bytesToInt(data.sublist(offset, offset + 4)); - offset += 4; - - if (data.length < offset + connectionIdSize) break; - - final connectionId = String.fromCharCodes(data.sublist(offset, offset + connectionIdSize)); - result['connectionId'] = connectionId; - offset += connectionIdSize; - break; - - case eventConnectionFailed: - if (data.length < offset + 4) break; - - final metaSize = _bytesToInt(data.sublist(offset, offset + 4)); - offset += 4; - - if (data.length < offset + metaSize) break; - - final metaJson = String.fromCharCodes(data.sublist(offset, offset + metaSize)); - result['meta'] = metaJson; - offset += metaSize; - - try { - final meta = jsonDecode(metaJson); - result['errorDetails'] = meta['error_msg'] ?? 'Unknown error'; - } catch (_) {} - break; - - case eventSessionStarted: - case eventSessionFailed: - case eventSessionFinished: - // 读取会话ID - if (data.length < offset + 4) break; - - final sessionIdSize = _bytesToInt(data.sublist(offset, offset + 4)); - offset += 4; - - if (data.length < offset + sessionIdSize) break; - - final sessionId = String.fromCharCodes(data.sublist(offset, offset + sessionIdSize)); - result['sessionId'] = sessionId; - offset += sessionIdSize; - - // 读取元数据 - if (data.length < offset + 4) break; - - final metaSize = _bytesToInt(data.sublist(offset, offset + 4)); - offset += 4; - - if (data.length < offset + metaSize) break; - - final metaJson = String.fromCharCodes(data.sublist(offset, offset + metaSize)); - result['meta'] = metaJson; - offset += metaSize; - - try { - final meta = jsonDecode(metaJson); - if (meta['error_msg'] != null) { - result['errorDetails'] = meta['error_msg']; - } - } catch (_) {} - break; - - default: - // 读取会话ID - if (data.length < offset + 4) break; - - final sessionIdSize = _bytesToInt(data.sublist(offset, offset + 4)); - offset += 4; - - if (data.length < offset + sessionIdSize) break; - - final sessionId = String.fromCharCodes(data.sublist(offset, offset + sessionIdSize)); - result['sessionId'] = sessionId; - offset += sessionIdSize; - - // 读取序列号 - if (header['message_type_specific_flags'] == _msgTypeFlagNegativeSeq || - header['message_type_specific_flags'] == _msgTypeFlagPositiveSeq) { - if (data.length < offset + 4) break; - - final sequence = _bytesToInt(data.sublist(offset, offset + 4)); - result['sequence'] = sequence; - offset += 4; - } - - // 读取负载 - if (data.length < offset + 4) break; - - final payloadSize = _bytesToInt(data.sublist(offset, offset + 4)); - offset += 4; - - if (data.length < offset + payloadSize) break; - - final payload = data.sublist(offset, offset + payloadSize); - result['payload'] = payload; - - if (messageType == _fullServerResponse) { - try { - final payloadStr = String.fromCharCodes(payload); - result['payloadJson'] = payloadStr; - } catch (_) {} - } - break; - } - } - } else if (messageType == _errorInformation) { - if (data.length < offset + 4) { - return result; - } - - final errorCode = _bytesToInt(data.sublist(offset, offset + 4)); - result['errorCode'] = errorCode; - offset += 4; - - // 读取负载 - if (data.length < offset + 4) { - return result; - } - - final payloadSize = _bytesToInt(data.sublist(offset, offset + 4)); - offset += 4; - - if (data.length < offset + payloadSize) { - return result; - } - - final payload = data.sublist(offset, offset + payloadSize); - try { - final payloadStr = String.fromCharCodes(payload); - result['errorDetails'] = payloadStr; - } catch (_) {} - } - - return result; - } catch (e) { - if (kDebugMode) { - print('解析响应失败: $e'); - } - return null; - } - } - - /// 开始连接 - Future _startConnection() async { - final header = _createHeader( - _fullClientRequest, - _msgTypeFlagWithEvent, - _jsonSerialization, - _compressionNo - ); - - final optional = _createOptional(eventStartConnection, null, -1); - final payload = utf8.encode('{}'); - - await _sendEvent(header, optional, payload); - } - - /// 结束连接 - Future _finishConnection() async { - final header = _createHeader( - _fullClientRequest, - _msgTypeFlagWithEvent, - _jsonSerialization, - _compressionNo - ); - - final optional = _createOptional(eventFinishConnection, null, -1); - final payload = utf8.encode('{}'); - - await _sendEvent(header, optional, payload); - } - - /// 开始TTS会话 - Future _startTtsSession(String speaker) async { - final header = _createHeader( - _fullClientRequest, - _msgTypeFlagWithEvent, - _jsonSerialization, - _compressionNo - ); - - final optional = _createOptional(eventStartSession, _sessionId, -1); - - // 创建会话参数 - final payloadMap = { - 'user': {'uid': '123456'}, - 'event': eventStartSession, - 'namespace': 'BidirectionalTTS', - 'req_params': { - 'speaker': speaker, - 'audio_params': { - 'format': 'mp3', - 'sample_rate': 24000 - } - } - }; - - final payload = utf8.encode(jsonEncode(payloadMap)); - - await _sendEvent(header, optional, payload); - } - - /// 发送TTS消息 - Future _sendTtsMessage(String speaker, String text) async { - final header = _createHeader( - _fullClientRequest, - _msgTypeFlagWithEvent, - _jsonSerialization, - _compressionNo - ); - - final optional = _createOptional(eventTaskRequest, _sessionId, -1); - - // 创建任务参数 - final payloadMap = { - 'user': {'uid': '123456'}, - 'event': eventTaskRequest, - 'namespace': 'BidirectionalTTS', - 'req_params': { - 'text': text, - 'speaker': speaker, - 'audio_params': { - 'format': 'mp3', - 'sample_rate': 24000 - } - } - }; - - final payload = utf8.encode(jsonEncode(payloadMap)); - - await _sendEvent(header, optional, payload); - } - - /// 结束会话 - Future _finishSession() async { - final header = _createHeader( - _fullClientRequest, - _msgTypeFlagWithEvent, - _jsonSerialization, - _compressionNo - ); - - final optional = _createOptional(eventFinishSession, _sessionId, -1); - final payload = utf8.encode('{}'); - await _sendEvent(header, optional, payload); - } - - /// 创建头部 - Uint8List _createHeader( - int messageType, - int messageTypeSpecificFlags, - int serializationMethod, - int messageCompression - ) { - return Uint8List.fromList([ - // Protocol version | Header size - ((_protocolVersion << 4) | _defaultHeaderSize) & 0xFF, - // Message type | Message type specific flags - ((messageType << 4) | messageTypeSpecificFlags) & 0xFF, - // Serialization method | Compression method - ((serializationMethod << 4) | messageCompression) & 0xFF, - // Reserved - 0 - ]); - } - - /// 创建可选部分 - Uint8List _createOptional(int event, String? sessionId, int sequence) { - final buffer = BytesBuilder(); - - // 添加事件 - if (event != eventNone) { - buffer.add(_intToBytes(event)); - } - - // 添加会话ID - if (sessionId != null) { - final sessionIdBytes = utf8.encode(sessionId); - buffer.add(_intToBytes(sessionIdBytes.length)); - buffer.add(sessionIdBytes); - } - - // 添加序列号 - if (sequence >= 0) { - buffer.add(_intToBytes(sequence)); - } - - return buffer.toBytes(); - } - - /// 发送事件 - Future _sendEvent(Uint8List header, Uint8List optional, List payload) async { - if (_channel == null) { - throw Exception('WebSocket未连接'); - } - - final buffer = BytesBuilder(); - - // 添加头部 - buffer.add(header); - - // 添加可选部分 - if (optional.isNotEmpty) { - buffer.add(optional); - } - - // 添加负载大小 - buffer.add(_intToBytes(payload.length)); - - // 添加负载 - buffer.add(payload); - - // 发送数据 - _channel!.sink.add(buffer.toBytes()); - } - - /// 整数转字节数组 - Uint8List _intToBytes(int value) { - return Uint8List(4) - ..[0] = (value >> 24) & 0xFF - ..[1] = (value >> 16) & 0xFF - ..[2] = (value >> 8) & 0xFF - ..[3] = value & 0xFF; - } - - /// 字节数组转整数 - int _bytesToInt(Uint8List bytes) { - if (bytes.length != 4) { - throw ArgumentError('字节数组长度必须为4'); - } - - return ((bytes[0] & 0xFF) << 24) | - ((bytes[1] & 0xFF) << 16) | - ((bytes[2] & 0xFF) << 8) | - (bytes[3] & 0xFF); - } - - /// 释放资源 - @override - void onClose() async { - await disconnect(); - - // 关闭控制器 - if (!_audioDataController.isClosed) { - await _audioDataController.close(); - } - - if (!_eventController.isClosed) { - await _eventController.close(); - } - - // 释放资源 - _audioPlayer.dispose(); - - // 清除单例实例,确保下次获取时创建新实例 - _instance = null; - _isSessionActive = false; - - super.onClose(); - } - - /// 合成并播放文本 - Future speak(String text, {String? speaker}) async { - if (text.isEmpty) return false; - - try { - // 使用默认发音人 - final actualSpeaker = speaker ?? defaultSpeaker; - - // 合成文本 - final success = await synthesize(text, actualSpeaker); - - - return success; - } catch (e) { - _handleError(e); - return false; - } - } - - /// 停止播放 - Future stop() async { - try { - // 停止音频播放 - await _audioPlayer.stop(); - - // 清空播放列表 - await _playlist.clear(); - - // // 结束当前会话 - // await endSession(); - - // 清空音频缓冲区 - _audioBuffer.clear(); - } catch (e) { - _handleError(e); - } - } - - /// 检查是否正在播放 - bool isActuallyPlaying() { - return _isPlaying.value; - } - - /// 检查会话是否活跃 - bool hasActiveSession() { - return _isSessionActive && _sessionId != null; - } - - /// 设置音量 - Future setVolume(double volume) async { - try { - await _audioPlayer.setVolume(volume.clamp(0.0, 1.0)); - } catch (e) { - _handleError(e); - } - } - - /// 设置播放速度 - Future setSpeed(double speed) async { - try { - await _audioPlayer.setSpeed(speed.clamp(0.5, 2.0)); - } catch (e) { - _handleError(e); - } - } - - /// 切换启用状态 - void toggleEnabled() { - // 这个方法在当前实现中不需要特殊处理 - } - - /// 适合单句或少量文本的快速合成场景 - /// - /// [text] 要合成的文本 - /// [speaker] 发音人,如果为null则使用默认发音人 - /// - /// 返回合成是否成功 - Future speakOnce(String text, {String? speaker}) async { - if (text.isEmpty) { - Logger.warning('合成文本为空,跳过合成'); - return false; - } - - try { - // 使用默认发音人 - final actualSpeaker = speaker ?? defaultSpeaker; - - // 1. 确保连接 - if (!_isConnected) { - Logger.info('TTS未连接,开始连接'); - final connected = await connect(); - if (!connected) { - Logger.error('TTS连接失败,无法合成文本'); - return false; - } - } - - // 2. 开始会话 - final sessionStarted = await startSession(actualSpeaker); - if (!sessionStarted) { - Logger.error('TTS会话开始失败,无法合成文本'); - return false; - } - - // 3. 合成文本 - isSynthesizing.value = true; - final success = await synthesize(text, actualSpeaker); - - endSession(); - - return success; - } catch (e) { - Logger.error('TTS一次性合成失败: ${e.toString()}'); - // 确保会话结束 - endSession(); - return false; - } - } -} - -/// 使用 BytesAudioSource 进行音频播放 -/// 这种方式更简单可靠,适合已经收集完整的音频数据 -class BytesAudioSource extends StreamAudioSource { - final Uint8List _bytes; - final String _contentType; - static const int _bufferSize = 4096; // 4KB buffer size for better Android compatibility - - BytesAudioSource(List bytes, {String contentType = 'audio/mpeg'}) - : _bytes = bytes is Uint8List ? bytes : Uint8List.fromList(bytes), - _contentType = contentType; - - @override - Future request([int? start, int? end]) async { - try { - start = start ?? 0; - end = end ?? _bytes.length; - - // 确保范围有效 - final int validStart = math.min(math.max(0, start), _bytes.length); - final int validEnd = math.min(math.max(validStart, end), _bytes.length); - - // 提取请求的数据范围 - final data = _bytes.sublist(validStart, validEnd); - - if (kDebugMode && data.length > 1024) { - print('BytesAudioSource 请求数据: $validStart-$validEnd (${data.length} 字节)'); - } - - // 使用固定大小的块进行流式传输,提高兼容性 - final chunks = >[]; - var offset = 0; - while (offset < data.length) { - final chunkSize = math.min(_bufferSize, data.length - offset); - chunks.add(data.sublist(offset, offset + chunkSize)); - offset += chunkSize; - } - - return StreamAudioResponse( - sourceLength: _bytes.length, - contentLength: data.length, - offset: validStart, - stream: Stream.fromIterable(chunks), - contentType: _contentType, - ); - } catch (e) { - if (kDebugMode) { - print('BytesAudioSource 请求处理错误: $e'); - } - // 返回一个空响应而不是抛出异常,提高容错性 - return StreamAudioResponse( - sourceLength: _bytes.length, - contentLength: 0, - offset: 0, - stream: Stream.value(Uint8List(0)), - contentType: _contentType, - ); - } - } - - @override - Future get length => Future.value(_bytes.length); -} \ No newline at end of file diff --git a/apps/client/lib/data/services/speech_impl/volcano_tts_service.dart b/apps/client/lib/data/services/speech_impl/volcano_tts_service.dart deleted file mode 100644 index c0dfb893..00000000 --- a/apps/client/lib/data/services/speech_impl/volcano_tts_service.dart +++ /dev/null @@ -1,342 +0,0 @@ -import 'dart:async'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/services.dart'; -import 'package:get/get.dart'; -import '../tts_service.dart'; -import 'package:flutter_dotenv/flutter_dotenv.dart'; - -/// 火山语音合成服务实现 -class VolcanoTtsService extends GetxService implements TtsService { - /// 方法通道 - static const MethodChannel _channel = MethodChannel('volcano_speech/tts'); - - /// 事件通道 - static const EventChannel _eventChannel = - EventChannel('volcano_speech/tts_events'); - - /// 音频数据通道 - static const EventChannel _audioDataChannel = - EventChannel('volcano_speech/tts_audio_data'); - - /// 事件流控制器 - final StreamController _eventStreamController = - StreamController.broadcast(); - - /// 音频数据流控制器 - final StreamController _audioDataStreamController = - StreamController.broadcast(); - - /// 事件处理器 - StreamSubscription? _eventSubscription; - - /// 音频数据处理器 - StreamSubscription? _audioDataSubscription; - - /// 是否初始化完成 - bool _isInitialized = false; - - /// 当前语音名称 - String _currentVoice = "zh_female_qingxin"; - - /// 是否启用音频回调 - bool _isAudioCallbackEnabled = false; - - @override - String get currentVoice => _currentVoice; - - @override - bool get isSpeaking => _isSpeaking; - - /// 是否正在播放 - bool _isSpeaking = false; - - @override - Stream get onEvent => _eventStreamController.stream; - - /// 音频数据流 - Stream get onAudioData => _audioDataStreamController.stream; - - /// 构造函数 - VolcanoTtsService() { - _setupEventListeners(); - _setupAudioDataListeners(); - } - - /// 设置事件监听 - void _setupEventListeners() { - _eventSubscription = _eventChannel.receiveBroadcastStream().listen( - (dynamic event) { - if (event is! Map) return; - - final Map eventMap = event; - final String? type = eventMap['type'] as String?; - - switch (type) { - case 'started': - _isSpeaking = true; - _eventStreamController.add(TtsEvent(type: TtsEventType.started)); - break; - - case 'completed': - _isSpeaking = false; - _eventStreamController.add(TtsEvent(type: TtsEventType.completed)); - break; - - case 'canceled': - _isSpeaking = false; - _eventStreamController.add(TtsEvent(type: TtsEventType.canceled)); - break; - - case 'error': - _isSpeaking = false; - final errorCode = eventMap['errorCode'] as String? ?? "-1"; - final errorMessage = eventMap['errorMessage'] as String? ?? '未知错误'; - _eventStreamController.add(TtsEvent( - type: TtsEventType.error, - error: '$errorMessage (错误码: $errorCode)', - )); - break; - } - }, - onError: (Object error) { - debugPrint('TTS事件流错误: $error'); - _eventStreamController.add(TtsEvent( - type: TtsEventType.error, - error: '事件流错误: $error', - )); - }, - ); - } - - /// 设置音频数据监听 - void _setupAudioDataListeners() { - _audioDataSubscription = _audioDataChannel.receiveBroadcastStream().listen( - (dynamic data) { - if (data is Uint8List) { - _audioDataStreamController.add(data); - } - }, - onError: (Object error) { - debugPrint('TTS音频数据流错误: $error'); - }, - ); - } - - @override - Future initialize({List? supportedLanguages}) async { - if (_isInitialized) return true; - - try { - // 从.env文件读取配置 - final appId = dotenv.env['VOLCANO_SPEECH_APP_ID'] ?? ''; - final appToken = dotenv.env['VOLCANO_SPEECH_APP_TOKEN'] ?? ''; - - if (appId.isEmpty || appToken.isEmpty) { - debugPrint( - '火山语音初始化失败:缺少VOLCANO_SPEECH_APP_ID或VOLCANO_SPEECH_APP_TOKEN环境变量'); - return false; - } - - // 初始化火山语音TTS - final result = await _channel.invokeMethod('initialize', { - 'appId': appId, - 'appToken': appToken, - }) ?? - false; - - if (!result) { - debugPrint('火山语音TTS初始化失败'); - return false; - } - - _isInitialized = true; - return true; - } catch (e) { - debugPrint('火山语音TTS初始化异常:$e'); - return false; - } - } - - /// 检查初始化状态 - Future _ensureInitialized() async { - if (!_isInitialized) { - return await initialize(); - } - return true; - } - - @override - Future setVoice(String voiceName) async { - if (!await _ensureInitialized()) return false; - - try { - final result = await _channel.invokeMethod('setVoice', { - 'voice': voiceName, - }) ?? - false; - - if (result) { - _currentVoice = voiceName; - } - return result; - } catch (e) { - debugPrint('设置语音失败:$e'); - return false; - } - } - - @override - Future setTtsMode(String mod) async { - if (!await _ensureInitialized()) return false; - - try { - final result = await _channel.invokeMethod('setTtsMode', { - 'mod': mod, - }) ?? - false; - - return result; - } catch (e) { - debugPrint('设置TTS模式失败:$e'); - return false; - } - } - - @override - Future setVoiceFlocking(String speakerProfileId) async { - return true; - } - - /// 设置是否启用音频数据回调 - Future setEnableAudioCallback(bool enable) async { - if (!await _ensureInitialized()) return false; - - try { - final result = await _channel.invokeMethod('enableAudioCallback', { - 'enable': enable, - }) ?? - false; - - if (result) { - _isAudioCallbackEnabled = enable; - } - return result; - } catch (e) { - debugPrint('设置音频回调失败:$e'); - return false; - } - } - - @override - Future startspeak(String sessionid) async { - if (!await _ensureInitialized()) return false; - - try { - // 单次播放 - final result = await _channel.invokeMethod('startspeak', { - 'sessionid': sessionid, - }) ?? - false; - - return result; - } catch (e) { - debugPrint('单次播放失败:$e'); - _eventStreamController.add(TtsEvent.error('单次播放失败:$e')); - return false; - } - } - - @override - Future speakOnce(String sessionid, String text) async { - if (!await _ensureInitialized()) return false; - - try { - // 单次播放 - final result = await _channel.invokeMethod('speakOnce', { - 'text': text, - }) ?? - false; - - return result; - } catch (e) { - debugPrint('单次播放失败:$e'); - _eventStreamController.add(TtsEvent.error('单次播放失败:$e')); - return false; - } - } - - @override - Future speakStream(String sessionid, String text) async { - if (!await _ensureInitialized()) return false; - - try { - // 流式添加文本 - final result = await _channel.invokeMethod('speakStream', { - 'text': text, - }) ?? - false; - - return result; - } catch (e) { - debugPrint('流式播放失败:$e'); - _eventStreamController.add(TtsEvent.error('流式播放失败:$e')); - return false; - } - } - - @override - Future flushStream( - String sessionid, - ) async { - if (!await _ensureInitialized()) return false; - - try { - // 刷新流式文本 - return await _channel.invokeMethod('flushStream') ?? false; - } catch (e) { - debugPrint('刷新流式文本失败:$e'); - return false; - } - } - - @override - Future stop() async { - if (!_isInitialized) return false; - - try { - return await _channel.invokeMethod('stop') ?? false; - } catch (e) { - debugPrint('停止播放失败:$e'); - return false; - } - } - - @override - Future dispose() async { - if (_isSpeaking) { - await stop(); - } - - await _eventSubscription?.cancel(); - await _audioDataSubscription?.cancel(); - - if (!_eventStreamController.isClosed) { - await _eventStreamController.close(); - } - - if (!_audioDataStreamController.isClosed) { - await _audioDataStreamController.close(); - } - - if (_isInitialized) { - await _channel.invokeMethod('release'); - _isInitialized = false; - } - } - - @override - Future setAudioOutputDevice(int type) { - // TODO: implement setAudioOutputDevice - throw UnimplementedError(); - } -} diff --git a/apps/client/lib/data/services/translation_usage_service.dart b/apps/client/lib/data/services/translation_usage_service.dart deleted file mode 100644 index 5c4c5c72..00000000 --- a/apps/client/lib/data/services/translation_usage_service.dart +++ /dev/null @@ -1,545 +0,0 @@ -import 'dart:convert'; -import 'package:get/get.dart'; -import 'package:get_storage/get_storage.dart'; -import '../models/translation_usage_stats.dart'; -import '../../core/utils/logger.dart'; - -/// 翻译使用量统计服务 -class TranslationUsageService extends GetxService { - static const String _storageKey = 'translation_usage_stats'; - static const String _dailyStatsKey = 'daily_translation_stats'; - static const String _costConfigKey = 'translation_cost_config'; - - final GetStorage _storage = GetStorage(); - - // 实时统计数据 - final Rx realtimeStats = RealtimeUsageStats().obs; - - // 当日统计数据 - final Rx todayStats = - TranslationUsageStats.empty('').obs; - - // 成本配置 - final RxMap costConfig = {}.obs; - - // 预警阈值 - final RxDouble dailyCostThreshold = 50.0.obs; // 日成本预警阈值 - final RxDouble monthlyCostThreshold = 300.0.obs; // 月成本预警阈值 - - @override - void onInit() { - super.onInit(); - _initializeService(); - } - - /// 初始化服务 - void _initializeService() { - _loadCostConfig(); - _loadTodayStats(); - Logger.info('翻译使用量统计服务初始化完成'); - } - - /// 加载成本配置 - void _loadCostConfig() { - try { - final configData = _storage.read(_costConfigKey); - if (configData != null) { - costConfig.value = Map.from(configData); - } else { - // 设置默认成本配置(每千字符的成本,单位:元) - costConfig.value = { - 'translation_per_1k_chars': 0.05, // 翻译:每千字符0.05元 - 'asr_per_minute': 0.02, // ASR:每分钟0.02元 - 'tts_per_1k_chars': 0.03, // TTS:每千字符0.03元 - 'ai_summary_per_request': 0.01, // AI摘要:每次请求0.01元 - }; - _saveCostConfig(); - } - } catch (e) { - Logger.error('加载成本配置失败: $e'); - } - } - - /// 保存成本配置 - void _saveCostConfig() { - try { - _storage.write(_costConfigKey, costConfig.value); - } catch (e) { - Logger.error('保存成本配置失败: $e'); - } - } - - /// 加载当日统计数据 - void _loadTodayStats() { - try { - final today = DateTime.now(); - final todayKey = - '${today.year}-${today.month.toString().padLeft(2, '0')}-${today.day.toString().padLeft(2, '0')}'; - - final statsData = _storage.read('${_dailyStatsKey}_$todayKey'); - if (statsData != null) { - todayStats.value = TranslationUsageStats.fromJson( - Map.from(statsData)); - } else { - todayStats.value = TranslationUsageStats.empty(getCurrentUserId()); - } - } catch (e) { - Logger.error('加载当日统计数据失败: $e'); - todayStats.value = TranslationUsageStats.empty(getCurrentUserId()); - } - } - - /// 获取当前用户ID - String getCurrentUserId() { - try { - final userInfo = _storage.read('user_info'); - if (userInfo != null && userInfo['user'] != null) { - return userInfo['user']['uid'] ?? 'anonymous'; - } - } catch (e) { - Logger.warning('获取用户ID失败: $e'); - } - return 'anonymous'; - } - - /// 记录翻译API调用 - void recordTranslationApiCall({ - required String sourceText, - required String targetText, - required String sourceLanguage, - required String targetLanguage, - required String mode, - }) { - try { - // 更新实时统计 - realtimeStats.value.translationCount++; - realtimeStats.value.sourceTextCharacters += sourceText.length; - realtimeStats.value.ttsTextCharacters += targetText.length; - realtimeStats.value.currentLanguagePair = - '$sourceLanguage-$targetLanguage'; - realtimeStats.value.currentMode = mode; - realtimeStats.refresh(); - - // 更新当日统计 - 使用多维度统计 - final languagePair = '$sourceLanguage→$targetLanguage'; - - // 更新语言对统计 - final newLanguagePairStats = Map.from( - todayStats.value.languagePairStats); - if (newLanguagePairStats.containsKey(languagePair)) { - final existing = newLanguagePairStats[languagePair]!; - newLanguagePairStats[languagePair] = LanguagePairStats( - languagePair: languagePair, - translationCount: existing.translationCount + 1, - sourceCharacters: existing.sourceCharacters + sourceText.length, - cost: existing.cost + _calculateTranslationCost(sourceText.length), - ); - } else { - newLanguagePairStats[languagePair] = LanguagePairStats( - languagePair: languagePair, - translationCount: 1, - sourceCharacters: sourceText.length, - cost: _calculateTranslationCost(sourceText.length), - ); - } - - // 更新模式统计 - final newModeStats = - Map.from(todayStats.value.modeStats); - if (newModeStats.containsKey(mode)) { - final existing = newModeStats[mode]!; - newModeStats[mode] = existing.copyWith( - apiCalls: existing.apiCalls + 1, - sourceCharacters: existing.sourceCharacters + sourceText.length, - ttsCharacters: existing.ttsCharacters + targetText.length, - cost: existing.cost + _calculateTranslationCost(sourceText.length), - ); - } else { - newModeStats[mode] = TranslationModeStats( - apiCalls: 1, - sourceCharacters: sourceText.length, - ttsCharacters: targetText.length, - cost: _calculateTranslationCost(sourceText.length), - ); - } - - todayStats.value = todayStats.value.copyWith( - translationApiCalls: todayStats.value.translationApiCalls + 1, - sourceTextCharacters: - todayStats.value.sourceTextCharacters + sourceText.length, - ttsTextCharacters: - todayStats.value.ttsTextCharacters + targetText.length, - languagePairStats: newLanguagePairStats, - modeStats: newModeStats, - estimatedCost: _calculateEstimatedCost(todayStats.value.copyWith( - translationApiCalls: todayStats.value.translationApiCalls + 1, - sourceTextCharacters: - todayStats.value.sourceTextCharacters + sourceText.length, - ttsTextCharacters: - todayStats.value.ttsTextCharacters + targetText.length, - )), - ); - - _saveTodayStats(); - _checkCostThreshold(); - - Logger.info( - '记录翻译API调用: 源文本${sourceText.length}字符, 目标文本${targetText.length}字符'); - } catch (e) { - Logger.error('记录翻译API调用失败: $e'); - } - } - - /// 记录ASR API调用 - 优化版(精确计费参数) - void recordAsrApiCall({ - required int effectiveDurationSeconds, // 有效语音时长(VAD检测的实际语音) - required int totalDurationSeconds, // 总会话时长(包含静音) - required String language, - required String mode, // 翻译模式 - String? audioFormat, // 音频格式(可选) - int? sampleRate, // 采样率(可选) - }) { - try { - // 更新实时统计(使用有效语音时长作为主要计费依据) - realtimeStats.value.effectiveAudioDuration += effectiveDurationSeconds; - realtimeStats.value.totalSessionDuration += totalDurationSeconds; - realtimeStats.refresh(); - - // 更新模式统计 - final newModeStats = - Map.from(todayStats.value.modeStats); - if (newModeStats.containsKey(mode)) { - final existing = newModeStats[mode]!; - newModeStats[mode] = existing.copyWith( - effectiveAudioDuration: - existing.effectiveAudioDuration + effectiveDurationSeconds, - cost: existing.cost + _calculateAsrCost(effectiveDurationSeconds), - ); - } else { - newModeStats[mode] = TranslationModeStats( - effectiveAudioDuration: effectiveDurationSeconds, - cost: _calculateAsrCost(effectiveDurationSeconds), - ); - } - - // 更新当日统计 - todayStats.value = todayStats.value.copyWith( - asrApiCalls: todayStats.value.asrApiCalls + 1, - effectiveAudioDuration: - todayStats.value.effectiveAudioDuration + effectiveDurationSeconds, - totalSessionDuration: - todayStats.value.totalSessionDuration + totalDurationSeconds, - modeStats: newModeStats, - estimatedCost: _calculateEstimatedCost(todayStats.value.copyWith( - asrApiCalls: todayStats.value.asrApiCalls + 1, - effectiveAudioDuration: todayStats.value.effectiveAudioDuration + - effectiveDurationSeconds, - )), - ); - - _saveTodayStats(); - - Logger.info( - 'ASR统计: 有效语音${effectiveDurationSeconds}秒, 总时长${totalDurationSeconds}秒, 语言$language, 模式$mode'); - } catch (e) { - Logger.error('记录ASR API调用失败: $e'); - } - } - - /// 记录TTS API调用 - void recordTtsApiCall({ - required String text, - required int durationSeconds, - required String language, - }) { - try { - // 更新实时统计 - realtimeStats.value.totalSessionDuration += durationSeconds; - realtimeStats.refresh(); - - // 更新当日统计(TTS按字符数计费,不是按时长) - todayStats.value = todayStats.value.copyWith( - ttsApiCalls: todayStats.value.ttsApiCalls + 1, - ttsTextCharacters: todayStats.value.ttsTextCharacters + text.length, - totalSessionDuration: - todayStats.value.totalSessionDuration + durationSeconds, - estimatedCost: _calculateEstimatedCost(todayStats.value.copyWith( - ttsApiCalls: todayStats.value.ttsApiCalls + 1, - ttsTextCharacters: todayStats.value.ttsTextCharacters + text.length, - )), - ); - - _saveTodayStats(); - - Logger.info('记录TTS API调用: 文本${text.length}字符, 时长${durationSeconds}秒'); - } catch (e) { - Logger.error('记录TTS API调用失败: $e'); - } - } - - /// 记录AI摘要API调用 - void recordAiSummaryApiCall() { - try { - // 更新当日统计 - todayStats.value = todayStats.value.copyWith( - aiSummaryApiCalls: todayStats.value.aiSummaryApiCalls + 1, - estimatedCost: _calculateEstimatedCost(todayStats.value.copyWith( - aiSummaryApiCalls: todayStats.value.aiSummaryApiCalls + 1, - )), - ); - - _saveTodayStats(); - - Logger.info('记录AI摘要API调用'); - } catch (e) { - Logger.error('记录AI摘要API调用失败: $e'); - } - } - - /// 开始新会话 - void startNewSession() { - realtimeStats.value.reset(); - - // 更新当日会话数 - todayStats.value = todayStats.value.copyWith( - sessionCount: todayStats.value.sessionCount + 1, - ); - - _saveTodayStats(); - Logger.info('开始新的翻译会话'); - } - - /// 计算预估成本 - 优化版(基于精确计费参数) - double _calculateEstimatedCost(TranslationUsageStats stats) { - double cost = 0.0; - - // 翻译成本:基于源文本字符数 - cost += (stats.sourceTextCharacters / 1000) * - (costConfig['translation_per_1k_chars'] ?? 0.05); - - // ASR成本:基于有效音频时长 - cost += (stats.effectiveAudioDuration / 60) * - (costConfig['asr_per_minute'] ?? 0.02); - - // TTS成本:基于TTS文本字符数 - cost += (stats.ttsTextCharacters / 1000) * - (costConfig['tts_per_1k_chars'] ?? 0.03); - - // AI摘要成本(已废弃但保留兼容性) - cost += stats.aiSummaryApiCalls * - (costConfig['ai_summary_per_request'] ?? 0.01); - - return cost; - } - - /// 计算翻译成本(单次调用) - double _calculateTranslationCost(int sourceCharacters) { - return (sourceCharacters / 1000) * - (costConfig['translation_per_1k_chars'] ?? 0.05); - } - - /// 计算ASR成本(单次调用) - double _calculateAsrCost(int durationSeconds) { - return (durationSeconds / 60) * (costConfig['asr_per_minute'] ?? 0.02); - } - - /// 计算TTS成本(单次调用) - double _calculateTtsCost(int textCharacters) { - return (textCharacters / 1000) * (costConfig['tts_per_1k_chars'] ?? 0.03); - } - - /// 保存当日统计数据 - void _saveTodayStats() { - try { - final today = DateTime.now(); - final todayKey = - '${today.year}-${today.month.toString().padLeft(2, '0')}-${today.day.toString().padLeft(2, '0')}'; - _storage.write('${_dailyStatsKey}_$todayKey', todayStats.value.toJson()); - } catch (e) { - Logger.error('保存当日统计数据失败: $e'); - } - } - - /// 检查成本阈值 - void _checkCostThreshold() { - final todayCost = todayStats.value.estimatedCost; - - if (todayCost >= dailyCostThreshold.value) { - _showCostWarning('今日翻译成本已达到预警阈值:¥${todayCost.toStringAsFixed(2)}'); - } - } - - /// 显示成本预警 - void _showCostWarning(String message) { - Get.snackbar( - '成本预警', - message, - snackPosition: SnackPosition.TOP, - backgroundColor: Get.theme.colorScheme.error.withOpacity(0.1), - colorText: Get.theme.colorScheme.error, - duration: const Duration(seconds: 5), - ); - } - - /// 获取历史统计数据 - Future> getHistoryStats({ - required DateTime startDate, - required DateTime endDate, - }) async { - try { - final List historyStats = []; - - for (DateTime date = startDate; - date.isBefore(endDate) || date.isAtSameMomentAs(endDate); - date = date.add(const Duration(days: 1))) { - final dateKey = - '${date.year}-${date.month.toString().padLeft(2, '0')}-${date.day.toString().padLeft(2, '0')}'; - final statsData = _storage.read('${_dailyStatsKey}_$dateKey'); - - if (statsData != null) { - historyStats.add(TranslationUsageStats.fromJson( - Map.from(statsData))); - } - } - - return historyStats; - } catch (e) { - Logger.error('获取历史统计数据失败: $e'); - return []; - } - } - - /// 清理过期数据(保留最近90天) - void cleanupOldData() { - try { - final cutoffDate = DateTime.now().subtract(const Duration(days: 90)); - final allKeys = _storage.getKeys(); - - for (final key in allKeys) { - if (key.startsWith(_dailyStatsKey)) { - final dateStr = key.replaceFirst('${_dailyStatsKey}_', ''); - try { - final date = DateTime.parse(dateStr); - if (date.isBefore(cutoffDate)) { - _storage.remove(key); - Logger.info('清理过期统计数据: $key'); - } - } catch (e) { - // 忽略解析错误的键 - } - } - } - } catch (e) { - Logger.error('清理过期数据失败: $e'); - } - } - - /// 更新成本配置 - void updateCostConfig(Map newConfig) { - costConfig.value = newConfig; - _saveCostConfig(); - - // 重新计算当日成本 - todayStats.value = todayStats.value.copyWith( - estimatedCost: _calculateEstimatedCost(todayStats.value), - ); - _saveTodayStats(); - - Logger.info('更新成本配置完成'); - } - - /// 更新预警阈值 - void updateThresholds({ - double? dailyThreshold, - double? monthlyThreshold, - }) { - if (dailyThreshold != null) { - dailyCostThreshold.value = dailyThreshold; - } - if (monthlyThreshold != null) { - monthlyCostThreshold.value = monthlyThreshold; - } - - // 保存阈值配置 - _storage.write('daily_cost_threshold', dailyCostThreshold.value); - _storage.write('monthly_cost_threshold', monthlyCostThreshold.value); - - Logger.info('更新预警阈值完成'); - } - - /// 获取月度统计汇总 - Future getMonthlyStats(int year, int month) async { - try { - final startDate = DateTime(year, month, 1); - final endDate = DateTime(year, month + 1, 0); // 月末 - - final dailyStats = await getHistoryStats( - startDate: startDate, - endDate: endDate, - ); - - if (dailyStats.isEmpty) { - return TranslationUsageStats.empty(getCurrentUserId()); - } - - // 汇总月度数据 - int totalTranslationCalls = 0; - int totalAsrCalls = 0; - int totalTtsCalls = 0; - int totalAiSummaryCalls = 0; - int totalSourceChars = 0; - int totalTargetChars = 0; - int totalRecordingDuration = 0; - int totalTtsPlayDuration = 0; - int totalSessions = 0; - double totalCost = 0.0; - - final Map combinedLanguagePairUsage = {}; - final Map combinedModeUsage = {}; - - for (final stats in dailyStats) { - totalTranslationCalls += stats.translationApiCalls; - totalAsrCalls += stats.asrApiCalls; - totalTtsCalls += stats.ttsApiCalls; - totalAiSummaryCalls += stats.aiSummaryApiCalls; - totalSourceChars += stats.sourceCharacterCount; - totalTargetChars += stats.targetCharacterCount; - totalRecordingDuration += stats.audioRecordingDuration; - totalTtsPlayDuration += stats.ttsPlaybackDuration; - totalSessions += stats.sessionCount; - totalCost += stats.estimatedCost; - - // 合并语言对使用统计 - stats.languagePairUsage.forEach((key, value) { - combinedLanguagePairUsage[key] = - (combinedLanguagePairUsage[key] ?? 0) + value; - }); - - // 合并模式使用统计 - stats.modeUsage.forEach((key, value) { - combinedModeUsage[key] = (combinedModeUsage[key] ?? 0) + value; - }); - } - - return TranslationUsageStats( - id: 'monthly_${year}_$month', - date: startDate, - userId: getCurrentUserId(), - timeGranularity: 'month', - translationApiCalls: totalTranslationCalls, - asrApiCalls: totalAsrCalls, - ttsApiCalls: totalTtsCalls, - aiSummaryApiCalls: totalAiSummaryCalls, - sourceTextCharacters: totalSourceChars, - effectiveAudioDuration: totalRecordingDuration, - ttsTextCharacters: totalTargetChars, - totalSessionDuration: totalTtsPlayDuration, - sessionCount: totalSessions, - estimatedCost: totalCost, - ); - } catch (e) { - Logger.error('获取月度统计失败: $e'); - return TranslationUsageStats.empty(getCurrentUserId()); - } - } -} diff --git a/apps/client/lib/modules/goods/bindings/goodsai_binding.dart b/apps/client/lib/modules/goods/bindings/goodsai_binding.dart deleted file mode 100644 index 4c21e492..00000000 --- a/apps/client/lib/modules/goods/bindings/goodsai_binding.dart +++ /dev/null @@ -1,9 +0,0 @@ -import 'package:get/get.dart'; -import '../controllers/goodsai_controller.dart'; - -class GoodsaiBinding extends Bindings { - @override - void dependencies() { - Get.lazyPut(() => GoodsaiController()); - } -} \ No newline at end of file diff --git a/apps/client/lib/modules/goods/controllers/goodsai_controller.dart b/apps/client/lib/modules/goods/controllers/goodsai_controller.dart deleted file mode 100644 index fe04c175..00000000 --- a/apps/client/lib/modules/goods/controllers/goodsai_controller.dart +++ /dev/null @@ -1,40 +0,0 @@ -import 'dart:convert'; -import 'dart:developer' as developer; - -import 'package:get/get.dart'; -import '../../../routes/app_routes.dart'; -import '../../../data/models/goods.dart'; -import '../../../data/services/network/api.dart'; -import 'goods_base_controller.dart'; -// ... existing code ... - -class GoodsaiController extends GoodsBaseController { - @override - Future> fetchProducts() async { - final resp = await Api.getGoods({'usagetype': UsageType.AI.toInt}); - // 输出完整响应,便于调试接口结构 - try { - developer.log('getGoods(AI) resp: ${jsonEncode(resp)}'); - } catch (_) { - developer.log('getGoods(AI) resp (raw): $resp'); - } - if (resp == null || resp is! Map) return []; - if (resp.containsKey('error') || resp.containsKey('msg')) { - final msg = resp['error'] ?? resp['msg'] ?? '服务器错误'; - throw Exception(msg); - } - final container = - (resp is Map && resp['data'] is Map) ? resp['data'] : resp; - final data = (container is Map) ? (container['goodss']) : null; - if (data is List) { - final list = - data.whereType>().map(DBGoods.fromJson).toList(); - // 兜底过滤确保展示 AI 类型 - return list.where((g) => g.usagetype == UsageType.AI).toList(); - } - return []; - } - - // 如需自定义跳转逻辑,可保留重写调用父类 - // Future purchase(DBGoods item) async => super.purchase(item); -} diff --git a/apps/client/lib/modules/goods/controllers/goodsmeet_controller.dart b/apps/client/lib/modules/goods/controllers/goodsmeet_controller.dart index ad171e3c..bd3656ab 100644 --- a/apps/client/lib/modules/goods/controllers/goodsmeet_controller.dart +++ b/apps/client/lib/modules/goods/controllers/goodsmeet_controller.dart @@ -1,5 +1,3 @@ -import 'package:get/get.dart'; -import '../../../routes/app_routes.dart'; import '../../../data/models/goods.dart'; import '../../../data/services/network/api.dart'; import 'goods_base_controller.dart'; diff --git a/apps/client/lib/modules/goods/controllers/goodstrans_controller.dart b/apps/client/lib/modules/goods/controllers/goodstrans_controller.dart index fabab8ae..bff9544a 100644 --- a/apps/client/lib/modules/goods/controllers/goodstrans_controller.dart +++ b/apps/client/lib/modules/goods/controllers/goodstrans_controller.dart @@ -1,5 +1,3 @@ -import 'package:get/get.dart'; -import '../../../routes/app_routes.dart'; import '../../../data/models/goods.dart'; import '../../../data/services/network/api.dart'; import 'goods_base_controller.dart'; diff --git a/apps/client/lib/modules/goods/views/goodsai_view.dart b/apps/client/lib/modules/goods/views/goodsai_view.dart deleted file mode 100644 index 928401bb..00000000 --- a/apps/client/lib/modules/goods/views/goodsai_view.dart +++ /dev/null @@ -1,497 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:get/get.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; -import '../../../data/models/goods.dart'; -import '../../../data/models/user_Info.dart'; -import '../controllers/goodsai_controller.dart'; -import '../utils/goods_i18n.dart'; -import 'widgets/goods_footer_section.dart'; - -class GoodsaiView extends GetView { - const GoodsaiView({super.key}); - - @override - Widget build(BuildContext context) { - final isDarkMode = Theme.of(context).brightness == Brightness.dark; - - return Scaffold( - backgroundColor: isDarkMode ? Colors.black : Colors.grey[50], - appBar: AppBar( - backgroundColor: isDarkMode ? Colors.black : Colors.white, - elevation: 0.5, - title: Text( - 'aiFunction'.tr, - style: TextStyle( - fontSize: 18.sp, - fontWeight: FontWeight.w600, - color: isDarkMode ? Colors.white : Colors.black, - ), - ), - centerTitle: true, - ), - body: SafeArea( - top: false, - child: Obx(() { - // 访问刷新信号以建立依赖关系:用户信息变化时触发重建 - final _ = User.refreshTick.value; - Widget content; - if (controller.loading.value) { - content = const Center(child: CircularProgressIndicator()); - } else if (controller.error.isNotEmpty) { - content = Center(child: Text(controller.error.value)); - } else { - content = ListView( - padding: EdgeInsets.all(16.w), - children: [ - _buildHeader(isDarkMode), - SizedBox(height: 12.h), - _buildUsageCard(isDarkMode), - SizedBox(height: 16.h), - Text( - 'availablePackages'.tr, - style: TextStyle( - fontSize: 16.sp, - fontWeight: FontWeight.w600, - color: isDarkMode ? Colors.white : Colors.black, - ), - ), - SizedBox(height: 8.h), - ...controller.items.map((item) => Padding( - padding: EdgeInsets.only(bottom: 12.h), - child: _buildCard(item, isDarkMode), - )), - SizedBox(height: 16.h), - _buildFeaturesSection(isDarkMode), - SizedBox(height: 16.h), - GoodsFooterSection(isDarkMode: isDarkMode), - ], - ); - } - return Stack( - children: [ - content, - if (controller.isPaying.value) - Positioned.fill( - child: AbsorbPointer( - absorbing: true, - child: Container( - color: Colors.black.withOpacity(0.35), - child: const Center( - child: CircularProgressIndicator(), - ), - ), - ), - ), - ], - ); - }), - ), - ); - } - - Widget _buildHeader(bool isDarkMode) { - return Container( - padding: EdgeInsets.all(16.w), - decoration: BoxDecoration( - color: isDarkMode ? Colors.grey[900] : Colors.white, - borderRadius: BorderRadius.circular(12.r), - boxShadow: [ - BoxShadow( - color: isDarkMode - ? Colors.black.withOpacity(0.2) - : Colors.black.withOpacity(0.05), - blurRadius: 10, - offset: const Offset(0, 2), - ), - ], - ), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - width: 44.w, - height: 44.w, - decoration: BoxDecoration( - color: isDarkMode - ? Colors.indigo[900]!.withOpacity(0.3) - : Colors.indigo[100]!, - borderRadius: BorderRadius.circular(22.r), - ), - child: Icon(Icons.smart_toy, - color: isDarkMode ? Colors.indigo[300]! : Colors.indigo[600]!), - ), - SizedBox(width: 12.w), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'aiFunction'.tr, - style: TextStyle( - fontSize: 18.sp, - fontWeight: FontWeight.w700, - color: isDarkMode ? Colors.white : Colors.black, - ), - ), - SizedBox(height: 6.h), - Text( - 'aiHeaderDesc1'.tr, - style: TextStyle( - fontSize: 12.sp, - color: isDarkMode ? Colors.white70 : Colors.grey[700], - ), - ), - SizedBox(height: 4.h), - Text( - 'aiHeaderDesc2'.tr, - style: TextStyle( - fontSize: 12.sp, - color: isDarkMode ? Colors.white70 : Colors.grey[700], - ), - ), - ], - ), - ), - ], - ), - ); - } - - Widget _buildUsageCard(bool isDarkMode) { - // 从 User 属性计算 aitimer 数据 - int totalAi = 0; - int remainAi = 0; - if (User.isLoggedIn()) { - final u = User.instance; - totalAi = u.aichattotalintegral; - remainAi = u.aichatintegral; - } - // 进度显示为“剩余额度比例”,remain/total: - final progress = (totalAi > 0) ? (remainAi / totalAi).clamp(0.0, 1.0) : 0.0; - - return Container( - padding: EdgeInsets.all(16.w), - decoration: BoxDecoration( - color: isDarkMode ? Colors.grey[900] : Colors.white, - borderRadius: BorderRadius.circular(12.r), - boxShadow: [ - BoxShadow( - color: isDarkMode - ? Colors.black.withOpacity(0.2) - : Colors.black.withOpacity(0.05), - blurRadius: 10, - offset: const Offset(0, 2), - ), - ], - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Icon(Icons.timeline, - color: isDarkMode ? Colors.blue[300]! : Colors.blue[600]!), - SizedBox(width: 8.w), - Text( - 'remainingQuota'.tr, - style: TextStyle( - fontSize: 16.sp, - fontWeight: FontWeight.w600, - color: isDarkMode ? Colors.white : Colors.black, - ), - ), - ], - ), - SizedBox(height: 12.h), - LinearProgressIndicator( - value: progress, - minHeight: 8.h, - backgroundColor: isDarkMode ? Colors.grey[800] : Colors.grey[300], - valueColor: AlwaysStoppedAnimation( - isDarkMode ? Colors.blue[300]! : Colors.blue[600]!), - ), - SizedBox(height: 8.h), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - '${'totalQuota'.tr}:$totalAi', - style: TextStyle( - fontSize: 12.sp, - color: isDarkMode ? Colors.white70 : Colors.grey[700], - ), - ), - Text( - '${'remaining'.tr}:$remainAi', - style: TextStyle( - fontSize: 12.sp, - color: isDarkMode ? Colors.white70 : Colors.grey[700], - ), - ), - ], - ), - ], - ), - ); - } - - Widget _buildFeaturesSection(bool isDarkMode) { - final textColor = isDarkMode ? Colors.white : Colors.black; - final subColor = isDarkMode ? Colors.white70 : Colors.grey[700]; - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'featureDescription'.tr, - style: TextStyle( - fontSize: 16.sp, - fontWeight: FontWeight.w600, - color: textColor, - ), - ), - SizedBox(height: 10.h), - MasonryGridView.count( - crossAxisCount: 2, - mainAxisSpacing: 12.h, - crossAxisSpacing: 12.w, - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - itemCount: 6, - itemBuilder: (context, index) { - switch (index) { - case 0: - return _buildFeatureCard( - isDarkMode, - icon: Icons.music_note, - title: 'musicAndRecommendation'.tr, - lines: [ - 'musicSearchPlaybackControl'.tr, - 'smartPlaylistAndSimilarRecommendations'.tr, - ], - colorSeed: Colors.purple, - ); - case 1: - return _buildFeatureCard( - isDarkMode, - icon: Icons.navigation, - title: 'navigationAndRoutes'.tr, - lines: [ - 'routePlanningAndCongestionAvoidance'.tr, - 'voiceBroadcastAndWaypoints'.tr, - ], - colorSeed: Colors.orange, - ); - case 2: - return _buildFeatureCard( - isDarkMode, - icon: Icons.wb_sunny, - title: 'weatherQuery'.tr, - lines: [ - 'realTimeWeatherForecast'.tr, - 'clothingAdviceAndTravelReminders'.tr, - ], - colorSeed: Colors.blue, - ); - case 3: - return _buildFeatureCard( - isDarkMode, - icon: Icons.place, - title: 'nearbySearch'.tr, - lines: [ - 'poiSearchFoodGasParking'.tr, - 'ratingsHoursAndDirectRoutes'.tr, - ], - colorSeed: Colors.green, - ); - case 4: - return _buildFeatureCard( - isDarkMode, - icon: Icons.newspaper, - title: 'newsInformation'.tr, - lines: [ - 'hotNewsAndTopicOverview'.tr, - 'longArticleSummariesAndKeyPoints'.tr, - ], - colorSeed: Colors.indigo, - ); - default: - return _buildFeatureCard( - isDarkMode, - icon: Icons.call, - title: 'communicationAssistant'.tr, - lines: [ - 'helpCallAndSMS'.tr, - 'templatedMessagesAndScheduleReminders'.tr, - ], - colorSeed: Colors.teal, - ); - } - }, - ), - SizedBox(height: 12.h), - Text( - 'aiDisclaimer'.tr, - style: TextStyle(fontSize: 12.sp, color: subColor), - ), - ], - ); - } - - Widget _buildFeatureCard( - bool isDarkMode, { - required IconData icon, - required String title, - required List lines, - required MaterialColor colorSeed, - }) { - final bgColor = isDarkMode ? Colors.grey[900] : Colors.white; - final mainColor = isDarkMode ? colorSeed[300]! : colorSeed[600]!; - final subColor = isDarkMode ? Colors.white70 : Colors.grey[700]; - return Container( - padding: EdgeInsets.all(12.w), - decoration: BoxDecoration( - color: bgColor, - borderRadius: BorderRadius.circular(12.r), - boxShadow: [ - BoxShadow( - color: isDarkMode - ? Colors.black.withOpacity(0.2) - : Colors.black.withOpacity(0.05), - blurRadius: 10, - offset: const Offset(0, 2), - ), - ], - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Container( - width: 36.w, - height: 36.w, - decoration: BoxDecoration( - color: isDarkMode - ? mainColor.withOpacity(0.25) - : mainColor.withOpacity(0.15), - borderRadius: BorderRadius.circular(18.r), - ), - child: Icon(icon, color: mainColor), - ), - SizedBox(width: 8.w), - Expanded( - child: Text( - title, - style: TextStyle( - fontSize: 14.sp, - fontWeight: FontWeight.w600, - ), - ), - ), - ], - ), - SizedBox(height: 8.h), - ...lines.map((line) => Padding( - padding: EdgeInsets.only(bottom: 4.h), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Icon(Icons.check_circle, color: mainColor, size: 14.sp), - SizedBox(width: 6.w), - Expanded( - child: Text( - line, - style: TextStyle(fontSize: 12.sp, color: subColor), - ), - ), - ], - ), - )), - ], - ), - ); - } - - Widget _buildCard(DBGoods item, bool isDarkMode) { - return Container( - padding: EdgeInsets.all(16.w), - decoration: BoxDecoration( - color: isDarkMode ? Colors.grey[900] : Colors.white, - borderRadius: BorderRadius.circular(12.r), - boxShadow: [ - BoxShadow( - color: isDarkMode - ? Colors.black.withOpacity(0.2) - : Colors.black.withOpacity(0.05), - blurRadius: 10, - offset: const Offset(0, 2), - ), - ], - ), - child: Row( - children: [ - Container( - width: 42.w, - height: 42.w, - decoration: BoxDecoration( - color: isDarkMode - ? Colors.teal[900]!.withOpacity(0.3) - : Colors.teal[100]!, - borderRadius: BorderRadius.circular(21.r), - ), - child: Icon(Icons.auto_awesome, - color: isDarkMode ? Colors.teal[300]! : Colors.teal[600]!), - ), - SizedBox(width: 12.w), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text(localizedGoodsName(item), - style: TextStyle( - fontSize: 16.sp, - fontWeight: FontWeight.w600, - color: isDarkMode ? Colors.white : Colors.black, - )), - SizedBox(height: 4.h), - Text(localizedGoodsDesc(item), - style: TextStyle( - fontSize: 12.sp, - color: isDarkMode ? Colors.white70 : Colors.grey[600], - )), - ], - ), - ), - Column( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - Text(goodsDisplayPrice(item), - style: TextStyle( - fontSize: 16.sp, - fontWeight: FontWeight.w600, - color: isDarkMode ? Colors.white : Colors.black, - )), - SizedBox(height: 8.h), - GestureDetector( - onTap: () => controller.purchase(item), - child: Container( - padding: - EdgeInsets.symmetric(horizontal: 12.w, vertical: 6.h), - decoration: BoxDecoration( - color: Colors.blue[600], - borderRadius: BorderRadius.circular(20.r), - ), - child: Text( - 'purchase'.tr, - style: TextStyle(fontSize: 12.sp, color: Colors.white), - ), - ), - ), - ], - ), - ], - ), - ); - } -} diff --git a/apps/client/lib/modules/goods/views/goodsvip_view.dart b/apps/client/lib/modules/goods/views/goodsvip_view.dart index ffb2bbde..b1f7ee1c 100644 --- a/apps/client/lib/modules/goods/views/goodsvip_view.dart +++ b/apps/client/lib/modules/goods/views/goodsvip_view.dart @@ -281,7 +281,6 @@ class GoodsvipView extends GetView { UsageType.Vip: 'memberService'.tr, UsageType.Compute: 'computePack'.tr, }; - final iconAndColor = _iconColorForType(type, isDarkMode); final subColor = isDarkMode ? Colors.white70 : Colors.grey[700]; String titleStr = titles[type] ?? type.name; String? vipSubtitle; @@ -290,11 +289,9 @@ class GoodsvipView extends GetView { vipSubtitle = controller.computeSummary; } if (type == UsageType.Vip) { - int viplv = 0; int vipexptime = 0; if (User.isLoggedIn()) { final u = User.instance; - viplv = u.viplv; vipexptime = u.vipexptime; } DateTime? expiry; @@ -484,266 +481,6 @@ class GoodsvipView extends GetView { ); } - Widget _buildGoodsCardByType(DBGoods item, UsageType type, bool isDarkMode) { - final iconAndColor = _iconColorForType(type, isDarkMode); - return Container( - padding: EdgeInsets.all(16.w), - decoration: BoxDecoration( - color: isDarkMode ? Colors.grey[900] : Colors.white, - borderRadius: BorderRadius.circular(12.r), - boxShadow: [ - BoxShadow( - color: isDarkMode - ? Colors.black.withOpacity(0.2) - : Colors.black.withOpacity(0.05), - blurRadius: 10, - offset: const Offset(0, 2), - ), - ], - ), - child: Row( - children: [ - Container( - width: 42.w, - height: 42.w, - decoration: BoxDecoration( - color: iconAndColor.background, - borderRadius: BorderRadius.circular(21.r), - ), - child: Icon(iconAndColor.icon, color: iconAndColor.foreground), - ), - SizedBox(width: 12.w), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text(localizedGoodsName(item), - style: TextStyle( - fontSize: 16.sp, - fontWeight: FontWeight.w600, - color: isDarkMode ? Colors.white : Colors.black, - )), - SizedBox(height: 4.h), - Text(localizedGoodsDesc(item), - style: TextStyle( - fontSize: 12.sp, - color: isDarkMode ? Colors.white70 : Colors.grey[600], - )), - ], - ), - ), - SizedBox(width: 12.w), - Column( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - Text(goodsDisplayPrice(item), - style: TextStyle( - fontSize: 16.sp, - fontWeight: FontWeight.w600, - color: isDarkMode ? Colors.white : Colors.black, - )), - SizedBox(height: 8.h), - GestureDetector( - onTap: () => controller.purchase(item), - child: Container( - padding: - EdgeInsets.symmetric(horizontal: 12.w, vertical: 6.h), - decoration: BoxDecoration( - color: Colors.blue[600], - borderRadius: BorderRadius.circular(20.r), - ), - child: Text( - 'purchase'.tr, - style: TextStyle( - fontSize: 12.sp, - color: Colors.white, - ), - ), - ), - ), - ], - ), - ], - ), - ); - } - - Widget _buildMetricsForType(UsageType type, bool isDarkMode) { - if (type == UsageType.Vip) { - return _buildVipMetricsCard(isDarkMode); - } - return _buildQuotaCard(type, isDarkMode); - } - - Widget _buildVipMetricsCard(bool isDarkMode) { - final textColor = isDarkMode ? Colors.white : Colors.black; - final subColor = isDarkMode ? Colors.white70 : Colors.grey[700]; - int viplv = 0; - int vipexptime = 0; - if (User.isLoggedIn()) { - final u = User.instance; - viplv = u.viplv; - vipexptime = u.vipexptime; - } - DateTime? expiry; - if (vipexptime > 0) { - expiry = vipexptime > 1000000000000 - ? DateTime.fromMillisecondsSinceEpoch(vipexptime) - : DateTime.fromMillisecondsSinceEpoch(vipexptime * 1000); - } - final iconColors = _iconColorForType(UsageType.Vip, isDarkMode); - return Container( - padding: EdgeInsets.all(16.w), - decoration: BoxDecoration( - color: isDarkMode ? Colors.grey[900] : Colors.white, - borderRadius: BorderRadius.circular(12.r), - boxShadow: [ - BoxShadow( - color: isDarkMode - ? Colors.black.withOpacity(0.2) - : Colors.black.withOpacity(0.05), - blurRadius: 10, - offset: const Offset(0, 2), - ), - ], - ), - child: Row( - children: [ - Container( - width: 42.w, - height: 42.w, - decoration: BoxDecoration( - color: iconColors.background, - borderRadius: BorderRadius.circular(21.r), - ), - child: Icon(iconColors.icon, color: iconColors.foreground), - ), - SizedBox(width: 12.w), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Lv.$viplv', - style: TextStyle( - fontSize: 14.sp, - fontWeight: FontWeight.w600, - color: textColor, - ), - ), - SizedBox(height: 4.h), - Text( - expiry != null - ? '${'validityPeriod'.tr}${_fmtDate(expiry)}' - : 'notBound'.tr, - style: TextStyle(fontSize: 12.sp, color: subColor), - ), - ], - ), - ), - Container( - padding: EdgeInsets.symmetric(horizontal: 10.w, vertical: 4.h), - decoration: BoxDecoration( - color: isDarkMode ? Colors.white10 : Colors.black12, - borderRadius: BorderRadius.circular(16.r), - ), - child: Text( - viplv > 0 ? 'enabled'.tr : 'disabled'.tr, - style: TextStyle(fontSize: 11.sp, color: subColor), - ), - ), - ], - ), - ); - } - - Widget _buildQuotaCard(UsageType type, bool isDarkMode) { - int total = 0; - int remain = 0; - if (User.isLoggedIn()) { - final u = User.instance; - if (type == UsageType.AI) { - total = u.aichattotalintegral; - remain = u.aichatintegral; - } else if (type == UsageType.Meet) { - total = u.meettotalintegral; - remain = u.meetintegral; - } else if (type == UsageType.Translation) { - total = u.tradetotalintegral; - remain = u.tradeintegral; - } - } - final progress = (total > 0) ? (remain / total).clamp(0.0, 1.0) : 0.0; - final iconColors = _iconColorForType(type, isDarkMode); - final subColor = isDarkMode ? Colors.white70 : Colors.grey[700]; - final textColor = isDarkMode ? Colors.white : Colors.black; - return Container( - padding: EdgeInsets.all(16.w), - decoration: BoxDecoration( - color: isDarkMode ? Colors.grey[900] : Colors.white, - borderRadius: BorderRadius.circular(12.r), - boxShadow: [ - BoxShadow( - color: isDarkMode - ? Colors.black.withOpacity(0.2) - : Colors.black.withOpacity(0.05), - blurRadius: 10, - offset: const Offset(0, 2), - ), - ], - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Container( - width: 36.w, - height: 36.w, - decoration: BoxDecoration( - color: iconColors.background, - borderRadius: BorderRadius.circular(18.r), - ), - child: Icon(iconColors.icon, color: iconColors.foreground), - ), - SizedBox(width: 8.w), - Text( - 'remainingQuota'.tr, - style: TextStyle( - fontSize: 16.sp, - fontWeight: FontWeight.w600, - color: textColor, - ), - ), - ], - ), - SizedBox(height: 12.h), - LinearProgressIndicator( - value: progress, - minHeight: 8.h, - backgroundColor: isDarkMode ? Colors.grey[800] : Colors.grey[300], - valueColor: AlwaysStoppedAnimation( - isDarkMode ? Colors.blue[300]! : Colors.blue[600]!), - ), - SizedBox(height: 8.h), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - '${'totalQuota'.tr}:$total', - style: TextStyle(fontSize: 12.sp, color: subColor), - ), - Text( - '${'remaining'.tr}:$remain', - style: TextStyle(fontSize: 12.sp, color: subColor), - ), - ], - ), - ], - ), - ); - } - Widget _buildGoodsGrid(List list, UsageType type, bool isDarkMode) { return GridView.builder( shrinkWrap: true, @@ -896,56 +633,6 @@ class GoodsvipView extends GetView { } } - Widget _buildScenesSection(bool isDarkMode) { - final textColor = isDarkMode ? Colors.white : Colors.black; - final subColor = isDarkMode ? Colors.white70 : Colors.grey[700]; - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'scene'.tr, - style: TextStyle( - fontSize: 16.sp, - fontWeight: FontWeight.w600, - color: textColor, - ), - ), - SizedBox(height: 10.h), - Wrap( - spacing: 12.w, - runSpacing: 12.h, - children: [ - _buildFeatureCard( - isDarkMode, - icon: Icons.smart_toy, - title: 'aiFunction'.tr, - lines: ['aiHeaderDesc1'.tr, 'aiHeaderDesc2'.tr], - colorSeed: Colors.teal, - ), - _buildFeatureCard( - isDarkMode, - icon: Icons.people_alt, - title: 'conferenceAssistant'.tr, - lines: ['meetingHeaderDesc1'.tr, 'meetingHeaderDesc2'.tr], - colorSeed: Colors.pink, - ), - _buildFeatureCard( - isDarkMode, - icon: Icons.translate, - title: 'simultaneousTranslation'.tr, - lines: ['transHeaderDesc1'.tr, 'transHeaderDesc2'.tr], - colorSeed: Colors.indigo, - ), - ], - ), - SizedBox(height: 12.h), - Text( - 'vipDisclaimer'.tr, - style: TextStyle(fontSize: 12.sp, color: subColor), - ), - ], - ); - } } class _IconColors { diff --git a/apps/client/lib/modules/home/views/widgets/calendar/calendar_task_list.dart b/apps/client/lib/modules/home/views/widgets/calendar/calendar_task_list.dart deleted file mode 100644 index e84f0073..00000000 --- a/apps/client/lib/modules/home/views/widgets/calendar/calendar_task_list.dart +++ /dev/null @@ -1,514 +0,0 @@ -import 'dart:math' as math; - -import 'package:flutter/material.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:get/get.dart'; - -import '../../../controllers/calendar_controller.dart'; -import 'calendar_event.dart'; -import 'calendar_tokens.dart'; -import 'kids_card.dart'; - -/// 选中日期的代办/花销两张表(固定头 + 内部滚动)。 -/// -/// 折叠(周):紧凑头 + **一条**横向滑动的小卡片(代办/花销混排,各自样式区分,不含描述); -/// 展开(月):代办表 + 花销表依次纵向排列,各自带小节标题与完整卡片(含描述)。 -/// -/// 注意:折叠态与下方翻译卡片区共享同一屏固定高度(不接受滚动,见 -/// home_view.dart 的 heightFactor 收放逻辑),所以折叠态必须保持单行紧凑, -/// 代办/花销的"两张表"效果只在展开态(有充足空间)才真正分栏铺开。 -class CalendarTaskList extends GetView { - const CalendarTaskList({super.key}); - - // 折叠态:整条(标签行+横向条)总高度,与原单表版本保持一致,避免撑爆固定布局 - static const double _collapsedStripHeight = 112; - // 折叠态:横向条高度 - static const double _collapsedRowHeight = 84; - - @override - Widget build(BuildContext context) { - final isDark = Theme.of(context).brightness == Brightness.dark; - return LayoutBuilder( - builder: (context, constraints) { - final double areaH = constraints.maxHeight; - final double stripH = areaH.isFinite - ? math.min(_collapsedStripHeight.h, areaH) - : _collapsedStripHeight.h; - return Obx(() { - final todos = controller.todosForSelectedDate; - final expenses = controller.expensesForSelectedDate; - final totalExpense = controller.totalExpenseForSelectedDate; - // progress: 1 折叠 → 0 展开。透明度随下拉距离连续变化,交界点 0.5: - // 折叠层在 [0.5,1] 由透明→不透明;越过 0.5 完全透明后,展开层在 [0.5,0] 由透明→不透明。上拉反向。 - final double progress = controller.dragProgress.value; - final double stripOpacity = ((progress - 0.5) / 0.5).clamp(0.0, 1.0); - final double listOpacity = ((0.5 - progress) / 0.5).clamp(0.0, 1.0); - return Stack( - children: [ - // 展开态纵向列表:铺满任务区,透明度随下拉(progress↓)增大 - if (listOpacity > 0.0) - Positioned.fill( - child: IgnorePointer( - ignoring: listOpacity < 1.0, // 仅完全展开时可交互 - child: Opacity( - opacity: listOpacity, - child: _buildExpanded( - todos, expenses, totalExpense, isDark), - ), - ), - ), - // 折叠态:代办/花销各一条横向紧凑条,透明度随下拉(progress↓)减小 - if (stripOpacity > 0.0) - Positioned( - top: 0, - left: 0, - right: 0, - height: stripH, - child: IgnorePointer( - ignoring: stripOpacity < 1.0, // 仅完全折叠时可交互 - child: Opacity( - opacity: stripOpacity, - child: _buildCollapsed( - todos, expenses, totalExpense, isDark), - ), - ), - ), - ], - ); - }); - }, - ); - } - - // ==================== 折叠态:单行横向紧凑(代办+花销混排,可点击筛选) ==================== - - /// 折叠态空间有限(与下方翻译卡片区共享固定高度),代办/花销合并成一条横向 - /// 滑动条:默认代办卡片在前、花销卡片在后。点击"代办"/"花销"标签只看该类别, - /// 点击日期([CalendarController.onDaySelected])重置为全部显示。 - Widget _buildCollapsed(List todos, - List expenses, double totalExpense, bool isDark) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, // 只占内容高,让外层 Flexible 把空白挤到底部 - children: [ - Padding( - padding: EdgeInsets.symmetric(horizontal: 16.w), - child: Obx(() { - final filter = controller.categoryFilter.value; - return Wrap( - crossAxisAlignment: WrapCrossAlignment.center, - children: [ - Text('${controller.selectedDateLabel} · ', - style: AppKidsTextStyles.caption(isDark)), - _buildFilterLabel( - label: 'calTodoCount'.trParams({'count': '${todos.length}'}), - active: filter == CalendarEventCategory.todo, - isDark: isDark, - onTap: () => - controller.setCategoryFilter(CalendarEventCategory.todo), - ), - if (expenses.isNotEmpty) ...[ - Text(' · ', style: AppKidsTextStyles.caption(isDark)), - _buildFilterLabel( - label: - '${'calExpenseCount'.trParams({'count': '${expenses.length}'})}(¥${totalExpense.toStringAsFixed(0)})', - active: filter == CalendarEventCategory.expense, - isDark: isDark, - onTap: () => controller - .setCategoryFilter(CalendarEventCategory.expense), - ), - ], - ], - ); - }), - ), - SizedBox(height: AppKidsDimens.space8), - Flexible( - child: SizedBox( - height: _collapsedRowHeight.h, - width: double.infinity, - child: Obx(() { - final visible = controller.visibleEventsForSelectedDate; - if (visible.isEmpty) { - return Center(child: _emptyCard(isDark)); - } - return ListView.separated( - scrollDirection: Axis.horizontal, - physics: const BouncingScrollPhysics(), - padding: EdgeInsets.fromLTRB(16.w, 9.h, 16.w, 9.h), - itemCount: visible.length, - separatorBuilder: (_, __) => - SizedBox(width: AppKidsDimens.space12), - itemBuilder: (_, i) { - final event = visible[i]; - return event.category == CalendarEventCategory.todo - ? _buildCompactEventCard(event, isDark) - : _buildCompactExpenseCard(event, isDark); - }, - ); - }), - ), - ), - ], - ); - } - - /// 折叠态标签行里可点击的"代办"/"花销"文字:命中态加粗+主题色+下划线。 - Widget _buildFilterLabel({ - required String label, - required bool active, - required bool isDark, - required VoidCallback onTap, - }) { - return GestureDetector( - onTap: onTap, - behavior: HitTestBehavior.opaque, - child: Text( - label, - style: AppKidsTextStyles.caption(isDark).copyWith( - fontWeight: active ? FontWeight.w800 : FontWeight.w500, - color: active ? AppKidsColors.brandPrimary : null, - decoration: active ? TextDecoration.underline : null, - ), - ), - ); - } - - // ==================== 展开态:纵向完整(代办表 + 花销表) ==================== - - Widget _buildExpanded(List todos, - List expenses, double totalExpense, bool isDark) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: EdgeInsets.symmetric(horizontal: 16.w), - child: Text( - controller.selectedDateLabel, - style: AppKidsTextStyles.subtitle(isDark).copyWith( - fontWeight: FontWeight.w800, - ), - ), - ), - SizedBox(height: AppKidsDimens.space12), - Expanded( - child: ListView( - padding: EdgeInsets.symmetric( - horizontal: 16.w, vertical: AppKidsDimens.space12), - physics: const BouncingScrollPhysics(), - children: [ - _sectionHeader('calTodos'.tr, 'calTodoCount'.trParams({'count': '${todos.length}'}), isDark), - SizedBox(height: AppKidsDimens.space12), - if (todos.isEmpty) - _emptyCard(isDark) - else - ...todos.expand((e) => [ - _buildEventCard(e, isDark), - SizedBox(height: AppKidsDimens.space12), - ]), - SizedBox(height: AppKidsDimens.space8), - _sectionHeader( - 'calExpenses'.tr, - expenses.isEmpty - ? 'calExpenseCount'.trParams({'count': '0'}) - : '${'calExpenseCount'.trParams({'count': '${expenses.length}'})} · ${'calTotalAmount'.tr} ¥${totalExpense.toStringAsFixed(0)}', - isDark, - ), - SizedBox(height: AppKidsDimens.space12), - if (expenses.isEmpty) - _emptyCard(isDark) - else - ...expenses.expand((e) => [ - _buildExpenseEventCard(e, isDark), - SizedBox(height: AppKidsDimens.space12), - ]), - ], - ), - ), - ], - ); - } - - Widget _sectionHeader(String title, String countText, bool isDark) { - return Row( - children: [ - Text( - title, - style: AppKidsTextStyles.body(isDark).copyWith( - fontWeight: FontWeight.w700, - ), - ), - SizedBox(width: AppKidsDimens.space8), - Text(countText, style: AppKidsTextStyles.caption(isDark)), - ], - ); - } - - // ==================== 卡片 ==================== - - Widget _emptyCard(bool isDark, {bool compact = false}) { - return KidsCard( - padding: EdgeInsets.symmetric( - horizontal: AppKidsDimens.space20, - vertical: compact ? AppKidsDimens.space12 : AppKidsDimens.space20, - ), - child: Text( - compact ? 'calNoRecords'.tr : 'calNoRecordsDay'.tr, - style: AppKidsTextStyles.bodySmall(isDark).copyWith( - color: AppKidsColors.textSub(isDark), - ), - ), - ); - } - - /// 折叠态紧凑卡片:固定宽度、不含描述(标题 + 时间·地点)。 - Widget _buildCompactEventCard(CalendarEvent event, bool isDark) { - final isCompleted = event.taskStatus == 2; - final accent = isCompleted ? const Color(0xFF9CA3AF) : event.color; - final textColor = isCompleted - ? const Color(0xFF6B7280) - : (isDark ? Colors.white : Colors.black87); - return SizedBox( - width: 190.w, - child: KidsCard( - elevation: KidsElevation.sm, // 较小阴影,避免在矮条里被上下裁切 - borderRadius: BorderRadius.circular(AppKidsDimens.radiusMd), // 折叠态圆角更小 - padding: EdgeInsets.all(AppKidsDimens.space8), - child: Row( - children: [ - // 左侧色条 - Container( - width: 4.w, - height: 28.h, - decoration: BoxDecoration( - color: accent, - borderRadius: BorderRadius.circular(AppKidsDimens.radiusPill), - ), - ), - SizedBox(width: AppKidsDimens.space8), - Expanded( - child: Column( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - event.title, - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: AppKidsTextStyles.bodySmall(isDark).copyWith( - fontWeight: FontWeight.w700, - color: textColor, - ), - ), - SizedBox(height: 4.h), - Text( - '${event.timeText} · ${event.location}', - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: AppKidsTextStyles.caption(isDark).copyWith( - color: textColor.withValues(alpha: 0.75), - ), - ), - ], - ), - ), - ], - ), - ), - ); - } - - /// 折叠态紧凑花销卡片:固定宽度,标题 + 金额。 - Widget _buildCompactExpenseCard(CalendarEvent event, bool isDark) { - final textColor = isDark ? Colors.white : Colors.black87; - return SizedBox( - width: 190.w, - child: KidsCard( - elevation: KidsElevation.sm, - borderRadius: BorderRadius.circular(AppKidsDimens.radiusMd), - padding: EdgeInsets.all(AppKidsDimens.space8), - child: Row( - children: [ - Container( - width: 4.w, - height: 28.h, - decoration: BoxDecoration( - color: event.color, - borderRadius: BorderRadius.circular(AppKidsDimens.radiusPill), - ), - ), - SizedBox(width: AppKidsDimens.space8), - Expanded( - child: Column( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - event.title, - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: AppKidsTextStyles.bodySmall(isDark).copyWith( - fontWeight: FontWeight.w700, - color: textColor, - ), - ), - SizedBox(height: 4.h), - Text( - '-¥${(event.amount ?? 0).toStringAsFixed(0)}', - maxLines: 1, - style: AppKidsTextStyles.caption(isDark).copyWith( - color: AppKidsColors.statusError, - fontWeight: FontWeight.w700, - ), - ), - ], - ), - ), - ], - ), - ), - ); - } - - /// 展开态完整卡片:左色条 + 标题 + 标签 + 时间·地点 + 描述。 - Widget _buildEventCard(CalendarEvent event, bool isDark) { - final isCompleted = event.taskStatus == 2; - final cardAccentColor = isCompleted ? const Color(0xFF9CA3AF) : event.color; - final cardTextColor = isCompleted - ? const Color(0xFF6B7280) - : (isDark ? Colors.white : Colors.black87); - return KidsCard( - // 事件点击暂不跳转(我们尚无详情页) - padding: EdgeInsets.all(AppKidsDimens.space16), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // 左侧色条(已完成灰显) - Container( - width: 4.w, - height: 56.h, - decoration: BoxDecoration( - color: cardAccentColor, - borderRadius: BorderRadius.circular(AppKidsDimens.radiusPill), - ), - ), - SizedBox(width: AppKidsDimens.space12), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row(children: [ - Expanded( - child: Text( - event.title, - style: AppKidsTextStyles.body(isDark).copyWith( - fontWeight: FontWeight.w700, - color: cardTextColor, - ), - ), - ), - // 标签气泡(已完成灰显) - Container( - padding: EdgeInsets.symmetric( - horizontal: AppKidsDimens.space8, - vertical: 4.h, - ), - decoration: BoxDecoration( - color: cardAccentColor.withValues(alpha: 0.12), - borderRadius: - BorderRadius.circular(AppKidsDimens.radiusPill), - ), - child: Text( - event.tag, - style: AppKidsTextStyles.caption(isDark).copyWith( - color: cardAccentColor, - fontWeight: FontWeight.w700, - ), - ), - ), - ]), - SizedBox(height: 6.h), - Text( - '${event.timeText} · ${event.location}', - style: AppKidsTextStyles.caption(isDark).copyWith( - color: cardTextColor.withValues(alpha: 0.75), - ), - ), - SizedBox(height: 6.h), - Text( - event.description, - style: AppKidsTextStyles.bodySmall(isDark).copyWith( - color: cardTextColor.withValues(alpha: 0.85), - ), - ), - ], - ), - ), - ], - ), - ); - } - - /// 展开态完整花销卡片:左色条 + 标题 + 金额 + 时间·地点 + 描述。 - Widget _buildExpenseEventCard(CalendarEvent event, bool isDark) { - final cardTextColor = isDark ? Colors.white : Colors.black87; - return KidsCard( - padding: EdgeInsets.all(AppKidsDimens.space16), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - width: 4.w, - height: 56.h, - decoration: BoxDecoration( - color: event.color, - borderRadius: BorderRadius.circular(AppKidsDimens.radiusPill), - ), - ), - SizedBox(width: AppKidsDimens.space12), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row(children: [ - Expanded( - child: Text( - event.title, - style: AppKidsTextStyles.body(isDark).copyWith( - fontWeight: FontWeight.w700, - color: cardTextColor, - ), - ), - ), - Text( - '-¥${(event.amount ?? 0).toStringAsFixed(0)}', - style: AppKidsTextStyles.body(isDark).copyWith( - color: AppKidsColors.statusError, - fontWeight: FontWeight.w800, - ), - ), - ]), - SizedBox(height: 6.h), - Text( - '${event.timeText} · ${event.location}', - style: AppKidsTextStyles.caption(isDark).copyWith( - color: cardTextColor.withValues(alpha: 0.75), - ), - ), - SizedBox(height: 6.h), - Text( - event.description, - style: AppKidsTextStyles.bodySmall(isDark).copyWith( - color: cardTextColor.withValues(alpha: 0.85), - ), - ), - ], - ), - ), - ], - ), - ); - } -} diff --git a/apps/client/lib/modules/home/views/widgets/siri_orb_view.dart b/apps/client/lib/modules/home/views/widgets/siri_orb_view.dart deleted file mode 100644 index 5d23b01a..00000000 --- a/apps/client/lib/modules/home/views/widgets/siri_orb_view.dart +++ /dev/null @@ -1,437 +0,0 @@ -import 'dart:math' as math; -import 'dart:typed_data'; -import 'dart:ui' show Vertices, VertexMode; - -import 'package:flutter/material.dart'; -import 'package:flutter/scheduler.dart'; - -/// 仿 Apple Siri 的「3D 玻璃球」动效(从 Android SiriOrbView.kt 移植)。 -/// -/// 纯 CustomPaint 绘制,无图片资源:球面波浪纬带(贴在球面上、整球持续翻滚、 -/// 透视投影、菲涅耳边缘提亮、ADD 加法混合)+ 玻璃壳光效(偏心球底渐变、彩色轮辋光、 -/// 边缘压暗、上半球反光、左上镜面亮斑、整圈玻璃亮边、中心炽白光核)。 -/// -/// 首页常驻使用:搅动度固定为 0(球体缓慢自然翻滚),不区分状态,仅在挂载时动画。 -/// 性能:热路径零分配(复用 Path/Paint/缓冲)、与尺寸无关的 shader/三角值只算一次、 -/// 外层 RepaintBoundary 隔离重绘。 -class SiriOrbView extends StatefulWidget { - /// 组件方形边长;球体几乎填满方框。 - final double size; - - const SiriOrbView({Key? key, this.size = 96}) : super(key: key); - - @override - State createState() => _SiriOrbViewState(); -} - -class _SiriOrbViewState extends State - with SingleTickerProviderStateMixin { - late final Ticker _ticker; - // 累计时间(秒),驱动翻滚/波动;作为画笔的 repaint 源。 - final ValueNotifier _t = ValueNotifier(0); - // 只创建一次,避免父级 rebuild 丢失内部缓存。 - late final _SiriOrbPainter _painter = _SiriOrbPainter(_t); - int _lastMicros = -1; - - @override - void initState() { - super.initState(); - _ticker = createTicker(_onTick)..start(); - } - - void _onTick(Duration elapsed) { - final int now = elapsed.inMicroseconds; // int 属性,无 Duration 分配 - final double dt = - _lastMicros < 0 ? 0.016 : ((now - _lastMicros) / 1e6).clamp(0.0, 0.05); - _lastMicros = now; - // 搅动度=0 → 时间按 1x 流动(球体持续缓慢翻滚)。 - _t.value = _t.value + dt; - } - - @override - void dispose() { - _ticker.dispose(); - _t.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - // RepaintBoundary:球每帧重绘不牵连整页;willChange 避免无谓栅格缓存。 - return RepaintBoundary( - child: SizedBox( - width: widget.size, - height: widget.size, - child: CustomPaint( - painter: _painter, - size: Size(widget.size, widget.size), - willChange: true, - ), - ), - ); - } -} - -/// 基础时间循环(秒):纬带翻滚/波动的基准周期。 -const double _kLoopSeconds = 15.0; - -/// 角速度(= 2π / 循环周期):预算,避免每帧重算。 -const double _kOmega = 2.0 * math.pi / _kLoopSeconds; - -/// 纬带环向采样点数。 -const int _kBandPoints = 72; - -/// 渐变 shader 的基准半径(绘制时按 canvas 缩放,与 View 尺寸无关)。 -const double _kNorm = 100.0; - -/// 透视投影:视点距离 + 整体收缩系数(0.91 收在玻璃壳内)。 -const double _kViewDist = 3.2; -const double _kPersp = 0.91 * 3.2; - -/// 一条球面波浪纬带的参数(与 Kotlin/HTML 原型一致)。 -class _Band { - final int r, g, b; - final double th0; // 中心纬度 - final double amp; // 纬度波幅 - final int waves; // 波瓣数 - final double halfWidth; // 半带宽 - final double waveSpeed; // 波形流速 - final double tumbleX, tumbleY; // 绕 X/Y 轴翻滚速度 - final double phaseX, phaseY, wavePhase; - final double weight; // 不透明度权重 - - const _Band( - this.r, - this.g, - this.b, - this.th0, - this.amp, - this.waves, - this.halfWidth, - this.waveSpeed, - this.tumbleX, - this.tumbleY, - this.phaseX, - this.phaseY, - this.wavePhase, - this.weight, - ); -} - -/// 四条纬带:粉(主角,宽带)/ 青 / 蓝 / 青绿(细带点缀)。 -const List<_Band> _kBands = <_Band>[ - _Band(255, 45, 85, 0.15, 0.45, 2, 0.30, 1.3, 0.31, 0.53, 0.0, 1.1, 0.0, 1.2), - _Band( - 0, 229, 255, -0.20, 0.50, 3, 0.24, -1.7, -0.41, 0.67, 1.7, 0.4, 2.1, 1.0), - _Band(0, 122, 255, 0.45, 0.40, 2, 0.28, 1.0, 0.23, -0.45, 3.0, 2.2, 4.2, 1.0), - _Band( - 52, 225, 150, -0.50, 0.35, 4, 0.16, 2.0, 0.51, 0.37, 4.4, 3.3, 1.0, 0.6), -]; - -// ---- 尺寸无关的径向渐变(shader 以原点+NORM 创建,绘制时缩放) ---- - -/// 玻璃球底:左上受光的偏心渐变 -const RadialGradient _baseGradient = RadialGradient( - colors: [Color(0xFF5252A4), Color(0xFF2A2A5E), Color(0xFF0D0D26)], - stops: [0.0, 0.45, 1.0], -); - -/// 中心炽白光核(ADD) -const RadialGradient _coreGradient = RadialGradient( - colors: [Color(0x66FFFFFF), Color(0x26FFFFFF), Color(0x00FFFFFF)], - stops: [0.0, 0.30, 1.0], -); - -/// 边缘压暗(菲涅耳) -const RadialGradient _vignetteGradient = RadialGradient( - colors: [Color(0x00000000), Color(0x2902021E), Color(0x57020223)], - stops: [0.75, 0.92, 1.0], -); - -/// 上半球弧形反光 -const RadialGradient _domeGradient = RadialGradient( - colors: [Color(0x33FFFFFF), Color(0x14FFFFFF), Color(0x00FFFFFF)], - stops: [0.0, 0.7, 1.0], -); - -/// 左上镜面亮斑 -const RadialGradient _specularGradient = RadialGradient( - colors: [Color(0x73FFFFFF), Color(0x00FFFFFF)], -); - -/// 彩色轮辋光(顶绿→右上青绿→右下蓝→底蓝紫→左下品红→左上红) -const SweepGradient _rimGradient = SweepGradient( - startAngle: -math.pi / 2, - endAngle: 3 * math.pi / 2, - colors: [ - Color(0xBF1ED296), - Color(0xA832E1C3), - Color(0x963C8CFF), - Color(0xA85055EB), - Color(0xBFD71E6E), - Color(0xBFEB3755), - Color(0xBF1ED296), - ], - stops: [0.0, 0.16, 0.32, 0.50, 0.68, 0.84, 1.0], -); - -/// 整圈玻璃亮边(左上最亮) -const SweepGradient _rimHighlightGradient = SweepGradient( - startAngle: -math.pi / 2, - endAngle: 3 * math.pi / 2, - colors: [ - Color(0x99FFFFFF), - Color(0x47FFFFFF), - Color(0x33FFFFFF), - Color(0x73FFFFFF), - Color(0xD9FFFFFF), - Color(0x99FFFFFF), - ], - stops: [0.0, 0.25, 0.50, 0.75, 0.875, 1.0], -); - -class _SiriOrbPainter extends CustomPainter { - final ValueNotifier t; - - // ---- 复用缓冲与对象(热路径零分配) ---- - final Float64List _edgeA = Float64List(_kBandPoints * 3); - final Float64List _edgeB = Float64List(_kBandPoints * 3); - // drawVertices 批量绘制:所有纬带四边形顶点累积到复用缓冲,一帧只提交一次。 - final Paint _bandVertsPaint = Paint() - ..blendMode = BlendMode.plus // 加法合成(与原逐片 ADD 一致) - ..color = const Color(0xFFFFFFFF) // 配合 modulate:白 × 顶点色 = 顶点色 - ..isAntiAlias = true; - static final int _kMaxQuads = _kBands.length * (_kBandPoints - 1); - final Float32List _posBuf = Float32List(_kMaxQuads * 6 * 2); - final Int32List _colBuf = Int32List(_kMaxQuads * 6); - int _vCount = 0; - - // 环向采样角与其三角值:与时间无关、全类共享,只算一次。 - static final Float64List _sArr = _ring((double s) => s); - static final Float64List _cosS = _ring((double s) => math.cos(s)); - static final Float64List _sinS = _ring((double s) => math.sin(s)); - - static Float64List _ring(double Function(double s) f) { - final Float64List out = Float64List(_kBandPoints); - for (int i = 0; i < _kBandPoints; i++) { - out[i] = f(i * 2.0 * math.pi / (_kBandPoints - 1)); - } - return out; - } - - // 尺寸无关的光斑画笔(shader 只建一次)。 - Paint? _baseP, _coreP, _vignetteP, _domeP, _specularP; - - // 尺寸相关缓存(rs 变化时才重建)。 - double _cachedRs = -1; - late Path _clipPath; - late Paint _rimP; - late Paint _rimHiP; - - _SiriOrbPainter(this.t) : super(repaint: t); - - void _ensureBlobPaints() { - if (_baseP != null) return; - final Rect r = Rect.fromCircle(center: Offset.zero, radius: _kNorm); - _baseP = Paint()..shader = _baseGradient.createShader(r); - _coreP = Paint() - ..shader = _coreGradient.createShader(r) - ..blendMode = BlendMode.plus; - _vignetteP = Paint()..shader = _vignetteGradient.createShader(r); - _domeP = Paint()..shader = _domeGradient.createShader(r); - _specularP = Paint()..shader = _specularGradient.createShader(r); - } - - void _ensureSizeCache(double cx, double cy, double rs) { - if (_cachedRs == rs) return; - _cachedRs = rs; - _clipPath = Path() - ..addOval(Rect.fromCircle(center: Offset(cx, cy), radius: rs)); - _rimP = Paint() - ..style = PaintingStyle.stroke - ..strokeWidth = rs * 0.13 - ..blendMode = BlendMode.plus - ..maskFilter = MaskFilter.blur(BlurStyle.normal, rs * 0.05) - ..shader = _rimGradient.createShader( - Rect.fromCircle(center: Offset(cx, cy), radius: rs * 0.93)); - _rimHiP = Paint() - ..style = PaintingStyle.stroke - ..strokeWidth = rs * 0.035 - ..shader = _rimHighlightGradient.createShader( - Rect.fromCircle(center: Offset(cx, cy), radius: rs * 0.985)); - } - - @override - void paint(Canvas canvas, Size size) { - final double cx = size.width / 2; - final double cy = size.height / 2; - // 球体几乎填满方框,只留极小余量给玻璃亮边描边。 - final double rs = math.min(size.width, size.height) / 2 * 0.96; - if (rs <= 0) return; - - _ensureBlobPaints(); - _ensureSizeCache(cx, cy, rs); - - final double tt = t.value * _kOmega; - - // 裁到球内绘制内容(等价于离屏层 + 圆外 CLEAR)。 - canvas.save(); - canvas.clipPath(_clipPath); - - // 球底渐变中心偏向左上光源 - _blob(canvas, _baseP!, cx - rs * 0.30, cy - rs * 0.34, rs * 1.7, rs * 1.7); - - // 球面纬带:累积全部四边形顶点,单次 drawVertices 批量绘制(~280 drawPath → 1 次) - _vCount = 0; - for (final _Band band in _kBands) { - _appendBand(band, tt, cx, cy, rs); - } - if (_vCount > 0) { - final Vertices v = Vertices.raw( - VertexMode.triangles, - Float32List.view(_posBuf.buffer, 0, _vCount * 2), - colors: Int32List.view(_colBuf.buffer, 0, _vCount), - ); - // modulate × 白 = 顶点色;paint.blendMode=plus → 加法合成 - canvas.drawVertices(v, BlendMode.modulate, _bandVertsPaint); - } - - // 中心炽白光核(ADD;搅动度=0 → 固定 0.25R) - _blob(canvas, _coreP!, cx, cy, rs * 0.25, rs * 0.25); - - // ---- 玻璃球壳 ---- - canvas.drawCircle(Offset(cx, cy), rs * 0.93, _rimP); // 彩色轮辋光 - _blob(canvas, _vignetteP!, cx, cy, rs, rs); // 边缘压暗 - _blob(canvas, _domeP!, cx, cy - rs * 0.52, rs * 0.72, rs * 0.324); // 上半球反光 - _blob(canvas, _specularP!, cx - rs * 0.36, cy - rs * 0.40, rs * 0.24, - rs * 0.24); // 左上镜面亮斑 - canvas.drawCircle(Offset(cx, cy), rs * 0.985, _rimHiP); // 整圈玻璃亮边 - - canvas.restore(); - } - - /// 累积一条球面波浪纬带的四边形顶点到复用缓冲(不直接绘制)。 - void _appendBand(_Band band, double t, double cx, double cy, double rs) { - const int n = _kBandPoints; - final double amp = band.amp; // 搅动度=0,无额外放大 - final double thx = band.tumbleX * t + band.phaseX; - final double thy = band.tumbleY * t + band.phaseY; - final double cosX = math.cos(thx); - final double sinX = math.sin(thx); - final double cosY = math.cos(thy); - final double sinY = math.sin(thy); - // 半带宽为常量:用角和公式 cos/sin(th±hw) 由 cos(th)/sin(th) 推出,每点省 2 次三角。 - final double cosHw = math.cos(band.halfWidth); - final double sinHw = math.sin(band.halfWidth); - // 循环不变量外提:与采样点 i 无关的项只算一次。 - final int waves = band.waves; - final double th0 = band.th0; - final double wp = band.waveSpeed * t + band.wavePhase; - - // 生成两条边缘曲线(纬度 θ(s)±hw)的球面顶点(cos(s)/sin(s) 用预计算值) - for (int i = 0; i < n; i++) { - final double th = th0 + amp * math.sin(waves * _sArr[i] + wp); - final double st = math.sin(th); - // cos(th)=+√(1-sin²):各带 |th|<π/2(含满搅动 <1.06rad),cos(th) 恒为正, - // 用 sqrt(多为单条硬件指令)替代更贵的 cos。 - final double ct = math.sqrt(1.0 - st * st); - final double cs = _cosS[i]; - final double ss = _sinS[i]; - // edgeA:lat = th - hw → cos=ct·cosHw+st·sinHw,sin=st·cosHw-ct·sinHw - double cl = ct * cosHw + st * sinHw; - double sl = st * cosHw - ct * sinHw; - _storeRotated(_edgeA, i, cl * cs, cl * ss, sl, cosX, sinX, cosY, sinY); - // edgeB:lat = th + hw - cl = ct * cosHw - st * sinHw; - sl = st * cosHw + ct * sinHw; - _storeRotated(_edgeB, i, cl * cs, cl * ss, sl, cosX, sinX, cosY, sinY); - } - - final int br = band.r; - final int bg = band.g; - final int bb = band.b; - final double weight = band.weight; - - // ADD 加法混合可交换(且逐步 clamp 等价于总和 clamp):背/前半球合并为单遍, - // 每段只算一次、按 zc 即时取亮度系数,叠加结果与两遍完全一致。 - for (int i = 0; i < n - 1; i++) { - final int i0 = i * 3; - final int i1 = (i + 1) * 3; - final double p0z = _edgeA[i0 + 2]; - final double p1z = _edgeB[i0 + 2]; - final double p2z = _edgeB[i1 + 2]; - final double p3z = _edgeA[i1 + 2]; - final double zc = (p0z + p1z + p2z + p3z) / 4; - final double fb = zc >= 0 ? 1.0 : 0.22; // 前半球亮、背半球暗(×0.22) - - // 球面法线≈径向:|zc| 小 = 贴近轮廓 → 亮(菲涅耳)。clamp 防浮点越界 NaN。 - final double edge = (1 - zc.abs()).clamp(0.0, 1.0); - final double alpha = (0.30 + 0.50 * edge * math.sqrt(edge)) * fb * weight; - if (alpha < 0.015) continue; - - final int aByte = (alpha * 255).round().clamp(0, 255); - final int col = (aByte << 24) | (br << 16) | (bg << 8) | bb; // ARGB - - // 透视投影:近大远小 - final double f0 = _kPersp / (_kViewDist - p0z); - final double f1 = _kPersp / (_kViewDist - p1z); - final double f2 = _kPersp / (_kViewDist - p2z); - final double f3 = _kPersp / (_kViewDist - p3z); - final double ax0 = cx + _edgeA[i0] * f0 * rs; - final double ay0 = cy + _edgeA[i0 + 1] * f0 * rs; - final double bx0 = cx + _edgeB[i0] * f1 * rs; - final double by0 = cy + _edgeB[i0 + 1] * f1 * rs; - final double bx1 = cx + _edgeB[i1] * f2 * rs; - final double by1 = cy + _edgeB[i1 + 1] * f2 * rs; - final double ax1 = cx + _edgeA[i1] * f3 * rs; - final double ay1 = cy + _edgeA[i1 + 1] * f3 * rs; - - // 四边形 A0,B0,B1,A1 → 两个三角形 (A0,B0,B1)(A0,B1,A1),全顶点同色(平涂) - final int v = _vCount; - final int p = v * 2; - _posBuf[p] = ax0; - _posBuf[p + 1] = ay0; - _posBuf[p + 2] = bx0; - _posBuf[p + 3] = by0; - _posBuf[p + 4] = bx1; - _posBuf[p + 5] = by1; - _posBuf[p + 6] = ax0; - _posBuf[p + 7] = ay0; - _posBuf[p + 8] = bx1; - _posBuf[p + 9] = by1; - _posBuf[p + 10] = ax1; - _posBuf[p + 11] = ay1; - _colBuf[v] = col; - _colBuf[v + 1] = col; - _colBuf[v + 2] = col; - _colBuf[v + 3] = col; - _colBuf[v + 4] = col; - _colBuf[v + 5] = col; - _vCount = v + 6; - } - } - - /// 把 (x,y,z) 经 Rx 后 Ry 旋转,存入顶点缓冲第 i 个槽位。 - void _storeRotated(Float64List dst, int i, double x, double y, double z, - double cosX, double sinX, double cosY, double sinY) { - final double y1 = y * cosX - z * sinX; - final double z1 = y * sinX + z * cosX; - final int o = i * 3; - dst[o] = x * cosY + z1 * sinY; - dst[o + 1] = y1; - dst[o + 2] = -x * sinY + z1 * cosY; - } - - /// 把以原点为圆心、NORM 为半径的渐变圆,缩放到 (rx,ry) 后画到 (x,y)。 - void _blob( - Canvas canvas, Paint paint, double x, double y, double rx, double ry) { - canvas.save(); - canvas.translate(x, y); - canvas.scale(rx / _kNorm, ry / _kNorm); - canvas.drawCircle(Offset.zero, _kNorm, paint); - canvas.restore(); - } - - @override - bool shouldRepaint(covariant _SiriOrbPainter oldDelegate) => false; -} diff --git a/apps/client/lib/modules/login/controllers/appleLogin.dart b/apps/client/lib/modules/login/controllers/appleLogin.dart index 1dc85d42..ae717293 100644 --- a/apps/client/lib/modules/login/controllers/appleLogin.dart +++ b/apps/client/lib/modules/login/controllers/appleLogin.dart @@ -1,5 +1,4 @@ import 'dart:convert'; -import 'dart:io'; import 'dart:math'; import 'package:flutter/foundation.dart'; import 'package:sign_in_with_apple/sign_in_with_apple.dart'; diff --git a/apps/client/lib/modules/login/controllers/googleLogin.dart b/apps/client/lib/modules/login/controllers/googleLogin.dart index cd6630bd..241e7838 100644 --- a/apps/client/lib/modules/login/controllers/googleLogin.dart +++ b/apps/client/lib/modules/login/controllers/googleLogin.dart @@ -1,6 +1,5 @@ import 'package:firebase_auth/firebase_auth.dart'; import 'package:google_sign_in/google_sign_in.dart'; -import 'package:get/get.dart'; import '../../../core/utils/logger.dart'; class Google { diff --git a/apps/client/lib/modules/login/controllers/weixinLogin.dart b/apps/client/lib/modules/login/controllers/weixinLogin.dart index 89345511..fa14a1a7 100644 --- a/apps/client/lib/modules/login/controllers/weixinLogin.dart +++ b/apps/client/lib/modules/login/controllers/weixinLogin.dart @@ -143,30 +143,6 @@ class FlWX { ); } - /// 获取微信 用户token - String _getTokenUrl(String code) { - print("_getTokenUrl 数据获取${_appId},${_appSecret}"); - assert( - _appId != null && - _appId!.isNotEmpty && - _appSecret != null && - _appSecret!.isNotEmpty, - ); - return 'https://api.weixin.qq.com/sns/oauth2/access_token?appid=$_appId&secret=$_appSecret&code=$code&grant_type=authorization_code'; - } - - /// 获取微信 用户token - String _getRefreshTokenUrl(String code) { - print("_getRefreshTokenUrl 数据获取${_appId},${_appSecret}"); - assert( - _appId != null && - _appId!.isNotEmpty && - _appSecret != null && - _appSecret!.isNotEmpty, - ); - return 'https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=$_appId&grant_type=refresh_token&&refresh_token=$refresh_token'; - } - // GET请求示例 Future> fetchData(String Url) async { try { @@ -217,16 +193,6 @@ class FlWX { } } - /// 获取微信 用户信息 - String _getUserInfoUrl({required String openId, required String token}) => - 'https://api.weixin.qq.com/sns/userinfo?access_token=$token&openid=$openId'; - //检验授权凭证(access_token)是否有效 - String _getUserTokenEffertive({ - required String openId, - required String token, - }) => - 'https://api.weixin.qq.com/sns/auth?access_token=$token&openid=$openId'; - /// 是否安装微信 Future get isInstalled async { assert(_isRegister, '请先调用 FlWX().register()'); diff --git a/apps/client/lib/modules/meeting/controllers/meeting_record_controller.dart b/apps/client/lib/modules/meeting/controllers/meeting_record_controller.dart index 24d27934..3c113d88 100644 --- a/apps/client/lib/modules/meeting/controllers/meeting_record_controller.dart +++ b/apps/client/lib/modules/meeting/controllers/meeting_record_controller.dart @@ -34,7 +34,6 @@ class MeetingRecordController extends GetxController with GetTickerProviderStateMixin, WidgetsBindingObserver { static const int _backgroundRecordingNotificationId = 91001; static const Duration _stopRecordTimeout = Duration(seconds: 12); - static const Duration _fileOpTimeout = Duration(seconds: 8); static FlutterLocalNotificationsPlugin? _localNotificationsPlugin; final NativePlugin _nativePlugin = NativePlugin(); diff --git a/apps/client/lib/modules/ota_upgrade/model/ota_upgrade_model.dart b/apps/client/lib/modules/ota_upgrade/model/ota_upgrade_model.dart deleted file mode 100644 index d07dbe38..00000000 --- a/apps/client/lib/modules/ota_upgrade/model/ota_upgrade_model.dart +++ /dev/null @@ -1,62 +0,0 @@ -class OtaConfigResp { - // 单例实例 - static OtaConfigResp? _instance; - - // 单例访问器(增加空安全保护) - static OtaConfigResp get instance { - if (_instance == null) { - throw Exception("User must be initialized first"); - } - return _instance!; - } - - // 最终属性(不可变) - final String? id; - final int? factory; - final int? devicetype; - final String? devicename; - final String? systemversion; - final String? updatepackageaddress; - final String? updatedescription; - // 私有构造函数 - OtaConfigResp._({ - this.id, - this.factory, - this.devicetype, - this.devicename, - this.systemversion, - this.updatepackageaddress, - this.updatedescription, - }); - - factory OtaConfigResp.fromJson(Map json) { - print("数据获取fronTokenJson${json}"); - // 修复1:安全获取嵌套的 user 字段 - final infoData = json['product'] as Map?; // 允许空值 - - // 更新单例实例 - return _instance = OtaConfigResp._( - id: (infoData?['id'] as String?) ?? '', - factory: (infoData?['factoryid'] as int?) ?? 0, - devicetype: (infoData?['devicetype'] as int?) ?? 0, - devicename: (infoData?['devicename'] as String?) ?? '', - systemversion: (infoData?['systemversion'] as String?) ?? '', - updatepackageaddress: - (infoData?['updatepackageaddress'] as String?) ?? '', - updatedescription: (infoData?['updatedescription'] as String?) ?? '', - ); - } - - // 完整的JSON序列化 - Map toJson() => { - 'user': { - 'id': instance.id, - 'factory': instance.factory, - 'devicetype': instance.devicetype, - 'devicename': instance.devicename, - 'systemversion': instance.systemversion, - 'updatepackageaddress': instance.updatepackageaddress, - 'updatedescription': instance.updatedescription, - } - }; -} diff --git a/apps/client/lib/modules/ota_upgrade/views/ota_upgrade_popup_view.dart b/apps/client/lib/modules/ota_upgrade/views/ota_upgrade_popup_view.dart deleted file mode 100644 index a82f5ccb..00000000 --- a/apps/client/lib/modules/ota_upgrade/views/ota_upgrade_popup_view.dart +++ /dev/null @@ -1,118 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:get/get.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:logger/web.dart'; -import '/routes/app_routes.dart'; - -/// OTA UI服务 -/// 负责处理所有与用户界面交互相关的功能 -class OtaUpgradePopUp { - /// 显示更新确认对话框 - /// [latestVersion] 最新版本号 - /// [onConfirm] 确认更新的回调函数 - void showUpdateDialog(String latestVersion, VoidCallback onConfirm) { - Logger().d('显示更新对话框'); - Get.dialog( - AlertDialog( - title: Text('otaNewVersionFoundWithVersion'.trParams({'version': latestVersion})), - content: Text('otaConfirmUpdateNow'.tr), - actions: [ - TextButton( - onPressed: () { - Logger().d('取消按钮被点击'); - Get.back(); - }, - child: Text('cancel'.tr), - ), - TextButton( - onPressed: () { - Logger().d('更新按钮被点击'); - Get.back(); - Future.delayed(const Duration(milliseconds: 300)); - onConfirm(); - }, - child: Text('otaUpdate'.tr), - ), - ], - ), - ); - } - - /// 显示升级成功对话框 - /// 引导用户进行设备重新配对 - void showUpgradeSuccessDialog() { - Get.dialog( - AlertDialog( - title: Row( - children: [ - Icon( - Icons.check_circle, - color: Colors.green[600], - size: 28, - ), - SizedBox(width: 12.w), - Text( - 'otaUpgradeSuccess'.tr, - style: TextStyle( - color: Colors.green[700], - fontWeight: FontWeight.w600, - ), - ), - ], - ), - content: Text( - 'otaUpgradeCompleteRepair'.tr, - style: TextStyle( - fontSize: 16, - height: 1.4, - ), - ), - actions: [ - TextButton( - onPressed: () { - Get.back(); - }, - child: Text( - 'otaPairLater'.tr, - style: TextStyle(color: Colors.grey[600]), - ), - ), - ElevatedButton( - onPressed: () { - Get.back(); - Get.offAllNamed(Routes.deviceCategory); - }, - style: ElevatedButton.styleFrom( - backgroundColor: Colors.green[600], - foregroundColor: Colors.white, - ), - child: Text('otaPairNow'.tr), - ), - ], - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - ), - barrierDismissible: false, - ); - } - - /// 显示错误提示 - /// [title] 错误标题 - /// [message] 错误信息 - /// [backgroundColor] 背景颜色,可选 - void showErrorSnackbar(String title, String message, - {Color? backgroundColor}) { - Get.snackbar( - title, - message, - snackPosition: SnackPosition.BOTTOM, - backgroundColor: backgroundColor ?? Colors.red[600], - colorText: Colors.white, - icon: const Icon( - Icons.error_outline, - color: Colors.white, - ), - ); - } -} diff --git a/apps/client/lib/modules/permissions/controllers/permissions_controller.dart b/apps/client/lib/modules/permissions/controllers/permissions_controller.dart index e8038360..cb642adb 100644 --- a/apps/client/lib/modules/permissions/controllers/permissions_controller.dart +++ b/apps/client/lib/modules/permissions/controllers/permissions_controller.dart @@ -318,17 +318,6 @@ class PermissionsController extends GetxController with WidgetsBindingObserver { } } - /// 显示成功消息 - void _showSuccessMessage() { - Get.snackbar( - 'success'.tr, - 'permissionGranted'.tr, - snackPosition: SnackPosition.BOTTOM, - backgroundColor: Colors.green, - colorText: Colors.white, - ); - } - /// 显示错误消息 void _showErrorMessage() { Get.snackbar( diff --git a/apps/client/lib/modules/picture_translation/controllers/picture_translation_controller.dart b/apps/client/lib/modules/picture_translation/controllers/picture_translation_controller.dart index 25f7f81c..e48c9639 100644 --- a/apps/client/lib/modules/picture_translation/controllers/picture_translation_controller.dart +++ b/apps/client/lib/modules/picture_translation/controllers/picture_translation_controller.dart @@ -7,7 +7,6 @@ import 'package:get_storage/get_storage.dart'; // import 'package:google_mlkit_text_recognition/google_mlkit_text_recognition.dart'; import 'package:image_picker/image_picker.dart'; import 'package:image/image.dart' as img; -import 'package:path/path.dart' as path; import 'package:permission_handler/permission_handler.dart'; import '../../../core/utils/permission_util.dart'; @@ -221,33 +220,6 @@ class PictureTranslationController extends GetxController { // Get.snackbar('成功', '已清空所有历史记录'); } - /// 检查权限 - /// - /// 合规(场景 1/2):走统一网关,用户拒绝一次后 48 小时内不再申请。 - /// 返回 false 时只给一条静态提示并退出该功能,不弹引导框、不跳设置页。 - Future _checkPermissions(ImageSource source) async { - final bool isCamera = source == ImageSource.camera; - final granted = await PermissionUtil.instance.requestPermission( - permissionType: isCamera ? Permission.camera : Permission.photos, - permissionName: isCamera ? 'takePhoto'.tr : 'photoAlbum'.tr, - explanationText: isCamera - ? 'cameraPermissionRequired'.tr - : 'photoAlbumPermissionRequired'.tr, - permanentDenialText: isCamera - ? 'cameraPermissionRequired'.tr - : 'photoAlbumPermissionRequired'.tr, - ); - if (!granted) { - Get.snackbar( - 'permissionRequired'.tr, - isCamera - ? 'cameraPermissionRequired'.tr - : 'photoAlbumPermissionRequired'.tr, - ); - } - return granted; - } - /// 相机/相册权限是否处于拒绝冷却期 —— 视图据此把对应入口置灰 bool isImagePermissionCoolingDown({required bool camera}) => PermissionUtil.instance.isDenialCoolingDown( diff --git a/apps/client/lib/modules/picture_translation/views/picture_translation_history_detail_view.dart b/apps/client/lib/modules/picture_translation/views/picture_translation_history_detail_view.dart index bf664acb..98070b13 100644 --- a/apps/client/lib/modules/picture_translation/views/picture_translation_history_detail_view.dart +++ b/apps/client/lib/modules/picture_translation/views/picture_translation_history_detail_view.dart @@ -319,15 +319,4 @@ class PictureTranslationHistoryDetailView extends StatelessWidget { return DateFormat('yyyy-MM-dd HH:mm').format(dateTime); } - void _shareTranslation() { - final shareText = '${'originalText'.tr}:${item.sourceText}\n\n' // 原文 - '${'translatedText'.tr}:${item.translatedText}\n\n' // 译文 - '${'sourceLanguage'.tr}:${item.sourceLanguageName.tr} → ' // 源语言 - '${'targetLanguage'.tr}:${item.targetLanguageName.tr}'; // 目标语言 - - // 这里可以调用分享插件 - Get.snackbar( - 'tip'.tr, // 提示 - 'shareInDevelopment'.tr); // 分享功能开发中 - } } diff --git a/apps/client/lib/modules/picture_translation/views/picture_translation_view.dart b/apps/client/lib/modules/picture_translation/views/picture_translation_view.dart index 56d93c4c..aa0b41e3 100644 --- a/apps/client/lib/modules/picture_translation/views/picture_translation_view.dart +++ b/apps/client/lib/modules/picture_translation/views/picture_translation_view.dart @@ -1,10 +1,8 @@ -import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:get/get.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:image_picker/image_picker.dart'; import 'package:photo_view/photo_view.dart'; // 新增:图片查看器 import '../../../core/theme/app_colors.dart'; @@ -890,36 +888,6 @@ class PictureTranslationView extends GetView { ); } - void _showClearHistoryDialog() { - Get.dialog( - AlertDialog( - backgroundColor: Get.isDarkMode ? Colors.grey[900] : Colors.white, - title: Text('clearHistory'.tr, // 清除历史记录 - style: TextStyle( - color: Get.isDarkMode ? Colors.white : Colors.black87)), - content: Text('clearHistoryConfirm'.tr, // 确定要清除所有翻译历史记录吗?此操作无法撤销。 - style: TextStyle( - color: Get.isDarkMode ? Colors.white70 : Colors.black54)), - actions: [ - TextButton( - onPressed: () => Get.back(), - child: Text('cancel'.tr, // 取消 - style: TextStyle( - color: Get.isDarkMode ? Colors.white70 : Colors.black54)), - ), - TextButton( - onPressed: () { - controller.clearHistory(); - Get.back(); - }, - child: Text('confirm'.tr, // 确认 - style: TextStyle(color: AppColors.error)), - ), - ], - ), - ); - } - Widget _buildImagePreview() { final file = controller.pickedImageFile.value; return Container( @@ -987,36 +955,6 @@ class PictureTranslationView extends GetView { ); } - Widget _buildSourceTextBox() { - return _buildTextBox( - 'recognitionResult'.tr, // 识别结果 - controller.sourceText.value); - } - - Widget _buildTranslatedTextBox() { - return _buildTextBox( - 'translationResult'.tr, // 翻译结果 - controller.translatedText.value); - } - - Widget _buildTextBox(String title, String content) { - return Container( - padding: EdgeInsets.all(12.w), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(8.r), - border: Border.all( - color: Get.isDarkMode ? Colors.white12 : Colors.grey.shade300), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text(title, style: const TextStyle(fontWeight: FontWeight.bold)), - SizedBox(height: 8.h), - Text(content.isEmpty ? '—' : content), - ], - ), - ); - } } void _openImageViewer(ImageProvider provider) { diff --git a/apps/client/lib/modules/profile/views/profile_meeting_view.dart b/apps/client/lib/modules/profile/views/profile_meeting_view.dart index dcda9771..c4ce0c6e 100644 --- a/apps/client/lib/modules/profile/views/profile_meeting_view.dart +++ b/apps/client/lib/modules/profile/views/profile_meeting_view.dart @@ -1,4 +1,3 @@ -import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; diff --git a/apps/client/lib/modules/profile/views/profile_view.dart b/apps/client/lib/modules/profile/views/profile_view.dart index 9f408780..a9a3bf31 100644 --- a/apps/client/lib/modules/profile/views/profile_view.dart +++ b/apps/client/lib/modules/profile/views/profile_view.dart @@ -2,8 +2,6 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import '../controllers/profile_controller.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; -import '../../../routes/app_routes.dart'; -import 'dart:io'; import 'dart:ui'; import '../../common/webview_page.dart'; import '../../../core/utils/doc_url_helper.dart'; diff --git a/apps/client/lib/modules/profile/views/unified_avatar.dart b/apps/client/lib/modules/profile/views/unified_avatar.dart index d25a8a8f..dc96d64b 100644 --- a/apps/client/lib/modules/profile/views/unified_avatar.dart +++ b/apps/client/lib/modules/profile/views/unified_avatar.dart @@ -1,6 +1,5 @@ import 'dart:io'; import 'package:flutter/material.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:get/get.dart'; import '../controllers/profile_controller.dart'; diff --git a/apps/client/lib/modules/settings/bindings/settings_binding.dart b/apps/client/lib/modules/settings/bindings/settings_binding.dart deleted file mode 100644 index dae35e08..00000000 --- a/apps/client/lib/modules/settings/bindings/settings_binding.dart +++ /dev/null @@ -1,11 +0,0 @@ -import 'package:get/get.dart'; -import '../../profile/controllers/profile_controller.dart'; -import '../controllers/settings_controller.dart'; - -class SettingsBinding extends Bindings { - @override - void dependencies() { - Get.lazyPut(() => SettingsController()); - Get.lazyPut(() => ProfileController()); - } -} diff --git a/apps/client/lib/modules/splash/views/splash_view.dart b/apps/client/lib/modules/splash/views/splash_view.dart index 692ae2ad..8eb39404 100644 --- a/apps/client/lib/modules/splash/views/splash_view.dart +++ b/apps/client/lib/modules/splash/views/splash_view.dart @@ -2,7 +2,6 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import '../controllers/splash_controller.dart'; -import '../../common/webview_page.dart'; class SplashView extends GetView { const SplashView({Key? key}) : super(key: key); diff --git a/apps/client/lib/modules/translation/controllers/translation_controller.dart b/apps/client/lib/modules/translation/controllers/translation_controller.dart index e0580aa5..473fd363 100644 --- a/apps/client/lib/modules/translation/controllers/translation_controller.dart +++ b/apps/client/lib/modules/translation/controllers/translation_controller.dart @@ -19,7 +19,6 @@ import 'package:eaimar/data/services/qq_music.dart'; import '../../../data/services/ast_service.dart'; import '../../../data/services/server_translation_service.dart'; import '../../../data/services/music_manager.dart'; -import '../../../data/services/translation_usage_service.dart'; import '../../../data/services/tts_service.dart'; import '../../../data/services/language_manager.dart'; import '../../../core/utils/logger.dart'; @@ -33,16 +32,13 @@ import 'package:device_plugin_interface/device_plugin_interface.dart'; import '../../../devices/device_hub.dart'; import '../../../data/services/recording_archive.dart'; import '../models/translation_export.dart'; -import '../../../core/utils/device_connection.dart'; import '../../../core/utils/background_session_notifier.dart'; import 'record_timer_controller.dart'; import 'translation_history_controller.dart'; import '../models/translation_models.dart'; import '../models/translation_direction.dart'; -import '../views/dialogs/translation_mode_selector.dart'; import '../../../data/models/appconfig.dart'; import '../../../data/models/appconfig_model.dart'; -import '../../../data/models/user_Info.dart'; import '../../common/widgets/recharge_dialog.dart'; /// 通话翻译"后台继续"系统通知的 id @@ -131,7 +127,6 @@ class TranslationController extends GetxController with WidgetsBindingObserver { // 安卓悬浮窗管理器 late final FloatingWindowManager _floatingWindowManager; // 苹果悬浮窗管理器 - late final NativePlugin _nativePlugin; // ==================== 悬浮窗相关 ==================== final isFloatingWindowEnabled = false.obs; // 悬浮窗状态 @@ -158,7 +153,6 @@ class TranslationController extends GetxController with WidgetsBindingObserver { // 分页加载相关状态 final pageSize = 20; // 每页记录数量 - bool _scrollListenerSetup = false; // 滚动监听器设置标志 // ==================== 状态变量 ==================== RxInt activeSpeaker = 0.obs; // 0=无激活, 1=按钮1, 2=按钮2 @@ -296,7 +290,6 @@ class TranslationController extends GetxController with WidgetsBindingObserver { /// 初始化苹果悬浮窗管理器 Future initPlatformState() async { - _nativePlugin = NativePlugin(); if (!Platform.isIOS) return; // ⚠️ 不再走 pub 包 `pip`。它给小窗喂的是一整块纯黑像素,真正的字幕卡片 // 靠把 contentView 搬进「keyWindow」来显示,而 PiP 窗口由系统进程托管、 @@ -3436,23 +3429,6 @@ class TranslationController extends GetxController with WidgetsBindingObserver { /// 保存翻译历史 void saveTranslationHistory() => _historyManager.saveTranslationHistory(); - /// 设置滚动监听器(适配reverse模式) - void _setupScrollListener() { - if (_scrollListenerSetup) return; - - scrollController.addListener(() { - if (scrollController.position.pixels >= - scrollController.position.maxScrollExtent - 100) { - if (hasMoreHistory.value && !isLoadingMore.value) { - Logger.d(TAG, '触发加载更多翻译历史记录(reverse模式)'); - loadMoreHistory(); - } - } - }); - - _scrollListenerSetup = true; - } - /// 清空翻译历史 void clearTranslationHistory() => _historyManager.clearTranslationHistory(); diff --git a/apps/client/lib/modules/translation/controllers/translation_detail_controller.dart b/apps/client/lib/modules/translation/controllers/translation_detail_controller.dart index e2d965b0..fef17ab8 100644 --- a/apps/client/lib/modules/translation/controllers/translation_detail_controller.dart +++ b/apps/client/lib/modules/translation/controllers/translation_detail_controller.dart @@ -1,7 +1,6 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; // import '../../../data/services/volcano_ai_service.dart';// 注释掉火山AI服务导入 -import '../controllers/translation_controller.dart'; import 'translation_audiohistory_controller.dart'; import '../models/translation_models.dart'; // 添加这行导入 import 'package:get_storage/get_storage.dart'; @@ -14,14 +13,11 @@ class TranslationDetailController extends GetxController { // 依赖注入 //final VolcanoAIService _aiService = Get.find(); final GetStorage _storage = GetStorage(); - late final UsageStatsService _usageService; // 存储键前缀 static const String _summaryKeyPrefix = 'translation_summary_'; // 超时设置(秒) - static const int _defaultTimeoutDuration = 30; - static const int _extendedTimeoutDuration = 60; // 状态变量 final selectedTabIndex = 0.obs; @@ -43,7 +39,6 @@ class TranslationDetailController extends GetxController { if (!Get.isRegistered()) { Get.put(UsageStatsService(), permanent: true); } - _usageService = Get.find(); } catch (e) { Logger.error('初始化使用量统计服务失败: $e'); } diff --git a/apps/client/lib/modules/translation/views/dialogs/delete_confirm_dialog.dart b/apps/client/lib/modules/translation/views/dialogs/delete_confirm_dialog.dart deleted file mode 100644 index dbbd2b2f..00000000 --- a/apps/client/lib/modules/translation/views/dialogs/delete_confirm_dialog.dart +++ /dev/null @@ -1,172 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:get/get.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import '../../../../core/theme/app_colors.dart'; -import '../../models/translation_models.dart'; - -/// 删除确认对话框 -/// 提供翻译记录的删除确认功能 -class DeleteConfirmDialog { - /// 显示删除单条翻译记录确认对话框 - static void showDeleteItemDialog({ - required TranslationItem item, - required Function() onConfirm, - }) { - final isDarkMode = Theme.of(Get.context!).brightness == Brightness.dark; - - Get.dialog( - AlertDialog( - backgroundColor: isDarkMode ? AppColors.cardBackground : Colors.white, - title: Text( - 'deleteTranslationRecord'.tr, // 删除翻译记录 - style: TextStyle( - fontSize: 18.sp, - fontWeight: FontWeight.bold, - color: isDarkMode ? Colors.white : Colors.black, - ), - ), - content: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'deleteTranslationConfirm'.tr, // 确定要删除这条翻译记录吗?此操作无法撤销。 - style: TextStyle( - fontSize: 16.sp, - color: isDarkMode ? Colors.grey[300] : Colors.black87, - ), - ), - SizedBox(height: 12.h), - // 显示要删除的记录预览 - Container( - padding: EdgeInsets.all(12.w), - decoration: BoxDecoration( - color: isDarkMode - ? Colors.grey[800]?.withOpacity(0.5) - : Colors.grey[100], - borderRadius: BorderRadius.circular(8.r), - border: Border.all( - color: isDarkMode ? Colors.grey[700]! : Colors.grey[300]!, - width: 1, - ), - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - item.sourceText, - style: TextStyle( - fontSize: 14.sp, - color: isDarkMode ? Colors.white : Colors.black, - fontWeight: FontWeight.w500, - ), - maxLines: 2, - overflow: TextOverflow.ellipsis, - ), - if (item.translatedText.isNotEmpty) ...[ - SizedBox(height: 4.h), - Text( - item.translatedText, - style: TextStyle( - fontSize: 14.sp, - color: isDarkMode ? Colors.grey[300] : Colors.grey[700], - ), - maxLines: 2, - overflow: TextOverflow.ellipsis, - ), - ], - ], - ), - ), - ], - ), - actions: [ - TextButton( - onPressed: () => Get.back(), - child: Text( - 'cancel'.tr, - style: TextStyle( - fontSize: 16.sp, - color: isDarkMode ? Colors.grey[400] : Colors.grey[700], - ), - ), - ), - TextButton( - onPressed: () { - Get.back(); - onConfirm(); - }, - child: Text( - 'confirm'.tr, - style: TextStyle( - fontSize: 16.sp, - color: Colors.red, - fontWeight: FontWeight.bold, - ), - ), - ), - ], - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12.r), - ), - ), - ); - } - - /// 显示清除所有历史记录确认对话框 - static void showClearHistoryDialog({ - required Function() onConfirm, - }) { - final isDarkMode = Get.isDarkMode; - - Get.dialog( - AlertDialog( - backgroundColor: isDarkMode ? AppColors.cardBackground : Colors.white, - title: Text( - 'clearHistory'.tr, // 清除历史记录 - style: TextStyle( - fontSize: 18.sp, - fontWeight: FontWeight.bold, - color: isDarkMode ? Colors.white : Colors.black, - ), - ), - content: Text( - 'clearHistoryConfirm'.tr, // 确定要清除所有翻译历史记录吗?此操作无法撤销。 - style: TextStyle( - fontSize: 16.sp, - color: isDarkMode ? Colors.grey[300] : Colors.black87, - ), - ), - actions: [ - TextButton( - onPressed: () => Get.back(), - child: Text( - 'cancel'.tr, - style: TextStyle( - fontSize: 16.sp, - color: isDarkMode ? Colors.grey[400] : Colors.grey[700], - ), - ), - ), - TextButton( - onPressed: () { - Get.back(); - onConfirm(); - }, - child: Text( - 'confirm'.tr, - style: TextStyle( - fontSize: 16.sp, - color: Colors.red, - fontWeight: FontWeight.bold, - ), - ), - ), - ], - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12.r), - ), - ), - ); - } -} diff --git a/apps/client/lib/modules/translation/views/translation_detail_view.dart b/apps/client/lib/modules/translation/views/translation_detail_view.dart index 6ad3db2b..e770310e 100644 --- a/apps/client/lib/modules/translation/views/translation_detail_view.dart +++ b/apps/client/lib/modules/translation/views/translation_detail_view.dart @@ -1,8 +1,6 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; -import '../controllers/translation_controller.dart'; -import '../controllers/translation_audiohistory_controller.dart'; import '../controllers/translation_detail_controller.dart'; import 'package:intl/intl.dart'; import 'package:flutter/services.dart'; @@ -344,148 +342,6 @@ class TranslationDetailView extends GetView { // ); // } - // 构建摘要容器 - Widget _buildSummaryContainer(bool isDarkMode) { - return Container( - width: double.infinity, - margin: EdgeInsets.only(bottom: 16.h), - decoration: BoxDecoration( - color: isDarkMode ? AppColors.cardBackground : Colors.white, - borderRadius: BorderRadius.circular(16.r), - boxShadow: [ - BoxShadow( - color: Colors.black.withAlpha(isDarkMode ? 30 : 8), - blurRadius: 8, - offset: Offset(0, 2), - ), - ], - ), - child: Obx(() { - if (controller.summaryResult.value.isEmpty) { - return _buildEmptySummaryPrompt(isDarkMode); - } else { - return _buildSummaryContent(isDarkMode); - } - }), - ); - } - - // 构建空摘要提示 - Widget _buildEmptySummaryPrompt(bool isDarkMode) { - return Padding( - padding: EdgeInsets.all(24.r), - child: Center( - child: Text( - 'clickToGenerateSummary'.tr, // 点击下方按钮生成会话摘要 - style: TextStyle( - fontSize: 15.sp, - color: isDarkMode ? Colors.grey[400] : Colors.grey[600], - fontStyle: FontStyle.italic, - ), - textAlign: TextAlign.center, - ), - ), - ); - } - - // 构建摘要内容 - Widget _buildSummaryContent(bool isDarkMode) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: EdgeInsets.all(20.r), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'summaryContent'.tr, // 摘要内容 - style: TextStyle( - fontSize: 16.sp, - fontWeight: FontWeight.bold, - color: isDarkMode ? Colors.white : Colors.black, - ), - ), - SizedBox(height: 12.h), - Text( - controller.summaryResult.value, - style: TextStyle( - fontSize: 15.sp, - color: isDarkMode ? Colors.grey[400] : Colors.grey[800], - height: 1.5, - ), - ), - ], - ), - ), - Divider( - height: 1, - thickness: 0.5, - color: isDarkMode ? Colors.grey[700] : Colors.grey[200], - ), - Padding( - padding: EdgeInsets.symmetric(horizontal: 12.r, vertical: 8.r), - child: Row( - mainAxisAlignment: MainAxisAlignment.end, - children: [ - // 播放按钮 - Material( - color: Colors.transparent, - child: InkWell( - onTap: () => - controller.playText(controller.summaryResult.value), - borderRadius: BorderRadius.circular(20.r), - splashColor: isDarkMode - ? AppColors.primary.withOpacity(0.2) - : Colors.blue.withOpacity(0.2), - child: Padding( - padding: EdgeInsets.all(8.r), - child: Icon( - Icons.volume_up, - color: isDarkMode ? Colors.white : Colors.blue, - size: 18.sp, - ), - ), - ), - ), - SizedBox(width: 12.w), - // 复制按钮 - Material( - color: Colors.transparent, - child: InkWell( - onTap: _copySummaryToClipboard, - borderRadius: BorderRadius.circular(20.r), - splashColor: isDarkMode - ? AppColors.primary.withOpacity(0.2) - : Colors.blue.withOpacity(0.2), - child: Padding( - padding: EdgeInsets.all(8.r), - child: Icon( - Icons.copy, - color: isDarkMode ? Colors.white : Colors.blue, - size: 18.sp, - ), - ), - ), - ), - ], - ), - ), - ], - ); - } - - // 复制摘要到剪贴板 - void _copySummaryToClipboard() { - Clipboard.setData(ClipboardData(text: controller.summaryResult.value)); - Get.snackbar( - 'copied'.tr, // 已复制 - 'summaryCopiledToClipboard'.tr, // 摘要已复制到剪贴板 - snackPosition: SnackPosition.BOTTOM, - duration: Duration(seconds: 2), - ); - } - // 构建提取摘要按钮 // Widget _buildExtractSummaryButton( // String combinedSourceText, bool isDarkMode) { diff --git a/apps/client/lib/modules/translation/views/translation_history_view.dart b/apps/client/lib/modules/translation/views/translation_history_view.dart index 8fb2eded..ff5a90fe 100644 --- a/apps/client/lib/modules/translation/views/translation_history_view.dart +++ b/apps/client/lib/modules/translation/views/translation_history_view.dart @@ -2,7 +2,6 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:intl/intl.dart'; -import '../controllers/translation_controller.dart'; import '../controllers/translation_audiohistory_controller.dart'; import '../bindings/translation_detail_binding.dart'; import '../models/translation_models.dart'; diff --git a/apps/client/lib/modules/translation/views/translation_list_view.dart b/apps/client/lib/modules/translation/views/translation_list_view.dart index 4968bc57..c4500c81 100644 --- a/apps/client/lib/modules/translation/views/translation_list_view.dart +++ b/apps/client/lib/modules/translation/views/translation_list_view.dart @@ -11,7 +11,6 @@ import '../controllers/translation_list_controller.dart'; class TranslationListView extends GetView { const TranslationListView({super.key}); - static OverlayEntry? _recordingOverlayEntry; @override Widget build(BuildContext context) { final isDarkMode = Theme.of(context).brightness == Brightness.dark; @@ -258,8 +257,6 @@ class TranslationListView extends GetView { Offset.zero & renderBox.size, ); - final fileName = file.path.split('/').last; - showMenu( context: context, position: position, diff --git a/apps/client/lib/modules/translation/views/translation_view.dart b/apps/client/lib/modules/translation/views/translation_view.dart index bd24b4cc..60a9318a 100644 --- a/apps/client/lib/modules/translation/views/translation_view.dart +++ b/apps/client/lib/modules/translation/views/translation_view.dart @@ -6,12 +6,9 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:get/get.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:haptic_feedback/haptic_feedback.dart'; import '../controllers/translation_controller.dart'; import '../models/translation_models.dart'; import '../models/translation_direction.dart'; -import '../views/translation_history_view.dart'; -import '../bindings/translation_history_binding.dart'; import '../../../core/theme/app_colors.dart'; import '../../../core/utils/logger.dart'; import '../../../routes/app_routes.dart'; @@ -19,7 +16,6 @@ import '../../../core/utils/background_session_notifier.dart'; import '../../common/widgets/language_selector_bar.dart'; // 导入拆分后的组件 -import 'widgets/draggable_floating_button.dart'; // 可拖拽的悬浮按钮 import 'widgets/translation_item_widget.dart'; // 翻译项组件 import 'dialogs/language_selection_dialog.dart'; // 语言选择对话框 import 'dialogs/translation_mode_selector.dart'; // 翻译模式选择器 @@ -1137,39 +1133,6 @@ class TranslationView extends GetView { ); } - // 构建语言选择栏 - Widget _buildLanguageSelectionBar(bool isDarkMode) { - return Container( - height: 44.h, - padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 6.h), - decoration: BoxDecoration( - color: isDarkMode ? AppColors.cardBackground : Colors.white, - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.1), - blurRadius: 4, - offset: const Offset(0, 2), - ), - BoxShadow( - color: Colors.black.withOpacity(0.1), - blurRadius: 4, - offset: const Offset(0, -2), - ), - ], - ), - child: LanguageSelectorBar( - sourceText: () => controller.sourceLanguage.value.split(' ')[0], - targetText: () => controller.targetLanguage.value.split(' ')[0], - onTapSource: () => LanguageSelectionDialog.show(true, isDarkMode, - translationController: controller), - onTapTarget: () => LanguageSelectionDialog.show(false, isDarkMode, - translationController: controller), - onSwap: controller.swapLanguages, - translateLanguageNames: true, // 是否翻译语言名称 - fontSizeSp: 15, - ), - ); - } } /// 只做一件事:把「这个翻译页面还活着」这件事记进 [TranslationView._aliveCount]。 diff --git a/apps/client/lib/modules/translation/views/widgets/face_to_face_layout.dart b/apps/client/lib/modules/translation/views/widgets/face_to_face_layout.dart deleted file mode 100644 index 642afe57..00000000 --- a/apps/client/lib/modules/translation/views/widgets/face_to_face_layout.dart +++ /dev/null @@ -1,267 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:get/get.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import '../../controllers/translation_controller.dart'; -import '../../models/translation_models.dart'; -import '../../../../core/theme/app_colors.dart'; -import '../dialogs/language_selection_dialog.dart'; - -/// 面对面翻译布局组件 -class FaceToFaceLayout extends StatefulWidget { - final bool isDarkMode; - final TranslationController controller; - - const FaceToFaceLayout({ - Key? key, - required this.isDarkMode, - required this.controller, - }) : super(key: key); - - @override - State createState() => _FaceToFaceLayoutState(); -} - -class _FaceToFaceLayoutState extends State { - final ScrollController _topScrollController = ScrollController(); - final ScrollController _bottomScrollController = ScrollController(); - - @override - void dispose() { - _topScrollController.dispose(); - _bottomScrollController.dispose(); - super.dispose(); - } - - void _scrollToBottom({bool animate = false}) { - WidgetsBinding.instance.addPostFrameCallback((_) { - if (_topScrollController.hasClients) { - final m = _topScrollController.position.maxScrollExtent; - if (animate) { - _topScrollController.animateTo( - m, - duration: const Duration(milliseconds: 200), - curve: Curves.easeOut, - ); - } else { - _topScrollController.jumpTo(m); - } - } - if (_bottomScrollController.hasClients) { - final m2 = _bottomScrollController.position.maxScrollExtent; - if (animate) { - _bottomScrollController.animateTo( - m2, - duration: const Duration(milliseconds: 200), - curve: Curves.easeOut, - ); - } else { - _bottomScrollController.jumpTo(m2); - } - } - }); - } - - @override - Widget build(BuildContext context) { - final isDarkMode = widget.isDarkMode; - final controller = widget.controller; - return Obx(() { - // 获取最新的翻译记录 - final latestItem = controller.translationHistory.isNotEmpty - ? controller.translationHistory.last - : null; - _scrollToBottom(animate: false); - - return Column( - children: [ - // 上半部分 - (旋转180度) - Expanded( - child: Transform.rotate( - angle: 3.14159, // 180度 = π弧度 - child: Container( - width: double.infinity, - padding: EdgeInsets.fromLTRB(24.w, 24.w, 24.w, 24.w + 96.h), - decoration: BoxDecoration( - color: isDarkMode - ? AppColors.cardBackground.withValues(alpha: 0.5) - : Colors.blue[50]?.withValues(alpha: 0.3), - border: Border( - bottom: BorderSide( - color: isDarkMode ? Colors.grey[700]! : Colors.grey[300]!, - width: 1, - ), - ), - ), - child: SingleChildScrollView( - controller: _topScrollController, - physics: const BouncingScrollPhysics(), - child: Text( - latestItem?.targetLanguageCode == - controller.targetLanguageCode.value - ? latestItem?.translatedText ?? '' - : latestItem?.sourceText ?? '', - style: TextStyle( - fontSize: 20.sp, - fontWeight: FontWeight.w500, - color: isDarkMode ? Colors.white : Colors.black87, - height: 1.4, - ), - textAlign: TextAlign.center, - ), - ), - ), - ), - ), - - // 语言选择栏 - _buildLanguageSelectionBar(isDarkMode), - - // 下半部分 - (正常方向) - Expanded( - child: Container( - width: double.infinity, - padding: EdgeInsets.fromLTRB(24.w, 24.w, 24.w, 24.w + 96.h), - decoration: BoxDecoration( - color: isDarkMode - ? AppColors.cardBackground.withValues(alpha: 0.5) - : Colors.green[50]?.withValues(alpha: 0.3), - ), - child: SingleChildScrollView( - controller: _bottomScrollController, - physics: const BouncingScrollPhysics(), - child: Text( - latestItem?.sourceLanguageCode == - controller.sourceLanguageCode.value - ? latestItem?.sourceText ?? - (controller.faceToFaceRecognitionText.value.isEmpty - ? '' - : controller.faceToFaceRecognitionText.value) - : latestItem?.translatedText ?? '', - style: TextStyle( - fontSize: 20.sp, - fontWeight: FontWeight.w500, - color: isDarkMode ? Colors.white : Colors.black87, - height: 1.4, - ), - textAlign: TextAlign.center, - ), - ), - ), - ), - ], - ); - }); - } - - // 构建语言选择栏 - Widget _buildLanguageSelectionBar(bool isDarkMode) { - return Container( - height: 44.h, - padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 6.h), - decoration: BoxDecoration( - color: isDarkMode ? AppColors.cardBackground : Colors.white, - boxShadow: [ - BoxShadow( - color: Colors.black.withOpacity(0.1), - blurRadius: 4, - offset: const Offset(0, 2), - ), - BoxShadow( - color: Colors.black.withOpacity(0.1), - blurRadius: 4, - offset: const Offset(0, -2), - ), - ], - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - // 源语言选择 - Expanded( - child: GestureDetector( - onTap: () => _showLanguageSelectionDialog(true, isDarkMode), - child: Container( - padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 4.h), - decoration: BoxDecoration( - color: isDarkMode - ? Colors.white.withOpacity(0.1) - : Colors.grey[100], - borderRadius: BorderRadius.circular(16.r), - ), - child: Text( - '${widget.controller.sourceLanguage.value.split(' ')[0]}'.tr, - style: TextStyle( - fontSize: 15.sp, - fontWeight: FontWeight.w600, - color: isDarkMode ? Colors.white : Colors.black, - ), - textAlign: TextAlign.center, - overflow: TextOverflow.ellipsis, - ), - ), - ), - ), - - // 语言互换按钮 - GestureDetector( - onTap: widget.controller.swapLanguages, - child: Container( - margin: EdgeInsets.symmetric(horizontal: 8.w), - padding: EdgeInsets.all(4.r), - decoration: BoxDecoration( - color: isDarkMode - ? AppColors.primary.withOpacity(0.2) - : Colors.blue[50], - shape: BoxShape.circle, - ), - child: Icon( - Icons.swap_horiz, - color: isDarkMode ? AppColors.primary : Colors.blue, - size: 20.sp, - ), - ), - ), - - // 目标语言选择 - Expanded( - child: GestureDetector( - onTap: () => _showLanguageSelectionDialog(false, isDarkMode), - child: Container( - padding: EdgeInsets.symmetric(horizontal: 8.w, vertical: 4.h), - decoration: BoxDecoration( - color: isDarkMode - ? Colors.white.withOpacity(0.1) - : Colors.grey[100], - borderRadius: BorderRadius.circular(16.r), - ), - child: Transform.rotate( - angle: 3.14159, // 旋转180度 - child: Text( - '${widget.controller.targetLanguage.value.split(' ')[0]}' - .tr, - style: TextStyle( - fontSize: 15.sp, - fontWeight: FontWeight.w600, - color: isDarkMode ? Colors.white : Colors.black, - ), - textAlign: TextAlign.center, - overflow: TextOverflow.ellipsis, - ), - ), - ), - ), - ), - ], - ), - ); - } - - /// 显示语言选择对话框 - void _showLanguageSelectionDialog(bool isSource, bool isDarkMode) { - // 翻译进行中不开弹窗(见 controller.guardLanguageChange) - if (!widget.controller.guardLanguageChange()) return; - // 不传 excludeLanguage:两侧列表保持一致,选到对侧语言时 controller 对调 - LanguageSelectionDialog.show(isSource, isDarkMode, - translationController: widget.controller); - } -} diff --git a/apps/client/lib/modules/voice_replication/bindings/voice_replication_binding.dart b/apps/client/lib/modules/voice_replication/bindings/voice_replication_binding.dart deleted file mode 100644 index d52da42a..00000000 --- a/apps/client/lib/modules/voice_replication/bindings/voice_replication_binding.dart +++ /dev/null @@ -1,11 +0,0 @@ -import 'package:get/get.dart'; - -import '../controllers/voice_replication_controller.dart'; - -class VoiceReplicationBinding extends Bindings { - @override - void dependencies() { - // 注册控制器 - Get.lazyPut(() => VoiceReplicationController()); - } -} diff --git a/apps/client/lib/modules/voice_replication/controllers/voice_replication_controller.dart b/apps/client/lib/modules/voice_replication/controllers/voice_replication_controller.dart deleted file mode 100644 index 686da831..00000000 --- a/apps/client/lib/modules/voice_replication/controllers/voice_replication_controller.dart +++ /dev/null @@ -1,39 +0,0 @@ -import 'package:get/get.dart'; -import 'package:get_storage/get_storage.dart'; - -import '../../../data/services/tts_service.dart'; - -class VoiceReplicationController extends GetxController { - final TtsService _ttsService = Get.find(); - - final GetStorage _storage = GetStorage(); - - RxBool isReplicating = false.obs; - - RxString speakerProfileId = ''.obs; - - RxBool isAgent = false.obs; - RxBool isSimultaneous = false.obs; - RxBool isCall = false.obs; - RxBool isFaceToFace = false.obs; - - @override - void onInit() { - super.onInit(); - _getDefaultData(); - } - - void _getDefaultData() { - isReplicating.value = _storage.read('open_voice_replication') ?? false; - speakerProfileId.value = _storage.read('speakerProfileId') ?? ''; - } - - void enableVoiceFlocking() { - if (speakerProfileId.value.isNotEmpty) { - _ttsService.setVoiceFlocking( - isReplicating.value ? speakerProfileId.value : '', - ); - _storage.write('open_voice_replication', isReplicating.value); - } - } -} diff --git a/apps/client/lib/modules/voice_replication/views/recorder_bottom_sheet.dart b/apps/client/lib/modules/voice_replication/views/recorder_bottom_sheet.dart deleted file mode 100644 index f919b667..00000000 --- a/apps/client/lib/modules/voice_replication/views/recorder_bottom_sheet.dart +++ /dev/null @@ -1,341 +0,0 @@ -import 'dart:io'; -import 'dart:convert'; - -import 'package:flutter/material.dart'; -import 'package:flutter_easyloading/flutter_easyloading.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:get/get.dart'; -import 'package:get_storage/get_storage.dart'; -import 'package:http/http.dart' as http; -import 'package:path_provider/path_provider.dart'; -import 'package:permission_handler/permission_handler.dart'; -import 'package:record/record.dart'; -import 'package:uuid/uuid.dart'; - -import '../../../core/utils/permission_util.dart'; -import '../../../data/models/appconfig.dart'; -import '../controllers/voice_replication_controller.dart'; - -class RecorderBottomSheet extends StatefulWidget { - const RecorderBottomSheet({super.key}); - - @override - State createState() => _RecorderBottomSheetState(); -} - -class _RecorderBottomSheetState extends State { - final _controller = Get.find(); - - final GetStorage _storage = GetStorage(); - final _record = AudioRecorder(); - - bool _isRecording = false; - - String _resourceKey = ''; - String _resourceRegion = ''; - String _jessicaConsentId = ''; - - String _voiceTalentName = ''; - String _jessicaPersonalVoiceId = ''; - - String _path = ''; - - @override - void initState() { - super.initState(); - _getDefaultData(); - } - - @override - void dispose() { - _record.dispose(); - super.dispose(); - } - - void _getDefaultData() async { - _resourceKey = AppConfig.cred('stt_azure', 'subscription_key', 'AZURE_SPEECH_KEY') ?? ''; - _resourceRegion = AppConfig.cred('stt_azure', 'region', 'AZURE_SPEECH_REGION') ?? 'eastasia'; - _jessicaConsentId = const Uuid().v4(); - Map? userInfo = _storage.read('user_info'); - if (userInfo != null) { - _voiceTalentName = userInfo['user']['name'] ?? ''; - _jessicaPersonalVoiceId = userInfo['user']['uid'] ?? ''; - } - } - - void _startRecording() async { - setState(() { - _isRecording = true; - }); - await PermissionUtil.instance.requestPermission( - permissionType: Permission.microphone, - permissionName: 'microphonePermission'.tr, - explanationText: 'microphonePermissionExplanation'.tr, - permanentDenialText: 'microphonePermissionPermanentDenial'.tr, - ); - final directory = await getApplicationDocumentsDirectory(); - final recordDir = Directory('${directory.path}/VoiceReplication'); - if (!await recordDir.exists()) { - await recordDir.create(recursive: true); - } - _path = - '${directory.path}/VoiceReplication/recording_${DateTime.now().millisecondsSinceEpoch}.wav'; - await _record.start( - const RecordConfig( - encoder: AudioEncoder.wav, - sampleRate: 24000, - numChannels: 1, - ), - path: _path, - ); - } - - void _completeRecorder() async { - EasyLoading.show(status: '正在创建个人语音...'); - try { - await _record.stop(); - await _consents(); - await _personalvoices(); - } catch (e) { - Get.snackbar('error'.tr, e.toString(), snackPosition: SnackPosition.TOP); - } - EasyLoading.dismiss(); - } - - Future _consents() async { - final url = Uri.parse( - 'https://$_resourceRegion.api.cognitive.microsoft.com/customvoice/consents/$_jessicaConsentId?api-version=2024-02-01-preview'); - final request = http.MultipartRequest('POST', url); - request.headers['Ocp-Apim-Subscription-Key'] = _resourceKey; - - request.fields['description'] = 'Consent for $_voiceTalentName voice'; - request.fields['projectId'] = 'Eaimar'; - request.fields['voiceTalentName'] = _voiceTalentName; - request.fields['companyName'] = '深圳市云衍智能科技有限公司'; - request.fields['locale'] = 'zh-CN'; - - request.files.add(await http.MultipartFile.fromPath('audiodata', _path)); - - final streamed = await request.send(); - final response = await http.Response.fromStream(streamed); - if (streamed.statusCode >= 200 && streamed.statusCode < 300) { - final bodyText = utf8.decode(response.bodyBytes, allowMalformed: true); - if (bodyText.isNotEmpty) { - final decoded = jsonDecode(bodyText); - - String status = decoded['status'] ?? 'NotStarted'; - final operationLocation = response.headers['operation-location']; - int retryCount = 0; - - while (status != 'Succeeded' && status != 'Failed' && retryCount < 30) { - await Future.delayed(const Duration(seconds: 1)); - if (operationLocation != null && operationLocation.isNotEmpty) { - status = await _operations(operationLocation); - } else { - final consentUrl = - 'https://$_resourceRegion.api.cognitive.microsoft.com/customvoice/consents/$_jessicaConsentId?api-version=2024-02-01-preview'; - status = await _operations(consentUrl); - } - retryCount++; - } - - if (status != 'Succeeded') { - throw Exception('Consent validation failed or timed out: $status'); - } - } - } else { - throw Exception('Failed to create consent: ${response.statusCode}'); - } - } - - Future _operations(String operationUrl) async { - String status = 'NotStarted'; - - final url = Uri.parse(operationUrl); - final response = await http.get(url, headers: { - 'Ocp-Apim-Subscription-Key': _resourceKey, - }); - if (response.statusCode == 200) { - final bodyText = utf8.decode(response.bodyBytes, allowMalformed: true); - if (bodyText.isNotEmpty) { - final decoded = jsonDecode(bodyText); - status = decoded['status'] ?? status; - } - } - return status; - } - - Future _personalvoices() async { - final url = Uri.parse( - 'https://$_resourceRegion.api.cognitive.microsoft.com/customvoice/personalvoices/$_jessicaPersonalVoiceId?api-version=2024-02-01-preview'); - final request = http.MultipartRequest('POST', url); - request.headers['Ocp-Apim-Subscription-Key'] = _resourceKey; - - request.fields['projectId'] = 'Eaimar'; - request.fields['consentId'] = _jessicaConsentId; - - request.files.add(await http.MultipartFile.fromPath('audiodata', _path)); - - final streamed = await request.send(); - final response = await http.Response.fromStream(streamed); - if (streamed.statusCode >= 200 && streamed.statusCode < 300) { - final bodyText = utf8.decode(response.bodyBytes, allowMalformed: true); - if (bodyText.isNotEmpty) { - final decoded = jsonDecode(bodyText); - _controller.speakerProfileId.value = decoded['speakerProfileId']; - _storage.write('open_voice_replication', true); - _storage.write('speakerProfileId', decoded['speakerProfileId']); - } - } else { - throw Exception( - 'Failed to create personal voice: ${response.statusCode}'); - } - } - - @override - Widget build(BuildContext context) { - return Padding( - padding: EdgeInsets.symmetric(horizontal: 12.w), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Container( - padding: EdgeInsets.symmetric(vertical: 10.w), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - '同意并朗读使用个人语音', - style: TextStyle( - fontSize: 16.sp, - color: Colors.black87, - fontWeight: FontWeight.bold, - ), - ), - GestureDetector( - onTap: () => Get.back(), - child: Container( - width: 26.w, - height: 26.w, - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(26.r), - ), - child: Icon( - Icons.close, - size: 18.w, - color: Colors.grey[400], - ), - ), - ) - ], - ), - ), - Divider( - height: 1, - color: Colors.grey[300], - ), - Container( - padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 20.w), - margin: EdgeInsets.symmetric(vertical: 20.w), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(12.w), - boxShadow: [ - BoxShadow( - color: Colors.black.withValues(alpha: 0.05), - blurRadius: 10, - offset: const Offset(0, 2), - ), - ], - ), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - '请朗读:', - style: TextStyle( - fontSize: 14.sp, - color: Colors.black87, - ), - ), - Padding( - padding: EdgeInsets.only(top: 20.w, bottom: 50.w), - child: Text( - '我(你的姓名)确认我的声音将会被(深圳市云衍智能科技有限公司)使用于创建合成版本语音。', - style: TextStyle( - fontSize: 16.sp, - color: Colors.red, - ), - ), - ), - Text( - '例:我(李伟)确认我的声音将会被(深圳市云衍智能科技有限公司)使用于创建合成版本语音。', - style: TextStyle( - fontSize: 12.sp, - color: Colors.grey, - ), - ), - ], - ), - ), - Padding( - padding: EdgeInsets.only(bottom: 20.w), - child: Row( - children: [ - Expanded( - child: GestureDetector( - onTap: () => Get.back(), - child: Container( - height: 48.w, - alignment: Alignment.center, - decoration: BoxDecoration( - color: Colors.grey[300], - borderRadius: BorderRadius.circular(12.r), - ), - child: Text( - 'cancel'.tr, // 取消 - style: TextStyle( - fontSize: 16.sp, - color: Colors.black, - ), - ), - ), - ), - ), - 10.horizontalSpace, - Expanded( - child: GestureDetector( - onTap: () { - if (_isRecording) { - Get.back(); - _completeRecorder(); - } else { - _startRecording(); - } - }, - child: Container( - height: 48.w, - alignment: Alignment.center, - decoration: BoxDecoration( - color: _isRecording ? Colors.blue : Colors.red, - borderRadius: BorderRadius.circular(12.r), - ), - child: Text( - _isRecording ? 'confirm'.tr : 'startRecording'.tr, // 确认 - style: TextStyle( - fontSize: 16.sp, - color: Colors.white, - ), - ), - ), - ), - ), - ], - ), - ), - ], - ), - ); - } -} diff --git a/apps/client/lib/modules/voice_replication/views/voice_replication_view.dart b/apps/client/lib/modules/voice_replication/views/voice_replication_view.dart deleted file mode 100644 index 7efd4d7a..00000000 --- a/apps/client/lib/modules/voice_replication/views/voice_replication_view.dart +++ /dev/null @@ -1,282 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_screenutil/flutter_screenutil.dart'; -import 'package:get/get.dart'; - -import '../controllers/voice_replication_controller.dart'; -import 'recorder_bottom_sheet.dart'; - -class VoiceReplicationView extends GetView { - const VoiceReplicationView({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - final isDarkMode = Theme.of(context).brightness == Brightness.dark; - - return Scaffold( - backgroundColor: isDarkMode ? Colors.black : Colors.grey[50], - appBar: _buildAppBar(isDarkMode), - body: _buildBody(isDarkMode), - ); - } - - // 构建应用栏 - PreferredSizeWidget _buildAppBar(bool isDarkMode) { - return AppBar( - backgroundColor: isDarkMode ? Colors.black : Colors.white, - elevation: 0.5, - leading: IconButton( - icon: Icon( - Icons.arrow_back_ios, - color: isDarkMode ? Colors.white : Colors.black, - size: 20.sp, - ), - onPressed: () => Get.back(), - ), - title: Text( - '声音复刻', - style: TextStyle( - fontSize: 17.sp, - fontWeight: FontWeight.w600, - color: isDarkMode ? Colors.white : Colors.black, - ), - ), - centerTitle: true, - ); - } - - // 构建主体内容 - Widget _buildBody(bool isDarkMode) { - return ListView( - padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 15.w), - children: [ - Container( - padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 20.w), - margin: EdgeInsets.only(bottom: 15.w), - decoration: BoxDecoration( - color: isDarkMode ? Colors.grey[800] : Colors.white, - borderRadius: BorderRadius.circular(12.w), - boxShadow: [ - BoxShadow( - color: isDarkMode - ? Colors.black.withValues(alpha: 0.2) - : Colors.black.withValues(alpha: 0.05), - blurRadius: 10, - offset: const Offset(0, 4), - ), - ], - ), - child: Column( - children: [ - Container( - width: 60.w, - height: 60.w, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(12.w), - border: Border.all( - color: Colors.grey, - ), - ), - child: Icon( - Icons.voice_chat, - size: 40.w, - ), - ), - Padding( - padding: EdgeInsets.only(top: 20.w, bottom: 10.w), - child: Text( - 'voiceCloneFirstMonthFree'.tr, - style: TextStyle( - color: isDarkMode ? Colors.white : Colors.black87, - fontSize: 18.sp, - fontWeight: FontWeight.bold, - ), - ), - ), - Text( - '使用声音复刻可为你生成专属音色档案,在配音、播报与对话中保留你的声音特征,适用于视频解说、虚拟助理、无障碍朗读等场景。', - textAlign: TextAlign.center, - style: TextStyle( - color: isDarkMode ? Colors.white : Colors.black87, - fontSize: 14.sp, - ), - ), - ], - ), - ), - Container( - padding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 2.w), - margin: EdgeInsets.only(bottom: 15.w), - decoration: BoxDecoration( - color: isDarkMode ? Colors.grey[800] : Colors.white, - borderRadius: BorderRadius.circular(12.w), - boxShadow: [ - BoxShadow( - color: isDarkMode - ? Colors.black.withValues(alpha: 0.2) - : Colors.black.withValues(alpha: 0.05), - blurRadius: 10, - offset: const Offset(0, 4), - ), - ], - ), - child: Obx( - () => Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - _buildSwitch( - isDarkMode, - 'voiceCloneEnable'.tr, - controller.isReplicating.value, - onChanged: (bool value) { - controller.isReplicating.value = value; - controller.enableVoiceFlocking(); - }, - ), - if (controller.isReplicating.value) _buildOpen(isDarkMode), - ], - ), - ), - ), - Obx( - () => controller.isReplicating.value - ? Container( - padding: - EdgeInsets.symmetric(horizontal: 12.w, vertical: 5.w), - margin: EdgeInsets.only(bottom: 15.w), - decoration: BoxDecoration( - color: isDarkMode ? Colors.grey[800] : Colors.white, - borderRadius: BorderRadius.circular(12.w), - boxShadow: [ - BoxShadow( - color: isDarkMode - ? Colors.black.withValues(alpha: 0.2) - : Colors.black.withValues(alpha: 0.05), - blurRadius: 10, - offset: const Offset(0, 4), - ), - ], - ), - child: Column( - children: [ - _buildSwitch( - isDarkMode, - 'AI全能助手开启', - controller.isAgent.value, - onChanged: (bool value) { - controller.isAgent.value = value; - }, - ), - _buildSwitch( - isDarkMode, - '同声翻译开启', - controller.isSimultaneous.value, - onChanged: (bool value) { - controller.isSimultaneous.value = value; - }, - ), - _buildSwitch( - isDarkMode, - '通话翻译开启', - controller.isCall.value, - onChanged: (bool value) { - controller.isCall.value = value; - }, - ), - _buildSwitch( - isDarkMode, - '面对面翻译开启', - controller.isFaceToFace.value, - onChanged: (bool value) { - controller.isFaceToFace.value = value; - }, - ), - ], - ), - ) - : const SizedBox.shrink(), - ), - ], - ); - } - - Widget _buildOpen(bool isDarkMode) { - return Container( - padding: EdgeInsets.symmetric(vertical: 10.w), - child: controller.speakerProfileId.value.isNotEmpty - ? Text( - '个人语音ID:\n${controller.speakerProfileId.value}', - style: TextStyle( - color: isDarkMode ? Colors.white : Colors.grey, - fontSize: 14.sp, - ), - ) - : GestureDetector( - onTap: () { - Get.bottomSheet( - const RecorderBottomSheet(), - isScrollControlled: true, - backgroundColor: - isDarkMode ? Colors.grey[800] : Colors.grey[100], - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.vertical( - top: Radius.circular(12.r), - ), - ), - ); - }, - child: Container( - padding: EdgeInsets.symmetric( - horizontal: 12.w, - vertical: 6.w, - ), - decoration: BoxDecoration( - color: Colors.blue.withValues(alpha: 0.1), - borderRadius: BorderRadius.circular(6.r), - border: Border.all( - color: Colors.blue.withValues(alpha: 0.3), - ), - ), - child: Text( - 'voiceCloneCreate'.tr, - style: TextStyle( - fontSize: 14.sp, - color: Colors.blue, - fontWeight: FontWeight.w500, - ), - ), - ), - ), - ); - } - - Widget _buildSwitch( - bool isDarkMode, - String title, - bool value, { - Function(bool)? onChanged, - }) { - return Padding( - padding: EdgeInsets.symmetric(vertical: 2.w), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text( - title, - style: TextStyle( - color: isDarkMode ? Colors.white : Colors.black87, - fontSize: 16.sp, - ), - ), - Transform.scale( - scale: 0.8, - alignment: Alignment.centerRight, - child: Switch( - value: value, - onChanged: onChanged, - ), - ), - ], - ), - ); - } -} diff --git a/apps/client/lib/routes/app_pages.dart b/apps/client/lib/routes/app_pages.dart index f049ce78..fbfe8310 100644 --- a/apps/client/lib/routes/app_pages.dart +++ b/apps/client/lib/routes/app_pages.dart @@ -36,8 +36,6 @@ import '../modules/profile/views/profile_meeting_view.dart'; import '../modules/profile/views/profile_view.dart'; import '../modules/splash/bindings/splash_binding.dart'; import '../modules/splash/views/splash_view.dart'; -import '../modules/voice_replication/bindings/voice_replication_binding.dart'; -import '../modules/voice_replication/views/voice_replication_view.dart'; import '../modules/bes_test/bindings/bes_test_binding.dart'; import '../modules/module_registry.dart'; import '../modules/bes_test/views/bes_test_view.dart'; @@ -84,8 +82,6 @@ abstract class AppPages { binding: ProfileBinding()), _page(Routes.profileMeeting, () => ProfileMeetingView(), binding: ProfileBinding()), - _page(Routes.voiceReplication, () => const VoiceReplicationView(), - binding: VoiceReplicationBinding()), _page(Routes.feedback, () => const FeedbackView(), binding: FeedbackBinding()), _page(Routes.logExport, () => const LogExportView(), diff --git a/apps/client/lib/routes/app_routes.dart b/apps/client/lib/routes/app_routes.dart index ab0503e5..899c3733 100644 --- a/apps/client/lib/routes/app_routes.dart +++ b/apps/client/lib/routes/app_routes.dart @@ -29,7 +29,6 @@ abstract class Routes { static const fieldRecording = '/field_recording'; // 现场录音 // 设置 - static const voiceReplication = '/voice_replication'; // 声音复刻 static const permissions = '/permissions'; // 权限管理 static const logExport = '/log_export'; // 日志导出 static const feedback = '/feedback'; // 用户反馈 diff --git a/apps/client/preview/yidong.html b/apps/client/preview/yidong.html deleted file mode 100644 index c8be59f7..00000000 --- a/apps/client/preview/yidong.html +++ /dev/null @@ -1,563 +0,0 @@ - - - - - -移动精灵 UI 预览 - - - - - -
-

① 文本输入模式

-
-
- ‹ -
晓
- 移动精灵 - 空闲 -
-
-
-
晓
-
移动精灵
-
点击右下角按钮,即可与晓晓对话
-
-
-
-
- -
- - -
- -
-
-
-
- - -
-

② 语音模式 - 按住说话

-
-
- ‹ -
晓
- 移动精灵 - 空闲 -
-
-
-
晓
晓晓
-
你好!我是晓晓,有什么可以帮你的吗?
- 14:23 -
-
-
-
- -
按住 说话
- -
-
-
-
- - -
-

③ 按住说话 - 连接中(同空闲样式)

-
-
- ‹ -
晓
- 移动精灵 - 连接中… -
-
-
-
晓
晓晓
-
你好!我是晓晓,有什么可以帮你的吗?
- 14:23 -
-
-
-
- -
-
- 连接中... -
- -
-
-
-
- - -
-

④ 按住说话 - 录音中(橙色)

-
-
- ‹ -
晓
- 移动精灵 - 识别中 -
-
-
-
晓
晓晓
-
你好!我是晓晓,有什么可以帮你的吗?
- 14:23 -
-
-
- -
今天天气怎么样?
-
- -
-
- 松开发送 · 2s -
- -
-
-
-
- - -
-

⑤ AI 思考中(输入栏禁用)

-
-
- ‹ -
晓
- 移动精灵 - 处理中 -
-
-
-
晓
晓晓
-
你好!我是晓晓,有什么可以帮你的吗?
- 14:23 -
-
-
今天天气怎么样?
- 14:24 -
-
-
-
-
- AI 思考中... -
-
- -
按住 说话
- -
-
-
-
- - -
-

⑥ AI 播报中(可打断)

-
-
- ‹ -
晓
- 移动精灵 - 朗读中 -
-
-
-
今天天气怎么样?
- 14:24 -
-
-
晓
晓晓
-
今天晴天,气温 18°C,微风,空气质量优,很适合出行哦
- 14:24 -
-
-
-
-
- 晓晓正在朗读... - -
-
- -
按住 说话
- -
-
-
-
- - -
-

⑦ 通话模式 - 等待说话

-
-
- ‹ -
晓
- 移动精灵 - 通话中 01:23 -
-
-
-
今天天气怎么样?
- 14:24 -
-
-
晓
晓晓
-
今天晴天,气温 18°C,微风,空气质量优
- 14:24 -
-
-
-
-
-
- 通话中 - 01:23 -
- -
-
-
-
-
-
-
- - -
-
-
-
- - -
-

⑧ 通话模式 - AI 播报

-
-
- ‹ -
晓
- 移动精灵 - 朗读中 01:48 -
-
-
-
Flutter 有什么优势?
- 14:41 -
-
-
晓
晓晓
-
Flutter 的核心优势在于跨平台能力强、渲染性能高,以及 Dart 语言的高效开发体验...
- 14:41 -
-
-
-
-
- 晓晓正在朗读... - -
-
-
-
- 通话中 - 01:48 -
-
-
-
-
-
-
-
- -
-
-
-
- - - diff --git a/apps/client/pubspec.lock b/apps/client/pubspec.lock index 1dbdf8c2..46c9e5d9 100644 --- a/apps/client/pubspec.lock +++ b/apps/client/pubspec.lock @@ -781,14 +781,6 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "5.9.3" - flutter_shaders: - dependency: "direct main" - description: - name: flutter_shaders - sha256: "1cf98f699701b520ed029c144f22c478c1f37f5784a4789b61d4fdbe95350a56" - url: "https://pub.flutter-io.cn" - source: hosted - version: "0.0.6" flutter_spinkit: dependency: transitive description: @@ -805,14 +797,6 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "0.7.0" - flutter_svg: - dependency: "direct main" - description: - name: flutter_svg - sha256: "35882981abcbfb8c15b286f0cd690ff25bac12d95eff3e25ee207f37d4c42e7f" - url: "https://pub.flutter-io.cn" - source: hosted - version: "2.3.0" flutter_test: dependency: "direct dev" description: flutter @@ -826,14 +810,6 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "3.0.1" - flutter_tts: - dependency: "direct main" - description: - name: flutter_tts - sha256: ce5eb209b40e95f2f4a1397116c87ab2fcdff32257d04ed7a764e75894c03775 - url: "https://pub.flutter-io.cn" - source: hosted - version: "4.2.5" flutter_web_plugins: dependency: transitive description: flutter @@ -1271,7 +1247,7 @@ packages: source: hosted version: "1.7.8" markdown: - dependency: "direct main" + dependency: transitive description: name: markdown sha256: ee85086ad7698b42522c6ad42fe195f1b9898e4d974a1af4576c1a3a176cada9 @@ -1509,14 +1485,6 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "0.15.0" - pip: - dependency: "direct main" - description: - name: pip - sha256: e99bf7dfc0fcbc49128314fc4307c79b93cee9f7b45795319a03f3e22e71d7f4 - url: "https://pub.flutter-io.cn" - source: hosted - version: "0.0.4" platform: dependency: transitive description: @@ -1856,21 +1824,13 @@ packages: source: hosted version: "1.4.1" synchronized: - dependency: "direct main" + dependency: transitive description: name: synchronized sha256: "63896c27e81b28f8cb4e69ead0d3e8f03f1d1e5fc531a3e579cabed6a2c7c9e5" url: "https://pub.flutter-io.cn" source: hosted version: "3.4.0+1" - tencentcloud_cos_sdk_plugin: - dependency: "direct main" - description: - name: tencentcloud_cos_sdk_plugin - sha256: a5333b6ec3ee7d2b8a031154ca559b3124743a4982838d589f3f4b3bfb15f8be - url: "https://pub.flutter-io.cn" - source: hosted - version: "1.2.8" term_glyph: dependency: transitive description: @@ -1997,30 +1957,6 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "4.6.0" - vector_graphics: - dependency: transitive - description: - name: vector_graphics - sha256: "9d0e3b9cb16542ad660daee871e726a10d13a93b7b5391677c3160e8f5e83935" - url: "https://pub.flutter-io.cn" - source: hosted - version: "1.2.3" - vector_graphics_codec: - dependency: transitive - description: - name: vector_graphics_codec - sha256: "99fd9fbd34d9f9a32efd7b6a6aae14125d8237b10403b422a6a6dfeac2806146" - url: "https://pub.flutter-io.cn" - source: hosted - version: "1.1.13" - vector_graphics_compiler: - dependency: transitive - description: - name: vector_graphics_compiler - sha256: "4dca4feb77dc3ec7f6e27e49c53241eb8217f55e4f9b12599a27f8903bca5682" - url: "https://pub.flutter-io.cn" - source: hosted - version: "1.3.0" vector_math: dependency: transitive description: diff --git a/apps/client/pubspec.yaml b/apps/client/pubspec.yaml index 7617d37c..4fef5c57 100644 --- a/apps/client/pubspec.yaml +++ b/apps/client/pubspec.yaml @@ -17,7 +17,6 @@ dependencies: flutter_localizations: sdk: flutter cupertino_icons: ^1.0.6 - flutter_shaders: ^0.0.6 get: ^4.7.2 in_app_purchase: ^3.3.0 @@ -29,7 +28,6 @@ dependencies: path_provider: ^2.1.5 audio_session: ^0.1.18 flutter_markdown: ^0.7.7+1 - markdown: ^7.1.1 fleather: 1.26.0 parchment: ^1.25.1 htmltopdfwidgets: ^1.1.0 @@ -38,11 +36,9 @@ dependencies: permission_handler: ^12.0.1 web_socket_channel: ^2.4.0 flutter_dotenv: ^5.1.0 - synchronized: ^3.1.0 intl: ^0.20.2 lunar: ^1.7.2 # 农历/节日(首页日历面板) crypto: ^3.0.3 - flutter_tts: ^4.2.2 logger: ^2.0.2+1 flutter_blue_plus: ^1.35.5 just_audio: ^0.9.36 @@ -51,7 +47,6 @@ dependencies: package_info_plus: ^8.3.0 file_picker: ^10.2.0 haptic_feedback: ^0.5.1+1 - tencentcloud_cos_sdk_plugin: 1.2.8 photo_view: ^0.15.0 window_size: git: @@ -72,7 +67,6 @@ dependencies: audio_waveforms: ^1.3.0 font_awesome_flutter: ^10.8.0 lottie: ^3.3.1 - flutter_svg: ^2.0.10+1 app_settings: 5.2.0 fluwx: ^5.7.1 @@ -103,7 +97,6 @@ dependencies: dio: ^5.8.0+1 sqflite: ^2.4.2 path: ^1.9.1 - pip: ^0.0.3 connectivity_plus: ^6.1.5 # 网络连接检测依赖 wakelock_plus: ^1.2.8 # 固件升级期间保持屏幕常亮 speech: @@ -170,30 +163,17 @@ dev_dependencies: flutter: uses-material-design: true - shaders: - - shaders/mic_flow.frag assets: # - assets/images/headphone_light.png # - assets/images/headphone_dark.png - - assets/images/robot_light.png - - assets/images/glasses_light.png - - assets/images/agents/ - - assets/images/explore.png - - assets/images/explore1.png - - assets/images/explore2.jpg - assets/images/mine-background.png - assets/images/app_icon.png - assets/fonts/NotoSansSC-Regular.ttf - assets/lottie/ - assets/js/ - assets/audio/silence_1s.wav - - assets/images/defaultPicture.png - - assets/images/defaultPicture.jpg # 设备品类实拍图(「添加设备 → 选择设备」页和设备页展示用) - assets/images/devices/ - - assets/images/qqmusic.png - - assets/images/music.png - - assets/weather/ - .env - .mcp.json diff --git a/apps/client/shaders/mic_flow.frag b/apps/client/shaders/mic_flow.frag deleted file mode 100644 index 0b462df5..00000000 --- a/apps/client/shaders/mic_flow.frag +++ /dev/null @@ -1,70 +0,0 @@ -// shaders/dialog_wave_core.frag -#version 300 es -precision highp float; - -#include - -uniform vec2 u_resolution; // setFloat(0, w) & (1, h) -uniform float u_time; // setFloat(2, t) -uniform float u_amp; // setFloat(3, amp) —— 建议传音量 RMS - -out vec4 fragColor; - -// ─────────── Noise Helpers ─────────── -float hash(vec2 p){return fract(sin(dot(p,vec2(127.1,311.7)))*43758.545);} -float noise(vec2 p){ - vec2 i=floor(p), f=fract(p); - vec2 u=f*f*(3.0-2.0*f); - return mix( - mix(hash(i), hash(i+vec2(1,0)),u.x), - mix(hash(i+vec2(0,1)), hash(i+vec2(1,1)),u.x),u.y); -} -float fbm(vec2 p){ - float a=.5, v=0.; - mat2 m=mat2(1.6,1.2,-1.2,1.6); - for(int i=0;i<3;i++){ - v+=a*noise(p); p=m*p*1.6; a*=.55; - } - return v; -} - -// ─────────── Palette ─────────── -vec3 palette(float t){ - vec3 deep = vec3(0.05,0.10,0.30); // 靛蓝 - vec3 mid = vec3(0.15,0.00,0.55); // 暗紫 - vec3 glow = vec3(0.00,0.60,1.00); // 电蓝 - return mix(deep, mix(mid, glow, t*t), t); // t² 让亮部偏蓝 -} - -void main(){ - // ① 归一化到 [-1,1](保持比例) - vec2 uv = (FlutterFragCoord().xy / u_resolution)*2.0 - 1.0; - uv.x *= u_resolution.x / u_resolution.y; - float r = length(uv); // 半径 0~√2 - - // ② “呼吸”——音量驱动整体缩放(amp ∈ [0,1]) - float breath = 1.0 - (.08 + .05*u_amp) * sin(u_time*1.5); - vec2 p = uv / breath; // 越大越收缩 - p *= 3.0; // 纹理密度 - p += u_time * 0.35; // 缓慢横移 - - // ③ 旋转扭曲 + fBm 云雾 - float angle = atan(p.y,p.x) + 0.25*r; // 小角度漩涡 - float radius = length(p); - vec2 q = vec2(cos(angle),sin(angle))*radius; - float n = fbm(q) * .7 + fbm(q*2.0) * .3; - n = smoothstep(.3,.7,n); - - vec3 col = palette(n); - - // ④ 亮度脉冲(随 amp 加强) - col += (.05 + .08*u_amp) * sin(u_time*2.0 + n*6.0); - - // ⑤ 外环光晕(amp 加深) - float halo = smoothstep(.55,.05,r) * (0.15 + 0.5*u_amp); - col += halo; - - // ⑥ 羽化:可见区半径 ≈ 0.96 -float alpha = step(r, 0.75); -fragColor = vec4(col, alpha); -} \ No newline at end of file diff --git a/apps/client/shaders/mic_flow2.frag b/apps/client/shaders/mic_flow2.frag deleted file mode 100644 index 63e23dfe..00000000 --- a/apps/client/shaders/mic_flow2.frag +++ /dev/null @@ -1,67 +0,0 @@ -// shaders/mic_flow.frag -#version 300 es -precision highp float; - -#include - -uniform vec2 u_resolution; // 由 FlutterShaders 自动注入 -uniform float u_time; // AnimationController -> setFloat(2, ...) -uniform float u_amp; // 可选:实时音量 (0~1),建议 setFloat(3, rms) - -out vec4 fragColor; - -// ——— 经典 hash & noise ——— -float hash(vec2 p) { - return fract(sin(dot(p, vec2(127.1,311.7))) * 43758.5453123); -} -float noise(vec2 p) { - vec2 i = floor(p), f = fract(p); - vec2 u = f * f * (3.0 - 2.0 * f); - return mix(mix(hash(i), hash(i + vec2(1.0,0.0)), u.x), - mix(hash(i + vec2(0.0,1.0)), hash(i + vec2(1.0,1.0)), u.x), - u.y); -} -// fBm:3-oct & 微 Domain Warp -float fbm(vec2 p) { - float sum = 0.0, amp = 0.5; - mat2 m = mat2(1.6, 1.2, - -1.2, 1.6); // 轻微旋转,防止轴纹 - for (int i = 0; i < 3; ++i) { - sum += amp * noise(p); - p = m * p * 1.6; - amp *= 0.55; - } - return sum; -} - -// 调色盘:深蓝 → 云白 -vec3 palette(float t) { - vec3 deep = vec3(0.08, 0.42, 1.00); - vec3 light= vec3(0.94, 0.98, 1.00); - return mix(deep, light, t); -} - -void main() { - // 0‒1 -> -0.5‒0.5,保持圆心在 Shader 0,0 - vec2 uv = (FlutterFragCoord().xy / u_resolution) - .5; - - // 呼吸缩放(≈ 0.92‒1.08) - float breath = 1.0 + (0.05 + 0.03 * u_amp) * sin(u_time * 1.4); - vec2 p = uv * 3.2 / breath; // 越大云越细腻 - p += u_time * 0.35; // 横向漂移 - - // 多层 fBm + 微距 domain-warp - float n = fbm(p) * 0.65 + fbm(p * 2.0 + vec2(5.2)) * 0.35; - float t = smoothstep(0.32, 0.68, n); // 阈值决定明暗分布 - vec3 col= palette(t); - - // ─── 边缘羽化 ─── - float r = length(uv); // 半径 0-0.5 - float alpha = smoothstep(0.48, 0.46, r); // 92% 处开始衰减 - - // 轻量亮度脉冲:让中心更有“呼吸”感 - float pulse = 0.04 * sin(u_time * 2.0 + n * 4.0); - col += pulse; - - fragColor = vec4(col, alpha); -} \ No newline at end of file diff --git a/apps/proto/google/protobuf/any.proto b/apps/proto/google/protobuf/any.proto deleted file mode 100644 index e2c2042f..00000000 --- a/apps/proto/google/protobuf/any.proto +++ /dev/null @@ -1,158 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -syntax = "proto3"; - -package google.protobuf; - -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; -option go_package = "google.golang.org/protobuf/types/known/anypb"; -option java_package = "com.google.protobuf"; -option java_outer_classname = "AnyProto"; -option java_multiple_files = true; -option objc_class_prefix = "GPB"; - -// `Any` contains an arbitrary serialized protocol buffer message along with a -// URL that describes the type of the serialized message. -// -// Protobuf library provides support to pack/unpack Any values in the form -// of utility functions or additional generated methods of the Any type. -// -// Example 1: Pack and unpack a message in C++. -// -// Foo foo = ...; -// Any any; -// any.PackFrom(foo); -// ... -// if (any.UnpackTo(&foo)) { -// ... -// } -// -// Example 2: Pack and unpack a message in Java. -// -// Foo foo = ...; -// Any any = Any.pack(foo); -// ... -// if (any.is(Foo.class)) { -// foo = any.unpack(Foo.class); -// } -// -// Example 3: Pack and unpack a message in Python. -// -// foo = Foo(...) -// any = Any() -// any.Pack(foo) -// ... -// if any.Is(Foo.DESCRIPTOR): -// any.Unpack(foo) -// ... -// -// Example 4: Pack and unpack a message in Go -// -// foo := &pb.Foo{...} -// any, err := anypb.New(foo) -// if err != nil { -// ... -// } -// ... -// foo := &pb.Foo{} -// if err := any.UnmarshalTo(foo); err != nil { -// ... -// } -// -// The pack methods provided by protobuf library will by default use -// 'type.googleapis.com/full.type.name' as the type URL and the unpack -// methods only use the fully qualified type name after the last '/' -// in the type URL, for example "foo.bar.com/x/y.z" will yield type -// name "y.z". -// -// -// JSON -// -// The JSON representation of an `Any` value uses the regular -// representation of the deserialized, embedded message, with an -// additional field `@type` which contains the type URL. Example: -// -// package google.profile; -// message Person { -// string first_name = 1; -// string last_name = 2; -// } -// -// { -// "@type": "type.googleapis.com/google.profile.Person", -// "firstName": , -// "lastName": -// } -// -// If the embedded message type is well-known and has a custom JSON -// representation, that representation will be embedded adding a field -// `value` which holds the custom JSON in addition to the `@type` -// field. Example (for message [google.protobuf.Duration][]): -// -// { -// "@type": "type.googleapis.com/google.protobuf.Duration", -// "value": "1.212s" -// } -// -message Any { - // A URL/resource name that uniquely identifies the type of the serialized - // protocol buffer message. This string must contain at least - // one "/" character. The last segment of the URL's path must represent - // the fully qualified name of the type (as in - // `path/google.protobuf.Duration`). The name should be in a canonical form - // (e.g., leading "." is not accepted). - // - // In practice, teams usually precompile into the binary all types that they - // expect it to use in the context of Any. However, for URLs which use the - // scheme `http`, `https`, or no scheme, one can optionally set up a type - // server that maps type URLs to message definitions as follows: - // - // * If no scheme is provided, `https` is assumed. - // * An HTTP GET on the URL must yield a [google.protobuf.Type][] - // value in binary format, or produce an error. - // * Applications are allowed to cache lookup results based on the - // URL, or have them precompiled into a binary to avoid any - // lookup. Therefore, binary compatibility needs to be preserved - // on changes to types. (Use versioned type names to manage - // breaking changes.) - // - // Note: this functionality is not currently available in the official - // protobuf release, and it is not used for type URLs beginning with - // type.googleapis.com. - // - // Schemes other than `http`, `https` (or the empty scheme) might be - // used with implementation specific semantics. - // - string type_url = 1; - - // Must be a valid serialized protocol buffer of the above specified type. - bytes value = 2; -} diff --git a/deploy/admin/env/dev.env.example b/deploy/admin/env/dev.env.example deleted file mode 100644 index 22ea82c5..00000000 --- a/deploy/admin/env/dev.env.example +++ /dev/null @@ -1,10 +0,0 @@ -# admin 服务 · dev 开发环境(复制为 dev.env 后填写真实值) -# 仓库地址 REGISTRY 已写死在 deploy.sh,这里不填 -TAG=dev -PLATFORM=linux/amd64 -DOCKER_NETWORK=yunyan-net -ADMIN_PORT=3000 -CONSOLE_BACKEND=http://yunyan-console:8080 - -# 部署目标(DEPLOY_HOST/USER/KEY/DIR)与仓库凭据(REGISTRY_USER/PASS)已写死在 -# deploy.sh 顶部的 deploy_profile(dev 段),不在此文件填。 diff --git a/deploy/admin/env/local.env.example b/deploy/admin/env/local.env.example deleted file mode 100644 index 31547f4f..00000000 --- a/deploy/admin/env/local.env.example +++ /dev/null @@ -1,8 +0,0 @@ -# admin 服务 · local 本机环境(复制为 local.env 后使用) -# 仓库地址 REGISTRY 已写死在 deploy.sh,这里不填 -TAG=latest -PLATFORM=linux/amd64 -DOCKER_NETWORK=1panel-network -ADMIN_PORT=3000 -# 连接同网络的 console 服务(容器名);若 console 不在同机/同网络,填其可达地址 -CONSOLE_BACKEND=http://yunyan-console:8080 diff --git a/deploy/admin/env/prod.env.example b/deploy/admin/env/prod.env.example deleted file mode 100644 index 2a7577c8..00000000 --- a/deploy/admin/env/prod.env.example +++ /dev/null @@ -1,10 +0,0 @@ -# admin 服务 · prod 生产环境(复制为 prod.env 后填写真实值) -# 仓库地址 REGISTRY 已写死在 deploy.sh,这里不填 -TAG=latest # 生产建议固定版本号,如 v1.2.0 -PLATFORM=linux/amd64 -DOCKER_NETWORK=yunyan-net -ADMIN_PORT=3000 -CONSOLE_BACKEND=http://yunyan-console:8080 - -# 部署目标(DEPLOY_HOST/USER/KEY/DIR)与仓库凭据(REGISTRY_USER/PASS)已写死在 -# deploy.sh 顶部的 deploy_profile(prod 段),不在此文件填。