<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns:m="http://schemas.microsoft.com/office/2004/12/omml" xmlns="http://www.w3.org/TR/REC-html40">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="Generator" content="Microsoft Word 15 (filtered medium)">
<style><!--
/* Font Definitions */
@font-face
        {font-family:"Cambria Math";
        panose-1:2 4 5 3 5 4 6 3 2 4;}
@font-face
        {font-family:DengXian;
        panose-1:2 1 6 0 3 1 1 1 1 1;}
@font-face
        {font-family:Calibri;
        panose-1:2 15 5 2 2 2 4 3 2 4;}
@font-face
        {font-family:"\@DengXian";
        panose-1:2 1 6 0 3 1 1 1 1 1;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
        {margin:0in;
        margin-bottom:.0001pt;
        font-size:11.0pt;
        font-family:"Calibri",sans-serif;}
a:link, span.MsoHyperlink
        {mso-style-priority:99;
        color:blue;
        text-decoration:underline;}
span.EmailStyle18
        {mso-style-type:personal-reply;
        font-family:"Calibri",sans-serif;
        color:windowtext;}
.MsoChpDefault
        {mso-style-type:export-only;
        font-family:"Calibri",sans-serif;}
@page WordSection1
        {size:8.5in 11.0in;
        margin:1.0in 1.0in 1.0in 1.0in;}
div.WordSection1
        {page:WordSection1;}
--></style><!--[if gte mso 9]><xml>
<o:shapedefaults v:ext="edit" spidmax="1026" />
</xml><![endif]--><!--[if gte mso 9]><xml>
<o:shapelayout v:ext="edit">
<o:idmap v:ext="edit" data="1" />
</o:shapelayout></xml><![endif]-->
</head>
<body lang="EN-US" link="blue" vlink="purple">
<div class="WordSection1">
<p class="MsoNormal">Hi, Mikhail Isachenkov<o:p></o:p></p>
<p class="MsoNormal">The server  and client on the same machine. You can see from the below detail, the AVG of course do have less value<o:p></o:p></p>
<p class="MsoNormal">  Latency Distribution<br>
  50.00%    8.28ms<br>
  75.00%    9.28ms<br>
  90.00%   19.02ms<br>
  99.00%    1.36s<br>
  99.90%    2.76s<br>
  99.99%    4.63s<o:p></o:p></p>
<p class="MsoNormal">Thanks<o:p></o:p></p>
<p class="MsoNormal">LQ<o:p></o:p></p>
<p class="MsoNormal"><b>From:</b> nginx-devel <nginx-devel-bounces@nginx.org> <b>
On Behalf Of </b>Martin Grigorov<br>
<b>Sent:</b> Thursday, November 19, 2020 3:28 PM<br>
<b>To:</b> nginx-devel@nginx.org<br>
<b>Subject:</b> Re: [PATCH] Use BPF to distribute packet to different work thread.<o:p></o:p></p>
<p class="MsoNormal"><o:p> </o:p></p>
<div>
<div>
<p class="MsoNormal">Hi,<o:p></o:p></p>
</div>
<p class="MsoNormal"><o:p> </o:p></p>
<div>
<div>
<p class="MsoNormal">On Wed, Nov 18, 2020 at 9:17 AM Liu, Qiao <<a href="mailto:qiao.liu@intel.com">qiao.liu@intel.com</a>> wrote:<o:p></o:p></p>
</div>
<blockquote style="border:none;border-left:solid #CCCCCC 1.0pt;padding:0in 0in 0in 6.0pt;margin-left:4.8pt;margin-right:0in">
<p class="MsoNormal">Hi, Mikhail Isachenkov:<br>
Great thanks for reply, I use wrk to do the test, please see below link for wrk script and nginx config file<br>
<a href="https://gist.github.com/qiaoliu78/75e7710a02c3346d22ddda04cea83b97" target="_blank">https://gist.github.com/qiaoliu78/75e7710a02c3346d22ddda04cea83b97</a><br>
I use 2 different E5 8280 servers, each with 2 Mellanox 100GB cards bound and directly connected, one server run Nginx the other server run WRK. I also run the test on same server, but seems can not prove anything.  Below is the result<br>
Run wrk and nginx on same server:<br>
<br>
  112 threads and 10000 connections<br>
  Thread Stats   Avg      Stdev     Max   +/- Stdev<br>
    Latency    57.24ms  248.60ms   8.09s    95.49%<o:p></o:p></p>
</blockquote>
<div>
<p class="MsoNormal"><o:p> </o:p></p>
</div>
<div>
<div>
<p class="MsoNormal">There is something wrong here.<o:p></o:p></p>
</div>
<div>
<p class="MsoNormal">How come the Stdev value is bigger than Avg value ?! Does that mean that some responses have been sent before their request came to Nginx, i.e. they have negative latency ?!<o:p></o:p></p>
</div>
</div>
<div>
<p class="MsoNormal"> <o:p></o:p></p>
</div>
<blockquote style="border:none;border-left:solid #CCCCCC 1.0pt;padding:0in 0in 0in 6.0pt;margin-left:4.8pt;margin-right:0in">
<p class="MsoNormal">    Connect   269.96ms  450.84ms   1.07s    74.07%<br>
    Delay      20.80ms  133.16ms   1.99s    99.08%<br>
    Req/Sec   812.77    749.04     3.90k    76.18%<br>
  Latency Distribution<br>
  50.00%    8.28ms<br>
  75.00%    9.28ms<br>
  90.00%   19.02ms<br>
  99.00%    1.36s<br>
  99.90%    2.76s<br>
  99.99%    4.63s<br>
  Connect Distribution<br>
  50.00%  346.00us<br>
  75.00%    1.00s<br>
  90.00%    1.04s<br>
  99.00%    1.06s<br>
  99.90%    1.07s<br>
  99.99%    1.07s<br>
  Delay Distribution<br>
  50.00%    6.60ms<br>
  75.00%    7.53ms<br>
  90.00%    9.92ms<br>
  99.00%   45.82ms<br>
  99.90%    1.55s<br>
  99.99%    1.82s<br>
  2247253 requests in 1.00m, 2.14TB read<br>
  Socket errors: connect 0, read 376, write 0, pconn 581, nodata 0, timeout 19, connect_timeout 2419, delay_timeout 1178<br>
Requests/sec:  37389.74<br>
Transfer/sec:     36.53GB<br>
<br>
<br>
Run nginx and wrk on two different server:<br>
112 threads and 10000 connections<br>
  Thread Stats   Avg      Stdev     Max   +/- Stdev<br>
    Latency     1.27s   879.93ms   9.84s    76.66%<br>
    Connect     8.49ms   16.28ms  99.52ms   90.27%<br>
    Delay     740.14ms  597.38ms   2.00s    48.97%<br>
    Req/Sec    73.41     32.15     2.06k    68.31%<br>
  Latency Distribution<br>
  50.00%    1.24s<br>
  75.00%    1.67s<br>
  90.00%    2.16s<br>
  99.00%    4.40s<br>
  99.90%    7.74s<br>
  99.99%    9.11s<br>
  Connect Distribution<br>
  50.00%    2.71ms<br>
  75.00%    4.43ms<br>
  90.00%   24.43ms<br>
  99.00%   84.09ms<br>
  99.90%   99.25ms<br>
  99.99%   99.51ms<br>
  Delay Distribution<br>
  50.00%  747.60ms<br>
  75.00%    1.29s<br>
  90.00%    1.51s<br>
  99.00%    1.85s<br>
  99.90%    1.98s<br>
  99.99%    2.00s<br>
  487468 requests in 1.00m, 476.98GB read<br>
  Socket errors: connect 0, read 0, write 0, pconn 1, nodata 0, timeout 9, conne                                                                                                             ct_timeout 0, delay_timeout 6912<br>
Requests/sec:   8110.10<br>
Transfer/sec:      7.94GB<br>
<br>
Thanks <br>
LQ<br>
-----Original Message-----<br>
From: Mikhail Isachenkov <<a href="mailto:mikhail.isachenkov@nginx.com" target="_blank">mikhail.isachenkov@nginx.com</a>>
<br>
Sent: Tuesday, November 17, 2020 5:09 PM<br>
To: <a href="mailto:nginx-devel@nginx.org" target="_blank">nginx-devel@nginx.org</a>; Liu, Qiao <<a href="mailto:qiao.liu@intel.com" target="_blank">qiao.liu@intel.com</a>><br>
Subject: Re: [PATCH] Use BPF to distribute packet to different work thread.<br>
<br>
Hi Liu Quao,<br>
<br>
Looks like you didn't receive my answer for some reason. You can find it in maillist archive:<br>
<a href="http://mailman.nginx.org/pipermail/nginx-devel/2020-September/013483.html" target="_blank">http://mailman.nginx.org/pipermail/nginx-devel/2020-September/013483.html</a><br>
<br>
And let me quote it a little:<br>
<br>
a) please share your test stand/test scripts/nginx configuration<br>
b) did you perform any tests with server and client running on the same server?<br>
<br>
17.11.2020 03:34, Liu, Qiao пишет:<br>
> Hi, what is the result of this patch set now?<br>
> Thanks<br>
> LQ<br>
> <br>
> -----Original Message-----<br>
> From: Liu, Qiao<br>
> Sent: Thursday, September 24, 2020 8:59 AM<br>
> To: <a href="mailto:nginx-devel@nginx.org" target="_blank">nginx-devel@nginx.org</a><br>
> Subject: RE: [PATCH] Use BPF to distribute packet to different work thread.<br>
> <br>
> Remove printf<br>
> <br>
> # HG changeset patch<br>
> # User Liu Qiao <<a href="mailto:qiao.liu@intel.com" target="_blank">qiao.liu@intel.com</a>><br>
> # Date 1599735293 14400<br>
> #      Thu Sep 10 06:54:53 2020 -0400<br>
> # Node ID c2eabe9168d0cbefc030807a0808568d86c93e4f<br>
> # Parent  da5e3f5b16733167142b599b6af3ce9469a07d52<br>
> Use BPF to distribute packet to different work thread.<br>
> Use Berkeley Packet Filter to get packet queue_mapping number, and use this queue_mapping number to distribute the packet to different work thread, this will improve CPU utilization and http latency.<br>
> Author: Samudrala, Sridhar <<a href="mailto:sridhar.samudrala@intel.com" target="_blank">sridhar.samudrala@intel.com</a>><br>
> <br>
> diff -r da5e3f5b1673 -r c2eabe9168d0 auto/os/linux<br>
> --- a/auto/os/linux   Wed Sep 02 23:13:36 2020 +0300<br>
> +++ b/auto/os/linux   Thu Sep 10 06:54:53 2020 -0400<br>
> @@ -32,6 +32,10 @@<br>
>       have=NGX_HAVE_POSIX_FADVISE . auto/nohave  fi<br>
>   <br>
> +if [ $version -lt 263680 ]; then<br>
> +    have=NGX_HAVE_REUSEPORT_CBPF . auto/nohave fi<br>
> +<br>
>   # epoll, EPOLLET version<br>
>   <br>
>   ngx_feature="epoll"<br>
> diff -r da5e3f5b1673 -r c2eabe9168d0 auto/unix<br>
> --- a/auto/unix       Wed Sep 02 23:13:36 2020 +0300<br>
> +++ b/auto/unix       Thu Sep 10 06:54:53 2020 -0400<br>
> @@ -331,6 +331,17 @@<br>
>   ngx_feature_test="setsockopt(0, SOL_SOCKET, SO_REUSEPORT, NULL, 0)"<br>
>   . auto/feature<br>
>   <br>
> +ngx_feature="SO_REUSEPORT_CBPF"<br>
> +ngx_feature_name="NGX_HAVE_REUSEPORT_CBPF"<br>
> +ngx_feature_run=no<br>
> +ngx_feature_incs="#include <sys/socket.h><br>
> +                  #include <linux/filter.h><br>
> +                  #include <error.h>"<br>
> +ngx_feature_path=<br>
> +ngx_feature_libs=<br>
> +ngx_feature_test="setsockopt(0, SOL_SOCKET, SO_ATTACH_REUSEPORT_CBPF, NULL, 0)"<br>
> +. auto/feature<br>
> +<br>
>   <br>
>   ngx_feature="SO_ACCEPTFILTER"<br>
>   ngx_feature_name="NGX_HAVE_DEFERRED_ACCEPT"<br>
> diff -r da5e3f5b1673 -r c2eabe9168d0 src/core/ngx_connection.c<br>
> --- a/src/core/ngx_connection.c       Wed Sep 02 23:13:36 2020 +0300<br>
> +++ b/src/core/ngx_connection.c       Thu Sep 10 06:54:53 2020 -0400<br>
> @@ -8,7 +8,10 @@<br>
>   #include <ngx_config.h><br>
>   #include <ngx_core.h><br>
>   #include <ngx_event.h><br>
> -<br>
> +#if (NGX_HAVE_REUSEPORT_CBPF)<br>
> +#include <linux/filter.h><br>
> +#include <error.h><br>
> +#endif<br>
>   <br>
>   ngx_os_io_t  ngx_io;<br>
>   <br>
> @@ -708,6 +711,35 @@<br>
>       return NGX_OK;<br>
>   }<br>
>   <br>
> +#if(NGX_HAVE_REUSEPORT)<br>
> +#if(NGX_HAVE_REUSEPORT_CBPF)<br>
> +#ifndef ARRAY_SIZE<br>
> +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) #endif<br>
> +<br>
> +static ngx_int_t  attach_bpf(int fd, uint16_t n) {<br>
> +     struct sock_filter code[] = {<br>
> +             /* A = skb->queue_mapping */<br>
> +             { BPF_LD  | BPF_W | BPF_ABS, 0, 0, SKF_AD_OFF + SKF_AD_QUEUE },<br>
> +             /* A = A % n */<br>
> +             { BPF_ALU | BPF_MOD, 0, 0, n },<br>
> +             /* return A */<br>
> +             { BPF_RET | BPF_A, 0, 0, 0 },<br>
> +     };<br>
> +     struct sock_fprog p = {<br>
> +             .len = ARRAY_SIZE(code),<br>
> +             .filter = code,<br>
> +     };<br>
> +<br>
> +     if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_REUSEPORT_CBPF, &p, sizeof(p)))<br>
> +         return NGX_ERROR;<br>
> +     else<br>
> +            return NGX_OK;<br>
> +}<br>
> +#endif<br>
> +#endif<br>
> +<br>
>   <br>
>   void<br>
>   ngx_configure_listening_sockets(ngx_cycle_t *cycle) @@ -719,6 +751,11 @@  #if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER)<br>
>       struct accept_filter_arg   af;<br>
>   #endif<br>
> +#if (NGX_HAVE_REUSEPORT)<br>
> +#if (NGX_HAVE_REUSEPORT_CBPF)<br>
> +        ngx_core_conf_t* ccf ;<br>
> +#endif<br>
> +#endif<br>
>   <br>
>       ls = cycle->listening.elts;<br>
>       for (i = 0; i < cycle->listening.nelts; i++) { @@ -1011,6 +1048,31 @@<br>
>           }<br>
>   <br>
>   #endif<br>
> +#if (NGX_HAVE_REUSEPORT)<br>
> +#if (NGX_HAVE_REUSEPORT_CBPF)<br>
> +    if(ls[i].reuseport)<br>
> +    {<br>
> +        ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx,ngx_core_module);<br>
> +        if(ccf)<br>
> +        {<br>
> +            if( NGX_OK == attach_bpf(ls[i].fd, ccf->worker_processes) )<br>
> +            {<br>
> +                ngx_log_error(NGX_LOG_INFO,cycle->log ,ngx_socket_errno,\<br>
> +                      "bpf prog attached to fd:%d\n", ls[i].fd);<br>
> +            }<br>
> +            else<br>
> +            {<br>
> +                ngx_log_error(NGX_LOG_ERR,cycle->log ,ngx_socket_errno,\<br>
> +                      "failed to set SO_ATTACH_REUSEPORT_CBPF\n");<br>
> +            }<br>
> +        }<br>
> +        else<br>
> +           ngx_log_error(NGX_LOG_ERR,cycle->log ,ngx_socket_errno,\<br>
> +                      "can not get config, attach bpf failed\n");<br>
> +<br>
> +    }<br>
> +#endif<br>
> +#endif<br>
>       }<br>
>   <br>
>       return;<br>
> <br>
> -----Original Message-----<br>
> From: Liu, Qiao<br>
> Sent: Tuesday, September 15, 2020 10:09 AM<br>
> To: <a href="mailto:nginx-devel@nginx.org" target="_blank">nginx-devel@nginx.org</a><br>
> Subject: RE: [PATCH] Use BPF to distribute packet to different work thread.<br>
> <br>
> Below is 5 times test result compare, 112 threads, 10000 connections, <br>
> 1M object http request. Seems P99 have great improvement, and Max is <br>
> also reduced<br>
> <br>
> <br>
> <br>
>                                     AVG          Stdev            Max        P99<br>
>                    test 1      1.32s        447.09ms     5.48s      2.82s<br>
> BPF           test 2      1.39s        513.8ms       9.42s      3.1s<br>
>                    test 3      1.4s          341.38ms     5.63s      2.55s<br>
>                    test 4      1.41s        407.45ms     6.96s      2.77s<br>
>                    test 5      1.29s        644.81ms     9.45s      3.74s<br>
>                   Average  1.362s      470.906ms   7.388s    2.996s<br>
> <br>
> NonBPF   test 1      1.48s         916.88ms     9.44s       5.08s<br>
>                   test 2      1.43s         658.48ms     9.54s       3.92s<br>
>                   test 3      1.41s         650.38ms     8.63s       3.59s<br>
>                   test 4      1.29s         1010ms        10s           5.21s<br>
>                   test 5      1.31s         875.01ms     9.53s       4.39s<br>
>               Average     1.384s        822.15ms    9.428s    4.438s<br>
> <br>
> <br>
> Thanks<br>
> LQ<br>
> -----Original Message-----<br>
> From: nginx-devel <<a href="mailto:nginx-devel-bounces@nginx.org" target="_blank">nginx-devel-bounces@nginx.org</a>> On Behalf Of Liu,
<br>
> Qiao<br>
> Sent: Monday, September 14, 2020 9:18 AM<br>
> To: <a href="mailto:nginx-devel@nginx.org" target="_blank">nginx-devel@nginx.org</a><br>
> Subject: RE: [PATCH] Use BPF to distribute packet to different work thread.<br>
> <br>
> Hi, Maxim Dounin:<br>
> Thanks for your reply, this server is random selected, we just do BPF <br>
> and no-BPF test, I think the latency based on server configuration, <br>
> not related with BPF patch, also the NIC of the server is Mellanox, <br>
> not ADQ capable hardware , we will do more test Thanks LQ<br>
> <br>
> -----Original Message-----<br>
> From: nginx-devel <<a href="mailto:nginx-devel-bounces@nginx.org" target="_blank">nginx-devel-bounces@nginx.org</a>> On Behalf Of Maxim
<br>
> Dounin<br>
> Sent: Monday, September 14, 2020 7:40 AM<br>
> To: <a href="mailto:nginx-devel@nginx.org" target="_blank">nginx-devel@nginx.org</a><br>
> Subject: Re: [PATCH] Use BPF to distribute packet to different work thread.<br>
> <br>
> Hello!<br>
> <br>
> On Fri, Sep 11, 2020 at 05:41:47AM +0000, Liu, Qiao wrote:<br>
> <br>
>> Hi, Vladimir Homutov:<br>
>> The below is our WRK test result output with BPF enable<br>
>><br>
>>    112 threads and 10000 connections<br>
>>    Thread Stats   Avg      Stdev     Max   +/- Stdev<br>
>>      Latency   608.23ms  820.71ms  10.00s    87.48%<br>
>>      Connect    16.52ms   54.53ms   1.99s    94.73%<br>
>>      Delay     153.13ms  182.17ms   2.00s    90.74%<br>
>>      Req/Sec   244.79    142.32     1.99k    68.40%<br>
>>    Latency Distribution<br>
>>    50.00%  293.50ms<br>
>>    75.00%  778.33ms<br>
>>    90.00%    1.61s<br>
>>    99.00%    3.71s<br>
>>    99.90%    7.03s<br>
>>    99.99%    8.94s<br>
>>    Connect Distribution<br>
>>    50.00%    1.93ms<br>
>>    75.00%    2.85ms<br>
>>    90.00%   55.76ms<br>
>>    99.00%  229.19ms<br>
>>    99.90%  656.79ms<br>
>>    99.99%    1.43s<br>
>>    Delay Distribution<br>
>>    50.00%  110.96ms<br>
>>    75.00%  193.67ms<br>
>>    90.00%  321.77ms<br>
>>    99.00%  959.27ms<br>
>>    99.90%    1.57s<br>
>>    99.99%    1.91s<br>
>> Compared with no BPF but enable reuseport as below<br>
>><br>
>> 112 threads and 10000 connections<br>
>>    Thread Stats   Avg      Stdev     Max   +/- Stdev<br>
>>      Latency   680.50ms  943.69ms  10.00s    87.18%<br>
>>      Connect    58.44ms  238.08ms   2.00s    94.58%<br>
>>      Delay     158.84ms  256.28ms   2.00s    90.92%<br>
>>      Req/Sec   244.51    151.00     1.41k    69.67%<br>
>>    Latency Distribution<br>
>>    50.00%  317.61ms<br>
>>    75.00%  913.52ms<br>
>>    90.00%    1.90s<br>
>>    99.00%    4.30s<br>
>>    99.90%    6.52s<br>
>>    99.99%    8.80s<br>
>>    Connect Distribution<br>
>>    50.00%    1.88ms<br>
>>    75.00%    2.21ms<br>
>>    90.00%   55.94ms<br>
>>    99.00%    1.45s<br>
>>    99.90%    1.95s<br>
>>    99.99%    2.00s<br>
>>    Delay Distribution<br>
>>    50.00%   73.01ms<br>
>>    75.00%  190.40ms<br>
>>    90.00%  387.01ms<br>
>>    99.00%    1.34s<br>
>>    99.90%    1.86s<br>
>>    99.99%    1.99s<br>
>><br>
>><br>
>>  From the above results, there shows almost 20% percent latency <br>
>> reduction. P99 latency of BPF is 3.71s , but without BPF is 4.3s.<br>
> <br>
> Thank you for the results.<br>
> <br>
> Given that latency stdev is way higher than the average latency, I don't think the "20% percent latency reduction" observed is statistically significant.  Please try running several tests and use ministat(1) to check the results.<br>
> <br>
> Also, the latency values look very high, and request rate very low.  What's on the server side?<br>
> <br>
> --<br>
> Maxim Dounin<br>
> <a href="http://mdounin.ru/" target="_blank">http://mdounin.ru/</a><br>
> _______________________________________________<br>
> nginx-devel mailing list<br>
> <a href="mailto:nginx-devel@nginx.org" target="_blank">nginx-devel@nginx.org</a><br>
> <a href="http://mailman.nginx.org/mailman/listinfo/nginx-devel" target="_blank">
http://mailman.nginx.org/mailman/listinfo/nginx-devel</a><br>
> _______________________________________________<br>
> nginx-devel mailing list<br>
> <a href="mailto:nginx-devel@nginx.org" target="_blank">nginx-devel@nginx.org</a><br>
> <a href="http://mailman.nginx.org/mailman/listinfo/nginx-devel" target="_blank">
http://mailman.nginx.org/mailman/listinfo/nginx-devel</a><br>
> _______________________________________________<br>
> nginx-devel mailing list<br>
> <a href="mailto:nginx-devel@nginx.org" target="_blank">nginx-devel@nginx.org</a><br>
> <a href="http://mailman.nginx.org/mailman/listinfo/nginx-devel" target="_blank">
http://mailman.nginx.org/mailman/listinfo/nginx-devel</a><br>
> <br>
<br>
--<br>
Best regards,<br>
Mikhail Isachenkov<br>
NGINX Professional Services<br>
_______________________________________________<br>
nginx-devel mailing list<br>
<a href="mailto:nginx-devel@nginx.org" target="_blank">nginx-devel@nginx.org</a><br>
<a href="http://mailman.nginx.org/mailman/listinfo/nginx-devel" target="_blank">http://mailman.nginx.org/mailman/listinfo/nginx-devel</a><o:p></o:p></p>
</blockquote>
</div>
</div>
</div>
</body>
</html>