gearman and perl
DESCRIPTION
An introduction of what are Gearman and its architecture, and how to use it to dispatch jobs in Perl.TRANSCRIPT
![Page 1: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/1.jpg)
Dispatching jobs with Gearman
![Page 2: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/2.jpg)
or
![Page 3: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/3.jpg)
How to farm out jobs
![Page 4: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/4.jpg)
or
![Page 5: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/5.jpg)
Using Gearmanin Perl
![Page 6: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/6.jpg)
Using Gearmanin Perl
![Page 7: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/7.jpg)
gearman.org
![Page 8: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/8.jpg)
![Page 9: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/9.jpg)
![Page 10: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/10.jpg)
![Page 11: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/11.jpg)
![Page 12: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/12.jpg)
![Page 13: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/13.jpg)
The name "Gearman" was chosen as an
anagram for "Manager," "since it dispatches
jobs to be done, but does not do anything
useful itself"
![Page 14: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/14.jpg)
Originally written in Perl
![Page 15: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/15.jpg)
Rewritten in C
![Page 16: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/16.jpg)
Clients in Perl, PHP, Phython,
Java, C# (.NET)
![Page 17: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/17.jpg)
Clients in Perl, PHP, Phython,
Java, C# (.NET),even MySQL and PostgreSQL
![Page 18: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/18.jpg)
![Page 19: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/19.jpg)
WTF?
![Page 20: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/20.jpg)
Architecture
Part I
![Page 21: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/21.jpg)
Application
Job
![Page 22: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/22.jpg)
Application
Job (or task)
![Page 23: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/23.jpg)
Application
Job
gearmand
![Page 24: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/24.jpg)
Application
Job
gearmand
Worker
Job
![Page 25: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/25.jpg)
Application
Job
gearmand
Worker
Job Response
![Page 26: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/26.jpg)
Application
gearmand
Worker
Worker
Worker
![Page 27: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/27.jpg)
Application
gearmand
Worker
Worker
gearmand
![Page 28: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/28.jpg)
Application
gearmand
Worker
Worker
gearmand
Application
![Page 29: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/29.jpg)
Workers are scalable
![Page 30: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/30.jpg)
Run any number you need
![Page 31: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/31.jpg)
Run on remote servers
![Page 32: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/32.jpg)
Application does not care
![Page 33: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/33.jpg)
Application only talks with gearmand server
![Page 34: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/34.jpg)
Application only talks with gearmand server
(one or more)
![Page 35: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/35.jpg)
One or more application
![Page 36: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/36.jpg)
One or more application
Applications throw jobs
![Page 37: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/37.jpg)
One or more job servers
![Page 38: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/38.jpg)
One or more job servers
Job servers dispatch jobs
![Page 39: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/39.jpg)
One or more workers
![Page 40: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/40.jpg)
One or more workers(clones or different)
![Page 41: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/41.jpg)
One or more workers
Workers do jobs
![Page 42: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/42.jpg)
One or more workers
Workers do jobsand may issue new jobs
![Page 43: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/43.jpg)
Scalable also means redundant
![Page 44: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/44.jpg)
Scalable also means redundant and reliable
![Page 45: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/45.jpg)
Scalable also means redundant and reliable*
* when it works properly
![Page 46: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/46.jpg)
Differentapproaches
to the architecture
![Page 47: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/47.jpg)
Synchronousor
asynchronous
![Page 48: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/48.jpg)
Worker either generates a response or works silently
![Page 49: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/49.jpg)
Application
Job
gearmand
Worker
Job Response
Response
Synchronous
![Page 50: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/50.jpg)
Application
Job
gearmand
Worker
Job Response
Response
Asynchronous
![Page 51: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/51.jpg)
Application
Job
gearmand
Worker
Job Response
Response
With a response
![Page 52: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/52.jpg)
Application
Job
gearmand
Worker
Job
With no response
“I’m done”
![Page 53: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/53.jpg)
Application
Job
gearmand
Worker
Job
With no response
“I’m done”
DatabaseResult
![Page 54: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/54.jpg)
Installation
![Page 55: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/55.jpg)
Installation
1. Job server2. Client libraries3. Worker libraries
![Page 56: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/56.jpg)
Installation
1. Job server C2. Client libraries Perl3. Worker libraries
![Page 57: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/57.jpg)
Installation
1. Job server C2. Client libraries Perl XS3. Worker libraries
![Page 58: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/58.jpg)
https://launchpad.net/gearmand
$./configure
$make
#makeinstall
Installing job server
![Page 59: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/59.jpg)
#cpanGearman
Installing Perl modules
#cpanGearman::Client
#cpanGearman::Worker
or
![Page 60: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/60.jpg)
#cpanGearman
Installing Perl modules
#cpanGearman::XS
or
![Page 61: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/61.jpg)
Starting gearmand deamon
$gearmand‐d
![Page 62: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/62.jpg)
Starting gearmand deamon
$gearmand‐d
or$gearmand‐d\
‐L127.0.0.1\
‐p4730
![Page 63: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/63.jpg)
Starting worker(s)
$./worker.pl&
![Page 64: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/64.jpg)
Starting worker(s)
$./worker.pl&
or$./workerA.pl&
$./workerB.pl&
![Page 65: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/65.jpg)
Starting worker(s)
$./worker.pl&
or$./workerA.pl&
$./workerB.pl&
$./workerA.pl&
$./workerB.pl&
![Page 66: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/66.jpg)
Running client
$./client.pl
![Page 67: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/67.jpg)
Worker example#!/usr/bin/perl
usev5.10;
usestrict;
useGearman::Worker;
my$worker=newGearman::Worker;
$worker‐>job_servers('127.0.0.1:4730');
$worker‐>register_function(echo=>\&echo);
$worker‐>workwhile1;
subecho{
my$job=shift;
say'+1';
return$job‐>arg+1;
}
![Page 68: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/68.jpg)
Worker example
my$worker=newGearman::Worker;
$worker‐>job_servers('127.0.0.1:4730');
$worker‐>register_function(echo=>\&echo);
$worker‐>workwhile1;
![Page 69: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/69.jpg)
Worker example
my$worker=newGearman::Worker;
$worker‐>job_servers('127.0.0.1:4730');
$worker‐>register_function(echo=>\&echo);
$worker‐>workwhile1;
Connect to the server
![Page 70: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/70.jpg)
Worker example
my$worker=newGearman::Worker;
$worker‐>job_servers('127.0.0.1:4730');
$worker‐>register_function(echo=>\&echo);
$worker‐>workwhile1;
Register worker method
![Page 71: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/71.jpg)
Worker example
my$worker=newGearman::Worker;
$worker‐>job_servers('127.0.0.1:4730');
$worker‐>register_function(echo=>\&echo);
$worker‐>workwhile1;
Wait for incoming jobs
![Page 72: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/72.jpg)
Worker example#!/usr/bin/perl
usev5.10;
usestrict;
useGearman::Worker;
my$worker=newGearman::Worker;
$worker‐>job_servers('127.0.0.1:4730');
$worker‐>register_function(echo=>\&echo);
$worker‐>workwhile1;
subecho{
my$job=shift;
say'+1';
return$job‐>arg+1;
}
![Page 73: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/73.jpg)
Job method
subecho{my$job=shift;say'+1';return$job‐>arg+1;}
Receive data
![Page 74: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/74.jpg)
Job method
subecho{my$job=shift;say'+1';return$job‐>arg+1;}
Evaluate response
![Page 75: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/75.jpg)
Client example#!/usr/bin/perl
use v5.10;use strict;use Gearman::Client;
my $client = new Gearman::Client;$client->job_servers('127.0.0.1:4730');
for (1..10000) { my $result_ref = $client->do_task('echo', 10); say $$result_ref;}
![Page 76: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/76.jpg)
Client example
for (1..10000) { my $result_ref = $client->do_task('echo', 10); say $$result_ref;}
Issue jobs
![Page 77: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/77.jpg)
Asynchronous client exampleuse v5.10;use strict;use Gearman::Client;
my $client = new Gearman::Client;$client->job_servers('example.com:4730');
my $tasks = $client->new_task_set;$tasks->add_task( 'echo' => 10, { on_complete => \&completed });
$tasks->wait;
sub completed { my $result = shift; say $$result;}
![Page 78: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/78.jpg)
my $tasks = $client->new_task_set;$tasks->add_task( 'echo' => 10, { on_complete => \&completed });$tasks->wait;
Get task set placeholder
Asynchronous client example
![Page 79: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/79.jpg)
my $tasks = $client->new_task_set;$tasks->add_task( 'echo' => 10, { on_complete => \&completed });$tasks->wait;
Place the task
Asynchronous client example
![Page 80: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/80.jpg)
my $tasks = $client->new_task_set;$tasks->add_task( 'echo' => 10, { on_complete => \&completed });$tasks->wait;
and register callback method
Asynchronous client example
![Page 81: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/81.jpg)
my $tasks = $client->new_task_set;$tasks->add_task( 'echo' => 10, { on_complete => \&completed });$tasks->wait;
Wait until the job is done
Asynchronous client example
![Page 82: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/82.jpg)
sub completed { my $result = shift; say $$result;}
Use result somehow
Asynchronous client example
![Page 83: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/83.jpg)
XS worker exampleuse v5.10;
use strict;
use Gearman::XS::Worker;
my $worker = new Gearman::XS::Worker;
$worker->add_server('127.0.0.1', 4730);
$worker->add_function('echo', 0, \&echo, undef);
$worker->work() while 1;
sub echo {
my $job = shift;
return $job->workload() + 1;
}
![Page 84: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/84.jpg)
XS client exampleuse v5.10;
use strict;
use Gearman::XS::Client;
my $client = new Gearman::XS::Client;
$client->add_server('127.0.0.1', 4730);
my ($ret, $result) = $client->do('echo', '15'); # arg as string!
say $result;
![Page 85: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/85.jpg)
Async XS client exampleuse v5.10;
use strict;
use Gearman::XS::Client;
my $client = new Gearman::XS::Client;
$client->add_server('127.0.0.1', 4730);
my ($ret1, $task1) = $client->add_task('echo', '15');
my ($ret2, $task2) = $client->add_task('echo', '51');
$client->run_tasks();
![Page 86: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/86.jpg)
Monitoring job server
![Page 87: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/87.jpg)
TCP protocol
![Page 88: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/88.jpg)
Connect with telnet
![Page 89: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/89.jpg)
$ telnet localhost 4730
![Page 90: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/90.jpg)
$ telnet localhost 4730Trying 127.0.0.1...Connected to localhost.Escape character is '^]'.
![Page 91: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/91.jpg)
$ telnet localhost 4730Trying 127.0.0.1...Connected to localhost.Escape character is '^]'.status
![Page 92: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/92.jpg)
$ telnet localhost 4730Trying 127.0.0.1...Connected to localhost.Escape character is '^]'.statusecho2 1 1 2echo 5 2 5.
![Page 93: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/93.jpg)
echo2 1 1 2echo 5 2 5.
![Page 94: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/94.jpg)
echo2 1 1 2echo 5 2 5.
Known worker methods
![Page 95: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/95.jpg)
echo2 1 1 2echo 5 2 5.
Jobs running
![Page 96: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/96.jpg)
echo2 1 1 2echo 5 2 5.
Jobs queued
![Page 97: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/97.jpg)
echo2 1 1 2echo 5 2 5.
Workers available
![Page 98: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/98.jpg)
Step by step example
Part III
![Page 99: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/99.jpg)
for(...){...}
worker.pl
worker.pl
worker.pl
worker.pl
![Page 100: Gearman and Perl](https://reader033.vdocuments.site/reader033/viewer/2022042601/54b76a334a795918158b4579/html5/thumbnails/100.jpg)
Live demo