CUDA Convolution

- GPGPU Programming -

Dec, 2008

Sangyoon Lee (sjames @ evl.uic.edu)

Electronic Visualization Laboratory

University of Illinois at Chicago

* This project is a part of CS525 GPU Programming Class instructed by Andy Johnson.

1. Concept and Brief

A given final exam is to explore CUDA optimization with Convoluiton filter application from nvidia's CUDA 2.0 SDK. There are three type of convolution filter in SDK. I mainly used convolutionTexture and convolutionSeparable application.

- Dataset (Images)

Images used in final is provided by Andy (see class website). I used 1kby1k, 2kby2k and 4kby4k image for performance testing. For some reason, 8kby8k image does not work well on my system.

- Development platform

Mac OSX 10.5, MacBook Pro 2.5GHz, Geforce 8600M GT 512MB, nvidia CUDA SDK 2.0

Intermediate and Final version of application is available to download and test. See more details in section 7 below.

2. Starting

Since there is well optimized application is available in SDK, I started to look at their code. First of all, original code uses random data instead of real images. Each data pixel in image represented as single float in these application. To make this application work with real image, I implemeted image loader and writer in RAW format. This code was slightly modified the module we used in project 2.

Each color component of pixel is composed of three values, RGB. To apply convolution filter on image, there are two ways. The first one is simply to map each component as single float and run convolution filter three times for each channel. The second apporach is to modify the original code to use uchar4 or int type as dataset so that we can compute separate channel value within CUDA kernel. I implemeted both ways in convolutionTexuture and convolutionSeparable but later on I only used the first method since it makes kernel code much simpler.

First thing I tried is top-down approach. I mean I took nvidia application and started to remove some of optimization techniques. Then, realized that it is not easy to make this all the way down to naive approach. So, restarted implementation from the most naive way and optimized it to close to the nvidia's application. Later section will explain these steps.

If you are not familiar with convolution filter, please take a look wikipedia entry, Gaussian blur or Convolution. Also, class lecture note (week4, convolution) is useful.

3. Step 0: the most Naive approach

From the idea of convolutio filter itself, the most naive approach is to use global memory to send data to device and each thread accesses this to compute convolution kernel. Our convolution kernel size is radius 8 (total 17x17 multiplicaiton for single pixel value). In image border area, reference value will be set to 0 during computation. This naive approach includes many of conditional statements and this causes very slow execution.

There is no idle threads since total number of threads invoked is the same as total pixel numbers. CUDA kernel block size is 16x16. Below execution time is a mean value over 10 times execution. As you can see, it is extremely slow here.

Figure 1. Memory Access Pattern in Naive approach: each threads in block access 17x17 times global memory.

Below is CUDA kernel code.

__global__ void convolutionGPU(
...............................float *d_Result,
...............................float *d_Data,
...............................int dataW,
...............................int dataH )
      {
....//////////////////////////////////////////////////////////////////////
....// most slowest way to compute convolution
....//////////////////////////////////////////////////////////////////////

....// global mem address for this thread
....const int gLoc = threadIdx.x +
.....................blockIdx.x * blockDim.x +
.....................threadIdx.y * dataW +
.....................blockIdx.y * blockDim.y * dataW;

....float sum = 0;
....float value = 0;

....for (int i = -KERNEL_RADIUS; i <= KERNEL_RADIUS; i++)		// row wise
........for (int j = -KERNEL_RADIUS; j <= KERNEL_RADIUS; j++)	// col wise
........{
............// check row first
............if (blockIdx.x == 0 && (threadIdx.x + i) < 0)					// left apron
................value = 0;
............else if ( blockIdx.x == (gridDim.x - 1) &&
........................(threadIdx.x + i) > blockDim.x-1 )					// right apron
................value = 0;
............else
............{
................// check col next
................if (blockIdx.y == 0 && (threadIdx.y + j) < 0)				// top apron
....................value = 0;
................else if ( blockIdx.y == (gridDim.y - 1) &&
............................(threadIdx.y + j) > blockDim.y-1 )					// bottom apron
....................value = 0;
................else														// safe case
....................value = d_Data[gLoc + i + j * dataW];
............}
............sum += value * d_Kernel[KERNEL_RADIUS + i] * d_Kernel[KERNEL_RADIUS + j];
........}
........d_Result[gLoc] = sum;
      }

4. Step 1: Shared Memory

We all experienced the importance of shared memory throughout project 2. Now, it is time to incorporate with this feature from naive code. When I read nvidia convolution document, I thought that it is OK to invoke many of threads and each thread load data from global mem to shared mem. Then, let some of threads idle. Those are thread loaded apron pixels and do not compute convolution.

The first attempt was to keep active thread size as same as previous and increase block size for apron pixels. This did not work since convolution kernel radius is 8 and it make block size to 32 x 32 (1024). This is bigger than G80 hardware limit (512 threads max per block).

Therefore, I changes scheme as all threads are active and each thread loads four pixels and keep the block size 16x16.  Shared Memory size used is 32x32 (this includes all necessary apron pixel values for 16x16 active pixels). Below shows quite a bit of performance improve. This is almost x2.8 speed up over naive approach (in 2048 resolution).

Figure 2. Shared Memory Model for naive approach: each threads in block load 4 values from global memory. Threfore, total shared memory size is 4 times bigger than active convolution pixels to include apron area (kernel radius 8 and block size 16x16. active pixels 256 float vs. shared memory size is 1024 float).

Below codes illustrate the convolution kernel.

__global__ void convolutionGPU(
................................float *d_Result,
................................float *d_Data,
................................int dataW,
................................int dataH
................................)
      {
....// Data cache: threadIdx.x , threadIdx.y
....__shared__ float data[TILE_W + KERNEL_RADIUS * 2][TILE_W + KERNEL_RADIUS * 2];

....// global mem address of this thread
....const int gLoc = threadIdx.x +
........................IMUL(blockIdx.x, blockDim.x) +
........................IMUL(threadIdx.y, dataW) +
........................IMUL(blockIdx.y, blockDim.y) * dataW;

      ....// load cache (32x32 shared memory, 16x16 threads blocks)
....// each threads loads four values from global memory into shared mem
....// if in image area, get value in global mem, else 0
....int x, y;		// image based coordinate

      ....// original image based coordinate
....const int x0 = threadIdx.x + IMUL(blockIdx.x, blockDim.x);
....const int y0 = threadIdx.y + IMUL(blockIdx.y, blockDim.y);

      ....// case1: upper left
....x = x0 - KERNEL_RADIUS;
....y = y0 - KERNEL_RADIUS;
....if ( x < 0 || y < 0 )
........data[threadIdx.x][threadIdx.y] = 0;
....else
........data[threadIdx.x][threadIdx.y] = d_Data[ gLoc - KERNEL_RADIUS - IMUL(dataW, KERNEL_RADIUS)];

      ....// case2: upper right
....x = x0 + KERNEL_RADIUS;
....y = y0 - KERNEL_RADIUS;
....if ( x > dataW-1 || y < 0 )
........data[threadIdx.x + blockDim.x][threadIdx.y] = 0;
....else
........data[threadIdx.x + blockDim.x][threadIdx.y] = d_Data[gLoc + KERNEL_RADIUS - IMUL(dataW, KERNEL_RADIUS)];

      ....// case3: lower left
....x = x0 - KERNEL_RADIUS;
....y = y0 + KERNEL_RADIUS;
....if (x < 0 || y > dataH-1)
........data[threadIdx.x][threadIdx.y + blockDim.y] = 0;
....else
........data[threadIdx.x][threadIdx.y + blockDim.y] = d_Data[gLoc - KERNEL_RADIUS + IMUL(dataW, KERNEL_RADIUS)];

      ....// case4: lower right
....x = x0 + KERNEL_RADIUS;
....y = y0 + KERNEL_RADIUS;
....if ( x > dataW-1 || y > dataH-1)
........data[threadIdx.x + blockDim.x][threadIdx.y + blockDim.y] = 0;
....else
........data[threadIdx.x + blockDim.x][threadIdx.y + blockDim.y] = d_Data[gLoc + KERNEL_RADIUS + IMUL(dataW, KERNEL_RADIUS)];

      ....__syncthreads();

      ....// convolution
....float sum = 0;
....x = KERNEL_RADIUS + threadIdx.x;
....y = KERNEL_RADIUS + threadIdx.y;
....for (int i = -KERNEL_RADIUS; i <= KERNEL_RADIUS; i++)
........for (int j = -KERNEL_RADIUS; j <= KERNEL_RADIUS; j++)
............sum += data[x + i][y + j] * d_Kernel[KERNEL_RADIUS + j] * d_Kernel[KERNEL_RADIUS + i];

      ....d_Result[gLoc] = sum;
      }

One more optimization tested here. The use of faster integer multiplication instruction (above code already has this change), __mul24. After replacing all integer multiplication with __mul24, I got slight better performance.

5. Step 2: Filter Separation

Here very important aspect of convolution filter is that it can be separated by row and column. This will reduce computation complexity from m*m to m+m. Basically we apply two separate convolution. The first one is row-wise and the second one is column-wise from the first result data (apply column convolution over row-wise filtered data). This also reduces some of conditional statement and total number of apron pixel data in each path since we do not need to consider vertical apron in row-convolution kernel and horizontal apron in column-convolution kernel.

This gives me a great improvement over the last shared memory optimized version. This is almost x6.2 speed-up from the last version (in resolution 2048). Code already includes __mul24 instruction.

Figure 3. Shared Memory for separate filter: this time only twice bigger memory is necessary for each filter

