Reland Implement Skottie vs Lottie perf tool

Add PerfActivity to Skottie demo app, which can render
with both Lottie and Skottie players. Create bash script, which
runs 15 lottie files with both renderers, runs perfetto and
outputs performance metrics in json files.

Test: ran run_perf.sh and it outputs perf metrics on WearOS and Android
Change-Id: I6bdd86629284ac5c461cf2f5ee537e0495a72bd2
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/298980
Reviewed-by: Derek Sollenberger <djsollen@google.com>
Commit-Queue: Stan Iliev <stani@google.com>
This commit is contained in:
Stan Iliev 2020-06-26 04:35:08 -04:00 committed by Skia Commit-Bot
parent fe7794d4ba
commit c0ab92c52f
20 changed files with 458 additions and 19 deletions

View File

@ -9,6 +9,8 @@ apply plugin: 'com.android.application'
dependencies {
implementation project("skottielib")
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation 'com.airbnb.android:lottie:3.4.1'
}
android {

View File

@ -0,0 +1,7 @@
# Copyright 2020 Google Inc.
#
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
cat ./perfetto_config.pb | adb shell perfetto -c - -o /data/misc/perfetto-traces/trace.pb
adb pull /data/misc/perfetto-traces/trace.pb trace

Binary file not shown.

View File

@ -0,0 +1,59 @@
# Copyright 2020 Google Inc.
#
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
#!/bin/bash
mkdir -p out
# download perfetto trace_processor
if [ ! -f "trace_processor" ]; then
wget https://get.perfetto.dev/trace_processor
chmod +x trace_processor
fi
declare -a testnames=("movie_loading" "uk" "white_material_wave_loading"
"check_animation" "confetti" "gears"
"hand_sanitizer" "heart_preloader" "i_was_scared_after_that_brouhaha"
"im_thirsty" "true_will" "workout_monkey_stay_healthy"
"ripple_loading_animation" "signature" "asdasd")
adb root
# get out of the lock screen
adb shell input keyevent MENU
adb shell input keyevent MENU
adb shell setprop persist.traced.enable 1
adb shell setenforce 0
adb shell setprop debug.egl.traceGpuCompletion 1
adb shell am force-stop org.skia.skottie
renderer_names=(lottie_hw lottie_sw skottie)
# iterate over lottie HW and skottie renderers
for renderer in {0,2}
do
echo "renderer " ${renderer_names[${renderer}]}
# iterate over each of the 15 lottie files
for file in {0..14}
do
if [[ $1 == "delay" ]]; then
# start program first and wait 7 seconds for program to load fully
echo "waiting to show file " ${file} " " ${testnames[$file]}
adb shell am start -n org.skia.skottie/.PerfActivity --ei renderer ${renderer} --ei file ${file}
sleep 7
./collect.sh
else
# start perfetto first (before the app) to give it a chance to capture startup metrics/shader compile and first frame rendering
./collect.sh &
perfetto_pid=$!
# give one second for the perfetto script to start
sleep 1
echo "show file " ${file} " " ${testnames[$file]}
adb shell am start -n org.skia.skottie/.PerfActivity --ei renderer ${renderer} --ei file ${file}
#wait for perfetto to finish (~10s)
wait $perfetto_pid
fi
adb shell am force-stop org.skia.skottie
./trace_processor --run-metrics=skottie_metric.sql --metrics-output=json trace > out/data_${renderer_names[${renderer}]}_${file}_${testnames[$file]}.json
mv trace out/trace_${renderer_names[${renderer}]}_${file}_${testnames[$file]}
done
done
echo All done

View File

@ -0,0 +1,61 @@
syntax = "proto2";
package perfetto.protos;
import "protos/perfetto/metrics/metrics.proto";
import "protos/perfetto/metrics/android/hwui_metric.proto";
// Android HWUI graphics performance and graphics memory usage metrics augmented with
// perf data which is specific to the Skottie player. Skottie app has an additional
// render thread named "SkottieAnimator" in the traces. Perf metrics are filtered for
// 'org.skia.skottie' process only.
message ProcessRenderInfoEx {
// original HWUI metric as defined by built-in perfetto proto.
optional ProcessRenderInfo hwui_process_info = 1;
// Number of times the Skottie GL thread rendered a frame and max/min/avg time for Skottie GL
// renderer to finish rendering in
// in nanoseconds. These values have 0 value for lottie player, because it does it renders only
// in RenderThread.
optional uint32 skottie_animator_count = 2;
optional int64 skottie_animator_max = 3;
optional int64 skottie_animator_min = 4;
optional double skottie_animator_avg = 5;
optional uint32 dequeue_buffer_count = 6;
optional int64 dequeue_buffer_max = 7;
optional int64 dequeue_buffer_min = 8;
optional double dequeue_buffer_avg = 9;
// The following 2 fields are useful to compare render thread performance between Lottie and
// Skottie players.
// Skottie metric is a sum of the time on RenderThread and SkottieAnimator threads, while Lottie
// is only the time on RenderThread.
optional double render_time_avg = 10; // draw_frame_avg + skottie_animator_avg
// "render_time_avg_no_dequeue" tries to compensate the time spent to wait for a new buffer.
// It equals draw_frame_avg + skottie_animator_avg - dequeue_buffer_avg.
optional double render_time_avg_no_dequeue = 11;
optional int64 ui_thread_cpu_time = 12; // CPU time spent on UI thread in nanoseconds
optional int64 rt_thread_cpu_time = 13; // CPU time spent on RenderThread in nanoseconds
optional int64 hwui_tasks_cpu_time = 14; // CPU time spent on hwuiTask0/1 threads in nanoseconds
optional int64 skottie_animator_cpu_time = 15; // CPU time spent on SkottieAnimator in ns
optional int64 total_cpu_time = 16; // Total CPU time in nanoseconds. Equals
// ui_thread_cpu_time + rt_thread_cpu_time + skottie_animator_cpu_time + hwui_tasks_cpu_time
optional int64 total_gpu_time = 17; // GPU time spent to render all content in nanoseconds.
// This one number is the "ultimate" benchmark to compare airbnb lottie vs skottie player.
// performance. It is the total time for any rendering related work on CPU and GPU combined.
optional int64 total_time = 18; // This is total_cpu_time + total_gpu_time in nanoseconds.
}
message SkottieMetric {
repeated ProcessRenderInfoEx process_info = 1;
}
extend TraceMetrics {
optional SkottieMetric skottie_metric = 460;
}

View File

@ -0,0 +1,217 @@
SELECT RUN_METRIC('android/android_hwui_metric.sql');
CREATE VIEW dequeue_buffer AS
SELECT
count(*) as dequeue_buffer_count,
max(dur) as dequeue_buffer_max,
min(dur) as dequeue_buffer_min,
avg(dur) as dequeue_buffer_avg,
sum(dur) as dequeue_buffer_sum,
thread_track.utid as render_thread_id
FROM slice
INNER JOIN thread_track ON (thread_track.id = slice.track_id)
WHERE slice.name='dequeueBuffer' AND slice.dur >= 0
GROUP BY thread_track.utid;
CREATE VIEW skottie_animator AS
SELECT
count(*) as skottie_animator_count,
max(dur) as skottie_animator_max,
min(dur) as skottie_animator_min,
avg(dur) as skottie_animator_avg,
sum(dur) as skottie_animator_sum,
thread.upid as process_upid
FROM slice
INNER JOIN thread_track ON (thread_track.id = slice.track_id)
INNER JOIN thread ON (thread.name='SkottieAnimator' AND thread.utid = thread_track.utid)
WHERE slice.name='Choreographer#doFrame' AND slice.dur >= 0
GROUP BY thread_track.utid;
CREATE VIEW total_cpu_time AS
SELECT
sum(sched_slice.dur) as cpu_time,
thread.upid as process_upid
FROM sched_slice
INNER JOIN process ON (process.upid = thread.upid)
INNER JOIN thread ON (
(thread.name LIKE 'hwuiTask%' OR thread.name=substr(process.name,-15) OR thread.name LIKE '%skottie' OR thread.name='RenderThread' OR thread.name='SkottieAnimator')
AND thread.utid = sched_slice.utid
)
WHERE sched_slice.dur >= 0
GROUP BY thread.upid;
CREATE VIEW cpu_time_rt_hwui_tasks AS
SELECT
sum(sched_slice.dur) as cpu_time,
thread.upid as process_upid
FROM sched_slice
INNER JOIN thread ON (thread.name LIKE 'hwuiTask%' AND thread.utid = sched_slice.utid)
WHERE sched_slice.dur >= 0
GROUP BY thread.upid;
CREATE VIEW cpu_time_ui_thread AS
SELECT
sum(sched_slice.dur) as cpu_time,
thread.upid as process_upid
FROM sched_slice
INNER JOIN process ON (process.upid = thread.upid)
INNER JOIN thread ON ((thread.name=substr(process.name,-15) OR thread.name LIKE '%skottie') AND thread.utid = sched_slice.utid)
WHERE sched_slice.dur >= 0
GROUP BY thread.upid;
CREATE VIEW cpu_time_rt AS
SELECT
sum(sched_slice.dur) as cpu_time,
thread.upid as process_upid
FROM sched_slice
INNER JOIN thread ON (thread.name='RenderThread' AND thread.utid = sched_slice.utid)
WHERE sched_slice.dur >= 0
GROUP BY thread.upid;
CREATE VIEW cpu_time_skottie_animator AS
SELECT
sum(sched_slice.dur) as cpu_time,
thread.upid as process_upid
FROM sched_slice
INNER JOIN thread ON (thread.name='SkottieAnimator' AND thread.utid = sched_slice.utid)
WHERE sched_slice.dur >= 0
GROUP BY thread.upid;
CREATE VIEW hwui_gpu_completion2 AS
SELECT
count(*) as gpu_completion_count,
max(dur) as gpu_completion_max,
min(dur) as gpu_completion_min,
avg(dur) as gpu_completion_avg,
sum(dur) as gpu_completion_sum,
thread.upid as process_upid
FROM slice
INNER JOIN thread_track ON (thread_track.id = slice.track_id)
INNER JOIN thread ON (thread.name='GPU completion' AND thread.utid = thread_track.utid)
WHERE slice.name LIKE 'waiting for GPU completion%' AND slice.dur >= 0
GROUP BY thread_track.utid;
CREATE VIEW hwui_gpu_completion3 AS
SELECT
sum(dur) as gpu_completion_sum,
thread.upid as process_upid
FROM slice
INNER JOIN thread_track ON (thread_track.id = slice.track_id)
INNER JOIN thread ON (thread.utid = thread_track.utid)
WHERE slice.name LIKE 'waiting for frame%' AND slice.dur >= 0
GROUP BY thread_track.utid;
CREATE VIEW skottie_metric_output AS
SELECT SkottieMetric(
'process_info', (
SELECT RepeatedField(
ProcessRenderInfoEx(
'hwui_process_info',
ProcessRenderInfo(
'process_name', process_name,
'rt_cpu_time_ms', rt_cpu_time_ms,
'draw_frame_count', hwui_draw_frame.draw_frame_count,
'draw_frame_max', hwui_draw_frame.draw_frame_max,
'draw_frame_min', hwui_draw_frame.draw_frame_min,
'draw_frame_avg', hwui_draw_frame.draw_frame_avg,
'flush_count', hwui_flush_commands.flush_count,
'flush_max', hwui_flush_commands.flush_max,
'flush_min', hwui_flush_commands.flush_min,
'flush_avg', hwui_flush_commands.flush_avg,
'prepare_tree_count', hwui_prepare_tree.prepare_tree_count,
'prepare_tree_max', hwui_prepare_tree.prepare_tree_max,
'prepare_tree_min', hwui_prepare_tree.prepare_tree_min,
'prepare_tree_avg', hwui_prepare_tree.prepare_tree_avg,
'gpu_completion_count', hwui_gpu_completion2.gpu_completion_count,
'gpu_completion_max', hwui_gpu_completion2.gpu_completion_max,
'gpu_completion_min', hwui_gpu_completion2.gpu_completion_min,
'gpu_completion_avg', hwui_gpu_completion2.gpu_completion_avg,
'ui_record_count', hwui_ui_record.ui_record_count,
'ui_record_max', hwui_ui_record.ui_record_max,
'ui_record_min', hwui_ui_record.ui_record_min,
'ui_record_avg', hwui_ui_record.ui_record_avg,
'shader_compile_count', hwui_shader_compile.shader_compile_count,
'shader_compile_time', hwui_shader_compile.shader_compile_time,
'shader_compile_avg', hwui_shader_compile.shader_compile_avg,
'cache_hit_count', hwui_cache_hit.cache_hit_count,
'cache_hit_time', hwui_cache_hit.cache_hit_time,
'cache_hit_avg', hwui_cache_hit.cache_hit_avg,
'cache_miss_count', hwui_cache_miss.cache_miss_count,
'cache_miss_time', hwui_cache_miss.cache_miss_time,
'cache_miss_avg', hwui_cache_miss.cache_miss_avg,
'graphics_cpu_mem_max', CAST(hwui_graphics_cpu_mem.graphics_cpu_mem_max as INT64),
'graphics_cpu_mem_min', CAST(hwui_graphics_cpu_mem.graphics_cpu_mem_min as INT64),
'graphics_cpu_mem_avg', hwui_graphics_cpu_mem.graphics_cpu_mem_avg,
'graphics_gpu_mem_max', CAST(hwui_graphics_gpu_mem.graphics_gpu_mem_max as INT64),
'graphics_gpu_mem_min', CAST(hwui_graphics_gpu_mem.graphics_gpu_mem_min as INT64),
'graphics_gpu_mem_avg', hwui_graphics_gpu_mem.graphics_gpu_mem_avg,
'texture_mem_max', CAST(hwui_texture_mem.texture_mem_max as INT64),
'texture_mem_min', CAST(hwui_texture_mem.texture_mem_min as INT64),
'texture_mem_avg', hwui_texture_mem.texture_mem_avg,
'all_mem_max', CAST(hwui_all_mem.all_mem_max as INT64),
'all_mem_min', CAST(hwui_all_mem.all_mem_min as INT64),
'all_mem_avg', hwui_all_mem.all_mem_avg
),
'skottie_animator_count', ifnull(skottie_animator.skottie_animator_count, 0),
'skottie_animator_max', ifnull(skottie_animator.skottie_animator_max, 0),
'skottie_animator_min', ifnull(skottie_animator.skottie_animator_min, 0),
'skottie_animator_avg', ifnull(skottie_animator.skottie_animator_avg, 0.0),
'dequeue_buffer_count', dequeue_buffer.dequeue_buffer_count,
'dequeue_buffer_max', dequeue_buffer.dequeue_buffer_max,
'dequeue_buffer_min', dequeue_buffer.dequeue_buffer_min,
'dequeue_buffer_avg', dequeue_buffer.dequeue_buffer_avg,
'render_time_avg', ifnull(skottie_animator.skottie_animator_avg, 0.0) + hwui_draw_frame.draw_frame_avg,
'render_time_avg_no_dequeue', ifnull(skottie_animator.skottie_animator_avg, 0.0) + hwui_draw_frame.draw_frame_avg - ifnull(dequeue_buffer.dequeue_buffer_avg, 0.0),
'ui_thread_cpu_time', ifnull(cpu_time_ui_thread.cpu_time, 0),
'rt_thread_cpu_time', ifnull(cpu_time_rt.cpu_time, 0),
'hwui_tasks_cpu_time', ifnull(cpu_time_rt_hwui_tasks.cpu_time, 0),
'skottie_animator_cpu_time', ifnull(cpu_time_skottie_animator.cpu_time, 0),
'total_cpu_time', ifnull(total_cpu_time.cpu_time, 0),
'total_gpu_time', ifnull(hwui_gpu_completion3.gpu_completion_sum, 0),
'total_time', ifnull(total_cpu_time.cpu_time, 0) + ifnull(hwui_gpu_completion3.gpu_completion_sum, 0)
)
)
FROM hwui_processes
LEFT JOIN hwui_draw_frame ON (hwui_draw_frame.render_thread_id = hwui_processes.render_thread_id)
LEFT JOIN hwui_flush_commands ON (hwui_flush_commands.render_thread_id = hwui_processes.render_thread_id)
LEFT JOIN hwui_prepare_tree ON (hwui_prepare_tree.render_thread_id = hwui_processes.render_thread_id)
LEFT JOIN hwui_gpu_completion2 ON (hwui_gpu_completion2.process_upid = hwui_processes.process_upid)
LEFT JOIN hwui_ui_record ON (hwui_ui_record.process_upid = hwui_processes.process_upid)
LEFT JOIN hwui_shader_compile ON (hwui_shader_compile.render_thread_id = hwui_processes.render_thread_id)
LEFT JOIN hwui_cache_hit ON (hwui_cache_hit.render_thread_id = hwui_processes.render_thread_id)
LEFT JOIN hwui_cache_miss ON (hwui_cache_miss.render_thread_id = hwui_processes.render_thread_id)
LEFT JOIN hwui_graphics_cpu_mem ON (hwui_graphics_cpu_mem.process_upid = hwui_processes.process_upid)
LEFT JOIN hwui_graphics_gpu_mem ON (hwui_graphics_gpu_mem.process_upid = hwui_processes.process_upid)
LEFT JOIN hwui_texture_mem ON (hwui_texture_mem.process_upid = hwui_processes.process_upid)
LEFT JOIN hwui_all_mem ON (hwui_all_mem.process_upid = hwui_processes.process_upid)
LEFT JOIN skottie_animator ON (skottie_animator.process_upid = hwui_processes.process_upid)
LEFT JOIN dequeue_buffer ON (dequeue_buffer.render_thread_id = hwui_processes.render_thread_id)
LEFT JOIN total_cpu_time ON (total_cpu_time.process_upid = hwui_processes.process_upid)
LEFT JOIN cpu_time_rt_hwui_tasks ON (cpu_time_rt_hwui_tasks.process_upid = hwui_processes.process_upid)
LEFT JOIN cpu_time_rt ON (cpu_time_rt.process_upid = hwui_processes.process_upid)
LEFT JOIN cpu_time_skottie_animator ON (cpu_time_skottie_animator.process_upid = hwui_processes.process_upid)
LEFT JOIN cpu_time_ui_thread ON (cpu_time_ui_thread.process_upid = hwui_processes.process_upid)
LEFT JOIN hwui_gpu_completion3 ON (hwui_gpu_completion3.process_upid = hwui_processes.process_upid)
JOIN (SELECT MAX(rt_cpu_time_ms), process_upid AS id FROM hwui_processes) max_render ON hwui_processes.process_upid = max_render.id
-- process name is often missing on WearOs/Android P -> instead select process is highest CPU time in RenderThread.
-- WHERE hwui_processes.process_name='org.skia.skottie'
)
);

View File

@ -1,23 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- BEGIN_INCLUDE(manifest) -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.skia.skottie"
android:versionCode="1"
android:versionName="1.0">
package="org.skia.skottie"
android:versionCode="1"
android:versionName="1.0">
<application
android:allowBackup="false"
android:theme="@android:style/Theme.Holo.Light"
android:name=".SkottieApplication"
android:label="Skottie">
<application
android:name=".SkottieApplication"
android:allowBackup="false"
android:label="Skottie"
android:theme="@android:style/Theme.Holo.Light">
<activity android:name=".PerfActivity" android:exported="true">
</activity>
<activity android:name=".SkottieActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
<activity android:name=".SkottieActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
<!-- END_INCLUDE(manifest) -->
</manifest>

View File

@ -0,0 +1,82 @@
package org.skia.skottie;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.Window;
import android.view.WindowManager;
import android.widget.TextView;
import com.airbnb.lottie.LottieAnimationView;
import com.airbnb.lottie.LottieDrawable;
import com.airbnb.lottie.RenderMode;
public class PerfActivity extends Activity {
int rawAssets[] = {
/*R.raw.star,*/ R.raw.movie_loading, R.raw.uk, R.raw.white_material_wave_loading,
R.raw.check_animation, R.raw.confetti, R.raw.gears,
R.raw.hand_sanitizer, R.raw.heart_preloader, R.raw.i_was_scared_after_that_brouhaha,
R.raw.im_thirsty, R.raw.true_will, R.raw.workout_monkey_stay_healthy,
R.raw.ripple_loading_animation, R.raw.signature, R.raw.asdasd
};
@Override
protected void onCreate(Bundle savedInstanceState) {
//Remove title bar
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
//Remove notification bar
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
super.onCreate(savedInstanceState);
// Run activity with:
// adb shell am start -n org.skia.skottie/.PerfActivity --ei renderer 0 --ei file 0
// renderer is 0 to 2, file is 0 to 14
Intent intent = getIntent();
int renderer = intent.getIntExtra("renderer", 0);
int file = intent.getIntExtra("file", 0);
if (file < 0 || file >= rawAssets.length) {
return;
}
switch (renderer) {
case 0:
// render with airbnb hardware lottie player
runLottie(rawAssets[file], true);
break;
case 1:
// render with airbnb software lottie player
runLottie(rawAssets[file], false);
break;
case 2:
// render with skottie player
runSkottie(rawAssets[file]);
break;
default:
break;
}
}
void runSkottie(int id) {
SkottieView view = new SkottieView(this);
view.setSource(getResources().openRawResource(id));
view.getSkottieAnimation().start();
setContentView(view);
}
void runLottie(int id, boolean useHardware) {
LottieAnimationView lottie = new LottieAnimationView(this);
lottie.setAnimation(id);
if (useHardware) {
lottie.setRenderMode(RenderMode.HARDWARE);
} else {
lottie.setRenderMode(RenderMode.SOFTWARE);
}
lottie.setRepeatMode(LottieDrawable.RESTART);
lottie.setRepeatCount(LottieDrawable.INFINITE);
lottie.playAnimation();
setContentView(lottie);
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
{"v":"5.5.7","meta":{"g":"LottieFiles AE 0.1.20","a":"","k":"","d":"","tc":""},"fr":60,"ip":0,"op":30,"w":300,"h":300,"nm":"All Preloaders","ddd":0,"assets":[{"id":"comp_0","layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[52.5,52.5,0],"ix":2},"a":{"a":0,"k":[0,0,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"hasMask":true,"masksProperties":[{"inv":false,"mode":"f","pt":{"a":0,"k":{"i":[[-0.29,-1.59],[0,0],[0.05,-0.31],[2.46,-4.273],[2.662,-2.965],[3.911,-3.417],[3.76,-2.82],[5.1,-3.65],[0.348,0.308],[4.37,3.33],[4.44,3.78],[4.382,5.881],[1.126,5.435],[0.23,1.22],[0,0],[-0.06,0.26],[-0.63,2],[-6.073,3.37],[-6.437,-1.191],[-4.197,-4.783],[-0.147,-0.317],[-0.85,0.79],[-10.845,-9.997],[-1.314,-5.331]],"o":[[0,0],[-0.07,0.3],[-0.629,4.89],[-2.075,3.401],[-3.414,3.914],[-3.59,3.12],[-5,3.76],[-0.348,0.308],[-4.49,-3.16],[-4.6,-3.51],[-5.586,-4.752],[-3.326,-4.444],[-0.35,-1.28],[0,0],[0.06,-0.26],[0.44,-2],[2.11,-6.618],[5.653,-3.301],[6.278,1.037],[0.206,0.282],[1.09,-1.09],[10.777,-10.07],[4.064,3.691],[0.44,1.53]],"v":[[50.5,-15.281],[50.5,-10.811],[50.3,-9.891],[45.62,3.989],[38.5,13.559],[27.5,24.569],[16.5,33.569],[1.2,44.509],[-0.02,44.509],[-13.49,34.999],[-26.93,23.999],[-41.93,7.999],[-48.69,-7.001],[-49.5,-10.671],[-49.5,-15.281],[-49.33,-16.051],[-47.98,-22.051],[-35.24,-37.601],[-16.5,-40.871],[-0.3,-31.871],[0.23,-30.971],[2.98,-33.691],[41.32,-33.821],[49.57,-19.981]],"c":true},"ix":1},"o":{"a":0,"k":100,"ix":3},"x":{"a":0,"k":0,"ix":4},"nm":"Mask 1"}],"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[126.336,126.336],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":20,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"gf","o":{"a":0,"k":100,"ix":10},"r":1,"bm":0,"g":{"p":2,"k":{"a":0,"k":[0,1,0,0.2235294117647059,1,1,0.6980392156862745,0.5333333333333333],"ix":9}},"s":{"a":0,"k":[0,0],"ix":5},"e":{"a":0,"k":[100,0],"ix":6},"t":2,"h":{"a":0,"k":0,"ix":7},"a":{"a":0,"k":0,"ix":8},"nm":"Gradient Fill 1","mn":"ADBE Vector Graphic - G-Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-0.207,-0.145],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[83.088,83.088],"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":30,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"5_white","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[150,150,0],"ix":2},"a":{"a":0,"k":[52.5,52.5,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":0,"s":[80,84.211,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":5,"s":[90,94.737,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":9,"s":[100,105.263,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":13,"s":[125,131.579,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":15,"s":[130,136.842,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":17,"s":[125,131.579,100]},{"t":29,"s":[80,84.211,100]}],"ix":6}},"ao":0,"w":105,"h":105,"ip":0,"op":30,"st":0,"bm":0}],"markers":[]}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long