Unfortunately compiler directive for loopunroll (#pragma unroll 17) does not give any significat improvement. Below shows kernel code for separable convolution filter. Applicatin also modified to run twice of the kernel for row and col convolution.

////////////////////////////////////////////////////////////////////////////////
      // Row convolution filter
      ////////////////////////////////////////////////////////////////////////////////
      __global__ void convolutionRowGPU(
....................................float *d_Result,
....................................float *d_Data,
....................................int dataW,
....................................int dataH
..................................)
      {
....// Data cache: threadIdx.x , threadIdx.y
....__shared__ float data[TILE_W + KERNEL_RADIUS * 2][TILE_H];

      ....// global mem address of this thread
....const int gLoc = threadIdx.x +
........................IMUL(blockIdx.x, blockDim.x) +
........................IMUL(threadIdx.y, dataW) +
........................IMUL(blockIdx.y, blockDim.y) * dataW;

....int x;		// image based coordinate

      ....// original image based coordinate
....const int x0 = threadIdx.x + IMUL(blockIdx.x, blockDim.x);

.... // case1: left
....x = x0 - KERNEL_RADIUS;
....if ( x < 0 )
........data[threadIdx.x][threadIdx.y] = 0;
....else
........data[threadIdx.x][threadIdx.y] = d_Data[ gLoc - KERNEL_RADIUS];

.... // case2: right
....x = x0 + KERNEL_RADIUS;
....if ( x > dataW-1 )
........data[threadIdx.x + blockDim.x][threadIdx.y] = 0;
....else
........data[threadIdx.x + blockDim.x][threadIdx.y] = d_Data[gLoc + KERNEL_RADIUS];

.... __syncthreads();

....// convolution
....float sum = 0;
....x = KERNEL_RADIUS + threadIdx.x;
....
....for (int i = -KERNEL_RADIUS; i <= KERNEL_RADIUS; i++)
........sum += data[x + i][threadIdx.y] * d_Kernel[KERNEL_RADIUS + i];

.... d_Result[gLoc] = sum;
}

      ////////////////////////////////////////////////////////////////////////////////
      // Column convolution filter
      ////////////////////////////////////////////////////////////////////////////////
      __global__ void convolutionColGPU(
....................................float *d_Result,
....................................float *d_Data,
....................................int dataW,
....................................int dataH
.................................)
      {
....// Data cache: threadIdx.x , threadIdx.y
....__shared__ float data[TILE_W][TILE_H + KERNEL_RADIUS * 2];

.... // global mem address of this thread
....const int gLoc = threadIdx.x +
........................IMUL(blockIdx.x, blockDim.x) +
........................IMUL(threadIdx.y, dataW) +
........................IMUL(blockIdx.y, blockDim.y) * dataW;

....int y;		// image based coordinate

....// original image based coordinate
....const int y0 = threadIdx.y + IMUL(blockIdx.y, blockDim.y);

....// case1: upper
....y = y0 - KERNEL_RADIUS;
....if ( y < 0 )
........data[threadIdx.x][threadIdx.y] = 0;
....else
........data[threadIdx.x][threadIdx.y] = d_Data[ gLoc - IMUL(dataW, KERNEL_RADIUS)];

....// case2: lower
....y = y0 + KERNEL_RADIUS;
....if ( y > dataH-1 )
........data[threadIdx.x][threadIdx.y + blockDim.y] = 0;
....else
........data[threadIdx.x][threadIdx.y + blockDim.y] = d_Data[gLoc + IMUL(dataW, KERNEL_RADIUS)];

....__syncthreads();

....// convolution
....float sum = 0;
....y = KERNEL_RADIUS + threadIdx.y;
....for (int i = -KERNEL_RADIUS; i <= KERNEL_RADIUS; i++)
........sum += data[threadIdx.x][y + i] * d_Kernel[KERNEL_RADIUS + i];

....d_Result[gLoc] = sum;
}

6. Step 3: Reorganize Shared Memory

Until step 2, I used 2D array of shared memory to make indexing a bit simpler. Inside computation loop, there is possibility of bank conflict for warp since each thread access first column major memory at the same time. Now, let's re-arrange this shared memory to 1D array so that all threads access data consequently and optimize memory bus here. This only requires changes of indexing in kernel code. Below table shows performance after this re-arrange.

Figure 4. 1D Shared Memory Access Pattern for row filter: shows the first four iteration of convolution computataion. red area is indicating values accessed by half warp threads. Even we obtained fair amount speed up with this re-arrangement, memory access pattern is not aligned well enough to meet the requirement of half-warp alignment for optimal performance.

As you can see above table data, it achived about x3.2 speed-up over the first separable convoluiton implementation (in resolution 2048). Following shows kernel code for this optimization. From step 0 to this point, we made x57 speed-up overall (in resolution 2048).

////////////////////////////////////////////////////////////////////////////////
      // Row convolution filter
      ////////////////////////////////////////////////////////////////////////////////
      __global__ void convolutionRowGPU(
................................................float *d_Result,
................................................float *d_Data,
................................................int dataW,
................................................int dataH
.............................................)
      {
....// Data cache: threadIdx.x , threadIdx.y
....__shared__ float data[ TILE_H * (TILE_W + KERNEL_RADIUS * 2) ];

....// global mem address of this thread
....const int gLoc = threadIdx.x +
............................IMUL(blockIdx.x, blockDim.x) +
............................IMUL(threadIdx.y, dataW) +
............................IMUL(blockIdx.y, blockDim.y) * dataW;

....int x;		// image based coordinate

....// original image based coordinate
....const int x0 = threadIdx.x + IMUL(blockIdx.x, blockDim.x);
....const int shift = threadIdx.y * (TILE_W + KERNEL_RADIUS * 2);

....// case1: left
....x = x0 - KERNEL_RADIUS;
....if ( x < 0 )
........data[threadIdx.x + shift] = 0;
....else
........data[threadIdx.x + shift] = d_Data[ gLoc - KERNEL_RADIUS];

....// case2: right
....x = x0 + KERNEL_RADIUS;
....if ( x > dataW-1 )
........data[threadIdx.x + blockDim.x + shift] = 0;
....else
........data[threadIdx.x + blockDim.x + shift] = d_Data[gLoc + KERNEL_RADIUS];

....__syncthreads();

....// convolution
....float sum = 0;
....x = KERNEL_RADIUS + threadIdx.x;
....for (int i = -KERNEL_RADIUS; i <= KERNEL_RADIUS; i++)
........sum += data[x + i + shift] * d_Kernel[KERNEL_RADIUS + i];

....d_Result[gLoc] = sum;

}

////////////////////////////////////////////////////////////////////////////////
      // Row convolution filter
      ////////////////////////////////////////////////////////////////////////////////
      __global__ void convolutionColGPU(
....................................float *d_Result,
....................................float *d_Data,
....................................int dataW,
....................................int dataH
..................................)
      {
....// Data cache: threadIdx.x , threadIdx.y
....__shared__ float data[TILE_W * (TILE_H + KERNEL_RADIUS * 2)];

....// global mem address of this thread
....const int gLoc = threadIdx.x +
........................IMUL(blockIdx.x, blockDim.x) +
........................IMUL(threadIdx.y, dataW) +
........................IMUL(blockIdx.y, blockDim.y) * dataW;

....int y;		// image based coordinate

....// original image based coordinate
....const int y0 = threadIdx.y + IMUL(blockIdx.y, blockDim.y);
....const int shift = threadIdx.y * (TILE_W);

....// case1: upper
....y = y0 - KERNEL_RADIUS;
....if ( y < 0 )
........data[threadIdx.x + shift] = 0;
....else
........data[threadIdx.x + shift] = d_Data[ gLoc - IMUL(dataW, KERNEL_RADIUS)];

....// case2: lower
....y = y0 + KERNEL_RADIUS;
....const int shift1 = shift + IMUL(blockDim.y, TILE_W);
....if ( y > dataH-1 )
........data[threadIdx.x + shift1] = 0;
....else
........data[threadIdx.x + shift1] = d_Data[gLoc + IMUL(dataW, KERNEL_RADIUS)];

....__syncthreads();

....// convolution
....float sum = 0;
....for (int i = 0; i <= KERNEL_RADIUS*2; i++)
........sum += data[threadIdx.x + (threadIdx.y + i) * TILE_W] * d_Kernel[i];

....d_Result[gLoc] = sum;

}

7. Step 4: nvidia convolution app

In step 3, we made many of optimizations and improved performance greately. Now, there is a bit of further possible optimization to maximize memory bandwidth by change block organization as we see in nvidia's convolution document. Instead of changing code from step 3, I modified nvidia's original code to use image data to see the difference in performance. As I explained in the very beginning, there are two version of convolution app from nvidia. Following table shows those two application performance (modiifed version).

Compared to the result from step 3, convolutionSeparable optimization shows x2 speed-up (in resolution 2048). This application's kernel code is the same as the original one from nvidia. Only applicaiton side code is modified.

Below table shows a couple of experiments I ran at the beginning of top-down approach with this code (original nvidia convolutionSeparable app).

As we can see here, loop unrolling does not impact on performance that much but __mul24 intruction gives x1.3 speed-up.

Here is a brief performance chart from step 1 to step 4 (step 0 is excludes due to its huge number).

8. Application

Here are three different version of convolution application. The first one is my own implemetation until step 3 and the other two applicaitons are the one I modified to use texture image instead of random data from nvidia application (see details in section 2 & 7).

Image Data: hubble.tar.gz (34MB. only include 1kby1k, 2kby2k, 4kby4k raw image from Andy's ditribution)

Need to copy these image file in directory name of hubble at the same level of each convolution application directory. (if you copied application in xxx/convolution directory, then image directory must be xxx/hubble )

Download application source & executable:

convolution.tar.gz (version of step 3)

convolutionTexture.tar.gz (version of step 4, texture)

convolutionSeparable.tar.gz (version of step 4, separable)

Execution

inside bin/darwin/release

./convolution [-i=image resolution] [-n=number of total run]

./convolutionTexture [-i=image resolution] [-n=number of total run]

./convolutionSeparable [-i=image resolution] [-n=number of total run]

default image resolution is 1024 and total run is 10 times.

Compile

in each application directory, type 'make'

9. References

[1] Nvidia CUDA Programming Guide 2.0, http://www.nvidia.com/object/cuda_develop.html

[2] Victor Podlozhnyuk, Image Convolution with CUDA, nvidia CUDA 2.0 SDK convolutionSpeparable document


Optimize CUDA Host/Device Transfers

justin.p.mckennon

·

This post is Topic #2 (part 2) in our series Parallel Code: Maximizing your Performance Potential.

In my previous post, CUDA Host/Device Transfers and Data Movement, I provided an introduction into the bottlenecks associated with host/device transfers and data movement. This post will delve a bit further into the subject and provide a few nifty ways to mitigate these very costly operations.

In every single CUDA application (well any useful ones, that is) there is at the very least one host-to-device transfer and one device-to-host transfer. More complicated applications often have many transfers between the host and device. In CUDA programming, this is one of the most expensive operations in terms of timing.

So, if these host/device data transfers are so costly, how do you avoid them? Well, you can’t. But what you can do is minimize the number of transfers between host and device in your application, and mask their impact on the performance of your application.

First, any intermediate data structures that are used within your kernel should always be allocated and destroyed solely on the device. This removes the need to map these structures to host memory and removes the need to transfer this data between the host and device.

If your application has multiple host/device transfers, every effort should be made to batch these transfers into one large transfer. I like to think of this as if you were carrying groceries. Why make multiple trips out to the car when you can load up your arms and do it all at once? Most GPUs support transfer speeds between 5GB/sec and 11GB/sec.

For situations where there is no way around transferring data between host and device, more advanced techniques can be employed to lessen the impact on your application: pinned (also known as page-locked, or mapped) memory and asynchronous transfers.

Pinned Memory

The cudaHostAlloc() function allows you to allocate host memory that can be read from the device and written directly to by the device. This allocated memory is called pinned memory. Pinned memory transfers attain the highest bandwidth between the host and device. During execution, a block that requires host data only needs to wait for a small portion of the data to be transferred (when operating through pinned memory). Typical host-to-device copies make all blocks wait until all of the data associated with the copy operation is transferred. Keep in mind, however, that pinning too much memory can degrade overall system performance by reducing the amount of memory available to the system for paging operations. How much memory you can safely pin differs from system to system, so definitely experiment with this to find the optimal amount.

Asynchronous Transfers

Standard host/device transfers are known as blocking transfers. Control of the main thread is returned only after the data transfer is complete. The cudaMemcpyAsync() function is effectively a non-blocking version of the standard cudaMemcpy(). When executing an asynchronous transfer via cudaMemcpyAsync(), control is returned immediately to the main thread. If you’re not jumping up and down with excitement after hearing that, you should be!

Asynchronous transfers required pinned memory and make use of CUDA streams. In CUDA, streams are essentially sequences of operations that are performed in order on the device. Creating multiple streams is a bit more of an advanced CUDA technique, but one that must be learned if you want the most bang for your buck. With multiple streams in a single application, operations within separate streams can be overlapped, providing a great way to mask the host/device transfer time. Let’s look at an example of how using multiple streams can benefit you and your application:

cudaMemcpyAsync(deviceArray,hostArray,size,cudaMemcpyHostToDevice,0);
kernel<<>>(deviceArray);
//your code

Here, both the transfer and kernel are using the default stream, 0. During execution, the kernel will not be launched until the entire copy operation is complete and control has been returned back to the main thread. This is because both the kernel and memory copy are part of the same stream. Now, let’s look at the code using multiple streams:

cudaStreamCreate(&mystream1);
cudaStreamCreate(&mystream2);
cudaMemcpyAsync(deviceArray,hostArray,size,cudaMemcpyHostToDevice,mystream1);
kernel<<>>(otherDataArray);
//your code

By defining two new streams, we are able to make use of concurrent copy and compute. The memory copy is executing in one stream while the kernel is off in another stream, asynchronous from one another. An important note is to make sure that your device supports concurrent copy and execute before you put this in all of your code. This can be done via the deviceOverlap field of the cudaDeviceProp structure.

While this is an advanced technique, if your data can be broken into chunks and transferred in various stages, you can launch multiple kernel instances to operate on each chunk of data as it arrives on the device. Doing so will almost completely mask the transfer time between the host and device.

So, armed with the knowledge of streams, asynchronous transfers, and pinned memory, you now have some insight on how to squeeze out some more performance from your application. My next post will discuss how to efficiently make use of the available memory types accessible to you within your GPU application.

You May Also Like

DGX A100 review: Throughput and Hardware Summary

When NVIDIA launched the Ampere GPU architecture, they also launched their new flagship system for HPC and deep learning – the DGX 100. This system offers exceptional performance, but also new capabilities. We’ve seen immediate interest and have already shipped to some of the first adopters. Given our early access, we wanted to share a…

Deploying GPUs for Classroom and Remote Learning

As one of NVIDIA’s Elite partners, we see a lot of GPU deployments in higher education. GPUs have been proving themselves in HPC for over a decade, and they are the de-facto standard for deep learning research. They’re also becoming essential for other types of machine learning and data science. But GPUs are not always…

What Can You Do with a $15k NVIDIA Data Science Workstation? – Change Healthcare Data Science

NVIDIA’s Data Science Workstation Platform is designed to bring the power of accelerated computing to a broad set of data science workflows. Recently, we found out what happens when you lend a talented data scientist (with a serious appetite for after-hours projects + coffee) a $15k accelerated data science tool. You can recreate a massive…


=אa1@�ى�i��4�t��E`��w�t�p��L��J� t����_�a95��V�!�y	���
ytך(��_�bG�o�B��&���l��k��"�G?^��痔ޚ����g�k
�,���v��e�������;pu�ڸ��q�)��p��B�û8��w
���{��'��7���V֗4��T�RȤ	�_�w��c��3�}��,#����t,Z\e�Z��`�o���7ݙ�5��g|��x����2�ܰa�W���2������@X�.���r*_n�,����-Wx�i��Z-$���D]�N=8.�
���.K�_��1:󲇼1�d�nhE`h@���;��wnw	?��/�����EO��޻,�C7^�5Sh
�s�B֙�dSx�OW�s-~�V�y������x�.6Q �{|xQ֧G�Z#F�Z�8��āR3&ܖ���HP�g�f	�-G�O��x_��{zF�հ�)�������6�U��{��&�mJ����9�7�!��o�����&�>ќj��X��eanJF*MNj�|K��$Oʴ9[�2��P�xH��[W'ʍ7�>L��+����A=8o�Е�Q{����;�)�I���|�#�CJ�M�����^�&R/�2q ar�Ǥ��E�w�&�#}��U��/h�ϑOyW��_Ѧ�%�E32�J���}B�7U.����pݖlE��B<M�a�{G*Ɖ�l�1��@�jʸ �n�M�cFU��쬫PD���Y޳�@œi���#��v�p�|��S�������xO�E�ѐӃ��\q3P���&����������������O��u��3��Θ;��ȷ:P�������嫞�W���)��G�����%�:'�4>���ǁ��b���J�Y3�g�����������ALM_�4�/[�����?������\��U閱?DȐ�h��a�&�<(("2`ɩ�����#	�����eaG���d�z��?��*m��MS�>� �9����'6�^S�0#��'c%l���=l�`k����e���_�|`u(��:������ѧ�'�U=�y��\>?)��0��M���vF��F�
�pSyVF��ZqJ���{��ۍ������
b�=�d1*P��RG.>&���J����Xy�ϲ�p���P,�U�|G�]��C�&=%���w'.�8�W��88#Ð�\vjFr���D�^p6ȳ0?��ΐ���wޤ�-;3#��|��R��������iK/���=-i�mX�ܚ��%�1z�]�0®��!�?>_!��2�ݭ��4��DMX兄��*�a ���Z8VU)�ߋ��Y�2���5����з��r�g�Yvv�K��1���Ң8
endstream
endobj
113 0 obj
<>
endobj
135 0 obj
<>stream
x��=K�@�&V�_��/=С��VQ$R)�E�:�ڣi0�p9
���p��C�"4K'�@F?�?������~��1������t���8�Ȥ����
|�IM��:��5�[��e�^A
�^�\g~�wڶ �f���Q��W�9s)�4-�����k��y
��P�%��-�\��aX�ܠ�x��X"aG���?�9g� �KɌV�u��������E����">%��f����'Fo�X��e����3�=_26������%�j�+����E�Ø�D,��(�҃��� ���>�,$��@�&YB���n�
endstream
endobj
55 0 obj
<>
endobj
136 0 obj
<>stream
x��W	tSe��!4\�d^�roY�EYD� ���,�-m�k�6m�$͞��7��fi�.t��B���\�>:#�Tt�3ϗz{�y_��Ggμ3���MN�}�����1r!D+7lX�$�4=�� ���$a>o��T�:�	a��C��_���y�ǣ=��A~��YYPX.��ʖ%�L���Ē%��&/�?I�LiNzZ~�4Yvf^���M�Z���)+O��,[&+\���r�������
�Y�͚�,ϑe'o�,Δ�ff$�P�/Kޘ���<�c�W���2��
22�����9��O1yŎ�v�,\�ZZ,+Y��Ҿ��227e�l;����g��'�)�b*��XJL#^&~GL'�ۈW���l�yb.���G�"#V/��:b!���@<@�'&�1׋It
���?	?y0ቄ���QO��J.%o�V�yx욱�+��WՉߎ_?��`{p��)��L��д���3&����j���:4Z���c�Q��5�&u��
�Is�଱N��j�BУd��������!��S$NB>�Yf�1K-�=`$+�/�TC��a��8Sah`�40��	?ͫ�&��b�W��0�1VH�@��T�|��b����o&$�߂�~A� f�=$�6�s�!�rE]�K���?�yX7�bt�t9&�QjFPely<�r�s
 u8&���hs�E��3�����(U��ѱ�"=f��ak�Z�F.3�����)�`�b��K0TBy�<�*��Fc�00600�b���J��(_�ڸ1#}�Nɨ������d�!A1�xx��T��?X_�a�8h�������&�};jlr�$����F_Q��HꕌBm78����t�ld���طL	|�W	��zwXM'�q˯FQg��?�!Z��X�eR/�L��qA��"�4��|{}�n���n����ȏ��oD�J�I'D,A0�Z��*�3���� ��L�#��8H�#�{�e����h~/[\�C7�5��;����ڒ�fѥ˅�gΟˏ�c:U46#*��u,�������>����S��)��
=�&!
M��(���~��S����l�Y {{s��T��XGܶ5}��������.�o|v�|��`-Np��UK� ϸB�97�
}%n�FGLn-�y��W�$~4:����r��7���@Х6k1B�B:�c����@�p��$��o�ϭ�C�3��O�˫_a���>���!���#,G�
�r�	3Q&�=N�(5�WA��8��h��j�'���s���k����E%���Z}_	���K�fO<\�e\*�Ѩ�R_4�
$0��^�}~*�|9/�|�CY��������w>��,��dW�L:C�����f9{�y4�׏|���n|w�.�Hx�i~D�QZ�����J�y���h�`Sc�?��?(���{�Ta(8����l�>��Z�6ބԚ��"Q�T�;m�&K��D�\����a|�F�A���?����t�~�F���]�9���U���-` �v���Y�V*�i���Cp�R�T�4��\�5���������Pj��~B�v:gKZ�~ �U|j�qV֊��������h�/i�n����F�h�B4��O�w�W�0��xB�ѽ�/�◥�S�ΤwmY���[2N�K��1�/�������,��W�K
�I���2��zX��B�A�-q�Z$��+�S�e���9W�tm�zl>;׎��!B6�-��灖�X�N|D��"hc��ʨ�h8��tꌬ�`�����$�BJ�� ���&k�z��@[��F�02��O޷�_�s������Ut�'*@?|-�͌��)
��,�)�M���G�ZR��m-���o�gB�J�eY�����\]�-��kP�󋓴��b#Y���k�7��)O�ӱN4���Ym�׿�	���#UEO�F�?��=�z��0696F��`�-��V��C���S:W�g�ؕ�{�T��IwD۫v������_T��@���z	u���;ThS�gV���r�hY'��Uڠ��EMm�v���bd�������������a8���Q���V�2,�vM�rb��߈��A��D��҄@����&��D����ʔ���o���QM�A�dsoΛ�Σi.��^S�Z*w�Δ �Jo{��c�c}�rH�Q�{�X�Tlk���E«�TU��ZJ_��o�(�Jߵ
�
p9��=ՃFҎz�B���S��S������P�GO�1W�+��b:��P������ܱí
Th��`���"G���+��x�JF_f��.���X���a�a:�����+ò�`��bW�������
�ud2Z�����E��99�	U��Ճ&Lc�����с�$u���9 K0������ B�C=0����O�@�)|_����g����������	�#���1Hl(~?��W�]=s6���N�������.�,ᒧJ�r�������=���X|�0��WK59zj��ˀ�(�ڻ��Z����T���v���n �����z���8\4ol��A�<�K=]��m��ɲjJ:�&̶���x����i��*��ht�UJ"M�L��N�U]���$�j��OAb�N�V������gUm�ޡJ�h��<8H.|c�~:�v��.�QU[���}��~6����G���S~�ﰽ��nۦ�X�^����
�f'���"�I�b(f�1֋��-gsY����Cz�+j�uD\�Xɱ{�Z�5�A��r��E�J g���oVEѡ���u%Xʧ�&�3y>H��F�'|����/���͸��{4��{^�֡�3�JMmZ1_�*�[�w�r{�G�|�2�ม!�L�Q6���kb;;��O���w����M$�$V�
$\KZ�`hd�$���	��>T���j���<4`K�~�@��H���σ���@�-3��k|5R�j:�-��òfz$v,������j� ��es�����m~��{C�ă�@�Q���~6
a\�n&��יB�m��q��v|����kJ��V��/�ʞ�ɬ�PgH�u	�Z�Y3�b��P��*��@g��u&V�!q0�E'?B�N!����p�x���}:�s�m�A͝�/������uD�*�v��þ��=*>��-�����XŮ�����Q_r���f�黱�a?[-F&#�/�xv��Q�4�"�[I
�xV<g�h�h�M$�o|w��C ��l�Ⱥ"~�"��,��x����������������m�0n�1J*���Z��g�8��5R+��wu���I��sh"�<�S�DU.��5`l����{Mu��b��J�tZf��rh��ut���x���6�}ӎ��t*��Y|[p�j�!��)���������h3�(����%��eY�qDu�|���@O�9W�=.����nJ���OU�d�_��;��gʓ��e�*~��L��sI���}�vaÁ�����;��b?�mu������ ������P��L3�-ޡ=���Q�hkem`���wE��0ڲ
��$���E�����m�[h~��ȣ�f0jt&-^����YF�d�Tc������&�Z�f8���x�]�Hg�O�A*UWH��JO�0�0���10�S����_�@��֓���t}��S:0+� U���|,������ ��]f�
����wH_L2��X�5���8x��盞s
�E��������oy��mP퇪A]�<�^ܞ�1%eo�Zjq��
2�WE�'�bK��y2��S	�a����O�F3����^U`����;�9R禂G<�#��r(��S�>�U��g�K]"��_����uQ!Z�MzɊU:]�z�Z�����4�Rɉ�9򢂂pQ��ouc�.�_�B�㬸E�͕I��륭����,o���5,8�*�m�O�Wx�[�TU4&����u�xL�j���rX�v*��{G$v>,�C�H��b�"vZ�6�n��
�Y:%5p���
*TK�ʩw�c��$�ւ�'x��j-*+=Ё<؍>�Q�݊��
N},DQ��o�>��4�T�����n�&
�B���Sk����O��?�O����k���:�-6U}�$C��W{�0�:Ӊ%u��n�ԉ�4���1��ƌ\7:j7� �\��
endstream
endobj
11 0 obj
<</Type/FontDescriptor/FontName/PAWSOM+CMR10/FontBBox[0 -250 1009 750]/Flags 4
/Ascent 750
/CapHeight 750
/Descent -250
/ItalicAngle 0
/StemV 151
/MissingWidth 500
/CharSet(/A/B/C/D/E/F/G/H/I/J/K/L/M/N/O/P/R/S/T/U/V/W/X/a/b/bracketleft/bracketright/c/comma/d/dieresis/e/eight/equal/f/ff/fi/five/fl/four/g/h/hyphen/i/k/l/m/n/nine/o/one/p/parenleft/parenright/percent/period/plus/q/quoteright/r/s/seven/six/slash/t/three/two/u/v/w/x/y/z/zero)/FontFile3 137 0 R>>
endobj
137 0 obj
<</Filter/FlateDecode
/Subtype/Type1C/Length 7606>>stream
x��yyXS�������J<Ԟ�<[q�N�8�΢̃�Sd�0��$��A  ��Uq��C��Z�j���m���v���};l��������yxHr��{���w��݋�%�6�M7�7�.�G���־�w$Y@!��}pĸAV��`T1mD	����%A�Q���}�m'�O���;�~������:x��sw
�]����N^��:��������'<<x�{�EDDLs
�����)���}l7{�y�����]n��5��ּ�i�K���ឡ��<<C)�Z��cqВ�!�B���_)]�u��H��Q��=�{n�����y�������O�=9���{�N{o�݌��fϱ�؅�'���Q�j.5��H��6Qc���8ʑOm�&P[���6j���L��SS���j*��ZJM�vS˨����tjeG��VQ3���,j6���C������T_j՟J��T �eI
�Q�)+JL
�X�j(eM�P�(�Q�GЗZC*D��Ԃa�g�|z]��､���-�8�5:�nav1���#�󤯾߇�~�l�À"K;˂�3�
T5x�`��׬�Ǌ��r��e~'k���k�^��ج���9?�r��a/��~k���#������w���\�d���|ۋ#w�=�s���F�+,;���v�U:A]���ձ�M-Pf�@(�qؽ���[U�?]�>�i#�)�T���6�;C
UZu�Z#9��Z ��S�i9��8B0�O7jo�!8
'T-J�-Q��˒�3X���ߵ�R�%�FޢE��B��#��C��Q/�����^�$jP���*�����W�����y��弭�9�o�����e�#
����W�����%h#���G�,�i���)�$�t��ʎ�B~���E{�u���6F�C�w�
�Z�t�Y��B8$*�)2,��1��*��ِn����j�H�(�'��:���tW}�Rʂ�Zl����Ը��=����Lݢ��&8�
�����@)�hӳ��(�e�f�dM�6
6� �v1զA{�$��m�#I��3�ˎ������
I����*�Q(ߋE*�^��ʡA��
s���e������eׯ������w��^���;������歔}����#D��I��Ͻ����u�����Y�T�6�/Z��\�}��%����zA�CT�P��!_
���'a��_'�>h��?!1�C�����'B��'���l�'Z˛��V�T��&�Jo�*u��u�	$F/��c����+ޯ!�0T��<����h�C��OH��\Ȋ��<Q�%�Ѷs���x�AtZ"����?A���x���ā��bЖKP"]Y��4HH�v:x5�85l���<��.$�6�͈��y��P������P�s�!ߟ�F�1&d�̒;K�_w��@���MSല��p^@��1-[����'�"���D�|!�:GH-.bQ]s�d�i`n}2[����=uG�%q�IGz����6t,b�+��T��-@��6��x8�Ë$x��mYs�C]�x)��KO/=�1g6,,���+"x�q$�|ew�:��Q1�ܯ�A��x���� �=�[��Wǻ]�?3�&�w����C�t���0Z���4�EI�������Y��Ѩߍ�_�o�������KFTP�F��]4٠5ш�lO�_�ZP�E�(O_�?�tU��~��7Gb@����2�I�Ju�+BS���b,a� $��������z}�����;h>��E�h,1U��"����au������-��vP�5J�4�&�_ei@����a��c�����:�N|g1x��s!�%a�щ�0��h���ױ��<�=�{J+j��%�s���_z
4H���cnO�������(�;��"4	�Ř#[�L��)��7�~���
�#��է=��%����������D`�!%J���hH��P���8�4�e�\���	���}q&�6!_�[��Mx�1oe��a
UG�^v�N��`
 �L��R���)�����nK�g��ѧ8�T"n���G�c��t(�ȏ5���v����X��e�@��LdI�b�pz�U�H{��(��o3���O�2/�Z܊{cqR�j���&�������������궞�6x=��g`W�f�h�D{�W���̀��P����z
#(u�ǰh��FkCE����鷸���%4ެ�y����&z�k%|_�u
�O��ь��v!����6j��p�F��P�'|>樺���6O��UP�ϗd����`�O���E�
��U�ezii���<�~���ј<#�,9�$i�h<�m������+ۧ��q���O�b�O��t4�G��c�5�2�����6�]�����y��*SdH\��;�*���;2�lb��=���p�{�!��yϕ�r~�QP��	�Y��SQr��ir�+U�{4�j�oR�C$$)��dcq�5�������PJ��rT�C0���Þ���4#��8Mj@zNz.AE�T���GPo4��C��v:n�����\[~mUc�.H�/�����_nݸ�'Qg��2�F�H!\&+:+=UN�
3��x#���z��
�Ԥ�������
���$,)�^MdWX�*}y-ej�t�c=ե�4�as�0�����0������X��!�Ȋ��S�� ]j>�Xz�]yH�mj�;NA�"�Y�߭3�ɦ<h23
F�ֿ�t��-��v�F!�G������z��;��"���x8�}Ŧ�pm���¯%�C�M�r�o��9�D
�n�8��x70s�;�
�EWU���S���%N��s���->zf�b�bm���B��33�y�e�,r
N4��2)�}v<=eɾ���N�ky��f�V,���ޞE+�Cv���_�Tb��6þ��I�������6kt�АKh���
�g&��C�M�D�$�Yw7��n9Ho����L#�4���|^-D�(��=t�de���HQ�	!�U)�6M|,ʕ���
�$Ƨ��-�^�sR.)q�
���w�V)c`?8����|Ԫ�
/0k=�۽i�r�I�Vi��*��ee��jS
��5��|��x�lYA_RRl�I�֪�k�D6V���	�a��B0=Z��Zz�V,[Xt�[m�	��V���2��E-;��#�&��"����)&�H�b��P�����eW�qh���r�n7�Rnܻ���w+��ʰ&���PJf��bw�uq񷦁���P�ll��K	�t_K���z��[1�<҃(�Si�Td�U���ox)��o��LҶU�O���-E��F�U��8�؛D�25aVYc!ҧ�*�IV5A�U��?��G$�B4�S`��+��n	Z�R���,5�g롘��,����m�>u�ȅ��%��L���M����4�`�}P ����ɹ��n����gBJ#��t%��/:���� N��b��:�?77�A�J.p��/`����G�l��	�}e[�W~-D�l�^A6���o����1f�w�إz8٣/�@�	ߨ����2�3^m�@����T�՝7E=]դ������4����ʞ��E!��(�yɚd���ŀ>%�Əes�L��$C�o�dx��A��KY�ED�H��:$�@	�6qY�表m j4	���T_Q�Ĵ1��[G��α�h4���y������t`�K�V�3FM�,�4��}�4�1��7v�	X����{�.&W�
9��@�a��R��r����(Zb�{��>��������VQl�6)_��$}�_#*��HU�P� ��,��J���jU������:'A�����$�I���"�Q�R��/���t��8K:�]�(G��V�?&]5��7�`3��o�y���{Hp�~Չ�Z(��9�>�1x��`n�o��a�<��e�ɚ�$�<Y�����D�	��M�5h$Q�J�:�D=:�vx��,r����\�W�xv#�n�����h2���r�[�;��|4����8��w�ߓX��f�E����P�kO�~	����>:�-��".!-*B���5E��&��m��l�az��=|�<�m$2�]6�P�l2}����E��,Z(B���˟&|�ߕ����1Z��E]&�]�f��]N@y���c�
���7*���"n�ŷڜ/�.C��Cv��8��+2H��+���y�ÃU~����� w$ƃ�t�(�:�(����w�b�B+$�3JIWe�V%KK�A]�P�[�UQ�P��,ws�\�]�R`�-_����Ӱ_�>����OcĆh?pg��؂,Q�_O�m�;����V�	��t��_�~#�6���㖟>s�P�1��c�#�fo]�s���`�ܖ�.-+D��b���Iك�hO��s�[v�K���g���hEL=R!�E�~�*~���k��P�zm��t�<A�����a����x�y��O�.�#}��s���F�M3��6�=�"Ѵ���DM5�;�
��V���#�����-yP�	y�2HJQI�K}�Ba$��{�:�ʮ�-eD�ך�2�����e׆���e�zۚ��#'D��IS������QCO�V�e��N��u��A����`}���P^G&R���1���|U����m$!��/�5���y���67�~r�����frj9���%�c�o)*UB
�9�����߄�3G�f��`I^��ь�ف�ڔj��\�P�ҝK�e���m:���jT�&����:��o�Z��ŁZ��?c�wŻ�́>�B�$�[�r�{��I��r��$h4��v�mvL��v"Q$��R�fգ�PJ0��,O�3�`� n��/:��N��Wp�\0wz4�.����<��2 (�-ĳ͎�K�����k��oQ\O��j�Yլ�ů�+��lq�(���Hr]��cM9p5����@
�g���ViR3�(J�y)7���M�I*�!�H�u��.V/S�� "���-����y)��.5�a4����4��k@�9~�_*�4�L��'ϐ���� �t����a�ڭ�>�[���acFi�����-�X��YK��o�uFc�qMjy���;F�ֱ[�!���Mj>7%�_�n�ӛ4!]����C��IVȕr��s�5v�5�B�}����Ih���g�WM���v��Ί�P@	h22
	����ss��>��<:�oQZ�c���o�ܿ~{�~���o�X�&L�f$I`酣��M�7@�"���$�3�Η�o�"�$pR��5��ǫҕ�ĩ�^�*sW���q���C��~�5�t:�ټL�%2D�o��
��^ȩ��Z��M,R���4�ϰF�:3�޴�z�t����ousQ�Z����24`�؀ξ��<-M�eY��	�L���y�x��O �K����2s�|��s�Q�|$�oL܉��o�4P�f!��Z�yқ)ϛ���%S���rt���	x�f!?E�TPa�t�'�u�^Te��z\O�EBDA��W�8��頬�P����R��峗B���[Q$��յ��Jm}�Z�
�	Ӆ�V���\��6F���no4����OW�?��c�Y�n\�{���*)FE~�F�P�TB�p�Y�^<j���11\ǹ)�A��VŗUT�~���a�8,�'����@whS"���Gm#˭�>R�IF:��+aG�}��CBJ���3�s9��B�Vŭ	Z��$��ɮҘ�����{��6b������&�>��$ڿ���[n!�:
T�4�_��tf8���_�@�F���<��ė9 ��KJ�I��ʎ-��.�\fv$��]����2��+�D�І��<T*D5h{�n2%^��-gؚ��������ʰ����,��}�*�Ww8���5L^R�,.-1Q���cqj<��JYNR^azn��t�T�a�~��
yt�����}�����bW��Cܦ�-O]���t�#��λq��W��~���q�1��b=`�!�G�%x
���}����c F�ZTل\GXk�X![;es�^��
R�&�1ҏ�_
Qk��4�ܺ53�ZG�V�t��O���L"�1����[��v��&�ԅ;��~6Z��
9�e?�w�ׯ�t�]:/m���>����p<ڒ��#UQU>�JP)���g�.���ys��\�e�o��2����Ӣj����Ԁ��ؔ�Ud���/��I��
���O
V-���_����^
c
E��\�A2�`����mX䫏�1��5�� �3��V�̑sR��gI��}�PU�*L�ɪ$2�N�,J�c�M+&���]>,��GҐj��!�1X��<��*$@���G��k�.�J0f�]I�[����,��t����Iы-p�[�t;��/����$��1I
ө9�Թ��d �V����ca��	�գ��N��mD���V�[����S�]b|�9�����Sꈸx���LEF���h�$"iW�Jp�=YN��Z%�4��1|�����,�63��+n:�5��aOvT���v2�7Dls
��
�C��3�kɘ ����PYm���I�3��$�["�1������Q�o&uz�<��~2T܉���l%M���ӕ-�}z.���W��ks_r��}<'�=D"~�u�Y�	��O<�G,�ĝ+�kG�n�÷ٵpI^�
����[��I�	Xg�J�`�ۻag�w��=��]�)���7��T���ӑl9��D��ieL�����-ι\���y
H�E��X ����}�ƒ��=q��r�i8�=�}6���ѱO��>��JḨ��c�L_y��{�=�i����j��[W�/��{���e�h:�ט�3.L?�aZ�fo����j "�զ�َ���e�o�⇇�7ʎ{�p��1�k���,��:�5��8|�}��%�>�Xw��V3�T7>���cJ����	-Bt���q��=���jsǲkJ�aEҘ�$��gݾE,q�#��>�c��[vE�u�������Dԛ��	i����A�1��/G5�)0�TkyӁS�
���W�7�/}-�a��7i&GT��a=�V�X/8�)�l@�L��B3s4Z�4ShbjJ��۹be�bX�[�"K��Z������w�օvԻZ��I�z�Jm���13]�����w��xH51onRn�&=/�3��؈Uh�����i�Q�ھd����9�_~@R��E���K��5MG�ȦMk��*�X��E=Ң�GQ��(��?�ml�舕t�M�#2�t�%������]c׍�^
;��3wu���Ĝi�j50�K�KY�v�$�K�fo�ïP_������op
k�D�%x0��C�M��Z���&�k��4�<�no�v�^	XH���<<����>Z�Lf�6��������'�y]{�X�o1}9G�aD�����5�>7:{��r�M���L��vL�_G:���"�÷��?h�z�:Ԝ��VF���\z ���$H`0M[J������a�|���z?�oo{]�>����������t���
endstream
endobj
111 0 obj
<</Type/FontDescriptor/FontName/AKTSTT+CMMI5/FontBBox[0 -194 304 122]/Flags 65540
/Ascent 122
/CapHeight 122
/Descent -194
/ItalicAngle 0
/StemV 45
/MissingWidth 500
/CharSet(/comma/period)/FontFile3 138 0 R>>
endobj
138 0 obj
<</Filter/FlateDecode
/Subtype/Type1C/Length 336>>stream
x�cd`ab`ddds���4�TH3��a�!���;����|��<��<,+��'�=��{�3#c^q�s~AeQfzF��F��������������cnjQfrb��obIFjnb	�������ZR��a�QRR`��_^^���[��_�n���P�Y���Z�ZT������W������v��t��-(-I-R��OI-�c```��b`�e�9��>�Gߏ��a�;~�c��x
��E3E���C
J�;;�[8Z��O����w��;�RKrs��m�5��49��n�6��|�߷�]��<++??+ky��5˗���+]��yڴi����N�ɾ��)��?���<<]�z�
endstream
endobj
42 0 obj
<</Type/FontDescriptor/FontName/GXIXLG+CMEX10/FontBBox[-24 -214 474 334]/Flags 4
/Ascent 334
/CapHeight 334
/Descent -214
/ItalicAngle 0
/StemV 71
/MissingWidth 500
/CharSet(/bracehtipdownleft/bracehtipdownright/bracehtipupleft/bracehtipupright)/FontFile3 139 0 R>>
endobj
139 0 obj
<</Filter/FlateDecode
/Subtype/Type1C/Length 507>>stream
x�U�MhA�g��]�ڪzp��%�BI/�z����
q��MJ��lf��X�1�Y5FD�4!�x�bE!�� ţw/��&�4b�@i���~�!�K7b�A�CO�N�
|����Q*����z��؇��3�֎Bݪ�~��{B7Jfn1KP8=�b���it2��yl�Ҫ��*��J��2���s��P�L���̌m�5_����٩id�H]�lq]�5�f�<FC��0%��al������`�i�%9#���2�C�
v�v'����2v�����H���Q��m��j��<_j�9&������[�.u�!n��5.+e�t����6��/6ɔ�,�B|C��)H5~>�e�ʭ^��E��+��wʦ���s��v2ϫ/�[*�]�3��Lb����mZ_Qf����-�0?��O�*�1�e��|�Y���آnw���m:�K�:N����$W.��S�!��0uZ����jLV������Bo�wH�t��zC��q�����
endstream
endobj
9 0 obj
<</Type/FontDescriptor/FontName/LABKNK+CMBX12/FontBBox[0 -201 1139 700]/Flags 4
/Ascent 700
/CapHeight 700
/Descent -201
/ItalicAngle 0
/StemV 170
/MissingWidth 500
/XHeight 456
/CharSet(/A/C/D/E/F/I/L/M/P/R/S/U/V/W/a/c/d/e/f/fi/five/four/g/h/i/k/l/m/n/o/one/p/r/s/seven/six/t/three/two/u/v/x/y)/FontFile3 140 0 R>>
endobj
140 0 obj
<</Filter/FlateDecode
/Subtype/Type1C/Length 4377>>stream
x��X	TSW��1$���S�Bkop�����:�8RQT�MPd�)���d'`�Y"
�j��U�Pkm���V��ڿRm��o<���������u``�ܳ����}'Ʀ#�HXW�yk]&[_�ߐ��{�oJ�lln񐁝�l�~�V������}�D�q
�����4z�'��3��w���<�in�O��VU���*��'HA	t�����4�����oM�5Q>1$���1㝢�#��V�����}�9��G8��
�q�:�Į�!A;##|�C���33nnp�������#"�U��Eou�����o��g���5A^v.��L��i�f(���`�3+��HƓŬbV3k���3�Y�L`�3��ƍYȸ0����f	3�Y�Lcܙ��{�&���`^cxf 3�q`�S &�y$Y 9�cFC��s��6o���|.�eQ��r����m�p'{���my�>�{u�U�����޿�{�?���k�wU��6������܀�b������,.)���-3y�~�pm�&��;^8hb@�����E+������~h7��F���g���Ն�L~�8�&(�������ϒ{b�i��8��Ef��$A)Jp3J��A<��������7�_�a9��"S��a��|�d+��A�^=�
�Yd�n�|�,|�@��.��ϧ6���$uh�h'�1��7&=&.d��ad �p���{���@dO��}>,iP�{�>����BJ}�6p3�p��-m	f�*�%e�m�\�!��YjI�L�+ 3R���yrQ�\p$)d"A�oCƠݐE{�ݗ��MJ�D�"��'��,�)�=/�5�ৢ/N��|�I�I�	�[UK��s��
0T*(�d�G��A
�gG#��q���WE��]�|�-�Da�}��ڨ���S,��;�9�Ml⏜l+>
ܕ�ā�p]�T�,?H��֭�,��8@�����y��yG��8��U8��T��؇x(��o�x�ǲ��3�#^5�%��@z�z�m�۴h�p�5m�f3����3)�k��W��d��Ydp�����y�V4c�J>'I5N��bt��0-)"<�,�$Yǯ�8�(-2�����˞={���a$o��)�S�K��h�۴��ʴ������w��Tq��r2�_��&E����Φ���[��k�W����#�Zf����.�1��@܇:�D���(g˼��l'��&�)P5����؋�SM�S���S��T*�g�%�����X!=#Q��R���\d�P�Y���N3�f���ca���u��e��!Bj�N�85dD(��MQ��K�%������x����PS�~�w��qu�����p��r�Pj\f��9֦+��
����҉5��R�/��z7K�W��p3��*�n�ѣ3�ߐ:v���o���!�����A����j卌�ȵ�A~|.�ǿB|-;{�{��W��K���E;�j�����Yп%ǹF��u��Q�hCy>��5���Z�hc��jG���Q�k�eP�MG;�Q�
�'�L�h�*�u�ie"o��)�=�]��s	83�Ղ7�-��܁�.O��@��� =I�^v�,��.�A��B;�.�8���.CZ8C�!���ͩ&��Ʃ&I=���:��x�8�"�IlӦ�EW�֔5�h���L��PܧM>3[Y2�L�B���E]���R�vP�,���r��,���P���'L�X�m:�=2u?�hr�c_Rx �9���{ss�G3�I��'WBHW�%ei*Z�b���[�l�n!�.Vw�\gљ���sTB�F3����(K��`�:�R��փ>;G�e(%o�TJy��*�R-%FW�ʥ�����$��-�f�8':=����ɰ��Cp��F�9k��F�x�,)���"�ፅY9����צ����O@|FF�.�Z�=�5��V.��B����e�;F�%��%8�7�-�tH�D�A_[��)�,(0\���Eu���-��J
:���,D[��=��DH����ͮ��&�!6p����8e�צ�t:�N��a��~wUY���	k\M�P�a��'�(t�C.[�y��Q'�gև���h��ɴ�j*3���r���Bӣ�Q�h�"��
�W���V�$F�VD�3��tz(��3z�:^�I4&��}`�ۓ���z+��j�3���Tw�}����L�Y5$C���"��&\�ڙ��J�'VQ�&�f6�dK��~��)ĉ{<
Ϝ(1Ux����E�H:������F���Jpy����yc4AK�i�P^jz��]���P*��P��U����N(T͞{WX%c�ҟ8=u�q8�����b!5F���]�X��F���g56�&�Ѳ��C����r��~g��:	��ԥȞݷ
H�u��ͤ�S��O�M���(�&%�5��P�򆢖&����D�C8a�\�
���H.ݽ�ۺ�O�)�s<�+Ƿ����w�LE���V����z5]u`�u���I0s�b�N&)�ۨ��'���7a|���6�?7ޖ�@\=E�g���5�!!OQS\��ϐ�F-^<�.�u�@aIYe�!��[��+�宥8	��]����ؽ+�|AY��,&<�=VrW�2|���߭�	+6T.�)�Fn�4�2;���}Q�^{��p��q�v��m�nSg�������VP���{���%(R�2�ֶ��8r�� �V�$���9������Lj31a��g=qȠ����z���p�{2�q:d��YgA~}U<��{ɏ�����Z������ﶮ�_
�KɌߥ���i��!�4WSrbS�47c�C��'=��n��3gz��M%o+��
���gn�F)�[�|ӎ�mށ�>>u�MGMuM�OS���s�F��A���x��8��,�la�I.>�/H1[\Ə.��
�V����{ɠ2!S
��n�G��A4��dA�>�l�ѱt���B$�6�)NyL}�$�@[��_k9��b3�(jqd����Q�|�G���s���ܽUU�6ݎ�zU�O�?���"�R��+��J�������^��V�6��A(xBD�l/��HIOM��E���2Q���5�`Tõ�[�u���ho�~�M��S�X�qIQ'(�J�'4�
��K�b
�q�陉�t���`�.���Z�����Y�
���Ԣ[Es���}�
�P�Q���A$�я%�F� ��5_?'�3���`��/8��s.,qxNz�&t�C�
���^�[�!Ȳ��k��;3����\f�e�X�,oܛ�w�}fy��R�翂���փ�iqD��G�$�fy�v���h�z�b�o�r�ru�Vo��e���Y��m���Z�R�>�v�،ܸ0 F����h)�/w��?��I�9u�Hy���� ��l��B�e���|�~���#���g%�y��G�A����
�N�J�P��hE`"E �v��a�C��`�
��Y�C��!��b�o�qw���!3�X��D��v��1�-�=Y�%\�×��@�2�U�Ѫ>W��d��:'ۼc�
U+&ŇC(��:��t�����s#����'���HͿ�_��ʨ�S���q���LK�in)�`ʤ����5Z�.%R����D~ڌ��r�D�d�
��	��wӃ�ٹ��etl5K΢#z�kRр��e�5�I)�YK�d������]���o?m�G�:]��_6v��5�؊����́e�Y±�mYe�=l��:k���RA�HTR2�i��nq���	ǎ�����ך$_at�*i!ޡ��m�C�^�Y�Aa�-��Z�)��[���d5��μ����~$����?�����������xk�ј5�K�W$�o���>#p��-((}S��"�?T�M�E�ҵ���tn��n��Im����Ҫ[Ѕo7��ʫtYa�Z�MH{�r���
J�l��1��zx����R3$���:��,�c?�`�etS�8�X/9�b�>���z%|W��JN�O��(H�i!-I��>ѓ������4�Cp	��[AZ�N,�3��r����e���+#}�/+��_Ѷ�XyCh�����ޚ��pb�}��3�7�nH	P*:��tm6HN ��8@���x�8�����ͭG�P�oȨ�I�	���ouġ�}-�~<��#�f��E@�0	~�
��i�
�+j)L�*��\��B����8|
��i;u�1�=j4�=̊sB�X��VH<���$>�s�茥2�+��'������q*��f9���}���o�M���r곇��zx.��s�Z!��pov�����z['�ͥ��}B�葋[J�
�dS6k�EI/��fz�]��\;;�T�����3�?�q`r
endstream
endobj
109 0 obj
<</Type/FontDescriptor/FontName/POAFWI+CMR5/FontBBox[0 -22 683 694]/Flags 131104
/Ascent 694
/CapHeight 694
/Descent -22
/ItalicAngle 0
/StemV 102
/MissingWidth 500
/XHeight 448
/CharSet(/b/d/e/eight/five/four/l/nine/o/one/seven/six/three/two/u/zero)/FontFile3 141 0 R>>
endobj
141 0 obj
<</Filter/FlateDecode
/Subtype/Type1C/Length 1952>>stream
x�]�	Pgǻ�n9L:jbzFY9\J9T��(ΪY"�!2�#�0 �\p�(0�C��"�(7"+0��x�1�^몬�%�	��������6X�Jm�����z��~�_�i�Ԅ�i�L��p�0G��f��J ylɘ�XJ�Ҵy&;}*���)hMIh:6^���HM�DF%���.���NrWggO�O�:A�������Ա�$�f�<H�Q'������vx͟���2O�8O�����<E�%T'�v�#�+�qI�ժX�|\ڼ�B�#9I� ��F��(���&o�Powvqu[�p���'E�S�(��ZA�Q6�T��C��>��Qө�ǔ��/eJS���t�&�L&/$Jɏ�
�a3�����'�y�Z�����iD"�phC�ф��aNL�
�D[tF4�-yRK�9�t���G*��o�H��c��&��@���I����c�*#�����s��zy|̐�:�0�A�>���1���2�	���w���.532>�E=2��y�wZ�S�=�g#����x�����3_��Pt(������c���o�E'��mВHF��W���e!\sύWķ�fd(#��bbCS7�Ji�v���wg�=�^cK~�$�I�>�,�K���Tb�f��q�RKu�l
�K�.<g\�
r||2"`=���6ƴe_��ɻ��u��\E����gV��Ե��t�H��`�d�h1T����$'4� �d[�/��T��i9Y��e�>�A��;��#��7P��5pe8�eM7���G�qb;0
/D�^O%X�����˧�I���r�A}{�YK[c*��
‽���L��#x_t̿�.w���H�b�*4���./>��m�C	�I?��
�pn����'�;�c��r�A	�/b�J[?�i� �����4^~!f�Ys�����"�`w��K��@~�q�]�(X7�_&�P0�b���q��YP:!����7��qּ��0�SI����{���&R)��s����_{��,~H�n[��b�c����H[K|��|�����[`_>pt��3_�&�{3���jF��f�	����qRW+�J�'I���{q5�aΪ`W��sJY[aYT�����1�;U�h�g���W/���HO�h��ƿ�Evp�U�gSB\6��=�rlOmd!��5�ػ維P;�m�����ub@����@��(����J�_Н3aS�/�O���u�;�
fa�l�t�>*Lڝ7�7�zΙ�q�Q�(i���q�r俤�}�ߡ).nB�a��xzT�J�ח�	�p�V�0T���*��./;'�xu�_�� ֖�;�+ȁ`�a�n�cvAFEin^i1�j쫺)�o�v��@��yS`v2�²����
�p�mL��I�dlr��i舓G���!�U���[�	��E��75��#��_T�s�]�[��\�T@gN}���4а1�;��[��ϫ�+����Y$���Ivh���Tm3���e8WSzB��No�Y�U)XtMO�z�?�����ƌ�Y��\���cµ�Q�A6O>*t
��6/���	/��b��=�֒L<���������V%U�d�vi��ҁ��?��W�T*��4�;Xͮ=��H�����V4�r�}�����-|{M"��/�OM}p���0gčb=g����[���gm]�����g�T���}4Gڶ��z�(_s[�2N�v�>X��ѓ�%nD�U����L�m)��[����3��\��:��B������[͂��b����x��UYK4���[�@�AS}��p�'z4nWd�F"E{�Ao�Gc��x���>4J��)3ւ˕�7v���B�1���%�s�.��=�o��p'��������;"3{ �[<���&'W	�r�+-����e��|Ȃ77u����Tji9TniEQ�{�R
endstream
endobj
40 0 obj
<</Type/FontDescriptor/FontName/AVTVER+CMBX7/FontBBox[0 -249 926 750]/Flags 65568
/Ascent 750
/CapHeight 750
/Descent -249
/ItalicAngle 0
/StemV 138
/MissingWidth 500
/CharSet(/one/parenleft/parenright/plus/zero)/FontFile3 142 0 R>>
endobj
142 0 obj
<</Filter/FlateDecode
/Subtype/Type1C/Length 682>>stream
x�M�ILaǿ��p(R���Đ�@�p@�����14&JhjӖ�Kڡe	�h؞P�J�Z�q)n1UC�A�^����ӛ�y�p����%���c�<�0�0�ڮ7�r����r��2�����\�d��_ejtaW!^;Id��O=�a_��)�ݕ���������k�[]������M6�)�lbx���W����(z�kk�������=>ǅ�j>�+:��/�B��q���K��o�O���o��>7!$����PAH>�HQ�<��~D��J�2�ʼ�fU�]�v��B�LR��ń�1srؙ!��8��i�N
@�@u}���В���b�7 ���ŵ�`��U�Sc\��K�1F�ٗIϱO�i��6$�0���#�m�Z��i�d6��a��`Od��*S:������p
u2�'~�`�8��0
�����(��˸E+k�&���k��>y���c�Ctow�
����h�j���p	�n�ǚ�G��f7AJS�F6�L:�a4/�Mk��4vX�yK����}�����f��r�	H�'�	|�<Ǧ�^��ZՑ�V:��{���k����=�N�����R����:,���lU-jڲK˱�ă)�&��
Xש&"��0Z�#��(S�X|B�/o�qy����[\�]NE�?��>+
endstream
endobj
97 0 obj
<</Type/FontDescriptor/FontName/OUHFBR+CMR6/FontBBox[0 -21 580 676]/Flags 65568
/Ascent 676
/CapHeight 676
/Descent -21
/ItalicAngle 0
/StemV 87
/MissingWidth 500
/CharSet(/eight/five/nine/one/seven/zero)/FontFile3 143 0 R>>
endobj
143 0 obj
<</Filter/FlateDecode
/Subtype/Type1C/Length 970>>stream
x�%�Lg��z���Av��y\�!��9�f�YD��B�r�����dX�A�@�XK�6[̆��8T��s��&I\2sْ}Ǿ���%/�����I"DA�$����,��m���B�N�UZ�H	5ꐑ��#ѱT��@P$)�h҉���rc���U�%��&�s�'$�ro���T_���-e����M%�/���zn׾2��z�V[[[��f�h2���s��2.�7�&+o�2�*��^� �&�t�P]c�M\�h�MUA(��SR	"��$^"�[�W��B�y��R�?J��%d�m(|��t�	%M�� n�m�=�u�ݨ
�r/���FY.�r�
X�[�=,~r����Fa�����߾� bN�o�+��%  �.yQo�3��A`�s^#��������CU��l�A9۹sr,����zg�X
}�� �D�P�/��k/��)�Ҥ��<j�!y�����8���{�Y�7�F��8
=��w؁�ASC��:	�{��]�����(p�qCk~EIT%�AC1dB�%���s8O_�W6��jWw�H��k()�b�@���8$tK_?�լQ�]�w��	�q�����Qǩ�3��1���_(n�����s��_��*�l9�8��w������4L��^����W���}x�'o�V�(�AϘ���iX��w��ġ�Y1��E_�Xg�p��%ۤɇ���C�F[��!�~Џ���
z�.g�ƴ���$������⌴���&�����u���8+@�O[�G�tme��ܬ�wǼk|R����AI��.�g�E�o�
����3�Ҟ�!A��������4(
q�GvL��_���xK�W?fd'�/���0u��q\�՟7��Kg���p�q�pFvl��������Y�^׏Dg�[���������M!�.u��K�^P?O���*
endstream
endobj
38 0 obj
<</Type/FontDescriptor/FontName/SFWNEH+CMMIB7/FontBBox[0 -16 943 702]/Flags 131104
/Ascent 702
/CapHeight 702
/Descent -16
/ItalicAngle 0
/StemV 141
/MissingWidth 500
/XHeight 452
/CharSet(/C/k/z)/FontFile3 144 0 R>>
endobj
144 0 obj
<</Filter/FlateDecode
/Subtype/Type1C/Length 815>>stream
x�%QLw��UO��I�0�z�X"��%g0Z%j�[J������^�\�^m��*������
T놄�R��X�d���a��%����iL�-�������뽗�c�"��F����ey~#��T�߬q�X0/�t�L��:��j*F��bg�=F�)pL�����TP�jkwTR����R{4ǴX�)����+�d�P
lC��e���;��=O���b����J���6�L�h�,�Jճ�<u�꠩�ݪ>��u8�<�Q&����1�;OcX9v;�i
�Ţ������_���k_@�jw�KcI�B�Hu�Hn�א�����7���Y=�~�E'�7����'����]�)�	~��)�R+̪,��Ϝm�.ކ0�BPћ��B+�O�@�翯�/���I���^�#��5~T��G���Y�/��<ˎ&^޿��s���{���0�[��Γ^���@;t���m鎄��M����0��Bb�00�_8��݌�F[m�M��V���!D)NG 1@Nߝ���$L�cݷ\�|Ӑ��Pv�a61��e/�:�� /��h�	��e$N�B��-R}a�_Af�aXAu�֡�h� "�ʆ�wh�K3?߹55��D��� 	1_�E�8�>�=�|���{���H6�N7�%J���?/�Kc|(�L�_|2/��̝�d*	�������!� �ٯ	��r���7����-����rP:=K���8���9d[���%�g�d7�46�!M&�cc���7	�p	^��.%�"!4�Q/���G���js�
e���\�X�Je^�[�N�a�t�
endstream
endobj
90 0 obj
<</Type/FontDescriptor/FontName/DIOZUW+CMTI9/FontBBox[-25 -205 885 705]/Flags 131076
/Ascent 705
/CapHeight 683
/Descent -205
/ItalicAngle 0
/StemV 132
/MissingWidth 500
/XHeight 442
/CharSet(/I/V/d/e/fi/i/r/s)/FontFile3 145 0 R>>
endobj
145 0 obj
<</Filter/FlateDecode
/Subtype/Type1C/Length 1346>>stream
x����OSw�ϡ�eu[R�����;�̈́�6����f�h̼U(�@)����^��[�BK[� �^@Z�)Sw�.�L�Y��%ۋ��9�e��{�������~���C��EѬ������[t.J�Ϡ�`I�_��U� �9�#�I_�Z^�N�����P�I�/�4+��:����z�����wv�*����j~��/
�|y�i�UH�E����}�\�\�s�B���e�iݞ-�y
�\�+��6A
o��I���/���/�b���U.���$5i� �TVZ#�A�
�ي|��G ��N{C2�.�o�%c]F7+�5���-lz�6No#Qz�s���w�Z�<0���[Lѧ�
$.����N$õSB�ԃT����`ƺ��W̍ǞFǆ���L-63Q̤̝`�n��W���$|8�.ВןR����(��[j�
����������~z ��N3�'�+?x�9b�gtS:8�5��cЖ
��qC
���Gk:a9Xq��3j�8Ş�
)�xː�}�/��ya�?z12������G(�K���u�|X���F�����N�Y
�9�;A���à����A0�c�z����:PZ�1�dZ�%Kr�'�!-���p���K�鸖�7�T�Je<d�w�r�!���;T�
��6�
TXzZdzX͝x9���ZF���d^a�my7*�ߜ����)��x��}N,����݌�J���k7�I�s�#>�r��O�TVi���r���Hݹ|u�[�c7�,���F-I5�TAz5�#ʖbQ�����F{���86%H��1[w0�L�ҟ^�<{�"n�=&��ը/����`%�.��l�.�!9���ߝ��M���̻p�`S�{�uOQj���-�l��	k"m2Y�T2h
��������h��fi3�:IQڄ��~&�$��1pD.��e�00Q������L�^w��t�ޡ3���'`m����0ߤT�-z��M/VuQ��u�����������	t�D��$��w�~;�1��m�� �1�;�W��[�	��v�
P�;�ZfvA���Y�[vn(�����uPc�MG��ٰ�VW��g����n�G�����}�Ʀ�>�q��W'��O�HT������t\G��X�>fl�J��~~��W��dć�?	��kv��NnPj��dn��D'b�'# 7aDj�6h@���i��/��9f%��2�
LQ޾iYI�J�$>L��*^X�=V�����,�
���g<XLT�6�j�I���ij���٭tq����Y?�<���J|EfA,'������Ң�
endstream
endobj
49 0 obj
<</Type/FontDescriptor/FontName/TZIEEQ+DejaVuSans/FontBBox[7 -176 675 742]/Flags 4
/Ascent 742
/CapHeight 742
/Descent -176
/ItalicAngle 0
/StemV 101
/MissingWidth 600
/FontFile2 146 0 R>>
endobj
146 0 obj
<</Filter/FlateDecode
/Length1 3556/Length 2319>>stream
x��Wyt������7��d&��` ��8 B���C٪m#��H �"D�U0PȈ��TA1R��u�Eǵ��m�h�7��S{N��zz��|�����۷�!ED� ��;�3��yx�2f�Ԣҫ��(�ʙ8kf��n�-�{"sq���{ΚBd�L�'�3���~|O���L*
_�;�^�=-`�j���\��K�Μs��|!�=�&]�wX�kjќR=�1]�c���M�tM?NHj鴲���U����J�9?o�Ջj�V�K��6��"��.�Vk/-��yEժV�`;�����2��.Mj(���mc�5����lP�N�&}�ާG�}V�Q]���x]�z`�cvʑ��,?�vT�>�2:�O��u�����.:#^�د�J�A�$���F�y�HA��:�(s��ש-�DwP-�z�m
�-�^򪥋����s�X�?"��d�F*�dꕋ��,�D/�&4�6�0�ͳ���Q��Q�8��K�b;�+������q���Z����z0U^��S�����(Vs%��n����.�D�wNۯ�2�����Q1�c�Ö���%X!��V�P�s�Δ�b�Y.YMC/�"�<�C{)�K��:����s�>%9W���E�Cu�b}^jM����hX���j+4$\�3� xtlZF���3XMë=s�5MM�tk3�ڤV#W�C���⩌.Æ��̻fu��<����I>0�y-�ڄ�7d|upbIp��2��J{R�y�$��F���<�C�5t3�1�:S	%�E6=B�$�$+Yκƪ�i�Ĉ����\����_B�܋�"h�ӕ̧�����!�?G�'�'}�q.�2���3��͙N���||�a��(�3q���Y�}�G��]?�)�ۇ�㤨�,G��A��'�����qƛ��;�o�a��Q��m��ڶ�U�1^_�3���d��x��2�%Ƌ�_2~��9�0��/,
�5�Ɓ����!�������9M؟��a�g�e<Ǩf<���3^<�;d�c�.���.?������I�O;O����}��l��6/c��l��1Ɩ�	fcs6=�b6���F�<���6qa���<̈xP%��"X��k�߀u^�$��k���5��f�!��Е�Le!*s�C!�f�z��Y�x�+VJ�+`�r�Y�r7�	�,��R��!,��ǌŋ|f1c����������r�cި$3/��ss����Y.�ǘEY3��E)c�^�=i�c�/�L��݌�rL��1�fLdL`���(�J@!���3����(
\�39�ܙ�1���yt.F%!_�&�:�`��fc�w0n��6�3n��=�0Y�:�6C[`H�bc��ߍ``y�[�sk��0`r�a�r��������~���1�s��σ��l�M}�(���M�z�r��6z�ѳ-zx���m�����6�<�t�kF��j##]���Ɛ�ƍ����:�qCǐ�a:��!�6r�zF:�}"�$�4?�a������6�6�JS��h��Rׅ�R*Ւ�,��S��0Z0���g�$W_.�r$��ex���� �	�p3\6�q��p�Cˢ�; 	����g+�1T�
/Y�:�/�o�/Gy�sD��59�UN��D�K*�,�4e�z��;�'N4tk�K��|iŚ.����3qz��|��S��[zS/��^�@>E�h�g�V>\�p9}F;b`����B.�Y��0���I/�����>�j������v7�9ms�)��OqWY�*?���`�R�9��*�Jt&�%R͢RZE�Ng9��U�5FX�&�k��e��=�9'n�ZnU$l�AD�,��x��z�t�!�:���;ce���ʸ���{%{���^kϤ/"� �Ǒ��tkNz
U���U��v>w��"��!oj�II�O�~�f_nȺ,U���Ύ���p��>��mob{�B�Ҳz���!�&����p8۪��NOS�T��͛��a�y�ڵ��m�ъ�UOp�+[Ǯ����UK�b�eڌ�;_|nŶ@�v��w�[����(�R
��i�yܻ�U�S��]�r�oU+g����V�c����.��/�u�֖���U��g�D�'����l:�]�DܨlE��O9�c~��WKU��sfB������o��<X=��J��5���G�J�5�ֵ�! ���Z��1��yh��L���F45	U1*�n�Vs�����s�Iy����/��޲�>����1��b#56}����?�b3�lSN�LD��w�b��Q�?W���q����vW�>�~���/O^��?�����OH
endstream
endobj
36 0 obj
<</Type/FontDescriptor/FontName/XVAMOC+CMSY7/FontBBox[0 -17 714 518]/Flags 4
/Ascent 518
/CapHeight 518
/Descent -17
/ItalicAngle 0
/StemV 107
/MissingWidth 500
/CharSet(/multiply/openbullet)/FontFile3 147 0 R>>
endobj
147 0 obj
<</Filter/FlateDecode
/Subtype/Type1C/Length 438>>stream
x�cd`ab`ddds�
�4�T~H3��a�!��]�3��,�n�n��?t��g~O��/���ȘW���_PY���Q�����`hii��`d``����Z�������X����X��(�'g��T*h�d��X�뗗��%�����i�(�g�d(�����(���(�%�*�ݦ&��sJKR�|�SR���R�JsrRK���V0v1032�������K�j�������~�a��#Stڴ��ݓ8f�Mih�訯����;�w���Ʃ��Mݒ�

�M}�������ڮ��V��i
3���M�&���{��	:'vKN�1e���ގ>����a�òWq����~���{o��~o���}��y�^���ͣ����7���\�y^���)�;�������'/�^y�򲽑����<_���K�~�Og�õ�{�| �e`Q�
endstream
endobj
88 0 obj
<</Type/FontDescriptor/FontName/QAEHQH+CMEX9/FontBBox[0 -1757 576 42]/Flags 4
/Ascent 42
/CapHeight 42
/Descent -1757
/ItalicAngle 0
/StemV 86
/MissingWidth 500
/CharSet(/parenleftBig/parenrightBig)/FontFile3 148 0 R>>
endobj
148 0 obj
<</Filter/FlateDecode
/Subtype/Type1C/Length 462>>stream
x�cd`ab`ddds�u���TH3��a�!��-�S�Ǖ���<��<,�~�
}��^���@����1���o�s~AeQfzF��F��������������cnjQfrb��obIFjnb	�������ZR��a�QRR`��_^^���[��_�n���P�Y���Z�ZT������W������v��t��-(-I-R��OI-�+H,J��IM+q�L���r����Y
�������2l��3~������O=����ޮނeZo��+������ ����#߳��̜T��1��������X����-���t�>��G�������Oi����1mj�4y�>�r��V����o��g}�j���]�����������%���ݹ���Փ�2{;l��5��a7}��}�w���ں���v��i�Sg�v/Z,�}����v?�����*�Ke>�U<<Wg��20j�Ϊ
endstream
endobj
51 0 obj
<</Type/FontDescriptor/FontName/PASSYV+Sawasdee/FontBBox[29 -153 298 764]/Flags 4
/Ascent 764
/CapHeight 764
/Descent -153
/ItalicAngle 0
/StemV 44
/MissingWidth 365
/FontFile2 149 0 R>>
endobj
149 0 obj
<</Filter/FlateDecode
/Length1 1820/Length 1099>>stream
x��TMlE~���nH�8�t�0�MR�]��!!!nY7�c�ZN��U��nCiZC��"Ú@��H�8!�9D���K��9�rA\��!�@�7�J8 ��jߛ��{��fv�@��r���	������B���b+I�����M!p�c����p� T.\�v��w��X`�R,�:���	��y�q�����/,.7��D�t�Tl�9�P\��>�%�mz��Pi��Bq�z��bӾ�׫�T��6�����h�
g�?��Y|����9��Y��8�����,�� �AG��lj�d�<a�8n��u�~�H�@$ƈF�g�j�	Z6o�TL9�\ڋ���!3݌1��CeE~��A�mJ�g�H�LI���lbɴL�Z[�l�y�Z��!;]+$�ƫ�zmH��i� ���!�^�$�0
e���B���Aΰ*V��ɨ$˦d�Vޱ8a�����1�C��.�U�q�U���D�"5hy�I���83RS�NZEŢ�b�)<9�����+���v���VD�%�ea0(���i�M����B���
5�Ӓ̈iXXPF�je,����b,��!����$�,���������
����m�*+��ќ����vt��R$��ؒ;�\�
ew��$TDIa���Q
ϔRuB	*FK��ҽ�թ1D�/(b������xG�����d�j�s��lD���n���aJ6�� ����Y��5B�6k�DY/k8���v�`�I�Rӄy����*fK#AY����5�d���yĻɺK�)�\9\�z��u��쓃rZ��^�~c^���Ӵ��][��
��s�a��u��u�,_�a̭v4κ�����<?3o��jQo�ݑC*�D�1�B
����746��`�p�����G:��������p���'��dTό(=C��C=�HF��.���x���2+g[S���Lttv�q�̍L��U�.�^}��o��k�z������qN�=����wb����I����@Ⱦ��;ƛ��W�W˕��J��?���۰�{h������t��_��;2Yc�}��?���C��������XK���~��G
\Q
endstream
endobj
34 0 obj
<</Type/FontDescriptor/FontName/KGDDXH+CMMI7/FontBBox[0 -10 658 441]/Flags 131104
/Ascent 441
/CapHeight 441
/Descent -10
/ItalicAngle 0
/StemV 98
/MissingWidth 500
/XHeight 441
/CharSet(/n)/FontFile3 150 0 R>>
endobj
150 0 obj
<</Filter/FlateDecode
/Subtype/Type1C/Length 441>>stream
x��Q�CMMI7$������&�M����"�Z�W�Tns�Copyright (c) 1997, 2009 American Mathematical Society (<http://www.ams.org>), with Reserved Font Name CMMI7.CMMI7Computer ModernnO����V�����7Ӎ����~�r��u������������������������������������֋ŌXxO`�{a�o���zV�j�����~��}����t;`bc�v���������������>�V8SXcm��P�b�`�tl~tuf}R��~���������ƞ�����upx�f�p�p�b�uw��C����p��`��
�
7�	��/c�I
endstream
endobj
86 0 obj
<</Type/FontDescriptor/FontName/RSRSZA+CMMIB6/FontBBox[0 -194 712 453]/Flags 131104
/Ascent 453
/CapHeight 453
/Descent -194
/ItalicAngle 0
/StemV 106
/MissingWidth 500
/XHeight 453
/CharSet(/p)/FontFile3 151 0 R>>
endobj
151 0 obj
<</Filter/FlateDecode
/Subtype/Type1C/Length 436>>stream
x�cd`ab`dddw���t21UH3��a�!���;�g̏H�n�n��?����	~���!���Ș_��_PY���Q�����`hii��`d``����Z�������X����X��(�'g��T*h�d��X�뗗��%�����i�(�g�d(�����(���(�%�*@����sJKR�|�SR���Y�����Y�;��w�}���c�q��w�ߜ�u]@��Y���]�-�-���]�S�fȭ��ؿ�{i�����{y��O��dAyO[�|cOaWcϦ�&�
�7n��������w�o6~�[�W�ʧ������͐�[��l~�����'��:�`��n��Y���-�M��y+D����̙}������fƦ���f,M��	-���N�W����8�w=n9.��|��{yx�������c`o��I
endstream
endobj
53 0 obj
<</Type/FontDescriptor/FontName/GMJVEG+f-2-0/FontBBox[-22 -299 625 639]/Flags 131077
/Ascent 639
/CapHeight 595
/Descent -299
/ItalicAngle 0
/StemV 93
/AvgWidth 602
/MaxWidth 602
/MissingWidth 602
/XHeight 464
/CharSet(/B/C/D/E/I/K/L/M/O/T/X/Y/k/m/n/underscore)/FontFile3 152 0 R>>
endobj
152 0 obj
<</Filter/FlateDecode
/Subtype/Type1C/Length 2070>>stream
x�eU{PS��!��,�1B�͍v��,:�*�먰]�ͮ����y�#@ �H �!	���$��Vݵ�؎�v�ak��YGgt�i;���N���ћ����9s�9������~���!x<Y��5=3��!��c7İ�:|����H��C�|;����@�%@�Z"��;Z���iP��)��-YY��B���Z����)�5��bY�J])+j��+�j���*ف�c2�^�R=���K4%j}I1�5[U]Z^\R�-/Tfd�t���lK��P���� ��k�q�ē�1���*ޚA$���;�W�����iD:�Ad�9�!��H�H�o��C1��Ͽ��� [�Wry�zO�N��}��}�Bp3���$Xu��&��ê�؆�\�5����i��E��~D��w�N4���Z;���|���sW?W���S�����h����O�@��ܓc�^�Ղ���Z
�g�2O��+��D!oKO��(��C�j_�!7���/�~�2���.1d�
�����f���}ƀ֓ӌkj��SjiA-4$�H�{,��iE�2����i�����o8`��:i� ��L�؈٫�q�1��A�l�u:iL�-�[�Nԍ$S����ɫ�lԚMZ��y�c�DȽ��� ~Z��>H݆��{�y�u�����'3#�%�Tq>gL(bύ�/}�9�����ԙL���Y�?,o$:*��-ba5��~XM-/T��<U&-��3b���+u�����>�)�;���E!6-$΁�I�	g�9�DT0�sO�ltѻ�6d�BXlh��aZN�ܝ�8+p(\�Ʌd�kٴ�YN�X����B��9�rТl�3�f�o�UU��N�` ����3���H=ƻl�M��#>{��&����!!~��d���x-l���S���ȉ~���:]C��D_d.�v�?�M���|�벣^ړߦ9��S.f��>����vy}���*�l�u »�����N)@�^4;6�>��/�t����ũ���o��F}B���&��9|�����E���z�OE��F�5���r��!1+�D]C'�`*�����3�����#}��K���U�Z�A�2�����e=��2#7��V����P$}3��uTT,6a��a|�kp^�gj�6X��+�;[�A��A0���.��m�p�f�@Q�&F'
�m�r�v��	˕da�]�������g?
�q+���@�L��fN�6_|�xa9�=O�����p�\8�5���OS&���ѐҩ�K�Y�/쓜��sZz
.[	?���hrW��j�wB��G{��Sx?e���9�{��CG�WIus�Z�3�89�h\���Ճ�\ϝpM��qWT2�y��5�o��Qt���d��а�r�?�[�3w�����20K|���:̰�{�'���0lf�D9������H��<C�}�0�fn��+�����%��M��}��+`��j�����"�f����W�cZqH�"¯����[l/��8��isI&��;�w�x�;�(���V��`��'
������6���*>ȸǇ�^=��T��u�����N?�o�aqQ�)�>�Aڭ�@|��v���r�o�a̜�p�����똇�~N��?�t��~�s߹���߁86I�
"����ߓ�(FM}5�V���=e��:�`Ĥ"��:��O����Qs�I�o�jdn�д�m)�5I���IE� r�;�
�M/���+�pP|n6�jK�	5HtLˤR�1�wd�ܧ�H,��/o���uH�8G�((4y�R�B�����>�p�7�8���N����3�a�yz(lג��*��4NC�3��(ɖ����u6,Aʝd�,��11�P���	�Ur�{��Uj�#d��B��ږ\Eݱ�q�j(�����j�(4���ԧ�!kMf틹�oR/�e/w?7ܦ<�ɗFr��G�SOOTnEM���E��MX�e8)���K��S_��_�.��-��5O�$�ϭ����dS��D�R��fF�>&�C���� ]�8�~�50���$�ǈ�C��U�_j5��
endstream
endobj
32 0 obj
<</Type/FontDescriptor/FontName/WEWHHV+MSBM10/FontBBox[0 0 703 685]/Flags 65568
/Ascent 685
/CapHeight 685
/Descent 0
/ItalicAngle 0
/StemV 105
/MissingWidth 500
/CharSet(/R)/FontFile3 153 0 R>>
endobj
153 0 obj
<</Filter/FlateDecode
/Subtype/Type1C/Length 499>>stream
x�cd`ab`ddd�
v�541U~H3��a�!����3��#k7s7ˊ	B߃���``fd�/�r�/�,�L�(Q�H�T0��4�Q020�Tp�M-�LN�S�M,�H�M,rr��3SK*4l2JJ
�������s�����4u�3K2�R�S��RS���J�sS nӃP��9�E�A�L@�3�0������ֽ���u��c���ź��>�c����9��lߵ~�L�^�2�FrR}_��n��rlsguϝ�:��W>mr����-S#�z|gx2������������%��[euweռ��G&�D���d�lk	j�讪��=W��2�Is����'���}���
}��w�n=��eKӻ�n�n���
�ߡ�kEt�9�`k�o�ߢ9���~��>':yn���)?zٻ�v/k��񝍭��������D����ɕ�������3�{V���Y����3�v�g����W>���<��I��7sm��b1��ùn�20m���
endstream
endobj
179 0 obj
<</Type/Metadata
/Subtype/XML/Length 1376>>stream
<?xpacket begin='' id='W5M0MpCehiHzreSzNTczkc9d'?>
<?adobe-xap-filters esc="CRLF"?>
<x:xmpmeta xmlns:x='adobe:ns:meta/' x:xmptk='XMP toolkit 2.9.1-13, framework 1.6'>
<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#' xmlns:iX='http://ns.adobe.com/iX/1.0/'>
<rdf:Description rdf:about='uuid:4b9419f2-d9cb-11f1-0000-c43adc00e114' xmlns:pdf='http://ns.adobe.com/pdf/1.3/' pdf:Producer='GPL Ghostscript 9.16'/>
<rdf:Description rdf:about='uuid:4b9419f2-d9cb-11f1-0000-c43adc00e114' xmlns:xmp='http://ns.adobe.com/xap/1.0/'><xmp:ModifyDate>2016-11-03T11:17:38+01:00</xmp:ModifyDate>
<xmp:CreateDate>2016-11-03T11:17:38+01:00</xmp:CreateDate>
<xmp:CreatorTool>dvips(k) 5.995 Copyright 2015 Radical Eye Software</xmp:CreatorTool></rdf:Description>
<rdf:Description rdf:about='uuid:4b9419f2-d9cb-11f1-0000-c43adc00e114' xmlns:xapMM='http://ns.adobe.com/xap/1.0/mm/' xapMM:DocumentID='uuid:4b9419f2-d9cb-11f1-0000-c43adc00e114'/>
<rdf:Description rdf:about='uuid:4b9419f2-d9cb-11f1-0000-c43adc00e114' xmlns:dc='http://purl.org/dc/elements/1.1/' dc:format='application/pdf'><dc:title><rdf:Alt><rdf:li xml:lang='x-default'>CP88.dvi</rdf:li></rdf:Alt></dc:title></rdf:Description>
</rdf:RDF>
</x:xmpmeta>

<?xpacket end='w'?>
endstream
endobj
2 0 obj
<</Producer(GPL Ghostscript 9.16)
/CreationDate(D:20161103111738+01'00')
/ModDate(D:20161103111738+01'00')
/Creator(dvips\(k\) 5.995 Copyright 2015 Radical Eye Software)
/Title(CP88.dvi)>>endobj
xref
0 180
0000000000 65535 f
0000057005 00000 n
0000144232 00000 n
0000056879 00000 n
0000055201 00000 n
0000000015 00000 n
0000005006 00000 n
0000057071 00000 n
0000067007 00000 n
0000120253 00000 n
0000065802 00000 n
0000110562 00000 n
0000064021 00000 n
0000097151 00000 n
0000063442 00000 n
0000092725 00000 n
0000062416 00000 n
0000088262 00000 n
0000057112 00000 n
0000057142 00000 n
0000055361 00000 n
0000005026 00000 n
0000010670 00000 n
0000060995 00000 n
0000079332 00000 n
0000060299 00000 n
0000076146 00000 n
0000059209 00000 n
0000073248 00000 n
0000058636 00000 n
0000071307 00000 n
0000071152 00000 n
0000141983 00000 n
0000070512 00000 n
0000138024 00000 n
0000069581 00000 n
0000135105 00000 n
0000068228 00000 n
0000129685 00000 n
0000067866 00000 n
0000127373 00000 n
0000066693 00000 n
0000119379 00000 n
0000057216 00000 n
0000057246 00000 n
0000055531 00000 n
0000010691 00000 n
0000014831 00000 n
0000069182 00000 n
0000132497 00000 n
0000070361 00000 n
0000136638 00000 n
0000070825 00000 n
0000139529 00000 n
0000065253 00000 n
0000105823 00000 n
0000063811 00000 n
0000095740 00000 n
0000063135 00000 n
0000091922 00000 n
0000061868 00000 n
0000086892 00000 n
0000057397 00000 n
0000057427 00000 n
0000055693 00000 n
0000014852 00000 n
0000020519 00000 n
0000057580 00000 n
0000057610 00000 n
0000055863 00000 n
0000020540 00000 n
0000026179 00000 n
0000061578 00000 n
0000084587 00000 n
0000060798 00000 n
0000077951 00000 n
0000059737 00000 n
0000075384 00000 n
0000057739 00000 n
0000057769 00000 n
0000056033 00000 n
0000026200 00000 n
0000032617 00000 n
0000059028 00000 n
0000072226 00000 n
0000070668 00000 n
0000138777 00000 n
0000069874 00000 n
0000135856 00000 n
0000068498 00000 n
0000130818 00000 n
0000057931 00000 n
0000057961 00000 n
0000056203 00000 n
0000032638 00000 n
0000038527 00000 n
0000068047 00000 n
0000128389 00000 n
0000058136 00000 n
0000058166 00000 n
0000056373 00000 n
0000038548 00000 n
0000047202 00000 n
0000058253 00000 n
0000058284 00000 n
0000056547 00000 n
0000047224 00000 n
0000053501 00000 n
0000067542 00000 n
0000125047 00000 n
0000066446 00000 n
0000118731 00000 n
0000064667 00000 n
0000105204 00000 n
0000058383 00000 n
0000058414 00000 n
0000056713 00000 n
0000053523 00000 n
0000055179 00000 n
0000058550 00000 n
0000058581 00000 n
0000071567 00000 n
0000072475 00000 n
0000073494 00000 n
0000075615 00000 n
0000076391 00000 n
0000078189 00000 n
0000079713 00000 n
0000084834 00000 n
0000087189 00000 n
0000088612 00000 n
0000092156 00000 n
0000093081 00000 n
0000095977 00000 n
0000097637 00000 n
0000105430 00000 n
0000106125 00000 n
0000111039 00000 n
0000118958 00000 n
0000119661 00000 n
0000120584 00000 n
0000125335 00000 n
0000127622 00000 n
0000128630 00000 n
0000129918 00000 n
0000131065 00000 n
0000132702 00000 n
0000135333 00000 n
0000136091 00000 n
0000136841 00000 n
0000138251 00000 n
0000139008 00000 n
0000139827 00000 n
0000142194 00000 n
0000058890 00000 n
0000059498 00000 n
0000059915 00000 n
0000060019 00000 n
0000060691 00000 n
0000061469 00000 n
0000062235 00000 n
0000062789 00000 n
0000062892 00000 n
0000063330 00000 n
0000064552 00000 n
0000064818 00000 n
0000064920 00000 n
0000065686 00000 n
0000066328 00000 n
0000066598 00000 n
0000066854 00000 n
0000067457 00000 n
0000068865 00000 n
0000068950 00000 n
0000069343 00000 n
0000069770 00000 n
0000070024 00000 n
0000070133 00000 n
0000071030 00000 n
0000142778 00000 n
trailer
<< /Size 180 /Root 1 0 R /Info 2 0 R
/ID [<D8966A0924A438A93538B237FBECA616><D8966A0924A438A93538B237FBECA616>]
>>
startxref
144435
%%EOF


Conv2d and Tensor Cores

Hi there,

I am running into an issue where a conv2d layer is not using Tensor Cores for some configurations of dilations/padding.

For certain inputs size the layer uses a Tensor Core CUDNN implementation but not for others. Is there some known limitations/rules that should be followed to guarantee TCUs are used every time for 2d convolution, regardless of input size and dilation/padding parameters?

o Linux distro and version: Debian 9
o GPU type: RTX 2080 TI
o Nvidia driver version: 410.93
o CUDA version: 10.0
o CUDNN version: 7.6.5
o Python version [if using python]: Using c++
o Tensorflow and PyTorch version
o TensorRT version: 7.0.0.11

Thanks in advance for your help!

Hi,

For best practice, please refer to below link:
https://docs.nvidia.com/deeplearning/sdk/tensorrt-best-practices/index.html#optimize-layer

If possible please share your model and configuration setting so that we can help better.

Thanks

Thanks.

I have three parallel 2d conv nodes. They all have the same input size and same output size.
The difference is one has (6,6), other (12,12), other (18,18) padding. The kernel shape is (3,3) for all of them.

The one with (6,6) always runs on TCUs regardless of input size.
The one with (12,12) runs on TCUs for some input sizes.
The one with (18,18) never runs on TCUs.

My guess is that there is some rule that only triggers TCUs usage if the input/work size/output size is a multiple of 8 or something like that. But I would like to clarify what the rules are instead of trying to guess.

Thanks for your help

For best practice, please refer to below link:
https://docs.nvidia.com/deeplearning/sdk/tensorrt-best-practices/index.html#optimize-layer

As mentioned in above link:
Tensor dimensions (or the number of input and output channels for FullyConnected layer) of multiples of 32 tend to have the best performance for FP16 and INT8 inference because of the utilization of Tensor Cores if the hardware supports them.

Tensor Core kernels for FP16 data requires striding between data rows to be multiples of 8 data elements. For example, a MatrixMultiply that is M x K times K x N requires M, K, and N to be multiple of 8 to use Tensor Core optimized kernels.

Can you share more details regarding stride, dilation, in / out channels? Also if possible please share the model & script file to repro the issue.

Thanks

Sorry, I am not allowed to share the model but it is DeepLab with atrous classifier.

The convolutions that are giving me trouble are the atrous convolutions in the classifier.

In channels: 2048
Out channels: 256
Kernel: 3,3
Stride: 1,1
Pads: 6,6
Dilation: 6,6

In channels: 2048
Out channels: 256
Kernel: 3,3
Stride: 1,1
Pads: 12,12
Dilation: 12,12

In channels: 2048
Out channels: 256
Kernel: 3,3
Stride: 1,1
Pads: 18,18
Dilation: 18,18

The problem is the optimizer not being able to find an optimized implementation but resorting to use the implicit_convolve_sgemm instead of some turing_h1688 implementation like the other ‘regular’ convolutions.

Screenshot at 2020-04-29 15-11-31 (1)1565×424 189 KB

Thanks SunilJB

Hi @ricardo10silva,

There are some additional fixes pushed in latest release, could you please try using latest TRT and let us know in case issue persist.

Thanks

Related topics

Powered by Discourse, best viewed with JavaScript enabled